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