1 /*- 2 * Copyright (c) 2008, 2016 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 #include "file.h" 27 28 #ifndef lint 29 FILE_RCSID("@(#)$File: readcdf.c,v 1.81 2026/02/04 14:56:28 christos Exp $") 30 #endif 31 32 #include <assert.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <time.h> 37 #include <ctype.h> 38 39 #include "cdf.h" 40 #include "magic.h" 41 42 #define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0) 43 44 static const struct nv { 45 const char *pattern; 46 const char *mime; 47 } app2mime[] = { 48 { "Word", "msword", }, 49 { "Excel", "vnd.ms-excel", }, 50 { "Powerpoint", "vnd.ms-powerpoint", }, 51 { "Crystal Reports", "x-rpt", }, 52 { "Advanced Installer", "vnd.ms-msi", }, 53 { "InstallShield", "vnd.ms-msi", }, 54 { "Microsoft Patch Compiler", "vnd.ms-msi", }, 55 { "NAnt", "vnd.ms-msi", }, 56 { "Windows Installer", "vnd.ms-msi", }, 57 { NULL, NULL, }, 58 }, name2mime[] = { 59 { "Book", "vnd.ms-excel", }, 60 { "Workbook", "vnd.ms-excel", }, 61 { "WordDocument", "msword", }, 62 { "PowerPoint", "vnd.ms-powerpoint", }, 63 { "DigitalSignature", "vnd.ms-msi", }, 64 { NULL, NULL, }, 65 }, name2desc[] = { 66 { "Book", "Microsoft Excel", }, 67 { "Workbook", "Microsoft Excel", }, 68 { "WordDocument", "Microsoft Word", }, 69 { "PowerPoint", "Microsoft PowerPoint", }, 70 { "DigitalSignature", "Microsoft Installer", }, 71 { NULL, NULL, }, 72 }; 73 74 static const struct cv { 75 uint64_t clsid[2]; 76 const char *mime; 77 } clsid2mime[] = { 78 { 79 { 0x00000000000c1084ULL, 0x46000000000000c0ULL }, 80 "x-msi", 81 }, 82 { { 0, 0 }, 83 NULL, 84 }, 85 }, clsid2desc[] = { 86 { 87 { 0x00000000000c1084ULL, 0x46000000000000c0ULL }, 88 "MSI Installer", 89 }, 90 { { 0, 0 }, 91 NULL, 92 }, 93 }; 94 95 file_private const char * 96 cdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv) 97 { 98 size_t i; 99 for (i = 0; cv[i].mime != NULL; i++) { 100 if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1]) 101 return cv[i].mime; 102 } 103 #ifdef CDF_DEBUG 104 fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0], 105 clsid[1]); 106 #endif 107 return NULL; 108 } 109 110 file_private const char * 111 cdf_app_to_mime(const char *vbuf, const struct nv *nv) 112 { 113 size_t i; 114 const char *rv = NULL; 115 #ifdef USE_C_LOCALE 116 locale_t old_lc_ctype, c_lc_ctype; 117 118 c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); 119 assert(c_lc_ctype != NULL); 120 old_lc_ctype = uselocale(c_lc_ctype); 121 assert(old_lc_ctype != NULL); 122 #else 123 char *old_lc_ctype = setlocale(LC_CTYPE, NULL); 124 assert(old_lc_ctype != NULL); 125 old_lc_ctype = strdup(old_lc_ctype); 126 assert(old_lc_ctype != NULL); 127 (void)setlocale(LC_CTYPE, "C"); 128 #endif 129 for (i = 0; nv[i].pattern != NULL; i++) 130 if (strcasestr(vbuf, nv[i].pattern) != NULL) { 131 rv = nv[i].mime; 132 break; 133 } 134 #ifdef CDF_DEBUG 135 fprintf(stderr, "unknown app %s\n", vbuf); 136 #endif 137 #ifdef USE_C_LOCALE 138 (void)uselocale(old_lc_ctype); 139 freelocale(c_lc_ctype); 140 #else 141 (void)setlocale(LC_CTYPE, old_lc_ctype); 142 free(old_lc_ctype); 143 #endif 144 return rv; 145 } 146 147 file_private int 148 cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, 149 size_t count, const cdf_directory_t *root_storage) 150 { 151 size_t i; 152 cdf_timestamp_t tp; 153 struct timespec ts; 154 char buf[64]; 155 const char *str = NULL; 156 const char *s, *e; 157 int len; 158 159 if (!NOTMIME(ms) && root_storage) 160 str = cdf_clsid_to_mime(root_storage->d_storage_uuid, 161 clsid2mime); 162 163 for (i = 0; i < count; i++) { 164 cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); 165 switch (info[i].pi_type) { 166 case CDF_NULL: 167 break; 168 case CDF_SIGNED16: 169 if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, 170 info[i].pi_s16) == -1) 171 return -1; 172 break; 173 case CDF_SIGNED32: 174 if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, 175 info[i].pi_s32) == -1) 176 return -1; 177 break; 178 case CDF_UNSIGNED32: 179 if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, 180 info[i].pi_u32) == -1) 181 return -1; 182 break; 183 case CDF_FLOAT: 184 if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, 185 info[i].pi_f) == -1) 186 return -1; 187 break; 188 case CDF_DOUBLE: 189 if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, 190 info[i].pi_d) == -1) 191 return -1; 192 break; 193 case CDF_LENGTH32_STRING: 194 case CDF_LENGTH32_WSTRING: 195 len = info[i].pi_str.s_len; 196 if (len > 1) { 197 char vbuf[1024]; 198 size_t j, k = 1; 199 200 if (info[i].pi_type == CDF_LENGTH32_WSTRING) 201 k++; 202 s = info[i].pi_str.s_buf; 203 e = info[i].pi_str.s_buf + len; 204 for (j = 0; s < e && j < sizeof(vbuf) 205 && len--; s += k) { 206 if (*s == '\0') 207 break; 208 if (isprint(CAST(unsigned char, *s))) 209 vbuf[j++] = *s; 210 } 211 if (j == sizeof(vbuf)) 212 --j; 213 vbuf[j] = '\0'; 214 if (NOTMIME(ms)) { 215 if (vbuf[0]) { 216 if (file_printf(ms, ", %s: %s", 217 buf, vbuf) == -1) 218 return -1; 219 } 220 } else if (str == NULL && info[i].pi_id == 221 CDF_PROPERTY_NAME_OF_APPLICATION) { 222 str = cdf_app_to_mime(vbuf, app2mime); 223 #ifdef CDF_DEBUG 224 fprintf(stderr, "Found property " 225 "application name = \"%s\" " 226 "(mime=%s)\n", vbuf, str); 227 #endif 228 } 229 } 230 break; 231 case CDF_FILETIME: 232 tp = info[i].pi_tp; 233 if (tp != 0) { 234 char tbuf[64]; 235 if (tp < 1000000000000000LL) { 236 cdf_print_elapsed_time(tbuf, 237 sizeof(tbuf), tp); 238 if (NOTMIME(ms) && file_printf(ms, 239 ", %s: %s", buf, tbuf) == -1) 240 return -1; 241 } else { 242 char *c, *ec; 243 cdf_timestamp_to_timespec(&ts, tp); 244 c = cdf_ctime(&ts.tv_sec, tbuf); 245 if (c != NULL && 246 (ec = strchr(c, '\n')) != NULL) 247 *ec = '\0'; 248 249 if (NOTMIME(ms) && file_printf(ms, 250 ", %s: %s", buf, c) == -1) 251 return -1; 252 } 253 } 254 break; 255 case CDF_CLIPBOARD: 256 break; 257 default: 258 return -1; 259 } 260 } 261 if (ms->flags & MAGIC_MIME_TYPE) { 262 if (str == NULL) 263 return 0; 264 if (file_printf(ms, "application/%s", str) == -1) 265 return -1; 266 } 267 return 1; 268 } 269 270 file_private int 271 cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h, 272 const cdf_stream_t *sst) 273 { 274 cdf_catalog_t *cat; 275 size_t i; 276 char buf[256]; 277 cdf_catalog_entry_t *ce; 278 279 if (NOTMIME(ms)) { 280 if (file_printf(ms, "Microsoft Thumbs.db [") == -1) 281 return -1; 282 if (cdf_unpack_catalog(h, sst, &cat) == -1) 283 return -1; 284 ce = cat->cat_e; 285 /* skip first entry since it has a , or paren */ 286 for (i = 1; i < cat->cat_num; i++) 287 if (file_printf(ms, "%s%s", 288 cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name), 289 i == cat->cat_num - 1 ? "]" : ", ") == -1) { 290 free(cat); 291 return -1; 292 } 293 free(cat); 294 } else if (ms->flags & MAGIC_MIME_TYPE) { 295 if (file_printf(ms, "application/CDFV2") == -1) 296 return -1; 297 } 298 return 1; 299 } 300 301 file_private int 302 cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, 303 const cdf_stream_t *sst, const cdf_directory_t *root_storage) 304 { 305 cdf_summary_info_header_t si; 306 cdf_property_info_t *info; 307 size_t count; 308 int m; 309 310 if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1) 311 return -1; 312 313 if (NOTMIME(ms)) { 314 const char *str; 315 316 if (file_printf(ms, "Composite Document File V2 Document") 317 == -1) 318 return -1; 319 320 if (file_printf(ms, ", %s Endian", 321 si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) 322 return -2; 323 switch (si.si_os) { 324 case 2: 325 if (file_printf(ms, ", Os: Windows, Version %d.%d", 326 si.si_os_version & 0xff, 327 CAST(uint32_t, si.si_os_version) >> 8) == -1) 328 return -2; 329 break; 330 case 1: 331 if (file_printf(ms, ", Os: MacOS, Version %d.%d", 332 CAST(uint32_t, si.si_os_version) >> 8, 333 si.si_os_version & 0xff) == -1) 334 return -2; 335 break; 336 default: 337 if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, 338 si.si_os_version & 0xff, 339 CAST(uint32_t, si.si_os_version) >> 8) == -1) 340 return -2; 341 break; 342 } 343 if (root_storage) { 344 str = cdf_clsid_to_mime(root_storage->d_storage_uuid, 345 clsid2desc); 346 if (str) { 347 if (file_printf(ms, ", %s", str) == -1) 348 return -2; 349 } 350 } 351 } 352 353 m = cdf_file_property_info(ms, info, count, root_storage); 354 free(info); 355 356 return m == -1 ? -2 : m; 357 } 358 359 #ifdef notdef 360 file_private char * 361 format_clsid(char *buf, size_t len, const uint64_t uuid[2]) { 362 snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4" 363 PRIx64 "-%.12" PRIx64, 364 (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL, 365 (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL, 366 (uuid[0] >> 0) & (uint64_t)0x0000000000000ffffULL, 367 (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL, 368 (uuid[1] >> 0) & (uint64_t)0x0000fffffffffffffULL); 369 return buf; 370 } 371 #endif 372 373 file_private int 374 cdf_file_catalog_info(struct magic_set *ms, const cdf_info_t *info, 375 const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat, 376 const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn) 377 { 378 int i; 379 380 if ((i = cdf_read_user_stream(info, h, sat, ssat, sst, 381 dir, "Catalog", scn)) == -1) 382 return i; 383 #ifdef CDF_DEBUG 384 cdf_dump_catalog(h, scn); 385 #endif 386 if ((i = cdf_file_catalog(ms, h, scn)) == -1) 387 return -1; 388 return i; 389 } 390 391 file_private int 392 cdf_check_summary_info(struct magic_set *ms, const cdf_info_t *info, 393 const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat, 394 const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn, 395 const cdf_directory_t *root_storage, const char **expn) 396 { 397 int i; 398 const char *str = NULL; 399 cdf_directory_t *d; 400 char name[__arraycount(d->d_name)]; 401 size_t j, k; 402 403 #ifdef CDF_DEBUG 404 cdf_dump_summary_info(h, scn); 405 #endif 406 if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) { 407 *expn = "Can't expand summary_info"; 408 return i; 409 } 410 if (i == 1) 411 return i; 412 for (j = 0; str == NULL && j < dir->dir_len; j++) { 413 d = &dir->dir_tab[j]; 414 for (k = 0; k < sizeof(name); k++) 415 name[k] = CAST(char, cdf_tole2(d->d_name[k])); 416 str = cdf_app_to_mime(name, 417 NOTMIME(ms) ? name2desc : name2mime); 418 } 419 if (NOTMIME(ms)) { 420 if (str != NULL) { 421 if (file_printf(ms, "%s", str) == -1) 422 return -1; 423 i = 1; 424 } 425 } else if (ms->flags & MAGIC_MIME_TYPE) { 426 if (str == NULL) 427 str = "vnd.ms-office"; 428 if (file_printf(ms, "application/%s", str) == -1) 429 return -1; 430 i = 1; 431 } 432 if (i <= 0) { 433 i = cdf_file_catalog_info(ms, info, h, sat, ssat, sst, 434 dir, scn); 435 } 436 return i; 437 } 438 439 file_private struct sinfo { 440 const char *name; 441 const char *mime; 442 const char *sections[5]; 443 const int types[5]; 444 } sectioninfo[] = { 445 { "Encrypted", "encrypted", 446 { 447 "EncryptedPackage", "EncryptedSummary", 448 NULL, NULL, NULL, 449 }, 450 { 451 CDF_DIR_TYPE_USER_STREAM, 452 CDF_DIR_TYPE_USER_STREAM, 453 0, 0, 0, 454 455 }, 456 }, 457 { "QuickBooks", "quickbooks", 458 { 459 #if 0 460 "TaxForms", "PDFTaxForms", "modulesInBackup", 461 #endif 462 "mfbu_header", NULL, NULL, NULL, NULL, 463 }, 464 { 465 #if 0 466 CDF_DIR_TYPE_USER_STORAGE, 467 CDF_DIR_TYPE_USER_STORAGE, 468 CDF_DIR_TYPE_USER_STREAM, 469 #endif 470 CDF_DIR_TYPE_USER_STREAM, 471 0, 0, 0, 0 472 }, 473 }, 474 { "Microsoft Excel", "vnd.ms-excel", 475 { 476 "Book", "Workbook", NULL, NULL, NULL, 477 }, 478 { 479 CDF_DIR_TYPE_USER_STREAM, 480 CDF_DIR_TYPE_USER_STREAM, 481 0, 0, 0, 482 }, 483 }, 484 { "Microsoft Word", "msword", 485 { 486 "WordDocument", NULL, NULL, NULL, NULL, 487 }, 488 { 489 CDF_DIR_TYPE_USER_STREAM, 490 0, 0, 0, 0, 491 }, 492 }, 493 { "Microsoft PowerPoint", "vnd.ms-powerpoint", 494 { 495 "PowerPoint Document", NULL, NULL, NULL, NULL, 496 }, 497 { 498 CDF_DIR_TYPE_USER_STREAM, 499 0, 0, 0, 0, 500 }, 501 }, 502 { "Microsoft Outlook Message", "vnd.ms-outlook", 503 { 504 "__properties_version1.0", 505 "__recip_version1.0_#00000000", 506 NULL, NULL, NULL, 507 }, 508 { 509 CDF_DIR_TYPE_USER_STREAM, 510 CDF_DIR_TYPE_USER_STORAGE, 511 0, 0, 0, 512 }, 513 }, 514 }; 515 516 file_private int 517 cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir) 518 { 519 size_t sd, i, j; 520 uint16_t *dir_name; 521 int dir_type; 522 const char* section_name; 523 524 for (i = 0; i < dir->dir_len; i++) { 525 dir_name = dir->dir_tab[i].d_name; 526 dir_type = dir->dir_tab[i].d_type; 527 528 for (sd = 0; sd < __arraycount(sectioninfo); sd++) { 529 const struct sinfo *si = §ioninfo[sd]; 530 for (j = 0; si->sections[j]; j++) { 531 if (si->sections[j] == NULL) 532 continue; 533 section_name = si->sections[j]; 534 if (si->types[j] != dir_type || 535 cdf_namecmp(section_name, dir_name, 536 strlen(section_name) + 1) != 0) 537 continue; 538 #ifdef CDF_DEBUG 539 fprintf(stderr, "Matching directory %" 540 SIZE_T_FORMAT 541 "u with expected name \"%s\"\n", 542 i, section_name); 543 #endif 544 if (NOTMIME(ms)) { 545 if (file_printf(ms, "CDFV2 %s", 546 si->name) == -1) 547 return -1; 548 } else if (ms->flags & MAGIC_MIME_TYPE) { 549 if (file_printf(ms, "application/%s", 550 si->mime) == -1) 551 return -1; 552 } 553 return 1; 554 } 555 } 556 } 557 return -1; 558 } 559 560 file_protected int 561 file_trycdf(struct magic_set *ms, const struct buffer *b) 562 { 563 int fd = b->fd; 564 const unsigned char *buf = CAST(const unsigned char *, b->fbuf); 565 size_t nbytes = b->flen; 566 cdf_info_t info; 567 cdf_header_t h; 568 cdf_sat_t sat, ssat; 569 cdf_stream_t sst, scn; 570 cdf_dir_t dir; 571 int i; 572 const char *expn = ""; 573 const cdf_directory_t *root_storage; 574 575 scn.sst_tab = NULL; 576 info.i_fd = fd; 577 info.i_buf = buf; 578 info.i_len = nbytes; 579 if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) 580 return 0; 581 if (cdf_read_header(&info, &h) == -1) 582 return 0; 583 #ifdef CDF_DEBUG 584 cdf_dump_header(&h); 585 #endif 586 587 if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { 588 expn = "Can't read SAT"; 589 goto out0; 590 } 591 #ifdef CDF_DEBUG 592 cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); 593 #endif 594 595 if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { 596 expn = "Can't read SSAT"; 597 goto out1; 598 } 599 #ifdef CDF_DEBUG 600 cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); 601 #endif 602 603 if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { 604 expn = "Can't read directory"; 605 goto out2; 606 } 607 608 if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst, 609 &root_storage)) == -1) { 610 expn = "Cannot read short stream"; 611 goto out3; 612 } 613 #ifdef CDF_DEBUG 614 cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); 615 #endif 616 #ifdef notdef 617 if (root_storage) { 618 if (NOTMIME(ms)) { 619 char clsbuf[128]; 620 if (file_printf(ms, "CLSID %s, ", 621 format_clsid(clsbuf, sizeof(clsbuf), 622 root_storage->d_storage_uuid)) == -1) 623 return -1; 624 } 625 } 626 #endif 627 628 if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir, 629 "FileHeader", &scn) != -1) { 630 #define HWP5_SIGNATURE "HWP Document File" 631 if (scn.sst_len * scn.sst_ss >= sizeof(HWP5_SIGNATURE) - 1 632 && memcmp(scn.sst_tab, HWP5_SIGNATURE, 633 sizeof(HWP5_SIGNATURE) - 1) == 0) { 634 if (NOTMIME(ms)) { 635 if (file_printf(ms, 636 "Hancom HWP (Hangul Word Processor) file, version 5.0") == -1) 637 return -1; 638 } else if (ms->flags & MAGIC_MIME_TYPE) { 639 if (file_printf(ms, "application/x-hwp") == -1) 640 return -1; 641 } 642 i = 1; 643 goto out5; 644 } else { 645 cdf_zero_stream(&scn); 646 } 647 } 648 649 if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, 650 &scn)) == -1) { 651 if (errno != ESRCH) { 652 expn = "Cannot read summary info"; 653 } 654 } else { 655 i = cdf_check_summary_info(ms, &info, &h, 656 &sat, &ssat, &sst, &dir, &scn, root_storage, &expn); 657 cdf_zero_stream(&scn); 658 } 659 if (i <= 0) { 660 if ((i = cdf_read_doc_summary_info(&info, &h, &sat, &ssat, 661 &sst, &dir, &scn)) == -1) { 662 if (errno != ESRCH) { 663 expn = "Cannot read summary info"; 664 } 665 } else { 666 i = cdf_check_summary_info(ms, &info, &h, &sat, &ssat, 667 &sst, &dir, &scn, root_storage, &expn); 668 } 669 } 670 if (i <= 0) { 671 i = cdf_file_dir_info(ms, &dir); 672 if (i < 0) 673 expn = "Cannot read section info"; 674 } 675 out5: 676 cdf_zero_stream(&scn); 677 cdf_zero_stream(&sst); 678 out3: 679 free(dir.dir_tab); 680 out2: 681 free(ssat.sat_tab); 682 out1: 683 free(sat.sat_tab); 684 out0: 685 /* If we handled it already, return */ 686 if (i != -1) 687 return i; 688 /* Provide a default handler */ 689 if (NOTMIME(ms)) { 690 if (file_printf(ms, 691 "Composite Document File V2 Document") == -1) 692 return -1; 693 if (*expn) 694 if (file_printf(ms, ", %s", expn) == -1) 695 return -1; 696 } else if (ms->flags & MAGIC_MIME_TYPE) { 697 /* https://reposcope.com/mimetype/application/x-ole-storage */ 698 if (file_printf(ms, "application/x-ole-storage") == -1) 699 return -1; 700 } 701 return 1; 702 } 703