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