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