1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * test-msole1.c: test program to dump biff streams
4  *
5  * Copyright (C) 2002-2006	Jody Goldberg (jody@gnome.org)
6  * Copyright (C) 2002-2003	Michael Meeks (michael.meeks@novell.com)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2.1 of the GNU Lesser General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
20  * USA
21  *
22  * Parts of this code are taken from libole2/test/test-ole.c
23  */
24 
25 #include <gsf/gsf.h>
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <ctype.h>
30 
31 #define BIFF_TYPES_FILE    "biff-types.h"
32 #define DUMP_CONTENT
33 
34 typedef struct {
35 	guint16 opcode;
36 	char *name;
37 } GENERIC_TYPE;
38 
39 #ifdef DUMP_CONTENT
40 static GPtrArray *biff_types   = NULL;
41 static void
read_types(char const * fname,GPtrArray ** types)42 read_types (char const *fname, GPtrArray **types)
43 {
44 	FILE *file = fopen(fname, "r");
45 	unsigned char buffer[1024];
46 	*types = g_ptr_array_new ();
47 	if (!file) {
48 		char *newname = g_strconcat ("../", fname, NULL);
49 		file = fopen (newname, "r");
50 	}
51 	if (!file) {
52 		g_printerr ("Can't find vital file '%s'\n", fname);
53 		return;
54 	}
55 	while (!feof(file)) {
56 		unsigned char *p;
57 		fgets ((char *)buffer, sizeof (buffer)-1, file);
58 		for (p=buffer;*p;p++)
59 			if (*p=='0' && *(p+1)=='x') {
60 				GENERIC_TYPE *bt = g_new (GENERIC_TYPE,1);
61 				unsigned char *name, *pt;
62 				bt->opcode=strtol((char *)p+2,0,16);
63 				pt = buffer;
64 				while (*pt && *pt != '#') pt++;      /* # */
65 				while (*pt && !isspace(*pt))
66 					pt++;  /* define */
67 				while (*pt && isspace((unsigned char)*pt))
68 					pt++;  /* '   ' */
69 				while (*pt && *pt != '_') pt++;     /* BIFF_ */
70 				name = *pt?pt+1:pt;
71 				while (*pt && !isspace((unsigned char)*pt))
72 					pt++;
73 				bt->name = g_strndup ((gchar *)name, (unsigned)(pt - name));
74 				g_ptr_array_add (*types, bt);
75 				break;
76 			}
77 	}
78 	fclose (file);
79 }
80 
81 static char const *
get_biff_opcode_name(unsigned opcode)82 get_biff_opcode_name (unsigned opcode)
83 {
84 	int lp;
85 	if (!biff_types)
86 		read_types (BIFF_TYPES_FILE, &biff_types);
87 	/* Count backwars to give preference to non-filtered record types */
88 	for (lp=biff_types->len; --lp >= 0 ;) {
89 		GENERIC_TYPE *bt = g_ptr_array_index (biff_types, lp);
90 		if (bt->opcode == opcode)
91 			return bt->name;
92 	}
93 	return "Unknown";
94 }
95 
96 static void
dump_biff_stream(GsfInput * stream)97 dump_biff_stream (GsfInput *stream)
98 {
99 	guint8 const *data;
100 	guint16 len, opcode;
101 
102 	while (NULL != (data = gsf_input_read (stream, 4, NULL))) {
103 		gboolean enable_dump = TRUE;
104 
105 		opcode	= GSF_LE_GET_GUINT16 (data);
106 		len	= GSF_LE_GET_GUINT16 (data+2);
107 
108 		if (len > 15000) {
109 			enable_dump = TRUE;
110 			g_warning ("Suspicious import of biff record > 15,000 (0x%x) for opcode 0x%hx",
111 				   len, opcode);
112 		} else if ((opcode & 0xff00) > 0x1000) {
113 			enable_dump = TRUE;
114 			g_warning ("Suspicious import of biff record with opcode 0x%hx",
115 				   opcode);
116 		}
117 
118 		if (enable_dump)
119 			printf ("Opcode 0x%3hx : %15s, length 0x%hx (=%hd)\n",
120 				opcode, get_biff_opcode_name (opcode),
121 				len, len);
122 
123 		if (len > 0) {
124 			data = gsf_input_read (stream, len, NULL);
125 			if (data == NULL)
126 				break;
127 			if (enable_dump)
128 				gsf_mem_dump (data, len);
129 		}
130 	}
131 }
132 #endif /* DUMP_CONTENT */
133 
134 static int
test(unsigned argc,char * argv[])135 test (unsigned argc, char *argv[])
136 {
137 	static char const * const stream_names[] = {
138 		"Workbook",	"WORKBOOK",	"workbook",
139 		"Book",		"BOOK",		"book"
140 	};
141 
142 	GsfInput  *input, *stream, *pcache_dir;
143 	GsfInfile *infile;
144 	GError    *err = NULL;
145 	unsigned i, j;
146 
147 	for (i = 1 ; i < argc ; i++) {
148 		fprintf( stderr, "%s\n",argv[i]);
149 
150 		input = gsf_input_mmap_new (argv[i], NULL);
151 		if (input == NULL)	/* Only report error if stdio fails too */
152 			input = gsf_input_stdio_new (argv[i], &err);
153 		if (input == NULL) {
154 			g_return_val_if_fail (err != NULL, 1);
155 			g_warning ("'%s' error: %s", argv[i], err->message);
156 			g_error_free (err);
157 			err = NULL;
158 			continue;
159 		}
160 
161 		input = gsf_input_uncompress (input);
162 
163 		infile = gsf_infile_msole_new (input, &err);
164 
165 		if (infile == NULL) {
166 			g_return_val_if_fail (err != NULL, 1);
167 
168 			g_warning ("'%s' Not an OLE file: %s", argv[i], err->message);
169 			g_error_free (err);
170 			err = NULL;
171 
172 #ifdef DUMP_CONTENT
173 			dump_biff_stream (input);
174 #endif
175 
176 			g_object_unref (G_OBJECT (input));
177 			continue;
178 		}
179 #if 0
180 		stream = gsf_infile_child_by_name (infile, "\01CompObj");
181 		if (stream != NULL) {
182 			gsf_off_t len = gsf_input_size (stream);
183 			guint8 const *data = gsf_input_read (stream, len, NULL);
184 			if (data != NULL)
185 				gsf_mem_dump (data, len);
186 			g_object_unref (G_OBJECT (stream));
187 		}
188 		return 0;
189 #endif
190 
191 		stream = gsf_infile_child_by_name (infile, "\05SummaryInformation");
192 		if (stream != NULL) {
193 			GsfDocMetaData *meta_data = gsf_doc_meta_data_new ();
194 
195 			puts ( "SummaryInfo");
196 			err = gsf_doc_meta_data_read_from_msole (meta_data, stream);
197 			if (err != NULL) {
198 				g_warning ("'%s' error: %s", argv[i], err->message);
199 				g_error_free (err);
200 				err = NULL;
201 			} else
202 				gsf_doc_meta_dump (meta_data);
203 
204 			g_object_unref (meta_data);
205 			g_object_unref (G_OBJECT (stream));
206 		}
207 
208 		stream = gsf_infile_child_by_name (infile, "\05DocumentSummaryInformation");
209 		if (stream != NULL) {
210 			GsfDocMetaData *meta_data = gsf_doc_meta_data_new ();
211 
212 			puts ( "DocSummaryInfo");
213 			err = gsf_doc_meta_data_read_from_msole (meta_data, stream);
214 			if (err != NULL) {
215 				g_warning ("'%s' error: %s", argv[i], err->message);
216 				g_error_free (err);
217 				err = NULL;
218 			} else
219 				gsf_doc_meta_dump (meta_data);
220 
221 			g_object_unref (meta_data);
222 			g_object_unref (G_OBJECT (stream));
223 		}
224 
225 		for (j = 0 ; j < G_N_ELEMENTS (stream_names) ; j++) {
226 			stream = gsf_infile_child_by_name (infile, stream_names[j]);
227 			if (stream != NULL) {
228 				puts (j < 3 ? "Excel97" : "Excel95");
229 #ifdef DUMP_CONTENT
230 				dump_biff_stream (stream);
231 #endif
232 				g_object_unref (G_OBJECT (stream));
233 				break;
234 			}
235 		}
236 
237 #ifdef DUMP_CONTENT
238 		pcache_dir = gsf_infile_child_by_name (infile, "_SX_DB_CUR");	/* Excel 97 */
239 		if (NULL == pcache_dir)
240 			pcache_dir = gsf_infile_child_by_name (infile, "_SX_DB");	/* Excel 95 */
241 		if (NULL != pcache_dir) {
242 			int i, n = gsf_infile_num_children (infile);
243 			for (i = 0 ; i < n ; i++) {
244 				stream = gsf_infile_child_by_index  (GSF_INFILE (pcache_dir), i);
245 				if (stream != NULL) {
246 					printf ("=================================================\nPivot cache '%04hX'\n\n", i);
247 
248 					dump_biff_stream (stream);
249 					g_object_unref (G_OBJECT (stream));
250 				}
251 			}
252 			g_object_unref (G_OBJECT (pcache_dir));
253 		}
254 #endif
255 
256 		g_object_unref (G_OBJECT (infile));
257 		g_object_unref (G_OBJECT (input));
258 	}
259 
260 	return 0;
261 }
262 
263 int
main(int argc,char * argv[])264 main (int argc, char *argv[])
265 {
266 	int res;
267 
268 	gsf_init ();
269 	res = test (argc, argv);
270 	gsf_shutdown ();
271 
272 	return res;
273 }
274