/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * test-msole1.c: test program to dump biff streams * * Copyright (C) 2002-2006 Jody Goldberg (jody@gnome.org) * Copyright (C) 2002-2003 Michael Meeks (michael.meeks@novell.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2.1 of the GNU Lesser General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA * * Parts of this code are taken from libole2/test/test-ole.c */ #include #include #include #include #include #include #include #include #include #define BIFF_TYPES_FILE "biff-types.h" #define DUMP_CONTENT typedef struct { guint16 opcode; char *name; } GENERIC_TYPE; #ifdef DUMP_CONTENT static GPtrArray *biff_types = NULL; static void read_types (char const *fname, GPtrArray **types) { FILE *file = fopen(fname, "r"); unsigned char buffer[1024]; *types = g_ptr_array_new (); if (!file) { char *newname = g_strconcat ("../", fname, NULL); file = fopen (newname, "r"); } if (!file) { g_printerr ("Can't find vital file '%s'\n", fname); return; } while (!feof(file)) { unsigned char *p; fgets ((char *)buffer, sizeof (buffer)-1, file); for (p=buffer;*p;p++) if (*p=='0' && *(p+1)=='x') { GENERIC_TYPE *bt = g_new (GENERIC_TYPE,1); unsigned char *name, *pt; bt->opcode=strtol((char *)p+2,0,16); pt = buffer; while (*pt && *pt != '#') pt++; /* # */ while (*pt && !isspace(*pt)) pt++; /* define */ while (*pt && isspace((unsigned char)*pt)) pt++; /* ' ' */ while (*pt && *pt != '_') pt++; /* BIFF_ */ name = *pt?pt+1:pt; while (*pt && !isspace((unsigned char)*pt)) pt++; bt->name = g_strndup ((gchar *)name, (unsigned)(pt - name)); g_ptr_array_add (*types, bt); break; } } fclose (file); } static char const * get_biff_opcode_name (unsigned opcode) { int lp; if (!biff_types) read_types (BIFF_TYPES_FILE, &biff_types); /* Count backwars to give preference to non-filtered record types */ for (lp=biff_types->len; --lp >= 0 ;) { GENERIC_TYPE *bt = g_ptr_array_index (biff_types, lp); if (bt->opcode == opcode) return bt->name; } return "Unknown"; } static void dump_biff_stream (GsfInput *stream) { guint8 const *data; guint16 len, opcode; unsigned pos = gsf_input_tell (stream); while (NULL != (data = gsf_input_read (stream, 4, NULL))) { gboolean enable_dump = TRUE; opcode = GSF_LE_GET_GUINT16 (data); len = GSF_LE_GET_GUINT16 (data+2); if (len > 15000) { enable_dump = TRUE; g_warning ("Suspicious import of biff record > 15,000 (0x%x) for opcode 0x%hx", len, opcode); } else if ((opcode & 0xff00) > 0x1000) { enable_dump = TRUE; g_warning ("Suspicious import of biff record with opcode 0x%hx", opcode); } if (enable_dump) printf ("Opcode 0x%3hx : %15s, length 0x%hx (=%hd)\n", opcode, get_biff_opcode_name (opcode), len, len); if (len > 0) { data = gsf_input_read (stream, len, NULL); if (data == NULL) break; if (enable_dump) gsf_mem_dump (data, len); } pos = gsf_input_tell (stream); } } #endif /* DUMP_CONTENT */ static int test (unsigned argc, char *argv[]) { static char const * const stream_names[] = { "Workbook", "WORKBOOK", "workbook", "Book", "BOOK", "book" }; GsfInput *input, *stream; GsfInfile *infile; GError *err = NULL; unsigned i, j; for (i = 1 ; i < argc ; i++) { fprintf( stderr, "%s\n",argv[i]); input = gsf_input_mmap_new (argv[i], NULL); if (input == NULL) /* Only report error if stdio fails too */ input = gsf_input_stdio_new (argv[i], &err); if (input == NULL) { g_return_val_if_fail (err != NULL, 1); g_warning ("'%s' error: %s", argv[i], err->message); g_error_free (err); continue; } input = gsf_input_uncompress (input); infile = gsf_infile_msole_new (input, &err); if (infile == NULL) { g_return_val_if_fail (err != NULL, 1); g_warning ("'%s' Not an OLE file: %s", argv[i], err->message); g_error_free (err); #ifdef DUMP_CONTENT dump_biff_stream (input); #endif g_object_unref (G_OBJECT (input)); continue; } #if 0 stream = gsf_infile_child_by_name (infile, "\01CompObj"); if (stream != NULL) { gsf_off_t len = gsf_input_size (stream); guint8 const *data = gsf_input_read (stream, len, NULL); if (data != NULL) gsf_mem_dump (data, len); g_object_unref (G_OBJECT (stream)); } return 0; #endif stream = gsf_infile_child_by_name (infile, "\05SummaryInformation"); if (stream != NULL) { GsfDocMetaData *meta_data = gsf_doc_meta_data_new (); puts ( "SummaryInfo"); err = gsf_msole_metadata_read (stream, meta_data); if (err != NULL) { g_warning ("'%s' error: %s", argv[i], err->message); g_error_free (err); err = NULL; } else gsf_doc_meta_dump (meta_data); g_object_unref (meta_data); g_object_unref (G_OBJECT (stream)); } stream = gsf_infile_child_by_name (infile, "\05DocumentSummaryInformation"); if (stream != NULL) { GsfDocMetaData *meta_data = gsf_doc_meta_data_new (); puts ( "DocSummaryInfo"); err = gsf_msole_metadata_read (stream, meta_data); if (err != NULL) { g_warning ("'%s' error: %s", argv[i], err->message); g_error_free (err); err = NULL; } else gsf_doc_meta_dump (meta_data); g_object_unref (meta_data); g_object_unref (G_OBJECT (stream)); } for (j = 0 ; j < G_N_ELEMENTS (stream_names) ; j++) { stream = gsf_infile_child_by_name (infile, stream_names[j]); if (stream != NULL) { puts (j < 3 ? "Excel97" : "Excel95"); #ifdef DUMP_CONTENT dump_biff_stream (stream); #endif g_object_unref (G_OBJECT (stream)); break; } } g_object_unref (G_OBJECT (infile)); g_object_unref (G_OBJECT (input)); } return 0; } int main (int argc, char *argv[]) { int res; gsf_init (); res = test (argc, argv); gsf_shutdown (); return res; }