Line | Count | Source |
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 | 4.25k | #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 | 83 | { |
98 | 83 | size_t i; |
99 | 166 | for (i = 0; cv[i].mime != NULL; i++) { |
100 | 83 | if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1]) |
101 | 0 | return cv[i].mime; |
102 | 83 | } |
103 | | #ifdef CDF_DEBUG |
104 | | fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0], |
105 | | clsid[1]); |
106 | | #endif |
107 | 83 | return NULL; |
108 | 83 | } |
109 | | |
110 | | file_private const char * |
111 | | cdf_app_to_mime(const char *vbuf, const struct nv *nv) |
112 | 0 | { |
113 | 0 | size_t i; |
114 | 0 | const char *rv = NULL; |
115 | 0 | #ifdef USE_C_LOCALE |
116 | 0 | locale_t old_lc_ctype, c_lc_ctype; |
117 | |
|
118 | 0 | c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); |
119 | 0 | assert(c_lc_ctype != NULL); |
120 | 0 | old_lc_ctype = uselocale(c_lc_ctype); |
121 | 0 | 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 | 0 | for (i = 0; nv[i].pattern != NULL; i++) |
130 | 0 | if (strcasestr(vbuf, nv[i].pattern) != NULL) { |
131 | 0 | rv = nv[i].mime; |
132 | 0 | break; |
133 | 0 | } |
134 | | #ifdef CDF_DEBUG |
135 | | fprintf(stderr, "unknown app %s\n", vbuf); |
136 | | #endif |
137 | 0 | #ifdef USE_C_LOCALE |
138 | 0 | (void)uselocale(old_lc_ctype); |
139 | 0 | freelocale(c_lc_ctype); |
140 | | #else |
141 | | (void)setlocale(LC_CTYPE, old_lc_ctype); |
142 | | free(old_lc_ctype); |
143 | | #endif |
144 | 0 | return rv; |
145 | 0 | } |
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 | 240 | { |
151 | 240 | size_t i; |
152 | 240 | cdf_timestamp_t tp; |
153 | 240 | struct timespec ts; |
154 | 240 | char buf[64]; |
155 | 240 | const char *str = NULL; |
156 | 240 | const char *s, *e; |
157 | 240 | int len; |
158 | | |
159 | 240 | if (!NOTMIME(ms) && root_storage) |
160 | 0 | str = cdf_clsid_to_mime(root_storage->d_storage_uuid, |
161 | 0 | clsid2mime); |
162 | | |
163 | 1.75k | for (i = 0; i < count; i++) { |
164 | 1.64k | cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); |
165 | 1.64k | switch (info[i].pi_type) { |
166 | 213 | case CDF_NULL: |
167 | 213 | break; |
168 | 180 | case CDF_SIGNED16: |
169 | 180 | if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, |
170 | 180 | info[i].pi_s16) == -1) |
171 | 0 | return -1; |
172 | 180 | break; |
173 | 180 | case CDF_SIGNED32: |
174 | 129 | if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, |
175 | 129 | info[i].pi_s32) == -1) |
176 | 0 | return -1; |
177 | 129 | break; |
178 | 163 | case CDF_UNSIGNED32: |
179 | 163 | if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, |
180 | 163 | info[i].pi_u32) == -1) |
181 | 0 | return -1; |
182 | 163 | break; |
183 | 163 | case CDF_FLOAT: |
184 | 101 | if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, |
185 | 101 | info[i].pi_f) == -1) |
186 | 0 | return -1; |
187 | 101 | break; |
188 | 101 | case CDF_DOUBLE: |
189 | 64 | if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, |
190 | 64 | info[i].pi_d) == -1) |
191 | 0 | return -1; |
192 | 64 | break; |
193 | 113 | case CDF_LENGTH32_STRING: |
194 | 236 | case CDF_LENGTH32_WSTRING: |
195 | 236 | len = info[i].pi_str.s_len; |
196 | 236 | if (len > 1) { |
197 | 192 | char vbuf[1024]; |
198 | 192 | size_t j, k = 1; |
199 | | |
200 | 192 | if (info[i].pi_type == CDF_LENGTH32_WSTRING) |
201 | 93 | k++; |
202 | 192 | s = info[i].pi_str.s_buf; |
203 | 192 | e = info[i].pi_str.s_buf + len; |
204 | 59.1k | for (j = 0; s < e && j < sizeof(vbuf) |
205 | 59.0k | && len--; s += k) { |
206 | 59.0k | if (*s == '\0') |
207 | 148 | break; |
208 | 58.9k | if (isprint(CAST(unsigned char, *s))) |
209 | 30.3k | vbuf[j++] = *s; |
210 | 58.9k | } |
211 | 192 | if (j == sizeof(vbuf)) |
212 | 10 | --j; |
213 | 192 | vbuf[j] = '\0'; |
214 | 192 | if (NOTMIME(ms)) { |
215 | 192 | if (vbuf[0]) { |
216 | 144 | if (file_printf(ms, ", %s: %s", |
217 | 144 | buf, vbuf) == -1) |
218 | 7 | return -1; |
219 | 144 | } |
220 | 192 | } else if (str == NULL && info[i].pi_id == |
221 | 0 | CDF_PROPERTY_NAME_OF_APPLICATION) { |
222 | 0 | 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 | 0 | } |
229 | 192 | } |
230 | 229 | break; |
231 | 410 | case CDF_FILETIME: |
232 | 410 | tp = info[i].pi_tp; |
233 | 410 | if (tp != 0) { |
234 | 387 | char tbuf[64]; |
235 | 387 | if (tp < 1000000000000000LL) { |
236 | 143 | cdf_print_elapsed_time(tbuf, |
237 | 143 | sizeof(tbuf), tp); |
238 | 143 | if (NOTMIME(ms) && file_printf(ms, |
239 | 143 | ", %s: %s", buf, tbuf) == -1) |
240 | 0 | return -1; |
241 | 244 | } else { |
242 | 244 | char *c, *ec; |
243 | 244 | cdf_timestamp_to_timespec(&ts, tp); |
244 | 244 | c = cdf_ctime(&ts.tv_sec, tbuf); |
245 | 244 | if (c != NULL && |
246 | 244 | (ec = strchr(c, '\n')) != NULL) |
247 | 244 | *ec = '\0'; |
248 | | |
249 | 244 | if (NOTMIME(ms) && file_printf(ms, |
250 | 244 | ", %s: %s", buf, c) == -1) |
251 | 0 | return -1; |
252 | 244 | } |
253 | 387 | } |
254 | 410 | break; |
255 | 410 | case CDF_CLIPBOARD: |
256 | 22 | break; |
257 | 127 | default: |
258 | 127 | return -1; |
259 | 1.64k | } |
260 | 1.64k | } |
261 | 106 | if (ms->flags & MAGIC_MIME_TYPE) { |
262 | 0 | if (str == NULL) |
263 | 0 | return 0; |
264 | 0 | if (file_printf(ms, "application/%s", str) == -1) |
265 | 0 | return -1; |
266 | 0 | } |
267 | 106 | return 1; |
268 | 106 | } |
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 | 0 | { |
274 | 0 | cdf_catalog_t *cat; |
275 | 0 | size_t i; |
276 | 0 | char buf[256]; |
277 | 0 | cdf_catalog_entry_t *ce; |
278 | |
|
279 | 0 | if (NOTMIME(ms)) { |
280 | 0 | if (file_printf(ms, "Microsoft Thumbs.db [") == -1) |
281 | 0 | return -1; |
282 | 0 | if (cdf_unpack_catalog(h, sst, &cat) == -1) |
283 | 0 | return -1; |
284 | 0 | ce = cat->cat_e; |
285 | | /* skip first entry since it has a , or paren */ |
286 | 0 | for (i = 1; i < cat->cat_num; i++) |
287 | 0 | if (file_printf(ms, "%s%s", |
288 | 0 | cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name), |
289 | 0 | i == cat->cat_num - 1 ? "]" : ", ") == -1) { |
290 | 0 | free(cat); |
291 | 0 | return -1; |
292 | 0 | } |
293 | 0 | free(cat); |
294 | 0 | } else if (ms->flags & MAGIC_MIME_TYPE) { |
295 | 0 | if (file_printf(ms, "application/CDFV2") == -1) |
296 | 0 | return -1; |
297 | 0 | } |
298 | 0 | return 1; |
299 | 0 | } |
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 | 689 | { |
305 | 689 | cdf_summary_info_header_t si; |
306 | 689 | cdf_property_info_t *info; |
307 | 689 | size_t count; |
308 | 689 | int m; |
309 | | |
310 | 689 | if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1) |
311 | 449 | return -1; |
312 | | |
313 | 240 | if (NOTMIME(ms)) { |
314 | 240 | const char *str; |
315 | | |
316 | 240 | if (file_printf(ms, "Composite Document File V2 Document") |
317 | 240 | == -1) |
318 | 0 | return -1; |
319 | | |
320 | 240 | if (file_printf(ms, ", %s Endian", |
321 | 240 | si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) |
322 | 0 | return -2; |
323 | 240 | switch (si.si_os) { |
324 | 42 | case 2: |
325 | 42 | if (file_printf(ms, ", Os: Windows, Version %d.%d", |
326 | 42 | si.si_os_version & 0xff, |
327 | 42 | CAST(uint32_t, si.si_os_version) >> 8) == -1) |
328 | 0 | return -2; |
329 | 42 | break; |
330 | 42 | case 1: |
331 | 26 | if (file_printf(ms, ", Os: MacOS, Version %d.%d", |
332 | 26 | CAST(uint32_t, si.si_os_version) >> 8, |
333 | 26 | si.si_os_version & 0xff) == -1) |
334 | 0 | return -2; |
335 | 26 | break; |
336 | 172 | default: |
337 | 172 | if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, |
338 | 172 | si.si_os_version & 0xff, |
339 | 172 | CAST(uint32_t, si.si_os_version) >> 8) == -1) |
340 | 0 | return -2; |
341 | 172 | break; |
342 | 240 | } |
343 | 240 | if (root_storage) { |
344 | 83 | str = cdf_clsid_to_mime(root_storage->d_storage_uuid, |
345 | 83 | clsid2desc); |
346 | 83 | if (str) { |
347 | 0 | if (file_printf(ms, ", %s", str) == -1) |
348 | 0 | return -2; |
349 | 0 | } |
350 | 83 | } |
351 | 240 | } |
352 | | |
353 | 240 | m = cdf_file_property_info(ms, info, count, root_storage); |
354 | 240 | free(info); |
355 | | |
356 | 240 | return m == -1 ? -2 : m; |
357 | 240 | } |
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 | 0 | { |
378 | 0 | int i; |
379 | |
|
380 | 0 | if ((i = cdf_read_user_stream(info, h, sat, ssat, sst, |
381 | 0 | dir, "Catalog", scn)) == -1) |
382 | 0 | return i; |
383 | | #ifdef CDF_DEBUG |
384 | | cdf_dump_catalog(h, scn); |
385 | | #endif |
386 | 0 | if ((i = cdf_file_catalog(ms, h, scn)) == -1) |
387 | 0 | return -1; |
388 | 0 | return i; |
389 | 0 | } |
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 | 689 | { |
397 | 689 | int i; |
398 | 689 | const char *str = NULL; |
399 | 689 | cdf_directory_t *d; |
400 | 689 | char name[__arraycount(d->d_name)]; |
401 | 689 | size_t j, k; |
402 | | |
403 | | #ifdef CDF_DEBUG |
404 | | cdf_dump_summary_info(h, scn); |
405 | | #endif |
406 | 689 | if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) { |
407 | 583 | *expn = "Can't expand summary_info"; |
408 | 583 | return i; |
409 | 583 | } |
410 | 106 | if (i == 1) |
411 | 106 | return i; |
412 | 0 | for (j = 0; str == NULL && j < dir->dir_len; j++) { |
413 | 0 | d = &dir->dir_tab[j]; |
414 | 0 | for (k = 0; k < sizeof(name); k++) |
415 | 0 | name[k] = CAST(char, cdf_tole2(d->d_name[k])); |
416 | 0 | str = cdf_app_to_mime(name, |
417 | 0 | NOTMIME(ms) ? name2desc : name2mime); |
418 | 0 | } |
419 | 0 | if (NOTMIME(ms)) { |
420 | 0 | if (str != NULL) { |
421 | 0 | if (file_printf(ms, "%s", str) == -1) |
422 | 0 | return -1; |
423 | 0 | i = 1; |
424 | 0 | } |
425 | 0 | } else if (ms->flags & MAGIC_MIME_TYPE) { |
426 | 0 | if (str == NULL) |
427 | 0 | str = "vnd.ms-office"; |
428 | 0 | if (file_printf(ms, "application/%s", str) == -1) |
429 | 0 | return -1; |
430 | 0 | i = 1; |
431 | 0 | } |
432 | 0 | if (i <= 0) { |
433 | 0 | i = cdf_file_catalog_info(ms, info, h, sat, ssat, sst, |
434 | 0 | dir, scn); |
435 | 0 | } |
436 | 0 | return i; |
437 | 0 | } |
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 | 731 | { |
519 | 731 | size_t sd, i, j; |
520 | 731 | uint16_t *dir_name; |
521 | 731 | int dir_type; |
522 | 731 | const char* section_name; |
523 | | |
524 | 7.86k | for (i = 0; i < dir->dir_len; i++) { |
525 | 7.15k | dir_name = dir->dir_tab[i].d_name; |
526 | 7.15k | dir_type = dir->dir_tab[i].d_type; |
527 | | |
528 | 50.0k | for (sd = 0; sd < __arraycount(sectioninfo); sd++) { |
529 | 42.8k | const struct sinfo *si = §ioninfo[sd]; |
530 | 107k | for (j = 0; si->sections[j]; j++) { |
531 | 64.3k | if (si->sections[j] == NULL) |
532 | 0 | continue; |
533 | 64.3k | section_name = si->sections[j]; |
534 | 64.3k | if (si->types[j] != dir_type || |
535 | 10.3k | cdf_namecmp(section_name, dir_name, |
536 | 10.3k | strlen(section_name) + 1) != 0) |
537 | 64.3k | 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 | 24 | if (NOTMIME(ms)) { |
545 | 24 | if (file_printf(ms, "CDFV2 %s", |
546 | 24 | si->name) == -1) |
547 | 0 | return -1; |
548 | 24 | } else if (ms->flags & MAGIC_MIME_TYPE) { |
549 | 0 | if (file_printf(ms, "application/%s", |
550 | 0 | si->mime) == -1) |
551 | 0 | return -1; |
552 | 0 | } |
553 | 24 | return 1; |
554 | 24 | } |
555 | 42.8k | } |
556 | 7.15k | } |
557 | 707 | return -1; |
558 | 731 | } |
559 | | |
560 | | file_protected int |
561 | | file_trycdf(struct magic_set *ms, const struct buffer *b) |
562 | 12.1k | { |
563 | 12.1k | int fd = b->fd; |
564 | 12.1k | const unsigned char *buf = CAST(const unsigned char *, b->fbuf); |
565 | 12.1k | size_t nbytes = b->flen; |
566 | 12.1k | cdf_info_t info; |
567 | 12.1k | cdf_header_t h; |
568 | 12.1k | cdf_sat_t sat, ssat; |
569 | 12.1k | cdf_stream_t sst, scn; |
570 | 12.1k | cdf_dir_t dir; |
571 | 12.1k | int i; |
572 | 12.1k | const char *expn = ""; |
573 | 12.1k | const cdf_directory_t *root_storage; |
574 | | |
575 | 12.1k | scn.sst_tab = NULL; |
576 | 12.1k | info.i_fd = fd; |
577 | 12.1k | info.i_buf = buf; |
578 | 12.1k | info.i_len = nbytes; |
579 | 12.1k | if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) |
580 | 0 | return 0; |
581 | 12.1k | if (cdf_read_header(&info, &h) == -1) |
582 | 10.7k | return 0; |
583 | | #ifdef CDF_DEBUG |
584 | | cdf_dump_header(&h); |
585 | | #endif |
586 | | |
587 | 1.40k | if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { |
588 | 177 | expn = "Can't read SAT"; |
589 | 177 | goto out0; |
590 | 177 | } |
591 | | #ifdef CDF_DEBUG |
592 | | cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); |
593 | | #endif |
594 | | |
595 | 1.22k | if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { |
596 | 206 | expn = "Can't read SSAT"; |
597 | 206 | goto out1; |
598 | 206 | } |
599 | | #ifdef CDF_DEBUG |
600 | | cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); |
601 | | #endif |
602 | | |
603 | 1.02k | if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { |
604 | 92 | expn = "Can't read directory"; |
605 | 92 | goto out2; |
606 | 92 | } |
607 | | |
608 | 928 | if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst, |
609 | 928 | &root_storage)) == -1) { |
610 | 90 | expn = "Cannot read short stream"; |
611 | 90 | goto out3; |
612 | 90 | } |
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 | 838 | if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir, |
629 | 838 | "FileHeader", &scn) != -1) { |
630 | 22 | #define HWP5_SIGNATURE "HWP Document File" |
631 | 8 | if (scn.sst_len * scn.sst_ss >= sizeof(HWP5_SIGNATURE) - 1 |
632 | 7 | && memcmp(scn.sst_tab, HWP5_SIGNATURE, |
633 | 7 | sizeof(HWP5_SIGNATURE) - 1) == 0) { |
634 | 1 | if (NOTMIME(ms)) { |
635 | 1 | if (file_printf(ms, |
636 | 1 | "Hancom HWP (Hangul Word Processor) file, version 5.0") == -1) |
637 | 0 | return -1; |
638 | 1 | } else if (ms->flags & MAGIC_MIME_TYPE) { |
639 | 0 | if (file_printf(ms, "application/x-hwp") == -1) |
640 | 0 | return -1; |
641 | 0 | } |
642 | 1 | i = 1; |
643 | 1 | goto out5; |
644 | 7 | } else { |
645 | 7 | cdf_zero_stream(&scn); |
646 | 7 | } |
647 | 8 | } |
648 | | |
649 | 837 | if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, |
650 | 837 | &scn)) == -1) { |
651 | 254 | if (errno != ESRCH) { |
652 | 124 | expn = "Cannot read summary info"; |
653 | 124 | } |
654 | 583 | } else { |
655 | 583 | i = cdf_check_summary_info(ms, &info, &h, |
656 | 583 | &sat, &ssat, &sst, &dir, &scn, root_storage, &expn); |
657 | 583 | cdf_zero_stream(&scn); |
658 | 583 | } |
659 | 837 | if (i <= 0) { |
660 | 731 | if ((i = cdf_read_doc_summary_info(&info, &h, &sat, &ssat, |
661 | 731 | &sst, &dir, &scn)) == -1) { |
662 | 625 | if (errno != ESRCH) { |
663 | 37 | expn = "Cannot read summary info"; |
664 | 37 | } |
665 | 625 | } else { |
666 | 106 | i = cdf_check_summary_info(ms, &info, &h, &sat, &ssat, |
667 | 106 | &sst, &dir, &scn, root_storage, &expn); |
668 | 106 | } |
669 | 731 | } |
670 | 837 | if (i <= 0) { |
671 | 731 | i = cdf_file_dir_info(ms, &dir); |
672 | 731 | if (i < 0) |
673 | 707 | expn = "Cannot read section info"; |
674 | 731 | } |
675 | 838 | out5: |
676 | 838 | cdf_zero_stream(&scn); |
677 | 838 | cdf_zero_stream(&sst); |
678 | 928 | out3: |
679 | 928 | free(dir.dir_tab); |
680 | 1.02k | out2: |
681 | 1.02k | free(ssat.sat_tab); |
682 | 1.22k | out1: |
683 | 1.22k | free(sat.sat_tab); |
684 | 1.40k | out0: |
685 | | /* If we handled it already, return */ |
686 | 1.40k | if (i != -1) |
687 | 131 | return i; |
688 | | /* Provide a default handler */ |
689 | 1.27k | if (NOTMIME(ms)) { |
690 | 1.27k | if (file_printf(ms, |
691 | 1.27k | "Composite Document File V2 Document") == -1) |
692 | 0 | return -1; |
693 | 1.27k | if (*expn) |
694 | 1.27k | if (file_printf(ms, ", %s", expn) == -1) |
695 | 0 | return -1; |
696 | 1.27k | } else if (ms->flags & MAGIC_MIME_TYPE) { |
697 | | /* https://reposcope.com/mimetype/application/x-ole-storage */ |
698 | 0 | if (file_printf(ms, "application/x-ole-storage") == -1) |
699 | 0 | return -1; |
700 | 0 | } |
701 | 1.27k | return 1; |
702 | 1.27k | } |