1b6cee71dSXin LI /*- 2a5d223e6SXin LI * Copyright (c) 2008, 2016 Christos Zoulas 3b6cee71dSXin LI * All rights reserved. 4b6cee71dSXin LI * 5b6cee71dSXin LI * Redistribution and use in source and binary forms, with or without 6b6cee71dSXin LI * modification, are permitted provided that the following conditions 7b6cee71dSXin LI * are met: 8b6cee71dSXin LI * 1. Redistributions of source code must retain the above copyright 9b6cee71dSXin LI * notice, this list of conditions and the following disclaimer. 10b6cee71dSXin LI * 2. Redistributions in binary form must reproduce the above copyright 11b6cee71dSXin LI * notice, this list of conditions and the following disclaimer in the 12b6cee71dSXin LI * documentation and/or other materials provided with the distribution. 13b6cee71dSXin LI * 14b6cee71dSXin LI * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 15b6cee71dSXin LI * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16b6cee71dSXin LI * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17b6cee71dSXin LI * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18b6cee71dSXin LI * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19b6cee71dSXin LI * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20b6cee71dSXin LI * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21b6cee71dSXin LI * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22b6cee71dSXin LI * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23b6cee71dSXin LI * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24b6cee71dSXin LI * POSSIBILITY OF SUCH DAMAGE. 25b6cee71dSXin LI */ 26b6cee71dSXin LI #include "file.h" 27b6cee71dSXin LI 28b6cee71dSXin LI #ifndef lint 29*d38c30c0SXin LI FILE_RCSID("@(#)$File: readcdf.c,v 1.74 2019/09/11 15:46:30 christos Exp $") 30b6cee71dSXin LI #endif 31b6cee71dSXin LI 32b6cee71dSXin LI #include <assert.h> 33b6cee71dSXin LI #include <stdlib.h> 34b6cee71dSXin LI #include <unistd.h> 35b6cee71dSXin LI #include <string.h> 36b6cee71dSXin LI #include <time.h> 37b6cee71dSXin LI #include <ctype.h> 38b6cee71dSXin LI 39b6cee71dSXin LI #include "cdf.h" 40b6cee71dSXin LI #include "magic.h" 41b6cee71dSXin LI 42b6cee71dSXin LI #define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0) 43b6cee71dSXin LI 44b6cee71dSXin LI static const struct nv { 45b6cee71dSXin LI const char *pattern; 46b6cee71dSXin LI const char *mime; 47b6cee71dSXin LI } app2mime[] = { 48b6cee71dSXin LI { "Word", "msword", }, 49b6cee71dSXin LI { "Excel", "vnd.ms-excel", }, 50b6cee71dSXin LI { "Powerpoint", "vnd.ms-powerpoint", }, 51b6cee71dSXin LI { "Crystal Reports", "x-rpt", }, 52b6cee71dSXin LI { "Advanced Installer", "vnd.ms-msi", }, 53b6cee71dSXin LI { "InstallShield", "vnd.ms-msi", }, 54b6cee71dSXin LI { "Microsoft Patch Compiler", "vnd.ms-msi", }, 55b6cee71dSXin LI { "NAnt", "vnd.ms-msi", }, 56b6cee71dSXin LI { "Windows Installer", "vnd.ms-msi", }, 57b6cee71dSXin LI { NULL, NULL, }, 58b6cee71dSXin LI }, name2mime[] = { 593e41d09dSXin LI { "Book", "vnd.ms-excel", }, 603e41d09dSXin LI { "Workbook", "vnd.ms-excel", }, 61b6cee71dSXin LI { "WordDocument", "msword", }, 62b6cee71dSXin LI { "PowerPoint", "vnd.ms-powerpoint", }, 63b6cee71dSXin LI { "DigitalSignature", "vnd.ms-msi", }, 64b6cee71dSXin LI { NULL, NULL, }, 65b6cee71dSXin LI }, name2desc[] = { 663e41d09dSXin LI { "Book", "Microsoft Excel", }, 673e41d09dSXin LI { "Workbook", "Microsoft Excel", }, 683e41d09dSXin LI { "WordDocument", "Microsoft Word", }, 69b6cee71dSXin LI { "PowerPoint", "Microsoft PowerPoint", }, 70b6cee71dSXin LI { "DigitalSignature", "Microsoft Installer", }, 71b6cee71dSXin LI { NULL, NULL, }, 72b6cee71dSXin LI }; 73b6cee71dSXin LI 74b6cee71dSXin LI static const struct cv { 75b6cee71dSXin LI uint64_t clsid[2]; 76b6cee71dSXin LI const char *mime; 77b6cee71dSXin LI } clsid2mime[] = { 78b6cee71dSXin LI { 79c2931133SXin LI { 0x00000000000c1084ULL, 0x46000000000000c0ULL }, 80b6cee71dSXin LI "x-msi", 81b6cee71dSXin LI }, 82b6cee71dSXin LI { { 0, 0 }, 83b6cee71dSXin LI NULL, 84b6cee71dSXin LI }, 85b6cee71dSXin LI }, clsid2desc[] = { 86b6cee71dSXin LI { 87c2931133SXin LI { 0x00000000000c1084ULL, 0x46000000000000c0ULL }, 88b6cee71dSXin LI "MSI Installer", 89b6cee71dSXin LI }, 90b6cee71dSXin LI { { 0, 0 }, 91b6cee71dSXin LI NULL, 92b6cee71dSXin LI }, 93b6cee71dSXin LI }; 94b6cee71dSXin LI 95b6cee71dSXin LI private const char * 96b6cee71dSXin LI cdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv) 97b6cee71dSXin LI { 98b6cee71dSXin LI size_t i; 99b6cee71dSXin LI for (i = 0; cv[i].mime != NULL; i++) { 100b6cee71dSXin LI if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1]) 101b6cee71dSXin LI return cv[i].mime; 102b6cee71dSXin LI } 1035f0216bdSXin LI #ifdef CDF_DEBUG 1045f0216bdSXin LI fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0], 1055f0216bdSXin LI clsid[1]); 1065f0216bdSXin LI #endif 107b6cee71dSXin LI return NULL; 108b6cee71dSXin LI } 109b6cee71dSXin LI 110b6cee71dSXin LI private const char * 111b6cee71dSXin LI cdf_app_to_mime(const char *vbuf, const struct nv *nv) 112b6cee71dSXin LI { 113b6cee71dSXin LI size_t i; 114b6cee71dSXin LI const char *rv = NULL; 115c2931133SXin LI #ifdef USE_C_LOCALE 116c2931133SXin LI locale_t old_lc_ctype, c_lc_ctype; 117b6cee71dSXin LI 118c2931133SXin LI c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); 119c2931133SXin LI assert(c_lc_ctype != NULL); 120c2931133SXin LI old_lc_ctype = uselocale(c_lc_ctype); 121b6cee71dSXin LI assert(old_lc_ctype != NULL); 1223e41d09dSXin LI #else 123*d38c30c0SXin LI char *old_lc_ctype = setlocale(LC_CTYPE, NULL); 124*d38c30c0SXin LI assert(old_lc_ctype != NULL); 125*d38c30c0SXin LI old_lc_ctype = strdup(old_lc_ctype); 126*d38c30c0SXin LI assert(old_lc_ctype != NULL); 127*d38c30c0SXin LI (void)setlocale(LC_CTYPE, "C"); 128c2931133SXin LI #endif 129b6cee71dSXin LI for (i = 0; nv[i].pattern != NULL; i++) 130b6cee71dSXin LI if (strcasestr(vbuf, nv[i].pattern) != NULL) { 131b6cee71dSXin LI rv = nv[i].mime; 132b6cee71dSXin LI break; 133b6cee71dSXin LI } 1345f0216bdSXin LI #ifdef CDF_DEBUG 1355f0216bdSXin LI fprintf(stderr, "unknown app %s\n", vbuf); 1365f0216bdSXin LI #endif 137c2931133SXin LI #ifdef USE_C_LOCALE 138c2931133SXin LI (void)uselocale(old_lc_ctype); 139c2931133SXin LI freelocale(c_lc_ctype); 1403e41d09dSXin LI #else 141*d38c30c0SXin LI (void)setlocale(LC_CTYPE, old_lc_ctype); 142*d38c30c0SXin LI free(old_lc_ctype); 143c2931133SXin LI #endif 144b6cee71dSXin LI return rv; 145b6cee71dSXin LI } 146b6cee71dSXin LI 147b6cee71dSXin LI private int 148b6cee71dSXin LI cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, 149b6cee71dSXin LI size_t count, const cdf_directory_t *root_storage) 150b6cee71dSXin LI { 151b6cee71dSXin LI size_t i; 152b6cee71dSXin LI cdf_timestamp_t tp; 153b6cee71dSXin LI struct timespec ts; 154b6cee71dSXin LI char buf[64]; 155b6cee71dSXin LI const char *str = NULL; 15640427ccaSGordon Tetlow const char *s, *e; 157b6cee71dSXin LI int len; 158b6cee71dSXin LI 159b6cee71dSXin LI if (!NOTMIME(ms) && root_storage) 160b6cee71dSXin LI str = cdf_clsid_to_mime(root_storage->d_storage_uuid, 161b6cee71dSXin LI clsid2mime); 162b6cee71dSXin LI 163b6cee71dSXin LI for (i = 0; i < count; i++) { 164b6cee71dSXin LI cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); 165b6cee71dSXin LI switch (info[i].pi_type) { 166b6cee71dSXin LI case CDF_NULL: 167b6cee71dSXin LI break; 168b6cee71dSXin LI case CDF_SIGNED16: 169b6cee71dSXin LI if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, 170b6cee71dSXin LI info[i].pi_s16) == -1) 171b6cee71dSXin LI return -1; 172b6cee71dSXin LI break; 173b6cee71dSXin LI case CDF_SIGNED32: 174b6cee71dSXin LI if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, 175b6cee71dSXin LI info[i].pi_s32) == -1) 176b6cee71dSXin LI return -1; 177b6cee71dSXin LI break; 178b6cee71dSXin LI case CDF_UNSIGNED32: 179b6cee71dSXin LI if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, 180b6cee71dSXin LI info[i].pi_u32) == -1) 181b6cee71dSXin LI return -1; 182b6cee71dSXin LI break; 183b6cee71dSXin LI case CDF_FLOAT: 184b6cee71dSXin LI if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, 185b6cee71dSXin LI info[i].pi_f) == -1) 186b6cee71dSXin LI return -1; 187b6cee71dSXin LI break; 188b6cee71dSXin LI case CDF_DOUBLE: 189b6cee71dSXin LI if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, 190b6cee71dSXin LI info[i].pi_d) == -1) 191b6cee71dSXin LI return -1; 192b6cee71dSXin LI break; 193b6cee71dSXin LI case CDF_LENGTH32_STRING: 194b6cee71dSXin LI case CDF_LENGTH32_WSTRING: 195b6cee71dSXin LI len = info[i].pi_str.s_len; 196b6cee71dSXin LI if (len > 1) { 197b6cee71dSXin LI char vbuf[1024]; 198b6cee71dSXin LI size_t j, k = 1; 199b6cee71dSXin LI 200b6cee71dSXin LI if (info[i].pi_type == CDF_LENGTH32_WSTRING) 201b6cee71dSXin LI k++; 202b6cee71dSXin LI s = info[i].pi_str.s_buf; 20340427ccaSGordon Tetlow e = info[i].pi_str.s_buf + len; 20440427ccaSGordon Tetlow for (j = 0; s < e && j < sizeof(vbuf) 20540427ccaSGordon Tetlow && len--; s += k) { 206b6cee71dSXin LI if (*s == '\0') 207b6cee71dSXin LI break; 20848c779cdSXin LI if (isprint(CAST(unsigned char, *s))) 209b6cee71dSXin LI vbuf[j++] = *s; 210b6cee71dSXin LI } 211b6cee71dSXin LI if (j == sizeof(vbuf)) 212b6cee71dSXin LI --j; 213b6cee71dSXin LI vbuf[j] = '\0'; 214b6cee71dSXin LI if (NOTMIME(ms)) { 215b6cee71dSXin LI if (vbuf[0]) { 216b6cee71dSXin LI if (file_printf(ms, ", %s: %s", 217b6cee71dSXin LI buf, vbuf) == -1) 218b6cee71dSXin LI return -1; 219b6cee71dSXin LI } 220b6cee71dSXin LI } else if (str == NULL && info[i].pi_id == 221b6cee71dSXin LI CDF_PROPERTY_NAME_OF_APPLICATION) { 222b6cee71dSXin LI str = cdf_app_to_mime(vbuf, app2mime); 223b6cee71dSXin LI } 224b6cee71dSXin LI } 225b6cee71dSXin LI break; 226b6cee71dSXin LI case CDF_FILETIME: 227b6cee71dSXin LI tp = info[i].pi_tp; 228b6cee71dSXin LI if (tp != 0) { 229b6cee71dSXin LI char tbuf[64]; 230b6cee71dSXin LI if (tp < 1000000000000000LL) { 231b6cee71dSXin LI cdf_print_elapsed_time(tbuf, 232b6cee71dSXin LI sizeof(tbuf), tp); 233b6cee71dSXin LI if (NOTMIME(ms) && file_printf(ms, 234b6cee71dSXin LI ", %s: %s", buf, tbuf) == -1) 235b6cee71dSXin LI return -1; 236b6cee71dSXin LI } else { 237b6cee71dSXin LI char *c, *ec; 238b6cee71dSXin LI cdf_timestamp_to_timespec(&ts, tp); 239b6cee71dSXin LI c = cdf_ctime(&ts.tv_sec, tbuf); 240b6cee71dSXin LI if (c != NULL && 241b6cee71dSXin LI (ec = strchr(c, '\n')) != NULL) 242b6cee71dSXin LI *ec = '\0'; 243b6cee71dSXin LI 244b6cee71dSXin LI if (NOTMIME(ms) && file_printf(ms, 245b6cee71dSXin LI ", %s: %s", buf, c) == -1) 246b6cee71dSXin LI return -1; 247b6cee71dSXin LI } 248b6cee71dSXin LI } 249b6cee71dSXin LI break; 250b6cee71dSXin LI case CDF_CLIPBOARD: 251b6cee71dSXin LI break; 252b6cee71dSXin LI default: 253b6cee71dSXin LI return -1; 254b6cee71dSXin LI } 255b6cee71dSXin LI } 25648c779cdSXin LI if (ms->flags & MAGIC_MIME_TYPE) { 257b6cee71dSXin LI if (str == NULL) 258b6cee71dSXin LI return 0; 259b6cee71dSXin LI if (file_printf(ms, "application/%s", str) == -1) 260b6cee71dSXin LI return -1; 261b6cee71dSXin LI } 262b6cee71dSXin LI return 1; 263b6cee71dSXin LI } 264b6cee71dSXin LI 265b6cee71dSXin LI private int 266c2931133SXin LI cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h, 267c2931133SXin LI const cdf_stream_t *sst) 268c2931133SXin LI { 269c2931133SXin LI cdf_catalog_t *cat; 270c2931133SXin LI size_t i; 271c2931133SXin LI char buf[256]; 272c2931133SXin LI cdf_catalog_entry_t *ce; 273c2931133SXin LI 274c2931133SXin LI if (NOTMIME(ms)) { 275c2931133SXin LI if (file_printf(ms, "Microsoft Thumbs.db [") == -1) 276c2931133SXin LI return -1; 277c2931133SXin LI if (cdf_unpack_catalog(h, sst, &cat) == -1) 278c2931133SXin LI return -1; 279c2931133SXin LI ce = cat->cat_e; 280c2931133SXin LI /* skip first entry since it has a , or paren */ 281c2931133SXin LI for (i = 1; i < cat->cat_num; i++) 282c2931133SXin LI if (file_printf(ms, "%s%s", 283c2931133SXin LI cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name), 284c2931133SXin LI i == cat->cat_num - 1 ? "]" : ", ") == -1) { 285c2931133SXin LI free(cat); 286c2931133SXin LI return -1; 287c2931133SXin LI } 288c2931133SXin LI free(cat); 28948c779cdSXin LI } else if (ms->flags & MAGIC_MIME_TYPE) { 290c2931133SXin LI if (file_printf(ms, "application/CDFV2") == -1) 291c2931133SXin LI return -1; 292c2931133SXin LI } 293c2931133SXin LI return 1; 294c2931133SXin LI } 295c2931133SXin LI 296c2931133SXin LI private int 297b6cee71dSXin LI cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, 298b6cee71dSXin LI const cdf_stream_t *sst, const cdf_directory_t *root_storage) 299b6cee71dSXin LI { 300b6cee71dSXin LI cdf_summary_info_header_t si; 301b6cee71dSXin LI cdf_property_info_t *info; 302b6cee71dSXin LI size_t count; 303b6cee71dSXin LI int m; 304b6cee71dSXin LI 305b6cee71dSXin LI if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1) 306b6cee71dSXin LI return -1; 307b6cee71dSXin LI 308b6cee71dSXin LI if (NOTMIME(ms)) { 309b6cee71dSXin LI const char *str; 310b6cee71dSXin LI 311b6cee71dSXin LI if (file_printf(ms, "Composite Document File V2 Document") 312b6cee71dSXin LI == -1) 313b6cee71dSXin LI return -1; 314b6cee71dSXin LI 315b6cee71dSXin LI if (file_printf(ms, ", %s Endian", 316b6cee71dSXin LI si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) 317b6cee71dSXin LI return -2; 318b6cee71dSXin LI switch (si.si_os) { 319b6cee71dSXin LI case 2: 320b6cee71dSXin LI if (file_printf(ms, ", Os: Windows, Version %d.%d", 321b6cee71dSXin LI si.si_os_version & 0xff, 32248c779cdSXin LI CAST(uint32_t, si.si_os_version) >> 8) == -1) 323b6cee71dSXin LI return -2; 324b6cee71dSXin LI break; 325b6cee71dSXin LI case 1: 326b6cee71dSXin LI if (file_printf(ms, ", Os: MacOS, Version %d.%d", 32748c779cdSXin LI CAST(uint32_t, si.si_os_version) >> 8, 328b6cee71dSXin LI si.si_os_version & 0xff) == -1) 329b6cee71dSXin LI return -2; 330b6cee71dSXin LI break; 331b6cee71dSXin LI default: 332b6cee71dSXin LI if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, 333b6cee71dSXin LI si.si_os_version & 0xff, 33448c779cdSXin LI CAST(uint32_t, si.si_os_version) >> 8) == -1) 335b6cee71dSXin LI return -2; 336b6cee71dSXin LI break; 337b6cee71dSXin LI } 338b6cee71dSXin LI if (root_storage) { 339b6cee71dSXin LI str = cdf_clsid_to_mime(root_storage->d_storage_uuid, 340b6cee71dSXin LI clsid2desc); 341c2931133SXin LI if (str) { 342b6cee71dSXin LI if (file_printf(ms, ", %s", str) == -1) 343b6cee71dSXin LI return -2; 344b6cee71dSXin LI } 345b6cee71dSXin LI } 346c2931133SXin LI } 347b6cee71dSXin LI 348b6cee71dSXin LI m = cdf_file_property_info(ms, info, count, root_storage); 349b6cee71dSXin LI free(info); 350b6cee71dSXin LI 351b6cee71dSXin LI return m == -1 ? -2 : m; 352b6cee71dSXin LI } 353b6cee71dSXin LI 354b6cee71dSXin LI #ifdef notdef 355b6cee71dSXin LI private char * 356b6cee71dSXin LI format_clsid(char *buf, size_t len, const uint64_t uuid[2]) { 357b6cee71dSXin LI snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4" 358b6cee71dSXin LI PRIx64 "-%.12" PRIx64, 359c2931133SXin LI (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL, 360c2931133SXin LI (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL, 361c2931133SXin LI (uuid[0] >> 0) & (uint64_t)0x0000000000000ffffULL, 362c2931133SXin LI (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL, 363c2931133SXin LI (uuid[1] >> 0) & (uint64_t)0x0000fffffffffffffULL); 364b6cee71dSXin LI return buf; 365b6cee71dSXin LI } 366b6cee71dSXin LI #endif 367b6cee71dSXin LI 3685f0216bdSXin LI private int 3695f0216bdSXin LI cdf_file_catalog_info(struct magic_set *ms, const cdf_info_t *info, 3705f0216bdSXin LI const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat, 3715f0216bdSXin LI const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn) 3725f0216bdSXin LI { 3735f0216bdSXin LI int i; 3745f0216bdSXin LI 3755f0216bdSXin LI if ((i = cdf_read_user_stream(info, h, sat, ssat, sst, 3765f0216bdSXin LI dir, "Catalog", scn)) == -1) 3775f0216bdSXin LI return i; 3785f0216bdSXin LI #ifdef CDF_DEBUG 379a5d223e6SXin LI cdf_dump_catalog(h, scn); 3805f0216bdSXin LI #endif 3815f0216bdSXin LI if ((i = cdf_file_catalog(ms, h, scn)) == -1) 3825f0216bdSXin LI return -1; 3835f0216bdSXin LI return i; 3845f0216bdSXin LI } 3855f0216bdSXin LI 386a5d223e6SXin LI private int 387a5d223e6SXin LI cdf_check_summary_info(struct magic_set *ms, const cdf_info_t *info, 388a5d223e6SXin LI const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat, 389a5d223e6SXin LI const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn, 390a5d223e6SXin LI const cdf_directory_t *root_storage, const char **expn) 391a5d223e6SXin LI { 392a5d223e6SXin LI int i; 393a5d223e6SXin LI const char *str = NULL; 394a5d223e6SXin LI cdf_directory_t *d; 395a5d223e6SXin LI char name[__arraycount(d->d_name)]; 396a5d223e6SXin LI size_t j, k; 397a5d223e6SXin LI 398a5d223e6SXin LI #ifdef CDF_DEBUG 399a5d223e6SXin LI cdf_dump_summary_info(h, scn); 400a5d223e6SXin LI #endif 401a5d223e6SXin LI if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) { 402a5d223e6SXin LI *expn = "Can't expand summary_info"; 403a5d223e6SXin LI return i; 404a5d223e6SXin LI } 405a5d223e6SXin LI if (i == 1) 406a5d223e6SXin LI return i; 407a5d223e6SXin LI for (j = 0; str == NULL && j < dir->dir_len; j++) { 408a5d223e6SXin LI d = &dir->dir_tab[j]; 409a5d223e6SXin LI for (k = 0; k < sizeof(name); k++) 41048c779cdSXin LI name[k] = CAST(char, cdf_tole2(d->d_name[k])); 411a5d223e6SXin LI str = cdf_app_to_mime(name, 412a5d223e6SXin LI NOTMIME(ms) ? name2desc : name2mime); 413a5d223e6SXin LI } 414a5d223e6SXin LI if (NOTMIME(ms)) { 415a5d223e6SXin LI if (str != NULL) { 416a5d223e6SXin LI if (file_printf(ms, "%s", str) == -1) 417a5d223e6SXin LI return -1; 418a5d223e6SXin LI i = 1; 419a5d223e6SXin LI } 42048c779cdSXin LI } else if (ms->flags & MAGIC_MIME_TYPE) { 421a5d223e6SXin LI if (str == NULL) 422a5d223e6SXin LI str = "vnd.ms-office"; 423a5d223e6SXin LI if (file_printf(ms, "application/%s", str) == -1) 424a5d223e6SXin LI return -1; 425a5d223e6SXin LI i = 1; 426a5d223e6SXin LI } 427a5d223e6SXin LI if (i <= 0) { 428a5d223e6SXin LI i = cdf_file_catalog_info(ms, info, h, sat, ssat, sst, 429a5d223e6SXin LI dir, scn); 430a5d223e6SXin LI } 431a5d223e6SXin LI return i; 432a5d223e6SXin LI } 433a5d223e6SXin LI 4345f0216bdSXin LI private struct sinfo { 4355f0216bdSXin LI const char *name; 4365f0216bdSXin LI const char *mime; 4375f0216bdSXin LI const char *sections[5]; 4385f0216bdSXin LI const int types[5]; 4395f0216bdSXin LI } sectioninfo[] = { 4405f0216bdSXin LI { "Encrypted", "encrypted", 4415f0216bdSXin LI { 442a5d223e6SXin LI "EncryptedPackage", "EncryptedSummary", 443a5d223e6SXin LI NULL, NULL, NULL, 4445f0216bdSXin LI }, 4455f0216bdSXin LI { 446a5d223e6SXin LI CDF_DIR_TYPE_USER_STREAM, 447a5d223e6SXin LI CDF_DIR_TYPE_USER_STREAM, 448a5d223e6SXin LI 0, 0, 0, 4495f0216bdSXin LI 4505f0216bdSXin LI }, 4515f0216bdSXin LI }, 4525f0216bdSXin LI { "QuickBooks", "quickbooks", 4535f0216bdSXin LI { 4545f0216bdSXin LI #if 0 4555f0216bdSXin LI "TaxForms", "PDFTaxForms", "modulesInBackup", 4565f0216bdSXin LI #endif 4575f0216bdSXin LI "mfbu_header", NULL, NULL, NULL, NULL, 4585f0216bdSXin LI }, 4595f0216bdSXin LI { 4605f0216bdSXin LI #if 0 4615f0216bdSXin LI CDF_DIR_TYPE_USER_STORAGE, 4625f0216bdSXin LI CDF_DIR_TYPE_USER_STORAGE, 4635f0216bdSXin LI CDF_DIR_TYPE_USER_STREAM, 4645f0216bdSXin LI #endif 4655f0216bdSXin LI CDF_DIR_TYPE_USER_STREAM, 4665f0216bdSXin LI 0, 0, 0, 0 4675f0216bdSXin LI }, 4685f0216bdSXin LI }, 469a5d223e6SXin LI { "Microsoft Excel", "vnd.ms-excel", 470a5d223e6SXin LI { 471a5d223e6SXin LI "Book", "Workbook", NULL, NULL, NULL, 472a5d223e6SXin LI }, 473a5d223e6SXin LI { 474a5d223e6SXin LI CDF_DIR_TYPE_USER_STREAM, 475a5d223e6SXin LI CDF_DIR_TYPE_USER_STREAM, 476a5d223e6SXin LI 0, 0, 0, 477a5d223e6SXin LI }, 478a5d223e6SXin LI }, 479a5d223e6SXin LI { "Microsoft Word", "msword", 480a5d223e6SXin LI { 481a5d223e6SXin LI "WordDocument", NULL, NULL, NULL, NULL, 482a5d223e6SXin LI }, 483a5d223e6SXin LI { 484a5d223e6SXin LI CDF_DIR_TYPE_USER_STREAM, 485a5d223e6SXin LI 0, 0, 0, 0, 486a5d223e6SXin LI }, 487a5d223e6SXin LI }, 488a5d223e6SXin LI { "Microsoft PowerPoint", "vnd.ms-powerpoint", 489a5d223e6SXin LI { 490a5d223e6SXin LI "PowerPoint", NULL, NULL, NULL, NULL, 491a5d223e6SXin LI }, 492a5d223e6SXin LI { 493a5d223e6SXin LI CDF_DIR_TYPE_USER_STREAM, 494a5d223e6SXin LI 0, 0, 0, 0, 495a5d223e6SXin LI }, 496a5d223e6SXin LI }, 497a5d223e6SXin LI { "Microsoft Outlook Message", "vnd.ms-outlook", 498a5d223e6SXin LI { 499a5d223e6SXin LI "__properties_version1.0", 500a5d223e6SXin LI "__recip_version1.0_#00000000", 501a5d223e6SXin LI NULL, NULL, NULL, 502a5d223e6SXin LI }, 503a5d223e6SXin LI { 504a5d223e6SXin LI CDF_DIR_TYPE_USER_STREAM, 505a5d223e6SXin LI CDF_DIR_TYPE_USER_STORAGE, 506a5d223e6SXin LI 0, 0, 0, 507a5d223e6SXin LI }, 508a5d223e6SXin LI }, 5095f0216bdSXin LI }; 5105f0216bdSXin LI 5115f0216bdSXin LI private int 5125f0216bdSXin LI cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir) 5135f0216bdSXin LI { 5145f0216bdSXin LI size_t sd, j; 5155f0216bdSXin LI 5165f0216bdSXin LI for (sd = 0; sd < __arraycount(sectioninfo); sd++) { 5175f0216bdSXin LI const struct sinfo *si = §ioninfo[sd]; 5185f0216bdSXin LI for (j = 0; si->sections[j]; j++) { 5195f0216bdSXin LI if (cdf_find_stream(dir, si->sections[j], si->types[j]) 520a5d223e6SXin LI > 0) 5215f0216bdSXin LI break; 522a5d223e6SXin LI #ifdef CDF_DEBUG 523a5d223e6SXin LI fprintf(stderr, "Can't read %s\n", si->sections[j]); 524a5d223e6SXin LI #endif 5255f0216bdSXin LI } 526a5d223e6SXin LI if (si->sections[j] == NULL) 5275f0216bdSXin LI continue; 5285f0216bdSXin LI if (NOTMIME(ms)) { 5295f0216bdSXin LI if (file_printf(ms, "CDFV2 %s", si->name) == -1) 5305f0216bdSXin LI return -1; 53148c779cdSXin LI } else if (ms->flags & MAGIC_MIME_TYPE) { 532a5d223e6SXin LI if (file_printf(ms, "application/%s", si->mime) == -1) 5335f0216bdSXin LI return -1; 5345f0216bdSXin LI } 5355f0216bdSXin LI return 1; 5365f0216bdSXin LI } 5375f0216bdSXin LI return -1; 5385f0216bdSXin LI } 5395f0216bdSXin LI 540b6cee71dSXin LI protected int 54158a0f0d0SEitan Adler file_trycdf(struct magic_set *ms, const struct buffer *b) 542b6cee71dSXin LI { 54358a0f0d0SEitan Adler int fd = b->fd; 54448c779cdSXin LI const unsigned char *buf = CAST(const unsigned char *, b->fbuf); 54558a0f0d0SEitan Adler size_t nbytes = b->flen; 546b6cee71dSXin LI cdf_info_t info; 547b6cee71dSXin LI cdf_header_t h; 548b6cee71dSXin LI cdf_sat_t sat, ssat; 549b6cee71dSXin LI cdf_stream_t sst, scn; 550b6cee71dSXin LI cdf_dir_t dir; 551b6cee71dSXin LI int i; 552b6cee71dSXin LI const char *expn = ""; 553c2931133SXin LI const cdf_directory_t *root_storage; 554b6cee71dSXin LI 555a5d223e6SXin LI scn.sst_tab = NULL; 556b6cee71dSXin LI info.i_fd = fd; 557b6cee71dSXin LI info.i_buf = buf; 558b6cee71dSXin LI info.i_len = nbytes; 5595f0216bdSXin LI if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) 560b6cee71dSXin LI return 0; 561b6cee71dSXin LI if (cdf_read_header(&info, &h) == -1) 562b6cee71dSXin LI return 0; 563b6cee71dSXin LI #ifdef CDF_DEBUG 564b6cee71dSXin LI cdf_dump_header(&h); 565b6cee71dSXin LI #endif 566b6cee71dSXin LI 567b6cee71dSXin LI if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { 568b6cee71dSXin LI expn = "Can't read SAT"; 569b6cee71dSXin LI goto out0; 570b6cee71dSXin LI } 571b6cee71dSXin LI #ifdef CDF_DEBUG 572b6cee71dSXin LI cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); 573b6cee71dSXin LI #endif 574b6cee71dSXin LI 575b6cee71dSXin LI if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { 576b6cee71dSXin LI expn = "Can't read SSAT"; 577b6cee71dSXin LI goto out1; 578b6cee71dSXin LI } 579b6cee71dSXin LI #ifdef CDF_DEBUG 580b6cee71dSXin LI cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); 581b6cee71dSXin LI #endif 582b6cee71dSXin LI 583b6cee71dSXin LI if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { 584b6cee71dSXin LI expn = "Can't read directory"; 585b6cee71dSXin LI goto out2; 586b6cee71dSXin LI } 587b6cee71dSXin LI 588b6cee71dSXin LI if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst, 589b6cee71dSXin LI &root_storage)) == -1) { 590b6cee71dSXin LI expn = "Cannot read short stream"; 591b6cee71dSXin LI goto out3; 592b6cee71dSXin LI } 593b6cee71dSXin LI #ifdef CDF_DEBUG 594b6cee71dSXin LI cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); 595b6cee71dSXin LI #endif 596b6cee71dSXin LI #ifdef notdef 597b6cee71dSXin LI if (root_storage) { 598b6cee71dSXin LI if (NOTMIME(ms)) { 599b6cee71dSXin LI char clsbuf[128]; 600b6cee71dSXin LI if (file_printf(ms, "CLSID %s, ", 601b6cee71dSXin LI format_clsid(clsbuf, sizeof(clsbuf), 602b6cee71dSXin LI root_storage->d_storage_uuid)) == -1) 603b6cee71dSXin LI return -1; 604b6cee71dSXin LI } 605b6cee71dSXin LI } 606b6cee71dSXin LI #endif 607b6cee71dSXin LI 608b6cee71dSXin LI if ((i = cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir, 609b6cee71dSXin LI "FileHeader", &scn)) != -1) { 610b6cee71dSXin LI #define HWP5_SIGNATURE "HWP Document File" 61140427ccaSGordon Tetlow if (scn.sst_len * scn.sst_ss >= sizeof(HWP5_SIGNATURE) - 1 612b6cee71dSXin LI && memcmp(scn.sst_tab, HWP5_SIGNATURE, 613b6cee71dSXin LI sizeof(HWP5_SIGNATURE) - 1) == 0) { 614b6cee71dSXin LI if (NOTMIME(ms)) { 615b6cee71dSXin LI if (file_printf(ms, 616b6cee71dSXin LI "Hangul (Korean) Word Processor File 5.x") == -1) 617b6cee71dSXin LI return -1; 61848c779cdSXin LI } else if (ms->flags & MAGIC_MIME_TYPE) { 619b6cee71dSXin LI if (file_printf(ms, "application/x-hwp") == -1) 620b6cee71dSXin LI return -1; 621b6cee71dSXin LI } 622b6cee71dSXin LI i = 1; 623b6cee71dSXin LI goto out5; 624b6cee71dSXin LI } else { 625a5d223e6SXin LI cdf_zero_stream(&scn); 626b6cee71dSXin LI } 627b6cee71dSXin LI } 628b6cee71dSXin LI 629b6cee71dSXin LI if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, 630b6cee71dSXin LI &scn)) == -1) { 6315f0216bdSXin LI if (errno != ESRCH) { 632b6cee71dSXin LI expn = "Cannot read summary info"; 633b6cee71dSXin LI } 634a5d223e6SXin LI } else { 635a5d223e6SXin LI i = cdf_check_summary_info(ms, &info, &h, 636a5d223e6SXin LI &sat, &ssat, &sst, &dir, &scn, root_storage, &expn); 637a5d223e6SXin LI cdf_zero_stream(&scn); 638a5d223e6SXin LI } 639a5d223e6SXin LI if (i <= 0) { 640a5d223e6SXin LI if ((i = cdf_read_doc_summary_info(&info, &h, &sat, &ssat, 641a5d223e6SXin LI &sst, &dir, &scn)) == -1) { 642a5d223e6SXin LI if (errno != ESRCH) { 643a5d223e6SXin LI expn = "Cannot read summary info"; 644a5d223e6SXin LI } 645a5d223e6SXin LI } else { 646a5d223e6SXin LI i = cdf_check_summary_info(ms, &info, &h, &sat, &ssat, 647a5d223e6SXin LI &sst, &dir, &scn, root_storage, &expn); 648a5d223e6SXin LI } 649a5d223e6SXin LI } 650a5d223e6SXin LI if (i <= 0) { 6515f0216bdSXin LI i = cdf_file_dir_info(ms, &dir); 6525f0216bdSXin LI if (i < 0) 6535f0216bdSXin LI expn = "Cannot read section info"; 654b6cee71dSXin LI } 655b6cee71dSXin LI out5: 656a5d223e6SXin LI cdf_zero_stream(&scn); 657a5d223e6SXin LI cdf_zero_stream(&sst); 658b6cee71dSXin LI out3: 659b6cee71dSXin LI free(dir.dir_tab); 660b6cee71dSXin LI out2: 661b6cee71dSXin LI free(ssat.sat_tab); 662b6cee71dSXin LI out1: 663b6cee71dSXin LI free(sat.sat_tab); 664b6cee71dSXin LI out0: 66548c779cdSXin LI /* If we handled it already, return */ 66648c779cdSXin LI if (i != -1) 66748c779cdSXin LI return i; 66848c779cdSXin LI /* Provide a default handler */ 669b6cee71dSXin LI if (NOTMIME(ms)) { 670b6cee71dSXin LI if (file_printf(ms, 671b6cee71dSXin LI "Composite Document File V2 Document") == -1) 672b6cee71dSXin LI return -1; 673b6cee71dSXin LI if (*expn) 6745f0216bdSXin LI if (file_printf(ms, ", %s", expn) == -1) 675b6cee71dSXin LI return -1; 67648c779cdSXin LI } else if (ms->flags & MAGIC_MIME_TYPE) { 677a5d223e6SXin LI if (file_printf(ms, "application/CDFV2") == -1) 678b6cee71dSXin LI return -1; 679b6cee71dSXin LI } 68048c779cdSXin LI return 1; 681b6cee71dSXin LI } 682