xref: /dflybsd-src/contrib/file/src/readcdf.c (revision 739f0ef867128a933e021db3d831e906fcafd825)
179343712SPeter Avalos /*-
2c30bd091SSascha Wildner  * Copyright (c) 2008, 2016 Christos Zoulas
379343712SPeter Avalos  * All rights reserved.
479343712SPeter Avalos  *
579343712SPeter Avalos  * Redistribution and use in source and binary forms, with or without
679343712SPeter Avalos  * modification, are permitted provided that the following conditions
779343712SPeter Avalos  * are met:
879343712SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
979343712SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1079343712SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1179343712SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1279343712SPeter Avalos  *    documentation and/or other materials provided with the distribution.
1379343712SPeter Avalos  *
1479343712SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1579343712SPeter Avalos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1679343712SPeter Avalos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1779343712SPeter Avalos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1879343712SPeter Avalos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1979343712SPeter Avalos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2079343712SPeter Avalos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2179343712SPeter Avalos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2279343712SPeter Avalos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2379343712SPeter Avalos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2479343712SPeter Avalos  * POSSIBILITY OF SUCH DAMAGE.
2579343712SPeter Avalos  */
2679343712SPeter Avalos #include "file.h"
2779343712SPeter Avalos 
2879343712SPeter Avalos #ifndef lint
29*3b9cdfa3SAntonio Huete Jimenez FILE_RCSID("@(#)$File: readcdf.c,v 1.76 2022/01/17 16:59:01 christos Exp $")
3079343712SPeter Avalos #endif
3179343712SPeter Avalos 
32e8af9738SPeter Avalos #include <assert.h>
3379343712SPeter Avalos #include <stdlib.h>
3479343712SPeter Avalos #include <unistd.h>
3579343712SPeter Avalos #include <string.h>
3679343712SPeter Avalos #include <time.h>
3779343712SPeter Avalos #include <ctype.h>
3879343712SPeter Avalos 
3979343712SPeter Avalos #include "cdf.h"
4079343712SPeter Avalos #include "magic.h"
4179343712SPeter Avalos 
4279343712SPeter Avalos #define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
4379343712SPeter Avalos 
44e8af9738SPeter Avalos static const struct nv {
45e8af9738SPeter Avalos 	const char *pattern;
46e8af9738SPeter Avalos 	const char *mime;
47e8af9738SPeter Avalos } app2mime[] =  {
48e8af9738SPeter Avalos 	{ "Word",			"msword",		},
49e8af9738SPeter Avalos 	{ "Excel",			"vnd.ms-excel",		},
50e8af9738SPeter Avalos 	{ "Powerpoint",			"vnd.ms-powerpoint",	},
51e8af9738SPeter Avalos 	{ "Crystal Reports",		"x-rpt",		},
52e8af9738SPeter Avalos 	{ "Advanced Installer",		"vnd.ms-msi",		},
53e8af9738SPeter Avalos 	{ "InstallShield",		"vnd.ms-msi",		},
54e8af9738SPeter Avalos 	{ "Microsoft Patch Compiler",	"vnd.ms-msi",		},
55e8af9738SPeter Avalos 	{ "NAnt",			"vnd.ms-msi",		},
56e8af9738SPeter Avalos 	{ "Windows Installer",		"vnd.ms-msi",		},
57e8af9738SPeter Avalos 	{ NULL,				NULL,			},
58e8af9738SPeter Avalos }, name2mime[] = {
59c30bd091SSascha Wildner 	{ "Book",			"vnd.ms-excel",		},
60c30bd091SSascha Wildner 	{ "Workbook",			"vnd.ms-excel",		},
61e8af9738SPeter Avalos 	{ "WordDocument",		"msword",		},
62e8af9738SPeter Avalos 	{ "PowerPoint",			"vnd.ms-powerpoint",	},
63e8af9738SPeter Avalos 	{ "DigitalSignature",		"vnd.ms-msi",		},
64e8af9738SPeter Avalos 	{ NULL,				NULL,			},
65e8af9738SPeter Avalos }, name2desc[] = {
66c30bd091SSascha Wildner 	{ "Book",			"Microsoft Excel",	},
67c30bd091SSascha Wildner 	{ "Workbook",			"Microsoft Excel",	},
68c30bd091SSascha Wildner 	{ "WordDocument",		"Microsoft Word",	},
69e8af9738SPeter Avalos 	{ "PowerPoint",			"Microsoft PowerPoint",	},
70e8af9738SPeter Avalos 	{ "DigitalSignature",		"Microsoft Installer",	},
71e8af9738SPeter Avalos 	{ NULL,				NULL,			},
72e8af9738SPeter Avalos };
73e8af9738SPeter Avalos 
74e8af9738SPeter Avalos static const struct cv {
75e8af9738SPeter Avalos 	uint64_t clsid[2];
76e8af9738SPeter Avalos 	const char *mime;
77e8af9738SPeter Avalos } clsid2mime[] = {
78e8af9738SPeter Avalos 	{
7982c5fa3eSPeter Avalos 		{ 0x00000000000c1084ULL, 0x46000000000000c0ULL  },
80e8af9738SPeter Avalos 		"x-msi",
8182c5fa3eSPeter Avalos 	},
8282c5fa3eSPeter Avalos 	{	{ 0,			 0			},
8382c5fa3eSPeter Avalos 		NULL,
8482c5fa3eSPeter Avalos 	},
85e8af9738SPeter Avalos }, clsid2desc[] = {
86e8af9738SPeter Avalos 	{
8782c5fa3eSPeter Avalos 		{ 0x00000000000c1084ULL, 0x46000000000000c0ULL  },
88e8af9738SPeter Avalos 		"MSI Installer",
89e8af9738SPeter Avalos 	},
9082c5fa3eSPeter Avalos 	{	{ 0,			 0			},
9182c5fa3eSPeter Avalos 		NULL,
9282c5fa3eSPeter Avalos 	},
93e8af9738SPeter Avalos };
94e8af9738SPeter Avalos 
95e8af9738SPeter Avalos private const char *
cdf_clsid_to_mime(const uint64_t clsid[2],const struct cv * cv)96e8af9738SPeter Avalos cdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv)
97e8af9738SPeter Avalos {
98e8af9738SPeter Avalos 	size_t i;
99e8af9738SPeter Avalos 	for (i = 0; cv[i].mime != NULL; i++) {
100e8af9738SPeter Avalos 		if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1])
101e8af9738SPeter Avalos 			return cv[i].mime;
102e8af9738SPeter Avalos 	}
103c30bd091SSascha Wildner #ifdef CDF_DEBUG
104c30bd091SSascha Wildner 	fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0],
105c30bd091SSascha Wildner 	    clsid[1]);
106c30bd091SSascha Wildner #endif
107e8af9738SPeter Avalos 	return NULL;
108e8af9738SPeter Avalos }
109e8af9738SPeter Avalos 
110e8af9738SPeter Avalos private const char *
cdf_app_to_mime(const char * vbuf,const struct nv * nv)111e8af9738SPeter Avalos cdf_app_to_mime(const char *vbuf, const struct nv *nv)
112e8af9738SPeter Avalos {
113e8af9738SPeter Avalos 	size_t i;
114e8af9738SPeter Avalos 	const char *rv = NULL;
11582c5fa3eSPeter Avalos #ifdef USE_C_LOCALE
11682c5fa3eSPeter Avalos 	locale_t old_lc_ctype, c_lc_ctype;
117e8af9738SPeter Avalos 
11882c5fa3eSPeter Avalos 	c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
11982c5fa3eSPeter Avalos 	assert(c_lc_ctype != NULL);
12082c5fa3eSPeter Avalos 	old_lc_ctype = uselocale(c_lc_ctype);
121e8af9738SPeter Avalos 	assert(old_lc_ctype != NULL);
122c30bd091SSascha Wildner #else
1236fca56fbSSascha Wildner 	char *old_lc_ctype = setlocale(LC_CTYPE, NULL);
1246fca56fbSSascha Wildner 	assert(old_lc_ctype != NULL);
1256fca56fbSSascha Wildner 	old_lc_ctype = strdup(old_lc_ctype);
1266fca56fbSSascha Wildner 	assert(old_lc_ctype != NULL);
1276fca56fbSSascha Wildner 	(void)setlocale(LC_CTYPE, "C");
12882c5fa3eSPeter Avalos #endif
129e8af9738SPeter Avalos 	for (i = 0; nv[i].pattern != NULL; i++)
130e8af9738SPeter Avalos 		if (strcasestr(vbuf, nv[i].pattern) != NULL) {
131e8af9738SPeter Avalos 			rv = nv[i].mime;
132e8af9738SPeter Avalos 			break;
133e8af9738SPeter Avalos 		}
134c30bd091SSascha Wildner #ifdef CDF_DEBUG
135c30bd091SSascha Wildner 	fprintf(stderr, "unknown app %s\n", vbuf);
136c30bd091SSascha Wildner #endif
13782c5fa3eSPeter Avalos #ifdef USE_C_LOCALE
13882c5fa3eSPeter Avalos 	(void)uselocale(old_lc_ctype);
13982c5fa3eSPeter Avalos 	freelocale(c_lc_ctype);
140c30bd091SSascha Wildner #else
1416fca56fbSSascha Wildner 	(void)setlocale(LC_CTYPE, old_lc_ctype);
1426fca56fbSSascha Wildner 	free(old_lc_ctype);
14382c5fa3eSPeter Avalos #endif
144e8af9738SPeter Avalos 	return rv;
145e8af9738SPeter Avalos }
146e8af9738SPeter Avalos 
14779343712SPeter Avalos 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)14879343712SPeter Avalos cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
14982c5fa3eSPeter Avalos     size_t count, const cdf_directory_t *root_storage)
15079343712SPeter Avalos {
15179343712SPeter Avalos 	size_t i;
15279343712SPeter Avalos 	cdf_timestamp_t tp;
15379343712SPeter Avalos 	struct timespec ts;
15479343712SPeter Avalos 	char buf[64];
155a96e001bSPeter Avalos 	const char *str = NULL;
156c30bd091SSascha Wildner 	const char *s, *e;
15779343712SPeter Avalos 	int len;
15879343712SPeter Avalos 
15982c5fa3eSPeter Avalos 	if (!NOTMIME(ms) && root_storage)
16082c5fa3eSPeter Avalos 		str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
16182c5fa3eSPeter Avalos 		    clsid2mime);
162e8af9738SPeter Avalos 
16379343712SPeter Avalos 	for (i = 0; i < count; i++) {
16479343712SPeter Avalos 		cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
16579343712SPeter Avalos 		switch (info[i].pi_type) {
166f72f8299SJan Lentfer 		case CDF_NULL:
167f72f8299SJan Lentfer 			break;
16879343712SPeter Avalos 		case CDF_SIGNED16:
16979343712SPeter Avalos 			if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
17079343712SPeter Avalos 			    info[i].pi_s16) == -1)
17179343712SPeter Avalos 				return -1;
17279343712SPeter Avalos 			break;
17379343712SPeter Avalos 		case CDF_SIGNED32:
17479343712SPeter Avalos 			if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
17579343712SPeter Avalos 			    info[i].pi_s32) == -1)
17679343712SPeter Avalos 				return -1;
17779343712SPeter Avalos 			break;
17879343712SPeter Avalos 		case CDF_UNSIGNED32:
17979343712SPeter Avalos 			if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
18079343712SPeter Avalos 			    info[i].pi_u32) == -1)
18179343712SPeter Avalos 				return -1;
18279343712SPeter Avalos 			break;
18317b11469SPeter Avalos 		case CDF_FLOAT:
18417b11469SPeter Avalos 			if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
18517b11469SPeter Avalos 			    info[i].pi_f) == -1)
18617b11469SPeter Avalos 				return -1;
18717b11469SPeter Avalos 			break;
18817b11469SPeter Avalos 		case CDF_DOUBLE:
18917b11469SPeter Avalos 			if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
19017b11469SPeter Avalos 			    info[i].pi_d) == -1)
19117b11469SPeter Avalos 				return -1;
19217b11469SPeter Avalos 			break;
19379343712SPeter Avalos 		case CDF_LENGTH32_STRING:
194f72f8299SJan Lentfer 		case CDF_LENGTH32_WSTRING:
19579343712SPeter Avalos 			len = info[i].pi_str.s_len;
19679343712SPeter Avalos 			if (len > 1) {
19779343712SPeter Avalos 				char vbuf[1024];
198f72f8299SJan Lentfer 				size_t j, k = 1;
199f72f8299SJan Lentfer 
200f72f8299SJan Lentfer 				if (info[i].pi_type == CDF_LENGTH32_WSTRING)
201f72f8299SJan Lentfer 				    k++;
202f72f8299SJan Lentfer 				s = info[i].pi_str.s_buf;
203c30bd091SSascha Wildner 				e = info[i].pi_str.s_buf + len;
204c30bd091SSascha Wildner 				for (j = 0; s < e && j < sizeof(vbuf)
205c30bd091SSascha Wildner 				    && len--; s += k) {
20679343712SPeter Avalos 					if (*s == '\0')
20779343712SPeter Avalos 						break;
2086fca56fbSSascha Wildner 					if (isprint(CAST(unsigned char, *s)))
20982c5fa3eSPeter Avalos 						vbuf[j++] = *s;
21079343712SPeter Avalos 				}
21179343712SPeter Avalos 				if (j == sizeof(vbuf))
21279343712SPeter Avalos 					--j;
21379343712SPeter Avalos 				vbuf[j] = '\0';
214f72f8299SJan Lentfer 				if (NOTMIME(ms)) {
21579343712SPeter Avalos 					if (vbuf[0]) {
21679343712SPeter Avalos 						if (file_printf(ms, ", %s: %s",
21779343712SPeter Avalos 						    buf, vbuf) == -1)
21879343712SPeter Avalos 							return -1;
21979343712SPeter Avalos 					}
220e8af9738SPeter Avalos 				} else if (str == NULL && info[i].pi_id ==
22179343712SPeter Avalos 				    CDF_PROPERTY_NAME_OF_APPLICATION) {
222e8af9738SPeter Avalos 					str = cdf_app_to_mime(vbuf, app2mime);
22379343712SPeter Avalos 				}
22479343712SPeter Avalos 			}
22579343712SPeter Avalos 			break;
22679343712SPeter Avalos 		case CDF_FILETIME:
22779343712SPeter Avalos 			tp = info[i].pi_tp;
22879343712SPeter Avalos 			if (tp != 0) {
22979343712SPeter Avalos 				char tbuf[64];
230e8af9738SPeter Avalos 				if (tp < 1000000000000000LL) {
23179343712SPeter Avalos 					cdf_print_elapsed_time(tbuf,
23279343712SPeter Avalos 					    sizeof(tbuf), tp);
23379343712SPeter Avalos 					if (NOTMIME(ms) && file_printf(ms,
23479343712SPeter Avalos 					    ", %s: %s", buf, tbuf) == -1)
23579343712SPeter Avalos 						return -1;
23679343712SPeter Avalos 				} else {
23779343712SPeter Avalos 					char *c, *ec;
23879343712SPeter Avalos 					cdf_timestamp_to_timespec(&ts, tp);
239e8af9738SPeter Avalos 					c = cdf_ctime(&ts.tv_sec, tbuf);
240e8af9738SPeter Avalos 					if (c != NULL &&
241e8af9738SPeter Avalos 					    (ec = strchr(c, '\n')) != NULL)
24279343712SPeter Avalos 						*ec = '\0';
24379343712SPeter Avalos 
24479343712SPeter Avalos 					if (NOTMIME(ms) && file_printf(ms,
24579343712SPeter Avalos 					    ", %s: %s", buf, c) == -1)
24679343712SPeter Avalos 						return -1;
24779343712SPeter Avalos 				}
24879343712SPeter Avalos 			}
24979343712SPeter Avalos 			break;
25079343712SPeter Avalos 		case CDF_CLIPBOARD:
25179343712SPeter Avalos 			break;
25279343712SPeter Avalos 		default:
25379343712SPeter Avalos 			return -1;
25479343712SPeter Avalos 		}
25579343712SPeter Avalos 	}
2566fca56fbSSascha Wildner 	if (ms->flags & MAGIC_MIME_TYPE) {
257a96e001bSPeter Avalos 		if (str == NULL)
258a96e001bSPeter Avalos 			return 0;
2599f86ab30SPeter Avalos 		if (file_printf(ms, "application/%s", str) == -1)
2609f86ab30SPeter Avalos 			return -1;
26179343712SPeter Avalos 	}
26279343712SPeter Avalos 	return 1;
26379343712SPeter Avalos }
26479343712SPeter Avalos 
26579343712SPeter Avalos private int
cdf_file_catalog(struct magic_set * ms,const cdf_header_t * h,const cdf_stream_t * sst)26682c5fa3eSPeter Avalos cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
26782c5fa3eSPeter Avalos     const cdf_stream_t *sst)
26882c5fa3eSPeter Avalos {
26982c5fa3eSPeter Avalos 	cdf_catalog_t *cat;
27082c5fa3eSPeter Avalos 	size_t i;
27182c5fa3eSPeter Avalos 	char buf[256];
27282c5fa3eSPeter Avalos 	cdf_catalog_entry_t *ce;
27382c5fa3eSPeter Avalos 
27482c5fa3eSPeter Avalos 	if (NOTMIME(ms)) {
27582c5fa3eSPeter Avalos 		if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
27682c5fa3eSPeter Avalos 			return -1;
27782c5fa3eSPeter Avalos 		if (cdf_unpack_catalog(h, sst, &cat) == -1)
27882c5fa3eSPeter Avalos 			return -1;
27982c5fa3eSPeter Avalos 		ce = cat->cat_e;
28082c5fa3eSPeter Avalos 		/* skip first entry since it has a , or paren */
28182c5fa3eSPeter Avalos 		for (i = 1; i < cat->cat_num; i++)
28282c5fa3eSPeter Avalos 			if (file_printf(ms, "%s%s",
28382c5fa3eSPeter Avalos 			    cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
28482c5fa3eSPeter Avalos 			    i == cat->cat_num - 1 ? "]" : ", ") == -1) {
28582c5fa3eSPeter Avalos 				free(cat);
28682c5fa3eSPeter Avalos 				return -1;
28782c5fa3eSPeter Avalos 			}
28882c5fa3eSPeter Avalos 		free(cat);
2896fca56fbSSascha Wildner 	} else if (ms->flags & MAGIC_MIME_TYPE) {
29082c5fa3eSPeter Avalos 		if (file_printf(ms, "application/CDFV2") == -1)
29182c5fa3eSPeter Avalos 			return -1;
29282c5fa3eSPeter Avalos 	}
29382c5fa3eSPeter Avalos 	return 1;
29482c5fa3eSPeter Avalos }
29582c5fa3eSPeter Avalos 
29682c5fa3eSPeter Avalos 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)297ff91a668SPeter Avalos cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
29882c5fa3eSPeter Avalos     const cdf_stream_t *sst, const cdf_directory_t *root_storage)
29979343712SPeter Avalos {
30079343712SPeter Avalos 	cdf_summary_info_header_t si;
30179343712SPeter Avalos 	cdf_property_info_t *info;
30279343712SPeter Avalos 	size_t count;
30379343712SPeter Avalos 	int m;
30479343712SPeter Avalos 
305ff91a668SPeter Avalos 	if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1)
30679343712SPeter Avalos 		return -1;
30779343712SPeter Avalos 
30879343712SPeter Avalos 	if (NOTMIME(ms)) {
309e8af9738SPeter Avalos 		const char *str;
310e8af9738SPeter Avalos 
31117b11469SPeter Avalos 		if (file_printf(ms, "Composite Document File V2 Document")
31217b11469SPeter Avalos 		    == -1)
31379343712SPeter Avalos 			return -1;
31479343712SPeter Avalos 
31579343712SPeter Avalos 		if (file_printf(ms, ", %s Endian",
31679343712SPeter Avalos 		    si.si_byte_order == 0xfffe ?  "Little" : "Big") == -1)
31717b11469SPeter Avalos 			return -2;
31879343712SPeter Avalos 		switch (si.si_os) {
31979343712SPeter Avalos 		case 2:
32079343712SPeter Avalos 			if (file_printf(ms, ", Os: Windows, Version %d.%d",
321f72f8299SJan Lentfer 			    si.si_os_version & 0xff,
3226fca56fbSSascha Wildner 			    CAST(uint32_t, si.si_os_version) >> 8) == -1)
32317b11469SPeter Avalos 				return -2;
32479343712SPeter Avalos 			break;
32579343712SPeter Avalos 		case 1:
32679343712SPeter Avalos 			if (file_printf(ms, ", Os: MacOS, Version %d.%d",
3276fca56fbSSascha Wildner 			    CAST(uint32_t, si.si_os_version) >> 8,
328f72f8299SJan Lentfer 			    si.si_os_version & 0xff) == -1)
32917b11469SPeter Avalos 				return -2;
33079343712SPeter Avalos 			break;
33179343712SPeter Avalos 		default:
33279343712SPeter Avalos 			if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
333f72f8299SJan Lentfer 			    si.si_os_version & 0xff,
3346fca56fbSSascha Wildner 			    CAST(uint32_t, si.si_os_version) >> 8) == -1)
33517b11469SPeter Avalos 				return -2;
33679343712SPeter Avalos 			break;
33779343712SPeter Avalos 		}
33882c5fa3eSPeter Avalos 		if (root_storage) {
33982c5fa3eSPeter Avalos 			str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
34082c5fa3eSPeter Avalos 			    clsid2desc);
34182c5fa3eSPeter Avalos 			if (str) {
342e8af9738SPeter Avalos 				if (file_printf(ms, ", %s", str) == -1)
343e8af9738SPeter Avalos 					return -2;
34479343712SPeter Avalos 			}
34582c5fa3eSPeter Avalos 		}
34682c5fa3eSPeter Avalos 	}
34779343712SPeter Avalos 
34882c5fa3eSPeter Avalos 	m = cdf_file_property_info(ms, info, count, root_storage);
34979343712SPeter Avalos 	free(info);
35079343712SPeter Avalos 
35117b11469SPeter Avalos 	return m == -1 ? -2 : m;
35279343712SPeter Avalos }
35379343712SPeter Avalos 
354e8af9738SPeter Avalos #ifdef notdef
355e8af9738SPeter Avalos private char *
format_clsid(char * buf,size_t len,const uint64_t uuid[2])356e8af9738SPeter Avalos format_clsid(char *buf, size_t len, const uint64_t uuid[2]) {
357e8af9738SPeter Avalos 	snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4"
358e8af9738SPeter Avalos 	    PRIx64 "-%.12" PRIx64,
35982c5fa3eSPeter Avalos 	    (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL,
36082c5fa3eSPeter Avalos 	    (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL,
36182c5fa3eSPeter Avalos 	    (uuid[0] >>  0) & (uint64_t)0x0000000000000ffffULL,
36282c5fa3eSPeter Avalos 	    (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL,
36382c5fa3eSPeter Avalos 	    (uuid[1] >>  0) & (uint64_t)0x0000fffffffffffffULL);
364e8af9738SPeter Avalos 	return buf;
365e8af9738SPeter Avalos }
366e8af9738SPeter Avalos #endif
367e8af9738SPeter Avalos 
368c30bd091SSascha Wildner 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)369c30bd091SSascha Wildner cdf_file_catalog_info(struct magic_set *ms, const cdf_info_t *info,
370c30bd091SSascha Wildner     const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
371c30bd091SSascha Wildner     const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn)
372c30bd091SSascha Wildner {
373c30bd091SSascha Wildner 	int i;
374c30bd091SSascha Wildner 
375c30bd091SSascha Wildner 	if ((i = cdf_read_user_stream(info, h, sat, ssat, sst,
376c30bd091SSascha Wildner 	    dir, "Catalog", scn)) == -1)
377c30bd091SSascha Wildner 		return i;
378c30bd091SSascha Wildner #ifdef CDF_DEBUG
379c30bd091SSascha Wildner 	cdf_dump_catalog(h, scn);
380c30bd091SSascha Wildner #endif
381c30bd091SSascha Wildner 	if ((i = cdf_file_catalog(ms, h, scn)) == -1)
382c30bd091SSascha Wildner 		return -1;
383c30bd091SSascha Wildner 	return i;
384c30bd091SSascha Wildner }
385c30bd091SSascha Wildner 
386c30bd091SSascha Wildner 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)387c30bd091SSascha Wildner cdf_check_summary_info(struct magic_set *ms, const cdf_info_t *info,
388c30bd091SSascha Wildner     const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
389c30bd091SSascha Wildner     const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn,
390c30bd091SSascha Wildner     const cdf_directory_t *root_storage, const char **expn)
391c30bd091SSascha Wildner {
392c30bd091SSascha Wildner 	int i;
393c30bd091SSascha Wildner 	const char *str = NULL;
394c30bd091SSascha Wildner 	cdf_directory_t *d;
395c30bd091SSascha Wildner 	char name[__arraycount(d->d_name)];
396c30bd091SSascha Wildner 	size_t j, k;
397c30bd091SSascha Wildner 
398c30bd091SSascha Wildner #ifdef CDF_DEBUG
399c30bd091SSascha Wildner 	cdf_dump_summary_info(h, scn);
400c30bd091SSascha Wildner #endif
401c30bd091SSascha Wildner 	if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) {
402c30bd091SSascha Wildner 	    *expn = "Can't expand summary_info";
403c30bd091SSascha Wildner 	    return i;
404c30bd091SSascha Wildner 	}
405c30bd091SSascha Wildner 	if (i == 1)
406c30bd091SSascha Wildner 		return i;
407c30bd091SSascha Wildner 	for (j = 0; str == NULL && j < dir->dir_len; j++) {
408c30bd091SSascha Wildner 		d = &dir->dir_tab[j];
409c30bd091SSascha Wildner 		for (k = 0; k < sizeof(name); k++)
4106fca56fbSSascha Wildner 			name[k] = CAST(char, cdf_tole2(d->d_name[k]));
411c30bd091SSascha Wildner 		str = cdf_app_to_mime(name,
412c30bd091SSascha Wildner 				      NOTMIME(ms) ? name2desc : name2mime);
413c30bd091SSascha Wildner 	}
414c30bd091SSascha Wildner 	if (NOTMIME(ms)) {
415c30bd091SSascha Wildner 		if (str != NULL) {
416c30bd091SSascha Wildner 			if (file_printf(ms, "%s", str) == -1)
417c30bd091SSascha Wildner 				return -1;
418c30bd091SSascha Wildner 			i = 1;
419c30bd091SSascha Wildner 		}
4206fca56fbSSascha Wildner 	} else if (ms->flags & MAGIC_MIME_TYPE) {
421c30bd091SSascha Wildner 		if (str == NULL)
422c30bd091SSascha Wildner 			str = "vnd.ms-office";
423c30bd091SSascha Wildner 		if (file_printf(ms, "application/%s", str) == -1)
424c30bd091SSascha Wildner 			return -1;
425c30bd091SSascha Wildner 		i = 1;
426c30bd091SSascha Wildner 	}
427c30bd091SSascha Wildner 	if (i <= 0) {
428c30bd091SSascha Wildner 		i = cdf_file_catalog_info(ms, info, h, sat, ssat, sst,
429c30bd091SSascha Wildner 					  dir, scn);
430c30bd091SSascha Wildner 	}
431c30bd091SSascha Wildner 	return i;
432c30bd091SSascha Wildner }
433c30bd091SSascha Wildner 
434c30bd091SSascha Wildner private struct sinfo {
435c30bd091SSascha Wildner 	const char *name;
436c30bd091SSascha Wildner 	const char *mime;
437c30bd091SSascha Wildner 	const char *sections[5];
438c30bd091SSascha Wildner 	const int  types[5];
439c30bd091SSascha Wildner } sectioninfo[] = {
440c30bd091SSascha Wildner 	{ "Encrypted", "encrypted",
441c30bd091SSascha Wildner 		{
442c30bd091SSascha Wildner 			"EncryptedPackage", "EncryptedSummary",
443c30bd091SSascha Wildner 			NULL, NULL, NULL,
444c30bd091SSascha Wildner 		},
445c30bd091SSascha Wildner 		{
446c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
447c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
448c30bd091SSascha Wildner 			0, 0, 0,
449c30bd091SSascha Wildner 
450c30bd091SSascha Wildner 		},
451c30bd091SSascha Wildner 	},
452c30bd091SSascha Wildner 	{ "QuickBooks", "quickbooks",
453c30bd091SSascha Wildner 		{
454c30bd091SSascha Wildner #if 0
455c30bd091SSascha Wildner 			"TaxForms", "PDFTaxForms", "modulesInBackup",
456c30bd091SSascha Wildner #endif
457c30bd091SSascha Wildner 			"mfbu_header", NULL, NULL, NULL, NULL,
458c30bd091SSascha Wildner 		},
459c30bd091SSascha Wildner 		{
460c30bd091SSascha Wildner #if 0
461c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STORAGE,
462c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STORAGE,
463c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
464c30bd091SSascha Wildner #endif
465c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
466c30bd091SSascha Wildner 			0, 0, 0, 0
467c30bd091SSascha Wildner 		},
468c30bd091SSascha Wildner 	},
469c30bd091SSascha Wildner 	{ "Microsoft Excel", "vnd.ms-excel",
470c30bd091SSascha Wildner 		{
471c30bd091SSascha Wildner 			"Book", "Workbook", NULL, NULL, NULL,
472c30bd091SSascha Wildner 		},
473c30bd091SSascha Wildner 		{
474c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
475c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
476c30bd091SSascha Wildner 			0, 0, 0,
477c30bd091SSascha Wildner 		},
478c30bd091SSascha Wildner 	},
479c30bd091SSascha Wildner 	{ "Microsoft Word", "msword",
480c30bd091SSascha Wildner 		{
481c30bd091SSascha Wildner 			"WordDocument", NULL, NULL, NULL, NULL,
482c30bd091SSascha Wildner 		},
483c30bd091SSascha Wildner 		{
484c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
485c30bd091SSascha Wildner 			0, 0, 0, 0,
486c30bd091SSascha Wildner 		},
487c30bd091SSascha Wildner 	},
488c30bd091SSascha Wildner 	{ "Microsoft PowerPoint", "vnd.ms-powerpoint",
489c30bd091SSascha Wildner 		{
490c30bd091SSascha Wildner 			"PowerPoint", NULL, NULL, NULL, NULL,
491c30bd091SSascha Wildner 		},
492c30bd091SSascha Wildner 		{
493c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
494c30bd091SSascha Wildner 			0, 0, 0, 0,
495c30bd091SSascha Wildner 		},
496c30bd091SSascha Wildner 	},
497c30bd091SSascha Wildner 	{ "Microsoft Outlook Message", "vnd.ms-outlook",
498c30bd091SSascha Wildner 		{
499c30bd091SSascha Wildner 			"__properties_version1.0",
500c30bd091SSascha Wildner 			"__recip_version1.0_#00000000",
501c30bd091SSascha Wildner 			NULL, NULL, NULL,
502c30bd091SSascha Wildner 		},
503c30bd091SSascha Wildner 		{
504c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STREAM,
505c30bd091SSascha Wildner 			CDF_DIR_TYPE_USER_STORAGE,
506c30bd091SSascha Wildner 			0, 0, 0,
507c30bd091SSascha Wildner 		},
508c30bd091SSascha Wildner 	},
509c30bd091SSascha Wildner };
510c30bd091SSascha Wildner 
511c30bd091SSascha Wildner private int
cdf_file_dir_info(struct magic_set * ms,const cdf_dir_t * dir)512c30bd091SSascha Wildner cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir)
513c30bd091SSascha Wildner {
514c30bd091SSascha Wildner 	size_t sd, j;
515c30bd091SSascha Wildner 
516c30bd091SSascha Wildner 	for (sd = 0; sd < __arraycount(sectioninfo); sd++) {
517c30bd091SSascha Wildner 		const struct sinfo *si = &sectioninfo[sd];
518c30bd091SSascha Wildner 		for (j = 0; si->sections[j]; j++) {
519c30bd091SSascha Wildner 			if (cdf_find_stream(dir, si->sections[j], si->types[j])
520c30bd091SSascha Wildner 			    > 0)
521c30bd091SSascha Wildner 				break;
522c30bd091SSascha Wildner #ifdef CDF_DEBUG
523c30bd091SSascha Wildner 			fprintf(stderr, "Can't read %s\n", si->sections[j]);
524c30bd091SSascha Wildner #endif
525c30bd091SSascha Wildner 		}
526c30bd091SSascha Wildner 		if (si->sections[j] == NULL)
527c30bd091SSascha Wildner 			continue;
528c30bd091SSascha Wildner 		if (NOTMIME(ms)) {
529c30bd091SSascha Wildner 			if (file_printf(ms, "CDFV2 %s", si->name) == -1)
530c30bd091SSascha Wildner 				return -1;
5316fca56fbSSascha Wildner 		} else if (ms->flags & MAGIC_MIME_TYPE) {
532c30bd091SSascha Wildner 			if (file_printf(ms, "application/%s", si->mime) == -1)
533c30bd091SSascha Wildner 				return -1;
534c30bd091SSascha Wildner 		}
535c30bd091SSascha Wildner 		return 1;
536c30bd091SSascha Wildner 	}
537c30bd091SSascha Wildner 	return -1;
538c30bd091SSascha Wildner }
539c30bd091SSascha Wildner 
54079343712SPeter Avalos protected int
file_trycdf(struct magic_set * ms,const struct buffer * b)5416fca56fbSSascha Wildner file_trycdf(struct magic_set *ms, const struct buffer *b)
54279343712SPeter Avalos {
5436fca56fbSSascha Wildner 	int fd = b->fd;
5446fca56fbSSascha Wildner 	const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
5456fca56fbSSascha Wildner 	size_t nbytes = b->flen;
54679343712SPeter Avalos 	cdf_info_t info;
54779343712SPeter Avalos 	cdf_header_t h;
54879343712SPeter Avalos 	cdf_sat_t sat, ssat;
54979343712SPeter Avalos 	cdf_stream_t sst, scn;
55079343712SPeter Avalos 	cdf_dir_t dir;
55179343712SPeter Avalos 	int i;
55279343712SPeter Avalos 	const char *expn = "";
55382c5fa3eSPeter Avalos 	const cdf_directory_t *root_storage;
55479343712SPeter Avalos 
555c30bd091SSascha Wildner 	scn.sst_tab = NULL;
55679343712SPeter Avalos 	info.i_fd = fd;
55779343712SPeter Avalos 	info.i_buf = buf;
55879343712SPeter Avalos 	info.i_len = nbytes;
559c30bd091SSascha Wildner 	if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))
56079343712SPeter Avalos 		return 0;
56179343712SPeter Avalos 	if (cdf_read_header(&info, &h) == -1)
56279343712SPeter Avalos 		return 0;
56379343712SPeter Avalos #ifdef CDF_DEBUG
56479343712SPeter Avalos 	cdf_dump_header(&h);
56579343712SPeter Avalos #endif
56679343712SPeter Avalos 
56779343712SPeter Avalos 	if ((i = cdf_read_sat(&info, &h, &sat)) == -1) {
56879343712SPeter Avalos 		expn = "Can't read SAT";
56979343712SPeter Avalos 		goto out0;
57079343712SPeter Avalos 	}
57179343712SPeter Avalos #ifdef CDF_DEBUG
57279343712SPeter Avalos 	cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
57379343712SPeter Avalos #endif
57479343712SPeter Avalos 
57579343712SPeter Avalos 	if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) {
57679343712SPeter Avalos 		expn = "Can't read SSAT";
57779343712SPeter Avalos 		goto out1;
57879343712SPeter Avalos 	}
57979343712SPeter Avalos #ifdef CDF_DEBUG
58079343712SPeter Avalos 	cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
58179343712SPeter Avalos #endif
58279343712SPeter Avalos 
58379343712SPeter Avalos 	if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) {
58479343712SPeter Avalos 		expn = "Can't read directory";
58579343712SPeter Avalos 		goto out2;
58679343712SPeter Avalos 	}
58779343712SPeter Avalos 
588e8af9738SPeter Avalos 	if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst,
589e8af9738SPeter Avalos 	    &root_storage)) == -1) {
59079343712SPeter Avalos 		expn = "Cannot read short stream";
59179343712SPeter Avalos 		goto out3;
59279343712SPeter Avalos 	}
59379343712SPeter Avalos #ifdef CDF_DEBUG
59479343712SPeter Avalos 	cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
59579343712SPeter Avalos #endif
596e8af9738SPeter Avalos #ifdef notdef
597e8af9738SPeter Avalos 	if (root_storage) {
598e8af9738SPeter Avalos 		if (NOTMIME(ms)) {
599e8af9738SPeter Avalos 			char clsbuf[128];
600e8af9738SPeter Avalos 			if (file_printf(ms, "CLSID %s, ",
601e8af9738SPeter Avalos 			    format_clsid(clsbuf, sizeof(clsbuf),
602e8af9738SPeter Avalos 			    root_storage->d_storage_uuid)) == -1)
603e8af9738SPeter Avalos 				return -1;
604e8af9738SPeter Avalos 		}
605e8af9738SPeter Avalos 	}
606e8af9738SPeter Avalos #endif
60779343712SPeter Avalos 
608*3b9cdfa3SAntonio Huete Jimenez 	if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir,
609*3b9cdfa3SAntonio Huete Jimenez 	    "FileHeader", &scn) != -1) {
61082c5fa3eSPeter Avalos #define HWP5_SIGNATURE "HWP Document File"
611c30bd091SSascha Wildner 		if (scn.sst_len * scn.sst_ss >= sizeof(HWP5_SIGNATURE) - 1
61282c5fa3eSPeter Avalos 		    && memcmp(scn.sst_tab, HWP5_SIGNATURE,
61382c5fa3eSPeter Avalos 		    sizeof(HWP5_SIGNATURE) - 1) == 0) {
61482c5fa3eSPeter Avalos 		    if (NOTMIME(ms)) {
61582c5fa3eSPeter Avalos 			if (file_printf(ms,
61682c5fa3eSPeter Avalos 			    "Hangul (Korean) Word Processor File 5.x") == -1)
61782c5fa3eSPeter Avalos 			    return -1;
6186fca56fbSSascha Wildner 		    } else if (ms->flags & MAGIC_MIME_TYPE) {
61982c5fa3eSPeter Avalos 			if (file_printf(ms, "application/x-hwp") == -1)
62082c5fa3eSPeter Avalos 			    return -1;
62182c5fa3eSPeter Avalos 		    }
62282c5fa3eSPeter Avalos 		    i = 1;
62382c5fa3eSPeter Avalos 		    goto out5;
62482c5fa3eSPeter Avalos 		} else {
625c30bd091SSascha Wildner 		    cdf_zero_stream(&scn);
62682c5fa3eSPeter Avalos 		}
62782c5fa3eSPeter Avalos 	}
62882c5fa3eSPeter Avalos 
62979343712SPeter Avalos 	if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
63079343712SPeter Avalos 	    &scn)) == -1) {
631c30bd091SSascha Wildner 		if (errno != ESRCH) {
63279343712SPeter Avalos 			expn = "Cannot read summary info";
633f72f8299SJan Lentfer 		}
634c30bd091SSascha Wildner 	} else {
635c30bd091SSascha Wildner 		i = cdf_check_summary_info(ms, &info, &h,
636c30bd091SSascha Wildner 		    &sat, &ssat, &sst, &dir, &scn, root_storage, &expn);
637c30bd091SSascha Wildner 		cdf_zero_stream(&scn);
63879343712SPeter Avalos 	}
639c30bd091SSascha Wildner 	if (i <= 0) {
640c30bd091SSascha Wildner 		if ((i = cdf_read_doc_summary_info(&info, &h, &sat, &ssat,
641c30bd091SSascha Wildner 		    &sst, &dir, &scn)) == -1) {
642c30bd091SSascha Wildner 			if (errno != ESRCH) {
643c30bd091SSascha Wildner 				expn = "Cannot read summary info";
644a96e001bSPeter Avalos 			}
645e8af9738SPeter Avalos 		} else {
646c30bd091SSascha Wildner 			i = cdf_check_summary_info(ms, &info, &h, &sat, &ssat,
647c30bd091SSascha Wildner 			    &sst, &dir, &scn, root_storage, &expn);
648a96e001bSPeter Avalos 		}
649e8af9738SPeter Avalos 	}
650c30bd091SSascha Wildner 	if (i <= 0) {
651c30bd091SSascha Wildner 		i = cdf_file_dir_info(ms, &dir);
652c30bd091SSascha Wildner 		if (i < 0)
653c30bd091SSascha Wildner 			expn = "Cannot read section info";
654c30bd091SSascha Wildner 	}
65582c5fa3eSPeter Avalos out5:
656c30bd091SSascha Wildner 	cdf_zero_stream(&scn);
657c30bd091SSascha Wildner 	cdf_zero_stream(&sst);
65879343712SPeter Avalos out3:
65979343712SPeter Avalos 	free(dir.dir_tab);
66079343712SPeter Avalos out2:
66179343712SPeter Avalos 	free(ssat.sat_tab);
66279343712SPeter Avalos out1:
66379343712SPeter Avalos 	free(sat.sat_tab);
66479343712SPeter Avalos out0:
6656fca56fbSSascha Wildner 	/* If we handled it already, return */
6666fca56fbSSascha Wildner 	if (i != -1)
6676fca56fbSSascha Wildner 		return i;
6686fca56fbSSascha Wildner 	/* Provide a default handler */
669e8af9738SPeter Avalos 	if (NOTMIME(ms)) {
670e8af9738SPeter Avalos 		if (file_printf(ms,
671e8af9738SPeter Avalos 		    "Composite Document File V2 Document") == -1)
67279343712SPeter Avalos 			return -1;
67379343712SPeter Avalos 		if (*expn)
674c30bd091SSascha Wildner 			if (file_printf(ms, ", %s", expn) == -1)
67579343712SPeter Avalos 				return -1;
6766fca56fbSSascha Wildner 	} else if (ms->flags & MAGIC_MIME_TYPE) {
677*3b9cdfa3SAntonio Huete Jimenez 		/* https://reposcope.com/mimetype/application/x-ole-storage */
678*3b9cdfa3SAntonio Huete Jimenez 		if (file_printf(ms, "application/x-ole-storage") == -1)
679e8af9738SPeter Avalos 			return -1;
680e8af9738SPeter Avalos 	}
6816fca56fbSSascha Wildner 	return 1;
68279343712SPeter Avalos }
683