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