readcdf.c revision 191739
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
29191739SobrienFILE_RCSID("@(#)$File: readcdf.c,v 1.11 2009/02/03 20:27:51 christos Exp $")
30191739Sobrien#endif
31191739Sobrien
32191739Sobrien#include <stdlib.h>
33191739Sobrien#include <unistd.h>
34191739Sobrien#include <string.h>
35191739Sobrien#include <time.h>
36191739Sobrien#include <ctype.h>
37191739Sobrien
38191739Sobrien#include "cdf.h"
39191739Sobrien#include "magic.h"
40191739Sobrien
41191739Sobrien#define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
42191739Sobrien
43191739Sobrienprivate int
44191739Sobriencdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
45191739Sobrien    size_t count)
46191739Sobrien{
47191739Sobrien	size_t i;
48191739Sobrien	cdf_timestamp_t tp;
49191739Sobrien	struct timespec ts;
50191739Sobrien	char buf[64];
51191739Sobrien	const char *str = "vnd.ms-office";
52191739Sobrien	const char *s;
53191739Sobrien	int len;
54191739Sobrien
55191739Sobrien	for (i = 0; i < count; i++) {
56191739Sobrien		cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
57191739Sobrien		switch (info[i].pi_type) {
58191739Sobrien		case CDF_SIGNED16:
59191739Sobrien			if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
60191739Sobrien			    info[i].pi_s16) == -1)
61191739Sobrien				return -1;
62191739Sobrien			break;
63191739Sobrien		case CDF_SIGNED32:
64191739Sobrien			if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
65191739Sobrien			    info[i].pi_s32) == -1)
66191739Sobrien				return -1;
67191739Sobrien			break;
68191739Sobrien		case CDF_UNSIGNED32:
69191739Sobrien			if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
70191739Sobrien			    info[i].pi_u32) == -1)
71191739Sobrien				return -1;
72191739Sobrien			break;
73191739Sobrien		case CDF_LENGTH32_STRING:
74191739Sobrien			len = info[i].pi_str.s_len;
75191739Sobrien			if (len > 1) {
76191739Sobrien				s = info[i].pi_str.s_buf;
77191739Sobrien				if (NOTMIME(ms)) {
78191739Sobrien					if (file_printf(ms, ", %s: %.*s", buf,
79191739Sobrien					    len, s) == -1)
80191739Sobrien						return -1;
81191739Sobrien				} else if (info[i].pi_id ==
82191739Sobrien					CDF_PROPERTY_NAME_OF_APPLICATION) {
83191739Sobrien					if (strstr(s, "Word"))
84191739Sobrien						str = "msword";
85191739Sobrien					else if (strstr(s, "Excel"))
86191739Sobrien						str = "vnd.ms-excel";
87191739Sobrien					else if (strstr(s, "Powerpoint"))
88191739Sobrien						str = "vnd.ms-powerpoint";
89191739Sobrien				}
90191739Sobrien			}
91191739Sobrien			break;
92191739Sobrien		case CDF_FILETIME:
93191739Sobrien			tp = info[i].pi_tp;
94191739Sobrien			if (tp != 0) {
95191739Sobrien				if (tp < 1000000000000000LL) {
96191739Sobrien					char tbuf[64];
97191739Sobrien					cdf_print_elapsed_time(tbuf,
98191739Sobrien					    sizeof(tbuf), tp);
99191739Sobrien					if (NOTMIME(ms) && file_printf(ms,
100191739Sobrien					    ", %s: %s", buf, tbuf) == -1)
101191739Sobrien						return -1;
102191739Sobrien				} else {
103191739Sobrien					char *c, *ec;
104191739Sobrien					cdf_timestamp_to_timespec(&ts, tp);
105191739Sobrien					c = ctime(&ts.tv_sec);
106191739Sobrien					if ((ec = strchr(c, '\n')) != NULL)
107191739Sobrien						*ec = '\0';
108191739Sobrien
109191739Sobrien					if (NOTMIME(ms) && file_printf(ms,
110191739Sobrien					    ", %s: %s", buf, c) == -1)
111191739Sobrien						return -1;
112191739Sobrien				}
113191739Sobrien			}
114191739Sobrien			break;
115191739Sobrien		case CDF_CLIPBOARD:
116191739Sobrien			break;
117191739Sobrien		default:
118191739Sobrien			file_error(ms, 0, "Internal parsing error");
119191739Sobrien			return -1;
120191739Sobrien		}
121191739Sobrien	}
122191739Sobrien	if (!NOTMIME(ms)) {
123191739Sobrien		if (file_printf(ms, "application/%s", str) == -1)
124191739Sobrien			return -1;
125191739Sobrien	}
126191739Sobrien	return 1;
127191739Sobrien}
128191739Sobrien
129191739Sobrienprivate int
130191739Sobriencdf_file_summary_info(struct magic_set *ms, const cdf_stream_t *sst)
131191739Sobrien{
132191739Sobrien	cdf_summary_info_header_t si;
133191739Sobrien	cdf_property_info_t *info;
134191739Sobrien	size_t count;
135191739Sobrien	int m;
136191739Sobrien
137191739Sobrien	if (cdf_unpack_summary_info(sst, &si, &info, &count) == -1) {
138191739Sobrien		if (si.si_byte_order != 0xfffe)
139191739Sobrien			return 0;
140191739Sobrien		else
141191739Sobrien			return -1;
142191739Sobrien	}
143191739Sobrien
144191739Sobrien	if (si.si_byte_order != 0xfffe)
145191739Sobrien		return 0;
146191739Sobrien
147191739Sobrien	if (NOTMIME(ms)) {
148191739Sobrien		if (file_printf(ms, "CDF V2 Document") == -1)
149191739Sobrien			return -1;
150191739Sobrien
151191739Sobrien		if (file_printf(ms, ", %s Endian",
152191739Sobrien		    si.si_byte_order == 0xfffe ?  "Little" : "Big") == -1)
153191739Sobrien			return -1;
154191739Sobrien		switch (si.si_os) {
155191739Sobrien		case 2:
156191739Sobrien			if (file_printf(ms, ", Os: Windows, Version %d.%d",
157191739Sobrien			    si.si_os_version & 0xff, si.si_os_version >> 8)
158191739Sobrien			    == -1)
159191739Sobrien				return -1;
160191739Sobrien			break;
161191739Sobrien		case 1:
162191739Sobrien			if (file_printf(ms, ", Os: MacOS, Version %d.%d",
163191739Sobrien			    si.si_os_version >> 8, si.si_os_version & 0xff)
164191739Sobrien			    == -1)
165191739Sobrien				return -1;
166191739Sobrien			break;
167191739Sobrien		default:
168191739Sobrien			if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
169191739Sobrien			    si.si_os_version & 0xff, si.si_os_version >> 8)
170191739Sobrien			    == -1)
171191739Sobrien				return -1;
172191739Sobrien			break;
173191739Sobrien		}
174191739Sobrien	}
175191739Sobrien
176191739Sobrien	m = cdf_file_property_info(ms, info, count);
177191739Sobrien	free(info);
178191739Sobrien
179191739Sobrien	return m;
180191739Sobrien}
181191739Sobrien
182191739Sobrienprotected int
183191739Sobrienfile_trycdf(struct magic_set *ms, int fd, const unsigned char *buf,
184191739Sobrien    size_t nbytes)
185191739Sobrien{
186191739Sobrien	cdf_header_t h;
187191739Sobrien	cdf_sat_t sat, ssat;
188191739Sobrien	cdf_stream_t sst, scn;
189191739Sobrien	cdf_dir_t dir;
190191739Sobrien	int i;
191191739Sobrien	(void)&nbytes;
192191739Sobrien	(void)&buf;
193191739Sobrien
194191739Sobrien	if (ms->flags & MAGIC_APPLE)
195191739Sobrien		return 0;
196191739Sobrien	if (cdf_read_header(fd, &h) == -1)
197191739Sobrien		return 0;
198191739Sobrien#ifdef CDF_DEBUG
199191739Sobrien	cdf_dump_header(&h);
200191739Sobrien#endif
201191739Sobrien
202191739Sobrien	if (cdf_read_sat(fd, &h, &sat) == -1) {
203191739Sobrien		file_error(ms, errno, "Can't read SAT");
204191739Sobrien		return -1;
205191739Sobrien	}
206191739Sobrien#ifdef CDF_DEBUG
207191739Sobrien	cdf_dump_sat("SAT", &h, &sat);
208191739Sobrien#endif
209191739Sobrien
210191739Sobrien	if ((i = cdf_read_ssat(fd, &h, &sat, &ssat)) == -1) {
211191739Sobrien		file_error(ms, errno, "Can't read SAT");
212191739Sobrien		goto out1;
213191739Sobrien	}
214191739Sobrien#ifdef CDF_DEBUG
215191739Sobrien	cdf_dump_sat("SSAT", &h, &ssat);
216191739Sobrien#endif
217191739Sobrien
218191739Sobrien	if ((i = cdf_read_dir(fd, &h, &sat, &dir)) == -1) {
219191739Sobrien		file_error(ms, errno, "Can't read directory");
220191739Sobrien		goto out2;
221191739Sobrien	}
222191739Sobrien
223191739Sobrien	if ((i = cdf_read_short_stream(fd, &h, &sat, &dir, &sst)) == -1) {
224191739Sobrien		file_error(ms, errno, "Cannot read short stream");
225191739Sobrien		goto out3;
226191739Sobrien	}
227191739Sobrien
228191739Sobrien#ifdef CDF_DEBUG
229191739Sobrien	cdf_dump_dir(fd, &h, &sat, &ssat, &sst, &dir);
230191739Sobrien#endif
231191739Sobrien	if ((i = cdf_read_summary_info(fd, &h, &sat, &ssat, &sst, &dir, &scn))
232191739Sobrien	    == -1) {
233191739Sobrien		/* Some files don't have summary info! */
234191739Sobrien#ifdef notyet
235191739Sobrien		file_error(ms, errno, "Can't read summary_info");
236191739Sobrien#else
237191739Sobrien		i = 0;
238191739Sobrien#endif
239191739Sobrien		goto out4;
240191739Sobrien	}
241191739Sobrien#ifdef CDF_DEBUG
242191739Sobrien	cdf_dump_summary_info(&h, &scn);
243191739Sobrien#endif
244191739Sobrien	if ((i = cdf_file_summary_info(ms, &scn)) == -1)
245191739Sobrien		file_error(ms, errno, "Can't expand summary_info");
246191739Sobrien	free(scn.sst_tab);
247191739Sobrienout4:
248191739Sobrien	free(sst.sst_tab);
249191739Sobrienout3:
250191739Sobrien	free(dir.dir_tab);
251191739Sobrienout2:
252191739Sobrien	free(ssat.sat_tab);
253191739Sobrienout1:
254191739Sobrien	free(sat.sat_tab);
255191739Sobrien	return i;
256191739Sobrien}
257