/* 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 <gsf/gsf-input-stdio.h>
#include <gsf/gsf-input-memory.h>
#include <gsf/gsf-utils.h>
#include <gsf/gsf-infile.h>
#include <gsf/gsf-infile-msole.h>
#include <gsf/gsf-msole-utils.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1