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