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