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
29284193SdelphijFILE_RCSID("@(#)$File: readcdf.c,v 1.49 2014/12/04 15:56:46 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
42191739Sobrien#define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
43191739Sobrien
44267843Sdelphijstatic const struct nv {
45267843Sdelphij	const char *pattern;
46267843Sdelphij	const char *mime;
47267843Sdelphij} app2mime[] =  {
48267843Sdelphij	{ "Word",			"msword",		},
49267843Sdelphij	{ "Excel",			"vnd.ms-excel",		},
50267843Sdelphij	{ "Powerpoint",			"vnd.ms-powerpoint",	},
51267843Sdelphij	{ "Crystal Reports",		"x-rpt",		},
52267843Sdelphij	{ "Advanced Installer",		"vnd.ms-msi",		},
53267843Sdelphij	{ "InstallShield",		"vnd.ms-msi",		},
54267843Sdelphij	{ "Microsoft Patch Compiler",	"vnd.ms-msi",		},
55267843Sdelphij	{ "NAnt",			"vnd.ms-msi",		},
56267843Sdelphij	{ "Windows Installer",		"vnd.ms-msi",		},
57267843Sdelphij	{ NULL,				NULL,			},
58267843Sdelphij}, name2mime[] = {
59267843Sdelphij	{ "WordDocument",		"msword",		},
60267843Sdelphij	{ "PowerPoint",			"vnd.ms-powerpoint",	},
61267843Sdelphij	{ "DigitalSignature",		"vnd.ms-msi",		},
62267843Sdelphij	{ NULL,				NULL,			},
63267843Sdelphij}, name2desc[] = {
64267843Sdelphij	{ "WordDocument",		"Microsoft Office Word",},
65267843Sdelphij	{ "PowerPoint",			"Microsoft PowerPoint",	},
66267843Sdelphij	{ "DigitalSignature",		"Microsoft Installer",	},
67267843Sdelphij	{ NULL,				NULL,			},
68267843Sdelphij};
69267843Sdelphij
70267843Sdelphijstatic const struct cv {
71267843Sdelphij	uint64_t clsid[2];
72267843Sdelphij	const char *mime;
73267843Sdelphij} clsid2mime[] = {
74267843Sdelphij	{
75284193Sdelphij		{ 0x00000000000c1084ULL, 0x46000000000000c0ULL  },
76267843Sdelphij		"x-msi",
77267843Sdelphij	},
78267843Sdelphij	{	{ 0,			 0			},
79267843Sdelphij		NULL,
80267843Sdelphij	},
81267843Sdelphij}, clsid2desc[] = {
82267843Sdelphij	{
83284193Sdelphij		{ 0x00000000000c1084ULL, 0x46000000000000c0ULL  },
84267843Sdelphij		"MSI Installer",
85267843Sdelphij	},
86267843Sdelphij	{	{ 0,			 0			},
87267843Sdelphij		NULL,
88267843Sdelphij	},
89267843Sdelphij};
90267843Sdelphij
91267843Sdelphijprivate const char *
92267843Sdelphijcdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv)
93267843Sdelphij{
94267843Sdelphij	size_t i;
95267843Sdelphij	for (i = 0; cv[i].mime != NULL; i++) {
96267843Sdelphij		if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1])
97267843Sdelphij			return cv[i].mime;
98267843Sdelphij	}
99267843Sdelphij	return NULL;
100267843Sdelphij}
101267843Sdelphij
102267843Sdelphijprivate const char *
103267843Sdelphijcdf_app_to_mime(const char *vbuf, const struct nv *nv)
104267843Sdelphij{
105267843Sdelphij	size_t i;
106267843Sdelphij	const char *rv = NULL;
107284193Sdelphij#ifdef USE_C_LOCALE
108284193Sdelphij	locale_t old_lc_ctype, c_lc_ctype;
109267843Sdelphij
110284193Sdelphij	c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
111284193Sdelphij	assert(c_lc_ctype != NULL);
112284193Sdelphij	old_lc_ctype = uselocale(c_lc_ctype);
113267843Sdelphij	assert(old_lc_ctype != NULL);
114284193Sdelphij#endif
115267843Sdelphij	for (i = 0; nv[i].pattern != NULL; i++)
116267843Sdelphij		if (strcasestr(vbuf, nv[i].pattern) != NULL) {
117267843Sdelphij			rv = nv[i].mime;
118267843Sdelphij			break;
119267843Sdelphij		}
120284193Sdelphij#ifdef USE_C_LOCALE
121284193Sdelphij	(void)uselocale(old_lc_ctype);
122284193Sdelphij	freelocale(c_lc_ctype);
123284193Sdelphij#endif
124267843Sdelphij	return rv;
125267843Sdelphij}
126267843Sdelphij
127191739Sobrienprivate int
128191739Sobriencdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
129267843Sdelphij    size_t count, const cdf_directory_t *root_storage)
130191739Sobrien{
131226048Sobrien        size_t i;
132226048Sobrien        cdf_timestamp_t tp;
133226048Sobrien        struct timespec ts;
134226048Sobrien        char buf[64];
135226048Sobrien        const char *str = NULL;
136226048Sobrien        const char *s;
137226048Sobrien        int len;
138191739Sobrien
139267843Sdelphij        if (!NOTMIME(ms) && root_storage)
140267843Sdelphij		str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
141267843Sdelphij		    clsid2mime);
142267843Sdelphij
143226048Sobrien        for (i = 0; i < count; i++) {
144226048Sobrien                cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
145226048Sobrien                switch (info[i].pi_type) {
146226048Sobrien                case CDF_NULL:
147226048Sobrien                        break;
148226048Sobrien                case CDF_SIGNED16:
149226048Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
150226048Sobrien                            info[i].pi_s16) == -1)
151226048Sobrien                                return -1;
152226048Sobrien                        break;
153226048Sobrien                case CDF_SIGNED32:
154226048Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
155226048Sobrien                            info[i].pi_s32) == -1)
156226048Sobrien                                return -1;
157226048Sobrien                        break;
158226048Sobrien                case CDF_UNSIGNED32:
159226048Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
160226048Sobrien                            info[i].pi_u32) == -1)
161226048Sobrien                                return -1;
162226048Sobrien                        break;
163234250Sobrien                case CDF_FLOAT:
164234250Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
165234250Sobrien                            info[i].pi_f) == -1)
166234250Sobrien                                return -1;
167234250Sobrien                        break;
168234250Sobrien                case CDF_DOUBLE:
169234250Sobrien                        if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
170234250Sobrien                            info[i].pi_d) == -1)
171234250Sobrien                                return -1;
172234250Sobrien                        break;
173226048Sobrien                case CDF_LENGTH32_STRING:
174226048Sobrien                case CDF_LENGTH32_WSTRING:
175226048Sobrien                        len = info[i].pi_str.s_len;
176226048Sobrien                        if (len > 1) {
177226048Sobrien                                char vbuf[1024];
178226048Sobrien                                size_t j, k = 1;
179191739Sobrien
180226048Sobrien                                if (info[i].pi_type == CDF_LENGTH32_WSTRING)
181226048Sobrien                                    k++;
182226048Sobrien                                s = info[i].pi_str.s_buf;
183267843Sdelphij                                for (j = 0; j < sizeof(vbuf) && len--; s += k) {
184226048Sobrien                                        if (*s == '\0')
185226048Sobrien                                                break;
186226048Sobrien                                        if (isprint((unsigned char)*s))
187267843Sdelphij                                                vbuf[j++] = *s;
188226048Sobrien                                }
189226048Sobrien                                if (j == sizeof(vbuf))
190226048Sobrien                                        --j;
191226048Sobrien                                vbuf[j] = '\0';
192226048Sobrien                                if (NOTMIME(ms)) {
193226048Sobrien                                        if (vbuf[0]) {
194226048Sobrien                                                if (file_printf(ms, ", %s: %s",
195226048Sobrien                                                    buf, vbuf) == -1)
196226048Sobrien                                                        return -1;
197226048Sobrien                                        }
198267843Sdelphij                                } else if (str == NULL && info[i].pi_id ==
199267843Sdelphij				    CDF_PROPERTY_NAME_OF_APPLICATION) {
200267843Sdelphij					str = cdf_app_to_mime(vbuf, app2mime);
201267843Sdelphij				}
202267843Sdelphij			}
203226048Sobrien                        break;
204226048Sobrien                case CDF_FILETIME:
205226048Sobrien                        tp = info[i].pi_tp;
206226048Sobrien                        if (tp != 0) {
207267843Sdelphij				char tbuf[64];
208226048Sobrien                                if (tp < 1000000000000000LL) {
209226048Sobrien                                        cdf_print_elapsed_time(tbuf,
210226048Sobrien                                            sizeof(tbuf), tp);
211226048Sobrien                                        if (NOTMIME(ms) && file_printf(ms,
212226048Sobrien                                            ", %s: %s", buf, tbuf) == -1)
213226048Sobrien                                                return -1;
214226048Sobrien                                } else {
215226048Sobrien                                        char *c, *ec;
216226048Sobrien                                        cdf_timestamp_to_timespec(&ts, tp);
217267843Sdelphij                                        c = cdf_ctime(&ts.tv_sec, tbuf);
218267843Sdelphij                                        if (c != NULL &&
219267843Sdelphij					    (ec = strchr(c, '\n')) != NULL)
220267843Sdelphij						*ec = '\0';
221226048Sobrien
222226048Sobrien                                        if (NOTMIME(ms) && file_printf(ms,
223226048Sobrien                                            ", %s: %s", buf, c) == -1)
224226048Sobrien                                                return -1;
225226048Sobrien                                }
226226048Sobrien                        }
227226048Sobrien                        break;
228226048Sobrien                case CDF_CLIPBOARD:
229226048Sobrien                        break;
230226048Sobrien                default:
231226048Sobrien                        return -1;
232226048Sobrien                }
233226048Sobrien        }
234226048Sobrien        if (!NOTMIME(ms)) {
235226048Sobrien		if (str == NULL)
236226048Sobrien			return 0;
237234250Sobrien                if (file_printf(ms, "application/%s", str) == -1)
238234250Sobrien                        return -1;
239226048Sobrien        }
240226048Sobrien        return 1;
241191739Sobrien}
242191739Sobrien
243191739Sobrienprivate int
244284193Sdelphijcdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
245284193Sdelphij    const cdf_stream_t *sst)
246284193Sdelphij{
247284193Sdelphij	cdf_catalog_t *cat;
248284193Sdelphij	size_t i;
249284193Sdelphij	char buf[256];
250284193Sdelphij	cdf_catalog_entry_t *ce;
251284193Sdelphij
252284193Sdelphij        if (NOTMIME(ms)) {
253284193Sdelphij		if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
254284193Sdelphij			return -1;
255284193Sdelphij		if (cdf_unpack_catalog(h, sst, &cat) == -1)
256284193Sdelphij			return -1;
257284193Sdelphij		ce = cat->cat_e;
258284193Sdelphij		/* skip first entry since it has a , or paren */
259284193Sdelphij		for (i = 1; i < cat->cat_num; i++)
260284193Sdelphij			if (file_printf(ms, "%s%s",
261284193Sdelphij			    cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
262284193Sdelphij			    i == cat->cat_num - 1 ? "]" : ", ") == -1) {
263284193Sdelphij				free(cat);
264284193Sdelphij				return -1;
265284193Sdelphij			}
266284193Sdelphij		free(cat);
267284193Sdelphij	} else {
268284193Sdelphij		if (file_printf(ms, "application/CDFV2") == -1)
269284193Sdelphij			return -1;
270284193Sdelphij	}
271284193Sdelphij	return 1;
272284193Sdelphij}
273284193Sdelphij
274284193Sdelphijprivate int
275226048Sobriencdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
276267843Sdelphij    const cdf_stream_t *sst, const cdf_directory_t *root_storage)
277191739Sobrien{
278226048Sobrien        cdf_summary_info_header_t si;
279226048Sobrien        cdf_property_info_t *info;
280226048Sobrien        size_t count;
281226048Sobrien        int m;
282191739Sobrien
283226048Sobrien        if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1)
284226048Sobrien                return -1;
285191739Sobrien
286226048Sobrien        if (NOTMIME(ms)) {
287267843Sdelphij		const char *str;
288267843Sdelphij
289234250Sobrien                if (file_printf(ms, "Composite Document File V2 Document")
290234250Sobrien		    == -1)
291226048Sobrien                        return -1;
292191739Sobrien
293226048Sobrien                if (file_printf(ms, ", %s Endian",
294226048Sobrien                    si.si_byte_order == 0xfffe ?  "Little" : "Big") == -1)
295234250Sobrien                        return -2;
296226048Sobrien                switch (si.si_os) {
297226048Sobrien                case 2:
298226048Sobrien                        if (file_printf(ms, ", Os: Windows, Version %d.%d",
299226048Sobrien                            si.si_os_version & 0xff,
300226048Sobrien                            (uint32_t)si.si_os_version >> 8) == -1)
301234250Sobrien                                return -2;
302226048Sobrien                        break;
303226048Sobrien                case 1:
304226048Sobrien                        if (file_printf(ms, ", Os: MacOS, Version %d.%d",
305226048Sobrien                            (uint32_t)si.si_os_version >> 8,
306226048Sobrien                            si.si_os_version & 0xff) == -1)
307234250Sobrien                                return -2;
308226048Sobrien                        break;
309226048Sobrien                default:
310226048Sobrien                        if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
311226048Sobrien                            si.si_os_version & 0xff,
312226048Sobrien                            (uint32_t)si.si_os_version >> 8) == -1)
313234250Sobrien                                return -2;
314226048Sobrien                        break;
315226048Sobrien                }
316267843Sdelphij		if (root_storage) {
317267843Sdelphij			str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
318267843Sdelphij			    clsid2desc);
319284193Sdelphij			if (str) {
320267843Sdelphij				if (file_printf(ms, ", %s", str) == -1)
321267843Sdelphij					return -2;
322267843Sdelphij			}
323267843Sdelphij		}
324284193Sdelphij	}
325191739Sobrien
326267843Sdelphij        m = cdf_file_property_info(ms, info, count, root_storage);
327226048Sobrien        free(info);
328191739Sobrien
329234250Sobrien        return m == -1 ? -2 : m;
330191739Sobrien}
331191739Sobrien
332267843Sdelphij#ifdef notdef
333267843Sdelphijprivate char *
334267843Sdelphijformat_clsid(char *buf, size_t len, const uint64_t uuid[2]) {
335267843Sdelphij	snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4"
336267843Sdelphij	    PRIx64 "-%.12" PRIx64,
337284193Sdelphij	    (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL,
338284193Sdelphij	    (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL,
339284193Sdelphij	    (uuid[0] >>  0) & (uint64_t)0x0000000000000ffffULL,
340284193Sdelphij	    (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL,
341284193Sdelphij	    (uuid[1] >>  0) & (uint64_t)0x0000fffffffffffffULL);
342267843Sdelphij	return buf;
343267843Sdelphij}
344267843Sdelphij#endif
345267843Sdelphij
346191739Sobrienprotected int
347191739Sobrienfile_trycdf(struct magic_set *ms, int fd, const unsigned char *buf,
348191739Sobrien    size_t nbytes)
349191739Sobrien{
350226048Sobrien        cdf_info_t info;
351226048Sobrien        cdf_header_t h;
352226048Sobrien        cdf_sat_t sat, ssat;
353226048Sobrien        cdf_stream_t sst, scn;
354226048Sobrien        cdf_dir_t dir;
355226048Sobrien        int i;
356226048Sobrien        const char *expn = "";
357226048Sobrien        const char *corrupt = "corrupt: ";
358284193Sdelphij        const cdf_directory_t *root_storage;
359191739Sobrien
360226048Sobrien        info.i_fd = fd;
361226048Sobrien        info.i_buf = buf;
362226048Sobrien        info.i_len = nbytes;
363226048Sobrien        if (ms->flags & MAGIC_APPLE)
364226048Sobrien                return 0;
365226048Sobrien        if (cdf_read_header(&info, &h) == -1)
366226048Sobrien                return 0;
367191739Sobrien#ifdef CDF_DEBUG
368226048Sobrien        cdf_dump_header(&h);
369191739Sobrien#endif
370191739Sobrien
371226048Sobrien        if ((i = cdf_read_sat(&info, &h, &sat)) == -1) {
372226048Sobrien                expn = "Can't read SAT";
373226048Sobrien                goto out0;
374226048Sobrien        }
375191739Sobrien#ifdef CDF_DEBUG
376226048Sobrien        cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
377191739Sobrien#endif
378191739Sobrien
379226048Sobrien        if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) {
380226048Sobrien                expn = "Can't read SSAT";
381226048Sobrien                goto out1;
382226048Sobrien        }
383191739Sobrien#ifdef CDF_DEBUG
384226048Sobrien        cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
385191739Sobrien#endif
386191739Sobrien
387226048Sobrien        if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) {
388226048Sobrien                expn = "Can't read directory";
389226048Sobrien                goto out2;
390226048Sobrien        }
391191739Sobrien
392267843Sdelphij        if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst,
393267843Sdelphij	    &root_storage)) == -1) {
394226048Sobrien                expn = "Cannot read short stream";
395226048Sobrien                goto out3;
396226048Sobrien        }
397191739Sobrien#ifdef CDF_DEBUG
398226048Sobrien        cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
399191739Sobrien#endif
400267843Sdelphij#ifdef notdef
401267843Sdelphij	if (root_storage) {
402267843Sdelphij		if (NOTMIME(ms)) {
403267843Sdelphij			char clsbuf[128];
404267843Sdelphij			if (file_printf(ms, "CLSID %s, ",
405267843Sdelphij			    format_clsid(clsbuf, sizeof(clsbuf),
406267843Sdelphij			    root_storage->d_storage_uuid)) == -1)
407267843Sdelphij				return -1;
408267843Sdelphij		}
409267843Sdelphij	}
410267843Sdelphij#endif
411192348Sdelphij
412267843Sdelphij	if ((i = cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir,
413267843Sdelphij	    "FileHeader", &scn)) != -1) {
414267843Sdelphij#define HWP5_SIGNATURE "HWP Document File"
415267843Sdelphij		if (scn.sst_dirlen >= sizeof(HWP5_SIGNATURE) - 1
416267843Sdelphij		    && memcmp(scn.sst_tab, HWP5_SIGNATURE,
417267843Sdelphij		    sizeof(HWP5_SIGNATURE) - 1) == 0) {
418267843Sdelphij		    if (NOTMIME(ms)) {
419267843Sdelphij			if (file_printf(ms,
420267843Sdelphij			    "Hangul (Korean) Word Processor File 5.x") == -1)
421267843Sdelphij			    return -1;
422267843Sdelphij		    } else {
423267843Sdelphij			if (file_printf(ms, "application/x-hwp") == -1)
424267843Sdelphij			    return -1;
425267843Sdelphij		    }
426267843Sdelphij		    i = 1;
427267843Sdelphij		    goto out5;
428267843Sdelphij		} else {
429267843Sdelphij		    free(scn.sst_tab);
430267843Sdelphij		    scn.sst_tab = NULL;
431267843Sdelphij		    scn.sst_len = 0;
432267843Sdelphij		    scn.sst_dirlen = 0;
433267843Sdelphij		}
434267843Sdelphij	}
435267843Sdelphij
436226048Sobrien        if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
437226048Sobrien            &scn)) == -1) {
438226048Sobrien                if (errno == ESRCH) {
439284193Sdelphij			if ((i = cdf_read_catalog(&info, &h, &sat, &ssat, &sst,
440284193Sdelphij			    &dir, &scn)) == -1) {
441284193Sdelphij				corrupt = expn;
442284193Sdelphij				if ((i = cdf_read_encrypted_package(&info, &h,
443284193Sdelphij				    &sat, &ssat, &sst, &dir, &scn)) == -1)
444284193Sdelphij					expn = "No summary info";
445284193Sdelphij				else {
446284193Sdelphij					expn = "Encrypted";
447284193Sdelphij					i = -1;
448284193Sdelphij				}
449284193Sdelphij				goto out4;
450284193Sdelphij			}
451284193Sdelphij#ifdef CDF_DEBUG
452284193Sdelphij			cdf_dump_catalog(&h, &scn);
453284193Sdelphij#endif
454284193Sdelphij			if ((i = cdf_file_catalog(ms, &h, &scn))
455284193Sdelphij			    < 0)
456284193Sdelphij				expn = "Can't expand catalog";
457226048Sobrien                } else {
458226048Sobrien                        expn = "Cannot read summary info";
459226048Sobrien                }
460226048Sobrien                goto out4;
461226048Sobrien        }
462191739Sobrien#ifdef CDF_DEBUG
463226048Sobrien        cdf_dump_summary_info(&h, &scn);
464191739Sobrien#endif
465267843Sdelphij        if ((i = cdf_file_summary_info(ms, &h, &scn, root_storage)) < 0)
466267843Sdelphij            expn = "Can't expand summary_info";
467267843Sdelphij
468226048Sobrien	if (i == 0) {
469267843Sdelphij		const char *str = NULL;
470226048Sobrien		cdf_directory_t *d;
471226048Sobrien		char name[__arraycount(d->d_name)];
472226048Sobrien		size_t j, k;
473267843Sdelphij
474267843Sdelphij		for (j = 0; str == NULL && j < dir.dir_len; j++) {
475267843Sdelphij			d = &dir.dir_tab[j];
476267843Sdelphij			for (k = 0; k < sizeof(name); k++)
477267843Sdelphij				name[k] = (char)cdf_tole2(d->d_name[k]);
478267843Sdelphij			str = cdf_app_to_mime(name,
479267843Sdelphij			    NOTMIME(ms) ? name2desc : name2mime);
480226048Sobrien		}
481267843Sdelphij		if (NOTMIME(ms)) {
482267843Sdelphij			if (str != NULL) {
483267843Sdelphij				if (file_printf(ms, "%s", str) == -1)
484267843Sdelphij					return -1;
485267843Sdelphij				i = 1;
486267843Sdelphij			}
487267843Sdelphij		} else {
488267843Sdelphij			if (str == NULL)
489267843Sdelphij				str = "vnd.ms-office";
490267843Sdelphij			if (file_printf(ms, "application/%s", str) == -1)
491267843Sdelphij				return -1;
492267843Sdelphij			i = 1;
493267843Sdelphij		}
494226048Sobrien	}
495267843Sdelphijout5:
496226048Sobrien        free(scn.sst_tab);
497191739Sobrienout4:
498226048Sobrien        free(sst.sst_tab);
499191739Sobrienout3:
500226048Sobrien        free(dir.dir_tab);
501191739Sobrienout2:
502226048Sobrien        free(ssat.sat_tab);
503191739Sobrienout1:
504226048Sobrien        free(sat.sat_tab);
505192348Sdelphijout0:
506267843Sdelphij	if (i == -1) {
507267843Sdelphij	    if (NOTMIME(ms)) {
508267843Sdelphij		if (file_printf(ms,
509267843Sdelphij		    "Composite Document File V2 Document") == -1)
510267843Sdelphij		    return -1;
511267843Sdelphij		if (*expn)
512267843Sdelphij		    if (file_printf(ms, ", %s%s", corrupt, expn) == -1)
513267843Sdelphij			return -1;
514267843Sdelphij	    } else {
515284193Sdelphij		if (file_printf(ms, "application/CDFV2-%s",
516284193Sdelphij		    *corrupt ? "corrupt" : "encrypted") == -1)
517267843Sdelphij		    return -1;
518267843Sdelphij	    }
519267843Sdelphij	    i = 1;
520267843Sdelphij	}
521226048Sobrien        return i;
522191739Sobrien}
523