1 /*- 2 * Copyright (c) 2008 Christos Zoulas 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 */ 26 /* 27 * Parse Composite Document Files, the format used in Microsoft Office 28 * document files before they switched to zipped XML. 29 * Info from: http://sc.openoffice.org/compdocfileformat.pdf 30 * 31 * N.B. This is the "Composite Document File" format, and not the 32 * "Compound Document Format", nor the "Channel Definition Format". 33 */ 34 35 #include "file.h" 36 37 #ifndef lint 38 FILE_RCSID("@(#)$File: cdf.c,v 1.120 2021/09/24 13:59:19 christos Exp $") 39 #endif 40 41 #include <assert.h> 42 #ifdef CDF_DEBUG 43 #include <err.h> 44 #endif 45 #include <stdlib.h> 46 #include <unistd.h> 47 #include <string.h> 48 #include <time.h> 49 #include <ctype.h> 50 #include <limits.h> 51 52 #ifndef EFTYPE 53 #define EFTYPE EINVAL 54 #endif 55 56 #ifndef SIZE_T_MAX 57 #define SIZE_T_MAX CAST(size_t, ~0ULL) 58 #endif 59 60 #include "cdf.h" 61 62 #ifdef CDF_DEBUG 63 #define DPRINTF(a) printf a, fflush(stdout) 64 #else 65 #define DPRINTF(a) 66 #endif 67 68 static union { 69 char s[4]; 70 uint32_t u; 71 } cdf_bo; 72 73 #define NEED_SWAP (cdf_bo.u == CAST(uint32_t, 0x01020304)) 74 75 #define CDF_TOLE8(x) \ 76 (CAST(uint64_t, NEED_SWAP ? _cdf_tole8(x) : CAST(uint64_t, x))) 77 #define CDF_TOLE4(x) \ 78 (CAST(uint32_t, NEED_SWAP ? _cdf_tole4(x) : CAST(uint32_t, x))) 79 #define CDF_TOLE2(x) \ 80 (CAST(uint16_t, NEED_SWAP ? _cdf_tole2(x) : CAST(uint16_t, x))) 81 #define CDF_TOLE(x) (/*CONSTCOND*/sizeof(x) == 2 ? \ 82 CDF_TOLE2(CAST(uint16_t, x)) : \ 83 (/*CONSTCOND*/sizeof(x) == 4 ? \ 84 CDF_TOLE4(CAST(uint32_t, x)) : \ 85 CDF_TOLE8(CAST(uint64_t, x)))) 86 #define CDF_GETUINT32(x, y) cdf_getuint32(x, y) 87 88 #define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n)) 89 #define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n)) 90 #define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u)) 91 92 93 /*ARGSUSED*/ 94 static void * 95 cdf_malloc(const char *file __attribute__((__unused__)), 96 size_t line __attribute__((__unused__)), size_t n) 97 { 98 DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", 99 file, line, __func__, n)); 100 if (n == 0) 101 n++; 102 return malloc(n); 103 } 104 105 /*ARGSUSED*/ 106 static void * 107 cdf_realloc(const char *file __attribute__((__unused__)), 108 size_t line __attribute__((__unused__)), void *p, size_t n) 109 { 110 DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", 111 file, line, __func__, n)); 112 return realloc(p, n); 113 } 114 115 /*ARGSUSED*/ 116 static void * 117 cdf_calloc(const char *file __attribute__((__unused__)), 118 size_t line __attribute__((__unused__)), size_t n, size_t u) 119 { 120 DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u %" 121 SIZE_T_FORMAT "u\n", file, line, __func__, n, u)); 122 if (n == 0) 123 n++; 124 return calloc(n, u); 125 } 126 127 /* 128 * swap a short 129 */ 130 static uint16_t 131 _cdf_tole2(uint16_t sv) 132 { 133 uint16_t rv; 134 uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv)); 135 uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv)); 136 d[0] = s[1]; 137 d[1] = s[0]; 138 return rv; 139 } 140 141 /* 142 * swap an int 143 */ 144 static uint32_t 145 _cdf_tole4(uint32_t sv) 146 { 147 uint32_t rv; 148 uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv)); 149 uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv)); 150 d[0] = s[3]; 151 d[1] = s[2]; 152 d[2] = s[1]; 153 d[3] = s[0]; 154 return rv; 155 } 156 157 /* 158 * swap a quad 159 */ 160 static uint64_t 161 _cdf_tole8(uint64_t sv) 162 { 163 uint64_t rv; 164 uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv)); 165 uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv)); 166 d[0] = s[7]; 167 d[1] = s[6]; 168 d[2] = s[5]; 169 d[3] = s[4]; 170 d[4] = s[3]; 171 d[5] = s[2]; 172 d[6] = s[1]; 173 d[7] = s[0]; 174 return rv; 175 } 176 177 /* 178 * grab a uint32_t from a possibly unaligned address, and return it in 179 * the native host order. 180 */ 181 static uint32_t 182 cdf_getuint32(const uint8_t *p, size_t offs) 183 { 184 uint32_t rv; 185 (void)memcpy(&rv, p + offs * sizeof(uint32_t), sizeof(rv)); 186 return CDF_TOLE4(rv); 187 } 188 189 #define CDF_UNPACK(a) \ 190 (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a) 191 #define CDF_UNPACKA(a) \ 192 (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a) 193 194 uint16_t 195 cdf_tole2(uint16_t sv) 196 { 197 return CDF_TOLE2(sv); 198 } 199 200 uint32_t 201 cdf_tole4(uint32_t sv) 202 { 203 return CDF_TOLE4(sv); 204 } 205 206 uint64_t 207 cdf_tole8(uint64_t sv) 208 { 209 return CDF_TOLE8(sv); 210 } 211 212 void 213 cdf_swap_header(cdf_header_t *h) 214 { 215 size_t i; 216 217 h->h_magic = CDF_TOLE8(h->h_magic); 218 h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]); 219 h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]); 220 h->h_revision = CDF_TOLE2(h->h_revision); 221 h->h_version = CDF_TOLE2(h->h_version); 222 h->h_byte_order = CDF_TOLE2(h->h_byte_order); 223 h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2); 224 h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2); 225 h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat); 226 h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory); 227 h->h_min_size_standard_stream = 228 CDF_TOLE4(h->h_min_size_standard_stream); 229 h->h_secid_first_sector_in_short_sat = 230 CDF_TOLE4(CAST(uint32_t, h->h_secid_first_sector_in_short_sat)); 231 h->h_num_sectors_in_short_sat = 232 CDF_TOLE4(h->h_num_sectors_in_short_sat); 233 h->h_secid_first_sector_in_master_sat = 234 CDF_TOLE4(CAST(uint32_t, h->h_secid_first_sector_in_master_sat)); 235 h->h_num_sectors_in_master_sat = 236 CDF_TOLE4(h->h_num_sectors_in_master_sat); 237 for (i = 0; i < __arraycount(h->h_master_sat); i++) { 238 h->h_master_sat[i] = 239 CDF_TOLE4(CAST(uint32_t, h->h_master_sat[i])); 240 } 241 } 242 243 void 244 cdf_unpack_header(cdf_header_t *h, char *buf) 245 { 246 size_t i; 247 size_t len = 0; 248 249 CDF_UNPACK(h->h_magic); 250 CDF_UNPACKA(h->h_uuid); 251 CDF_UNPACK(h->h_revision); 252 CDF_UNPACK(h->h_version); 253 CDF_UNPACK(h->h_byte_order); 254 CDF_UNPACK(h->h_sec_size_p2); 255 CDF_UNPACK(h->h_short_sec_size_p2); 256 CDF_UNPACKA(h->h_unused0); 257 CDF_UNPACK(h->h_num_sectors_in_sat); 258 CDF_UNPACK(h->h_secid_first_directory); 259 CDF_UNPACKA(h->h_unused1); 260 CDF_UNPACK(h->h_min_size_standard_stream); 261 CDF_UNPACK(h->h_secid_first_sector_in_short_sat); 262 CDF_UNPACK(h->h_num_sectors_in_short_sat); 263 CDF_UNPACK(h->h_secid_first_sector_in_master_sat); 264 CDF_UNPACK(h->h_num_sectors_in_master_sat); 265 for (i = 0; i < __arraycount(h->h_master_sat); i++) 266 CDF_UNPACK(h->h_master_sat[i]); 267 } 268 269 void 270 cdf_swap_dir(cdf_directory_t *d) 271 { 272 d->d_namelen = CDF_TOLE2(d->d_namelen); 273 d->d_left_child = CDF_TOLE4(CAST(uint32_t, d->d_left_child)); 274 d->d_right_child = CDF_TOLE4(CAST(uint32_t, d->d_right_child)); 275 d->d_storage = CDF_TOLE4(CAST(uint32_t, d->d_storage)); 276 d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]); 277 d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]); 278 d->d_flags = CDF_TOLE4(d->d_flags); 279 d->d_created = CDF_TOLE8(CAST(uint64_t, d->d_created)); 280 d->d_modified = CDF_TOLE8(CAST(uint64_t, d->d_modified)); 281 d->d_stream_first_sector = CDF_TOLE4( 282 CAST(uint32_t, d->d_stream_first_sector)); 283 d->d_size = CDF_TOLE4(d->d_size); 284 } 285 286 void 287 cdf_swap_class(cdf_classid_t *d) 288 { 289 d->cl_dword = CDF_TOLE4(d->cl_dword); 290 d->cl_word[0] = CDF_TOLE2(d->cl_word[0]); 291 d->cl_word[1] = CDF_TOLE2(d->cl_word[1]); 292 } 293 294 void 295 cdf_unpack_dir(cdf_directory_t *d, char *buf) 296 { 297 size_t len = 0; 298 299 CDF_UNPACKA(d->d_name); 300 CDF_UNPACK(d->d_namelen); 301 CDF_UNPACK(d->d_type); 302 CDF_UNPACK(d->d_color); 303 CDF_UNPACK(d->d_left_child); 304 CDF_UNPACK(d->d_right_child); 305 CDF_UNPACK(d->d_storage); 306 CDF_UNPACKA(d->d_storage_uuid); 307 CDF_UNPACK(d->d_flags); 308 CDF_UNPACK(d->d_created); 309 CDF_UNPACK(d->d_modified); 310 CDF_UNPACK(d->d_stream_first_sector); 311 CDF_UNPACK(d->d_size); 312 CDF_UNPACK(d->d_unused0); 313 } 314 315 int 316 cdf_zero_stream(cdf_stream_t *scn) 317 { 318 scn->sst_len = 0; 319 scn->sst_dirlen = 0; 320 scn->sst_ss = 0; 321 free(scn->sst_tab); 322 scn->sst_tab = NULL; 323 return -1; 324 } 325 326 static size_t 327 cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h) 328 { 329 size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? 330 CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); 331 assert(ss == sst->sst_ss); 332 return sst->sst_ss; 333 } 334 335 static int 336 cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h, 337 const void *p, size_t tail, int line) 338 { 339 const char *b = RCAST(const char *, sst->sst_tab); 340 const char *e = RCAST(const char *, p) + tail; 341 size_t ss = cdf_check_stream(sst, h); 342 /*LINTED*/(void)&line; 343 if (e >= b && CAST(size_t, e - b) <= ss * sst->sst_len) 344 return 0; 345 DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u" 346 " > %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %" 347 SIZE_T_FORMAT "u]\n", line, b, e, (size_t)(e - b), 348 ss * sst->sst_len, ss, sst->sst_len)); 349 errno = EFTYPE; 350 return -1; 351 } 352 353 static ssize_t 354 cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len) 355 { 356 size_t siz = CAST(size_t, off + len); 357 358 if (CAST(off_t, off + len) != CAST(off_t, siz)) 359 goto out; 360 361 if (info->i_buf != NULL && info->i_len >= siz) { 362 (void)memcpy(buf, &info->i_buf[off], len); 363 return CAST(ssize_t, len); 364 } 365 366 if (info->i_fd == -1) 367 goto out; 368 369 if (pread(info->i_fd, buf, len, off) != CAST(ssize_t, len)) 370 return -1; 371 372 return CAST(ssize_t, len); 373 out: 374 errno = EINVAL; 375 return -1; 376 } 377 378 int 379 cdf_read_header(const cdf_info_t *info, cdf_header_t *h) 380 { 381 char buf[512]; 382 383 (void)memcpy(cdf_bo.s, "\01\02\03\04", 4); 384 if (cdf_read(info, CAST(off_t, 0), buf, sizeof(buf)) == -1) 385 return -1; 386 cdf_unpack_header(h, buf); 387 cdf_swap_header(h); 388 if (h->h_magic != CDF_MAGIC) { 389 DPRINTF(("Bad magic %#" INT64_T_FORMAT "x != %#" 390 INT64_T_FORMAT "x\n", 391 (unsigned long long)h->h_magic, 392 (unsigned long long)CDF_MAGIC)); 393 goto out; 394 } 395 if (h->h_sec_size_p2 > 20) { 396 DPRINTF(("Bad sector size %hu\n", h->h_sec_size_p2)); 397 goto out; 398 } 399 if (h->h_short_sec_size_p2 > 20) { 400 DPRINTF(("Bad short sector size %hu\n", 401 h->h_short_sec_size_p2)); 402 goto out; 403 } 404 return 0; 405 out: 406 errno = EFTYPE; 407 return -1; 408 } 409 410 411 ssize_t 412 cdf_read_sector(const cdf_info_t *info, void *buf, size_t offs, size_t len, 413 const cdf_header_t *h, cdf_secid_t id) 414 { 415 size_t ss = CDF_SEC_SIZE(h); 416 size_t pos; 417 418 if (SIZE_T_MAX / ss < CAST(size_t, id)) 419 return -1; 420 421 pos = CDF_SEC_POS(h, id); 422 assert(ss == len); 423 return cdf_read(info, CAST(off_t, pos), RCAST(char *, buf) + offs, len); 424 } 425 426 ssize_t 427 cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs, 428 size_t len, const cdf_header_t *h, cdf_secid_t id) 429 { 430 size_t ss = CDF_SHORT_SEC_SIZE(h); 431 size_t pos; 432 433 if (SIZE_T_MAX / ss < CAST(size_t, id)) 434 return -1; 435 436 pos = CDF_SHORT_SEC_POS(h, id); 437 assert(ss == len); 438 if (pos + len > CDF_SEC_SIZE(h) * sst->sst_len) { 439 DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %" 440 SIZE_T_FORMAT "u\n", 441 pos + len, CDF_SEC_SIZE(h) * sst->sst_len)); 442 goto out; 443 } 444 (void)memcpy(RCAST(char *, buf) + offs, 445 RCAST(const char *, sst->sst_tab) + pos, len); 446 return len; 447 out: 448 errno = EFTYPE; 449 return -1; 450 } 451 452 /* 453 * Read the sector allocation table. 454 */ 455 int 456 cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat) 457 { 458 size_t i, j, k; 459 size_t ss = CDF_SEC_SIZE(h); 460 cdf_secid_t *msa, mid, sec; 461 size_t nsatpersec = (ss / sizeof(mid)) - 1; 462 463 for (i = 0; i < __arraycount(h->h_master_sat); i++) 464 if (h->h_master_sat[i] == CDF_SECID_FREE) 465 break; 466 467 #define CDF_SEC_LIMIT (UINT32_MAX / (64 * ss)) 468 if ((nsatpersec > 0 && 469 h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec) || 470 i > CDF_SEC_LIMIT) { 471 DPRINTF(("Number of sectors in master SAT too big %u %" 472 SIZE_T_FORMAT "u\n", h->h_num_sectors_in_master_sat, i)); 473 errno = EFTYPE; 474 return -1; 475 } 476 477 sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i; 478 DPRINTF(("sat_len = %" SIZE_T_FORMAT "u ss = %" SIZE_T_FORMAT "u\n", 479 sat->sat_len, ss)); 480 if ((sat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(sat->sat_len, ss))) 481 == NULL) 482 return -1; 483 484 for (i = 0; i < __arraycount(h->h_master_sat); i++) { 485 if (h->h_master_sat[i] < 0) 486 break; 487 if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h, 488 h->h_master_sat[i]) != CAST(ssize_t, ss)) { 489 DPRINTF(("Reading sector %d", h->h_master_sat[i])); 490 goto out1; 491 } 492 } 493 494 if ((msa = CAST(cdf_secid_t *, CDF_CALLOC(1, ss))) == NULL) 495 goto out1; 496 497 mid = h->h_secid_first_sector_in_master_sat; 498 for (j = 0; j < h->h_num_sectors_in_master_sat; j++) { 499 if (mid < 0) 500 goto out; 501 if (j >= CDF_LOOP_LIMIT) { 502 DPRINTF(("Reading master sector loop limit")); 503 goto out3; 504 } 505 if (cdf_read_sector(info, msa, 0, ss, h, mid) != 506 CAST(ssize_t, ss)) { 507 DPRINTF(("Reading master sector %d", mid)); 508 goto out2; 509 } 510 for (k = 0; k < nsatpersec; k++, i++) { 511 sec = CDF_TOLE4(CAST(uint32_t, msa[k])); 512 if (sec < 0) 513 goto out; 514 if (i >= sat->sat_len) { 515 DPRINTF(("Out of bounds reading MSA %" 516 SIZE_T_FORMAT "u >= %" SIZE_T_FORMAT "u", 517 i, sat->sat_len)); 518 goto out3; 519 } 520 if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h, 521 sec) != CAST(ssize_t, ss)) { 522 DPRINTF(("Reading sector %d", 523 CDF_TOLE4(msa[k]))); 524 goto out2; 525 } 526 } 527 mid = CDF_TOLE4(CAST(uint32_t, msa[nsatpersec])); 528 } 529 out: 530 sat->sat_len = i; 531 free(msa); 532 return 0; 533 out3: 534 errno = EFTYPE; 535 out2: 536 free(msa); 537 out1: 538 free(sat->sat_tab); 539 return -1; 540 } 541 542 size_t 543 cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size) 544 { 545 size_t i, j; 546 cdf_secid_t maxsector = CAST(cdf_secid_t, (sat->sat_len * size) 547 / sizeof(maxsector)); 548 549 DPRINTF(("Chain:")); 550 if (sid == CDF_SECID_END_OF_CHAIN) { 551 /* 0-length chain. */ 552 DPRINTF((" empty\n")); 553 return 0; 554 } 555 556 for (j = i = 0; sid >= 0; i++, j++) { 557 DPRINTF((" %d", sid)); 558 if (j >= CDF_LOOP_LIMIT) { 559 DPRINTF(("Counting chain loop limit")); 560 goto out; 561 } 562 if (sid >= maxsector) { 563 DPRINTF(("Sector %d >= %d\n", sid, maxsector)); 564 goto out; 565 } 566 sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid])); 567 } 568 if (i == 0) { 569 DPRINTF((" none, sid: %d\n", sid)); 570 goto out; 571 572 } 573 DPRINTF(("\n")); 574 return i; 575 out: 576 errno = EFTYPE; 577 return CAST(size_t, -1); 578 } 579 580 int 581 cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h, 582 const cdf_sat_t *sat, cdf_secid_t sid, size_t len, cdf_stream_t *scn) 583 { 584 size_t ss = CDF_SEC_SIZE(h), i, j; 585 ssize_t nr; 586 scn->sst_tab = NULL; 587 scn->sst_len = cdf_count_chain(sat, sid, ss); 588 scn->sst_dirlen = MAX(h->h_min_size_standard_stream, len); 589 scn->sst_ss = ss; 590 591 if (sid == CDF_SECID_END_OF_CHAIN || len == 0) 592 return cdf_zero_stream(scn); 593 594 if (scn->sst_len == CAST(size_t, -1)) 595 goto out; 596 597 scn->sst_tab = CDF_CALLOC(scn->sst_len, ss); 598 if (scn->sst_tab == NULL) 599 return cdf_zero_stream(scn); 600 601 for (j = i = 0; sid >= 0; i++, j++) { 602 if (j >= CDF_LOOP_LIMIT) { 603 DPRINTF(("Read long sector chain loop limit")); 604 goto out; 605 } 606 if (i >= scn->sst_len) { 607 DPRINTF(("Out of bounds reading long sector chain " 608 "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i, 609 scn->sst_len)); 610 goto out; 611 } 612 if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h, 613 sid)) != CAST(ssize_t, ss)) { 614 if (i == scn->sst_len - 1 && nr > 0) { 615 /* Last sector might be truncated */ 616 return 0; 617 } 618 DPRINTF(("Reading long sector chain %d", sid)); 619 goto out; 620 } 621 sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid])); 622 } 623 return 0; 624 out: 625 errno = EFTYPE; 626 return cdf_zero_stream(scn); 627 } 628 629 int 630 cdf_read_short_sector_chain(const cdf_header_t *h, 631 const cdf_sat_t *ssat, const cdf_stream_t *sst, 632 cdf_secid_t sid, size_t len, cdf_stream_t *scn) 633 { 634 size_t ss = CDF_SHORT_SEC_SIZE(h), i, j; 635 scn->sst_tab = NULL; 636 scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h)); 637 scn->sst_dirlen = len; 638 scn->sst_ss = ss; 639 640 if (scn->sst_len == CAST(size_t, -1)) 641 goto out; 642 643 scn->sst_tab = CDF_CALLOC(scn->sst_len, ss); 644 if (scn->sst_tab == NULL) 645 return cdf_zero_stream(scn); 646 647 for (j = i = 0; sid >= 0; i++, j++) { 648 if (j >= CDF_LOOP_LIMIT) { 649 DPRINTF(("Read short sector chain loop limit")); 650 goto out; 651 } 652 if (i >= scn->sst_len) { 653 DPRINTF(("Out of bounds reading short sector chain " 654 "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", 655 i, scn->sst_len)); 656 goto out; 657 } 658 if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h, 659 sid) != CAST(ssize_t, ss)) { 660 DPRINTF(("Reading short sector chain %d", sid)); 661 goto out; 662 } 663 sid = CDF_TOLE4(CAST(uint32_t, ssat->sat_tab[sid])); 664 } 665 return 0; 666 out: 667 errno = EFTYPE; 668 return cdf_zero_stream(scn); 669 } 670 671 int 672 cdf_read_sector_chain(const cdf_info_t *info, const cdf_header_t *h, 673 const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, 674 cdf_secid_t sid, size_t len, cdf_stream_t *scn) 675 { 676 677 if (len < h->h_min_size_standard_stream && sst->sst_tab != NULL) 678 return cdf_read_short_sector_chain(h, ssat, sst, sid, len, 679 scn); 680 else 681 return cdf_read_long_sector_chain(info, h, sat, sid, len, scn); 682 } 683 684 int 685 cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h, 686 const cdf_sat_t *sat, cdf_dir_t *dir) 687 { 688 size_t i, j; 689 size_t ss = CDF_SEC_SIZE(h), ns, nd; 690 char *buf; 691 cdf_secid_t sid = h->h_secid_first_directory; 692 693 ns = cdf_count_chain(sat, sid, ss); 694 if (ns == CAST(size_t, -1)) 695 return -1; 696 697 nd = ss / CDF_DIRECTORY_SIZE; 698 699 dir->dir_len = ns * nd; 700 dir->dir_tab = CAST(cdf_directory_t *, 701 CDF_CALLOC(dir->dir_len, sizeof(dir->dir_tab[0]))); 702 if (dir->dir_tab == NULL) 703 return -1; 704 705 if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) { 706 free(dir->dir_tab); 707 return -1; 708 } 709 710 for (j = i = 0; i < ns; i++, j++) { 711 if (j >= CDF_LOOP_LIMIT) { 712 DPRINTF(("Read dir loop limit")); 713 goto out; 714 } 715 if (cdf_read_sector(info, buf, 0, ss, h, sid) != 716 CAST(ssize_t, ss)) { 717 DPRINTF(("Reading directory sector %d", sid)); 718 goto out; 719 } 720 for (j = 0; j < nd; j++) { 721 cdf_unpack_dir(&dir->dir_tab[i * nd + j], 722 &buf[j * CDF_DIRECTORY_SIZE]); 723 } 724 sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid])); 725 } 726 if (NEED_SWAP) 727 for (i = 0; i < dir->dir_len; i++) 728 cdf_swap_dir(&dir->dir_tab[i]); 729 free(buf); 730 return 0; 731 out: 732 free(dir->dir_tab); 733 free(buf); 734 errno = EFTYPE; 735 return -1; 736 } 737 738 739 int 740 cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h, 741 const cdf_sat_t *sat, cdf_sat_t *ssat) 742 { 743 size_t i, j; 744 size_t ss = CDF_SEC_SIZE(h); 745 cdf_secid_t sid = h->h_secid_first_sector_in_short_sat; 746 747 ssat->sat_tab = NULL; 748 ssat->sat_len = cdf_count_chain(sat, sid, ss); 749 if (ssat->sat_len == CAST(size_t, -1)) 750 goto out; 751 752 ssat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(ssat->sat_len, ss)); 753 if (ssat->sat_tab == NULL) 754 goto out1; 755 756 for (j = i = 0; sid >= 0; i++, j++) { 757 if (j >= CDF_LOOP_LIMIT) { 758 DPRINTF(("Read short sat sector loop limit")); 759 goto out; 760 } 761 if (i >= ssat->sat_len) { 762 DPRINTF(("Out of bounds reading short sector chain " 763 "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i, 764 ssat->sat_len)); 765 goto out; 766 } 767 if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) != 768 CAST(ssize_t, ss)) { 769 DPRINTF(("Reading short sat sector %d", sid)); 770 goto out1; 771 } 772 sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid])); 773 } 774 return 0; 775 out: 776 errno = EFTYPE; 777 out1: 778 free(ssat->sat_tab); 779 return -1; 780 } 781 782 int 783 cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h, 784 const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn, 785 const cdf_directory_t **root) 786 { 787 size_t i; 788 const cdf_directory_t *d; 789 790 *root = NULL; 791 for (i = 0; i < dir->dir_len; i++) 792 if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE) 793 break; 794 795 /* If the it is not there, just fake it; some docs don't have it */ 796 if (i == dir->dir_len) { 797 DPRINTF(("Cannot find root storage dir\n")); 798 goto out; 799 } 800 d = &dir->dir_tab[i]; 801 *root = d; 802 803 /* If the it is not there, just fake it; some docs don't have it */ 804 if (d->d_stream_first_sector < 0) { 805 DPRINTF(("No first secror in dir\n")); 806 goto out; 807 } 808 809 return cdf_read_long_sector_chain(info, h, sat, 810 d->d_stream_first_sector, d->d_size, scn); 811 out: 812 scn->sst_tab = NULL; 813 (void)cdf_zero_stream(scn); 814 return 0; 815 } 816 817 static int 818 cdf_namecmp(const char *d, const uint16_t *s, size_t l) 819 { 820 for (; l--; d++, s++) 821 if (*d != CDF_TOLE2(*s)) 822 return CAST(unsigned char, *d) - CDF_TOLE2(*s); 823 return 0; 824 } 825 826 int 827 cdf_read_doc_summary_info(const cdf_info_t *info, const cdf_header_t *h, 828 const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, 829 const cdf_dir_t *dir, cdf_stream_t *scn) 830 { 831 return cdf_read_user_stream(info, h, sat, ssat, sst, dir, 832 "\05DocumentSummaryInformation", scn); 833 } 834 835 int 836 cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h, 837 const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, 838 const cdf_dir_t *dir, cdf_stream_t *scn) 839 { 840 return cdf_read_user_stream(info, h, sat, ssat, sst, dir, 841 "\05SummaryInformation", scn); 842 } 843 844 int 845 cdf_read_user_stream(const cdf_info_t *info, const cdf_header_t *h, 846 const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, 847 const cdf_dir_t *dir, const char *name, cdf_stream_t *scn) 848 { 849 const cdf_directory_t *d; 850 int i = cdf_find_stream(dir, name, CDF_DIR_TYPE_USER_STREAM); 851 852 if (i <= 0) { 853 memset(scn, 0, sizeof(*scn)); 854 return -1; 855 } 856 857 d = &dir->dir_tab[i - 1]; 858 return cdf_read_sector_chain(info, h, sat, ssat, sst, 859 d->d_stream_first_sector, d->d_size, scn); 860 } 861 862 int 863 cdf_find_stream(const cdf_dir_t *dir, const char *name, int type) 864 { 865 size_t i, name_len = strlen(name) + 1; 866 867 for (i = dir->dir_len; i > 0; i--) 868 if (dir->dir_tab[i - 1].d_type == type && 869 cdf_namecmp(name, dir->dir_tab[i - 1].d_name, name_len) 870 == 0) 871 break; 872 if (i > 0) 873 return CAST(int, i); 874 875 DPRINTF(("Cannot find type %d `%s'\n", type, name)); 876 errno = ESRCH; 877 return 0; 878 } 879 880 #define CDF_SHLEN_LIMIT (UINT32_MAX / 64) 881 #define CDF_PROP_LIMIT (UINT32_MAX / (64 * sizeof(cdf_property_info_t))) 882 883 static const void * 884 cdf_offset(const void *p, size_t l) 885 { 886 return CAST(const void *, CAST(const uint8_t *, p) + l); 887 } 888 889 static const uint8_t * 890 cdf_get_property_info_pos(const cdf_stream_t *sst, const cdf_header_t *h, 891 const uint8_t *p, const uint8_t *e, size_t i) 892 { 893 size_t tail = (i << 1) + 1; 894 size_t ofs; 895 896 if (p >= e) { 897 DPRINTF(("Past end %p < %p\n", e, p)); 898 return NULL; 899 } 900 901 if (cdf_check_stream_offset(sst, h, p, (tail + 1) * sizeof(uint32_t), 902 __LINE__) == -1) 903 return NULL; 904 905 ofs = CDF_GETUINT32(p, tail); 906 if (ofs < 2 * sizeof(uint32_t)) { 907 DPRINTF(("Offset too small %zu\n", ofs)); 908 return NULL; 909 } 910 911 ofs -= 2 * sizeof(uint32_t); 912 if (ofs > CAST(size_t, e - p)) { 913 DPRINTF(("Offset too big %zu %td\n", ofs, e - p)); 914 return NULL; 915 } 916 917 return CAST(const uint8_t *, cdf_offset(CAST(const void *, p), ofs)); 918 } 919 920 static cdf_property_info_t * 921 cdf_grow_info(cdf_property_info_t **info, size_t *maxcount, size_t incr) 922 { 923 cdf_property_info_t *inp; 924 size_t newcount = *maxcount + incr; 925 926 if (newcount > CDF_PROP_LIMIT) { 927 DPRINTF(("exceeded property limit %" SIZE_T_FORMAT "u > %" 928 SIZE_T_FORMAT "u\n", newcount, CDF_PROP_LIMIT)); 929 goto out; 930 } 931 inp = CAST(cdf_property_info_t *, 932 CDF_REALLOC(*info, newcount * sizeof(*inp))); 933 if (inp == NULL) 934 goto out; 935 936 *info = inp; 937 *maxcount = newcount; 938 return inp; 939 out: 940 free(*info); 941 *maxcount = 0; 942 *info = NULL; 943 return NULL; 944 } 945 946 static int 947 cdf_copy_info(cdf_property_info_t *inp, const void *p, const void *e, 948 size_t len) 949 { 950 if (inp->pi_type & CDF_VECTOR) 951 return 0; 952 953 if (CAST(size_t, CAST(const char *, e) - CAST(const char *, p)) < len) 954 return 0; 955 956 (void)memcpy(&inp->pi_val, p, len); 957 958 switch (len) { 959 case 2: 960 inp->pi_u16 = CDF_TOLE2(inp->pi_u16); 961 break; 962 case 4: 963 inp->pi_u32 = CDF_TOLE4(inp->pi_u32); 964 break; 965 case 8: 966 inp->pi_u64 = CDF_TOLE8(inp->pi_u64); 967 break; 968 default: 969 abort(); 970 } 971 return 1; 972 } 973 974 int 975 cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, 976 uint32_t offs, cdf_property_info_t **info, size_t *count, size_t *maxcount) 977 { 978 const cdf_section_header_t *shp; 979 cdf_section_header_t sh; 980 const uint8_t *p, *q, *e; 981 size_t i, o4, nelements, j, slen, left; 982 cdf_property_info_t *inp; 983 984 if (offs > UINT32_MAX / 4) { 985 errno = EFTYPE; 986 goto out; 987 } 988 shp = CAST(const cdf_section_header_t *, 989 cdf_offset(sst->sst_tab, offs)); 990 if (cdf_check_stream_offset(sst, h, shp, sizeof(*shp), __LINE__) == -1) 991 goto out; 992 sh.sh_len = CDF_TOLE4(shp->sh_len); 993 if (sh.sh_len > CDF_SHLEN_LIMIT) { 994 errno = EFTYPE; 995 goto out; 996 } 997 998 if (cdf_check_stream_offset(sst, h, shp, sh.sh_len, __LINE__) == -1) 999 goto out; 1000 1001 sh.sh_properties = CDF_TOLE4(shp->sh_properties); 1002 DPRINTF(("section len: %u properties %u\n", sh.sh_len, 1003 sh.sh_properties)); 1004 if (sh.sh_properties > CDF_PROP_LIMIT) 1005 goto out; 1006 inp = cdf_grow_info(info, maxcount, sh.sh_properties); 1007 if (inp == NULL) 1008 goto out; 1009 inp += *count; 1010 *count += sh.sh_properties; 1011 p = CAST(const uint8_t *, cdf_offset(sst->sst_tab, offs + sizeof(sh))); 1012 e = CAST(const uint8_t *, cdf_offset(shp, sh.sh_len)); 1013 if (p >= e || cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1) 1014 goto out; 1015 1016 for (i = 0; i < sh.sh_properties; i++) { 1017 if ((q = cdf_get_property_info_pos(sst, h, p, e, i)) == NULL) 1018 goto out; 1019 inp[i].pi_id = CDF_GETUINT32(p, i << 1); 1020 left = CAST(size_t, e - q); 1021 if (left < sizeof(uint32_t)) { 1022 DPRINTF(("short info (no type)_\n")); 1023 goto out; 1024 } 1025 inp[i].pi_type = CDF_GETUINT32(q, 0); 1026 DPRINTF(("%" SIZE_T_FORMAT "u) id=%#x type=%#x offs=%#tx,%#x\n", 1027 i, inp[i].pi_id, inp[i].pi_type, q - p, offs)); 1028 if (inp[i].pi_type & CDF_VECTOR) { 1029 if (left < sizeof(uint32_t) * 2) { 1030 DPRINTF(("missing CDF_VECTOR length\n")); 1031 goto out; 1032 } 1033 nelements = CDF_GETUINT32(q, 1); 1034 if (nelements > CDF_ELEMENT_LIMIT || nelements == 0) { 1035 DPRINTF(("CDF_VECTOR with nelements == %" 1036 SIZE_T_FORMAT "u\n", nelements)); 1037 goto out; 1038 } 1039 slen = 2; 1040 } else { 1041 nelements = 1; 1042 slen = 1; 1043 } 1044 o4 = slen * sizeof(uint32_t); 1045 if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED)) 1046 goto unknown; 1047 switch (inp[i].pi_type & CDF_TYPEMASK) { 1048 case CDF_NULL: 1049 case CDF_EMPTY: 1050 break; 1051 case CDF_SIGNED16: 1052 if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int16_t))) 1053 goto unknown; 1054 break; 1055 case CDF_SIGNED32: 1056 case CDF_BOOL: 1057 case CDF_UNSIGNED32: 1058 case CDF_FLOAT: 1059 if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int32_t))) 1060 goto unknown; 1061 break; 1062 case CDF_SIGNED64: 1063 case CDF_UNSIGNED64: 1064 case CDF_DOUBLE: 1065 case CDF_FILETIME: 1066 if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int64_t))) 1067 goto unknown; 1068 break; 1069 case CDF_LENGTH32_STRING: 1070 case CDF_LENGTH32_WSTRING: 1071 if (nelements > 1) { 1072 size_t nelem = inp - *info; 1073 inp = cdf_grow_info(info, maxcount, nelements); 1074 if (inp == NULL) 1075 goto out; 1076 inp += nelem; 1077 } 1078 for (j = 0; j < nelements && i < sh.sh_properties; 1079 j++, i++) 1080 { 1081 uint32_t l; 1082 1083 if (o4 + sizeof(uint32_t) > left) 1084 goto out; 1085 1086 l = CDF_GETUINT32(q, slen); 1087 o4 += sizeof(uint32_t); 1088 if (o4 + l > left) 1089 goto out; 1090 1091 inp[i].pi_str.s_len = l; 1092 inp[i].pi_str.s_buf = CAST(const char *, 1093 CAST(const void *, &q[o4])); 1094 1095 DPRINTF(("o=%" SIZE_T_FORMAT "u l=%d(%" 1096 SIZE_T_FORMAT "u), t=%" SIZE_T_FORMAT 1097 "u s=%.*s\n", o4, l, 1098 CDF_ROUND(l, sizeof(l)), 1099 left, (int)l, inp[i].pi_str.s_buf)); 1100 1101 if (l & 1) 1102 l++; 1103 1104 slen += l >> 1; 1105 o4 = slen * sizeof(uint32_t); 1106 } 1107 i--; 1108 break; 1109 case CDF_CLIPBOARD: 1110 if (inp[i].pi_type & CDF_VECTOR) 1111 goto unknown; 1112 break; 1113 default: 1114 unknown: 1115 memset(&inp[i].pi_val, 0, sizeof(inp[i].pi_val)); 1116 DPRINTF(("Don't know how to deal with %#x\n", 1117 inp[i].pi_type)); 1118 break; 1119 } 1120 } 1121 return 0; 1122 out: 1123 free(*info); 1124 *info = NULL; 1125 *count = 0; 1126 *maxcount = 0; 1127 errno = EFTYPE; 1128 return -1; 1129 } 1130 1131 int 1132 cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h, 1133 cdf_summary_info_header_t *ssi, cdf_property_info_t **info, size_t *count) 1134 { 1135 size_t maxcount; 1136 const cdf_summary_info_header_t *si = 1137 CAST(const cdf_summary_info_header_t *, sst->sst_tab); 1138 const cdf_section_declaration_t *sd = 1139 CAST(const cdf_section_declaration_t *, RCAST(const void *, 1140 RCAST(const char *, sst->sst_tab) 1141 + CDF_SECTION_DECLARATION_OFFSET)); 1142 1143 if (cdf_check_stream_offset(sst, h, si, sizeof(*si), __LINE__) == -1 || 1144 cdf_check_stream_offset(sst, h, sd, sizeof(*sd), __LINE__) == -1) 1145 return -1; 1146 ssi->si_byte_order = CDF_TOLE2(si->si_byte_order); 1147 ssi->si_os_version = CDF_TOLE2(si->si_os_version); 1148 ssi->si_os = CDF_TOLE2(si->si_os); 1149 ssi->si_class = si->si_class; 1150 cdf_swap_class(&ssi->si_class); 1151 ssi->si_count = CDF_TOLE4(si->si_count); 1152 *count = 0; 1153 maxcount = 0; 1154 *info = NULL; 1155 if (cdf_read_property_info(sst, h, CDF_TOLE4(sd->sd_offset), info, 1156 count, &maxcount) == -1) 1157 return -1; 1158 return 0; 1159 } 1160 1161 1162 #define extract_catalog_field(t, f, l) \ 1163 if (b + l + sizeof(cep->f) > eb) { \ 1164 cep->ce_namlen = 0; \ 1165 break; \ 1166 } \ 1167 memcpy(&cep->f, b + (l), sizeof(cep->f)); \ 1168 ce[i].f = CAST(t, CDF_TOLE(cep->f)) 1169 1170 int 1171 cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst, 1172 cdf_catalog_t **cat) 1173 { 1174 size_t ss = cdf_check_stream(sst, h); 1175 const char *b = CAST(const char *, sst->sst_tab); 1176 const char *nb, *eb = b + ss * sst->sst_len; 1177 size_t nr, i, j, k; 1178 cdf_catalog_entry_t *ce; 1179 uint16_t reclen; 1180 const uint16_t *np; 1181 1182 for (nr = 0;; nr++) { 1183 memcpy(&reclen, b, sizeof(reclen)); 1184 reclen = CDF_TOLE2(reclen); 1185 if (reclen == 0) 1186 break; 1187 b += reclen; 1188 if (b > eb) 1189 break; 1190 } 1191 if (nr == 0) 1192 return -1; 1193 nr--; 1194 *cat = CAST(cdf_catalog_t *, 1195 CDF_MALLOC(sizeof(cdf_catalog_t) + nr * sizeof(*ce))); 1196 if (*cat == NULL) 1197 return -1; 1198 ce = (*cat)->cat_e; 1199 memset(ce, 0, nr * sizeof(*ce)); 1200 b = CAST(const char *, sst->sst_tab); 1201 for (j = i = 0; i < nr; b += reclen) { 1202 cdf_catalog_entry_t *cep = &ce[j]; 1203 uint16_t rlen; 1204 1205 extract_catalog_field(uint16_t, ce_namlen, 0); 1206 extract_catalog_field(uint16_t, ce_num, 4); 1207 extract_catalog_field(uint64_t, ce_timestamp, 8); 1208 reclen = cep->ce_namlen; 1209 1210 if (reclen < 14) { 1211 cep->ce_namlen = 0; 1212 continue; 1213 } 1214 1215 cep->ce_namlen = __arraycount(cep->ce_name) - 1; 1216 rlen = reclen - 14; 1217 if (cep->ce_namlen > rlen) 1218 cep->ce_namlen = rlen; 1219 1220 np = CAST(const uint16_t *, CAST(const void *, (b + 16))); 1221 nb = CAST(const char *, CAST(const void *, 1222 (np + cep->ce_namlen))); 1223 if (nb > eb) { 1224 cep->ce_namlen = 0; 1225 break; 1226 } 1227 1228 for (k = 0; k < cep->ce_namlen; k++) 1229 cep->ce_name[k] = np[k]; /* XXX: CDF_TOLE2? */ 1230 cep->ce_name[cep->ce_namlen] = 0; 1231 j = i; 1232 i++; 1233 } 1234 (*cat)->cat_num = j; 1235 return 0; 1236 } 1237 1238 int 1239 cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id) 1240 { 1241 return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-" 1242 "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0], 1243 id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0], 1244 id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4], 1245 id->cl_six[5]); 1246 } 1247 1248 static const struct { 1249 uint32_t v; 1250 const char *n; 1251 } vn[] = { 1252 { CDF_PROPERTY_CODE_PAGE, "Code page" }, 1253 { CDF_PROPERTY_TITLE, "Title" }, 1254 { CDF_PROPERTY_SUBJECT, "Subject" }, 1255 { CDF_PROPERTY_AUTHOR, "Author" }, 1256 { CDF_PROPERTY_KEYWORDS, "Keywords" }, 1257 { CDF_PROPERTY_COMMENTS, "Comments" }, 1258 { CDF_PROPERTY_TEMPLATE, "Template" }, 1259 { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" }, 1260 { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" }, 1261 { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" }, 1262 { CDF_PROPERTY_LAST_PRINTED, "Last Printed" }, 1263 { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" }, 1264 { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" }, 1265 { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" }, 1266 { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" }, 1267 { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" }, 1268 { CDF_PROPERTY_THUMBNAIL, "Thumbnail" }, 1269 { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" }, 1270 { CDF_PROPERTY_SECURITY, "Security" }, 1271 { CDF_PROPERTY_LOCALE_ID, "Locale ID" }, 1272 }; 1273 1274 int 1275 cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p) 1276 { 1277 size_t i; 1278 1279 for (i = 0; i < __arraycount(vn); i++) 1280 if (vn[i].v == p) 1281 return snprintf(buf, bufsiz, "%s", vn[i].n); 1282 return snprintf(buf, bufsiz, "%#x", p); 1283 } 1284 1285 int 1286 cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts) 1287 { 1288 int len = 0; 1289 int days, hours, mins, secs; 1290 1291 ts /= CDF_TIME_PREC; 1292 secs = CAST(int, ts % 60); 1293 ts /= 60; 1294 mins = CAST(int, ts % 60); 1295 ts /= 60; 1296 hours = CAST(int, ts % 24); 1297 ts /= 24; 1298 days = CAST(int, ts); 1299 1300 if (days) { 1301 len += snprintf(buf + len, bufsiz - len, "%dd+", days); 1302 if (CAST(size_t, len) >= bufsiz) 1303 return len; 1304 } 1305 1306 if (days || hours) { 1307 len += snprintf(buf + len, bufsiz - len, "%.2d:", hours); 1308 if (CAST(size_t, len) >= bufsiz) 1309 return len; 1310 } 1311 1312 len += snprintf(buf + len, bufsiz - len, "%.2d:", mins); 1313 if (CAST(size_t, len) >= bufsiz) 1314 return len; 1315 1316 len += snprintf(buf + len, bufsiz - len, "%.2d", secs); 1317 return len; 1318 } 1319 1320 char * 1321 cdf_u16tos8(char *buf, size_t len, const uint16_t *p) 1322 { 1323 size_t i; 1324 for (i = 0; i < len && p[i]; i++) 1325 buf[i] = CAST(char, p[i]); 1326 buf[i] = '\0'; 1327 return buf; 1328 } 1329 1330 #ifdef CDF_DEBUG 1331 void 1332 cdf_dump_header(const cdf_header_t *h) 1333 { 1334 size_t i; 1335 1336 #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b) 1337 #define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \ 1338 h->h_ ## b, 1 << h->h_ ## b) 1339 DUMP("%d", revision); 1340 DUMP("%d", version); 1341 DUMP("%#x", byte_order); 1342 DUMP2("%d", sec_size_p2); 1343 DUMP2("%d", short_sec_size_p2); 1344 DUMP("%d", num_sectors_in_sat); 1345 DUMP("%d", secid_first_directory); 1346 DUMP("%d", min_size_standard_stream); 1347 DUMP("%d", secid_first_sector_in_short_sat); 1348 DUMP("%d", num_sectors_in_short_sat); 1349 DUMP("%d", secid_first_sector_in_master_sat); 1350 DUMP("%d", num_sectors_in_master_sat); 1351 for (i = 0; i < __arraycount(h->h_master_sat); i++) { 1352 if (h->h_master_sat[i] == CDF_SECID_FREE) 1353 break; 1354 (void)fprintf(stderr, "%35.35s[%.3" SIZE_T_FORMAT "u] = %d\n", 1355 "master_sat", i, h->h_master_sat[i]); 1356 } 1357 } 1358 1359 void 1360 cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size) 1361 { 1362 size_t i, j, s = size / sizeof(cdf_secid_t); 1363 1364 for (i = 0; i < sat->sat_len; i++) { 1365 (void)fprintf(stderr, "%s[%" SIZE_T_FORMAT "u]:\n%.6" 1366 SIZE_T_FORMAT "u: ", prefix, i, i * s); 1367 for (j = 0; j < s; j++) { 1368 (void)fprintf(stderr, "%5d, ", 1369 CDF_TOLE4(sat->sat_tab[s * i + j])); 1370 if ((j + 1) % 10 == 0) 1371 (void)fprintf(stderr, "\n%.6" SIZE_T_FORMAT 1372 "u: ", i * s + j + 1); 1373 } 1374 (void)fprintf(stderr, "\n"); 1375 } 1376 } 1377 1378 void 1379 cdf_dump(const void *v, size_t len) 1380 { 1381 size_t i, j; 1382 const unsigned char *p = v; 1383 char abuf[16]; 1384 1385 (void)fprintf(stderr, "%.4x: ", 0); 1386 for (i = 0, j = 0; i < len; i++, p++) { 1387 (void)fprintf(stderr, "%.2x ", *p); 1388 abuf[j++] = isprint(*p) ? *p : '.'; 1389 if (j == 16) { 1390 j = 0; 1391 abuf[15] = '\0'; 1392 (void)fprintf(stderr, "%s\n%.4" SIZE_T_FORMAT "x: ", 1393 abuf, i + 1); 1394 } 1395 } 1396 (void)fprintf(stderr, "\n"); 1397 } 1398 1399 void 1400 cdf_dump_stream(const cdf_stream_t *sst) 1401 { 1402 size_t ss = sst->sst_ss; 1403 cdf_dump(sst->sst_tab, ss * sst->sst_len); 1404 } 1405 1406 void 1407 cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h, 1408 const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, 1409 const cdf_dir_t *dir) 1410 { 1411 size_t i, j; 1412 cdf_directory_t *d; 1413 char name[__arraycount(d->d_name)]; 1414 cdf_stream_t scn; 1415 struct timespec ts; 1416 1417 static const char *types[] = { "empty", "user storage", 1418 "user stream", "lockbytes", "property", "root storage" }; 1419 1420 for (i = 0; i < dir->dir_len; i++) { 1421 char buf[26]; 1422 d = &dir->dir_tab[i]; 1423 for (j = 0; j < sizeof(name); j++) 1424 name[j] = (char)CDF_TOLE2(d->d_name[j]); 1425 (void)fprintf(stderr, "Directory %" SIZE_T_FORMAT "u: %s\n", 1426 i, name); 1427 if (d->d_type < __arraycount(types)) 1428 (void)fprintf(stderr, "Type: %s\n", types[d->d_type]); 1429 else 1430 (void)fprintf(stderr, "Type: %d\n", d->d_type); 1431 (void)fprintf(stderr, "Color: %s\n", 1432 d->d_color ? "black" : "red"); 1433 (void)fprintf(stderr, "Left child: %d\n", d->d_left_child); 1434 (void)fprintf(stderr, "Right child: %d\n", d->d_right_child); 1435 (void)fprintf(stderr, "Flags: %#x\n", d->d_flags); 1436 cdf_timestamp_to_timespec(&ts, d->d_created); 1437 (void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec, buf)); 1438 cdf_timestamp_to_timespec(&ts, d->d_modified); 1439 (void)fprintf(stderr, "Modified %s", 1440 cdf_ctime(&ts.tv_sec, buf)); 1441 (void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector); 1442 (void)fprintf(stderr, "Size %d\n", d->d_size); 1443 switch (d->d_type) { 1444 case CDF_DIR_TYPE_USER_STORAGE: 1445 (void)fprintf(stderr, "Storage: %d\n", d->d_storage); 1446 break; 1447 case CDF_DIR_TYPE_USER_STREAM: 1448 if (sst == NULL) 1449 break; 1450 if (cdf_read_sector_chain(info, h, sat, ssat, sst, 1451 d->d_stream_first_sector, d->d_size, &scn) == -1) { 1452 warn("Can't read stream for %s at %d len %d", 1453 name, d->d_stream_first_sector, d->d_size); 1454 break; 1455 } 1456 cdf_dump_stream(&scn); 1457 free(scn.sst_tab); 1458 break; 1459 default: 1460 break; 1461 } 1462 1463 } 1464 } 1465 1466 void 1467 cdf_dump_property_info(const cdf_property_info_t *info, size_t count) 1468 { 1469 cdf_timestamp_t tp; 1470 struct timespec ts; 1471 char buf[64]; 1472 size_t i, j; 1473 1474 for (i = 0; i < count; i++) { 1475 cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); 1476 (void)fprintf(stderr, "%" SIZE_T_FORMAT "u) %s: ", i, buf); 1477 switch (info[i].pi_type) { 1478 case CDF_NULL: 1479 break; 1480 case CDF_SIGNED16: 1481 (void)fprintf(stderr, "signed 16 [%hd]\n", 1482 info[i].pi_s16); 1483 break; 1484 case CDF_SIGNED32: 1485 (void)fprintf(stderr, "signed 32 [%d]\n", 1486 info[i].pi_s32); 1487 break; 1488 case CDF_UNSIGNED32: 1489 (void)fprintf(stderr, "unsigned 32 [%u]\n", 1490 info[i].pi_u32); 1491 break; 1492 case CDF_FLOAT: 1493 (void)fprintf(stderr, "float [%g]\n", 1494 info[i].pi_f); 1495 break; 1496 case CDF_DOUBLE: 1497 (void)fprintf(stderr, "double [%g]\n", 1498 info[i].pi_d); 1499 break; 1500 case CDF_LENGTH32_STRING: 1501 (void)fprintf(stderr, "string %u [%.*s]\n", 1502 info[i].pi_str.s_len, 1503 info[i].pi_str.s_len, info[i].pi_str.s_buf); 1504 break; 1505 case CDF_LENGTH32_WSTRING: 1506 (void)fprintf(stderr, "string %u [", 1507 info[i].pi_str.s_len); 1508 for (j = 0; j < info[i].pi_str.s_len - 1; j++) 1509 (void)fputc(info[i].pi_str.s_buf[j << 1], stderr); 1510 (void)fprintf(stderr, "]\n"); 1511 break; 1512 case CDF_FILETIME: 1513 tp = info[i].pi_tp; 1514 if (tp < 1000000000000000LL) { 1515 cdf_print_elapsed_time(buf, sizeof(buf), tp); 1516 (void)fprintf(stderr, "timestamp %s\n", buf); 1517 } else { 1518 char tbuf[26]; 1519 cdf_timestamp_to_timespec(&ts, tp); 1520 (void)fprintf(stderr, "timestamp %s", 1521 cdf_ctime(&ts.tv_sec, tbuf)); 1522 } 1523 break; 1524 case CDF_CLIPBOARD: 1525 (void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32); 1526 break; 1527 default: 1528 DPRINTF(("Don't know how to deal with %#x\n", 1529 info[i].pi_type)); 1530 break; 1531 } 1532 } 1533 } 1534 1535 1536 void 1537 cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst) 1538 { 1539 char buf[128]; 1540 cdf_summary_info_header_t ssi; 1541 cdf_property_info_t *info; 1542 size_t count; 1543 1544 (void)&h; 1545 if (cdf_unpack_summary_info(sst, h, &ssi, &info, &count) == -1) 1546 return; 1547 (void)fprintf(stderr, "Endian: %#x\n", ssi.si_byte_order); 1548 (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff, 1549 ssi.si_os_version >> 8); 1550 (void)fprintf(stderr, "Os %d\n", ssi.si_os); 1551 cdf_print_classid(buf, sizeof(buf), &ssi.si_class); 1552 (void)fprintf(stderr, "Class %s\n", buf); 1553 (void)fprintf(stderr, "Count %d\n", ssi.si_count); 1554 cdf_dump_property_info(info, count); 1555 free(info); 1556 } 1557 1558 1559 void 1560 cdf_dump_catalog(const cdf_header_t *h, const cdf_stream_t *sst) 1561 { 1562 cdf_catalog_t *cat; 1563 cdf_unpack_catalog(h, sst, &cat); 1564 const cdf_catalog_entry_t *ce = cat->cat_e; 1565 struct timespec ts; 1566 char tbuf[64], sbuf[256]; 1567 size_t i; 1568 1569 printf("Catalog:\n"); 1570 for (i = 0; i < cat->cat_num; i++) { 1571 cdf_timestamp_to_timespec(&ts, ce[i].ce_timestamp); 1572 printf("\t%d %s %s", ce[i].ce_num, 1573 cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name), 1574 cdf_ctime(&ts.tv_sec, tbuf)); 1575 } 1576 free(cat); 1577 } 1578 1579 #endif 1580 1581 #ifdef TEST 1582 int 1583 main(int argc, char *argv[]) 1584 { 1585 int i; 1586 cdf_header_t h; 1587 cdf_sat_t sat, ssat; 1588 cdf_stream_t sst, scn; 1589 cdf_dir_t dir; 1590 cdf_info_t info; 1591 const cdf_directory_t *root; 1592 #ifdef __linux__ 1593 #define getprogname() __progname 1594 extern char *__progname; 1595 #endif 1596 if (argc < 2) { 1597 (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname()); 1598 return -1; 1599 } 1600 1601 info.i_buf = NULL; 1602 info.i_len = 0; 1603 for (i = 1; i < argc; i++) { 1604 if ((info.i_fd = open(argv[1], O_RDONLY)) == -1) 1605 err(EXIT_FAILURE, "Cannot open `%s'", argv[1]); 1606 1607 if (cdf_read_header(&info, &h) == -1) 1608 err(EXIT_FAILURE, "Cannot read header"); 1609 #ifdef CDF_DEBUG 1610 cdf_dump_header(&h); 1611 #endif 1612 1613 if (cdf_read_sat(&info, &h, &sat) == -1) 1614 err(EXIT_FAILURE, "Cannot read sat"); 1615 #ifdef CDF_DEBUG 1616 cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); 1617 #endif 1618 1619 if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1) 1620 err(EXIT_FAILURE, "Cannot read ssat"); 1621 #ifdef CDF_DEBUG 1622 cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); 1623 #endif 1624 1625 if (cdf_read_dir(&info, &h, &sat, &dir) == -1) 1626 err(EXIT_FAILURE, "Cannot read dir"); 1627 1628 if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root) 1629 == -1) 1630 err(EXIT_FAILURE, "Cannot read short stream"); 1631 #ifdef CDF_DEBUG 1632 cdf_dump_stream(&sst); 1633 #endif 1634 1635 #ifdef CDF_DEBUG 1636 cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); 1637 #endif 1638 1639 1640 if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, 1641 &scn) == -1) 1642 warn("Cannot read summary info"); 1643 #ifdef CDF_DEBUG 1644 else 1645 cdf_dump_summary_info(&h, &scn); 1646 #endif 1647 if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, 1648 &dir, "Catalog", &scn) == -1) 1649 warn("Cannot read catalog"); 1650 #ifdef CDF_DEBUG 1651 else 1652 cdf_dump_catalog(&h, &scn); 1653 #endif 1654 1655 (void)close(info.i_fd); 1656 } 1657 1658 return 0; 1659 } 1660 #endif 1661