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