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