1191739Sobrien/*-
2191739Sobrien * Copyright (c) 2008 Christos Zoulas
3191739Sobrien * All rights reserved.
4191739Sobrien *
5191739Sobrien * Redistribution and use in source and binary forms, with or without
6191739Sobrien * modification, are permitted provided that the following conditions
7191739Sobrien * are met:
8191739Sobrien * 1. Redistributions of source code must retain the above copyright
9191739Sobrien *    notice, this list of conditions and the following disclaimer.
10191739Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11191739Sobrien *    notice, this list of conditions and the following disclaimer in the
12191739Sobrien *    documentation and/or other materials provided with the distribution.
13191739Sobrien *
14191739Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15191739Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16191739Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17191739Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18191739Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19191739Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20191739Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21191739Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22191739Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23191739Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24191739Sobrien * POSSIBILITY OF SUCH DAMAGE.
25191739Sobrien */
26191739Sobrien#include "file.h"
27191739Sobrien
28191739Sobrien#ifndef lint
29284778SdelphijFILE_RCSID("@(#)$File: readcdf.c,v 1.53 2015/04/09 20:01:41 christos Exp $")
30191739Sobrien#endif
31191739Sobrien
32267843Sdelphij#include <assert.h>
33191739Sobrien#include <stdlib.h>
34191739Sobrien#include <unistd.h>
35191739Sobrien#include <string.h>
36191739Sobrien#include <time.h>
37191739Sobrien#include <ctype.h>
38191739Sobrien
39191739Sobrien#include "cdf.h"
40191739Sobrien#include "magic.h"
41191739Sobrien
42284778Sdelphij#ifndef __arraycount
43284778Sdelphij#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
44284778Sdelphij#endif
45284778Sdelphij
46191739Sobrien#define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
47191739Sobrien
48267843Sdelphijstatic const struct nv {
49267843Sdelphij	const char *pattern;
50267843Sdelphij	const char *mime;
51267843Sdelphij} app2mime[] =  {
52267843Sdelphij	{ "Word",			"msword",		},
53267843Sdelphij	{ "Excel",			"vnd.ms-excel",		},
54267843Sdelphij	{ "Powerpoint",			"vnd.ms-powerpoint",	},
55267843Sdelphij	{ "Crystal Reports",		"x-rpt",		},
56267843Sdelphij	{ "Advanced Installer",		"vnd.ms-msi",		},
57267843Sdelphij	{ "InstallShield",		"vnd.ms-msi",		},
58267843Sdelphij	{ "Microsoft Patch Compiler",	"vnd.ms-msi",		},
59267843Sdelphij	{ "NAnt",			"vnd.ms-msi",		},
60267843Sdelphij	{ "Windows Installer",		"vnd.ms-msi",		},
61267843Sdelphij	{ NULL,				NULL,			},
62267843Sdelphij}, name2mime[] = {
63267843Sdelphij	{ "WordDocument",		"msword",		},
64267843Sdelphij	{ "PowerPoint",			"vnd.ms-powerpoint",	},
65267843Sdelphij	{ "DigitalSignature",		"vnd.ms-msi",		},
66267843Sdelphij	{ NULL,				NULL,			},
67267843Sdelphij}, name2desc[] = {
68267843Sdelphij	{ "WordDocument",		"Microsoft Office Word",},
69267843Sdelphij	{ "PowerPoint",			"Microsoft PowerPoint",	},
70267843Sdelphij	{ "DigitalSignature",		"Microsoft Installer",	},
71267843Sdelphij	{ NULL,				NULL,			},
72267843Sdelphij};
73267843Sdelphij
74267843Sdelphijstatic const struct cv {
75267843Sdelphij	uint64_t clsid[2];
76267843Sdelphij	const char *mime;
77267843Sdelphij} clsid2mime[] = {
78267843Sdelphij	{
79276415Sdelphij		{ 0x00000000000c1084ULL, 0x46000000000000c0ULL  },
80267843Sdelphij		"x-msi",
81267843Sdelphij	},
82267843Sdelphij	{	{ 0,			 0			},
83267843Sdelphij		NULL,
84267843Sdelphij	},
85267843Sdelphij}, clsid2desc[] = {
86267843Sdelphij	{
87276415Sdelphij		{ 0x00000000000c1084ULL, 0x46000000000000c0ULL  },
88267843Sdelphij		"MSI Installer",
89267843Sdelphij	},
90267843Sdelphij	{	{ 0,			 0			},
91267843Sdelphij		NULL,
92267843Sdelphij	},
93267843Sdelphij};
94267843Sdelphij
95267843Sdelphijprivate const char *
96267843Sdelphijcdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv)
97267843Sdelphij{
98267843Sdelphij	size_t i;
99267843Sdelphij	for (i = 0; cv[i].mime != NULL; i++) {
100267843Sdelphij		if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1])
101267843Sdelphij			return cv[i].mime;
102267843Sdelphij	}
103284778Sdelphij#ifdef CDF_DEBUG
104284778Sdelphij	fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0],
105284778Sdelphij	    clsid[1]);
106284778Sdelphij#endif
107267843Sdelphij	return NULL;
108267843Sdelphij}
109267843Sdelphij
110267843Sdelphijprivate const char *
111267843Sdelphijcdf_app_to_mime(const char *vbuf, const struct nv *nv)
112267843Sdelphij{
113267843Sdelphij	size_t i;
114267843Sdelphij	const char *rv = NULL;
115276415Sdelphij#ifdef USE_C_LOCALE
116276415Sdelphij	locale_t old_lc_ctype, c_lc_ctype;
117267843Sdelphij
118276415Sdelphij	c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
119276415Sdelphij	assert(c_lc_ctype != NULL);
120276415Sdelphij	old_lc_ctype = uselocale(c_lc_ctype);
121267843Sdelphij	assert(old_lc_ctype != NULL);
122276415Sdelphij#endif
123267843Sdelphij	for (i = 0; nv[i].pattern != NULL; i++)
124267843Sdelphij		if (strcasestr(vbuf, nv[i].pattern) != NULL) {
125267843Sdelphij			rv = nv[i].mime;
126267843Sdelphij			break;
127267843Sdelphij		}
128284778Sdelphij#ifdef CDF_DEBUG
129284778Sdelphij	fprintf(stderr, "unknown app %s\n", vbuf);
130284778Sdelphij#endif
131276415Sdelphij#ifdef USE_C_LOCALE
132276415Sdelphij	(void)uselocale(old_lc_ctype);
133276415Sdelphij	freelocale(c_lc_ctype);
134276415Sdelphij#endif
135267843Sdelphij	return rv;
136267843Sdelphij}
137267843Sdelphij
138191739Sobrienprivate int
139191739Sobriencdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
140267843Sdelphij    size_t count, const cdf_directory_t *root_storage)
141191739Sobrien{
142226048Sobrien        size_t i;
143226048Sobrien        cdf_timestamp_t tp;
144226048Sobrien        struct timespec ts;
145226048Sobrien        char buf[64];
146226048Sobrien        const char *str = NULL;
147226048Sobrien        const char *s;
148226048Sobrien        int len;
149191739Sobrien
150267843Sdelphij        if (!NOTMIME(ms) && root_storage)
151267843Sdelphij		str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
152267843Sdelphij		    clsid2mime);
153267843Sdelphij
154226048Sobrien        for (i = 0; i < count; i++) {
155226048Sobrien                cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
156226048Sobrien                switch (info[i].pi_type) {
157226048Sobrien                case CDF_NULL:
158226048Sobrien                        break;
159226048Sobrien                case CDF_SIGNED16:
160226048Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
161226048Sobrien                            info[i].pi_s16) == -1)
162226048Sobrien                                return -1;
163226048Sobrien                        break;
164226048Sobrien                case CDF_SIGNED32:
165226048Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
166226048Sobrien                            info[i].pi_s32) == -1)
167226048Sobrien                                return -1;
168226048Sobrien                        break;
169226048Sobrien                case CDF_UNSIGNED32:
170226048Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
171226048Sobrien                            info[i].pi_u32) == -1)
172226048Sobrien                                return -1;
173226048Sobrien                        break;
174234250Sobrien                case CDF_FLOAT:
175234250Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
176234250Sobrien                            info[i].pi_f) == -1)
177234250Sobrien                                return -1;
178234250Sobrien                        break;
179234250Sobrien                case CDF_DOUBLE:
180234250Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
181234250Sobrien                            info[i].pi_d) == -1)
182234250Sobrien                                return -1;
183234250Sobrien                        break;
184226048Sobrien                case CDF_LENGTH32_STRING:
185226048Sobrien                case CDF_LENGTH32_WSTRING:
186226048Sobrien                        len = info[i].pi_str.s_len;
187226048Sobrien                        if (len > 1) {
188226048Sobrien                                char vbuf[1024];
189226048Sobrien                                size_t j, k = 1;
190191739Sobrien
191226048Sobrien                                if (info[i].pi_type == CDF_LENGTH32_WSTRING)
192226048Sobrien                                    k++;
193226048Sobrien                                s = info[i].pi_str.s_buf;
194267843Sdelphij                                for (j = 0; j < sizeof(vbuf) && len--; s += k) {
195226048Sobrien                                        if (*s == '\0')
196226048Sobrien                                                break;
197226048Sobrien                                        if (isprint((unsigned char)*s))
198267843Sdelphij                                                vbuf[j++] = *s;
199226048Sobrien                                }
200226048Sobrien                                if (j == sizeof(vbuf))
201226048Sobrien                                        --j;
202226048Sobrien                                vbuf[j] = '\0';
203226048Sobrien                                if (NOTMIME(ms)) {
204226048Sobrien                                        if (vbuf[0]) {
205226048Sobrien                                                if (file_printf(ms, ", %s: %s",
206226048Sobrien                                                    buf, vbuf) == -1)
207226048Sobrien                                                        return -1;
208226048Sobrien                                        }
209267843Sdelphij                                } else if (str == NULL && info[i].pi_id ==
210267843Sdelphij				    CDF_PROPERTY_NAME_OF_APPLICATION) {
211267843Sdelphij					str = cdf_app_to_mime(vbuf, app2mime);
212267843Sdelphij				}
213267843Sdelphij			}
214226048Sobrien                        break;
215226048Sobrien                case CDF_FILETIME:
216226048Sobrien                        tp = info[i].pi_tp;
217226048Sobrien                        if (tp != 0) {
218267843Sdelphij				char tbuf[64];
219226048Sobrien                                if (tp < 1000000000000000LL) {
220226048Sobrien                                        cdf_print_elapsed_time(tbuf,
221226048Sobrien                                            sizeof(tbuf), tp);
222226048Sobrien                                        if (NOTMIME(ms) && file_printf(ms,
223226048Sobrien                                            ", %s: %s", buf, tbuf) == -1)
224226048Sobrien                                                return -1;
225226048Sobrien                                } else {
226226048Sobrien                                        char *c, *ec;
227226048Sobrien                                        cdf_timestamp_to_timespec(&ts, tp);
228267843Sdelphij                                        c = cdf_ctime(&ts.tv_sec, tbuf);
229267843Sdelphij                                        if (c != NULL &&
230267843Sdelphij					    (ec = strchr(c, '\n')) != NULL)
231267843Sdelphij						*ec = '\0';
232226048Sobrien
233226048Sobrien                                        if (NOTMIME(ms) && file_printf(ms,
234226048Sobrien                                            ", %s: %s", buf, c) == -1)
235226048Sobrien                                                return -1;
236226048Sobrien                                }
237226048Sobrien                        }
238226048Sobrien                        break;
239226048Sobrien                case CDF_CLIPBOARD:
240226048Sobrien                        break;
241226048Sobrien                default:
242226048Sobrien                        return -1;
243226048Sobrien                }
244226048Sobrien        }
245226048Sobrien        if (!NOTMIME(ms)) {
246226048Sobrien		if (str == NULL)
247226048Sobrien			return 0;
248234250Sobrien                if (file_printf(ms, "application/%s", str) == -1)
249234250Sobrien                        return -1;
250226048Sobrien        }
251226048Sobrien        return 1;
252191739Sobrien}
253191739Sobrien
254191739Sobrienprivate int
255276415Sdelphijcdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
256276415Sdelphij    const cdf_stream_t *sst)
257276415Sdelphij{
258276415Sdelphij	cdf_catalog_t *cat;
259276415Sdelphij	size_t i;
260276415Sdelphij	char buf[256];
261276415Sdelphij	cdf_catalog_entry_t *ce;
262276415Sdelphij
263276415Sdelphij        if (NOTMIME(ms)) {
264276415Sdelphij		if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
265276415Sdelphij			return -1;
266276415Sdelphij		if (cdf_unpack_catalog(h, sst, &cat) == -1)
267276415Sdelphij			return -1;
268276415Sdelphij		ce = cat->cat_e;
269276415Sdelphij		/* skip first entry since it has a , or paren */
270276415Sdelphij		for (i = 1; i < cat->cat_num; i++)
271276415Sdelphij			if (file_printf(ms, "%s%s",
272276415Sdelphij			    cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
273276415Sdelphij			    i == cat->cat_num - 1 ? "]" : ", ") == -1) {
274276415Sdelphij				free(cat);
275276415Sdelphij				return -1;
276276415Sdelphij			}
277276415Sdelphij		free(cat);
278276415Sdelphij	} else {
279276415Sdelphij		if (file_printf(ms, "application/CDFV2") == -1)
280276415Sdelphij			return -1;
281276415Sdelphij	}
282276415Sdelphij	return 1;
283276415Sdelphij}
284276415Sdelphij
285276415Sdelphijprivate int
286226048Sobriencdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
287267843Sdelphij    const cdf_stream_t *sst, const cdf_directory_t *root_storage)
288191739Sobrien{
289226048Sobrien        cdf_summary_info_header_t si;
290226048Sobrien        cdf_property_info_t *info;
291226048Sobrien        size_t count;
292226048Sobrien        int m;
293191739Sobrien
294226048Sobrien        if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1)
295226048Sobrien                return -1;
296191739Sobrien
297226048Sobrien        if (NOTMIME(ms)) {
298267843Sdelphij		const char *str;
299267843Sdelphij
300234250Sobrien                if (file_printf(ms, "Composite Document File V2 Document")
301234250Sobrien		    == -1)
302226048Sobrien                        return -1;
303191739Sobrien
304226048Sobrien                if (file_printf(ms, ", %s Endian",
305226048Sobrien                    si.si_byte_order == 0xfffe ?  "Little" : "Big") == -1)
306234250Sobrien                        return -2;
307226048Sobrien                switch (si.si_os) {
308226048Sobrien                case 2:
309226048Sobrien                        if (file_printf(ms, ", Os: Windows, Version %d.%d",
310226048Sobrien                            si.si_os_version & 0xff,
311226048Sobrien                            (uint32_t)si.si_os_version >> 8) == -1)
312234250Sobrien                                return -2;
313226048Sobrien                        break;
314226048Sobrien                case 1:
315226048Sobrien                        if (file_printf(ms, ", Os: MacOS, Version %d.%d",
316226048Sobrien                            (uint32_t)si.si_os_version >> 8,
317226048Sobrien                            si.si_os_version & 0xff) == -1)
318234250Sobrien                                return -2;
319226048Sobrien                        break;
320226048Sobrien                default:
321226048Sobrien                        if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
322226048Sobrien                            si.si_os_version & 0xff,
323226048Sobrien                            (uint32_t)si.si_os_version >> 8) == -1)
324234250Sobrien                                return -2;
325226048Sobrien                        break;
326226048Sobrien                }
327267843Sdelphij		if (root_storage) {
328267843Sdelphij			str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
329267843Sdelphij			    clsid2desc);
330276415Sdelphij			if (str) {
331267843Sdelphij				if (file_printf(ms, ", %s", str) == -1)
332267843Sdelphij					return -2;
333267843Sdelphij			}
334267843Sdelphij		}
335276415Sdelphij	}
336191739Sobrien
337267843Sdelphij        m = cdf_file_property_info(ms, info, count, root_storage);
338226048Sobrien        free(info);
339191739Sobrien
340234250Sobrien        return m == -1 ? -2 : m;
341191739Sobrien}
342191739Sobrien
343267843Sdelphij#ifdef notdef
344267843Sdelphijprivate char *
345267843Sdelphijformat_clsid(char *buf, size_t len, const uint64_t uuid[2]) {
346267843Sdelphij	snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4"
347267843Sdelphij	    PRIx64 "-%.12" PRIx64,
348276415Sdelphij	    (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL,
349276415Sdelphij	    (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL,
350276415Sdelphij	    (uuid[0] >>  0) & (uint64_t)0x0000000000000ffffULL,
351276415Sdelphij	    (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL,
352276415Sdelphij	    (uuid[1] >>  0) & (uint64_t)0x0000fffffffffffffULL);
353267843Sdelphij	return buf;
354267843Sdelphij}
355267843Sdelphij#endif
356267843Sdelphij
357284778Sdelphijprivate int
358284778Sdelphijcdf_file_catalog_info(struct magic_set *ms, const cdf_info_t *info,
359284778Sdelphij    const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
360284778Sdelphij    const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn)
361284778Sdelphij{
362284778Sdelphij	int i;
363284778Sdelphij
364284778Sdelphij	if ((i = cdf_read_user_stream(info, h, sat, ssat, sst,
365284778Sdelphij	    dir, "Catalog", scn)) == -1)
366284778Sdelphij		return i;
367284778Sdelphij#ifdef CDF_DEBUG
368284778Sdelphij	cdf_dump_catalog(&h, &scn);
369284778Sdelphij#endif
370284778Sdelphij	if ((i = cdf_file_catalog(ms, h, scn)) == -1)
371284778Sdelphij		return -1;
372284778Sdelphij	return i;
373284778Sdelphij}
374284778Sdelphij
375284778Sdelphijprivate struct sinfo {
376284778Sdelphij	const char *name;
377284778Sdelphij	const char *mime;
378284778Sdelphij	const char *sections[5];
379284778Sdelphij	const int  types[5];
380284778Sdelphij} sectioninfo[] = {
381284778Sdelphij	{ "Encrypted", "encrypted",
382284778Sdelphij		{
383284778Sdelphij			"EncryptedPackage", NULL, NULL, NULL, NULL,
384284778Sdelphij		},
385284778Sdelphij		{
386284778Sdelphij			CDF_DIR_TYPE_USER_STREAM, 0, 0, 0, 0,
387284778Sdelphij
388284778Sdelphij		},
389284778Sdelphij	},
390284778Sdelphij	{ "QuickBooks", "quickbooks",
391284778Sdelphij		{
392284778Sdelphij#if 0
393284778Sdelphij			"TaxForms", "PDFTaxForms", "modulesInBackup",
394284778Sdelphij#endif
395284778Sdelphij			"mfbu_header", NULL, NULL, NULL, NULL,
396284778Sdelphij		},
397284778Sdelphij		{
398284778Sdelphij#if 0
399284778Sdelphij			CDF_DIR_TYPE_USER_STORAGE,
400284778Sdelphij			CDF_DIR_TYPE_USER_STORAGE,
401284778Sdelphij			CDF_DIR_TYPE_USER_STREAM,
402284778Sdelphij#endif
403284778Sdelphij			CDF_DIR_TYPE_USER_STREAM,
404284778Sdelphij			0, 0, 0, 0
405284778Sdelphij		},
406284778Sdelphij	},
407284778Sdelphij};
408284778Sdelphij
409284778Sdelphijprivate int
410284778Sdelphijcdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir)
411284778Sdelphij{
412284778Sdelphij	size_t sd, j;
413284778Sdelphij
414284778Sdelphij	for (sd = 0; sd < __arraycount(sectioninfo); sd++) {
415284778Sdelphij		const struct sinfo *si = &sectioninfo[sd];
416284778Sdelphij		for (j = 0; si->sections[j]; j++) {
417284778Sdelphij			if (cdf_find_stream(dir, si->sections[j], si->types[j])
418284778Sdelphij			    <= 0) {
419284778Sdelphij#ifdef CDF_DEBUG
420284778Sdelphij				fprintf(stderr, "Can't read %s\n",
421284778Sdelphij				    si->sections[j]);
422284778Sdelphij#endif
423284778Sdelphij				break;
424284778Sdelphij			}
425284778Sdelphij		}
426284778Sdelphij		if (si->sections[j] != NULL)
427284778Sdelphij			continue;
428284778Sdelphij		if (NOTMIME(ms)) {
429284778Sdelphij			if (file_printf(ms, "CDFV2 %s", si->name) == -1)
430284778Sdelphij				return -1;
431284778Sdelphij		} else {
432284778Sdelphij			if (file_printf(ms, "application/CDFV2-%s",
433284778Sdelphij			    si->mime) == -1)
434284778Sdelphij				return -1;
435284778Sdelphij		}
436284778Sdelphij		return 1;
437284778Sdelphij	}
438284778Sdelphij	return -1;
439284778Sdelphij}
440284778Sdelphij
441191739Sobrienprotected int
442191739Sobrienfile_trycdf(struct magic_set *ms, int fd, const unsigned char *buf,
443191739Sobrien    size_t nbytes)
444191739Sobrien{
445226048Sobrien        cdf_info_t info;
446226048Sobrien        cdf_header_t h;
447226048Sobrien        cdf_sat_t sat, ssat;
448226048Sobrien        cdf_stream_t sst, scn;
449226048Sobrien        cdf_dir_t dir;
450226048Sobrien        int i;
451226048Sobrien        const char *expn = "";
452276415Sdelphij        const cdf_directory_t *root_storage;
453191739Sobrien
454226048Sobrien        info.i_fd = fd;
455226048Sobrien        info.i_buf = buf;
456226048Sobrien        info.i_len = nbytes;
457284778Sdelphij        if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))
458226048Sobrien                return 0;
459226048Sobrien        if (cdf_read_header(&info, &h) == -1)
460226048Sobrien                return 0;
461191739Sobrien#ifdef CDF_DEBUG
462226048Sobrien        cdf_dump_header(&h);
463191739Sobrien#endif
464191739Sobrien
465226048Sobrien        if ((i = cdf_read_sat(&info, &h, &sat)) == -1) {
466226048Sobrien                expn = "Can't read SAT";
467226048Sobrien                goto out0;
468226048Sobrien        }
469191739Sobrien#ifdef CDF_DEBUG
470226048Sobrien        cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
471191739Sobrien#endif
472191739Sobrien
473226048Sobrien        if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) {
474226048Sobrien                expn = "Can't read SSAT";
475226048Sobrien                goto out1;
476226048Sobrien        }
477191739Sobrien#ifdef CDF_DEBUG
478226048Sobrien        cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
479191739Sobrien#endif
480191739Sobrien
481226048Sobrien        if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) {
482226048Sobrien                expn = "Can't read directory";
483226048Sobrien                goto out2;
484226048Sobrien        }
485191739Sobrien
486267843Sdelphij        if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst,
487267843Sdelphij	    &root_storage)) == -1) {
488226048Sobrien                expn = "Cannot read short stream";
489226048Sobrien                goto out3;
490226048Sobrien        }
491191739Sobrien#ifdef CDF_DEBUG
492226048Sobrien        cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
493191739Sobrien#endif
494267843Sdelphij#ifdef notdef
495267843Sdelphij	if (root_storage) {
496267843Sdelphij		if (NOTMIME(ms)) {
497267843Sdelphij			char clsbuf[128];
498267843Sdelphij			if (file_printf(ms, "CLSID %s, ",
499267843Sdelphij			    format_clsid(clsbuf, sizeof(clsbuf),
500267843Sdelphij			    root_storage->d_storage_uuid)) == -1)
501267843Sdelphij				return -1;
502267843Sdelphij		}
503267843Sdelphij	}
504267843Sdelphij#endif
505192348Sdelphij
506267843Sdelphij	if ((i = cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir,
507267843Sdelphij	    "FileHeader", &scn)) != -1) {
508267843Sdelphij#define HWP5_SIGNATURE "HWP Document File"
509267843Sdelphij		if (scn.sst_dirlen >= sizeof(HWP5_SIGNATURE) - 1
510267843Sdelphij		    && memcmp(scn.sst_tab, HWP5_SIGNATURE,
511267843Sdelphij		    sizeof(HWP5_SIGNATURE) - 1) == 0) {
512267843Sdelphij		    if (NOTMIME(ms)) {
513267843Sdelphij			if (file_printf(ms,
514267843Sdelphij			    "Hangul (Korean) Word Processor File 5.x") == -1)
515267843Sdelphij			    return -1;
516267843Sdelphij		    } else {
517267843Sdelphij			if (file_printf(ms, "application/x-hwp") == -1)
518267843Sdelphij			    return -1;
519267843Sdelphij		    }
520267843Sdelphij		    i = 1;
521267843Sdelphij		    goto out5;
522267843Sdelphij		} else {
523267843Sdelphij		    free(scn.sst_tab);
524267843Sdelphij		    scn.sst_tab = NULL;
525267843Sdelphij		    scn.sst_len = 0;
526267843Sdelphij		    scn.sst_dirlen = 0;
527267843Sdelphij		}
528267843Sdelphij	}
529267843Sdelphij
530226048Sobrien        if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
531226048Sobrien            &scn)) == -1) {
532284778Sdelphij                if (errno != ESRCH) {
533226048Sobrien                        expn = "Cannot read summary info";
534284778Sdelphij			goto out4;
535284778Sdelphij		}
536284778Sdelphij		i = cdf_file_catalog_info(ms, &info, &h, &sat, &ssat, &sst,
537284778Sdelphij		    &dir, &scn);
538284778Sdelphij		if (i > 0)
539284778Sdelphij			goto out4;
540284778Sdelphij		i = cdf_file_dir_info(ms, &dir);
541284778Sdelphij		if (i < 0)
542284778Sdelphij                        expn = "Cannot read section info";
543284778Sdelphij		goto out4;
544284778Sdelphij	}
545284778Sdelphij
546284778Sdelphij
547191739Sobrien#ifdef CDF_DEBUG
548226048Sobrien        cdf_dump_summary_info(&h, &scn);
549191739Sobrien#endif
550267843Sdelphij        if ((i = cdf_file_summary_info(ms, &h, &scn, root_storage)) < 0)
551267843Sdelphij            expn = "Can't expand summary_info";
552267843Sdelphij
553226048Sobrien	if (i == 0) {
554267843Sdelphij		const char *str = NULL;
555226048Sobrien		cdf_directory_t *d;
556226048Sobrien		char name[__arraycount(d->d_name)];
557226048Sobrien		size_t j, k;
558267843Sdelphij
559267843Sdelphij		for (j = 0; str == NULL && j < dir.dir_len; j++) {
560267843Sdelphij			d = &dir.dir_tab[j];
561267843Sdelphij			for (k = 0; k < sizeof(name); k++)
562267843Sdelphij				name[k] = (char)cdf_tole2(d->d_name[k]);
563267843Sdelphij			str = cdf_app_to_mime(name,
564267843Sdelphij			    NOTMIME(ms) ? name2desc : name2mime);
565226048Sobrien		}
566267843Sdelphij		if (NOTMIME(ms)) {
567267843Sdelphij			if (str != NULL) {
568267843Sdelphij				if (file_printf(ms, "%s", str) == -1)
569267843Sdelphij					return -1;
570267843Sdelphij				i = 1;
571267843Sdelphij			}
572267843Sdelphij		} else {
573267843Sdelphij			if (str == NULL)
574267843Sdelphij				str = "vnd.ms-office";
575267843Sdelphij			if (file_printf(ms, "application/%s", str) == -1)
576267843Sdelphij				return -1;
577267843Sdelphij			i = 1;
578267843Sdelphij		}
579226048Sobrien	}
580267843Sdelphijout5:
581226048Sobrien        free(scn.sst_tab);
582191739Sobrienout4:
583226048Sobrien        free(sst.sst_tab);
584191739Sobrienout3:
585226048Sobrien        free(dir.dir_tab);
586191739Sobrienout2:
587226048Sobrien        free(ssat.sat_tab);
588191739Sobrienout1:
589226048Sobrien        free(sat.sat_tab);
590192348Sdelphijout0:
591267843Sdelphij	if (i == -1) {
592267843Sdelphij	    if (NOTMIME(ms)) {
593267843Sdelphij		if (file_printf(ms,
594267843Sdelphij		    "Composite Document File V2 Document") == -1)
595267843Sdelphij		    return -1;
596267843Sdelphij		if (*expn)
597284778Sdelphij		    if (file_printf(ms, ", %s", expn) == -1)
598267843Sdelphij			return -1;
599267843Sdelphij	    } else {
600284778Sdelphij		if (file_printf(ms, "application/CDFV2-unknown") == -1)
601267843Sdelphij		    return -1;
602267843Sdelphij	    }
603267843Sdelphij	    i = 1;
604267843Sdelphij	}
605226048Sobrien        return i;
606191739Sobrien}
607