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