[CMF-checkins] CVS: CMF - config.h:1.1 glibconfig.h:1.1 libole2.h:1.1 ms-ole-summary.c:1.1 ms-ole-summary.h:1.1 ms-ole-vba.c:1.1 ms-ole-vba.h:1.1 ms-ole.c:1.1 ms-ole.h:1.1 ole.c:1.1 ole.i:1.1 ole_wrap.c:1.1 setup.py:1.1 test-ole.c:1.1 version.c:1.1
jack@digicool.com
jack@digicool.com
Wed, 30 May 2001 10:39:21 -0400 (EDT)
Update of /cvs-repository/Packages/Products/DCProject/CMF_MS_Files/src/libole
In directory korak.digicool.com:/tmp/cvs-serv12283
Added Files:
config.h glibconfig.h libole2.h ms-ole-summary.c
ms-ole-summary.h ms-ole-vba.c ms-ole-vba.h ms-ole.c ms-ole.h
ole.c ole.i ole_wrap.c setup.py test-ole.c version.c
Log Message:
Adding CMF_MS_Files Product
--- Added File config.h in package Packages/Products/DCProject ---
/* config.h. Generated automatically by configure. */
#ifndef CONFIG_H_CALLED
#define CONFIG_H_CALLED 1
/* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define to empty if the keyword does not work. */
/* #undef const */
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
/* #undef HAVE_SYS_WAIT_H */
/* Define if you have the wait3 system call. */
/* #undef HAVE_WAIT3 */
/* Define if you have the waitpid system call. */
/* #undef HAVE_WAITPID */
/* Define as the return type of signal handlers (int or void). */
/* #undef RETSIGTYPE */
/* Define if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* #undef HAVE_POSIX_SIGNALS */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef pid_t */
/* Define if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the <sys/file.h> header file. */
#define HAVE_SYS_FILE_H 1
/* Define if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if you want zlib to uncompress wmf files */
/* #undef SYSTEM_ZLIB */
/* Define if you have libwmf and want it to convert wmf to gif files */
#define HAVE_WMF 1
/* Define if you have freetype*/
#define HAVE_TTF 1
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if defined(HAVE_ERRNO_H)
#include <errno.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
/* #include <dirent.h> */
#include <stdarg.h>
/*
#include <getopt.h>
*/
#define MATCHED_TYPE 1
/* #undef WORDS_BIGENDIAN */
#define XML_BYTE_ORDER 12
#if defined(__GNUC__) && !defined(WORDS_BIGENDIAN) && defined(MATCHED_TYPE)
#define NO_HOLES
#endif
/* define if you have iconv */
#define USE_ICONV 1
/* define if you have iconv but do not have windows codepage to unicode support */
/* #undef MUST_USE_INTERNAL_ICONV_TABLE */
/* define if you have libpng */
#define HasPNG 1
/* Define if you have the memcpy function. */
#define HAVE_MEMCPY 1
#ifndef HAVE_MEMCPY
#define memcpy(d, s, n) bcopy ((s), (d), (n))
#endif /* not HAVE_MEMCPY */
#define HAVE_MMAP 1
#endif /* CONFIG_H_CALLED */
--- Added File glibconfig.h in package Packages/Products/DCProject ---
/* glibconfig.h
*
* This is a generated file. Please modify `configure.in'
*/
#ifndef GLIBCONFIG_H
#define GLIBCONFIG_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <limits.h>
#include <float.h>
#define GLIB_HAVE_SYS_POLL_H
#define G_MINFLOAT FLT_MIN
#define G_MAXFLOAT FLT_MAX
#define G_MINDOUBLE DBL_MIN
#define G_MAXDOUBLE DBL_MAX
#define G_MINSHORT SHRT_MIN
#define G_MAXSHORT SHRT_MAX
#define G_MININT INT_MIN
#define G_MAXINT INT_MAX
#define G_MINLONG LONG_MIN
#define G_MAXLONG LONG_MAX
typedef signed char gint8;
typedef unsigned char guint8;
typedef signed short gint16;
typedef unsigned short guint16;
typedef signed int gint32;
typedef unsigned int guint32;
#if defined (__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
# define G_GNUC_EXTENSION __extension__
#else
# define G_GNUC_EXTENSION
#endif
#define G_HAVE_GINT64 1
G_GNUC_EXTENSION typedef signed long long gint64;
G_GNUC_EXTENSION typedef unsigned long long guint64;
#define G_GINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##LL))
#define GPOINTER_TO_INT(p) ((gint) (p))
#define GPOINTER_TO_UINT(p) ((guint) (p))
#define GINT_TO_POINTER(i) ((gpointer) (i))
#define GUINT_TO_POINTER(u) ((gpointer) (u))
#ifdef NeXT /* @#%@! NeXTStep */
# define g_ATEXIT(proc) (!atexit (proc))
#else
# define g_ATEXIT(proc) (atexit (proc))
#endif
#define g_memmove(d,s,n) G_STMT_START { memmove ((d), (s), (n)); } G_STMT_END
#define GLIB_MAJOR_VERSION 1
#define GLIB_MINOR_VERSION 2
#define GLIB_MICRO_VERSION 8
#define G_VA_COPY __va_copy
#ifdef __cplusplus
#define G_HAVE_INLINE 1
#else /* !__cplusplus */
#define G_HAVE_INLINE 1
#define G_HAVE___INLINE 1
#define G_HAVE___INLINE__ 1
#endif /* !__cplusplus */
#define G_THREADS_ENABLED
#define G_THREADS_IMPL_POSIX
typedef struct _GStaticMutex GStaticMutex;
struct _GStaticMutex
{
struct _GMutex *runtime_mutex;
union {
char pad[24];
double dummy_double;
void *dummy_pointer;
long dummy_long;
} aligned_pad_u;
};
#define G_STATIC_MUTEX_INIT { NULL, { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } }
#define g_static_mutex_get_mutex(mutex) (g_thread_use_default_impl ? ((GMutex*) &((mutex)->aligned_pad_u)) : g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex)))
#define GINT16_TO_LE(val) ((gint16) (val))
#define GUINT16_TO_LE(val) ((guint16) (val))
#define GINT16_TO_BE(val) ((gint16) GUINT16_SWAP_LE_BE (val))
#define GUINT16_TO_BE(val) (GUINT16_SWAP_LE_BE (val))
#define GINT32_TO_LE(val) ((gint32) (val))
#define GUINT32_TO_LE(val) ((guint32) (val))
#define GINT32_TO_BE(val) ((gint32) GUINT32_SWAP_LE_BE (val))
#define GUINT32_TO_BE(val) (GUINT32_SWAP_LE_BE (val))
#define GINT64_TO_LE(val) ((gint64) (val))
#define GUINT64_TO_LE(val) ((guint64) (val))
#define GINT64_TO_BE(val) ((gint64) GUINT64_SWAP_LE_BE (val))
#define GUINT64_TO_BE(val) (GUINT64_SWAP_LE_BE (val))
#define GLONG_TO_LE(val) ((glong) GINT32_TO_LE (val))
#define GULONG_TO_LE(val) ((gulong) GUINT32_TO_LE (val))
#define GLONG_TO_BE(val) ((glong) GINT32_TO_BE (val))
#define GULONG_TO_BE(val) ((gulong) GUINT32_TO_BE (val))
#define GINT_TO_LE(val) ((gint) GINT32_TO_LE (val))
#define GUINT_TO_LE(val) ((guint) GUINT32_TO_LE (val))
#define GINT_TO_BE(val) ((gint) GINT32_TO_BE (val))
#define GUINT_TO_BE(val) ((guint) GUINT32_TO_BE (val))
#define G_BYTE_ORDER G_LITTLE_ENDIAN
#define GLIB_SYSDEF_POLLIN =1
#define GLIB_SYSDEF_POLLOUT =4
#define GLIB_SYSDEF_POLLPRI =2
#define GLIB_SYSDEF_POLLERR =8
#define GLIB_SYSDEF_POLLHUP =16
#define GLIB_SYSDEF_POLLNVAL =32
#define G_HAVE_WCHAR_H 1
#define G_HAVE_WCTYPE_H 1
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* GLIBCONFIG_H */
--- Added File libole2.h in package Packages/Products/DCProject ---
#include "ms-ole.h"
#include "ms-ole-summary.h"
extern int libole2_major_version;
extern int libole2_minor_version;
extern int libole2_micro_version;
#define LIBOLE2_MAJOR_VERSION 0
#define LIBOLE2_MINOR_VERSION 1
#define LIBOLE2_MICRO_VERSION 7
--- Added File ms-ole-summary.c in package Packages/Products/DCProject ---
/**
* ms-ole-summary.c: MS Office OLE support
*
* Authors:
* Michael Meeks (mmeeks@gnu.org)
* Frank Chiulli (fc-linux@home.com)
* From work by:
* Caolan McNamara (Caolan.McNamara@ul.ie)
* Built on work by:
* Somar Software's CPPSUM (http://www.somar.com)
**/
#include <config.h>
#include <glib.h>
#include <stdio.h>
#include <ms-ole.h>
#include <ms-ole-summary.h>
#define SUMMARY_ID(x) ((x) & 0xff)
typedef struct {
guint32 offset;
guint32 id;
MsOlePropertySetID ps_id;
} item_t;
const guint32 sum_fmtid[4] = {
0xF29F85E0,
0x10684FF9,
0x000891AB,
0xD9B3272B
};
const guint32 doc_fmtid[4] = {
0xD5CDD502,
0x101B2E9C,
0x00089793,
0xAEF92C2B
};
const guint32 user_fmtid[4] = {
0XD5CDD505,
0X101B2E9C,
0X00089793,
0XAEF92C2B
};
static gboolean
read_items (MsOleSummary *si, MsOlePropertySetID ps_id)
{
gint sect;
for (sect = 0; sect < si->sections->len; sect++) {
MsOleSummarySection st;
guint8 data[8];
gint i;
st = g_array_index (si->sections, MsOleSummarySection, sect);
if (st.ps_id != ps_id)
continue;
si->s->lseek (si->s, st.offset, MsOleSeekSet);
if (!si->s->read_copy (si->s, data, 8))
return FALSE;
st.bytes = MS_OLE_GET_GUINT32 (data);
st.props = MS_OLE_GET_GUINT32 (data + 4);
if (st.props == 0)
continue;
for (i = 0; i < st.props; i++) {
item_t item;
if (!si->s->read_copy (si->s, data, 8))
return FALSE;
item.id = MS_OLE_GET_GUINT32 (data);
item.offset = MS_OLE_GET_GUINT32 (data + 4);
item.offset = item.offset + st.offset;
item.ps_id = ps_id;
g_array_append_val (si->items, item);
}
}
return TRUE;
}
typedef struct {
MsOleSummaryPID id;
guint32 len;
guint8 *data;
} write_item_t;
#define PROPERTY_HDR_LEN 8
#define PROPERTY_DESC_LEN 8
static void
write_items (MsOleSummary *si)
{
MsOlePos cur_pos;
MsOlePos pos = 48; /* magic offset see: _create_stream */
guint8 data[PROPERTY_DESC_LEN];
guint8 fill_data[] = {0, 0, 0, 0};
guint32 i, num;
guint32 offset = 0;
GList *l;
/*
* Write out the property descriptors.
* Keep track of the number of properties and number of bytes for the properties.
*/
si->s->lseek (si->s, pos + PROPERTY_HDR_LEN, MsOleSeekSet);
l = si->write_items;
num = g_list_length (l);
i = 0;
offset = PROPERTY_HDR_LEN + num * PROPERTY_DESC_LEN;
while (l) {
write_item_t *w = l->data;
g_return_if_fail (w != NULL);
/*
* The offset is calculated from the start of the
* properties header. The offset must be on a
* 4-byte boundary. Therefore all data written must be
* in multiples of 4-bytes.
*/
MS_OLE_SET_GUINT32 (data + 0, w->id & 0xff);
MS_OLE_SET_GUINT32 (data + 4, offset);
si->s->write (si->s, data, PROPERTY_DESC_LEN);
offset += w->len;
if ((w->len & 0x3) > 0)
offset += (4 - (w->len & 0x3));
i++;
l = g_list_next (l);
}
g_return_if_fail (i == num);
/*
* Write out the section header.
*/
si->s->lseek (si->s, pos, MsOleSeekSet);
MS_OLE_SET_GUINT32 (data + 0, offset);
MS_OLE_SET_GUINT32 (data + 4, i);
si->s->write (si->s, data, PROPERTY_HDR_LEN);
/*
* Write out the property values.
* Keep track of the last position written to.
*/
cur_pos = pos + PROPERTY_HDR_LEN + num*PROPERTY_DESC_LEN;
si->s->lseek (si->s, cur_pos, MsOleSeekSet);
l = si->write_items;
while (l) {
write_item_t *w = l->data;
si->s->write (si->s, w->data, w->len);
cur_pos += w->len;
l = g_list_next (l);
/*
* Write out any fill.
*/
if ((w->len & 0x3) > 0) {
cur_pos += (4 - (w->len & 0x3));
si->s->write (si->s, fill_data, 4 - (w->len & 0x3));
}
}
/*
* Pad it out to a BB file.
*/
{
int i;
for (i = cur_pos; i < 0x1000; i+=4)
si->s->write (si->s, fill_data, 4);
}
}
/**
* ms_ole_summary_open_stream:
* @stream: stream object
* @psid: Property Set ID, indicates which property set to open
*
* Opens @s as a summary stream, returns NULL on failure.
*
* Return value: %NULL if unable to open summary stream or a pointer to the
* Summary Stream.
**/
MsOleSummary *
ms_ole_summary_open_stream (MsOleStream *stream,
const MsOlePropertySetID psid)
{
guint8 data[64];
guint16 byte_order;
gboolean panic = FALSE;
guint32 os_version;
MsOleSummary *si;
gint i, sections;
g_return_val_if_fail (stream != NULL, NULL);
if (!stream->read_copy (stream, data, 28))
return NULL;
si = g_new (MsOleSummary, 1);
si->s = stream;
si->write_items = NULL;
si->sections = NULL;
si->items = NULL;
si->read_mode = TRUE;
byte_order = MS_OLE_GET_GUINT16(data);
if (byte_order != 0xfffe)
panic = TRUE;
if (MS_OLE_GET_GUINT16 (data + 2) != 0) /* Format */
panic = TRUE;
os_version = MS_OLE_GET_GUINT32 (data + 4);
for (i = 0; i < 16; i++)
si->class_id[i] = data[8 + i];
sections = MS_OLE_GET_GUINT32 (data + 24);
if (panic) {
ms_ole_summary_close (si);
return NULL;
}
si->sections = g_array_new (FALSE, FALSE, sizeof (MsOleSummarySection));
for (i = 0; i < sections; i++) {
MsOleSummarySection sect;
if (!stream->read_copy (stream, data, 16 + 4)) {
ms_ole_summary_close (si);
return NULL;
}
if (psid == MS_OLE_PS_SUMMARY_INFO) {
if (MS_OLE_GET_GUINT32 (data + 0) == sum_fmtid[0] &&
MS_OLE_GET_GUINT32 (data + 4) == sum_fmtid[1] &&
MS_OLE_GET_GUINT32 (data + 8) == sum_fmtid[2] &&
MS_OLE_GET_GUINT32 (data + 12) == sum_fmtid[3] ) {
si->ps_id = MS_OLE_PS_SUMMARY_INFO;
sect.ps_id = MS_OLE_PS_SUMMARY_INFO;
} else {
ms_ole_summary_close (si);
return NULL;
}
} else if (psid == MS_OLE_PS_DOCUMENT_SUMMARY_INFO) {
if (MS_OLE_GET_GUINT32 (data + 0) == doc_fmtid[0] &&
MS_OLE_GET_GUINT32 (data + 4) == doc_fmtid[1] &&
MS_OLE_GET_GUINT32 (data + 8) == doc_fmtid[2] &&
MS_OLE_GET_GUINT32 (data + 12) == doc_fmtid[3] ) {
si->ps_id = MS_OLE_PS_DOCUMENT_SUMMARY_INFO;
sect.ps_id = MS_OLE_PS_DOCUMENT_SUMMARY_INFO;
} else if (MS_OLE_GET_GUINT32 (data + 0) == user_fmtid[0] &&
MS_OLE_GET_GUINT32 (data + 4) == user_fmtid[1] &&
MS_OLE_GET_GUINT32 (data + 8) == user_fmtid[2] &&
MS_OLE_GET_GUINT32 (data + 12) == user_fmtid[3] ) {
si->ps_id = MS_OLE_PS_DOCUMENT_SUMMARY_INFO;
sect.ps_id = MS_OLE_PS_USER_DEFINED_SUMMARY_INFO;
} else {
ms_ole_summary_close (si);
return NULL;
}
}
sect.offset = MS_OLE_GET_GUINT32 (data + 16);
g_array_append_val (si->sections, sect);
/* We want to read the offsets of the items here into si->items */
}
si->items = g_array_new (FALSE, FALSE, sizeof (item_t));
for (i = 0; i < sections; i++) {
MsOleSummarySection st;
st = g_array_index (si->sections, MsOleSummarySection, i);
if (!read_items (si, st.ps_id)) {
// JPP g_warning ("Serious error reading items");
ms_ole_summary_close (si);
return NULL;
}
}
return si;
}
/**
* ms_ole_summary_open:
* @f: filesystem object.
*
* Opens the SummaryInformation stream, returns NULL on failure.
*
* Return value: %NULL if unable to open summary stream or a pointer to the
* SummaryInformation Stream.
**/
MsOleSummary *
ms_ole_summary_open (MsOle *f)
{
MsOleStream *s;
MsOleErr result;
// JPP g_return_val_if_fail (f != NULL, NULL);
result = ms_ole_stream_open (&s, f, "/",
"\05SummaryInformation", 'r');
if (result != MS_OLE_ERR_OK || !s)
return NULL;
return ms_ole_summary_open_stream (s, MS_OLE_PS_SUMMARY_INFO);
}
/**
* ms_ole_docsummary_open:
* @f: filesystem object.
*
* Opens the DocumentSummaryInformation stream, returns NULL on failure.
*
* Return value: %NULL if unable to open summary stream or a pointer to the
* DocumentSummaryInformation Stream.
**/
MsOleSummary *
ms_ole_docsummary_open (MsOle *f)
{
MsOleStream *s;
MsOleErr result;
// JPP g_return_val_if_fail (f != NULL, NULL);
result = ms_ole_stream_open (&s, f, "/",
"\05DocumentSummaryInformation", 'r');
if (result != MS_OLE_ERR_OK || !s)
return NULL;
return ms_ole_summary_open_stream (s, MS_OLE_PS_DOCUMENT_SUMMARY_INFO);
}
/*
* Cheat by hard coding magic numbers and chaining on.
*/
/**
* ms_ole_summary_create_stream:
* @s: stream object
* @psid: Property Set ID, indicates which property set to open
*
* Creates @s as a summary stream (@psid determines which one), returns NULL on
* failure.
*
* Return value: %NULL if unable to create stream, otherwise a pointer to a new
* summary stream.
**/
MsOleSummary *
ms_ole_summary_create_stream (MsOleStream *s, const MsOlePropertySetID psid)
{
guint8 data[78];
MsOleSummary *si;
g_return_val_if_fail (s != NULL, NULL);
MS_OLE_SET_GUINT16 (data + 0, 0xfffe); /* byte order */
MS_OLE_SET_GUINT16 (data + 2, 0x0000); /* format */
MS_OLE_SET_GUINT16 (data + 4, 0x0001); /* OS version A */
MS_OLE_SET_GUINT16 (data + 6, 0x0000); /* OS version B */
MS_OLE_SET_GUINT32 (data + 8, 0x0000); /* class id */
MS_OLE_SET_GUINT32 (data + 12, 0x0000);
MS_OLE_SET_GUINT32 (data + 16, 0x0000);
MS_OLE_SET_GUINT32 (data + 20, 0x0000);
if (psid == MS_OLE_PS_SUMMARY_INFO) {
MS_OLE_SET_GUINT32 (data + 24, 0x0001); /* Sections */
MS_OLE_SET_GUINT32 (data + 28, sum_fmtid[0]); /* ID */
MS_OLE_SET_GUINT32 (data + 32, sum_fmtid[1]);
MS_OLE_SET_GUINT32 (data + 36, sum_fmtid[2]);
MS_OLE_SET_GUINT32 (data + 40, sum_fmtid[3]);
MS_OLE_SET_GUINT32 (data + 44, 0x30); /* Section offset = 48 */
MS_OLE_SET_GUINT32 (data + 48, 0); /* bytes */
MS_OLE_SET_GUINT32 (data + 52, 0); /* properties */
s->write (s, data, 56);
} else if (psid == MS_OLE_PS_DOCUMENT_SUMMARY_INFO) {
MS_OLE_SET_GUINT32 (data + 24, 0x0001); /* Sections */
MS_OLE_SET_GUINT32 (data + 28, doc_fmtid[0]); /* ID */
MS_OLE_SET_GUINT32 (data + 32, doc_fmtid[1]);
MS_OLE_SET_GUINT32 (data + 36, doc_fmtid[2]);
MS_OLE_SET_GUINT32 (data + 40, doc_fmtid[3]);
MS_OLE_SET_GUINT32 (data + 44, 0x30); /* Section offset = 48 */
MS_OLE_SET_GUINT32 (data + 48, 0); /* bytes */
MS_OLE_SET_GUINT32 (data + 52, 0); /* properties */
s->write (s, data, 56);
}
s->lseek (s, 0, MsOleSeekSet);
si = ms_ole_summary_open_stream (s, psid);
si->read_mode = FALSE;
return si;
}
/**
* ms_ole_summary_create:
* @f: filesystem object.
*
* Create a SummaryInformation stream, returns NULL on failure.
*
* Return value: %NULL if unable to create the stream, otherwise a pointer to a
* new SummaryInformation stream.
**/
MsOleSummary *
ms_ole_summary_create (MsOle *f)
{
MsOleStream *s;
MsOleErr result;
g_return_val_if_fail (f != NULL, NULL);
result = ms_ole_stream_open (&s, f, "/",
"\05SummaryInformation", 'w');
if (result != MS_OLE_ERR_OK || !s) {
printf ("ms_ole_summary_create: Can't open stream for writing\n");
return NULL;
}
return ms_ole_summary_create_stream (s, MS_OLE_PS_SUMMARY_INFO);
}
/**
* ms_ole_docsummary_create:
* @f: filesystem object.
*
* Create a DocumentSummaryInformation stream, returns NULL on failure.
*
* Return value: %NULL if unable to create the stream, otherwise a pointer to a
* new DocumentSummaryInformation stream.
**/
MsOleSummary *
ms_ole_docsummary_create (MsOle *f)
{
MsOleStream *s;
MsOleErr result;
g_return_val_if_fail (f != NULL, NULL);
result = ms_ole_stream_open (&s, f, "/",
"\05DocumentSummaryInformation", 'w');
if (result != MS_OLE_ERR_OK || !s) {
printf ("ms_ole_docsummary_create: Can't open stream for writing\n");
return NULL;
}
return ms_ole_summary_create_stream (s, MS_OLE_PS_DOCUMENT_SUMMARY_INFO);
}
/* FIXME: without the helpful type */
/**
* ms_ole_summary_get_properties:
* @si: summary stream
*
* Returns an array of MsOleSummaryPID.
*
* Return value: an array of property ids in the current summary stream or
* %NULL if either the summary stream is non-existent or the summary stream
* contains no properties.
**/
GArray *
ms_ole_summary_get_properties (MsOleSummary *si)
{
GArray *ans;
gint i;
g_return_val_if_fail (si != NULL, NULL);
g_return_val_if_fail (si->items != NULL, NULL);
ans = g_array_new (FALSE, FALSE, sizeof (MsOleSummaryPID));
g_array_set_size (ans, si->items->len);
for (i = 0; i < si->items->len; i++)
g_array_index (ans, MsOleSummaryPID, i) =
g_array_index (si->items, item_t, i).id;
return ans;
}
/**
* ms_ole_summary_close:
* @si: FIXME
*
* FIXME
**/
void
ms_ole_summary_close (MsOleSummary *si)
{
g_return_if_fail (si != NULL);
g_return_if_fail (si->s != NULL);
if (!si->read_mode)
write_items (si);
if (si->sections)
g_array_free (si->sections, TRUE);
si->sections = NULL;
if (si->items)
g_array_free (si->items, TRUE);
si->items = NULL;
if (si->s)
ms_ole_stream_close (&si->s);
si->s = NULL;
g_free (si);
}
/*
* Record handling code
*/
#define TYPE_SHORT 0x02 /* 2, VT_I2, 2-byte signed integer */
#define TYPE_LONG 0x03 /* 3, VT_I4, 4-byte signed integer */
#define TYPE_BOOLEAN 0x0b /* 11, VT_BOOL, Boolean value */
#define TYPE_STRING 0x1e /* 30, VT_LPSTR, Pointer to null terminated ANSI string */
#define TYPE_TIME 0x40 /* 64, VT_FILETIME, 64-bit FILETIME structure */
#define TYPE_PREVIEW 0x47 /* 71, VT_CF, Pointer to a CLIPDATA structure */
/* Seeks to the correct place, and returns a handle or NULL on failure */
static item_t *
seek_to_record (MsOleSummary *si, MsOleSummaryPID id)
{
gint i;
g_return_val_if_fail (si->items, FALSE);
/* These should / could be sorted for speed */
for (i = 0; i < si->items->len; i++) {
item_t item = g_array_index (si->items, item_t, i);
if (item.id == SUMMARY_ID(id)) {
gboolean is_summary, is_doc_summary;
is_summary = ((si->ps_id == MS_OLE_PS_SUMMARY_INFO) &&
(item.ps_id == MS_OLE_PS_SUMMARY_INFO));
is_doc_summary = ((si->ps_id == MS_OLE_PS_DOCUMENT_SUMMARY_INFO) &&
(item.ps_id == MS_OLE_PS_DOCUMENT_SUMMARY_INFO));
if (is_summary || is_doc_summary) {
si->s->lseek (si->s, item.offset, MsOleSeekSet);
return &g_array_index (si->items, item_t, i);
}
}
}
return NULL;
}
/**
* ms_ole_summary_get_string:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
* Note: Ensure that you free returned value after use.
*
* Return value: FIXME
**/
char *
ms_ole_summary_get_string (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type, len;
gchar *ans;
item_t *item;
g_return_val_if_fail (available != NULL, 0);
*available = FALSE;
g_return_val_if_fail (si != NULL, NULL);
g_return_val_if_fail (si->read_mode, NULL);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_STRING, NULL);
if (!(item = seek_to_record (si, id)))
return NULL;
if (!si->s->read_copy (si->s, data, 8))
return NULL;
type = MS_OLE_GET_GUINT32 (data);
len = MS_OLE_GET_GUINT32 (data + 4);
if (type != TYPE_STRING) { /* Very odd */
// JPP g_warning ("Summary string type mismatch");
return NULL;
}
ans = g_new (gchar, len + 1);
if (!si->s->read_copy (si->s, ans, len)) {
g_free (ans);
return NULL;
}
ans[len] = '\0';
*available = TRUE;
return ans;
}
/**
* ms_ole_summary_get_short:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
guint16
ms_ole_summary_get_short (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type;
guint32 value;
item_t *item;
g_return_val_if_fail (available != NULL, 0);
*available = FALSE;
g_return_val_if_fail (si != NULL, 0);
g_return_val_if_fail (si->read_mode, 0);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_SHORT, 0);
if (!(item = seek_to_record (si, id)))
return 0;
if (!si->s->read_copy (si->s, data, 8))
return 0;
type = MS_OLE_GET_GUINT32 (data);
value = MS_OLE_GET_GUINT16 (data + 4);
if (type != TYPE_SHORT) { /* Very odd */
// JPP g_warning ("Summary short type mismatch");
return 0;
}
*available = TRUE;
return value;
}
/**
* ms_ole_summary_get_boolean:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
gboolean
ms_ole_summary_get_boolean (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type;
gboolean value;
item_t *item;
g_return_val_if_fail (available != NULL, 0);
*available = FALSE;
g_return_val_if_fail (si != NULL, 0);
g_return_val_if_fail (si->read_mode, 0);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_BOOLEAN, 0);
if (!(item = seek_to_record (si, id)))
return 0;
if (!si->s->read_copy (si->s, data, 8))
return 0;
type = MS_OLE_GET_GUINT32 (data);
value = MS_OLE_GET_GUINT16 (data + 4);
if (type != TYPE_BOOLEAN) { /* Very odd */
// JPP g_warning ("Summary boolean type mismatch");
return 0;
}
*available = TRUE;
return value;
}
/**
* ms_ole_summary_get_long:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
guint32
ms_ole_summary_get_long (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type, value;
item_t *item;
g_return_val_if_fail (available != NULL, 0);
*available = FALSE;
g_return_val_if_fail (si != NULL, 0);
g_return_val_if_fail (si->read_mode, 0);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_LONG, 0);
if (!(item = seek_to_record (si, id)))
return 0;
if (!si->s->read_copy (si->s, data, 8))
return 0;
type = MS_OLE_GET_GUINT32 (data);
value = MS_OLE_GET_GUINT32 (data + 4);
if (type != TYPE_LONG) { /* Very odd */
// JPP g_warning ("Summary long type mismatch");
return 0;
}
*available = TRUE;
return value;
}
/*
* filetime_to_unixtime
*
* Convert a FILETIME format to unixtime
* FILETIME is the number of 100ns units since January 1, 1601.
* unixtime is the number of seconds since January 1, 1970.
*
* The difference in 100ns units between the two dates is:
* 116,444,736,000,000,000 (TIMEDIF)
* (I'll let you do the math)
* If we divide this into pieces,
* high 32-bits = 27111902 or TIMEDIF / 16^8
* mid 16-bits = 54590 or (TIMEDIF - (high 32-bits * 16^8)) / 16^4
* low 16-bits = 32768 or (TIMEDIF - (high 32-bits * 16^8) - (mid 16-bits * 16^4)
*
* where all math is integer.
*
* Adapted from work in 'wv' by:
* Caolan McNamara (Caolan.McNamara@ul.ie)
*/
#define HIGH32_DELTA 27111902
#define MID16_DELTA 54590
#define LOW16_DELTA 32768
/**
* filetime_to_unixtime:
* @low_time: FIXME
* @high_time: FIXME
*
* Converts a FILETIME format to unixtime. FILETIME is the number of 100ns units
* since January 1, 1601. unixtime is the number of seconds since January 1,
* 1970.
*
* Return value: FIXME
**/
glong filetime_to_unixtime (guint32 low_time, guint32 high_time);
glong
filetime_to_unixtime (guint32 low_time, guint32 high_time)
{
guint32 low16; /* 16 bit, low bits */
guint32 mid16; /* 16 bit, medium bits */
guint32 hi32; /* 32 bit, high bits */
unsigned int carry; /* carry bit for subtraction */
int negative; /* whether a represents a negative value */
/* Copy the time values to hi32/mid16/low16 */
hi32 = high_time;
mid16 = low_time >> 16;
low16 = low_time & 0xffff;
/* Subtract the time difference */
if (low16 >= LOW16_DELTA )
low16 -= LOW16_DELTA , carry = 0;
else
low16 += (1 << 16) - LOW16_DELTA , carry = 1;
if (mid16 >= MID16_DELTA + carry)
mid16 -= MID16_DELTA + carry, carry = 0;
else
mid16 += (1 << 16) - MID16_DELTA - carry, carry = 1;
hi32 -= HIGH32_DELTA + carry;
/* If a is negative, replace a by (-1-a) */
negative = (hi32 >= ((guint32)1) << 31);
if (negative) {
/* Set a to -a - 1 (a is hi32/mid16/low16) */
low16 = 0xffff - low16;
mid16 = 0xffff - mid16;
hi32 = ~hi32;
}
/*
* Divide a by 10000000 (a = hi32/mid16/low16), put the rest into r.
* Split the divisor into 10000 * 1000 which are both less than 0xffff.
*/
mid16 += (hi32 % 10000) << 16;
hi32 /= 10000;
low16 += (mid16 % 10000) << 16;
mid16 /= 10000;
low16 /= 10000;
mid16 += (hi32 % 1000) << 16;
hi32 /= 1000;
low16 += (mid16 % 1000) << 16;
mid16 /= 1000;
low16 /= 1000;
/* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
if (negative) {
/* Set a to -a - 1 (a is hi32/mid16/low16) */
low16 = 0xffff - low16;
mid16 = 0xffff - mid16;
hi32 = ~hi32;
}
/* Do not replace this by << 32, it gives a compiler warning and
* it does not work
*/
return ((((glong)hi32) << 16) << 16) + (mid16 << 16) + low16;
}
/**
* unixtime_to_filetime:
* @unix_time: FIXME
* @time_high: FIXME
* @time_low: FIXME
*
* Converts a unixtime format to FILETIME. FILETIME is the number of 100ns units
* since January 1, 1601. unixtime is the number of seconds since January 1,
* 1970.
**/
void unixtime_to_filetime (time_t unix_time, unsigned int *time_high,
unsigned int *time_low);
void
unixtime_to_filetime (time_t unix_time, unsigned int *time_high, unsigned int *time_low)
{
unsigned int low_16;
unsigned int mid_16;
unsigned int high32;
unsigned int carry;
/*
* First split unix_time up.
*/
high32 = (unix_time >> 16) >> 16;
mid_16 = unix_time >> 16;
low_16 = unix_time & 0xffff;
/*
* Convert seconds to 100 ns units by multipling by 10,000,000.
* Do this in two steps, 10,000 and 1,000.
*/
low_16 *= 10000;
carry = (low_16) >> 16;
low_16 = low_16 & 0xffff;
mid_16 *= 10000;
mid_16 += carry;
carry = (mid_16 >> 16);
mid_16 = mid_16 & 0xffff;
high32 *= 10000;
high32 += carry;
low_16 *= 1000;
carry = (low_16) >> 16;
low_16 = low_16 & 0xffff;
mid_16 *= 1000;
mid_16 += carry;
carry = (mid_16 >> 16);
mid_16 = mid_16 & 0xffff;
high32 *= 1000;
high32 += carry;
/*
* Now add in the time difference.
*/
low_16 += LOW16_DELTA;
mid_16 += (low_16 >> 16);
low_16 = low_16 & 0xffff;
mid_16 += MID16_DELTA;
high32 += (mid_16 >> 16);
mid_16 = mid_16 & 0xffff;
high32 += HIGH32_DELTA;
*time_high = high32;
*time_low = (mid_16 << 16) + low_16;
return;
}
/**
* ms_ole_summary_get_time:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
GTimeVal
ms_ole_summary_get_time (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[12];
guint32 type;
guint32 low_time;
guint32 high_time;
item_t *item;
GTimeVal time;
time.tv_sec = 0; /* Magic numbers */
time.tv_usec = 0;
/* g_date_set_dmy (&time.date, 18, 6, 1977); */
g_return_val_if_fail (available != NULL, time);
*available = FALSE;
g_return_val_if_fail (si != NULL, time);
g_return_val_if_fail (si->read_mode, time);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_TIME, time);
if (!(item = seek_to_record (si, id)))
return time;
if (!si->s->read_copy (si->s, data, 12))
return time;
type = MS_OLE_GET_GUINT32 (data);
low_time = MS_OLE_GET_GUINT32 (data + 4);
high_time = MS_OLE_GET_GUINT32 (data + 8);
if (type != TYPE_TIME) { /* Very odd */
// JPP g_warning ("Summary time type mismatch");
return time;
}
time.tv_sec = filetime_to_unixtime (low_time, high_time);
*available = TRUE;
return time;
}
/**
* ms_ole_summary_preview_destroy:
* @d: FIXME
*
* FIXME
**/
void
ms_ole_summary_preview_destroy (MsOleSummaryPreview d)
{
if (d.data)
g_free (d.data);
d.data = NULL;
}
/**
* ms_ole_summary_get_preview:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
MsOleSummaryPreview
ms_ole_summary_get_preview (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type;
MsOleSummaryPreview ans;
item_t *item;
ans.len = 0;
ans.data = NULL;
g_return_val_if_fail (available != NULL, ans);
*available = FALSE;
g_return_val_if_fail (si != NULL, ans);
g_return_val_if_fail (si->read_mode, ans);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_OTHER, ans);
if (!(item = seek_to_record (si, id)))
return ans;
if (!si->s->read_copy (si->s, data, 8))
return ans;
type = MS_OLE_GET_GUINT32 (data);
ans.len = MS_OLE_GET_GUINT32 (data + 4);
if (type != TYPE_PREVIEW) { /* Very odd */
// JPP g_warning ("Summary wmf type mismatch");
return ans;
}
ans.data = g_new (guint8, ans.len + 1);
if (!si->s->read_copy (si->s, ans.data, ans.len)) {
g_free (ans.data);
return ans;
}
*available = TRUE;
return ans;
}
static write_item_t *
write_item_t_new (MsOleSummary *si, MsOleSummaryPID id)
{
write_item_t *w = g_new (write_item_t, 1);
g_return_val_if_fail (si != NULL, NULL);
g_return_val_if_fail (!si->read_mode, NULL);
w->id = id;
w->len = 0;
w->data = NULL;
si->write_items = g_list_append (si->write_items, w);
return w;
}
/**
* ms_ole_summary_set_preview:
* @si: FIXME
* @id: FIXME
* @preview: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_preview (MsOleSummary *si, MsOleSummaryPID id,
const MsOleSummaryPreview *preview)
{
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
g_return_if_fail (preview != NULL);
w = write_item_t_new (si, id);
w->data = g_new (guint8, preview->len + 8);
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_PREVIEW);
MS_OLE_SET_GUINT32 (w->data + 4, preview->len);
memcpy (w->data + 8, preview->data, preview->len);
w->len = preview->len + 8;
}
/**
* ms_ole_summary_set_time:
* @si: FIXME
* @id: FIXME
* @time: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_time (MsOleSummary *si, MsOleSummaryPID id,
GTimeVal time)
{
unsigned int time_high;
unsigned int time_low;
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
w->data = g_new (guint8, 12);
w->len = 12;
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_TIME);
unixtime_to_filetime ((time_t)time.tv_sec, &time_high, &time_low);
MS_OLE_SET_GUINT32 (w->data + 4, time_low);
MS_OLE_SET_GUINT32 (w->data + 8, time_high);
}
/**
* ms_ole_summary_set_boolean:
* @si: FIXME
* @id: FIXME
* @bool: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_boolean (MsOleSummary *si, MsOleSummaryPID id,
gboolean value)
{
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
w->data = g_new (guint8, 8);
w->len = 6;
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_BOOLEAN);
MS_OLE_SET_GUINT16 (w->data + 4, value);
}
/**
* ms_ole_summary_set_short:
* @si: FIXME
* @id: FIXME
* @i: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_short (MsOleSummary *si, MsOleSummaryPID id,
guint16 i)
{
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
w->data = g_new (guint8, 8);
w->len = 6;
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_SHORT);
MS_OLE_SET_GUINT16 (w->data + 4, i);
}
/**
* ms_ole_summary_set_long:
* @si: FIXME
* @id: FIXME
* @i: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_long (MsOleSummary *si, MsOleSummaryPID id,
guint32 i)
{
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
w->data = g_new (guint8, 8);
w->len = 8;
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_LONG);
MS_OLE_SET_GUINT32 (w->data + 4, i);
}
/**
* ms_ole_summary_set_string:
* @si: FIXME
* @id: FIXME
* @str: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_string (MsOleSummary *si, MsOleSummaryPID id,
const gchar *str)
{
write_item_t *w;
guint32 len;
g_return_if_fail (si != NULL);
g_return_if_fail (str != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
len = strlen (str) + 1;
w->len = len + 8;
w->data = g_new (guint8, len + 8);
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_STRING);
MS_OLE_SET_GUINT32 (w->data + 4, len);
memcpy (w->data + 8, str, len);
}
--- Added File ms-ole-summary.h in package Packages/Products/DCProject ---
/**
* ms-ole-summary.h: MS Office OLE support
*
* Author:
* Michael Meeks (michael@imaginator.com)
* From work by:
* Caolan McNamara (Caolan.McNamara@ul.ie)
* Built on work by:
* Somar Software's CPPSUM (http://www.somar.com)
**/
#ifndef MS_OLE_SUMMARY_H
#define MS_OLE_SUMMARY_H
#include <time.h>
#include <ms-ole.h>
/*
* MS Ole Property Set IDs
* The SummaryInformation stream contains the SummaryInformation property set.
* The DocumentSummaryInformation stream contains both the
* DocumentSummaryInformation and the UserDefined property sets as sections.
*/
typedef enum {
MS_OLE_PS_SUMMARY_INFO,
MS_OLE_PS_DOCUMENT_SUMMARY_INFO,
MS_OLE_PS_USER_DEFINED_SUMMARY_INFO
} MsOlePropertySetID;
typedef struct {
guint8 class_id[16];
GArray * sections;
GArray * items;
GList * write_items;
gboolean read_mode;
MsOleStream * s;
MsOlePropertySetID ps_id;
} MsOleSummary;
/* Could store the FID, but why bother ? */
typedef struct {
guint32 offset;
guint32 props;
guint32 bytes;
MsOlePropertySetID ps_id;
} MsOleSummarySection;
MsOleSummary *ms_ole_summary_open (MsOle *f);
MsOleSummary *ms_ole_docsummary_open (MsOle *f);
MsOleSummary *ms_ole_summary_open_stream (MsOleStream *stream,
const MsOlePropertySetID psid);
MsOleSummary *ms_ole_summary_create (MsOle *f);
MsOleSummary *ms_ole_docsummary_create (MsOle *f);
MsOleSummary *ms_ole_summary_create_stream (MsOleStream *s,
const MsOlePropertySetID psid);
GArray *ms_ole_summary_get_properties (MsOleSummary *si);
void ms_ole_summary_close (MsOleSummary *si);
/*
* Can be used to interrogate a summary item as to its type
*/
typedef enum {
MS_OLE_SUMMARY_TYPE_STRING = 0x10,
MS_OLE_SUMMARY_TYPE_TIME = 0x20,
MS_OLE_SUMMARY_TYPE_LONG = 0x30,
MS_OLE_SUMMARY_TYPE_SHORT = 0x40,
MS_OLE_SUMMARY_TYPE_BOOLEAN = 0x50,
MS_OLE_SUMMARY_TYPE_OTHER = 0x60
} MsOleSummaryType;
#define MS_OLE_SUMMARY_TYPE(x) ((MsOleSummaryType)((x)>>8))
/* FIXME MS_OLE_SUMMARY_THUMBNAIL is Preview, no Security, isn't it? */
/*
* The MS byte specifies the type, the LS byte is the
* 'standard' MS PID.
*/
typedef enum {
/* SummaryInformation Stream Properties */
/* String properties */
MS_OLE_SUMMARY_TITLE = 0x1002,
MS_OLE_SUMMARY_SUBJECT = 0x1003,
MS_OLE_SUMMARY_AUTHOR = 0x1004,
MS_OLE_SUMMARY_KEYWORDS = 0x1005,
MS_OLE_SUMMARY_COMMENTS = 0x1006,
MS_OLE_SUMMARY_TEMPLATE = 0x1007,
MS_OLE_SUMMARY_LASTAUTHOR = 0x1008,
MS_OLE_SUMMARY_REVNUMBER = 0x1009,
MS_OLE_SUMMARY_APPNAME = 0x1012,
/* Time properties */
MS_OLE_SUMMARY_TOTAL_EDITTIME = 0x200A,
MS_OLE_SUMMARY_LASTPRINTED = 0x200B,
MS_OLE_SUMMARY_CREATED = 0x200C,
MS_OLE_SUMMARY_LASTSAVED = 0x200D,
/* Long integer properties */
MS_OLE_SUMMARY_PAGECOUNT = 0x300E,
MS_OLE_SUMMARY_WORDCOUNT = 0x300F,
MS_OLE_SUMMARY_CHARCOUNT = 0x3010,
MS_OLE_SUMMARY_SECURITY = 0x3013,
/* Short integer properties */
MS_OLE_SUMMARY_CODEPAGE = 0x4001,
/* Security */
MS_OLE_SUMMARY_THUMBNAIL = 0x6011,
/* DocumentSummaryInformation Properties */
/* String properties */
MS_OLE_SUMMARY_CATEGORY = 0x1002,
MS_OLE_SUMMARY_PRESFORMAT = 0x1003,
MS_OLE_SUMMARY_MANAGER = 0x100E,
MS_OLE_SUMMARY_COMPANY = 0x100F,
/* Long integer properties */
MS_OLE_SUMMARY_BYTECOUNT = 0x3004,
MS_OLE_SUMMARY_LINECOUNT = 0x3005,
MS_OLE_SUMMARY_PARCOUNT = 0x3006,
MS_OLE_SUMMARY_SLIDECOUNT = 0x3007,
MS_OLE_SUMMARY_NOTECOUNT = 0x3008,
MS_OLE_SUMMARY_HIDDENCOUNT = 0x3009,
MS_OLE_SUMMARY_MMCLIPCOUNT = 0X300A,
/* Boolean properties */
MS_OLE_SUMMARY_SCALE = 0x500B,
MS_OLE_SUMMARY_LINKSDIRTY = 0x5010
} MsOleSummaryPID;
/* bit masks for security long integer */
#define MsOleSummaryAllSecurityFlagsEqNone 0x00
#define MsOleSummarySecurityPassworded 0x01
#define MsOleSummarySecurityRORecommended 0x02
#define MsOleSummarySecurityRO 0x04
#define MsOleSummarySecurityLockedForAnnotations 0x08
typedef struct {
GTimeVal time;
GDate date;
} MsOleSummaryTime;
typedef struct {
guint32 len;
guint8 *data;
} MsOleSummaryPreview;
gchar * ms_ole_summary_get_string (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
gboolean ms_ole_summary_get_boolean (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
guint16 ms_ole_summary_get_short (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
guint32 ms_ole_summary_get_long (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
GTimeVal ms_ole_summary_get_time (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
MsOleSummaryPreview ms_ole_summary_get_preview (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
void ms_ole_summary_preview_destroy (MsOleSummaryPreview d);
/* FIXME The next comment isn't true, is it?
Return TRUE if write is successful */
void ms_ole_summary_set_string (MsOleSummary *si,
MsOleSummaryPID id,
const gchar *str);
void ms_ole_summary_set_boolean (MsOleSummary *si,
MsOleSummaryPID id,
gboolean value);
void ms_ole_summary_set_short (MsOleSummary *si,
MsOleSummaryPID id,
guint16 i);
void ms_ole_summary_set_long (MsOleSummary *si,
MsOleSummaryPID id,
guint32 i);
void ms_ole_summary_set_time (MsOleSummary *si,
MsOleSummaryPID id,
GTimeVal time);
void ms_ole_summary_set_preview (MsOleSummary *si,
MsOleSummaryPID id,
const
MsOleSummaryPreview *
preview);
#endif /* MS_OLE_SUMMARY_H */
--- Added File ms-ole-vba.c in package Packages/Products/DCProject ---
/**
* ms-ole-vba.c: MS Office VBA support
*
* Author:
* Michael Meeks (michael@imaginator.com)
*
* Copyright 2000 Helix Code, Inc.
**/
#include <config.h>
#include <stdio.h>
#include <ms-ole-vba.h>
#undef VBA_DEBUG
struct _MsOleVba {
MsOleStream *s;
GArray *text;
int pos;
};
inline gboolean
ms_ole_vba_eof (MsOleVba *vba)
{
return !vba || (vba->pos >= vba->text->len - 1);
}
char
ms_ole_vba_getc (MsOleVba *vba)
{
g_assert (!ms_ole_vba_eof (vba));
return g_array_index (vba->text, guint8, vba->pos++);
}
char
ms_ole_vba_peek (MsOleVba *vba)
{
g_assert (!ms_ole_vba_eof (vba));
return g_array_index (vba->text, guint8, vba->pos);
}
#if VBA_DEBUG > 1
static void
print_bin (guint16 dt)
{
int i;
printf ("|");
for (i = 15; i >= 0; i--) {
if (dt & (1 << i))
printf ("1");
else
printf ("0");
if (i == 8)
printf ("|");
}
printf ("|");
}
#endif
/**
* decompress_vba
* @vba Place to store the uncompressed VBA
* @data Pointer to start of compressed VBA
* @eos lwa+1 of stream
*
* Purpose: lzw, arc like compression.
*
* Internal function.
**/
static void
decompress_vba (MsOleVba *vba, guint8 *data, guint8 *eos)
{
#define BUF_SIZE 6144 /* a bottleneck */
guint8 buffer[BUF_SIZE];
guint8 *ptr;
guint8 *sptr;
guint32 len;
guint32 pos;
GArray *ans = g_array_new (FALSE, FALSE, 1);
vba->text = ans;
vba->pos = 0;
len = MS_OLE_GET_GUINT16 (data + 1);
#if VBA_DEBUG > 0
printf ("Length 0x%x\n", len);
#endif
len = (len & ~0xb000) + 1;
ptr = data + 3;
sptr = ptr;
pos = 0;
while (ptr < eos) {
#if VBA_DEBUG > 0
printf ("My compressed stream (addr=%#x, len = %#x (%d)):\n",
ptr - data, len, len);
ms_ole_dump (ptr, len);
#endif
while ((ptr < sptr + len) && (ptr < eos)) {
int shift;
guint8 flag_byte = *ptr++;
/*
* The first byte is a flag byte. Each bit in this byte
* determines what the next byte is. If the bit is zero,
* the next byte is a character. Otherwise the next two
* bytes contain the number of characters to copy from the
* umcompresed buffer and where to copy them from (offset,
* length).
*/
for (shift = 0x01; shift < 0x100; shift = shift << 1) {
if (ptr >= sptr + len)
break;
if (pos == BUF_SIZE) {
#if VBA_DEBUG > 0
printf ("\nSomething extremely odd"
" happens after %d bytes 0x%x\n\n",
BUF_SIZE, MS_OLE_GET_GUINT16 (ptr));
ms_ole_dump (ptr, len - (ptr - data));
#endif
ptr += 2;
flag_byte = *ptr++;
pos = 0;
shift = 0x01;
}
if (flag_byte & shift) {
int i;
int back;
int clen;
int shft;
guint16 dt = MS_OLE_GET_GUINT16 (ptr);
if (pos <= 16)
shft = 12;
else if (pos <= 32)
shft = 11;
else if (pos <= 64)
shft = 10;
else if (pos <= 128)
shft = 9;
else if (pos <= 256)
shft = 8;
else if (pos <= 512)
shft = 7;
else if (pos <= 1024)
shft = 6;
else if (pos <= 2048)
shft = 5;
else
shft = 4;
back = (dt >> shft) + 1;
clen = 0;
for (i = 0; i < shft; i++)
clen |= dt & (0x1 << i);
clen += 3;
#if VBA_DEBUG > 1
printf ("|match 0x%x (%d,%d) >> %d = %d, %d| pos = %d |\n",
dt, (dt>>8), (dt&0xff), shft, back, clen, pos);
/* Perhaps dt & SHIFT = dist. to end of run */
print_bin (dt);
printf ("\n");
#endif
for (i = 0; i < clen; i++) {
guint8 c;
guint32 srcpos = (BUF_SIZE + (pos%BUF_SIZE)) -
back;
if (srcpos >= BUF_SIZE)
srcpos-= BUF_SIZE;
g_assert (srcpos >= 0);
g_assert (srcpos < BUF_SIZE);
c = buffer [srcpos];
buffer [pos++ % BUF_SIZE] = c;
g_array_append_val (ans, c);
#if VBA_DEBUG > 0
printf ("%c", c);
#endif
}
ptr += 2;
} else {
buffer [pos++ % BUF_SIZE] = *ptr;
g_array_append_val (ans, *ptr);
#if VBA_DEBUG > 0
printf ("%c", *ptr);
#endif
ptr++;
}
if ((ptr >= sptr + len) || (ptr >= eos)) {
if ((ptr >= sptr + len) && (ptr < eos)) {
#if VBA_DEBUG > 0
printf ("Reseting ptr.\n");
printf ("ptr was %#x\n",
ptr - sptr);
printf ("ptr is %#x\n",
len);
#endif
ptr = sptr + len;
}
break;
}
} /* for (shift = 0x01; shift < 0x100; shift = shift << 1) */
} /* while ((ptr < sptr + len) && (ptr < eos)) */
#if VBA_DEBUG > 0
printf ("ptr = %#X\n", ptr-sptr);
#endif
if ((ptr + 3) < eos) {
len = MS_OLE_GET_GUINT16 (ptr);
len = (len & ~0xb000) + 1;
ptr += 2;
sptr = ptr;
pos = 0;
}
} /* while (ptr < eos) */
{
char c;
c = '\n';
g_array_append_val (ans, c);
c = '\0';
g_array_append_val (ans, c);
}
}
static guint8 *
seek_sig (guint8 *data, int len)
{
int i;
guint8 vba_sig[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1, 0x1 };
for (i = 0; i < len; i++) {
guint8 *p = data;
int j;
for (j = 0; j < sizeof (vba_sig); j++) {
if (*p++ != vba_sig [j])
break;
}
if (j == sizeof (vba_sig))
return p;
data++;
}
return NULL;
}
static guint8 *
find_compressed_vba (guint8 *data, MsOlePos len)
{
guint8 *sig;
guint32 offset;
guint32 offpos;
if (!(sig = seek_sig (data, len))) {
g_warning ("No VBA kludge signature");
return NULL;
}
offpos = MS_OLE_GET_GUINT32 (sig) + 0xd0 - 0x6b - 0x8;
#if VBA_DEBUG > 0
printf ("Offpos : 0x%x -> \n", offpos);
#endif
offset = MS_OLE_GET_GUINT32 (sig + offpos);
if (len < offset + 3) {
g_warning ("Too small for offset 0x%x\n", offset);
return NULL;
}
#if VBA_DEBUG > 0
printf ("Offset is 0x%x\n", offset);
#endif
return data + offset;
}
/**
* ms_ole_vba_open:
* @s: the stream pointer.
*
* Attempt to open a stream as a VBA stream, and commence
* decompression of it.
*
* Return value: NULL if not a VBA stream or fails.
**/
MsOleVba *
ms_ole_vba_open (MsOleStream *s)
{
const guint8 gid [16] = { 0x1, 0x16, 0x1, 0x0,
0x6, 0xb6, 0x0, 0xff,
0xff, 0x1, 0x1, 0x0,
0x0, 0x0, 0x0, 0xff };
int i;
int j;
int len;
guint8 *data, *vba_data;
guint8 sig [16];
MsOleVba *vba;
g_return_val_if_fail (s != NULL, NULL);
if (s->size < 16)
return NULL;
s->lseek (s, 0, MsOleSeekSet);
s->read_copy (s, sig, 16);
for (i = 0; i < 16; i++)
if (sig [i] != gid [i]) {
/*
* Version ??
*/
if (i == 4)
if (sig [i] == 0x4 )
continue;
return NULL;
}
data = g_new (guint8, s->size);
s->lseek (s, 0, MsOleSeekSet);
if (!s->read_copy (s, data, s->size)) {
g_warning ("Strange: failed read");
g_free (data);
return NULL;
}
if (!(vba_data = find_compressed_vba (data, s->size))) {
g_free (data);
return NULL;
}
if (MS_OLE_GET_GUINT8 (vba_data) != 1)
g_warning ("Digit 0x%x != 1...", MS_OLE_GET_GUINT8 (vba_data));
vba = g_new0 (MsOleVba, 1);
vba->s = s;
vba->pos = 0;
decompress_vba (vba, vba_data, data + s->size);
g_free (data);
return vba;
}
/**
* me_ols_vba_close:
* @vba:
*
* Free the resources associated with this vba
* stream.
**/
void
ms_ole_vba_close (MsOleVba *vba)
{
if (vba) {
g_array_free (vba->text, TRUE);
vba->text = NULL;
g_free (vba);
}
}
--- Added File ms-ole-vba.h in package Packages/Products/DCProject ---
/**
* ms-ole-vba.h: MS Office VBA support
*
* Author:
* Michael Meeks (michael@imaginator.com)
*
* Copyright 2000 Helix Code, Inc.
**/
#ifndef MS_OLE_VBA_H
#define MS_OLE_VBA_H
#include <ms-ole.h>
typedef struct _MsOleVba MsOleVba;
MsOleVba *ms_ole_vba_open (MsOleStream *s);
void ms_ole_vba_close (MsOleVba *vba);
char ms_ole_vba_getc (MsOleVba *vba);
char ms_ole_vba_peek (MsOleVba *vba);
gboolean ms_ole_vba_eof (MsOleVba *vba);
#endif
--- Added File ms-ole.c in package Packages/Products/DCProject ---
/**
* ms-ole.c: MS Office OLE support for Gnumeric
*
* Authors:
* Michael Meeks (michael@imaginator.com)
* Arturo Tena (arturo@directmail.org)
**/
#include <stdio.h>
/* BSDs require unistd.h before including stat.h */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h> /* for struct stat */
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <glib.h>
#include <string.h>
#include <ms-ole.h>
#include "config.h"
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#else
# include <io.h>
# include <sys/stat.h>
# include <sys/types.h>
/*
# define S_IRUSR 0000400
# define S_IWUSR 0000200
# define S_IRGRP 0000040
# define S_IWGRP 0000020
# define _S_ISREG(m) (((m)&0170000) == 0100000)
# define S_ISREG(m) _S_ISREG(m)
# define O_NONBLOCK 0x4000
*/
#endif
#ifndef MAP_FAILED
/* Someone needs their head examining - BSD ? */
# define MAP_FAILED ((void *)-1)
#endif
/* Implementational detail - not for global header */
#define OLE_DEBUG 0
/* FIXME tenix add ADD_BBD_LIST_BLOCK where it should be used) */
#define ADD_BBD_LIST_BLOCK 0xfffffffc /* -4 */
#define SPECIAL_BLOCK 0xfffffffd /* -3 (BBD_LIST BLOCK) */
#define END_OF_CHAIN 0xfffffffe /* -2 */
#define UNUSED_BLOCK 0xffffffff /* -1 */
/* FIXME tenix laola reads this from the header */
#define BB_BLOCK_SIZE 512
#define SB_BLOCK_SIZE 64
/* FIXME tenix laola understand the next header:
MAGIC => undef, # 00
CLSID => undef, # guid 08
REVISION => undef, # word 18
VERSION => undef, # word 1a
BYTEORDER => undef, # word 1c
B_S_LOG => undef, # word 1e big block size = 2^b_s_log
S_S_LOG => undef, # word 20 small block size = 2^s_s_log
UK1 => undef, # word(5) 22
B_D_NUM => undef, # long 2c bbd num of blocks
ROOT_SB => undef, # long 30 root start block
UK2 => undef, # long 34
B_S_MIN => undef, # long 38 minimum size of big_block
S_D_SB => undef, # long 3c sbd start block
S_D_NUM => undef, # long 40 number of sbd blocks
B_XD_SB => undef, # long 44
B_XD_NUM => undef, # long 48
*/
MsOle *jp_msOle;
/**
* Structure describing an OLE file
**/
struct _MsOle
{
int ref_count;
gboolean ole_mmap;
guint8 *mem;
guint32 length;
MsOleSysWrappers *syswrap;
char mode;
int file_des;
int dirty;
GArray *bb; /* Big blocks status */
GArray *sb; /* Small block status */
GArray *sbf; /* The small block file */
guint32 num_pps; /* Count of number of property sets */
GList *pps; /* Property Storage -> struct _PPS, always 1 valid entry or NULL */
/* if memory mapped */
GPtrArray *bbattr; /* Pointers to block structures */
/* end if memory mapped */
unsigned char *buf;
size_t len;
size_t idx;
};
/**
* Default system calls wrappers
**/
static int
open2_wrap (const char *pathname, int flags)
{
return open (pathname, flags);
}
static int
open3_wrap (const char *pathname, int flags, mode_t mode)
{
return open (pathname, flags, mode);
}
static ssize_t
read_wrap (int fd, void *buf, size_t count)
{
// printf(":read_wrap:\n");
return read (fd, buf, count);
}
static int
close_wrap (int fd)
{
return close (fd);
}
static ssize_t
write_wrap (int fd, const void *buf, size_t count)
{
return write (fd, buf, count);
}
static off_t
lseek_wrap (int fd, off_t offset, int whence)
{
return lseek (fd, offset, whence);
}
static int
isregfile_wrap (int fd)
{
struct stat st;
if (fstat (fd, &st))
return 0;
return S_ISREG(st.st_mode);
}
static int
getfilesize_wrap (int fd, guint32 *size)
{
struct stat st;
if (fstat (fd, &st))
return -1;
*size = st.st_size;
return 0;
}
static MsOleSysWrappers default_wrappers = {
open2_wrap,
open3_wrap,
read_wrap,
close_wrap,
write_wrap,
lseek_wrap,
isregfile_wrap,
getfilesize_wrap
};
//----------------------------------------------------------------------------//
static int open2_wrap_body (const char *pathname, int flags)
{
int fd;
fd = 3;
return fd;
}
//----------------------------------------------------------------------------//
static int open3_wrap_body (const char *pathname, int flags, mode_t mode)
{
int fd;
fd = 3;
return fd;
}
//----------------------------------------------------------------------------//
static ssize_t read_wrap_body (int fd, void *buf, size_t count)
{
ssize_t temp;
// printf(":read_wrap_body:\n");
temp = count;
memcpy(buf, &(jp_msOle->buf[jp_msOle->idx]), count);
jp_msOle->idx = jp_msOle->idx +count;
return temp;
}
//----------------------------------------------------------------------------//
static int close_wrap_body (int fd)
{
int result;
result = 0;
return result;
}
//----------------------------------------------------------------------------//
static ssize_t write_wrap_body (int fd, const void *buf, size_t count)
{
ssize_t temp;
temp = write(fd, buf, count);
return temp;
}
//----------------------------------------------------------------------------//
static off_t lseek_wrap_body (int fd, off_t offset, int whence)
{
off_t temp;
temp = offset;
jp_msOle->idx = offset;
return temp;
}
//----------------------------------------------------------------------------//
static int isregfile_wrap_body (int fd)
{
int result;
struct stat st;
result = 1;
return result;
}
//----------------------------------------------------------------------------//
static int getfilesize_wrap_body (int fd, guint32 *size)
{
int result;
struct stat st;
result = jp_msOle->len;
*size = result;
return 0;
}
//----------------------------------------------------------------------------//
static MsOleSysWrappers default_wrappers_body =
{
open2_wrap_body,
open3_wrap_body,
read_wrap_body,
close_wrap_body,
write_wrap_body,
lseek_wrap_body,
isregfile_wrap_body,
getfilesize_wrap_body
};
//----------------------------------------------------------------------------//
static void
take_wrapper_functions (MsOle *f, MsOleSysWrappers *wrappers) {
if (wrappers == NULL)
f->syswrap = &default_wrappers;
else
f->syswrap = wrappers;
}
/*
* A global variable to enable calles to check_stream,
* applications should optionally enable due to the performance penalty.
* of 30-50 % of load time.
*/
gboolean libole2_debug = FALSE;
typedef guint32 PPS_IDX ;
#if OLE_DEBUG > 0
/* Very grim, but quite necessary */
# define ms_array_index(a,b,c) (b)my_array_hack ((a), sizeof(b), (c))
static guint32
my_array_hack (GArray *a, guint s, guint32 idx)
{
g_assert (a != NULL);
g_assert (idx >= 0);
g_assert (idx < a->len);
g_assert (s == 4);
return ((guint32 *)a->data)[idx];
}
#else
/* Far far faster... */
# define ms_array_index(a,b,c) g_array_index (a, b, c)
#endif
typedef guint32 BLP; /* Block pointer */
#define BB_THRESHOLD 0x1000
#define PPS_ROOT_INDEX 0
#define PPS_BLOCK_SIZE 0x80
#define PPS_END_OF_CHAIN 0xffffffff
typedef struct _PPS PPS;
#define PPS_SIG 0x13579753
#define IS_PPS(p) (((PPS *)(p))->sig == PPS_SIG)
struct _PPS {
int sig;
char *name;
GList *children;
PPS *parent;
guint32 size;
BLP start;
MsOleType type;
PPS_IDX idx; /* Only used on write */
};
#define BB_R_PTR(f,b) ((f)->ole_mmap ? ((f)->mem + (b+1)*BB_BLOCK_SIZE) : \
(get_block_ptr (f, b, FALSE)))
#define BB_W_PTR(f,b) ((f)->ole_mmap ? BB_R_PTR(f,b) : \
(get_block_ptr (f, b, TRUE)))
#define GET_SB_R_PTR(f,b) (BB_R_PTR(f, g_array_index ((f)->sbf, BLP, (b)/(BB_BLOCK_SIZE/SB_BLOCK_SIZE))) \
+ (((b)%(BB_BLOCK_SIZE/SB_BLOCK_SIZE))*SB_BLOCK_SIZE))
#define GET_SB_W_PTR(f,b) (BB_W_PTR(f, g_array_index ((f)->sbf, BLP, (b)/(BB_BLOCK_SIZE/SB_BLOCK_SIZE))) \
+ (((b)%(BB_BLOCK_SIZE/SB_BLOCK_SIZE))*SB_BLOCK_SIZE))
#define MAX_CACHED_BLOCKS 32
typedef struct {
guint32 blk;
gboolean dirty;
int usage;
guint8 *data;
} BBBlkAttr;
static BBBlkAttr *
bb_blk_attr_new (guint32 blk)
{
BBBlkAttr *attr = g_new (BBBlkAttr, 1);
attr->blk = blk;
attr->dirty = FALSE;
attr->usage = 0;
attr->data = 0;
return attr;
}
static void
write_cache_block (MsOle *f, BBBlkAttr *attr)
{
size_t offset;
g_return_if_fail (f);
g_return_if_fail (attr);
g_return_if_fail (attr->data);
offset = (attr->blk+1)*BB_BLOCK_SIZE;
if (f->syswrap->lseek (f->file_des, offset, SEEK_SET)==(off_t)-1 ||
f->syswrap->write (f->file_des, attr->data, BB_BLOCK_SIZE) == -1)
printf ("Fatal error writing block %d at %d\n", attr->blk, offset);
#if OLE_DEBUG > 0
printf ("Writing cache block %d to offset %d\n",
attr->blk, offset);
#endif
attr->dirty = FALSE;
}
static guint8 *
get_block_ptr (MsOle *f, BLP b, gboolean forwrite)
{
BBBlkAttr *attr, *tmp, *min;
size_t offset;
guint32 i, blks;
g_assert (f);
g_assert (b < f->bbattr->len);
/* Have we cached it ? */
attr = g_ptr_array_index (f->bbattr, b);
g_assert (attr);
g_assert (attr->blk == b);
if (attr->data) {
attr->usage++;
if (forwrite)
attr->dirty = TRUE;
return attr->data;
}
/* LRU strategy */
min = NULL;
blks = 0;
for (i=0;i<f->bbattr->len;i++) {
tmp = g_ptr_array_index (f->bbattr, i);
if (tmp->data) {
blks++;
if (!min)
min = tmp;
else if (tmp->usage < min->usage)
min = tmp;
}
tmp->usage = (guint32)tmp->usage*0.707;
}
if (blks < MAX_CACHED_BLOCKS)
min = 0;
g_assert (!attr->data);
if (min) {
g_assert (min->data);
#if OLE_DEBUG > 0
printf ("Replacing cache block %d with %d\n", min->blk, b);
#endif
if (min->dirty)
write_cache_block (f, min);
attr->data = min->data;
min->data = 0;
min->usage = 0;
} else
attr->data = g_new (guint8, BB_BLOCK_SIZE);
offset = (b+1)*BB_BLOCK_SIZE;
f->syswrap->lseek (f->file_des, offset, SEEK_SET);
f->syswrap->read (f->file_des, attr->data, BB_BLOCK_SIZE);
attr->usage = 1;
attr->dirty = forwrite;
return attr->data;
}
/* This is a list of big blocks which contain a flat description of all blocks
in the file. Effectively inside these blocks is a FAT of chains of other BBs,
so the theoretical max size = 128 BB Fat blocks, thus = 128*512*512/4 blocks
~= 8.4MBytes */
/* FIXME tenix the max size would actually be 109*512*512/4 + 512 blocks ~=
7MBytes if we don't take in count the additional Big Block Depot lists.
Number of additional lists is in header:0x48, the location of the first
additional list is in header:0x44, the location of the second additional
list is at the very end of the first additional list and so on, the last
additional list have at the end a END_OF_CHAIN.
Each additional list can address 128*512/4*512 blocks ~= 8MBytes */
/* The number of Big Block Descriptor (fat) Blocks */
#define GET_NUM_BBD_BLOCKS(f) (MS_OLE_GET_GUINT32((f)->mem + 0x2c))
#define SET_NUM_BBD_BLOCKS(f,n) (MS_OLE_SET_GUINT32((f)->mem + 0x2c, (n)))
/* The block locations of the Big Block Descriptor Blocks */
#define MAX_SIZE_BBD_LIST 109
/* FIXME tenix next is broken with big files */
#define GET_BBD_LIST(f,i) (MS_OLE_GET_GUINT32((f)->mem + 0x4c + (i)*4))
/* FIXME tenix next is broken with big files */
#define SET_BBD_LIST(f,i,n) (MS_OLE_SET_GUINT32((f)->mem + 0x4c + (i)*4, (n)))
#define NEXT_BB(f,n) (g_array_index ((f)->bb, BLP, n))
#define NEXT_SB(f,n) (g_array_index ((f)->sb, BLP, n))
/* Additional Big Block Descriptor (fat) Blocks */
#define MAX_SIZE_ADD_BBD_LIST 127
#define GET_NUM_ADD_BBD_LISTS(f) (MS_OLE_GET_GUINT32((f)->mem + 0x48))
#define GET_FIRST_ADD_BBD_LIST(f) (MS_OLE_GET_GUINT32((f)->mem + 0x44))
/* Get the start block of the root directory ( PPS ) chain */
#define GET_ROOT_STARTBLOCK(f) (MS_OLE_GET_GUINT32((f)->mem + 0x30))
#define SET_ROOT_STARTBLOCK(f,i) (MS_OLE_SET_GUINT32((f)->mem + 0x30, i))
/* Get the start block of the SBD chain */
#define GET_SBD_STARTBLOCK(f) (MS_OLE_GET_GUINT32((f)->mem + 0x3c))
#define SET_SBD_STARTBLOCK(f,i) (MS_OLE_SET_GUINT32((f)->mem + 0x3c, i))
/* NB it is misleading to assume that Microsofts linked lists link correctly.
It is not the case that pps_next(f, pps_prev(f, n)) = n ! For the final list
item there are no valid links. Cretins. */
#define PPS_GET_NAME_LEN(p) (MS_OLE_GET_GUINT16(p + 0x40))
#define PPS_SET_NAME_LEN(p,i) (MS_OLE_SET_GUINT16(p + 0x40, (i)))
#define PPS_GET_PREV(p) ((PPS_IDX) MS_OLE_GET_GUINT32(p + 0x44))
#define PPS_GET_NEXT(p) ((PPS_IDX) MS_OLE_GET_GUINT32(p + 0x48))
#define PPS_GET_DIR(p) ((PPS_IDX) MS_OLE_GET_GUINT32(p + 0x4c))
#define PPS_SET_PREV(p,i) ((PPS_IDX) MS_OLE_SET_GUINT32(p + 0x44, i))
#define PPS_SET_NEXT(p,i) ((PPS_IDX) MS_OLE_SET_GUINT32(p + 0x48, i))
#define PPS_SET_DIR(p,i) ((PPS_IDX) MS_OLE_SET_GUINT32(p + 0x4c, i))
/* These get other interesting stuff from the PPS record */
#define PPS_GET_STARTBLOCK(p) ( MS_OLE_GET_GUINT32(p + 0x74))
#define PPS_GET_SIZE(p) ( MS_OLE_GET_GUINT32(p + 0x78))
#define PPS_GET_TYPE(p) ((MsOleType)( MS_OLE_GET_GUINT8(p + 0x42)))
#define PPS_SET_STARTBLOCK(p,i) ( MS_OLE_SET_GUINT32(p + 0x74, i))
#define PPS_SET_SIZE(p,i) ( MS_OLE_SET_GUINT32(p + 0x78, i))
#define PPS_SET_TYPE(p,i) ( MS_OLE_SET_GUINT8 (p + 0x42, i))
/* Try to mark the Big Block "b" as as unused if it is marked as "c", in the
FAT "f". */
#define TRY_MARK_UNUSED_BLOCK(f,block,mark) { \
if (g_array_index ((f), BLP, (block)) != (mark)) { \
g_warning ("Tried to mark as unused the block %d which has %d\n", \
(block), g_array_index ((f), BLP, (block))); \
} else { g_array_index ((f), BLP, (block)) = UNUSED_BLOCK; } }
/* FIXME: This needs proper unicode support ! current support is a guess */
/* Length is in bytes == 1/2 the final text length */
/* NB. Different from biff_get_text, looks like a bug ! */
static char *
pps_get_text (guint8 *ptr, int length)
{
int lp;
char *ans;
guint16 c;
guint8 *inb;
length = (length+1)/2;
if (length <= 0 ||
length > (PPS_BLOCK_SIZE/4)) {
#if OLE_DEBUG > 0
printf ("Nulled name of length %d\n", length);
#endif
return 0;
}
ans = (char *) g_malloc (sizeof (char) * length + 1);
inb = ptr;
for (lp = 0; lp < length; lp++) {
c = MS_OLE_GET_GUINT16 (inb);
ans [lp] = (char) c;
inb += 2;
}
ans [lp] = 0;
return ans;
}
static void
dump_header (MsOle *f)
{
printf ("--------------------------MsOle HEADER-------------------------\n");
printf ("Num BBD Blocks : %d Root %%d, SB blocks %d\n",
f->bb?f->bb->len:-1,
/* f->pps?f->pps->len:-1, */
/* FIXME tenix, here is not f->num_pps? */
f->sb?f->sb->len:-1);
printf ("-------------------------------------------------------------\n");
}
static void
characterise_block (MsOle *f, BLP blk, char **ans)
{
int nblk;
nblk = g_array_index (f->bb, BLP, blk);
if (nblk == UNUSED_BLOCK) {
*ans = "unused";
return;
} else if (nblk == SPECIAL_BLOCK) {
*ans = "special";
return;
} else if (nblk == ADD_BBD_LIST_BLOCK) {
*ans = "additional special";
return;
} else if (nblk == END_OF_CHAIN) {
*ans = "end of chain";
return;
}
*ans = "unknown";
g_return_if_fail (f);
g_return_if_fail (f->bb);
g_return_if_fail (f->pps);
/* for (lp=0;lp<f->pps->len;lp++) {
PPS *p = g_ptr_array_index (f->pps, lp);
BLP cur = p->start;
while (cur != END_OF_CHAIN) {
if (cur == SPECIAL_BLOCK ||
cur == UNUSED_BLOCK) {
*ans = "serious block error";
return;
}
if (cur == blk) {
*ans = p->name;
return;
}
cur = NEXT_BB (f, cur);
}
}*/
}
static void
dump_tree (GList *list, int indent)
{
PPS *p;
int lp;
char indentstr[64];
g_return_if_fail (indent<60);
for (lp=0;lp<indent;lp++)
indentstr[lp]= '-';
indentstr[lp]=0;
while (list) {
p = list->data;
if (p) {
printf ("%s '%s' (size: %d)\n",
indentstr, p->name, p->size);
if (p->children)
dump_tree (p->children, indent+1);
} else
printf ("%s NULL!\n", indentstr);
list = g_list_next (list);
}
}
static void
dump_allocation (MsOle *f)
{
int lp;
char *blktype;
for (lp=0;lp<f->bb->len;lp++) {
characterise_block (f, lp, &blktype);
printf ("Block %d -> block %d ( '%s' )\n", lp,
g_array_index (f->bb, BLP, lp),
blktype);
}
if (f->pps) {
printf ("Root blocks : %d\n", f->num_pps);
dump_tree (f->pps, 0);
} else
printf ("No root yet\n");
/*
printf ("sbd blocks : %d\n", h->sbd_list->len);
for (lp=0;lp<h->sbd_list->len;lp++)
printf ("sbd_list[%d] = %d\n", lp, (int)ms_array_index (h->sbd_list, SBPtr, lp));*/
printf ("-------------------------------------------------------------\n");
}
/*
* Dump some useful facts.
* magic: 2 : dump tree
* default : dump header and allocation
*/
void
ms_ole_debug (MsOle *fs, int magic)
{
switch (magic) {
case 2:
if (fs->pps)
dump_tree (fs->pps, 0);
else
printf ("There are no tree (no pps)\n");
break;
default:
dump_header (fs);
dump_allocation (fs);
break;
}
}
/*
* get_next_block:
* @f: the file handle
* @blk: an index into the big block fat
*
* Return value: the block index of the BBD block.
*/
static BLP
get_next_block (MsOle *f, BLP blk, gboolean *err)
{
BLP bbd = GET_BBD_LIST (f, blk / (BB_BLOCK_SIZE / 4));
if (bbd > (f->length / BB_BLOCK_SIZE)) {
*err = TRUE;
return 0;
} else
*err = FALSE;
return MS_OLE_GET_GUINT32 (BB_R_PTR (f, bbd) +
4 * (blk % (BB_BLOCK_SIZE / 4)));
}
/* Builds the FAT */
static int
read_bb (MsOle *f)
{
/* FIXME tenix may be later we wish to split this function */
guint32 numbbd;
BLP lp;
guint32 num_add_bbd_lists;
BLP missing_lps;
BLP missing_bbds;
guint32 visited_add_bbd_list;
BLP tmp;
BLP bbd;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->mem, 0);
f->bb = g_array_new (FALSE, FALSE, sizeof(BLP));
numbbd = GET_NUM_BBD_BLOCKS (f);
/* Sanity checks */
/* FIXME tenix reading big files
if (numbbd < ((f->length - BB_BLOCK_SIZE
+ ((BB_BLOCK_SIZE*BB_BLOCK_SIZE)/4) - 1)
/ ((BB_BLOCK_SIZE*BB_BLOCK_SIZE)/4))) {
printf ("Duff block descriptors\n");
return 0;
}
*/
/* FIXME tenix check if size is small, there's no add bbd lists */
/* Add BBD's that live in the BBD list */
for (lp = 0; (lp < (f->length / BB_BLOCK_SIZE) - 1) &&
(lp < MAX_SIZE_BBD_LIST * BB_BLOCK_SIZE / 4); lp++) {
gboolean err;
tmp = get_next_block (f, lp, &err);
if (err)
return 0;
g_array_append_val (f->bb, tmp);
}
/* Add BBD's that live in the additional BBD lists */
num_add_bbd_lists = GET_NUM_ADD_BBD_LISTS (f);
if (num_add_bbd_lists > 0) {
if (lp != MAX_SIZE_BBD_LIST * BB_BLOCK_SIZE / 4)
return 0;
visited_add_bbd_list = GET_FIRST_ADD_BBD_LIST (f);
missing_lps = (f->length/BB_BLOCK_SIZE) - 1
- MAX_SIZE_BBD_LIST*BB_BLOCK_SIZE/4;
for (lp = 0; lp < missing_lps; lp++) {
if ((lp!=0) && !(lp%(MAX_SIZE_ADD_BBD_LIST*
(BB_BLOCK_SIZE/4)))) {
/* This lp lives in the next add bbd list */
visited_add_bbd_list = MS_OLE_GET_GUINT32(
BB_R_PTR(f,visited_add_bbd_list)
+4*MAX_SIZE_ADD_BBD_LIST);
if (visited_add_bbd_list == END_OF_CHAIN) {
if (lp + 1 != missing_lps) {
/* FIXME tenix error */
}
}
}
/* tmp here means the number of one block that
belongs to the fat */
bbd = MS_OLE_GET_GUINT32 (BB_R_PTR (f, visited_add_bbd_list) + 4*((lp/(BB_BLOCK_SIZE/4))%MAX_SIZE_ADD_BBD_LIST));
tmp = MS_OLE_GET_GUINT32 (BB_R_PTR(f,bbd) +
4 * (lp % (BB_BLOCK_SIZE / 4)));
g_array_append_val (f->bb, tmp);
}
/* FIXME tenix do we check if we have visited all lp's but
there are more additional lists? */
}
/* Mark the bbd list blocks as unused */
for (lp=0; lp < MIN (numbbd, MAX_SIZE_BBD_LIST); lp++) {
TRY_MARK_UNUSED_BLOCK (f->bb, GET_BBD_LIST(f,lp),
SPECIAL_BLOCK);
}
if (num_add_bbd_lists > 0) {
visited_add_bbd_list = GET_FIRST_ADD_BBD_LIST (f);
TRY_MARK_UNUSED_BLOCK (f->bb, visited_add_bbd_list,
ADD_BBD_LIST_BLOCK);
missing_bbds = numbbd - MAX_SIZE_BBD_LIST;
for (lp = 0; lp < missing_bbds; lp++) {
if ((lp!=0) && !(lp % (MAX_SIZE_ADD_BBD_LIST))) {
/* This lp lives in the next add bbd list */
visited_add_bbd_list = MS_OLE_GET_GUINT32(
BB_R_PTR(f,visited_add_bbd_list)
+ 4*MAX_SIZE_ADD_BBD_LIST);
if (visited_add_bbd_list == END_OF_CHAIN) {
if (lp + 1 != missing_lps) {
/* FIXME tenix error */
}
}
TRY_MARK_UNUSED_BLOCK (f->bb,
visited_add_bbd_list,
ADD_BBD_LIST_BLOCK);
}
bbd = MS_OLE_GET_GUINT32 (BB_R_PTR(f, visited_add_bbd_list) + 4*(lp%MAX_SIZE_ADD_BBD_LIST));
TRY_MARK_UNUSED_BLOCK (f->bb, bbd, SPECIAL_BLOCK);
}
}
g_assert (f->bb->len < f->length/BB_BLOCK_SIZE);
/* FIXME tenix better check?:
g_assert (f->bb->len == f->length/BB_BLOCK_SIZE - 1); */
/* More sanity checks */
/* FIXME
for (lp=0; lp<numbbd; lp++) {
BLP bbdblk = GET_BBD_LIST(f, lp);
if (g_array_index(f->bb, BLP, bbdblk) != SPECIAL_BLOCK) {
printf ("Error - BBD blocks not marked correctly\n");
g_array_free (f->bb, TRUE);
return 0;
}
}
*/
#if OLE_DEBUG > 1
dump_header (f);
#endif
return 1;
}
static void
extend_file (MsOle *f, guint blocks)
{
#ifdef HAVE_MMAP
if (f->ole_mmap) {
int file;
guint8 *newptr, zero = 0;
guint32 filesize;
guint32 oldlen;
guint32 icount;
gchar zeroblock [BB_BLOCK_SIZE];
memset (zeroblock, zero, BB_BLOCK_SIZE);
g_assert (f);
file = f->file_des;
g_assert (munmap(f->mem, f->length) != -1);
/* Extend that file by blocks */
if (f->syswrap->getfilesize (file, &filesize)) {
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
if (f->syswrap->lseek (file, 0, SEEK_END) == (off_t)-1) {
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
for (icount = 0; icount < blocks; icount++) {
if (f->syswrap->write (file, zeroblock, BB_BLOCK_SIZE -
((icount == blocks - 1) ? 1 : 0))
== -1) {
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
}
if (f->syswrap->write (file, &zero, 1) == -1) {
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
oldlen = filesize;
if (f->syswrap->getfilesize (file, &(f->length))) {
printf ("Warning couldn't get the size of the file\n");
}
g_assert (f->length == BB_BLOCK_SIZE*blocks + oldlen);
if (f->length%BB_BLOCK_SIZE)
printf ("Warning file %d non-integer number of blocks\n", f->length);
/* NOTE tenix here we don't check if try_mmap is true, because
if it reach here it means f->ole_mmap is true and try_mmap is
true too. This is related with system wrappers. */
newptr = mmap (f->mem, f->length, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0);
#if OLE_DEBUG > 0
if (newptr != f->mem)
printf ("Memory map moved from %p to %p\n",
f->mem, newptr);
if (newptr == MAP_FAILED) {
f->mem = 0;
g_warning ("panic: re-map failed!");
}
#endif /* OLE_DEBUG */
f->mem = newptr;
} else /* !f->ole_mmap */ {
#endif /* HAVE_MMAP */
BBBlkAttr *s;
guint32 blkidx, i;
if (f->bbattr->len) {
s = g_ptr_array_index (f->bbattr, f->bbattr->len-1);
blkidx = s->blk+1;
} else
blkidx = 0;
for (i=0;i<blocks;i++) {
g_ptr_array_add (f->bbattr, bb_blk_attr_new (blkidx++));
f->length+= BB_BLOCK_SIZE;
}
#ifdef HAVE_MMAP
}
#endif /* HAVE_MMAP */
}
static BLP
next_free_bb (MsOle *f)
{
BLP blk, tblk;
g_assert (f);
blk = 0;
g_assert (f->bb->len < f->length/BB_BLOCK_SIZE);
while (blk < f->bb->len)
if (g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK)
return blk;
else
blk++;
extend_file (f, 1);
tblk = UNUSED_BLOCK;
g_array_append_val (f->bb, tblk);
g_assert ((g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK));
g_assert (f->bb->len < f->length/BB_BLOCK_SIZE);
return blk;
}
static int
write_bb (MsOle *f)
{
guint32 numbbd;
BLP lp, lpblk;
int a = BB_BLOCK_SIZE / 4;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->mem, 0);
g_return_val_if_fail (f->bb, 0);
numbbd = (f->bb->len + a - 2) / (a - 1); /* Think really hard! */
SET_NUM_BBD_BLOCKS (f, numbbd);
for (lp=0;lp<numbbd;lp++) {
BLP blk = next_free_bb(f);
SET_BBD_LIST (f, lp, blk);
g_array_index (f->bb, BLP, blk) = SPECIAL_BLOCK;
}
lpblk = 0;
while (lpblk < f->bb->len) { /* Described blocks */
guint8 *mem = BB_W_PTR(f, GET_BBD_LIST(f, lpblk/(BB_BLOCK_SIZE/4)));
MS_OLE_SET_GUINT32 (mem + (lpblk%(BB_BLOCK_SIZE/4))*4,
g_array_index (f->bb, BLP, lpblk));
lpblk++;
}
while (lpblk % (BB_BLOCK_SIZE/4) != 0) { /* Undescribed blocks */
guint8 *mem;
g_assert (lpblk/(BB_BLOCK_SIZE/4) < numbbd);
mem = BB_W_PTR(f, GET_BBD_LIST(f, lpblk/(BB_BLOCK_SIZE/4)));
MS_OLE_SET_GUINT32 (mem + (lpblk%(BB_BLOCK_SIZE/4))*4,
UNUSED_BLOCK);
lpblk++;
}
g_array_free (f->bb, TRUE);
f->bb = 0;
return 1;
}
static BLP
next_free_sb (MsOle *f)
{
BLP blk, tblk;
g_assert (f);
blk = 0;
while (blk < f->sb->len)
if (g_array_index (f->sb, BLP, blk) == UNUSED_BLOCK)
return blk;
else
blk++;
tblk = UNUSED_BLOCK;
g_array_append_val (f->sb, tblk);
g_assert ((g_array_index (f->sb, BLP, blk) == UNUSED_BLOCK));
g_assert (blk < f->sb->len);
if ((f->sb->len + (BB_BLOCK_SIZE/SB_BLOCK_SIZE) - 1) / (BB_BLOCK_SIZE/SB_BLOCK_SIZE) >= f->sbf->len) {
/* Create an extra big block on the small block stream */
BLP new_sbf = next_free_bb(f);
if (f->sbf->len > 0)
g_array_index (f->bb, BLP,
g_array_index (f->sbf, BLP, f->sbf->len-1)) = new_sbf;
g_array_append_val (f->sbf, new_sbf);
g_array_index (f->bb, BLP, new_sbf) = END_OF_CHAIN;
}
g_assert ((f->sb->len + (BB_BLOCK_SIZE/SB_BLOCK_SIZE) - 1) / (BB_BLOCK_SIZE/SB_BLOCK_SIZE) <= f->sbf->len);
return blk;
}
static guint8 *
get_pps_ptr (MsOle *f, PPS_IDX i, gboolean forwrite)
{
int lp;
BLP blk = GET_ROOT_STARTBLOCK (f);
lp = i/(BB_BLOCK_SIZE/PPS_BLOCK_SIZE);
while (lp && blk != END_OF_CHAIN) {
if (blk == SPECIAL_BLOCK ||
blk == UNUSED_BLOCK) {
printf ("Duff block in root chain\n");
return 0;
}
lp--;
blk = NEXT_BB (f, blk);
}
if (blk == END_OF_CHAIN) {
printf ("Serious error finding pps %d\n", i);
return 0;
}
#if OLE_DEBUG > 0
printf ("get_pps_ptr: blk = %d\n", blk);
#endif
if (forwrite)
return BB_W_PTR(f, blk) + (i%(BB_BLOCK_SIZE/PPS_BLOCK_SIZE))*PPS_BLOCK_SIZE;
else
return BB_R_PTR(f, blk) + (i%(BB_BLOCK_SIZE/PPS_BLOCK_SIZE))*PPS_BLOCK_SIZE;
}
static gint
pps_compare_func (PPS *a, PPS *b)
{
g_return_val_if_fail (a, 0);
g_return_val_if_fail (b, 0);
g_return_val_if_fail (a->name, 0);
g_return_val_if_fail (b->name, 0);
return g_strcasecmp (b->name, a->name);
}
static void
pps_decode_tree (MsOle *f, PPS_IDX p, PPS *parent)
{
PPS *pps;
guint8 *mem;
if (p == PPS_END_OF_CHAIN)
return;
pps = g_new (PPS, 1);
pps->sig = PPS_SIG;
mem = get_pps_ptr (f, p, FALSE);
if (!mem) {
printf ("Serious directory error %d\n", p);
f->pps = NULL;
return;
}
#if OLE_DEBUG > 0
printf ("pps_decode_tree: mem (offset)= %#8.8x\n", mem - f->mem);
#endif
pps->name = pps_get_text (mem, PPS_GET_NAME_LEN(mem));
pps->type = PPS_GET_TYPE (mem);
pps->size = PPS_GET_SIZE (mem);
pps->children = NULL;
pps->parent = parent;
pps->idx = 0;
if (!pps->name) { /* Make safe */
printf ("how odd: blank named file in directory\n");
g_free (pps);
return;
}
f->num_pps++;
if (parent) {
#if OLE_DEBUG > 0
printf ("Inserting '%s' into '%s'\n", pps->name, parent->name);
#endif
parent->children = g_list_insert_sorted (parent->children, pps,
(GCompareFunc)pps_compare_func);
}
else {
#if OLE_DEBUG > 0
printf ("Setting root to '%s'\n", pps->name);
#endif
f->pps = g_list_append (0, pps);
}
if (PPS_GET_NEXT(mem) != PPS_END_OF_CHAIN)
pps_decode_tree (f, PPS_GET_NEXT(mem), parent);
if (PPS_GET_PREV(mem) != PPS_END_OF_CHAIN)
pps_decode_tree (f, PPS_GET_PREV(mem), parent);
if (PPS_GET_DIR (mem) != PPS_END_OF_CHAIN)
pps_decode_tree (f, PPS_GET_DIR(mem), pps);
pps->start = PPS_GET_STARTBLOCK (mem);
#if OLE_DEBUG > 1
printf ("PPS decode : '%s'\n", pps->name?pps->name:"Null");
ms_ole_dump (mem, PPS_BLOCK_SIZE);
#endif
return;
}
static int
read_pps (MsOle *f)
{
PPS *pps;
g_return_val_if_fail (f, 0);
f->num_pps = 0;
pps_decode_tree (f, PPS_ROOT_INDEX, NULL);
if (!f->pps || g_list_length (f->pps) < 1 ||
g_list_length (f->pps) > 1) {
printf ("Invalid root chain\n");
return 0;
} else if (!f->pps->data) {
printf ("No root entry\n");
return 0;
}
/* Fiddle root, perhaps our get_text is broken */
/* perhaps it is just an MS oddity in coding */
pps = f->pps->data;
if (pps->name)
g_free (pps->name);
pps->name = g_strdup ("Root Entry");
{ /* Free up the root chain */
BLP blk, last;
last = blk = GET_ROOT_STARTBLOCK (f);
while (blk != END_OF_CHAIN) {
last = blk;
blk = NEXT_BB (f, blk);
g_array_index (f->bb, BLP, last) = UNUSED_BLOCK;
}
}
if (!f->pps) {
printf ("Root directory too small\n");
return 0;
}
return 1;
}
/**
* Write the blocks main data recursively.
**/
static void
pps_encode_tree_initial (MsOle *f, GList *list, PPS_IDX *p)
{
int lp, max;
guint8 *mem;
PPS *pps;
g_return_if_fail (list);
g_return_if_fail (list->data);
pps = list->data;
pps->idx = *p;
(*p)++;
#if OLE_DEBUG > 0
printf ("encoding '%s' as %d\n", pps->name, pps->idx);
#endif
mem = get_pps_ptr (f, pps->idx, TRUE);
/* Blank stuff I don't understand */
for (lp=0;lp<PPS_BLOCK_SIZE;lp++)
MS_OLE_SET_GUINT8(mem+lp, 0);
if (pps->name) {
max = strlen (pps->name);
if (max >= (PPS_BLOCK_SIZE/4))
max = (PPS_BLOCK_SIZE/4);
for (lp=0;lp<max;lp++)
MS_OLE_SET_GUINT16(mem + lp*2, pps->name[lp]);
} else {
printf ("No name %d\n", *p);
max = -1;
}
PPS_SET_NAME_LEN(mem, (max+1)*2);
/* Magic numbers */
if (pps->idx == PPS_ROOT_INDEX) { /* Only Root */
MS_OLE_SET_GUINT32 (mem + 0x50, 0x00020900);
MS_OLE_SET_GUINT32 (mem + 0x58, 0x000000c0);
MS_OLE_SET_GUINT32 (mem + 0x5c, 0x46000000);
MS_OLE_SET_GUINT8 (mem + 0x43, 0x01); /* or zero ? */
} else if (pps->size >= BB_THRESHOLD) {
MS_OLE_SET_GUINT32 (mem + 0x50, 0x00020900);
MS_OLE_SET_GUINT8 (mem + 0x43, 0x01);
} else {
MS_OLE_SET_GUINT32 (mem + 0x64, 0x09299c3c);
MS_OLE_SET_GUINT32 (mem + 0x6c, 0x09299c3c);
MS_OLE_SET_GUINT8 (mem + 0x43, 0x00);
}
PPS_SET_TYPE (mem, pps->type);
PPS_SET_SIZE (mem, pps->size);
PPS_SET_STARTBLOCK(mem, pps->start);
PPS_SET_NEXT (mem, PPS_END_OF_CHAIN);
PPS_SET_PREV (mem, PPS_END_OF_CHAIN);
PPS_SET_DIR (mem, PPS_END_OF_CHAIN);
#if OLE_DEBUG > 1
printf ("Encode '%s' as \n", pps->name);
ms_ole_dump (mem, PPS_BLOCK_SIZE);
#endif
if (pps->children)
pps_encode_tree_initial (f, pps->children, p);
if (g_list_next (list))
pps_encode_tree_initial (f, g_list_next(list), p);
}
/*
* Chain the blocks together afterwards
*/
static void
pps_encode_tree_chain (MsOle *f, GList *list)
{
PPS *parent; /* parent's PPS */
int len; /* how many childrens are there */
GList *lchildren; /* visited children */
PPS *children; /* visited children's PPS */
PPS *next; /* next children's PPS */
PPS *prev; /* previous children's PPS */
guint8 *mem; /* a PPS in memory */
guint8 *mem_parent; /* a PPS in memory */
gint i;
int half_way;
g_return_if_fail (list);
g_return_if_fail (list->data);
parent = list->data;
len = g_list_length (parent->children);
half_way = len / 2;
lchildren = parent->children;
/* The base node of the directory */
/* Choose the first child */
mem_parent = get_pps_ptr (f, parent->idx, TRUE);
if (len == 1) {
PPS_SET_DIR (mem_parent, ((PPS *)(lchildren->data))->idx);
#if OLE_DEBUG > 1
printf ("tenix3 Final encode '%s' as \n",
((PPS *)(parent))->name);
ms_ole_dump (mem_parent, PPS_BLOCK_SIZE);
printf ("tenix3 Final encode '%s' as \n",
((PPS *)(lchildren->data))->name);
ms_ole_dump (get_pps_ptr (f, ((PPS *)(lchildren->data))->idx, FALSE),
PPS_BLOCK_SIZE);
#endif
return;
}
#if OLE_DEBUG > 1
if (len == 0)
printf ("Empty directory '%s'\n", ((PPS *)(children))->name);
#endif
i = 0;
for (; lchildren; lchildren = g_list_next (lchildren)) {
children = lchildren->data;
if (children->type == MsOleStorageT)
pps_encode_tree_chain (f, lchildren);
if (i == half_way)
PPS_SET_DIR (mem_parent, ((PPS *)(children))->idx);
mem = get_pps_ptr (f, children->idx, TRUE);
if (i == half_way) {
if (g_list_previous (lchildren)) {
prev = g_list_previous(lchildren)->data;
PPS_SET_PREV (mem, prev->idx);
}
if (g_list_next (lchildren)) {
next = g_list_next (lchildren)->data;
PPS_SET_NEXT (mem, next->idx);
}
} else if (i < half_way) {
if (g_list_previous(lchildren)) {
prev = g_list_previous (lchildren)->data;
PPS_SET_PREV (mem, prev->idx);
}
} else /* i > half_way */ {
if (g_list_next(lchildren)) {
next = g_list_next (lchildren)->data;
PPS_SET_NEXT (mem, next->idx);
}
}
#if OLE_DEBUG > 1
printf ("tenix1 Final encode '%s' as \n",
((PPS *)(children))->name);
ms_ole_dump (mem, PPS_BLOCK_SIZE);
#endif
i++;
}
#if OLE_DEBUG > 1
printf ("tenix2 Final encode '%s' as \n", ((PPS *)(parent))->name);
ms_ole_dump (mem_parent, PPS_BLOCK_SIZE);
#endif
}
static int
write_pps (MsOle *f)
{
int lp;
PPS_IDX idx;
BLP blk = END_OF_CHAIN;
BLP last = END_OF_CHAIN;
/* Build the root chain */
for (lp=0;lp<(f->num_pps+(BB_BLOCK_SIZE/PPS_BLOCK_SIZE)-1)/(BB_BLOCK_SIZE/PPS_BLOCK_SIZE);lp++) {
last = blk;
blk = next_free_bb (f);
g_assert (g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK);
if (last != END_OF_CHAIN)
g_array_index (f->bb, BLP, last) = blk;
else {
#if OLE_DEBUG > 0
printf ("Set root block to %d\n", blk);
#endif
SET_ROOT_STARTBLOCK (f, blk);
}
g_array_index (f->bb, BLP, blk) = END_OF_CHAIN;
}
g_assert (GET_ROOT_STARTBLOCK(f) != END_OF_CHAIN);
idx = PPS_ROOT_INDEX;
pps_encode_tree_initial (f, f->pps, &idx);
pps_encode_tree_chain (f, f->pps);
f->pps = 0;
f->num_pps = 0;
return 1;
}
static int
read_sb (MsOle *f)
{
BLP ptr;
int lastidx, idx;
PPS *root;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->pps, 0);
root = f->pps->data;
g_return_val_if_fail (root, 0);
f->sbf = g_array_new (FALSE, FALSE, sizeof(BLP));
f->sb = g_array_new (FALSE, FALSE, sizeof(BLP));
/* List of big blocks in SB file */
ptr = root->start;
#if OLE_DEBUG > 0
printf ("Starting Small block file at %d\n", root->start);
#endif
while (ptr != END_OF_CHAIN) {
if (ptr == UNUSED_BLOCK ||
ptr == SPECIAL_BLOCK) {
printf ("Corrupt small block file: serious error, "
"invalid block in chain\n");
g_array_free (f->sbf, TRUE);
f->sbf = 0;
return 0;
}
g_array_append_val (f->sbf, ptr);
ptr = NEXT_BB (f, ptr);
}
/* Description of small blocks */
lastidx = -1;
idx = 0;
ptr = GET_SBD_STARTBLOCK (f);
if (f->sbf->len == 0 && ptr != END_OF_CHAIN) {
printf ("No small block file, but small block depot start block exists!: "
"ignore depot, since there's no small block files after all.\n");
ptr = END_OF_CHAIN;
}
while (ptr != END_OF_CHAIN) {
guint32 lp;
if (ptr == UNUSED_BLOCK ||
ptr == SPECIAL_BLOCK) {
printf ("Corrupt file descriptor: serious error, "
"invalid block in chain\n");
g_array_free (f->sb, TRUE);
f->sb = 0;
return 0;
}
for (lp=0;lp<BB_BLOCK_SIZE/4;lp++) {
BLP p = MS_OLE_GET_GUINT32 (BB_R_PTR(f, ptr) + lp*4);
g_array_append_val (f->sb, p);
if (p != UNUSED_BLOCK)
lastidx = idx;
idx++;
}
ptr = NEXT_BB (f, ptr);
}
if (lastidx>0)
g_array_set_size (f->sb, lastidx+1);
if (f->sbf->len * BB_BLOCK_SIZE < f->sb->len*SB_BLOCK_SIZE) {
printf ("Not enough small block file for descriptors\n"
"sbf->len == %d, sb->len == %d\n", f->sbf->len,
f->sb->len);
return 0;
}
return 1;
}
static int
write_sb (MsOle *f)
{
guint32 lp, lastused;
PPS *root;
BLP sbd_start = END_OF_CHAIN;
BLP sbf_start = END_OF_CHAIN;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->pps, 0);
root = f->pps->data;
if (f->sbf->len * BB_BLOCK_SIZE < f->sb->len*SB_BLOCK_SIZE) {
printf ("Not enough descriptor / blocks being written %d %d\n",
f->sbf->len, f->sb->len);
}
if (f->sbf->len>0)
sbf_start = g_array_index (f->sbf, BLP, 0);
lastused = END_OF_CHAIN;
for (lp=0;lp<f->sb->len;lp++) {
if (g_array_index (f->sb, BLP, lp) != UNUSED_BLOCK)
lastused = lp;
}
if (lastused != END_OF_CHAIN) { /* Bother writing stuff */
guint8 *mem = 0;
guint32 num_sbdf = (lastused + (BB_BLOCK_SIZE/4)-1) /
(BB_BLOCK_SIZE/4);
BLP blk = END_OF_CHAIN, last;
#if OLE_DEBUG > 0
printf ("Num SB descriptor blocks : %d\n", num_sbdf);
#endif
for (lp=0;lp<num_sbdf*(BB_BLOCK_SIZE/4);lp++) {
BLP set;
if (lp%(BB_BLOCK_SIZE/4) == 0) {
last = blk;
blk = next_free_bb(f);
if (!lp)
sbd_start = blk;
if (last != END_OF_CHAIN)
g_array_index (f->bb, BLP, last) = blk;
g_array_index (f->bb, BLP, blk) = END_OF_CHAIN;
mem = BB_W_PTR (f, blk);
}
if (lp<f->sb->len)
set = g_array_index (f->sb, BLP, lp);
else
set = UNUSED_BLOCK;
MS_OLE_SET_GUINT32 (mem + (lp%(BB_BLOCK_SIZE/4))*4, set);
}
} else {
#if OLE_DEBUG > 0
printf ("Blank SB allocation\n");
#endif
sbf_start = END_OF_CHAIN;
}
root->start = sbf_start;
SET_SBD_STARTBLOCK (f, sbd_start);
g_array_free (f->sb, TRUE);
g_array_free (f->sbf, TRUE);
f->sb = 0;
f->sbf = 0;
return 1;
}
static int
ms_ole_setup (MsOle *f)
{
if (!f->ole_mmap) {
guint32 i;
f->bbattr = g_ptr_array_new ();
for (i = 0; i <(f->length / BB_BLOCK_SIZE) + 1; i++)
g_ptr_array_add (f->bbattr, bb_blk_attr_new(i));
}
if (read_bb (f) &&
read_pps (f) &&
read_sb (f)) {
#if OLE_DEBUG > 1
printf ("Just read header of\n");
dump_header (f);
#endif
return 1;
}
return 0;
}
static int
ms_ole_cleanup (MsOle *f)
{
if (f->mode != 'w') /* Nothing to write */
return 1;
#if OLE_DEBUG > 1
printf ("About to write header of: \n");
dump_header (f);
#endif
if (write_sb (f) &&
write_pps (f) &&
write_bb (f))
return 1;
return 0;
}
static MsOle *
new_null_msole ()
{
MsOle *f = g_new0 (MsOle, 1);
f->mem = (guint8 *)0xdeadbeef;
f->length = 0;
f->mode = 'r';
f->bb = 0;
f->bbattr = 0;
f->sb = 0;
f->sbf = 0;
f->pps = 0;
f->dirty = 0;
return f;
}
/**
* ms_ole_ref:
* @fs: filesystem object.
*
* Increment by one the count of references to the filesystem.
**/
void
ms_ole_ref (MsOle *fs)
{
g_return_if_fail (fs != NULL);
fs->ref_count++;
}
/**
* ms_ole_unref:
* @fs: filesystem object.
*
* Decrement by one the count of references to the filesystem.
**/
void
ms_ole_unref (MsOle *fs)
{
g_return_if_fail (fs != NULL);
fs->ref_count--;
}
/**
* ms_ole_open_vfs:
* @fs: filesystem object.
* @path: path to the filesystem-in-the file on the actual filesystem.
* @try_mmap: TRUE if try to mmap(2) the filesystem-in-a-file,
* instead of opening.
* @wrappers: system functions wrappers, %NULL if standard functions are used.
*
* Opens the filesystem-in-the-file @path and creates the filesystem object @fs.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_open_vfs (MsOle **f, const char *name, gboolean try_mmap,
MsOleSysWrappers *wrappers)
{
#ifdef HAVE_MMAP
int prot = PROT_READ | PROT_WRITE;
#endif
int file;
if (!f)
return MS_OLE_ERR_BADARG;
#if OLE_DEBUG > 0
printf ("New OLE file '%s'\n", name);
#endif
*f = new_null_msole();
take_wrapper_functions (*f, wrappers);
(*f)->file_des = file = (*f)->syswrap->open2 (name, O_RDWR);
(*f)->ref_count = 0;
(*f)->mode = 'w';
if (file == -1) {
(*f)->file_des = file = (*f)->syswrap->open2 (name, O_RDONLY);
(*f)->mode = 'r';
prot &= ~PROT_WRITE;
}
if ((file == -1) || !((*f)->syswrap->isregfile (file))) {
/* FIXME tenix is not a memory leak not to close file? */
printf ("No such file '%s'\n", name);
g_free (*f) ;
return MS_OLE_ERR_EXIST;
}
if ((*f)->syswrap->getfilesize( file, &((*f)->length) )) {
printf ("Couldn't get the size of file '%s'\n", name);
(*f)->syswrap->close (file) ;
g_free (*f) ;
return MS_OLE_ERR_EXIST;
}
if ((*f)->length <= 0x4c) { /* Bad show */
#if OLE_DEBUG > 0
printf ("File '%s' too short\n", name);
#endif
(*f)->syswrap->close (file) ;
g_free (*f) ;
return MS_OLE_ERR_FORMAT;
}
if (try_mmap) {
#ifdef HAVE_MMAP
(*f)->ole_mmap = TRUE;
(*f)->mem = mmap (0, (*f)->length, prot, MAP_SHARED, file, 0);
if (!(*f)->mem || (caddr_t)(*f)->mem == (caddr_t)MAP_FAILED) {
#endif
// g_warning ("I can't mmap that file, falling back to slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
if (!(*f)->mem
|| ((*f)->syswrap->read (file, (*f)->mem, BB_BLOCK_SIZE)
== -1)) {
printf ("Error reading header\n");
g_free (*f);
return MS_OLE_ERR_EXIST;
}
#ifdef HAVE_MMAP
}
#endif
} else /* !try_mmap */ {
// g_warning ("I won't mmap that file, using a slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
if (!(*f)->mem
|| ((*f)->syswrap->read (file, (*f)->mem, BB_BLOCK_SIZE)
== -1)) {
printf ("Error reading header\n");
g_free (*f);
return MS_OLE_ERR_EXIST;
}
} /* try_mmap */
if (MS_OLE_GET_GUINT32((*f)->mem ) != 0xe011cfd0 ||
MS_OLE_GET_GUINT32((*f)->mem + 4) != 0xe11ab1a1) {
#if OLE_DEBUG > 0
printf ("Failed OLE2 magic number %x %x\n",
MS_OLE_GET_GUINT32((*f)->mem), MS_OLE_GET_GUINT32((*f)->mem+4));
#endif
ms_ole_destroy (f);
return MS_OLE_ERR_FORMAT;
}
if ((*f)->length % BB_BLOCK_SIZE)
printf ("Warning file '%s':%d non-integer number of blocks\n",
name, (*f)->length);
if (!ms_ole_setup (*f)) {
printf ("'%s' : duff file !\n", name);
ms_ole_destroy (f);
return MS_OLE_ERR_FORMAT;
}
g_assert ((*f)->bb->len < (*f)->length/BB_BLOCK_SIZE);
#if OLE_DEBUG > 0
printf ("New OLE file '%s'\n", name);
#endif
/* If writing then when destroy commit it */
return MS_OLE_ERR_OK;
}
MsOleErr ms_ole_open_vfs_body (MsOle **f, const char *name, gboolean try_mmap, MsOleSysWrappers *wrappers, char *jp_buf_ptr, size_t jp_buf_len)
{
#ifdef HAVE_MMAP
int prot = PROT_READ | PROT_WRITE;
#endif
int file;
if (!f)
return MS_OLE_ERR_BADARG;
#if OLE_DEBUG > 0
printf ("New OLE file '%s'\n", name);
#endif
*f = new_null_msole();
jp_msOle = *f;
(*f)->buf = jp_buf_ptr;
(*f)->len = jp_buf_len;
(*f)->idx = 0;
// take_wrapper_functions (*f, wrappers);
take_wrapper_functions (*f, &default_wrappers_body);
(*f)->file_des = file = (*f)->syswrap->open2 (name, O_RDWR);
(*f)->ref_count = 0;
(*f)->mode = 'w';
if (file == -1) {
(*f)->file_des = file = (*f)->syswrap->open2 (name, O_RDONLY);
(*f)->mode = 'r';
prot &= ~PROT_WRITE;
}
if ((file == -1) || !((*f)->syswrap->isregfile (file))) {
/* FIXME tenix is not a memory leak not to close file? */
printf ("No such file '%s'\n", name);
g_free (*f) ;
return MS_OLE_ERR_EXIST;
}
if ((*f)->syswrap->getfilesize( file, &((*f)->length) )) {
printf ("Couldn't get the size of file '%s'\n", name);
(*f)->syswrap->close (file) ;
g_free (*f) ;
return MS_OLE_ERR_EXIST;
}
if ((*f)->length <= 0x4c) { /* Bad show */
#if OLE_DEBUG > 0
printf ("File '%s' too short\n", name);
#endif
(*f)->syswrap->close (file) ;
g_free (*f) ;
return MS_OLE_ERR_FORMAT;
}
if (try_mmap) {
#ifdef HAVE_MMAP
(*f)->ole_mmap = TRUE;
(*f)->mem = mmap (0, (*f)->length, prot, MAP_SHARED, file, 0);
if (!(*f)->mem || (caddr_t)(*f)->mem == (caddr_t)MAP_FAILED) {
#endif
// g_warning ("I can't mmap that file, falling back to slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
if (!(*f)->mem
|| ((*f)->syswrap->read (file, (*f)->mem, BB_BLOCK_SIZE)
== -1)) {
printf ("Error reading header\n");
g_free (*f);
return MS_OLE_ERR_EXIST;
}
#ifdef HAVE_MMAP
}
#endif
} else /* !try_mmap */ {
// g_warning ("I won't mmap that file, using a slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
if (!(*f)->mem
|| ((*f)->syswrap->read (file, (*f)->mem, BB_BLOCK_SIZE)
== -1)) {
printf ("Error reading header\n");
g_free (*f);
return MS_OLE_ERR_EXIST;
}
} /* try_mmap */
if (MS_OLE_GET_GUINT32((*f)->mem ) != 0xe011cfd0 ||
MS_OLE_GET_GUINT32((*f)->mem + 4) != 0xe11ab1a1) {
#if OLE_DEBUG > 0
printf ("Failed OLE2 magic number %x %x\n",
MS_OLE_GET_GUINT32((*f)->mem), MS_OLE_GET_GUINT32((*f)->mem+4));
#endif
ms_ole_destroy (f);
return MS_OLE_ERR_FORMAT;
}
if ((*f)->length % BB_BLOCK_SIZE)
printf ("Warning file '%s':%d non-integer number of blocks\n", name, (*f)->length);
if (!ms_ole_setup (*f)) {
printf ("'%s' : duff file !\n", name);
ms_ole_destroy (f);
return MS_OLE_ERR_FORMAT;
}
g_assert ((*f)->bb->len < (*f)->length/BB_BLOCK_SIZE);
#if OLE_DEBUG > 0
printf ("New OLE file '%s'\n", name);
#endif
/* If writing then when destroy commit it */
return MS_OLE_ERR_OK;
}
/**
* ms_ole_create_vfs:
* @fs: filesystem object.
* @path: path to the filesystem-in-the file on the actual filesystem.
* @try_mmap: TRUE if try to mmap(2) the filesystem-in-a-file,
* instead of opening.
* @wrappers: system functions wrappers, %NULL if standard functions are used.
*
* Creates the filesystem-in-the-file @path and creates the filesystem @fs.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_create_vfs (MsOle **f, const char *name, gboolean try_mmap,
MsOleSysWrappers *wrappers)
{
int file, zero=0;
int init_blocks = 1, lp;
if (!f)
return MS_OLE_ERR_BADARG;
*f = new_null_msole ();
take_wrapper_functions (*f, wrappers);
if ((file = (*f)->syswrap->open3 (name,
O_RDWR|O_CREAT|O_TRUNC|O_NONBLOCK,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP))
== -1) {
printf ("Can't create file '%s'\n", name);
g_free (*f);
*f = NULL;
return MS_OLE_ERR_PERM;
}
if (((*f)->syswrap->lseek (file, BB_BLOCK_SIZE * init_blocks - 1,
SEEK_SET) == (off_t)-1) ||
((*f)->syswrap->write (file, &zero, 1) == -1)) {
printf ("Serious error extending file to %d bytes\n",
BB_BLOCK_SIZE*init_blocks);
g_free (*f);
*f = NULL;
return MS_OLE_ERR_SPACE;
}
(*f)->ref_count = 0;
(*f)->file_des = file;
(*f)->mode = 'w';
if ((*f)->syswrap->getfilesize (file, &((*f)->length))) {
printf ("Warning couldn't get the size of the file '%s'\n",
name);
}
if ((*f)->length % BB_BLOCK_SIZE)
printf ("Warning file %d non-integer number of blocks\n",
(*f)->length);
if (try_mmap) {
#ifdef HAVE_MMAP
(*f)->ole_mmap = TRUE;
(*f)->mem = mmap (0, (*f)->length, PROT_READ|PROT_WRITE,
MAP_SHARED, file, 0);
if (!(*f)->mem || (caddr_t)(*f)->mem == (caddr_t)MAP_FAILED) {
#endif
// g_warning ("I can't mmap that file, falling back to slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
#ifdef HAVE_MMAP
}
#endif
} else /* !try_mmap */ {
// g_warning ("I won't mmap that file, using a slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
} /* try_mmap */
/* The header block */
for (lp = 0; lp < BB_BLOCK_SIZE / 4; lp++)
MS_OLE_SET_GUINT32((*f)->mem + lp * 4,
(lp < (0x52 / 4)) ? 0: UNUSED_BLOCK);
MS_OLE_SET_GUINT32((*f)->mem, 0xe011cfd0); /* Magic number */
MS_OLE_SET_GUINT32((*f)->mem + 4, 0xe11ab1a1);
/* More magic numbers */
MS_OLE_SET_GUINT32((*f)->mem + 0x18, 0x0003003e);
MS_OLE_SET_GUINT32((*f)->mem + 0x1c, 0x0009fffe);
MS_OLE_SET_GUINT32((*f)->mem + 0x20, 0x6);
MS_OLE_SET_GUINT32((*f)->mem + 0x38, 0x00001000);
/* MS_OLE_SET_GUINT32((*f)->mem + 0x40, 0x1); */
MS_OLE_SET_GUINT32((*f)->mem + 0x44, 0xfffffffe);
SET_NUM_BBD_BLOCKS (*f, 0);
SET_ROOT_STARTBLOCK (*f, END_OF_CHAIN);
SET_SBD_STARTBLOCK (*f, END_OF_CHAIN);
{
PPS *p;
(*f)->bb = g_array_new (FALSE, FALSE, sizeof(BLP));
(*f)->sb = g_array_new (FALSE, FALSE, sizeof(BLP));
(*f)->sbf = g_array_new (FALSE, FALSE, sizeof(BLP));
p = g_new(PPS, 1);
p->sig = PPS_SIG;
p->name = g_strdup ("Root Entry");
p->start = END_OF_CHAIN;
p->type = MsOleRootT;
p->size = 0;
p->children = NULL;
p->parent = NULL;
(*f)->pps = g_list_append (0, p);
(*f)->num_pps = 1;
if ((*f)->ole_mmap)
(*f)->bbattr = NULL;
else
(*f)->bbattr = g_ptr_array_new ();
}
g_assert ((*f)->bb->len < (*f)->length/BB_BLOCK_SIZE);
return MS_OLE_ERR_OK;
}
static void
destroy_pps (GList *l)
{
GList *tmp;
for (tmp = l; tmp; tmp = g_list_next (tmp)) {
PPS *pps = tmp->data;
if (pps->name)
g_free (pps->name);
destroy_pps (pps->children);
g_free (pps);
}
g_list_free (l);
}
/**
* ms_ole_destroy:
* @fs: filesystem object.
*
* Closes the filesystem @fs and truncates any free blocks.
**/
void
ms_ole_destroy (MsOle **ptr)
{
MsOle *f = *ptr;
#if OLE_DEBUG > 0
printf ("FIXME: should truncate to remove unused blocks\n");
#endif
if (f) {
if (f->ref_count != 0)
g_warning ("Unclosed files exist on this OLE stream");
if (f->dirty)
ms_ole_cleanup (f);
if (f->mem == (void *)0xdeadbeef)
f->mem = NULL;
else if (f->ole_mmap) {
#ifdef HAVE_MMAP
munmap (f->mem, f->length);
#else
g_warning ("Unmapping while we dont have mmap call");
#endif
} else {
guint32 i;
for (i = 0; (f->bbattr) && (i < f->bbattr->len); i++) {
BBBlkAttr *attr = g_ptr_array_index (f->bbattr, i);
if (f->dirty && attr->dirty)
write_cache_block (f, attr);
g_free (attr->data);
attr->data = 0;
}
if (f->dirty) {
f->syswrap->lseek (f->file_des, 0, SEEK_SET);
f->syswrap->write (f->file_des, f->mem,
BB_BLOCK_SIZE);
}
g_free (f->mem);
f->mem = 0;
}
destroy_pps (f->pps);
f->syswrap->close (f->file_des);
g_free (f);
#if OLE_DEBUG > 0
printf ("Closing OLE file\n");
#endif
}
*ptr = NULL;
}
/**
* ms_ole_dump:
* @ptr: memory area to be dumped.
* @len: how many bytes will be dumped.
*
* Dump @len bytes from the memory location given by @ptr.
**/
void
ms_ole_dump (guint8 const *ptr, guint32 len)
{
guint32 lp,lp2;
guint32 off;
for (lp = 0;lp<(len+15)/16;lp++)
{
printf ("%8x | ", lp*16);
for (lp2=0;lp2<16;lp2++) {
off = lp2 + (lp<<4);
off<len?printf("%2x ", ptr[off]):printf("XX ");
}
printf ("| ");
for (lp2=0;lp2<16;lp2++) {
off = lp2 + (lp<<4);
printf ("%c", off<len?(ptr[off]>'!'&&ptr[off]<127?ptr[off]:'.'):'*');
}
printf ("\n");
}
}
/*
* Redundant stream check function.
*/
static void
check_stream (MsOleStream *s)
{
BLP blk;
guint32 idx;
PPS *p;
MsOle *f;
g_return_if_fail (s);
g_return_if_fail (s->file);
f = s->file;
p = s->pps;
g_return_if_fail (p);
blk = p->start;
idx = 0;
if (s->type == MsOleSmallBlock) {
while (blk != END_OF_CHAIN) {
g_assert (g_array_index (s->blocks, BLP, idx) ==
blk);
#if OLE_DEBUG > 2
ms_ole_dump (GET_SB_R_PTR(f, blk), SB_BLOCK_SIZE);
#endif
blk = NEXT_SB (f, blk);
idx++;
}
} else {
while (blk != END_OF_CHAIN) {
g_assert (g_array_index (s->blocks, BLP, idx) ==
blk);
#if OLE_DEBUG > 2
ms_ole_dump (BB_R_PTR(f, blk), BB_BLOCK_SIZE);
#endif
blk = NEXT_BB (f, blk);
idx++;
}
}
}
static MsOlePos
tell_pos (MsOleStream *s)
{
return s->position;
}
/*
* Free the allocation chains, and free up the blocks.
* "It was for freedom that Christ has set us free."
* Galatians 5:11
*/
static void
free_allocation (MsOle *f, guint32 startblock, gboolean is_big_block_stream)
{
g_return_if_fail (f);
#if OLE_DEBUG > 0
printf ("Free allocation %d : (%d)\n", startblock,
is_big_block_stream);
#endif
if (is_big_block_stream)
{
BLP p = startblock;
printf ("FIXME: this should also free up blocks\n");
while (p != END_OF_CHAIN) {
BLP next = NEXT_BB (f,p);
if (next == p) {
printf ("Serious bug: cyclic ring in BB allocation\n");
return;
} else if (p == SPECIAL_BLOCK ||
p == UNUSED_BLOCK) {
printf ("Serious bug: Special / Unused block "
"in BB allocation\n");
return;
}
g_array_index (f->bb, BLP, p) = UNUSED_BLOCK;
p = next;
}
}
else
{
BLP p = startblock;
while (p != END_OF_CHAIN) {
BLP next = NEXT_SB (f,p);
if (next == p) {
printf ("Serious bug: cyclic ring in SB allocation\n");
return;
} else if (p == SPECIAL_BLOCK ||
p == UNUSED_BLOCK) {
printf ("Serious bug: Special / Unused block "
"in SB allocation\n");
return;
}
g_array_index (f->sb, BLP, p) = UNUSED_BLOCK;
p = next;
}
/* Seek forwards to find blank sbf blocks */
{
guint32 lp;
BLP lastused = END_OF_CHAIN;
for (lp=0;lp<f->sb->len;lp++) {
if (g_array_index (f->sb, BLP, lp) != UNUSED_BLOCK)
lastused = lp;
}
if (lastused == END_OF_CHAIN) {
for (lp=0;lp<f->sbf->len;lp++) {
BLP sbfd = g_array_index (f->sbf, BLP, lp);
g_array_index (f->bb, BLP, sbfd) = UNUSED_BLOCK;
}
g_array_set_size (f->sbf, 0);
g_array_set_size (f->sb, 0);
} else {
guint32 sbf_needed = (lastused+(BB_BLOCK_SIZE/SB_BLOCK_SIZE)-1) /
(BB_BLOCK_SIZE/SB_BLOCK_SIZE);
if (sbf_needed == f->sbf->len)
return;
for (lp=sbf_needed;lp<f->sbf->len;lp++) {
BLP sbfd = g_array_index (f->sbf, BLP, lp);
g_array_index (f->bb, BLP, sbfd) = UNUSED_BLOCK;
}
g_array_set_size (f->sbf, sbf_needed);
g_array_set_size (f->sb, lastused+1);
}
}
}
}
/**
* ms_ole_lseek:
* @s: stream object.
* @bytes: number of bytes to set the stream pointer.
* @type: relative from where the stream pointer will be set.
*
* Set the stream pointer for @s as many as @bytes bytes according to @type.
*
* Return value: the new position of the stream pointer.
**/
static MsOleSPos
ms_ole_lseek (MsOleStream *s, MsOleSPos bytes, MsOleSeek type)
{
/* FIXME tenix improve limits detection: avoid gint vs guint limits */
MsOleSPos newpos;
g_return_val_if_fail (s, -1);
newpos = s->position;
if (type == MsOleSeekSet)
newpos = bytes;
else if (type == MsOleSeekCur)
newpos += bytes;
else
newpos = s->size - bytes;
if (newpos > s->size || newpos < 0) {
g_warning ("Invalid seek");
return -1;
}
s->position = newpos;
return newpos;
}
/*
* Returns:
* NULL - on error
*/
static guint8*
ms_ole_read_ptr_bb (MsOleStream *s, MsOlePos length)
{
int blklen;
guint8 *ans;
guint32 len=length;
int blockidx = s->position/BB_BLOCK_SIZE;
g_return_val_if_fail (s, NULL);
if (!s->blocks || blockidx >= s->blocks->len) {
printf ("Reading from NULL file\n");
return NULL;
}
blklen = BB_BLOCK_SIZE - s->position%BB_BLOCK_SIZE;
if (len > blklen && !s->file->ole_mmap)
return NULL;
while (len > blklen) {
len -= blklen;
blklen = BB_BLOCK_SIZE;
if (blockidx >= (s->blocks->len - 1)
|| (ms_array_index (s->blocks, BLP, blockidx)
!= blockidx + 1))
return NULL;
blockidx++;
}
/* Straight map, simply return a pointer */
ans = BB_R_PTR (s->file, ms_array_index (s->blocks, BLP,
s->position/BB_BLOCK_SIZE))
+ s->position%BB_BLOCK_SIZE;
ms_ole_lseek (s, length, MsOleSeekCur);
if (libole2_debug)
check_stream (s);
return ans;
}
/*
* Returns:
* NULL - on error
*/
static guint8*
ms_ole_read_ptr_sb (MsOleStream *s, MsOlePos length)
{
int blklen;
guint8 *ans;
guint32 len=length;
int blockidx = s->position/SB_BLOCK_SIZE;
g_return_val_if_fail (s, NULL);
if (!s->blocks || blockidx >= s->blocks->len) {
printf ("Reading from NULL file\n");
return NULL;
}
blklen = SB_BLOCK_SIZE - s->position%SB_BLOCK_SIZE;
if (len > blklen && !s->file->ole_mmap)
return NULL;
while (len > blklen) {
len -= blklen;
blklen = SB_BLOCK_SIZE;
if (blockidx >= (s->blocks->len - 1)
|| (ms_array_index (s->blocks, BLP, blockidx)
!= blockidx + 1))
return NULL;
blockidx++;
}
/* Straight map, simply return a pointer */
ans = GET_SB_R_PTR (s->file, ms_array_index (s->blocks, BLP,
s->position/SB_BLOCK_SIZE))
+ s->position%SB_BLOCK_SIZE;
ms_ole_lseek (s, length, MsOleSeekCur);
if (libole2_debug)
check_stream (s);
return ans;
}
/*
* Returns:
* zero - on error
* no zero - on success
*/
static gint
ms_ole_read_copy_bb (MsOleStream *s, guint8 *ptr, MsOlePos length)
{
guint8 *src;
int offset = s->position % BB_BLOCK_SIZE;
int blkidx = s->position / BB_BLOCK_SIZE;
g_return_val_if_fail (s, 0);
g_return_val_if_fail (ptr, 0);
if (!s->blocks) {
printf ("Reading from NULL file\n");
return 0;
}
while (length > 0)
{
BLP block;
int cpylen = BB_BLOCK_SIZE - offset;
if (cpylen > length)
cpylen = length;
if (s->position + cpylen > s->size
|| blkidx == s->blocks->len) {
#if OLE_DEBUG > 0
printf ("Trying 2 to read beyond end of stream %d+%d %d\n",
s->position, cpylen, s->size);
#endif
return 0;
}
g_assert (blkidx < s->blocks->len);
block = ms_array_index (s->blocks, BLP, blkidx);
src = BB_R_PTR (s->file, block) + offset;
memcpy (ptr, src, cpylen);
ptr += cpylen;
length -= cpylen;
offset = 0;
blkidx++;
s->position+=cpylen;
}
if (libole2_debug)
check_stream (s);
return 1;
}
/*
* Returns:
* zero - on error
* no zero - on success
*/
static gint
ms_ole_read_copy_sb (MsOleStream *s, guint8 *ptr, MsOlePos length)
{
int offset = s->position%SB_BLOCK_SIZE;
int blkidx = s->position/SB_BLOCK_SIZE;
guint8 *src;
g_return_val_if_fail (s, 0);
g_return_val_if_fail (ptr, 0);
if (!s->blocks) {
printf ("Reading from NULL file\n");
return 0;
}
while (length > 0)
{
int cpylen = SB_BLOCK_SIZE - offset;
BLP block;
if (cpylen>length)
cpylen = length;
if (s->position + cpylen > s->size
|| blkidx == s->blocks->len) {
#if OLE_DEBUG > 0
printf ("Trying 3 to read beyond end of stream %d+%d %d\n",
s->position, cpylen, s->size);
#endif
return 0;
}
g_assert (blkidx < s->blocks->len);
block = ms_array_index (s->blocks, BLP, blkidx);
src = GET_SB_R_PTR(s->file, block) + offset;
memcpy (ptr, src, cpylen);
ptr += cpylen;
length -= cpylen;
offset = 0;
blkidx++;
s->position+=cpylen;
}
if (libole2_debug)
check_stream (s);
return 1;
}
static void
ms_ole_append_block (MsOleStream *s)
{
BLP block;
BLP lastblk = END_OF_CHAIN;
BLP eoc = END_OF_CHAIN;
if (s->type==MsOleSmallBlock) {
if (!s->blocks)
s->blocks = g_array_new (FALSE, FALSE, sizeof(BLP));
else if (s->blocks->len>0)
lastblk = ms_array_index (s->blocks, BLP, s->blocks->len-1);
block = next_free_sb (s->file);
g_array_append_val (s->blocks, block);
if (lastblk != END_OF_CHAIN) { /* Link onwards */
g_array_index (s->file->sb, BLP, lastblk) = block;
#if OLE_DEBUG > 1
printf ("Chained Small block %d to previous block %d\n", block, lastblk);
#endif
} else { /* First block in a file */
PPS *p = s->pps;
#if OLE_DEBUG > 0
printf ("Set first Small block to %d\n", block);
#endif
p->start = block;
}
g_array_index (s->file->sb, BLP, block) = eoc;
} else {
if (!s->blocks)
s->blocks = g_array_new (FALSE, FALSE, sizeof(BLP));
else if (s->blocks->len>0)
lastblk = ms_array_index (s->blocks, BLP, s->blocks->len-1);
block = next_free_bb (s->file);
#if OLE_DEBUG > 0
{
int lp;
g_assert (g_array_index (s->file->bb, BLP, block) == UNUSED_BLOCK);
for (lp=0;lp<s->blocks->len;lp++)
g_assert (g_array_index (s->blocks, BLP, lp) != block);
}
#endif
g_array_append_val (s->blocks, block);
if (lastblk != END_OF_CHAIN) { /* Link onwards */
g_array_index (s->file->bb, BLP, lastblk) = block;
#if OLE_DEBUG > 1
printf ("Chained Big block %d to block %d\n", block, lastblk);
#endif
} else { /* First block in a file */
PPS *p = s->pps;
#if OLE_DEBUG > 0
printf ("Set first Big block to %d\n", block);
#endif
p->start = block;
}
g_array_index (s->file->bb, BLP, block) = eoc;
}
}
/* FIXME: I'm sure these functions should fail gracefully somehow :-) */
static MsOlePos
ms_ole_write_bb (MsOleStream *s, guint8 *ptr, MsOlePos length)
{
guint8 *dest;
gint32 lengthen;
guint32 bytes = length;
int offset = s->position%BB_BLOCK_SIZE;
guint32 blkidx = s->position/BB_BLOCK_SIZE;
s->file->dirty = 1;
while (bytes > 0) {
BLP block;
int cpylen = BB_BLOCK_SIZE - offset;
if (cpylen > bytes)
cpylen = bytes;
if (!s->blocks || blkidx >= s->blocks->len)
ms_ole_append_block (s);
g_assert (blkidx < s->blocks->len);
block = ms_array_index (s->blocks, BLP, blkidx);
dest = BB_W_PTR(s->file, block) + offset;
#if OLE_DEBUG > 1
printf ("Copy %d bytes to block %d\n", cpylen, block);
#endif
memcpy (dest, ptr, cpylen);
ptr += cpylen;
bytes -= cpylen;
offset = 0;
blkidx++;
}
lengthen = s->position - s->size + length;
if (lengthen > 0)
s->size += lengthen;
s->lseek (s, length, MsOleSeekCur);
if (libole2_debug)
check_stream (s);
return length;
}
/* FIXME: I'm sure these functions should fail gracefully somehow :-) */
static MsOlePos
ms_ole_write_sb (MsOleStream *s, guint8 *ptr, MsOlePos length)
{
guint8 *dest;
int offset = s->position%SB_BLOCK_SIZE;
guint32 blkidx = s->position/SB_BLOCK_SIZE;
guint32 bytes = length;
gint32 lengthen;
s->file->dirty = 1;
while (bytes > 0) {
BLP block;
int cpylen = SB_BLOCK_SIZE - offset;
if (cpylen > bytes)
cpylen = bytes;
if (!s->blocks || blkidx >= s->blocks->len)
ms_ole_append_block (s);
g_assert (s->blocks);
g_assert (blkidx < s->blocks->len);
block = ms_array_index (s->blocks, BLP, blkidx);
dest = GET_SB_W_PTR(s->file, block) + offset;
g_assert (cpylen >= 0);
memcpy (dest, ptr, cpylen);
ptr += cpylen;
bytes -= cpylen;
lengthen = s->position + length - bytes - s->size;
if (lengthen > 0)
s->size += lengthen;
/* Must be exactly filling the block */
if (s->size >= BB_THRESHOLD)
{
PPS *p = s->pps;
MsOlePos oldlen;
guint8 *buffer;
buffer = g_new (guint8, s->size);
s->lseek (s, 0, MsOleSeekSet);
oldlen = s->size;
s->read_copy (s, buffer, oldlen);
free_allocation (s->file, p->start, 0);
p->start = END_OF_CHAIN;
#if OLE_DEBUG > 1
printf ("\n\n--- Converting ---\n\n\n");
#endif
s->read_copy = ms_ole_read_copy_bb;
s->read_ptr = ms_ole_read_ptr_bb;
s->lseek = ms_ole_lseek;
s->tell = tell_pos;
s->write = ms_ole_write_bb;
g_assert (s->size % SB_BLOCK_SIZE == 0);
/* Convert the file to BBlocks */
s->size = 0;
s->position = 0;
s->type = MsOleLargeBlock;
g_array_free (s->blocks, TRUE);
s->blocks = 0;
s->write (s, buffer, oldlen);
/* Continue the interrupted write */
ms_ole_write_bb (s, ptr, bytes);
bytes = 0;
#if OLE_DEBUG > 1
printf ("\n\n--- Done ---\n\n\n");
#endif
g_free (buffer);
return length;
}
offset = 0;
blkidx++;
if (libole2_debug)
check_stream (s);
}
s->lseek (s, length, MsOleSeekCur);
return length;
}
/**
* pps_create:
* @f: ole file handle.
* @p: returned pps.
* @parent: parent pps.
* @name: its name.
* @type: the type.
*
* Creates a storage or stream.
*
* Return value: error status.
**/
static MsOleErr
pps_create (MsOle *f, GList **p, GList *parent, const char *name,
MsOleType type)
{
PPS *pps, *par;
if (!p || !parent || !parent->data || !name) {
g_warning ("duff arguments to pps_create");
return MS_OLE_ERR_BADARG;
}
pps = g_new (PPS, 1);
if (!pps)
return MS_OLE_ERR_MEM;
pps->sig = PPS_SIG;
pps->name = g_strdup (name);
pps->type = type;
pps->size = 0;
pps->start = END_OF_CHAIN;
pps->children = NULL;
pps->parent = parent->data;
par = (PPS *)parent->data;
par->children = g_list_insert_sorted (par->children, pps,
(GCompareFunc)pps_compare_func);
*p = g_list_find (par->children, pps);
f->num_pps++;
return MS_OLE_ERR_OK;
}
/**
* find_in_pps:
* @l: the parent storage chain element.
*
* Find the right Stream ... John 4:13-14 ...
* in a storage
*
* Return value: %NULL if not found or pointer to the child list
**/
static GList *
find_in_pps (GList *l, const char *name)
{
PPS *pps;
GList *cur;
g_return_val_if_fail (l != NULL, NULL);
g_return_val_if_fail (l->data != NULL, NULL);
pps = l->data;
g_return_val_if_fail (IS_PPS (pps), NULL);
if (pps->type == MsOleStorageT ||
pps->type == MsOleRootT)
cur = pps->children;
else {
g_warning ("trying to enter a stream '%s'",
pps->name?pps->name:"no name");
return NULL;
}
for ( ;cur ; cur = g_list_next (cur)) {
PPS *pps = cur->data;
g_return_val_if_fail (IS_PPS (pps), NULL);
if (!pps->name)
continue;
if (!g_strcasecmp (pps->name, name))
return cur;
}
return NULL;
}
/**
* path_to_pps:
* @pps: pointer to pps to return value in.
* @f: ole file hande.
* @path: path to find.
* @file: file to find in path.
* @create_if_not_found: create the pps with the given path if not found.
*
* Locates a stream or storage with the given path.
*
* Return value: a #MsOleErr code.
**/
static MsOleErr
path_to_pps (PPS **pps, MsOle *f, const char *path,
const char *file,
gboolean create_if_not_found)
{
guint lp;
gchar **dirs;
GList *cur, *parent;
g_return_val_if_fail (f != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (path != NULL, MS_OLE_ERR_BADARG);
dirs = g_strsplit (path, "/", -1);
g_return_val_if_fail (dirs != NULL, MS_OLE_ERR_BADARG);
parent = cur = f->pps;
for (lp = 0; dirs[lp]; lp++) {
if (dirs[lp][0] == '\0' || !cur) {
g_free (dirs[lp]);
continue;
}
parent = cur;
cur = find_in_pps (parent, dirs[lp]);
if (!cur && create_if_not_found &&
pps_create (f, &cur, parent, dirs[lp], MsOleStorageT) !=
MS_OLE_ERR_OK)
cur = NULL;
/* else carry on not finding them before dropping out */
g_free (dirs[lp]);
}
g_free (dirs);
if (!cur || !cur->data)
return MS_OLE_ERR_EXIST;
if (file[0] == '\0') { /* We just want a directory */
*pps = cur->data;
g_return_val_if_fail (IS_PPS (cur->data), MS_OLE_ERR_INVALID);
return MS_OLE_ERR_OK;
}
parent = cur;
cur = find_in_pps (parent, file);
/* now the file */
if (!cur) {
if (create_if_not_found) {
MsOleErr result;
result = pps_create (f, &cur, parent, file,
MsOleStreamT);
if (result == MS_OLE_ERR_OK) {
*pps = cur->data;
g_return_val_if_fail (IS_PPS (cur->data),
MS_OLE_ERR_INVALID);
return MS_OLE_ERR_OK;
} else
return result;
}
return MS_OLE_ERR_EXIST;
}
if (cur && cur->data) {
*pps = cur->data;
g_return_val_if_fail (IS_PPS (cur->data), MS_OLE_ERR_INVALID);
return MS_OLE_ERR_OK;
}
return MS_OLE_ERR_EXIST;
}
/**
* ms_ole_unlink:
* @fs: filesystem object.
* @path: path of the stream or directory to delete.
*
* Delete the stream or directory @path on the filesystem @fs.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_unlink (MsOle *f, const char *path)
{
g_warning ("Unimplemented");
/* FIXME missing implementation, or at least a better error code =-) */
return MS_OLE_ERR_NOTEMPTY;
}
/**
* ms_ole_directory:
* @names: array where the names are storesd, it's %NULL ended.
* @fs: filesystem object.
* @dirpath: directory path.
*
* Gets the names of the streams and directories in the directory @dirpath.
*
* Returns: a #MsOleErr code.
**/
MsOleErr
ms_ole_directory (char ***names, MsOle *f, const char *path)
{
char **ans;
PPS *pps;
MsOleErr result;
GList *l;
int lp;
g_return_val_if_fail (f != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (path != NULL, MS_OLE_ERR_BADARG);
if ((result = path_to_pps (&pps, f, path, "", FALSE)) !=
MS_OLE_ERR_OK)
return result;
if (!pps)
return MS_OLE_ERR_INVALID;
l = pps->children;
ans = g_new (char *, g_list_length (l) + 1);
lp = 0;
for (; l; l = g_list_next (l)) {
pps = (PPS *)l->data;
if (!pps->name)
continue;
ans[lp] = g_strdup (pps->name);
lp++;
}
ans[lp] = NULL;
*names = ans;
return MS_OLE_ERR_OK;
}
/**
* ms_ole_stat:
* @stat: stat information.
* @fs: filesystem object.
* @dirpath: directory path.
* @name: stream or directory name.
*
* Gets information about the stream or the directory which is in the directory
* @dirpath and its name is @file.
*
* Returns: a #MsOleErr code.
**/
MsOleErr
ms_ole_stat (MsOleStat *stat, MsOle *f, const char *path,
const char *file)
{
PPS *pps;
MsOleErr result;
g_return_val_if_fail (f != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (file != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (path != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (stat != NULL, MS_OLE_ERR_BADARG);
if ((result = path_to_pps (&pps, f, path, file, FALSE)) !=
MS_OLE_ERR_OK)
return result;
if (!pps)
return MS_OLE_ERR_INVALID;
stat->type = pps->type;
stat->size = pps->size;
return MS_OLE_ERR_OK;
}
/**
* ms_ole_stream_open:
* @stream: stream object.
* @fs: filesystem object.
* @dirpath: directory of the stream.
* @name: stream name.
* @mode: mode of opening stream.
*
* Opens the stream in @dirpath with the name @name and creates the stream
* object @stream. If @mode is '%r' it opens read only, and if it is '%w'
* it opens for write only.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_stream_open (MsOleStream ** const stream, MsOle *f,
const char *path, const char *fname, char mode)
{
PPS *p;
MsOleStream *s;
int lp, panic=0;
MsOleErr result;
if (!stream)
return MS_OLE_ERR_BADARG;
*stream = NULL;
if (!path || !f)
return MS_OLE_ERR_BADARG;
if (mode == 'w' && f->mode != 'w') {
printf ("Opening stream '%c' when file is '%c' only\n",
mode, f->mode);
return MS_OLE_ERR_PERM;
}
if ((result = path_to_pps (&p, f, path, fname, (mode == 'w'))) !=
MS_OLE_ERR_OK)
return result;
s = g_new0 (MsOleStream, 1);
s->file = f;
s->pps = p;
s->position = 0;
s->size = p->size;
s->blocks = NULL;
#if OLE_DEBUG > 0
printf ("Parsing blocks\n");
#endif
if (s->size >= BB_THRESHOLD) {
BLP b = p->start;
s->read_copy = ms_ole_read_copy_bb;
s->read_ptr = ms_ole_read_ptr_bb;
s->lseek = ms_ole_lseek;
s->tell = tell_pos;
s->write = ms_ole_write_bb;
s->blocks = g_array_new (FALSE, FALSE, sizeof(BLP));
s->type = MsOleLargeBlock;
for (lp = 0; !panic & (lp < (s->size + BB_BLOCK_SIZE - 1) / BB_BLOCK_SIZE); lp++) {
g_array_append_val (s->blocks, b);
#if OLE_DEBUG > 1
printf ("Block %d\n", b);
#endif
if (b == END_OF_CHAIN ||
b == SPECIAL_BLOCK ||
b == UNUSED_BLOCK) {
printf ("Panic: broken stream, truncating to block %d\n", lp);
s->size = (lp-1)*BB_BLOCK_SIZE;
panic = 1;
#if OLE_DEBUG > 0
if (b == END_OF_CHAIN)
printf ("Warning: bad file length in '%s'\n", p->name);
else if (b == SPECIAL_BLOCK)
printf ("Warning: special block in '%s'\n", p->name);
else if (b == UNUSED_BLOCK)
printf ("Warning: unused block in '%s'\n", p->name);
#endif
} else
b = NEXT_BB (f, b);
}
if (b != END_OF_CHAIN) {
BLP next;
printf ("Panic: extra unused blocks on end of '%s', wiping it\n",
p->name);
while (b != END_OF_CHAIN &&
b != UNUSED_BLOCK &&
b != SPECIAL_BLOCK) {
next = NEXT_BB (f, b);
g_array_index (f->bb, BLP, b) = END_OF_CHAIN;
b = next;
}
}
} else {
BLP b = p->start;
s->read_copy = ms_ole_read_copy_sb;
s->read_ptr = ms_ole_read_ptr_sb;
s->lseek = ms_ole_lseek;
s->tell = tell_pos;
s->write = ms_ole_write_sb;
if (s->size>0)
s->blocks = g_array_new (FALSE, FALSE, sizeof(BLP));
else
s->blocks = NULL;
s->type = MsOleSmallBlock;
for (lp = 0; !panic & (lp < (s->size + SB_BLOCK_SIZE - 1) / SB_BLOCK_SIZE); lp++) {
g_array_append_val (s->blocks, b);
#if OLE_DEBUG > 0
printf ("Block %d\n", b);
#endif
if (b == END_OF_CHAIN ||
b == SPECIAL_BLOCK ||
b == UNUSED_BLOCK) {
printf ("Panic: broken stream, truncating to block %d\n", lp);
s->size = (lp-1)*SB_BLOCK_SIZE;
panic = 1;
#if OLE_DEBUG > 0
if (b == END_OF_CHAIN)
printf ("Warning: bad file length in '%s'\n", p->name);
else if (b == SPECIAL_BLOCK)
printf ("Warning: special block in '%s'\n", p->name);
else if (b == UNUSED_BLOCK)
printf ("Warning: unused block in '%s'\n", p->name);
#endif
} else
b = NEXT_SB (f, b);
}
if (b != END_OF_CHAIN) {
BLP next;
printf ("Panic: extra unused blocks on end of '%s', wiping it\n",
p->name);
while (b != END_OF_CHAIN &&
b != UNUSED_BLOCK &&
b != SPECIAL_BLOCK) {
next = NEXT_SB (f, b);
g_array_index (f->sb, BLP, b) = END_OF_CHAIN;
b = next;
}
if (b != END_OF_CHAIN)
printf ("Panic: even more serious block error\n");
}
}
*stream = s;
ms_ole_ref (s->file);
return MS_OLE_ERR_OK;
}
/**
* ms_ole_stream_duplicate:
* @stream_copy: stream object copy.
* @stream: stream object to be duplicated.
*
* Duplicates the stream object @stream.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_stream_duplicate (MsOleStream **s, const MsOleStream * const stream)
{
if (!s || !stream)
return MS_OLE_ERR_BADARG;
/* Lets face it having two pointers to the same file is a nightmare anyway :-) */
g_warning ("Do NOT use this function, it is unsafe with the blocks array");
if (!(*s = g_new (MsOleStream, 1)))
return MS_OLE_ERR_MEM;
memcpy (*s, stream, sizeof (MsOleStream));
ms_ole_ref (stream->file);
return MS_OLE_ERR_OK;
}
/**
* ms_ole_stream_close:
* @stream: stream object to be closed.
*
* Closes the @stream.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_stream_close (MsOleStream **s)
{
if (*s) {
if ((*s)->file && (*s)->file->mode == 'w')
((PPS *)(*s)->pps)->size = (*s)->size;
if ((*s)->blocks)
g_array_free ((*s)->blocks, TRUE);
ms_ole_unref ((*s)->file);
g_free (*s);
*s = NULL;
return MS_OLE_ERR_OK;
}
return MS_OLE_ERR_BADARG;
}
--- Added File ms-ole.h in package Packages/Products/DCProject ---
/**
* ms-ole.h: MS Office OLE support for Gnumeric
*
* Authors:
* Michael Meeks (michael@imaginator.com)
* Arturo Tena (arturo@directmail.org)
**/
#ifndef MS_OLE_H
#define MS_OLE_H
/* This should be done in glib */
#ifndef _WIN32
# include <fcntl.h> /* for mode_t */
#else
typedef unsigned long mode_t;
typedef size_t ssize_t;
typedef /* signed */ long off_t;
#endif
#include <glib.h>
typedef enum {
MS_OLE_ERR_OK,
MS_OLE_ERR_EXIST,
MS_OLE_ERR_INVALID,
MS_OLE_ERR_FORMAT,
MS_OLE_ERR_PERM,
MS_OLE_ERR_MEM,
MS_OLE_ERR_SPACE,
MS_OLE_ERR_NOTEMPTY,
MS_OLE_ERR_BADARG
} MsOleErr;
typedef enum {
MsOleSeekSet,
MsOleSeekCur,
MsOleSeekEnd
} MsOleSeek;
typedef enum {
MsOleStorageT = 1,
MsOleStreamT = 2,
MsOleRootT = 5
} MsOleType;
typedef guint32 MsOlePos;
typedef gint32 MsOleSPos;
/*
#ifdef G_HAVE_GINT64
typedef guint64 MsOlePos;
typedef gint64 MsOleSPos;
#else
typedef guint32 MsOlePos;
typedef gint32 MsOleSPos;
#endif
*/
typedef struct _MsOle MsOle;
typedef struct _MsOleStat MsOleStat;
typedef struct _MsOleStream MsOleStream;
typedef struct _MsOleSysWrappers MsOleSysWrappers;
struct _MsOleSysWrappers {
int (*open2) (const char *pathname, int flags);
int (*open3) (const char *pathname, int flags, mode_t mode);
ssize_t (*read) (int fd, void *buf, size_t count);
int (*close) (int fd);
ssize_t (*write) (int fd, const void *buf, size_t count);
off_t (*lseek) (int fd, off_t offset, int whence);
int (*isregfile) (int fd);
int (*getfilesize) (int fd, guint32 *size);
};
struct _MsOleStat {
MsOleType type;
MsOlePos size;
};
#define ms_ole_open(fs,path) ms_ole_open_vfs ((fs), (path), TRUE, NULL)
extern MsOleErr ms_ole_open_vfs (MsOle **fs,
const char *path,
gboolean try_mmap,
MsOleSysWrappers *wrappers);
#define ms_ole_create(fs,path) ms_ole_create_vfs ((fs), (path), TRUE, NULL)
extern MsOleErr ms_ole_create_vfs (MsOle **fs,
const char *path,
int try_mmap,
MsOleSysWrappers *wrappers);
extern void ms_ole_destroy (MsOle **fs);
extern MsOleErr ms_ole_unlink (MsOle *fs,
const char *path);
extern MsOleErr ms_ole_directory (char ***names,
MsOle *fs,
const char *dirpath);
extern MsOleErr ms_ole_stat (MsOleStat *stat,
MsOle *fs,
const char *dirpath,
const char *name);
struct _MsOleStream {
MsOlePos size;
gint (*read_copy) (MsOleStream *stream,
guint8 *ptr,
MsOlePos length);
guint8 * (*read_ptr) (MsOleStream *stream,
MsOlePos length);
MsOleSPos (*lseek) (MsOleStream *stream,
MsOleSPos bytes,
MsOleSeek type);
MsOlePos (*tell) (MsOleStream *stream);
MsOlePos (*write) (MsOleStream *stream,
guint8 *ptr,
MsOlePos length);
/**
* Private.
**/
enum {
MsOleSmallBlock,
MsOleLargeBlock
} type;
MsOle *file;
void *pps; /* Straight PPS */
GArray *blocks; /* A list of the blocks in the file
if NULL: no file */
MsOlePos position; /* Current offset into file.
Points to the next byte to read */
};
#define MS_OLE_GET_GUINT8(p) (*((const guint8 *)(p) + 0))
#define MS_OLE_GET_GUINT16(p) (guint16)(*((const guint8 *)(p)+0) | \
(*((const guint8 *)(p)+1)<<8))
#define MS_OLE_GET_GUINT32(p) (guint32)(*((const guint8 *)(p)+0) | \
(*((const guint8 *)(p)+1)<<8) | \
(*((const guint8 *)(p)+2)<<16) | \
(*((const guint8 *)(p)+3)<<24))
#define MS_OLE_GET_GUINT64(p) (MS_OLE_GET_GUINT32(p) | \
(((guint32)MS_OLE_GET_GUINT32((const guint8 *)(p)+4))<<32))
#define MS_OLE_SET_GUINT8(p,n) (*((guint8 *)(p) + 0) = n)
#define MS_OLE_SET_GUINT16(p,n) ((*((guint8 *)(p)+0)=((n)&0xff)), \
(*((guint8 *)(p)+1)=((n)>>8)&0xff))
#define MS_OLE_SET_GUINT32(p,n) ((*((guint8 *)(p)+0)=((n))&0xff), \
(*((guint8 *)(p)+1)=((n)>>8)&0xff), \
(*((guint8 *)(p)+2)=((n)>>16)&0xff), \
(*((guint8 *)(p)+3)=((n)>>24)&0xff))
extern MsOleErr ms_ole_stream_open (MsOleStream ** const stream,
MsOle *fs,
const char *dirpath,
const char *name,
char mode);
extern MsOleErr ms_ole_stream_close (MsOleStream ** const stream);
extern MsOleErr ms_ole_stream_duplicate (MsOleStream ** const stream_copy,
const MsOleStream *
const stream);
extern void ms_ole_dump (guint8 const *ptr,
guint32 len);
extern void ms_ole_ref (MsOle *fs);
extern void ms_ole_unref (MsOle *fs);
extern void ms_ole_debug (MsOle *fs,
int magic);
#endif /* MS_OLE_H */
--- Added File ole.c in package Packages/Products/DCProject ---
//----------------------------------------------------------------------------//
// ole.c
// John Platten
// 01.12.01
//----------------------------------------------------------------------------//
#include <stdio.h>
#include "ms-ole.h"
#include "ms-ole-summary.h"
//----------------------------------------------------------------------------//
// GLOBALS
//----------------------------------------------------------------------------//
char str[512];
//----------------------------------------------------------------------------//
// PROTOTYPES
//----------------------------------------------------------------------------//
MsOle * _ms_ole_open (char *fileName);
MsOle * _ms_ole_open_body (char * jp_buf_ptr, int jp_buf_len);
void _ms_ole_destroy (MsOle *ole);
MsOleSummary * _ms_ole_summary_open (MsOle *ole);
void _ms_ole_summary_close (MsOleSummary *summary);
MsOleSummary * _ms_ole_docsummary_open (MsOle *f);
char * _ms_ole_summary_get_string (MsOleSummary *summary, int propertyId);
int _ms_ole_summary_get_long (MsOleSummary *summary, int propertyId);
short int _ms_ole_summary_get_short (MsOleSummary *summary, int propertyId);
char * _ms_ole_summary_get_time (MsOleSummary *summary, int propertyId);
//----------------------------------------------------------------------------//
MsOle * _ms_ole_open (char *fileName)
{
MsOle *ole = NULL;
ms_ole_open_vfs(&ole, fileName, FALSE, NULL);
// if (!ole) fprintf(stderr, ":ERROR:ms_ole_open_vfs:msOleErr:%x\n", ole);
return ole;
}
//----------------------------------------------------------------------------//
MsOle * _ms_ole_open_body (char * jp_buf_ptr, int jp_buf_len)
{
MsOle * msOle = NULL;
MsOleErr msOleErr;
char * fileName = "junk";
msOleErr = ms_ole_open_vfs_body(&msOle, fileName, FALSE, NULL, jp_buf_ptr, jp_buf_len);
// if (!msOle) fprintf(stderr, ":ERROR:ms_ole_open_vfs:msOleErr:%x\n", msOleErr);
return msOle;
}
//----------------------------------------------------------------------------//
void _ms_ole_destroy (MsOle *ole)
{
MsOle * myOle = ole;
ms_ole_destroy(&myOle);
}
//----------------------------------------------------------------------------//
MsOleSummary * _ms_ole_summary_open (MsOle *ole)
{
MsOleSummary *summary = NULL;
summary = ms_ole_summary_open(ole);
// if (!summary) fprintf(stderr, ":ERROR:_ms_ole_summary_open:summary:%x\n", summary);
return summary;
}
//----------------------------------------------------------------------------//
void _ms_ole_summary_close (MsOleSummary *summary)
{
ms_ole_summary_close(summary);
}
//----------------------------------------------------------------------------//
MsOleSummary * _ms_ole_docsummary_open (MsOle *f)
{
return ms_ole_docsummary_open(f);
}
//----------------------------------------------------------------------------//
char * _ms_ole_summary_get_string (MsOleSummary *summary, int propertyId)
{
char *str = NULL;
gboolean ret = FALSE;
return ms_ole_summary_get_string(summary, propertyId, &ret);
}
//----------------------------------------------------------------------------//
int _ms_ole_summary_get_long (MsOleSummary *summary, int propertyId)
{
gboolean ret = FALSE;
return ms_ole_summary_get_long(summary, propertyId, &ret);
}
//----------------------------------------------------------------------------//
short int _ms_ole_summary_get_short (MsOleSummary *summary, int propertyId)
{
gboolean ret = FALSE;
return ms_ole_summary_get_short(summary, propertyId, &ret);
}
//----------------------------------------------------------------------------//
char * _ms_ole_summary_get_time (MsOleSummary *summary, int propertyId)
{
GTimeVal timeval;
gboolean ret = FALSE;
timeval = ms_ole_summary_get_time(summary, propertyId, &ret);
strcpy(str, ctime(&timeval.tv_sec));
str[strlen(str)-1] = '\0';
return str;
}
//----------------------------------------------------------------------------//
--- Added File ole.i in package Packages/Products/DCProject ---
%module ole
%{
#include "ms-ole.h"
#include "ms-ole-summary.h"
%}
MsOle * _ms_ole_open (char *fileName);
MsOle * _ms_ole_open_body (char * jp_buf_ptr, int jp_buf_len);
void _ms_ole_destroy (MsOle *ole);
MsOleSummary * _ms_ole_summary_open (MsOle *ole);
void _ms_ole_summary_close (MsOleSummary *summary);
MsOleSummary * _ms_ole_docsummary_open (MsOle *f);
char * _ms_ole_summary_get_string (MsOleSummary *summary, int propertyId);
int _ms_ole_summary_get_long (MsOleSummary *summary, int propertyId);
short int _ms_ole_summary_get_short (MsOleSummary *summary, int propertyId);
char * _ms_ole_summary_get_time (MsOleSummary *summary, int propertyId);
--- Added File ole_wrap.c in package Packages/Products/DCProject ---
/*
* FILE : ole_wrap.c
*
* This file was automatically generated by :
* Simplified Wrapper and Interface Generator (SWIG)
* Version 1.1 (Build 883)
*
* Portions Copyright (c) 1995-1998
* The University of Utah and The Regents of the University of California.
* Permission is granted to distribute this file in any manner provided
* this notice remains intact.
*
* Do not make changes to this file--changes will be lost!
*
*/
#define SWIGCODE
/* Implementation : PYTHON */
#define SWIGPYTHON
/***********************************************************************
* $Header: /cvs-repository/Packages/Products/DCProject/CMF_MS_Files/src/libole/ole_wrap.c,v 1.1 2001/05/30 14:39:19 jack Exp $
* swig_lib/python/python.cfg
*
* Contains variable linking and pointer type-checking code.
************************************************************************/
#include <string.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "Python.h"
/* Definitions for Windows/Unix exporting */
#if defined(_WIN32) || defined(__WIN32__)
# if defined(_MSC_VER)
# define SWIGEXPORT(a) __declspec(dllexport) a
# else
# if defined(__BORLANDC__)
# define SWIGEXPORT(a) a _export
# else
# define SWIGEXPORT(a) a
# endif
# endif
#else
# define SWIGEXPORT(a) a
#endif
#ifdef SWIG_GLOBAL
#define SWIGSTATICRUNTIME(a) SWIGEXPORT(a)
#else
#define SWIGSTATICRUNTIME(a) static a
#endif
typedef struct {
char *name;
PyObject *(*get_attr)(void);
int (*set_attr)(PyObject *);
} swig_globalvar;
typedef struct swig_varlinkobject {
PyObject_HEAD
swig_globalvar **vars;
int nvars;
int maxvars;
} swig_varlinkobject;
/* ----------------------------------------------------------------------
swig_varlink_repr()
Function for python repr method
---------------------------------------------------------------------- */
static PyObject *
swig_varlink_repr(swig_varlinkobject *v)
{
v = v;
return PyString_FromString("<Global variables>");
}
/* ---------------------------------------------------------------------
swig_varlink_print()
Print out all of the global variable names
--------------------------------------------------------------------- */
static int
swig_varlink_print(swig_varlinkobject *v, FILE *fp, int flags)
{
int i = 0;
flags = flags;
fprintf(fp,"Global variables { ");
while (v->vars[i]) {
fprintf(fp,"%s", v->vars[i]->name);
i++;
if (v->vars[i]) fprintf(fp,", ");
}
fprintf(fp," }\n");
return 0;
}
/* --------------------------------------------------------------------
swig_varlink_getattr
This function gets the value of a variable and returns it as a
PyObject. In our case, we'll be looking at the datatype and
converting into a number or string
-------------------------------------------------------------------- */
static PyObject *
swig_varlink_getattr(swig_varlinkobject *v, char *n)
{
int i = 0;
char temp[128];
while (v->vars[i]) {
if (strcmp(v->vars[i]->name,n) == 0) {
return (*v->vars[i]->get_attr)();
}
i++;
}
sprintf(temp,"C global variable %s not found.", n);
PyErr_SetString(PyExc_NameError,temp);
return NULL;
}
/* -------------------------------------------------------------------
swig_varlink_setattr()
This function sets the value of a variable.
------------------------------------------------------------------- */
static int
swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p)
{
char temp[128];
int i = 0;
while (v->vars[i]) {
if (strcmp(v->vars[i]->name,n) == 0) {
return (*v->vars[i]->set_attr)(p);
}
i++;
}
sprintf(temp,"C global variable %s not found.", n);
PyErr_SetString(PyExc_NameError,temp);
return 1;
}
statichere PyTypeObject varlinktype = {
/* PyObject_HEAD_INIT(&PyType_Type) Note : This doesn't work on some machines */
PyObject_HEAD_INIT(0)
0,
"varlink", /* Type name */
sizeof(swig_varlinkobject), /* Basic size */
0, /* Itemsize */
0, /* Deallocator */
(printfunc) swig_varlink_print, /* Print */
(getattrfunc) swig_varlink_getattr, /* get attr */
(setattrfunc) swig_varlink_setattr, /* Set attr */
0, /* tp_compare */
(reprfunc) swig_varlink_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_mapping*/
0, /* tp_hash */
};
/* Create a variable linking object for use later */
SWIGSTATICRUNTIME(PyObject *)
SWIG_newvarlink(void)
{
swig_varlinkobject *result = 0;
result = PyMem_NEW(swig_varlinkobject,1);
varlinktype.ob_type = &PyType_Type; /* Patch varlinktype into a PyType */
result->ob_type = &varlinktype;
/* _Py_NewReference(result); Does not seem to be necessary */
result->nvars = 0;
result->maxvars = 64;
result->vars = (swig_globalvar **) malloc(64*sizeof(swig_globalvar *));
result->vars[0] = 0;
result->ob_refcnt = 0;
Py_XINCREF((PyObject *) result);
return ((PyObject*) result);
}
SWIGSTATICRUNTIME(void)
SWIG_addvarlink(PyObject *p, char *name,
PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p))
{
swig_varlinkobject *v;
v= (swig_varlinkobject *) p;
if (v->nvars >= v->maxvars -1) {
v->maxvars = 2*v->maxvars;
v->vars = (swig_globalvar **) realloc(v->vars,v->maxvars*sizeof(swig_globalvar *));
if (v->vars == NULL) {
fprintf(stderr,"SWIG : Fatal error in initializing Python module.\n");
exit(1);
}
}
v->vars[v->nvars] = (swig_globalvar *) malloc(sizeof(swig_globalvar));
v->vars[v->nvars]->name = (char *) malloc(strlen(name)+1);
strcpy(v->vars[v->nvars]->name,name);
v->vars[v->nvars]->get_attr = get_attr;
v->vars[v->nvars]->set_attr = set_attr;
v->nvars++;
v->vars[v->nvars] = 0;
}
/* -----------------------------------------------------------------------------
* Pointer type-checking
* ----------------------------------------------------------------------------- */
/* SWIG pointer structure */
typedef struct SwigPtrType {
char *name; /* Datatype name */
int len; /* Length (used for optimization) */
void *(*cast)(void *); /* Pointer casting function */
struct SwigPtrType *next; /* Linked list pointer */
} SwigPtrType;
/* Pointer cache structure */
typedef struct {
int stat; /* Status (valid) bit */
SwigPtrType *tp; /* Pointer to type structure */
char name[256]; /* Given datatype name */
char mapped[256]; /* Equivalent name */
} SwigCacheType;
static int SwigPtrMax = 64; /* Max entries that can be currently held */
static int SwigPtrN = 0; /* Current number of entries */
static int SwigPtrSort = 0; /* Status flag indicating sort */
static int SwigStart[256]; /* Starting positions of types */
static SwigPtrType *SwigPtrTable = 0; /* Table containing pointer equivalences */
/* Cached values */
#define SWIG_CACHESIZE 8
#define SWIG_CACHEMASK 0x7
static SwigCacheType SwigCache[SWIG_CACHESIZE];
static int SwigCacheIndex = 0;
static int SwigLastCache = 0;
/* Sort comparison function */
static int swigsort(const void *data1, const void *data2) {
SwigPtrType *d1 = (SwigPtrType *) data1;
SwigPtrType *d2 = (SwigPtrType *) data2;
return strcmp(d1->name,d2->name);
}
/* Register a new datatype with the type-checker */
SWIGSTATICRUNTIME(void)
SWIG_RegisterMapping(char *origtype, char *newtype, void *(*cast)(void *)) {
int i;
SwigPtrType *t = 0,*t1;
/* Allocate the pointer table if necessary */
if (!SwigPtrTable) {
SwigPtrTable = (SwigPtrType *) malloc(SwigPtrMax*sizeof(SwigPtrType));
}
/* Grow the table */
if (SwigPtrN >= SwigPtrMax) {
SwigPtrMax = 2*SwigPtrMax;
SwigPtrTable = (SwigPtrType *) realloc((char *) SwigPtrTable,SwigPtrMax*sizeof(SwigPtrType));
}
for (i = 0; i < SwigPtrN; i++) {
if (strcmp(SwigPtrTable[i].name,origtype) == 0) {
t = &SwigPtrTable[i];
break;
}
}
if (!t) {
t = &SwigPtrTable[SwigPtrN++];
t->name = origtype;
t->len = strlen(t->name);
t->cast = 0;
t->next = 0;
}
/* Check for existing entries */
while (t->next) {
if ((strcmp(t->name,newtype) == 0)) {
if (cast) t->cast = cast;
return;
}
t = t->next;
}
t1 = (SwigPtrType *) malloc(sizeof(SwigPtrType));
t1->name = newtype;
t1->len = strlen(t1->name);
t1->cast = cast;
t1->next = 0;
t->next = t1;
SwigPtrSort = 0;
}
/* Make a pointer value string */
SWIGSTATICRUNTIME(void)
SWIG_MakePtr(char *c, const void *ptr, char *type) {
static char hex[17] = "0123456789abcdef";
unsigned long p, s;
char result[24], *r;
r = result;
p = (unsigned long) ptr;
if (p > 0) {
while (p > 0) {
s = p & 0xf;
*(r++) = hex[s];
p = p >> 4;
}
*r = '_';
while (r >= result)
*(c++) = *(r--);
strcpy (c, type);
} else {
strcpy (c, "NULL");
}
}
/* Function for getting a pointer value */
SWIGSTATICRUNTIME(char *)
SWIG_GetPtr(char *c, void **ptr, char *t)
{
unsigned long p;
char temp_type[256], *name;
int i, len, start, end;
SwigPtrType *sp,*tp;
SwigCacheType *cache;
register int d;
p = 0;
/* Pointer values must start with leading underscore */
if (*c != '_') {
*ptr = (void *) 0;
if (strcmp(c,"NULL") == 0) return (char *) 0;
else c;
}
c++;
/* Extract hex value from pointer */
while (d = *c) {
if ((d >= '0') && (d <= '9'))
p = (p << 4) + (d - '0');
else if ((d >= 'a') && (d <= 'f'))
p = (p << 4) + (d - ('a'-10));
else
break;
c++;
}
*ptr = (void *) p;
if ((!t) || (strcmp(t,c)==0)) return (char *) 0;
if (!SwigPtrSort) {
qsort((void *) SwigPtrTable, SwigPtrN, sizeof(SwigPtrType), swigsort);
for (i = 0; i < 256; i++) SwigStart[i] = SwigPtrN;
for (i = SwigPtrN-1; i >= 0; i--) SwigStart[(int) (SwigPtrTable[i].name[1])] = i;
for (i = 255; i >= 1; i--) {
if (SwigStart[i-1] > SwigStart[i])
SwigStart[i-1] = SwigStart[i];
}
SwigPtrSort = 1;
for (i = 0; i < SWIG_CACHESIZE; i++) SwigCache[i].stat = 0;
}
/* First check cache for matches. Uses last cache value as starting point */
cache = &SwigCache[SwigLastCache];
for (i = 0; i < SWIG_CACHESIZE; i++) {
if (cache->stat && (strcmp(t,cache->name) == 0) && (strcmp(c,cache->mapped) == 0)) {
cache->stat++;
if (cache->tp->cast) *ptr = (*(cache->tp->cast))(*ptr);
return (char *) 0;
}
SwigLastCache = (SwigLastCache+1) & SWIG_CACHEMASK;
if (!SwigLastCache) cache = SwigCache;
else cache++;
}
/* Type mismatch. Look through type-mapping table */
start = SwigStart[(int) t[1]];
end = SwigStart[(int) t[1]+1];
sp = &SwigPtrTable[start];
/* Try to find a match */
while (start <= end) {
if (strncmp(t,sp->name,sp->len) == 0) {
name = sp->name;
len = sp->len;
tp = sp->next;
/* Try to find entry for our given datatype */
while(tp) {
if (tp->len >= 255) {
return c;
}
strcpy(temp_type,tp->name);
strncat(temp_type,t+len,255-tp->len);
if (strcmp(c,temp_type) == 0) {
strcpy(SwigCache[SwigCacheIndex].mapped,c);
strcpy(SwigCache[SwigCacheIndex].name,t);
SwigCache[SwigCacheIndex].stat = 1;
SwigCache[SwigCacheIndex].tp = tp;
SwigCacheIndex = SwigCacheIndex & SWIG_CACHEMASK;
/* Get pointer value */
*ptr = (void *) p;
if (tp->cast) *ptr = (*(tp->cast))(*ptr);
return (char *) 0;
}
tp = tp->next;
}
}
sp++;
start++;
}
return c;
}
/* New object-based GetPointer function. This uses the Python abstract
* object interface to automatically dereference the 'this' attribute
* of shadow objects. */
SWIGSTATICRUNTIME(char *)
SWIG_GetPtrObj(PyObject *obj, void **ptr, char *type) {
PyObject *sobj = obj;
char *str;
if (!PyString_Check(obj)) {
sobj = PyObject_GetAttrString(obj,"this");
if (!sobj) return "";
}
str = PyString_AsString(sobj);
return SWIG_GetPtr(str,ptr,type);
}
#ifdef __cplusplus
}
#endif
#define SWIG_init initole
#define SWIG_name "ole"
#include "ms-ole.h"
#include "ms-ole-summary.h"
#ifdef __cplusplus
extern "C" {
#endif
static PyObject *_wrap__ms_ole_open(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOle * _result;
char * _arg0;
char _ptemp[128];
self = self;
if(!PyArg_ParseTuple(args,"s:_ms_ole_open",&_arg0))
return NULL;
_result = (MsOle *)_ms_ole_open(_arg0);
if (_result) {
SWIG_MakePtr(_ptemp, (char *) _result,"_MsOle_p");
_resultobj = Py_BuildValue("s",_ptemp);
} else {
Py_INCREF(Py_None);
_resultobj = Py_None;
}
return _resultobj;
}
static PyObject *_wrap__ms_ole_open_body(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOle * _result;
char * _arg0;
int _arg1;
char _ptemp[128];
self = self;
if(!PyArg_ParseTuple(args,"s#:_ms_ole_open_body",&_arg0,&_arg1))
return NULL;
_result = (MsOle *)_ms_ole_open_body(_arg0,_arg1);
if (_result) {
SWIG_MakePtr(_ptemp, (char *) _result,"_MsOle_p");
_resultobj = Py_BuildValue("s",_ptemp);
} else {
Py_INCREF(Py_None);
_resultobj = Py_None;
}
return _resultobj;
}
static PyObject *_wrap__ms_ole_destroy(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOle * _arg0;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"O:_ms_ole_destroy",&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOle_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_destroy. Expected _MsOle_p.");
return NULL;
}
}
_ms_ole_destroy(_arg0);
Py_INCREF(Py_None);
_resultobj = Py_None;
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_open(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOleSummary * _result;
MsOle * _arg0;
PyObject * _argo0 = 0;
char _ptemp[128];
self = self;
if(!PyArg_ParseTuple(args,"O:_ms_ole_summary_open",&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOle_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_open. Expected _MsOle_p.");
return NULL;
}
}
_result = (MsOleSummary *)_ms_ole_summary_open(_arg0);
if (_result) {
SWIG_MakePtr(_ptemp, (char *) _result,"_MsOleSummary_p");
_resultobj = Py_BuildValue("s",_ptemp);
} else {
Py_INCREF(Py_None);
_resultobj = Py_None;
}
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_close(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOleSummary * _arg0;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"O:_ms_ole_summary_close",&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_close. Expected _MsOleSummary_p.");
return NULL;
}
}
_ms_ole_summary_close(_arg0);
Py_INCREF(Py_None);
_resultobj = Py_None;
return _resultobj;
}
static PyObject *_wrap__ms_ole_docsummary_open(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOleSummary * _result;
MsOle * _arg0;
PyObject * _argo0 = 0;
char _ptemp[128];
self = self;
if(!PyArg_ParseTuple(args,"O:_ms_ole_docsummary_open",&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOle_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_docsummary_open. Expected _MsOle_p.");
return NULL;
}
}
_result = (MsOleSummary *)_ms_ole_docsummary_open(_arg0);
if (_result) {
SWIG_MakePtr(_ptemp, (char *) _result,"_MsOleSummary_p");
_resultobj = Py_BuildValue("s",_ptemp);
} else {
Py_INCREF(Py_None);
_resultobj = Py_None;
}
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_get_string(PyObject *self, PyObject *args) {
PyObject * _resultobj;
char * _result;
MsOleSummary * _arg0;
int _arg1;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"Oi:_ms_ole_summary_get_string",&_argo0,&_arg1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_get_string. Expected _MsOleSummary_p.");
return NULL;
}
}
_result = (char *)_ms_ole_summary_get_string(_arg0,_arg1);
_resultobj = Py_BuildValue("s", _result);
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_get_long(PyObject *self, PyObject *args) {
PyObject * _resultobj;
int _result;
MsOleSummary * _arg0;
int _arg1;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"Oi:_ms_ole_summary_get_long",&_argo0,&_arg1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_get_long. Expected _MsOleSummary_p.");
return NULL;
}
}
_result = (int )_ms_ole_summary_get_long(_arg0,_arg1);
_resultobj = Py_BuildValue("i",_result);
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_get_short(PyObject *self, PyObject *args) {
PyObject * _resultobj;
short _result;
MsOleSummary * _arg0;
int _arg1;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"Oi:_ms_ole_summary_get_short",&_argo0,&_arg1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_get_short. Expected _MsOleSummary_p.");
return NULL;
}
}
_result = (short )_ms_ole_summary_get_short(_arg0,_arg1);
_resultobj = Py_BuildValue("h",_result);
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_get_time(PyObject *self, PyObject *args) {
PyObject * _resultobj;
char * _result;
MsOleSummary * _arg0;
int _arg1;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"Oi:_ms_ole_summary_get_time",&_argo0,&_arg1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_get_time. Expected _MsOleSummary_p.");
return NULL;
}
}
_result = (char *)_ms_ole_summary_get_time(_arg0,_arg1);
_resultobj = Py_BuildValue("s", _result);
return _resultobj;
}
static PyMethodDef oleMethods[] = {
{ "_ms_ole_summary_get_time", _wrap__ms_ole_summary_get_time, METH_VARARGS },
{ "_ms_ole_summary_get_short", _wrap__ms_ole_summary_get_short, METH_VARARGS },
{ "_ms_ole_summary_get_long", _wrap__ms_ole_summary_get_long, METH_VARARGS },
{ "_ms_ole_summary_get_string", _wrap__ms_ole_summary_get_string, METH_VARARGS },
{ "_ms_ole_docsummary_open", _wrap__ms_ole_docsummary_open, METH_VARARGS },
{ "_ms_ole_summary_close", _wrap__ms_ole_summary_close, METH_VARARGS },
{ "_ms_ole_summary_open", _wrap__ms_ole_summary_open, METH_VARARGS },
{ "_ms_ole_destroy", _wrap__ms_ole_destroy, METH_VARARGS },
{ "_ms_ole_open_body", _wrap__ms_ole_open_body, METH_VARARGS },
{ "_ms_ole_open", _wrap__ms_ole_open, METH_VARARGS },
{ NULL, NULL }
};
#ifdef __cplusplus
}
#endif
/*
* This table is used by the pointer type-checker
*/
static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = {
{ "_signed_long","_long",0},
{ "_long","_unsigned_long",0},
{ "_long","_signed_long",0},
{ "_unsigned_long","_long",0},
{ "_signed_int","_int",0},
{ "_unsigned_short","_short",0},
{ "_signed_short","_short",0},
{ "_unsigned_int","_int",0},
{ "_short","_unsigned_short",0},
{ "_short","_signed_short",0},
{ "_int","_unsigned_int",0},
{ "_int","_signed_int",0},
{0,0,0}};
static PyObject *SWIG_globals;
#ifdef __cplusplus
extern "C"
#endif
SWIGEXPORT(void) initole() {
PyObject *m, *d;
SWIG_globals = SWIG_newvarlink();
m = Py_InitModule("ole", oleMethods);
d = PyModule_GetDict(m);
{
int i;
for (i = 0; _swig_mapping[i].n1; i++)
SWIG_RegisterMapping(_swig_mapping[i].n1,_swig_mapping[i].n2,_swig_mapping[i].pcnv);
}
}
--- Added File setup.py in package Packages/Products/DCProject ---
#!/usr/bin/env python
from distutils.core import setup, Extension
setup(name = "ole",
version = "1.0",
description = "libole2 Interface",
author = "John Platten",
author_email = "jplatten@digicool.com",
ext_modules =
[('ole',
{ 'sources':
['ole_wrap.c',
'ole.c',
'version.c',
'ms-ole.c',
'ms-ole-vba.c',
'ms-ole-summary.c'],
'include_dirs': ['.'],
'includes':
['config.h',
'glibconfig.h',
'libole2.h',
'ms-ole.h',
'ms-ole-vba.h',
'ms-ole-summary.h'],
'libraries': ["glib"],
}
)]
)
--- Added File test-ole.c in package Packages/Products/DCProject ---
/**
* test-ole.c: OLE2 file format helper program,
* good for dumping OLE streams, and
* corresponding biff records, and hopefuly
* some more ...
*
* Author:
* Michael Meeks (michael@imaginator.com)
**/
#define TEST_DEBUG 0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* For ctime() */
#include <time.h>
#include <ms-ole.h>
#include <ms-ole-vba.h>
#include <ms-ole-summary.h>
#define BIFF_TYPES_FILE "biff-types.h"
#if TEST_DEBUG > 0
static char delim[]=":";
#else
static char delim[]=" ";
#endif
static char **arg_data = NULL;
static int arg_cur = 0;
typedef struct {
guint16 opcode;
char *name;
} GENERIC_TYPE;
static GPtrArray *biff_types = NULL;
static char *cur_dir = NULL;
static void
read_types (char *fname, GPtrArray **types)
{
FILE *file = fopen(fname, "r");
char buffer[1024];
*types = g_ptr_array_new ();
if (!file) {
char *newname = g_strconcat ("../", fname, NULL);
file = fopen (newname, "r");
}
if (!file) {
printf ("Can't find vital file '%s'\n", fname);
return;
}
while (!feof(file)) {
char *p;
fgets(buffer,1023,file);
for (p=buffer;*p;p++)
if (*p=='0' && *(p+1)=='x') {
GENERIC_TYPE *bt = g_new (GENERIC_TYPE,1);
char *name, *pt;
bt->opcode=strtol(p+2,0,16);
pt = buffer;
while (*pt && *pt != '#') pt++; /* # */
while (*pt && !isspace(*pt)) pt++; /* define */
while (*pt && isspace(*pt)) pt++; /* ' ' */
while (*pt && *pt != '_') pt++; /* BIFF_ */
name = *pt?pt+1:pt;
while (*pt && !isspace(*pt)) pt++;
bt->name=g_strndup(name, (pt-name));
g_ptr_array_add (*types, bt);
break;
}
}
fclose (file);
}
static char*
get_biff_opcode_name (guint16 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>0xff) {
if (bt->opcode == opcode)
return bt->name;
} else {
if (bt->opcode == (opcode&0xff))
return bt->name;
}
}
return "Unknown";
}
static void
list_files (MsOle *ole)
{
char **names;
MsOleErr result;
int lp;
result = ms_ole_directory (&names, ole, cur_dir);
if (result != MS_OLE_ERR_OK) {
g_warning ("Failed dir");
return;
}
if (!names[0])
printf ("Empty directory\n");
for (lp = 0; names[lp]; lp++) {
MsOleStat s;
result = ms_ole_stat (&s, ole, cur_dir, names[lp]);
if (s.type == MsOleStreamT)
if (names[lp][0] < 0x30) {
printf ("'\\%x%s' : length %d bytes\n",
names[lp][0], names[lp] + 1, s.size);
} else {
printf ("'%s : length %d bytes\n",
names[lp], s.size);
}
else
if (names[lp][0] < 0x30) {
printf ("'\\%d[%s]' : Storage ( directory )\n",
names[lp][0], names [lp] + 1);
} else {
printf ("'[%s] : Storage ( directory )\n",
names [lp]);
}
}
}
static void
list_commands ()
{
printf ("command can be one or all of:\n");
printf (" * ls: list files\n");
printf (" * cd: enter storage\n");
printf (" * biff <stream name>: dump biff records, merging continues\n");
printf (" * biffraw <stream name>: dump biff records no merge + raw data\n");
printf (" * dump <stream name>: dump stream\n");
printf (" * summary : dump summary info\n");
printf (" * docsummary : dump document summary info\n");
printf (" * debug : dump internal ole library status\n");
printf (" * tree : dump the tree\n");
printf (" * vba : attempt to dump vba \n");
printf (" Raw transfer commands\n");
printf (" * get <stream name> <fname>\n");
printf (" * put <fname> <stream name>\n");
printf (" * copyin [<fname>,]...\n");
printf (" * copyout [<fname>,]...\n");
printf (" * quit,exit,bye: exit\n");
}
static void
syntax_error (char *err)
{
if (err) {
printf("Error: '%s'\n",err);
exit(1);
}
printf ("Sytax:\n");
printf (" ole <ole-file> [-i] [commands...]\n\n");
printf (" -i: Interactive, queries for fresh commands\n\n");
list_commands ();
exit(1);
}
/* ---------------------------- End cut ---------------------------- */
static gboolean
simple_regexp (const char *regexp, const char *fname)
{
int i;
gboolean ret = TRUE;
g_return_val_if_fail (fname != NULL, FALSE);
g_return_val_if_fail (regexp != NULL, FALSE);
for (i = 0; regexp [i] && fname [i]; i++) {
if (regexp [i] == '.')
continue;
if (toupper (regexp [i]) != toupper (fname [i])) {
ret = FALSE;
break;
}
}
if (regexp [i] && regexp [i] == '*')
ret = TRUE;
else if (!regexp [i] && fname [i])
ret = FALSE;
/* if (ret)
printf ("'%s' matched '%s'\n", regexp, fname);*/
return ret;
}
/*
* This should take a path to check the directory out there.
*/
static char *
get_regexp_name (const char *regexp, const char *path, MsOle *ole)
{
char *res = NULL;
char **names;
MsOleErr result;
int lp;
result = ms_ole_directory (&names, ole, path);
if (result != MS_OLE_ERR_OK) {
g_warning ("Failed dir");
return NULL;
}
if (!names [0])
printf ("Empty directory\n");
for (lp = 0; names[lp]; lp++) {
if (simple_regexp (regexp, names [lp])) {
res = g_strdup (names [lp]);
break;
}
}
return res;
}
static void
enter_dir (MsOle *ole)
{
char *newpath, *ptr, *p;
p = arg_data [arg_cur++];
if (!p) {
printf ("Takes a directory argument\n");
return;
}
if (!g_strcasecmp (p, "..")) {
guint lp;
char **tmp;
GString *newp = g_string_new ("");
tmp = g_strsplit (cur_dir, "/", -1);
lp = 0;
if (!tmp[lp])
return;
while (tmp[lp+1]) {
g_string_sprintfa (newp, "%s/", tmp[lp]);
lp++;
}
g_free (cur_dir);
cur_dir = newp->str;
g_string_free (newp, FALSE);
} else {
MsOleStat s;
MsOleErr result;
ptr = get_regexp_name (p, cur_dir, ole);
if (!ptr)
return;
newpath = g_strconcat (cur_dir, ptr, "/", NULL);
result = ms_ole_stat (&s, ole, newpath, "");
if (result == MS_OLE_ERR_EXIST) {
printf ("Storage '%s' not found\n", ptr);
g_free (newpath);
return;
}
if (result != MS_OLE_ERR_OK) {
g_warning ("internal error");
g_free (newpath);
return;
}
if (s.type == MsOleStreamT) {
printf ("Trying to enter a stream. (%d)\n", s.type);
g_free (newpath);
return;
}
g_free (cur_dir);
cur_dir = newpath;
}
}
static MsOleErr
test_stream_open (MsOleStream ** const stream, MsOle *f,
const char *path, const char *fname, char mode)
{
MsOleErr err;
char *name;
name = get_regexp_name (fname, path, f);
if (name) {
err = ms_ole_stream_open (stream, f, path, name, mode);
g_free (name);
} else /* Fall back to original */
err = ms_ole_stream_open (stream, f, fname, name, mode);
return err;
}
static void
do_dump (MsOle *ole)
{
char *ptr;
MsOleStream *stream;
guint8 *buffer;
gchar *tname;
ptr = arg_data [arg_cur++];
if (!ptr) {
printf ("Need a stream name\n");
return;
}
tname = g_strdup (ptr);
if (strcmp(tname, "SummaryInformation") == 0) {
printf ("Changing name to prepend 005\n");
tname = "\05SummaryInformation";
}
if (strcmp(tname, "DocumentSummaryInformation") == 0) {
printf ("Changing name to prepend 005\n");
tname = "\05DocumentSummaryInformation";
}
if (test_stream_open (&stream, ole, cur_dir, tname, 'r') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", ptr);
return;
}
buffer = g_malloc (stream->size);
stream->read_copy (stream, buffer, stream->size);
printf ("Stream : '%s' length 0x%x\n", ptr, stream->size);
if (buffer)
ms_ole_dump (buffer, stream->size);
else
printf ("Failed read\n");
ms_ole_stream_close (&stream);
}
/*
* This is a massively cut down version ...
*/
typedef struct {
guint16 opcode;
guint32 length; /* NB. can be extended by a continue opcode */
guint8 *data;
guint32 streamPos;
MsOleStream *pos;
} BiffQuery;
static BiffQuery *
ms_biff_query_new (MsOleStream *ptr)
{
BiffQuery *bq ;
if (!ptr)
return 0;
bq = g_new0 (BiffQuery, 1);
bq->opcode = 0;
bq->length = 0;
bq->pos = ptr;
return bq;
}
static int
ms_biff_query_next (BiffQuery *bq)
{
guint8 tmp[4];
int ans=1;
if (!bq || bq->pos->position >= bq->pos->size)
return 0;
if (bq->data)
g_free (bq->data);
bq->streamPos = bq->pos->position;
if (!bq->pos->read_copy (bq->pos, tmp, 4))
return 0;
bq->opcode = MS_OLE_GET_GUINT16 (tmp);
bq->length = MS_OLE_GET_GUINT16 (tmp+2);
if (bq->length > 0) {
bq->data = g_new0 (guint8, bq->length);
if (!bq->pos->read_copy(bq->pos, bq->data, bq->length)) {
ans = 0;
g_free (bq->data);
bq->length = 0;
}
}
if (!bq->length) {
bq->data = NULL;
return 1;
}
return (ans);
}
static void
do_biff (MsOle *ole)
{
char *ptr;
MsOleStream *stream;
ptr = arg_data[arg_cur++];
if (!ptr) {
printf ("Need a stream name\n");
return;
}
if (test_stream_open (&stream, ole, cur_dir, ptr, 'r') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", ptr);
return;
}
{
BiffQuery *q = ms_biff_query_new (stream);
guint16 last_opcode=0xffff;
guint32 last_length=0;
guint32 count=0;
while (ms_biff_query_next(q)) {
if (q->opcode == last_opcode &&
q->length == last_length)
count++;
else {
if (count>0)
printf (" x %d\n", count+1);
else
printf ("\n");
count=0;
printf ("Opcode 0x%3x : %15s, length %d",
q->opcode, get_biff_opcode_name (q->opcode), q->length);
}
last_opcode=q->opcode;
last_length=q->length;
}
printf ("\n");
ms_ole_stream_close (&stream);
}
}
static void
do_biff_raw (MsOle *ole)
{
char *ptr;
MsOleStream *stream;
ptr = arg_data[arg_cur++];
if (!ptr) {
printf ("Need a stream name\n");
return;
}
if (test_stream_open (&stream, ole, cur_dir, ptr, 'r') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", ptr);
return;
}
{
guint8 data[4], *buffer;
buffer = g_new (guint8, 65550);
while (stream->read_copy (stream, data, 4)) {
guint32 len=MS_OLE_GET_GUINT16(data+2);
/* printf ("0x%4x Opcode 0x%3x : %15s, length 0x%x (=%d)\n", stream->position,
MS_OLE_GET_GUINT16(data), get_biff_opcode_name (MS_OLE_GET_GUINT16(data)),
len, len);*/
printf ("Opcode 0x%3x : %15s, length 0x%x (=%d)\n",
MS_OLE_GET_GUINT16(data), get_biff_opcode_name (MS_OLE_GET_GUINT16(data)),
len, len);
stream->read_copy (stream, buffer, len);
ms_ole_dump (buffer, len);
buffer[0]=0;
buffer[len-1]=0;
}
ms_ole_stream_close (&stream);
}
}
static void
really_get (MsOle *ole, char *from, char *to)
{
MsOleStream *stream;
if (test_stream_open (&stream, ole, cur_dir, from, 'r') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", from);
return;
} else {
guint8 *buffer = g_malloc (stream->size);
FILE *f = fopen (to, "w");
stream->read_copy (stream, buffer, stream->size);
printf ("Stream : '%s' length 0x%x\n", from, stream->size);
if (f && buffer) {
fwrite (buffer, 1, stream->size, f);
fclose (f);
} else
printf ("Failed write to '%s'\n", to);
ms_ole_stream_close (&stream);
}
}
static void
do_get (MsOle *ole)
{
char *from, *to;
from = arg_data[arg_cur++];
if (!from)
to = NULL;
else
to = arg_data[arg_cur++];
really_get (ole, from, to);
}
static void
really_put (MsOle *ole, char *from, char *to)
{
MsOleStream *stream;
char buffer[8200];
if (!from || !to) {
printf ("Null name\n");
return;
}
if (test_stream_open (&stream, ole, cur_dir, to, 'w') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", to);
return;
} else {
FILE *f = fopen (from, "r");
size_t len;
int block=0;
if (!f || !stream) {
printf ("Failed write\n");
return;
}
stream->lseek (stream, 0, MsOleSeekSet);
do {
guint32 lenr = 1+ (int)(8192.0*rand()/(RAND_MAX+1.0));
len = fread (buffer, 1, lenr, f);
printf ("Transfering block %d = %d bytes\n", block++, len);
stream->write (stream, buffer, len);
} while (!feof(f) && len>0);
fclose (f);
ms_ole_stream_close (&stream);
}
}
static void
do_summary (MsOle *ole)
{
MsOleSummary *si;
MsOleSummaryPreview preview;
gboolean ok;
gchar *txt;
guint32 num;
GTimeVal timeval;
si = ms_ole_summary_open (ole);
if (!si) {
printf ("No summary information\n");
return;
}
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_TITLE, &ok);
if (ok)
printf ("The title is %s\n", txt);
else
printf ("no title found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_SUBJECT, &ok);
if (ok)
printf ("The subject is %s\n", txt);
else
printf ("no subject found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_AUTHOR, &ok);
if (ok)
printf ("The author is %s\n", txt);
else
printf ("no author found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_KEYWORDS, &ok);
if (ok)
printf ("The keywords are %s\n", txt);
else
printf ("no keywords found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_COMMENTS, &ok);
if (ok)
printf ("The comments are %s\n", txt);
else
printf ("no comments found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_TEMPLATE, &ok);
if (ok)
printf ("The template was %s\n", txt);
else
printf ("no template found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_LASTAUTHOR, &ok);
if (ok)
printf ("The last author was %s\n", txt);
else
printf ("no last author found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_REVNUMBER, &ok);
if (ok)
printf ("The rev no was %s\n", txt);
else
printf ("no rev no found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_APPNAME, &ok);
if (ok)
printf ("The app name was %s\n", txt);
else
printf ("no app name found\n");
g_free (txt);
timeval = ms_ole_summary_get_time (si, MS_OLE_SUMMARY_TOTAL_EDITTIME, &ok);
if (ok)
printf ("Total edit time is %ld", timeval.tv_sec);
else
printf ("no total edit time found\n");
timeval = ms_ole_summary_get_time (si, MS_OLE_SUMMARY_LASTPRINTED, &ok);
if (ok)
printf ("Last printed at %s", ctime (&timeval.tv_sec));
else
printf ("no last printed time found\n");
timeval = ms_ole_summary_get_time (si, MS_OLE_SUMMARY_CREATED, &ok);
if (ok)
printf ("Was created at %s", ctime (&timeval.tv_sec));
else
printf ("no creation time found\n");
timeval = ms_ole_summary_get_time (si, MS_OLE_SUMMARY_LASTSAVED, &ok);
if (ok)
printf ("Last saved at %s", ctime (&timeval.tv_sec));
else
printf ("no last saved time found\n");
num = ms_ole_summary_get_long (si, MS_OLE_SUMMARY_PAGECOUNT, &ok);
if (ok)
printf ("PageCount is %d\n", num);
else
printf ("no pagecount found\n");
num = ms_ole_summary_get_long (si, MS_OLE_SUMMARY_WORDCOUNT, &ok);
if (ok)
printf ("WordCount is %d\n", num);
else
printf ("no wordcount found\n");
num = ms_ole_summary_get_long (si, MS_OLE_SUMMARY_CHARCOUNT, &ok);
if (ok)
printf ("CharCount is %d\n", num);
else
printf ("no charcount found\n");
num = ms_ole_summary_get_long (si, MS_OLE_SUMMARY_SECURITY, &ok);
if (ok)
printf ("Security is %d\n", num);
else
printf ("no security found\n");
num = ms_ole_summary_get_short (si, MS_OLE_SUMMARY_CODEPAGE, &ok);
if (ok)
printf ("CodePage is %d\n", num);
else
printf ("no codepage found\n");
preview = ms_ole_summary_get_preview (si, MS_OLE_SUMMARY_THUMBNAIL, &ok);
if (ok) {
printf ("preview is %d bytes long\n", preview.len);
ms_ole_summary_preview_destroy (preview);
} else
printf ("no preview found\n");
ms_ole_summary_close (si);
}
static void
do_docsummary (MsOle *ole)
{
MsOleSummary *si;
gboolean ok;
gchar *txt;
si = ms_ole_docsummary_open (ole);
if (!si) {
printf ("No document summary information\n");
return;
}
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_CATEGORY, &ok);
if (ok)
printf ("The category is %s\n", txt);
else
printf ("no category found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_PRESFORMAT, &ok);
if (ok)
printf ("The presformat is %s\n", txt);
else
printf ("no presformat found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_MANAGER, &ok);
if (ok)
printf ("The manager is %s\n", txt);
else
printf ("no manager found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_COMPANY, &ok);
if (ok)
printf ("The company is %s\n", txt);
else
printf ("no company found\n");
g_free (txt);
ms_ole_summary_close (si);
}
static void
do_put (MsOle *ole)
{
char *from, *to;
from = arg_data[arg_cur++];
if (!from)
to = NULL;
else
to = arg_data[arg_cur++];
if (!from || !to) {
printf ("put <filename> <stream>\n");
return;
}
really_put (ole, from, to);
}
static void
do_copyin (MsOle *ole)
{
char *from;
do {
from = arg_data[arg_cur++];
if (from)
really_put (ole, from, from);
} while (from);
}
static void
do_copyout (MsOle *ole)
{
char *from;
do {
from = arg_data[arg_cur++];
if (from)
really_get (ole, from, from);
} while (from);
}
static void
dump_vba (MsOle *f)
{
const char *vbapath = "/_VBA_PROJECT_CUR";
char **dir;
char *txt;
int i;
int module_count;
MsOleStream *s;
MsOleStat st;
if (ms_ole_stat (&st, f, vbapath, "") != MS_OLE_ERR_OK ||
st.type == MsOleStreamT) {
printf ("No valid VBA found\n");
return;
}
if (test_stream_open (&s, f, vbapath, "PROJECT", 'r') !=
MS_OLE_ERR_OK) {
printf ("No project file... wierd\n");
} else {
txt = g_new (guint8, s->size);
if (!s->read_copy (s, txt, s->size))
printf ("Failed to read project stream\n");
else {
printf ("----------\n");
printf ("Project file:\n");
printf ("%s", txt);
printf ("----------\n");
}
ms_ole_stream_close (&s);
g_free (txt);
}
txt = g_strconcat (vbapath, "/VBA", NULL);
if (ms_ole_directory (&dir, f, txt) != MS_OLE_ERR_OK) {
printf ("No VBA subdirectory found");
g_free (txt);
return;
}
module_count = 0;
for (i = 0; dir [i]; i++) {
if (test_stream_open (&s, f, txt, dir[i], 'r') !=
MS_OLE_ERR_OK)
printf ("Error opening %s\n", dir [i]);
else {
MsOleVba *vba;
vba = ms_ole_vba_open (s);
if (!vba)
g_warning ("Stream '%s' not VBA", dir [i]);
else {
module_count++;
while (!ms_ole_vba_eof (vba))
printf ("%c", ms_ole_vba_getc (vba));
}
ms_ole_vba_close (vba);
ms_ole_stream_close (&s);
}
}
if (!module_count)
printf ("Strange no modules found\n");
g_free (txt);
}
int
main_original (int argc, char **argv)
{
MsOle *ole;
int lp, exit = 0, interact = 0;
char *buffer = g_new (char, 1024) ;
if (argc<2)
syntax_error(0);
printf ("Ole file '%s'\n", argv[1]);
if (ms_ole_open_vfs (&ole, argv[1], TRUE, NULL)
!= MS_OLE_ERR_OK) {
printf ("Creating new file '%s'\n", argv[1]);
if (ms_ole_create_vfs (&ole, argv[1], TRUE, NULL)
!= MS_OLE_ERR_OK)
syntax_error ("Can't open file or create new one");
}
if (argc<=2)
syntax_error ("Need command or -i");
if (argc>2 && argv[argc-1][0]=='-'
&& argv[argc-1][1]=='i')
interact=1;
else {
char *str=g_strdup(argv[2]) ;
for (lp=3;lp<argc;lp++)
str = g_strconcat(str," ",argv[lp],NULL); /* FIXME Mega leak :-) */
buffer = str; /* and again */
}
cur_dir = g_strdup ("/");
do
{
char *ptr;
if (interact) {
fprintf (stdout,"> ");
fflush (stdout);
fgets (buffer, 1023, stdin);
}
arg_data = g_strsplit (g_strchomp (buffer), delim, -1);
arg_cur = 0;
if (!arg_data && interact) continue;
if (!interact)
printf ("Command : '%s'\n", arg_data[0]);
ptr = arg_data[arg_cur++];
if (!ptr)
continue;
if (g_strcasecmp (ptr, "ls") == 0)
list_files (ole);
else if (g_strcasecmp (ptr, "cd") == 0)
enter_dir (ole);
else if (g_strcasecmp (ptr, "dump") == 0)
do_dump (ole);
else if (g_strcasecmp (ptr, "biff") == 0)
do_biff (ole);
else if (g_strcasecmp (ptr, "biffraw") == 0)
do_biff_raw (ole);
else if (g_strcasecmp (ptr, "get") == 0)
do_get (ole);
else if (g_strcasecmp (ptr, "put") == 0)
do_put (ole);
else if (g_strcasecmp (ptr, "copyin") == 0)
do_copyin (ole);
else if (g_strcasecmp (ptr, "copyout") == 0)
do_copyout (ole);
else if (g_strcasecmp (ptr, "summary") == 0)
do_summary (ole);
else if (g_strcasecmp (ptr, "docsummary") == 0)
do_docsummary (ole);
else if (g_strcasecmp (ptr, "debug") == 0)
ms_ole_debug (ole, 1);
else if (g_strcasecmp (ptr, "tree") == 0)
ms_ole_debug (ole, 2);
else if (g_strcasecmp (ptr, "vba") == 0)
dump_vba (ole);
else if (g_strcasecmp (ptr,"help") == 0 ||
g_strcasecmp (ptr,"?") == 0 ||
g_strcasecmp (ptr,"info") == 0 ||
g_strcasecmp (ptr,"man") == 0)
list_commands ();
else if (g_strcasecmp (ptr,"exit") == 0 ||
g_strcasecmp (ptr,"quit") == 0 ||
g_strcasecmp (ptr,"q") == 0 ||
g_strcasecmp (ptr,"bye") == 0)
exit = 1;
}
while (!exit && interact);
ms_ole_destroy (&ole);
return 0;
}
//----------------------------------------------------------------------------//
int main_file (int argc, char **argv)
{
MsOle *ole;
// int lp, exit = 0, interact = 0;
// char *buffer = g_new (char, 1024) ;
printf("\n");
ms_ole_open_vfs (&ole, argv[1], FALSE, NULL);
do_summary (ole);
do_docsummary (ole);
ms_ole_destroy (&ole);
printf("\n");
return 0;
}
//----------------------------------------------------------------------------//
#define JP_MAX_BUF_LEN 100000
unsigned char jp_buf_buf[JP_MAX_BUF_LEN+1];
MsOle *jp_msOle;
int main_body (int argc, char **argv)
{
MsOle *msOle;
MsOleErr msOleErr;
int fd;
unsigned char *jp_buf_ptr;
size_t jp_buf_len;
fd = open(argv[1], O_RDONLY);
jp_buf_ptr = jp_buf_buf;
jp_buf_len = read(fd, jp_buf_ptr, JP_MAX_BUF_LEN);
close(fd);
msOleErr = ms_ole_open_vfs_body (&jp_msOle, argv[1], FALSE, NULL, jp_buf_ptr, jp_buf_len);
do_summary(jp_msOle);
do_docsummary(jp_msOle);
ms_ole_destroy(&jp_msOle);
}
//----------------------------------------------------------------------------//
int main (int argc, char **argv)
{
printf("\n");
main_file(argc, argv);
main_body(argc, argv);
printf("\n");
return 0;
}
//----------------------------------------------------------------------------//
--- Added File version.c in package Packages/Products/DCProject ---
int libole2_major_version = 0;
int libole2_minor_version = 1;
int libole2_micro_version = 7;
--- Added File config.h in package CMF ---
/* config.h. Generated automatically by configure. */
#ifndef CONFIG_H_CALLED
#define CONFIG_H_CALLED 1
/* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define to empty if the keyword does not work. */
/* #undef const */
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
/* #undef HAVE_SYS_WAIT_H */
/* Define if you have the wait3 system call. */
/* #undef HAVE_WAIT3 */
/* Define if you have the waitpid system call. */
/* #undef HAVE_WAITPID */
/* Define as the return type of signal handlers (int or void). */
/* #undef RETSIGTYPE */
/* Define if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* #undef HAVE_POSIX_SIGNALS */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef pid_t */
/* Define if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the <sys/file.h> header file. */
#define HAVE_SYS_FILE_H 1
/* Define if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if you want zlib to uncompress wmf files */
/* #undef SYSTEM_ZLIB */
/* Define if you have libwmf and want it to convert wmf to gif files */
#define HAVE_WMF 1
/* Define if you have freetype*/
#define HAVE_TTF 1
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if defined(HAVE_ERRNO_H)
#include <errno.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
/* #include <dirent.h> */
#include <stdarg.h>
/*
#include <getopt.h>
*/
#define MATCHED_TYPE 1
/* #undef WORDS_BIGENDIAN */
#define XML_BYTE_ORDER 12
#if defined(__GNUC__) && !defined(WORDS_BIGENDIAN) && defined(MATCHED_TYPE)
#define NO_HOLES
#endif
/* define if you have iconv */
#define USE_ICONV 1
/* define if you have iconv but do not have windows codepage to unicode support */
/* #undef MUST_USE_INTERNAL_ICONV_TABLE */
/* define if you have libpng */
#define HasPNG 1
/* Define if you have the memcpy function. */
#define HAVE_MEMCPY 1
#ifndef HAVE_MEMCPY
#define memcpy(d, s, n) bcopy ((s), (d), (n))
#endif /* not HAVE_MEMCPY */
#define HAVE_MMAP 1
#endif /* CONFIG_H_CALLED */
--- Added File glibconfig.h in package CMF ---
/* glibconfig.h
*
* This is a generated file. Please modify `configure.in'
*/
#ifndef GLIBCONFIG_H
#define GLIBCONFIG_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <limits.h>
#include <float.h>
#define GLIB_HAVE_SYS_POLL_H
#define G_MINFLOAT FLT_MIN
#define G_MAXFLOAT FLT_MAX
#define G_MINDOUBLE DBL_MIN
#define G_MAXDOUBLE DBL_MAX
#define G_MINSHORT SHRT_MIN
#define G_MAXSHORT SHRT_MAX
#define G_MININT INT_MIN
#define G_MAXINT INT_MAX
#define G_MINLONG LONG_MIN
#define G_MAXLONG LONG_MAX
typedef signed char gint8;
typedef unsigned char guint8;
typedef signed short gint16;
typedef unsigned short guint16;
typedef signed int gint32;
typedef unsigned int guint32;
#if defined (__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
# define G_GNUC_EXTENSION __extension__
#else
# define G_GNUC_EXTENSION
#endif
#define G_HAVE_GINT64 1
G_GNUC_EXTENSION typedef signed long long gint64;
G_GNUC_EXTENSION typedef unsigned long long guint64;
#define G_GINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##LL))
#define GPOINTER_TO_INT(p) ((gint) (p))
#define GPOINTER_TO_UINT(p) ((guint) (p))
#define GINT_TO_POINTER(i) ((gpointer) (i))
#define GUINT_TO_POINTER(u) ((gpointer) (u))
#ifdef NeXT /* @#%@! NeXTStep */
# define g_ATEXIT(proc) (!atexit (proc))
#else
# define g_ATEXIT(proc) (atexit (proc))
#endif
#define g_memmove(d,s,n) G_STMT_START { memmove ((d), (s), (n)); } G_STMT_END
#define GLIB_MAJOR_VERSION 1
#define GLIB_MINOR_VERSION 2
#define GLIB_MICRO_VERSION 8
#define G_VA_COPY __va_copy
#ifdef __cplusplus
#define G_HAVE_INLINE 1
#else /* !__cplusplus */
#define G_HAVE_INLINE 1
#define G_HAVE___INLINE 1
#define G_HAVE___INLINE__ 1
#endif /* !__cplusplus */
#define G_THREADS_ENABLED
#define G_THREADS_IMPL_POSIX
typedef struct _GStaticMutex GStaticMutex;
struct _GStaticMutex
{
struct _GMutex *runtime_mutex;
union {
char pad[24];
double dummy_double;
void *dummy_pointer;
long dummy_long;
} aligned_pad_u;
};
#define G_STATIC_MUTEX_INIT { NULL, { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } }
#define g_static_mutex_get_mutex(mutex) (g_thread_use_default_impl ? ((GMutex*) &((mutex)->aligned_pad_u)) : g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex)))
#define GINT16_TO_LE(val) ((gint16) (val))
#define GUINT16_TO_LE(val) ((guint16) (val))
#define GINT16_TO_BE(val) ((gint16) GUINT16_SWAP_LE_BE (val))
#define GUINT16_TO_BE(val) (GUINT16_SWAP_LE_BE (val))
#define GINT32_TO_LE(val) ((gint32) (val))
#define GUINT32_TO_LE(val) ((guint32) (val))
#define GINT32_TO_BE(val) ((gint32) GUINT32_SWAP_LE_BE (val))
#define GUINT32_TO_BE(val) (GUINT32_SWAP_LE_BE (val))
#define GINT64_TO_LE(val) ((gint64) (val))
#define GUINT64_TO_LE(val) ((guint64) (val))
#define GINT64_TO_BE(val) ((gint64) GUINT64_SWAP_LE_BE (val))
#define GUINT64_TO_BE(val) (GUINT64_SWAP_LE_BE (val))
#define GLONG_TO_LE(val) ((glong) GINT32_TO_LE (val))
#define GULONG_TO_LE(val) ((gulong) GUINT32_TO_LE (val))
#define GLONG_TO_BE(val) ((glong) GINT32_TO_BE (val))
#define GULONG_TO_BE(val) ((gulong) GUINT32_TO_BE (val))
#define GINT_TO_LE(val) ((gint) GINT32_TO_LE (val))
#define GUINT_TO_LE(val) ((guint) GUINT32_TO_LE (val))
#define GINT_TO_BE(val) ((gint) GINT32_TO_BE (val))
#define GUINT_TO_BE(val) ((guint) GUINT32_TO_BE (val))
#define G_BYTE_ORDER G_LITTLE_ENDIAN
#define GLIB_SYSDEF_POLLIN =1
#define GLIB_SYSDEF_POLLOUT =4
#define GLIB_SYSDEF_POLLPRI =2
#define GLIB_SYSDEF_POLLERR =8
#define GLIB_SYSDEF_POLLHUP =16
#define GLIB_SYSDEF_POLLNVAL =32
#define G_HAVE_WCHAR_H 1
#define G_HAVE_WCTYPE_H 1
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* GLIBCONFIG_H */
--- Added File libole2.h in package CMF ---
#include "ms-ole.h"
#include "ms-ole-summary.h"
extern int libole2_major_version;
extern int libole2_minor_version;
extern int libole2_micro_version;
#define LIBOLE2_MAJOR_VERSION 0
#define LIBOLE2_MINOR_VERSION 1
#define LIBOLE2_MICRO_VERSION 7
--- Added File ms-ole-summary.c in package CMF ---
/**
* ms-ole-summary.c: MS Office OLE support
*
* Authors:
* Michael Meeks (mmeeks@gnu.org)
* Frank Chiulli (fc-linux@home.com)
* From work by:
* Caolan McNamara (Caolan.McNamara@ul.ie)
* Built on work by:
* Somar Software's CPPSUM (http://www.somar.com)
**/
#include <config.h>
#include <glib.h>
#include <stdio.h>
#include <ms-ole.h>
#include <ms-ole-summary.h>
#define SUMMARY_ID(x) ((x) & 0xff)
typedef struct {
guint32 offset;
guint32 id;
MsOlePropertySetID ps_id;
} item_t;
const guint32 sum_fmtid[4] = {
0xF29F85E0,
0x10684FF9,
0x000891AB,
0xD9B3272B
};
const guint32 doc_fmtid[4] = {
0xD5CDD502,
0x101B2E9C,
0x00089793,
0xAEF92C2B
};
const guint32 user_fmtid[4] = {
0XD5CDD505,
0X101B2E9C,
0X00089793,
0XAEF92C2B
};
static gboolean
read_items (MsOleSummary *si, MsOlePropertySetID ps_id)
{
gint sect;
for (sect = 0; sect < si->sections->len; sect++) {
MsOleSummarySection st;
guint8 data[8];
gint i;
st = g_array_index (si->sections, MsOleSummarySection, sect);
if (st.ps_id != ps_id)
continue;
si->s->lseek (si->s, st.offset, MsOleSeekSet);
if (!si->s->read_copy (si->s, data, 8))
return FALSE;
st.bytes = MS_OLE_GET_GUINT32 (data);
st.props = MS_OLE_GET_GUINT32 (data + 4);
if (st.props == 0)
continue;
for (i = 0; i < st.props; i++) {
item_t item;
if (!si->s->read_copy (si->s, data, 8))
return FALSE;
item.id = MS_OLE_GET_GUINT32 (data);
item.offset = MS_OLE_GET_GUINT32 (data + 4);
item.offset = item.offset + st.offset;
item.ps_id = ps_id;
g_array_append_val (si->items, item);
}
}
return TRUE;
}
typedef struct {
MsOleSummaryPID id;
guint32 len;
guint8 *data;
} write_item_t;
#define PROPERTY_HDR_LEN 8
#define PROPERTY_DESC_LEN 8
static void
write_items (MsOleSummary *si)
{
MsOlePos cur_pos;
MsOlePos pos = 48; /* magic offset see: _create_stream */
guint8 data[PROPERTY_DESC_LEN];
guint8 fill_data[] = {0, 0, 0, 0};
guint32 i, num;
guint32 offset = 0;
GList *l;
/*
* Write out the property descriptors.
* Keep track of the number of properties and number of bytes for the properties.
*/
si->s->lseek (si->s, pos + PROPERTY_HDR_LEN, MsOleSeekSet);
l = si->write_items;
num = g_list_length (l);
i = 0;
offset = PROPERTY_HDR_LEN + num * PROPERTY_DESC_LEN;
while (l) {
write_item_t *w = l->data;
g_return_if_fail (w != NULL);
/*
* The offset is calculated from the start of the
* properties header. The offset must be on a
* 4-byte boundary. Therefore all data written must be
* in multiples of 4-bytes.
*/
MS_OLE_SET_GUINT32 (data + 0, w->id & 0xff);
MS_OLE_SET_GUINT32 (data + 4, offset);
si->s->write (si->s, data, PROPERTY_DESC_LEN);
offset += w->len;
if ((w->len & 0x3) > 0)
offset += (4 - (w->len & 0x3));
i++;
l = g_list_next (l);
}
g_return_if_fail (i == num);
/*
* Write out the section header.
*/
si->s->lseek (si->s, pos, MsOleSeekSet);
MS_OLE_SET_GUINT32 (data + 0, offset);
MS_OLE_SET_GUINT32 (data + 4, i);
si->s->write (si->s, data, PROPERTY_HDR_LEN);
/*
* Write out the property values.
* Keep track of the last position written to.
*/
cur_pos = pos + PROPERTY_HDR_LEN + num*PROPERTY_DESC_LEN;
si->s->lseek (si->s, cur_pos, MsOleSeekSet);
l = si->write_items;
while (l) {
write_item_t *w = l->data;
si->s->write (si->s, w->data, w->len);
cur_pos += w->len;
l = g_list_next (l);
/*
* Write out any fill.
*/
if ((w->len & 0x3) > 0) {
cur_pos += (4 - (w->len & 0x3));
si->s->write (si->s, fill_data, 4 - (w->len & 0x3));
}
}
/*
* Pad it out to a BB file.
*/
{
int i;
for (i = cur_pos; i < 0x1000; i+=4)
si->s->write (si->s, fill_data, 4);
}
}
/**
* ms_ole_summary_open_stream:
* @stream: stream object
* @psid: Property Set ID, indicates which property set to open
*
* Opens @s as a summary stream, returns NULL on failure.
*
* Return value: %NULL if unable to open summary stream or a pointer to the
* Summary Stream.
**/
MsOleSummary *
ms_ole_summary_open_stream (MsOleStream *stream,
const MsOlePropertySetID psid)
{
guint8 data[64];
guint16 byte_order;
gboolean panic = FALSE;
guint32 os_version;
MsOleSummary *si;
gint i, sections;
g_return_val_if_fail (stream != NULL, NULL);
if (!stream->read_copy (stream, data, 28))
return NULL;
si = g_new (MsOleSummary, 1);
si->s = stream;
si->write_items = NULL;
si->sections = NULL;
si->items = NULL;
si->read_mode = TRUE;
byte_order = MS_OLE_GET_GUINT16(data);
if (byte_order != 0xfffe)
panic = TRUE;
if (MS_OLE_GET_GUINT16 (data + 2) != 0) /* Format */
panic = TRUE;
os_version = MS_OLE_GET_GUINT32 (data + 4);
for (i = 0; i < 16; i++)
si->class_id[i] = data[8 + i];
sections = MS_OLE_GET_GUINT32 (data + 24);
if (panic) {
ms_ole_summary_close (si);
return NULL;
}
si->sections = g_array_new (FALSE, FALSE, sizeof (MsOleSummarySection));
for (i = 0; i < sections; i++) {
MsOleSummarySection sect;
if (!stream->read_copy (stream, data, 16 + 4)) {
ms_ole_summary_close (si);
return NULL;
}
if (psid == MS_OLE_PS_SUMMARY_INFO) {
if (MS_OLE_GET_GUINT32 (data + 0) == sum_fmtid[0] &&
MS_OLE_GET_GUINT32 (data + 4) == sum_fmtid[1] &&
MS_OLE_GET_GUINT32 (data + 8) == sum_fmtid[2] &&
MS_OLE_GET_GUINT32 (data + 12) == sum_fmtid[3] ) {
si->ps_id = MS_OLE_PS_SUMMARY_INFO;
sect.ps_id = MS_OLE_PS_SUMMARY_INFO;
} else {
ms_ole_summary_close (si);
return NULL;
}
} else if (psid == MS_OLE_PS_DOCUMENT_SUMMARY_INFO) {
if (MS_OLE_GET_GUINT32 (data + 0) == doc_fmtid[0] &&
MS_OLE_GET_GUINT32 (data + 4) == doc_fmtid[1] &&
MS_OLE_GET_GUINT32 (data + 8) == doc_fmtid[2] &&
MS_OLE_GET_GUINT32 (data + 12) == doc_fmtid[3] ) {
si->ps_id = MS_OLE_PS_DOCUMENT_SUMMARY_INFO;
sect.ps_id = MS_OLE_PS_DOCUMENT_SUMMARY_INFO;
} else if (MS_OLE_GET_GUINT32 (data + 0) == user_fmtid[0] &&
MS_OLE_GET_GUINT32 (data + 4) == user_fmtid[1] &&
MS_OLE_GET_GUINT32 (data + 8) == user_fmtid[2] &&
MS_OLE_GET_GUINT32 (data + 12) == user_fmtid[3] ) {
si->ps_id = MS_OLE_PS_DOCUMENT_SUMMARY_INFO;
sect.ps_id = MS_OLE_PS_USER_DEFINED_SUMMARY_INFO;
} else {
ms_ole_summary_close (si);
return NULL;
}
}
sect.offset = MS_OLE_GET_GUINT32 (data + 16);
g_array_append_val (si->sections, sect);
/* We want to read the offsets of the items here into si->items */
}
si->items = g_array_new (FALSE, FALSE, sizeof (item_t));
for (i = 0; i < sections; i++) {
MsOleSummarySection st;
st = g_array_index (si->sections, MsOleSummarySection, i);
if (!read_items (si, st.ps_id)) {
// JPP g_warning ("Serious error reading items");
ms_ole_summary_close (si);
return NULL;
}
}
return si;
}
/**
* ms_ole_summary_open:
* @f: filesystem object.
*
* Opens the SummaryInformation stream, returns NULL on failure.
*
* Return value: %NULL if unable to open summary stream or a pointer to the
* SummaryInformation Stream.
**/
MsOleSummary *
ms_ole_summary_open (MsOle *f)
{
MsOleStream *s;
MsOleErr result;
// JPP g_return_val_if_fail (f != NULL, NULL);
result = ms_ole_stream_open (&s, f, "/",
"\05SummaryInformation", 'r');
if (result != MS_OLE_ERR_OK || !s)
return NULL;
return ms_ole_summary_open_stream (s, MS_OLE_PS_SUMMARY_INFO);
}
/**
* ms_ole_docsummary_open:
* @f: filesystem object.
*
* Opens the DocumentSummaryInformation stream, returns NULL on failure.
*
* Return value: %NULL if unable to open summary stream or a pointer to the
* DocumentSummaryInformation Stream.
**/
MsOleSummary *
ms_ole_docsummary_open (MsOle *f)
{
MsOleStream *s;
MsOleErr result;
// JPP g_return_val_if_fail (f != NULL, NULL);
result = ms_ole_stream_open (&s, f, "/",
"\05DocumentSummaryInformation", 'r');
if (result != MS_OLE_ERR_OK || !s)
return NULL;
return ms_ole_summary_open_stream (s, MS_OLE_PS_DOCUMENT_SUMMARY_INFO);
}
/*
* Cheat by hard coding magic numbers and chaining on.
*/
/**
* ms_ole_summary_create_stream:
* @s: stream object
* @psid: Property Set ID, indicates which property set to open
*
* Creates @s as a summary stream (@psid determines which one), returns NULL on
* failure.
*
* Return value: %NULL if unable to create stream, otherwise a pointer to a new
* summary stream.
**/
MsOleSummary *
ms_ole_summary_create_stream (MsOleStream *s, const MsOlePropertySetID psid)
{
guint8 data[78];
MsOleSummary *si;
g_return_val_if_fail (s != NULL, NULL);
MS_OLE_SET_GUINT16 (data + 0, 0xfffe); /* byte order */
MS_OLE_SET_GUINT16 (data + 2, 0x0000); /* format */
MS_OLE_SET_GUINT16 (data + 4, 0x0001); /* OS version A */
MS_OLE_SET_GUINT16 (data + 6, 0x0000); /* OS version B */
MS_OLE_SET_GUINT32 (data + 8, 0x0000); /* class id */
MS_OLE_SET_GUINT32 (data + 12, 0x0000);
MS_OLE_SET_GUINT32 (data + 16, 0x0000);
MS_OLE_SET_GUINT32 (data + 20, 0x0000);
if (psid == MS_OLE_PS_SUMMARY_INFO) {
MS_OLE_SET_GUINT32 (data + 24, 0x0001); /* Sections */
MS_OLE_SET_GUINT32 (data + 28, sum_fmtid[0]); /* ID */
MS_OLE_SET_GUINT32 (data + 32, sum_fmtid[1]);
MS_OLE_SET_GUINT32 (data + 36, sum_fmtid[2]);
MS_OLE_SET_GUINT32 (data + 40, sum_fmtid[3]);
MS_OLE_SET_GUINT32 (data + 44, 0x30); /* Section offset = 48 */
MS_OLE_SET_GUINT32 (data + 48, 0); /* bytes */
MS_OLE_SET_GUINT32 (data + 52, 0); /* properties */
s->write (s, data, 56);
} else if (psid == MS_OLE_PS_DOCUMENT_SUMMARY_INFO) {
MS_OLE_SET_GUINT32 (data + 24, 0x0001); /* Sections */
MS_OLE_SET_GUINT32 (data + 28, doc_fmtid[0]); /* ID */
MS_OLE_SET_GUINT32 (data + 32, doc_fmtid[1]);
MS_OLE_SET_GUINT32 (data + 36, doc_fmtid[2]);
MS_OLE_SET_GUINT32 (data + 40, doc_fmtid[3]);
MS_OLE_SET_GUINT32 (data + 44, 0x30); /* Section offset = 48 */
MS_OLE_SET_GUINT32 (data + 48, 0); /* bytes */
MS_OLE_SET_GUINT32 (data + 52, 0); /* properties */
s->write (s, data, 56);
}
s->lseek (s, 0, MsOleSeekSet);
si = ms_ole_summary_open_stream (s, psid);
si->read_mode = FALSE;
return si;
}
/**
* ms_ole_summary_create:
* @f: filesystem object.
*
* Create a SummaryInformation stream, returns NULL on failure.
*
* Return value: %NULL if unable to create the stream, otherwise a pointer to a
* new SummaryInformation stream.
**/
MsOleSummary *
ms_ole_summary_create (MsOle *f)
{
MsOleStream *s;
MsOleErr result;
g_return_val_if_fail (f != NULL, NULL);
result = ms_ole_stream_open (&s, f, "/",
"\05SummaryInformation", 'w');
if (result != MS_OLE_ERR_OK || !s) {
printf ("ms_ole_summary_create: Can't open stream for writing\n");
return NULL;
}
return ms_ole_summary_create_stream (s, MS_OLE_PS_SUMMARY_INFO);
}
/**
* ms_ole_docsummary_create:
* @f: filesystem object.
*
* Create a DocumentSummaryInformation stream, returns NULL on failure.
*
* Return value: %NULL if unable to create the stream, otherwise a pointer to a
* new DocumentSummaryInformation stream.
**/
MsOleSummary *
ms_ole_docsummary_create (MsOle *f)
{
MsOleStream *s;
MsOleErr result;
g_return_val_if_fail (f != NULL, NULL);
result = ms_ole_stream_open (&s, f, "/",
"\05DocumentSummaryInformation", 'w');
if (result != MS_OLE_ERR_OK || !s) {
printf ("ms_ole_docsummary_create: Can't open stream for writing\n");
return NULL;
}
return ms_ole_summary_create_stream (s, MS_OLE_PS_DOCUMENT_SUMMARY_INFO);
}
/* FIXME: without the helpful type */
/**
* ms_ole_summary_get_properties:
* @si: summary stream
*
* Returns an array of MsOleSummaryPID.
*
* Return value: an array of property ids in the current summary stream or
* %NULL if either the summary stream is non-existent or the summary stream
* contains no properties.
**/
GArray *
ms_ole_summary_get_properties (MsOleSummary *si)
{
GArray *ans;
gint i;
g_return_val_if_fail (si != NULL, NULL);
g_return_val_if_fail (si->items != NULL, NULL);
ans = g_array_new (FALSE, FALSE, sizeof (MsOleSummaryPID));
g_array_set_size (ans, si->items->len);
for (i = 0; i < si->items->len; i++)
g_array_index (ans, MsOleSummaryPID, i) =
g_array_index (si->items, item_t, i).id;
return ans;
}
/**
* ms_ole_summary_close:
* @si: FIXME
*
* FIXME
**/
void
ms_ole_summary_close (MsOleSummary *si)
{
g_return_if_fail (si != NULL);
g_return_if_fail (si->s != NULL);
if (!si->read_mode)
write_items (si);
if (si->sections)
g_array_free (si->sections, TRUE);
si->sections = NULL;
if (si->items)
g_array_free (si->items, TRUE);
si->items = NULL;
if (si->s)
ms_ole_stream_close (&si->s);
si->s = NULL;
g_free (si);
}
/*
* Record handling code
*/
#define TYPE_SHORT 0x02 /* 2, VT_I2, 2-byte signed integer */
#define TYPE_LONG 0x03 /* 3, VT_I4, 4-byte signed integer */
#define TYPE_BOOLEAN 0x0b /* 11, VT_BOOL, Boolean value */
#define TYPE_STRING 0x1e /* 30, VT_LPSTR, Pointer to null terminated ANSI string */
#define TYPE_TIME 0x40 /* 64, VT_FILETIME, 64-bit FILETIME structure */
#define TYPE_PREVIEW 0x47 /* 71, VT_CF, Pointer to a CLIPDATA structure */
/* Seeks to the correct place, and returns a handle or NULL on failure */
static item_t *
seek_to_record (MsOleSummary *si, MsOleSummaryPID id)
{
gint i;
g_return_val_if_fail (si->items, FALSE);
/* These should / could be sorted for speed */
for (i = 0; i < si->items->len; i++) {
item_t item = g_array_index (si->items, item_t, i);
if (item.id == SUMMARY_ID(id)) {
gboolean is_summary, is_doc_summary;
is_summary = ((si->ps_id == MS_OLE_PS_SUMMARY_INFO) &&
(item.ps_id == MS_OLE_PS_SUMMARY_INFO));
is_doc_summary = ((si->ps_id == MS_OLE_PS_DOCUMENT_SUMMARY_INFO) &&
(item.ps_id == MS_OLE_PS_DOCUMENT_SUMMARY_INFO));
if (is_summary || is_doc_summary) {
si->s->lseek (si->s, item.offset, MsOleSeekSet);
return &g_array_index (si->items, item_t, i);
}
}
}
return NULL;
}
/**
* ms_ole_summary_get_string:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
* Note: Ensure that you free returned value after use.
*
* Return value: FIXME
**/
char *
ms_ole_summary_get_string (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type, len;
gchar *ans;
item_t *item;
g_return_val_if_fail (available != NULL, 0);
*available = FALSE;
g_return_val_if_fail (si != NULL, NULL);
g_return_val_if_fail (si->read_mode, NULL);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_STRING, NULL);
if (!(item = seek_to_record (si, id)))
return NULL;
if (!si->s->read_copy (si->s, data, 8))
return NULL;
type = MS_OLE_GET_GUINT32 (data);
len = MS_OLE_GET_GUINT32 (data + 4);
if (type != TYPE_STRING) { /* Very odd */
// JPP g_warning ("Summary string type mismatch");
return NULL;
}
ans = g_new (gchar, len + 1);
if (!si->s->read_copy (si->s, ans, len)) {
g_free (ans);
return NULL;
}
ans[len] = '\0';
*available = TRUE;
return ans;
}
/**
* ms_ole_summary_get_short:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
guint16
ms_ole_summary_get_short (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type;
guint32 value;
item_t *item;
g_return_val_if_fail (available != NULL, 0);
*available = FALSE;
g_return_val_if_fail (si != NULL, 0);
g_return_val_if_fail (si->read_mode, 0);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_SHORT, 0);
if (!(item = seek_to_record (si, id)))
return 0;
if (!si->s->read_copy (si->s, data, 8))
return 0;
type = MS_OLE_GET_GUINT32 (data);
value = MS_OLE_GET_GUINT16 (data + 4);
if (type != TYPE_SHORT) { /* Very odd */
// JPP g_warning ("Summary short type mismatch");
return 0;
}
*available = TRUE;
return value;
}
/**
* ms_ole_summary_get_boolean:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
gboolean
ms_ole_summary_get_boolean (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type;
gboolean value;
item_t *item;
g_return_val_if_fail (available != NULL, 0);
*available = FALSE;
g_return_val_if_fail (si != NULL, 0);
g_return_val_if_fail (si->read_mode, 0);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_BOOLEAN, 0);
if (!(item = seek_to_record (si, id)))
return 0;
if (!si->s->read_copy (si->s, data, 8))
return 0;
type = MS_OLE_GET_GUINT32 (data);
value = MS_OLE_GET_GUINT16 (data + 4);
if (type != TYPE_BOOLEAN) { /* Very odd */
// JPP g_warning ("Summary boolean type mismatch");
return 0;
}
*available = TRUE;
return value;
}
/**
* ms_ole_summary_get_long:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
guint32
ms_ole_summary_get_long (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type, value;
item_t *item;
g_return_val_if_fail (available != NULL, 0);
*available = FALSE;
g_return_val_if_fail (si != NULL, 0);
g_return_val_if_fail (si->read_mode, 0);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_LONG, 0);
if (!(item = seek_to_record (si, id)))
return 0;
if (!si->s->read_copy (si->s, data, 8))
return 0;
type = MS_OLE_GET_GUINT32 (data);
value = MS_OLE_GET_GUINT32 (data + 4);
if (type != TYPE_LONG) { /* Very odd */
// JPP g_warning ("Summary long type mismatch");
return 0;
}
*available = TRUE;
return value;
}
/*
* filetime_to_unixtime
*
* Convert a FILETIME format to unixtime
* FILETIME is the number of 100ns units since January 1, 1601.
* unixtime is the number of seconds since January 1, 1970.
*
* The difference in 100ns units between the two dates is:
* 116,444,736,000,000,000 (TIMEDIF)
* (I'll let you do the math)
* If we divide this into pieces,
* high 32-bits = 27111902 or TIMEDIF / 16^8
* mid 16-bits = 54590 or (TIMEDIF - (high 32-bits * 16^8)) / 16^4
* low 16-bits = 32768 or (TIMEDIF - (high 32-bits * 16^8) - (mid 16-bits * 16^4)
*
* where all math is integer.
*
* Adapted from work in 'wv' by:
* Caolan McNamara (Caolan.McNamara@ul.ie)
*/
#define HIGH32_DELTA 27111902
#define MID16_DELTA 54590
#define LOW16_DELTA 32768
/**
* filetime_to_unixtime:
* @low_time: FIXME
* @high_time: FIXME
*
* Converts a FILETIME format to unixtime. FILETIME is the number of 100ns units
* since January 1, 1601. unixtime is the number of seconds since January 1,
* 1970.
*
* Return value: FIXME
**/
glong filetime_to_unixtime (guint32 low_time, guint32 high_time);
glong
filetime_to_unixtime (guint32 low_time, guint32 high_time)
{
guint32 low16; /* 16 bit, low bits */
guint32 mid16; /* 16 bit, medium bits */
guint32 hi32; /* 32 bit, high bits */
unsigned int carry; /* carry bit for subtraction */
int negative; /* whether a represents a negative value */
/* Copy the time values to hi32/mid16/low16 */
hi32 = high_time;
mid16 = low_time >> 16;
low16 = low_time & 0xffff;
/* Subtract the time difference */
if (low16 >= LOW16_DELTA )
low16 -= LOW16_DELTA , carry = 0;
else
low16 += (1 << 16) - LOW16_DELTA , carry = 1;
if (mid16 >= MID16_DELTA + carry)
mid16 -= MID16_DELTA + carry, carry = 0;
else
mid16 += (1 << 16) - MID16_DELTA - carry, carry = 1;
hi32 -= HIGH32_DELTA + carry;
/* If a is negative, replace a by (-1-a) */
negative = (hi32 >= ((guint32)1) << 31);
if (negative) {
/* Set a to -a - 1 (a is hi32/mid16/low16) */
low16 = 0xffff - low16;
mid16 = 0xffff - mid16;
hi32 = ~hi32;
}
/*
* Divide a by 10000000 (a = hi32/mid16/low16), put the rest into r.
* Split the divisor into 10000 * 1000 which are both less than 0xffff.
*/
mid16 += (hi32 % 10000) << 16;
hi32 /= 10000;
low16 += (mid16 % 10000) << 16;
mid16 /= 10000;
low16 /= 10000;
mid16 += (hi32 % 1000) << 16;
hi32 /= 1000;
low16 += (mid16 % 1000) << 16;
mid16 /= 1000;
low16 /= 1000;
/* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
if (negative) {
/* Set a to -a - 1 (a is hi32/mid16/low16) */
low16 = 0xffff - low16;
mid16 = 0xffff - mid16;
hi32 = ~hi32;
}
/* Do not replace this by << 32, it gives a compiler warning and
* it does not work
*/
return ((((glong)hi32) << 16) << 16) + (mid16 << 16) + low16;
}
/**
* unixtime_to_filetime:
* @unix_time: FIXME
* @time_high: FIXME
* @time_low: FIXME
*
* Converts a unixtime format to FILETIME. FILETIME is the number of 100ns units
* since January 1, 1601. unixtime is the number of seconds since January 1,
* 1970.
**/
void unixtime_to_filetime (time_t unix_time, unsigned int *time_high,
unsigned int *time_low);
void
unixtime_to_filetime (time_t unix_time, unsigned int *time_high, unsigned int *time_low)
{
unsigned int low_16;
unsigned int mid_16;
unsigned int high32;
unsigned int carry;
/*
* First split unix_time up.
*/
high32 = (unix_time >> 16) >> 16;
mid_16 = unix_time >> 16;
low_16 = unix_time & 0xffff;
/*
* Convert seconds to 100 ns units by multipling by 10,000,000.
* Do this in two steps, 10,000 and 1,000.
*/
low_16 *= 10000;
carry = (low_16) >> 16;
low_16 = low_16 & 0xffff;
mid_16 *= 10000;
mid_16 += carry;
carry = (mid_16 >> 16);
mid_16 = mid_16 & 0xffff;
high32 *= 10000;
high32 += carry;
low_16 *= 1000;
carry = (low_16) >> 16;
low_16 = low_16 & 0xffff;
mid_16 *= 1000;
mid_16 += carry;
carry = (mid_16 >> 16);
mid_16 = mid_16 & 0xffff;
high32 *= 1000;
high32 += carry;
/*
* Now add in the time difference.
*/
low_16 += LOW16_DELTA;
mid_16 += (low_16 >> 16);
low_16 = low_16 & 0xffff;
mid_16 += MID16_DELTA;
high32 += (mid_16 >> 16);
mid_16 = mid_16 & 0xffff;
high32 += HIGH32_DELTA;
*time_high = high32;
*time_low = (mid_16 << 16) + low_16;
return;
}
/**
* ms_ole_summary_get_time:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
GTimeVal
ms_ole_summary_get_time (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[12];
guint32 type;
guint32 low_time;
guint32 high_time;
item_t *item;
GTimeVal time;
time.tv_sec = 0; /* Magic numbers */
time.tv_usec = 0;
/* g_date_set_dmy (&time.date, 18, 6, 1977); */
g_return_val_if_fail (available != NULL, time);
*available = FALSE;
g_return_val_if_fail (si != NULL, time);
g_return_val_if_fail (si->read_mode, time);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_TIME, time);
if (!(item = seek_to_record (si, id)))
return time;
if (!si->s->read_copy (si->s, data, 12))
return time;
type = MS_OLE_GET_GUINT32 (data);
low_time = MS_OLE_GET_GUINT32 (data + 4);
high_time = MS_OLE_GET_GUINT32 (data + 8);
if (type != TYPE_TIME) { /* Very odd */
// JPP g_warning ("Summary time type mismatch");
return time;
}
time.tv_sec = filetime_to_unixtime (low_time, high_time);
*available = TRUE;
return time;
}
/**
* ms_ole_summary_preview_destroy:
* @d: FIXME
*
* FIXME
**/
void
ms_ole_summary_preview_destroy (MsOleSummaryPreview d)
{
if (d.data)
g_free (d.data);
d.data = NULL;
}
/**
* ms_ole_summary_get_preview:
* @si: FIXME
* @id: FIXME
* @available: FIXME
*
* FIXME
*
* Return value: FIXME
**/
MsOleSummaryPreview
ms_ole_summary_get_preview (MsOleSummary *si, MsOleSummaryPID id,
gboolean *available)
{
guint8 data[8];
guint32 type;
MsOleSummaryPreview ans;
item_t *item;
ans.len = 0;
ans.data = NULL;
g_return_val_if_fail (available != NULL, ans);
*available = FALSE;
g_return_val_if_fail (si != NULL, ans);
g_return_val_if_fail (si->read_mode, ans);
g_return_val_if_fail (MS_OLE_SUMMARY_TYPE (id) ==
MS_OLE_SUMMARY_TYPE_OTHER, ans);
if (!(item = seek_to_record (si, id)))
return ans;
if (!si->s->read_copy (si->s, data, 8))
return ans;
type = MS_OLE_GET_GUINT32 (data);
ans.len = MS_OLE_GET_GUINT32 (data + 4);
if (type != TYPE_PREVIEW) { /* Very odd */
// JPP g_warning ("Summary wmf type mismatch");
return ans;
}
ans.data = g_new (guint8, ans.len + 1);
if (!si->s->read_copy (si->s, ans.data, ans.len)) {
g_free (ans.data);
return ans;
}
*available = TRUE;
return ans;
}
static write_item_t *
write_item_t_new (MsOleSummary *si, MsOleSummaryPID id)
{
write_item_t *w = g_new (write_item_t, 1);
g_return_val_if_fail (si != NULL, NULL);
g_return_val_if_fail (!si->read_mode, NULL);
w->id = id;
w->len = 0;
w->data = NULL;
si->write_items = g_list_append (si->write_items, w);
return w;
}
/**
* ms_ole_summary_set_preview:
* @si: FIXME
* @id: FIXME
* @preview: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_preview (MsOleSummary *si, MsOleSummaryPID id,
const MsOleSummaryPreview *preview)
{
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
g_return_if_fail (preview != NULL);
w = write_item_t_new (si, id);
w->data = g_new (guint8, preview->len + 8);
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_PREVIEW);
MS_OLE_SET_GUINT32 (w->data + 4, preview->len);
memcpy (w->data + 8, preview->data, preview->len);
w->len = preview->len + 8;
}
/**
* ms_ole_summary_set_time:
* @si: FIXME
* @id: FIXME
* @time: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_time (MsOleSummary *si, MsOleSummaryPID id,
GTimeVal time)
{
unsigned int time_high;
unsigned int time_low;
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
w->data = g_new (guint8, 12);
w->len = 12;
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_TIME);
unixtime_to_filetime ((time_t)time.tv_sec, &time_high, &time_low);
MS_OLE_SET_GUINT32 (w->data + 4, time_low);
MS_OLE_SET_GUINT32 (w->data + 8, time_high);
}
/**
* ms_ole_summary_set_boolean:
* @si: FIXME
* @id: FIXME
* @bool: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_boolean (MsOleSummary *si, MsOleSummaryPID id,
gboolean value)
{
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
w->data = g_new (guint8, 8);
w->len = 6;
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_BOOLEAN);
MS_OLE_SET_GUINT16 (w->data + 4, value);
}
/**
* ms_ole_summary_set_short:
* @si: FIXME
* @id: FIXME
* @i: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_short (MsOleSummary *si, MsOleSummaryPID id,
guint16 i)
{
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
w->data = g_new (guint8, 8);
w->len = 6;
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_SHORT);
MS_OLE_SET_GUINT16 (w->data + 4, i);
}
/**
* ms_ole_summary_set_long:
* @si: FIXME
* @id: FIXME
* @i: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_long (MsOleSummary *si, MsOleSummaryPID id,
guint32 i)
{
write_item_t *w;
g_return_if_fail (si != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
w->data = g_new (guint8, 8);
w->len = 8;
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_LONG);
MS_OLE_SET_GUINT32 (w->data + 4, i);
}
/**
* ms_ole_summary_set_string:
* @si: FIXME
* @id: FIXME
* @str: FIXME
*
* FIXME
**/
void
ms_ole_summary_set_string (MsOleSummary *si, MsOleSummaryPID id,
const gchar *str)
{
write_item_t *w;
guint32 len;
g_return_if_fail (si != NULL);
g_return_if_fail (str != NULL);
g_return_if_fail (!si->read_mode);
w = write_item_t_new (si, id);
len = strlen (str) + 1;
w->len = len + 8;
w->data = g_new (guint8, len + 8);
MS_OLE_SET_GUINT32 (w->data + 0, TYPE_STRING);
MS_OLE_SET_GUINT32 (w->data + 4, len);
memcpy (w->data + 8, str, len);
}
--- Added File ms-ole-summary.h in package CMF ---
/**
* ms-ole-summary.h: MS Office OLE support
*
* Author:
* Michael Meeks (michael@imaginator.com)
* From work by:
* Caolan McNamara (Caolan.McNamara@ul.ie)
* Built on work by:
* Somar Software's CPPSUM (http://www.somar.com)
**/
#ifndef MS_OLE_SUMMARY_H
#define MS_OLE_SUMMARY_H
#include <time.h>
#include <ms-ole.h>
/*
* MS Ole Property Set IDs
* The SummaryInformation stream contains the SummaryInformation property set.
* The DocumentSummaryInformation stream contains both the
* DocumentSummaryInformation and the UserDefined property sets as sections.
*/
typedef enum {
MS_OLE_PS_SUMMARY_INFO,
MS_OLE_PS_DOCUMENT_SUMMARY_INFO,
MS_OLE_PS_USER_DEFINED_SUMMARY_INFO
} MsOlePropertySetID;
typedef struct {
guint8 class_id[16];
GArray * sections;
GArray * items;
GList * write_items;
gboolean read_mode;
MsOleStream * s;
MsOlePropertySetID ps_id;
} MsOleSummary;
/* Could store the FID, but why bother ? */
typedef struct {
guint32 offset;
guint32 props;
guint32 bytes;
MsOlePropertySetID ps_id;
} MsOleSummarySection;
MsOleSummary *ms_ole_summary_open (MsOle *f);
MsOleSummary *ms_ole_docsummary_open (MsOle *f);
MsOleSummary *ms_ole_summary_open_stream (MsOleStream *stream,
const MsOlePropertySetID psid);
MsOleSummary *ms_ole_summary_create (MsOle *f);
MsOleSummary *ms_ole_docsummary_create (MsOle *f);
MsOleSummary *ms_ole_summary_create_stream (MsOleStream *s,
const MsOlePropertySetID psid);
GArray *ms_ole_summary_get_properties (MsOleSummary *si);
void ms_ole_summary_close (MsOleSummary *si);
/*
* Can be used to interrogate a summary item as to its type
*/
typedef enum {
MS_OLE_SUMMARY_TYPE_STRING = 0x10,
MS_OLE_SUMMARY_TYPE_TIME = 0x20,
MS_OLE_SUMMARY_TYPE_LONG = 0x30,
MS_OLE_SUMMARY_TYPE_SHORT = 0x40,
MS_OLE_SUMMARY_TYPE_BOOLEAN = 0x50,
MS_OLE_SUMMARY_TYPE_OTHER = 0x60
} MsOleSummaryType;
#define MS_OLE_SUMMARY_TYPE(x) ((MsOleSummaryType)((x)>>8))
/* FIXME MS_OLE_SUMMARY_THUMBNAIL is Preview, no Security, isn't it? */
/*
* The MS byte specifies the type, the LS byte is the
* 'standard' MS PID.
*/
typedef enum {
/* SummaryInformation Stream Properties */
/* String properties */
MS_OLE_SUMMARY_TITLE = 0x1002,
MS_OLE_SUMMARY_SUBJECT = 0x1003,
MS_OLE_SUMMARY_AUTHOR = 0x1004,
MS_OLE_SUMMARY_KEYWORDS = 0x1005,
MS_OLE_SUMMARY_COMMENTS = 0x1006,
MS_OLE_SUMMARY_TEMPLATE = 0x1007,
MS_OLE_SUMMARY_LASTAUTHOR = 0x1008,
MS_OLE_SUMMARY_REVNUMBER = 0x1009,
MS_OLE_SUMMARY_APPNAME = 0x1012,
/* Time properties */
MS_OLE_SUMMARY_TOTAL_EDITTIME = 0x200A,
MS_OLE_SUMMARY_LASTPRINTED = 0x200B,
MS_OLE_SUMMARY_CREATED = 0x200C,
MS_OLE_SUMMARY_LASTSAVED = 0x200D,
/* Long integer properties */
MS_OLE_SUMMARY_PAGECOUNT = 0x300E,
MS_OLE_SUMMARY_WORDCOUNT = 0x300F,
MS_OLE_SUMMARY_CHARCOUNT = 0x3010,
MS_OLE_SUMMARY_SECURITY = 0x3013,
/* Short integer properties */
MS_OLE_SUMMARY_CODEPAGE = 0x4001,
/* Security */
MS_OLE_SUMMARY_THUMBNAIL = 0x6011,
/* DocumentSummaryInformation Properties */
/* String properties */
MS_OLE_SUMMARY_CATEGORY = 0x1002,
MS_OLE_SUMMARY_PRESFORMAT = 0x1003,
MS_OLE_SUMMARY_MANAGER = 0x100E,
MS_OLE_SUMMARY_COMPANY = 0x100F,
/* Long integer properties */
MS_OLE_SUMMARY_BYTECOUNT = 0x3004,
MS_OLE_SUMMARY_LINECOUNT = 0x3005,
MS_OLE_SUMMARY_PARCOUNT = 0x3006,
MS_OLE_SUMMARY_SLIDECOUNT = 0x3007,
MS_OLE_SUMMARY_NOTECOUNT = 0x3008,
MS_OLE_SUMMARY_HIDDENCOUNT = 0x3009,
MS_OLE_SUMMARY_MMCLIPCOUNT = 0X300A,
/* Boolean properties */
MS_OLE_SUMMARY_SCALE = 0x500B,
MS_OLE_SUMMARY_LINKSDIRTY = 0x5010
} MsOleSummaryPID;
/* bit masks for security long integer */
#define MsOleSummaryAllSecurityFlagsEqNone 0x00
#define MsOleSummarySecurityPassworded 0x01
#define MsOleSummarySecurityRORecommended 0x02
#define MsOleSummarySecurityRO 0x04
#define MsOleSummarySecurityLockedForAnnotations 0x08
typedef struct {
GTimeVal time;
GDate date;
} MsOleSummaryTime;
typedef struct {
guint32 len;
guint8 *data;
} MsOleSummaryPreview;
gchar * ms_ole_summary_get_string (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
gboolean ms_ole_summary_get_boolean (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
guint16 ms_ole_summary_get_short (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
guint32 ms_ole_summary_get_long (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
GTimeVal ms_ole_summary_get_time (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
MsOleSummaryPreview ms_ole_summary_get_preview (MsOleSummary *si,
MsOleSummaryPID id,
gboolean *available);
void ms_ole_summary_preview_destroy (MsOleSummaryPreview d);
/* FIXME The next comment isn't true, is it?
Return TRUE if write is successful */
void ms_ole_summary_set_string (MsOleSummary *si,
MsOleSummaryPID id,
const gchar *str);
void ms_ole_summary_set_boolean (MsOleSummary *si,
MsOleSummaryPID id,
gboolean value);
void ms_ole_summary_set_short (MsOleSummary *si,
MsOleSummaryPID id,
guint16 i);
void ms_ole_summary_set_long (MsOleSummary *si,
MsOleSummaryPID id,
guint32 i);
void ms_ole_summary_set_time (MsOleSummary *si,
MsOleSummaryPID id,
GTimeVal time);
void ms_ole_summary_set_preview (MsOleSummary *si,
MsOleSummaryPID id,
const
MsOleSummaryPreview *
preview);
#endif /* MS_OLE_SUMMARY_H */
--- Added File ms-ole-vba.c in package CMF ---
/**
* ms-ole-vba.c: MS Office VBA support
*
* Author:
* Michael Meeks (michael@imaginator.com)
*
* Copyright 2000 Helix Code, Inc.
**/
#include <config.h>
#include <stdio.h>
#include <ms-ole-vba.h>
#undef VBA_DEBUG
struct _MsOleVba {
MsOleStream *s;
GArray *text;
int pos;
};
inline gboolean
ms_ole_vba_eof (MsOleVba *vba)
{
return !vba || (vba->pos >= vba->text->len - 1);
}
char
ms_ole_vba_getc (MsOleVba *vba)
{
g_assert (!ms_ole_vba_eof (vba));
return g_array_index (vba->text, guint8, vba->pos++);
}
char
ms_ole_vba_peek (MsOleVba *vba)
{
g_assert (!ms_ole_vba_eof (vba));
return g_array_index (vba->text, guint8, vba->pos);
}
#if VBA_DEBUG > 1
static void
print_bin (guint16 dt)
{
int i;
printf ("|");
for (i = 15; i >= 0; i--) {
if (dt & (1 << i))
printf ("1");
else
printf ("0");
if (i == 8)
printf ("|");
}
printf ("|");
}
#endif
/**
* decompress_vba
* @vba Place to store the uncompressed VBA
* @data Pointer to start of compressed VBA
* @eos lwa+1 of stream
*
* Purpose: lzw, arc like compression.
*
* Internal function.
**/
static void
decompress_vba (MsOleVba *vba, guint8 *data, guint8 *eos)
{
#define BUF_SIZE 6144 /* a bottleneck */
guint8 buffer[BUF_SIZE];
guint8 *ptr;
guint8 *sptr;
guint32 len;
guint32 pos;
GArray *ans = g_array_new (FALSE, FALSE, 1);
vba->text = ans;
vba->pos = 0;
len = MS_OLE_GET_GUINT16 (data + 1);
#if VBA_DEBUG > 0
printf ("Length 0x%x\n", len);
#endif
len = (len & ~0xb000) + 1;
ptr = data + 3;
sptr = ptr;
pos = 0;
while (ptr < eos) {
#if VBA_DEBUG > 0
printf ("My compressed stream (addr=%#x, len = %#x (%d)):\n",
ptr - data, len, len);
ms_ole_dump (ptr, len);
#endif
while ((ptr < sptr + len) && (ptr < eos)) {
int shift;
guint8 flag_byte = *ptr++;
/*
* The first byte is a flag byte. Each bit in this byte
* determines what the next byte is. If the bit is zero,
* the next byte is a character. Otherwise the next two
* bytes contain the number of characters to copy from the
* umcompresed buffer and where to copy them from (offset,
* length).
*/
for (shift = 0x01; shift < 0x100; shift = shift << 1) {
if (ptr >= sptr + len)
break;
if (pos == BUF_SIZE) {
#if VBA_DEBUG > 0
printf ("\nSomething extremely odd"
" happens after %d bytes 0x%x\n\n",
BUF_SIZE, MS_OLE_GET_GUINT16 (ptr));
ms_ole_dump (ptr, len - (ptr - data));
#endif
ptr += 2;
flag_byte = *ptr++;
pos = 0;
shift = 0x01;
}
if (flag_byte & shift) {
int i;
int back;
int clen;
int shft;
guint16 dt = MS_OLE_GET_GUINT16 (ptr);
if (pos <= 16)
shft = 12;
else if (pos <= 32)
shft = 11;
else if (pos <= 64)
shft = 10;
else if (pos <= 128)
shft = 9;
else if (pos <= 256)
shft = 8;
else if (pos <= 512)
shft = 7;
else if (pos <= 1024)
shft = 6;
else if (pos <= 2048)
shft = 5;
else
shft = 4;
back = (dt >> shft) + 1;
clen = 0;
for (i = 0; i < shft; i++)
clen |= dt & (0x1 << i);
clen += 3;
#if VBA_DEBUG > 1
printf ("|match 0x%x (%d,%d) >> %d = %d, %d| pos = %d |\n",
dt, (dt>>8), (dt&0xff), shft, back, clen, pos);
/* Perhaps dt & SHIFT = dist. to end of run */
print_bin (dt);
printf ("\n");
#endif
for (i = 0; i < clen; i++) {
guint8 c;
guint32 srcpos = (BUF_SIZE + (pos%BUF_SIZE)) -
back;
if (srcpos >= BUF_SIZE)
srcpos-= BUF_SIZE;
g_assert (srcpos >= 0);
g_assert (srcpos < BUF_SIZE);
c = buffer [srcpos];
buffer [pos++ % BUF_SIZE] = c;
g_array_append_val (ans, c);
#if VBA_DEBUG > 0
printf ("%c", c);
#endif
}
ptr += 2;
} else {
buffer [pos++ % BUF_SIZE] = *ptr;
g_array_append_val (ans, *ptr);
#if VBA_DEBUG > 0
printf ("%c", *ptr);
#endif
ptr++;
}
if ((ptr >= sptr + len) || (ptr >= eos)) {
if ((ptr >= sptr + len) && (ptr < eos)) {
#if VBA_DEBUG > 0
printf ("Reseting ptr.\n");
printf ("ptr was %#x\n",
ptr - sptr);
printf ("ptr is %#x\n",
len);
#endif
ptr = sptr + len;
}
break;
}
} /* for (shift = 0x01; shift < 0x100; shift = shift << 1) */
} /* while ((ptr < sptr + len) && (ptr < eos)) */
#if VBA_DEBUG > 0
printf ("ptr = %#X\n", ptr-sptr);
#endif
if ((ptr + 3) < eos) {
len = MS_OLE_GET_GUINT16 (ptr);
len = (len & ~0xb000) + 1;
ptr += 2;
sptr = ptr;
pos = 0;
}
} /* while (ptr < eos) */
{
char c;
c = '\n';
g_array_append_val (ans, c);
c = '\0';
g_array_append_val (ans, c);
}
}
static guint8 *
seek_sig (guint8 *data, int len)
{
int i;
guint8 vba_sig[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1, 0x1 };
for (i = 0; i < len; i++) {
guint8 *p = data;
int j;
for (j = 0; j < sizeof (vba_sig); j++) {
if (*p++ != vba_sig [j])
break;
}
if (j == sizeof (vba_sig))
return p;
data++;
}
return NULL;
}
static guint8 *
find_compressed_vba (guint8 *data, MsOlePos len)
{
guint8 *sig;
guint32 offset;
guint32 offpos;
if (!(sig = seek_sig (data, len))) {
g_warning ("No VBA kludge signature");
return NULL;
}
offpos = MS_OLE_GET_GUINT32 (sig) + 0xd0 - 0x6b - 0x8;
#if VBA_DEBUG > 0
printf ("Offpos : 0x%x -> \n", offpos);
#endif
offset = MS_OLE_GET_GUINT32 (sig + offpos);
if (len < offset + 3) {
g_warning ("Too small for offset 0x%x\n", offset);
return NULL;
}
#if VBA_DEBUG > 0
printf ("Offset is 0x%x\n", offset);
#endif
return data + offset;
}
/**
* ms_ole_vba_open:
* @s: the stream pointer.
*
* Attempt to open a stream as a VBA stream, and commence
* decompression of it.
*
* Return value: NULL if not a VBA stream or fails.
**/
MsOleVba *
ms_ole_vba_open (MsOleStream *s)
{
const guint8 gid [16] = { 0x1, 0x16, 0x1, 0x0,
0x6, 0xb6, 0x0, 0xff,
0xff, 0x1, 0x1, 0x0,
0x0, 0x0, 0x0, 0xff };
int i;
int j;
int len;
guint8 *data, *vba_data;
guint8 sig [16];
MsOleVba *vba;
g_return_val_if_fail (s != NULL, NULL);
if (s->size < 16)
return NULL;
s->lseek (s, 0, MsOleSeekSet);
s->read_copy (s, sig, 16);
for (i = 0; i < 16; i++)
if (sig [i] != gid [i]) {
/*
* Version ??
*/
if (i == 4)
if (sig [i] == 0x4 )
continue;
return NULL;
}
data = g_new (guint8, s->size);
s->lseek (s, 0, MsOleSeekSet);
if (!s->read_copy (s, data, s->size)) {
g_warning ("Strange: failed read");
g_free (data);
return NULL;
}
if (!(vba_data = find_compressed_vba (data, s->size))) {
g_free (data);
return NULL;
}
if (MS_OLE_GET_GUINT8 (vba_data) != 1)
g_warning ("Digit 0x%x != 1...", MS_OLE_GET_GUINT8 (vba_data));
vba = g_new0 (MsOleVba, 1);
vba->s = s;
vba->pos = 0;
decompress_vba (vba, vba_data, data + s->size);
g_free (data);
return vba;
}
/**
* me_ols_vba_close:
* @vba:
*
* Free the resources associated with this vba
* stream.
**/
void
ms_ole_vba_close (MsOleVba *vba)
{
if (vba) {
g_array_free (vba->text, TRUE);
vba->text = NULL;
g_free (vba);
}
}
--- Added File ms-ole-vba.h in package CMF ---
/**
* ms-ole-vba.h: MS Office VBA support
*
* Author:
* Michael Meeks (michael@imaginator.com)
*
* Copyright 2000 Helix Code, Inc.
**/
#ifndef MS_OLE_VBA_H
#define MS_OLE_VBA_H
#include <ms-ole.h>
typedef struct _MsOleVba MsOleVba;
MsOleVba *ms_ole_vba_open (MsOleStream *s);
void ms_ole_vba_close (MsOleVba *vba);
char ms_ole_vba_getc (MsOleVba *vba);
char ms_ole_vba_peek (MsOleVba *vba);
gboolean ms_ole_vba_eof (MsOleVba *vba);
#endif
--- Added File ms-ole.c in package CMF ---
/**
* ms-ole.c: MS Office OLE support for Gnumeric
*
* Authors:
* Michael Meeks (michael@imaginator.com)
* Arturo Tena (arturo@directmail.org)
**/
#include <stdio.h>
/* BSDs require unistd.h before including stat.h */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h> /* for struct stat */
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <glib.h>
#include <string.h>
#include <ms-ole.h>
#include "config.h"
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#else
# include <io.h>
# include <sys/stat.h>
# include <sys/types.h>
/*
# define S_IRUSR 0000400
# define S_IWUSR 0000200
# define S_IRGRP 0000040
# define S_IWGRP 0000020
# define _S_ISREG(m) (((m)&0170000) == 0100000)
# define S_ISREG(m) _S_ISREG(m)
# define O_NONBLOCK 0x4000
*/
#endif
#ifndef MAP_FAILED
/* Someone needs their head examining - BSD ? */
# define MAP_FAILED ((void *)-1)
#endif
/* Implementational detail - not for global header */
#define OLE_DEBUG 0
/* FIXME tenix add ADD_BBD_LIST_BLOCK where it should be used) */
#define ADD_BBD_LIST_BLOCK 0xfffffffc /* -4 */
#define SPECIAL_BLOCK 0xfffffffd /* -3 (BBD_LIST BLOCK) */
#define END_OF_CHAIN 0xfffffffe /* -2 */
#define UNUSED_BLOCK 0xffffffff /* -1 */
/* FIXME tenix laola reads this from the header */
#define BB_BLOCK_SIZE 512
#define SB_BLOCK_SIZE 64
/* FIXME tenix laola understand the next header:
MAGIC => undef, # 00
CLSID => undef, # guid 08
REVISION => undef, # word 18
VERSION => undef, # word 1a
BYTEORDER => undef, # word 1c
B_S_LOG => undef, # word 1e big block size = 2^b_s_log
S_S_LOG => undef, # word 20 small block size = 2^s_s_log
UK1 => undef, # word(5) 22
B_D_NUM => undef, # long 2c bbd num of blocks
ROOT_SB => undef, # long 30 root start block
UK2 => undef, # long 34
B_S_MIN => undef, # long 38 minimum size of big_block
S_D_SB => undef, # long 3c sbd start block
S_D_NUM => undef, # long 40 number of sbd blocks
B_XD_SB => undef, # long 44
B_XD_NUM => undef, # long 48
*/
MsOle *jp_msOle;
/**
* Structure describing an OLE file
**/
struct _MsOle
{
int ref_count;
gboolean ole_mmap;
guint8 *mem;
guint32 length;
MsOleSysWrappers *syswrap;
char mode;
int file_des;
int dirty;
GArray *bb; /* Big blocks status */
GArray *sb; /* Small block status */
GArray *sbf; /* The small block file */
guint32 num_pps; /* Count of number of property sets */
GList *pps; /* Property Storage -> struct _PPS, always 1 valid entry or NULL */
/* if memory mapped */
GPtrArray *bbattr; /* Pointers to block structures */
/* end if memory mapped */
unsigned char *buf;
size_t len;
size_t idx;
};
/**
* Default system calls wrappers
**/
static int
open2_wrap (const char *pathname, int flags)
{
return open (pathname, flags);
}
static int
open3_wrap (const char *pathname, int flags, mode_t mode)
{
return open (pathname, flags, mode);
}
static ssize_t
read_wrap (int fd, void *buf, size_t count)
{
// printf(":read_wrap:\n");
return read (fd, buf, count);
}
static int
close_wrap (int fd)
{
return close (fd);
}
static ssize_t
write_wrap (int fd, const void *buf, size_t count)
{
return write (fd, buf, count);
}
static off_t
lseek_wrap (int fd, off_t offset, int whence)
{
return lseek (fd, offset, whence);
}
static int
isregfile_wrap (int fd)
{
struct stat st;
if (fstat (fd, &st))
return 0;
return S_ISREG(st.st_mode);
}
static int
getfilesize_wrap (int fd, guint32 *size)
{
struct stat st;
if (fstat (fd, &st))
return -1;
*size = st.st_size;
return 0;
}
static MsOleSysWrappers default_wrappers = {
open2_wrap,
open3_wrap,
read_wrap,
close_wrap,
write_wrap,
lseek_wrap,
isregfile_wrap,
getfilesize_wrap
};
//----------------------------------------------------------------------------//
static int open2_wrap_body (const char *pathname, int flags)
{
int fd;
fd = 3;
return fd;
}
//----------------------------------------------------------------------------//
static int open3_wrap_body (const char *pathname, int flags, mode_t mode)
{
int fd;
fd = 3;
return fd;
}
//----------------------------------------------------------------------------//
static ssize_t read_wrap_body (int fd, void *buf, size_t count)
{
ssize_t temp;
// printf(":read_wrap_body:\n");
temp = count;
memcpy(buf, &(jp_msOle->buf[jp_msOle->idx]), count);
jp_msOle->idx = jp_msOle->idx +count;
return temp;
}
//----------------------------------------------------------------------------//
static int close_wrap_body (int fd)
{
int result;
result = 0;
return result;
}
//----------------------------------------------------------------------------//
static ssize_t write_wrap_body (int fd, const void *buf, size_t count)
{
ssize_t temp;
temp = write(fd, buf, count);
return temp;
}
//----------------------------------------------------------------------------//
static off_t lseek_wrap_body (int fd, off_t offset, int whence)
{
off_t temp;
temp = offset;
jp_msOle->idx = offset;
return temp;
}
//----------------------------------------------------------------------------//
static int isregfile_wrap_body (int fd)
{
int result;
struct stat st;
result = 1;
return result;
}
//----------------------------------------------------------------------------//
static int getfilesize_wrap_body (int fd, guint32 *size)
{
int result;
struct stat st;
result = jp_msOle->len;
*size = result;
return 0;
}
//----------------------------------------------------------------------------//
static MsOleSysWrappers default_wrappers_body =
{
open2_wrap_body,
open3_wrap_body,
read_wrap_body,
close_wrap_body,
write_wrap_body,
lseek_wrap_body,
isregfile_wrap_body,
getfilesize_wrap_body
};
//----------------------------------------------------------------------------//
static void
take_wrapper_functions (MsOle *f, MsOleSysWrappers *wrappers) {
if (wrappers == NULL)
f->syswrap = &default_wrappers;
else
f->syswrap = wrappers;
}
/*
* A global variable to enable calles to check_stream,
* applications should optionally enable due to the performance penalty.
* of 30-50 % of load time.
*/
gboolean libole2_debug = FALSE;
typedef guint32 PPS_IDX ;
#if OLE_DEBUG > 0
/* Very grim, but quite necessary */
# define ms_array_index(a,b,c) (b)my_array_hack ((a), sizeof(b), (c))
static guint32
my_array_hack (GArray *a, guint s, guint32 idx)
{
g_assert (a != NULL);
g_assert (idx >= 0);
g_assert (idx < a->len);
g_assert (s == 4);
return ((guint32 *)a->data)[idx];
}
#else
/* Far far faster... */
# define ms_array_index(a,b,c) g_array_index (a, b, c)
#endif
typedef guint32 BLP; /* Block pointer */
#define BB_THRESHOLD 0x1000
#define PPS_ROOT_INDEX 0
#define PPS_BLOCK_SIZE 0x80
#define PPS_END_OF_CHAIN 0xffffffff
typedef struct _PPS PPS;
#define PPS_SIG 0x13579753
#define IS_PPS(p) (((PPS *)(p))->sig == PPS_SIG)
struct _PPS {
int sig;
char *name;
GList *children;
PPS *parent;
guint32 size;
BLP start;
MsOleType type;
PPS_IDX idx; /* Only used on write */
};
#define BB_R_PTR(f,b) ((f)->ole_mmap ? ((f)->mem + (b+1)*BB_BLOCK_SIZE) : \
(get_block_ptr (f, b, FALSE)))
#define BB_W_PTR(f,b) ((f)->ole_mmap ? BB_R_PTR(f,b) : \
(get_block_ptr (f, b, TRUE)))
#define GET_SB_R_PTR(f,b) (BB_R_PTR(f, g_array_index ((f)->sbf, BLP, (b)/(BB_BLOCK_SIZE/SB_BLOCK_SIZE))) \
+ (((b)%(BB_BLOCK_SIZE/SB_BLOCK_SIZE))*SB_BLOCK_SIZE))
#define GET_SB_W_PTR(f,b) (BB_W_PTR(f, g_array_index ((f)->sbf, BLP, (b)/(BB_BLOCK_SIZE/SB_BLOCK_SIZE))) \
+ (((b)%(BB_BLOCK_SIZE/SB_BLOCK_SIZE))*SB_BLOCK_SIZE))
#define MAX_CACHED_BLOCKS 32
typedef struct {
guint32 blk;
gboolean dirty;
int usage;
guint8 *data;
} BBBlkAttr;
static BBBlkAttr *
bb_blk_attr_new (guint32 blk)
{
BBBlkAttr *attr = g_new (BBBlkAttr, 1);
attr->blk = blk;
attr->dirty = FALSE;
attr->usage = 0;
attr->data = 0;
return attr;
}
static void
write_cache_block (MsOle *f, BBBlkAttr *attr)
{
size_t offset;
g_return_if_fail (f);
g_return_if_fail (attr);
g_return_if_fail (attr->data);
offset = (attr->blk+1)*BB_BLOCK_SIZE;
if (f->syswrap->lseek (f->file_des, offset, SEEK_SET)==(off_t)-1 ||
f->syswrap->write (f->file_des, attr->data, BB_BLOCK_SIZE) == -1)
printf ("Fatal error writing block %d at %d\n", attr->blk, offset);
#if OLE_DEBUG > 0
printf ("Writing cache block %d to offset %d\n",
attr->blk, offset);
#endif
attr->dirty = FALSE;
}
static guint8 *
get_block_ptr (MsOle *f, BLP b, gboolean forwrite)
{
BBBlkAttr *attr, *tmp, *min;
size_t offset;
guint32 i, blks;
g_assert (f);
g_assert (b < f->bbattr->len);
/* Have we cached it ? */
attr = g_ptr_array_index (f->bbattr, b);
g_assert (attr);
g_assert (attr->blk == b);
if (attr->data) {
attr->usage++;
if (forwrite)
attr->dirty = TRUE;
return attr->data;
}
/* LRU strategy */
min = NULL;
blks = 0;
for (i=0;i<f->bbattr->len;i++) {
tmp = g_ptr_array_index (f->bbattr, i);
if (tmp->data) {
blks++;
if (!min)
min = tmp;
else if (tmp->usage < min->usage)
min = tmp;
}
tmp->usage = (guint32)tmp->usage*0.707;
}
if (blks < MAX_CACHED_BLOCKS)
min = 0;
g_assert (!attr->data);
if (min) {
g_assert (min->data);
#if OLE_DEBUG > 0
printf ("Replacing cache block %d with %d\n", min->blk, b);
#endif
if (min->dirty)
write_cache_block (f, min);
attr->data = min->data;
min->data = 0;
min->usage = 0;
} else
attr->data = g_new (guint8, BB_BLOCK_SIZE);
offset = (b+1)*BB_BLOCK_SIZE;
f->syswrap->lseek (f->file_des, offset, SEEK_SET);
f->syswrap->read (f->file_des, attr->data, BB_BLOCK_SIZE);
attr->usage = 1;
attr->dirty = forwrite;
return attr->data;
}
/* This is a list of big blocks which contain a flat description of all blocks
in the file. Effectively inside these blocks is a FAT of chains of other BBs,
so the theoretical max size = 128 BB Fat blocks, thus = 128*512*512/4 blocks
~= 8.4MBytes */
/* FIXME tenix the max size would actually be 109*512*512/4 + 512 blocks ~=
7MBytes if we don't take in count the additional Big Block Depot lists.
Number of additional lists is in header:0x48, the location of the first
additional list is in header:0x44, the location of the second additional
list is at the very end of the first additional list and so on, the last
additional list have at the end a END_OF_CHAIN.
Each additional list can address 128*512/4*512 blocks ~= 8MBytes */
/* The number of Big Block Descriptor (fat) Blocks */
#define GET_NUM_BBD_BLOCKS(f) (MS_OLE_GET_GUINT32((f)->mem + 0x2c))
#define SET_NUM_BBD_BLOCKS(f,n) (MS_OLE_SET_GUINT32((f)->mem + 0x2c, (n)))
/* The block locations of the Big Block Descriptor Blocks */
#define MAX_SIZE_BBD_LIST 109
/* FIXME tenix next is broken with big files */
#define GET_BBD_LIST(f,i) (MS_OLE_GET_GUINT32((f)->mem + 0x4c + (i)*4))
/* FIXME tenix next is broken with big files */
#define SET_BBD_LIST(f,i,n) (MS_OLE_SET_GUINT32((f)->mem + 0x4c + (i)*4, (n)))
#define NEXT_BB(f,n) (g_array_index ((f)->bb, BLP, n))
#define NEXT_SB(f,n) (g_array_index ((f)->sb, BLP, n))
/* Additional Big Block Descriptor (fat) Blocks */
#define MAX_SIZE_ADD_BBD_LIST 127
#define GET_NUM_ADD_BBD_LISTS(f) (MS_OLE_GET_GUINT32((f)->mem + 0x48))
#define GET_FIRST_ADD_BBD_LIST(f) (MS_OLE_GET_GUINT32((f)->mem + 0x44))
/* Get the start block of the root directory ( PPS ) chain */
#define GET_ROOT_STARTBLOCK(f) (MS_OLE_GET_GUINT32((f)->mem + 0x30))
#define SET_ROOT_STARTBLOCK(f,i) (MS_OLE_SET_GUINT32((f)->mem + 0x30, i))
/* Get the start block of the SBD chain */
#define GET_SBD_STARTBLOCK(f) (MS_OLE_GET_GUINT32((f)->mem + 0x3c))
#define SET_SBD_STARTBLOCK(f,i) (MS_OLE_SET_GUINT32((f)->mem + 0x3c, i))
/* NB it is misleading to assume that Microsofts linked lists link correctly.
It is not the case that pps_next(f, pps_prev(f, n)) = n ! For the final list
item there are no valid links. Cretins. */
#define PPS_GET_NAME_LEN(p) (MS_OLE_GET_GUINT16(p + 0x40))
#define PPS_SET_NAME_LEN(p,i) (MS_OLE_SET_GUINT16(p + 0x40, (i)))
#define PPS_GET_PREV(p) ((PPS_IDX) MS_OLE_GET_GUINT32(p + 0x44))
#define PPS_GET_NEXT(p) ((PPS_IDX) MS_OLE_GET_GUINT32(p + 0x48))
#define PPS_GET_DIR(p) ((PPS_IDX) MS_OLE_GET_GUINT32(p + 0x4c))
#define PPS_SET_PREV(p,i) ((PPS_IDX) MS_OLE_SET_GUINT32(p + 0x44, i))
#define PPS_SET_NEXT(p,i) ((PPS_IDX) MS_OLE_SET_GUINT32(p + 0x48, i))
#define PPS_SET_DIR(p,i) ((PPS_IDX) MS_OLE_SET_GUINT32(p + 0x4c, i))
/* These get other interesting stuff from the PPS record */
#define PPS_GET_STARTBLOCK(p) ( MS_OLE_GET_GUINT32(p + 0x74))
#define PPS_GET_SIZE(p) ( MS_OLE_GET_GUINT32(p + 0x78))
#define PPS_GET_TYPE(p) ((MsOleType)( MS_OLE_GET_GUINT8(p + 0x42)))
#define PPS_SET_STARTBLOCK(p,i) ( MS_OLE_SET_GUINT32(p + 0x74, i))
#define PPS_SET_SIZE(p,i) ( MS_OLE_SET_GUINT32(p + 0x78, i))
#define PPS_SET_TYPE(p,i) ( MS_OLE_SET_GUINT8 (p + 0x42, i))
/* Try to mark the Big Block "b" as as unused if it is marked as "c", in the
FAT "f". */
#define TRY_MARK_UNUSED_BLOCK(f,block,mark) { \
if (g_array_index ((f), BLP, (block)) != (mark)) { \
g_warning ("Tried to mark as unused the block %d which has %d\n", \
(block), g_array_index ((f), BLP, (block))); \
} else { g_array_index ((f), BLP, (block)) = UNUSED_BLOCK; } }
/* FIXME: This needs proper unicode support ! current support is a guess */
/* Length is in bytes == 1/2 the final text length */
/* NB. Different from biff_get_text, looks like a bug ! */
static char *
pps_get_text (guint8 *ptr, int length)
{
int lp;
char *ans;
guint16 c;
guint8 *inb;
length = (length+1)/2;
if (length <= 0 ||
length > (PPS_BLOCK_SIZE/4)) {
#if OLE_DEBUG > 0
printf ("Nulled name of length %d\n", length);
#endif
return 0;
}
ans = (char *) g_malloc (sizeof (char) * length + 1);
inb = ptr;
for (lp = 0; lp < length; lp++) {
c = MS_OLE_GET_GUINT16 (inb);
ans [lp] = (char) c;
inb += 2;
}
ans [lp] = 0;
return ans;
}
static void
dump_header (MsOle *f)
{
printf ("--------------------------MsOle HEADER-------------------------\n");
printf ("Num BBD Blocks : %d Root %%d, SB blocks %d\n",
f->bb?f->bb->len:-1,
/* f->pps?f->pps->len:-1, */
/* FIXME tenix, here is not f->num_pps? */
f->sb?f->sb->len:-1);
printf ("-------------------------------------------------------------\n");
}
static void
characterise_block (MsOle *f, BLP blk, char **ans)
{
int nblk;
nblk = g_array_index (f->bb, BLP, blk);
if (nblk == UNUSED_BLOCK) {
*ans = "unused";
return;
} else if (nblk == SPECIAL_BLOCK) {
*ans = "special";
return;
} else if (nblk == ADD_BBD_LIST_BLOCK) {
*ans = "additional special";
return;
} else if (nblk == END_OF_CHAIN) {
*ans = "end of chain";
return;
}
*ans = "unknown";
g_return_if_fail (f);
g_return_if_fail (f->bb);
g_return_if_fail (f->pps);
/* for (lp=0;lp<f->pps->len;lp++) {
PPS *p = g_ptr_array_index (f->pps, lp);
BLP cur = p->start;
while (cur != END_OF_CHAIN) {
if (cur == SPECIAL_BLOCK ||
cur == UNUSED_BLOCK) {
*ans = "serious block error";
return;
}
if (cur == blk) {
*ans = p->name;
return;
}
cur = NEXT_BB (f, cur);
}
}*/
}
static void
dump_tree (GList *list, int indent)
{
PPS *p;
int lp;
char indentstr[64];
g_return_if_fail (indent<60);
for (lp=0;lp<indent;lp++)
indentstr[lp]= '-';
indentstr[lp]=0;
while (list) {
p = list->data;
if (p) {
printf ("%s '%s' (size: %d)\n",
indentstr, p->name, p->size);
if (p->children)
dump_tree (p->children, indent+1);
} else
printf ("%s NULL!\n", indentstr);
list = g_list_next (list);
}
}
static void
dump_allocation (MsOle *f)
{
int lp;
char *blktype;
for (lp=0;lp<f->bb->len;lp++) {
characterise_block (f, lp, &blktype);
printf ("Block %d -> block %d ( '%s' )\n", lp,
g_array_index (f->bb, BLP, lp),
blktype);
}
if (f->pps) {
printf ("Root blocks : %d\n", f->num_pps);
dump_tree (f->pps, 0);
} else
printf ("No root yet\n");
/*
printf ("sbd blocks : %d\n", h->sbd_list->len);
for (lp=0;lp<h->sbd_list->len;lp++)
printf ("sbd_list[%d] = %d\n", lp, (int)ms_array_index (h->sbd_list, SBPtr, lp));*/
printf ("-------------------------------------------------------------\n");
}
/*
* Dump some useful facts.
* magic: 2 : dump tree
* default : dump header and allocation
*/
void
ms_ole_debug (MsOle *fs, int magic)
{
switch (magic) {
case 2:
if (fs->pps)
dump_tree (fs->pps, 0);
else
printf ("There are no tree (no pps)\n");
break;
default:
dump_header (fs);
dump_allocation (fs);
break;
}
}
/*
* get_next_block:
* @f: the file handle
* @blk: an index into the big block fat
*
* Return value: the block index of the BBD block.
*/
static BLP
get_next_block (MsOle *f, BLP blk, gboolean *err)
{
BLP bbd = GET_BBD_LIST (f, blk / (BB_BLOCK_SIZE / 4));
if (bbd > (f->length / BB_BLOCK_SIZE)) {
*err = TRUE;
return 0;
} else
*err = FALSE;
return MS_OLE_GET_GUINT32 (BB_R_PTR (f, bbd) +
4 * (blk % (BB_BLOCK_SIZE / 4)));
}
/* Builds the FAT */
static int
read_bb (MsOle *f)
{
/* FIXME tenix may be later we wish to split this function */
guint32 numbbd;
BLP lp;
guint32 num_add_bbd_lists;
BLP missing_lps;
BLP missing_bbds;
guint32 visited_add_bbd_list;
BLP tmp;
BLP bbd;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->mem, 0);
f->bb = g_array_new (FALSE, FALSE, sizeof(BLP));
numbbd = GET_NUM_BBD_BLOCKS (f);
/* Sanity checks */
/* FIXME tenix reading big files
if (numbbd < ((f->length - BB_BLOCK_SIZE
+ ((BB_BLOCK_SIZE*BB_BLOCK_SIZE)/4) - 1)
/ ((BB_BLOCK_SIZE*BB_BLOCK_SIZE)/4))) {
printf ("Duff block descriptors\n");
return 0;
}
*/
/* FIXME tenix check if size is small, there's no add bbd lists */
/* Add BBD's that live in the BBD list */
for (lp = 0; (lp < (f->length / BB_BLOCK_SIZE) - 1) &&
(lp < MAX_SIZE_BBD_LIST * BB_BLOCK_SIZE / 4); lp++) {
gboolean err;
tmp = get_next_block (f, lp, &err);
if (err)
return 0;
g_array_append_val (f->bb, tmp);
}
/* Add BBD's that live in the additional BBD lists */
num_add_bbd_lists = GET_NUM_ADD_BBD_LISTS (f);
if (num_add_bbd_lists > 0) {
if (lp != MAX_SIZE_BBD_LIST * BB_BLOCK_SIZE / 4)
return 0;
visited_add_bbd_list = GET_FIRST_ADD_BBD_LIST (f);
missing_lps = (f->length/BB_BLOCK_SIZE) - 1
- MAX_SIZE_BBD_LIST*BB_BLOCK_SIZE/4;
for (lp = 0; lp < missing_lps; lp++) {
if ((lp!=0) && !(lp%(MAX_SIZE_ADD_BBD_LIST*
(BB_BLOCK_SIZE/4)))) {
/* This lp lives in the next add bbd list */
visited_add_bbd_list = MS_OLE_GET_GUINT32(
BB_R_PTR(f,visited_add_bbd_list)
+4*MAX_SIZE_ADD_BBD_LIST);
if (visited_add_bbd_list == END_OF_CHAIN) {
if (lp + 1 != missing_lps) {
/* FIXME tenix error */
}
}
}
/* tmp here means the number of one block that
belongs to the fat */
bbd = MS_OLE_GET_GUINT32 (BB_R_PTR (f, visited_add_bbd_list) + 4*((lp/(BB_BLOCK_SIZE/4))%MAX_SIZE_ADD_BBD_LIST));
tmp = MS_OLE_GET_GUINT32 (BB_R_PTR(f,bbd) +
4 * (lp % (BB_BLOCK_SIZE / 4)));
g_array_append_val (f->bb, tmp);
}
/* FIXME tenix do we check if we have visited all lp's but
there are more additional lists? */
}
/* Mark the bbd list blocks as unused */
for (lp=0; lp < MIN (numbbd, MAX_SIZE_BBD_LIST); lp++) {
TRY_MARK_UNUSED_BLOCK (f->bb, GET_BBD_LIST(f,lp),
SPECIAL_BLOCK);
}
if (num_add_bbd_lists > 0) {
visited_add_bbd_list = GET_FIRST_ADD_BBD_LIST (f);
TRY_MARK_UNUSED_BLOCK (f->bb, visited_add_bbd_list,
ADD_BBD_LIST_BLOCK);
missing_bbds = numbbd - MAX_SIZE_BBD_LIST;
for (lp = 0; lp < missing_bbds; lp++) {
if ((lp!=0) && !(lp % (MAX_SIZE_ADD_BBD_LIST))) {
/* This lp lives in the next add bbd list */
visited_add_bbd_list = MS_OLE_GET_GUINT32(
BB_R_PTR(f,visited_add_bbd_list)
+ 4*MAX_SIZE_ADD_BBD_LIST);
if (visited_add_bbd_list == END_OF_CHAIN) {
if (lp + 1 != missing_lps) {
/* FIXME tenix error */
}
}
TRY_MARK_UNUSED_BLOCK (f->bb,
visited_add_bbd_list,
ADD_BBD_LIST_BLOCK);
}
bbd = MS_OLE_GET_GUINT32 (BB_R_PTR(f, visited_add_bbd_list) + 4*(lp%MAX_SIZE_ADD_BBD_LIST));
TRY_MARK_UNUSED_BLOCK (f->bb, bbd, SPECIAL_BLOCK);
}
}
g_assert (f->bb->len < f->length/BB_BLOCK_SIZE);
/* FIXME tenix better check?:
g_assert (f->bb->len == f->length/BB_BLOCK_SIZE - 1); */
/* More sanity checks */
/* FIXME
for (lp=0; lp<numbbd; lp++) {
BLP bbdblk = GET_BBD_LIST(f, lp);
if (g_array_index(f->bb, BLP, bbdblk) != SPECIAL_BLOCK) {
printf ("Error - BBD blocks not marked correctly\n");
g_array_free (f->bb, TRUE);
return 0;
}
}
*/
#if OLE_DEBUG > 1
dump_header (f);
#endif
return 1;
}
static void
extend_file (MsOle *f, guint blocks)
{
#ifdef HAVE_MMAP
if (f->ole_mmap) {
int file;
guint8 *newptr, zero = 0;
guint32 filesize;
guint32 oldlen;
guint32 icount;
gchar zeroblock [BB_BLOCK_SIZE];
memset (zeroblock, zero, BB_BLOCK_SIZE);
g_assert (f);
file = f->file_des;
g_assert (munmap(f->mem, f->length) != -1);
/* Extend that file by blocks */
if (f->syswrap->getfilesize (file, &filesize)) {
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
if (f->syswrap->lseek (file, 0, SEEK_END) == (off_t)-1) {
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
for (icount = 0; icount < blocks; icount++) {
if (f->syswrap->write (file, zeroblock, BB_BLOCK_SIZE -
((icount == blocks - 1) ? 1 : 0))
== -1) {
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
}
if (f->syswrap->write (file, &zero, 1) == -1) {
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
oldlen = filesize;
if (f->syswrap->getfilesize (file, &(f->length))) {
printf ("Warning couldn't get the size of the file\n");
}
g_assert (f->length == BB_BLOCK_SIZE*blocks + oldlen);
if (f->length%BB_BLOCK_SIZE)
printf ("Warning file %d non-integer number of blocks\n", f->length);
/* NOTE tenix here we don't check if try_mmap is true, because
if it reach here it means f->ole_mmap is true and try_mmap is
true too. This is related with system wrappers. */
newptr = mmap (f->mem, f->length, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0);
#if OLE_DEBUG > 0
if (newptr != f->mem)
printf ("Memory map moved from %p to %p\n",
f->mem, newptr);
if (newptr == MAP_FAILED) {
f->mem = 0;
g_warning ("panic: re-map failed!");
}
#endif /* OLE_DEBUG */
f->mem = newptr;
} else /* !f->ole_mmap */ {
#endif /* HAVE_MMAP */
BBBlkAttr *s;
guint32 blkidx, i;
if (f->bbattr->len) {
s = g_ptr_array_index (f->bbattr, f->bbattr->len-1);
blkidx = s->blk+1;
} else
blkidx = 0;
for (i=0;i<blocks;i++) {
g_ptr_array_add (f->bbattr, bb_blk_attr_new (blkidx++));
f->length+= BB_BLOCK_SIZE;
}
#ifdef HAVE_MMAP
}
#endif /* HAVE_MMAP */
}
static BLP
next_free_bb (MsOle *f)
{
BLP blk, tblk;
g_assert (f);
blk = 0;
g_assert (f->bb->len < f->length/BB_BLOCK_SIZE);
while (blk < f->bb->len)
if (g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK)
return blk;
else
blk++;
extend_file (f, 1);
tblk = UNUSED_BLOCK;
g_array_append_val (f->bb, tblk);
g_assert ((g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK));
g_assert (f->bb->len < f->length/BB_BLOCK_SIZE);
return blk;
}
static int
write_bb (MsOle *f)
{
guint32 numbbd;
BLP lp, lpblk;
int a = BB_BLOCK_SIZE / 4;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->mem, 0);
g_return_val_if_fail (f->bb, 0);
numbbd = (f->bb->len + a - 2) / (a - 1); /* Think really hard! */
SET_NUM_BBD_BLOCKS (f, numbbd);
for (lp=0;lp<numbbd;lp++) {
BLP blk = next_free_bb(f);
SET_BBD_LIST (f, lp, blk);
g_array_index (f->bb, BLP, blk) = SPECIAL_BLOCK;
}
lpblk = 0;
while (lpblk < f->bb->len) { /* Described blocks */
guint8 *mem = BB_W_PTR(f, GET_BBD_LIST(f, lpblk/(BB_BLOCK_SIZE/4)));
MS_OLE_SET_GUINT32 (mem + (lpblk%(BB_BLOCK_SIZE/4))*4,
g_array_index (f->bb, BLP, lpblk));
lpblk++;
}
while (lpblk % (BB_BLOCK_SIZE/4) != 0) { /* Undescribed blocks */
guint8 *mem;
g_assert (lpblk/(BB_BLOCK_SIZE/4) < numbbd);
mem = BB_W_PTR(f, GET_BBD_LIST(f, lpblk/(BB_BLOCK_SIZE/4)));
MS_OLE_SET_GUINT32 (mem + (lpblk%(BB_BLOCK_SIZE/4))*4,
UNUSED_BLOCK);
lpblk++;
}
g_array_free (f->bb, TRUE);
f->bb = 0;
return 1;
}
static BLP
next_free_sb (MsOle *f)
{
BLP blk, tblk;
g_assert (f);
blk = 0;
while (blk < f->sb->len)
if (g_array_index (f->sb, BLP, blk) == UNUSED_BLOCK)
return blk;
else
blk++;
tblk = UNUSED_BLOCK;
g_array_append_val (f->sb, tblk);
g_assert ((g_array_index (f->sb, BLP, blk) == UNUSED_BLOCK));
g_assert (blk < f->sb->len);
if ((f->sb->len + (BB_BLOCK_SIZE/SB_BLOCK_SIZE) - 1) / (BB_BLOCK_SIZE/SB_BLOCK_SIZE) >= f->sbf->len) {
/* Create an extra big block on the small block stream */
BLP new_sbf = next_free_bb(f);
if (f->sbf->len > 0)
g_array_index (f->bb, BLP,
g_array_index (f->sbf, BLP, f->sbf->len-1)) = new_sbf;
g_array_append_val (f->sbf, new_sbf);
g_array_index (f->bb, BLP, new_sbf) = END_OF_CHAIN;
}
g_assert ((f->sb->len + (BB_BLOCK_SIZE/SB_BLOCK_SIZE) - 1) / (BB_BLOCK_SIZE/SB_BLOCK_SIZE) <= f->sbf->len);
return blk;
}
static guint8 *
get_pps_ptr (MsOle *f, PPS_IDX i, gboolean forwrite)
{
int lp;
BLP blk = GET_ROOT_STARTBLOCK (f);
lp = i/(BB_BLOCK_SIZE/PPS_BLOCK_SIZE);
while (lp && blk != END_OF_CHAIN) {
if (blk == SPECIAL_BLOCK ||
blk == UNUSED_BLOCK) {
printf ("Duff block in root chain\n");
return 0;
}
lp--;
blk = NEXT_BB (f, blk);
}
if (blk == END_OF_CHAIN) {
printf ("Serious error finding pps %d\n", i);
return 0;
}
#if OLE_DEBUG > 0
printf ("get_pps_ptr: blk = %d\n", blk);
#endif
if (forwrite)
return BB_W_PTR(f, blk) + (i%(BB_BLOCK_SIZE/PPS_BLOCK_SIZE))*PPS_BLOCK_SIZE;
else
return BB_R_PTR(f, blk) + (i%(BB_BLOCK_SIZE/PPS_BLOCK_SIZE))*PPS_BLOCK_SIZE;
}
static gint
pps_compare_func (PPS *a, PPS *b)
{
g_return_val_if_fail (a, 0);
g_return_val_if_fail (b, 0);
g_return_val_if_fail (a->name, 0);
g_return_val_if_fail (b->name, 0);
return g_strcasecmp (b->name, a->name);
}
static void
pps_decode_tree (MsOle *f, PPS_IDX p, PPS *parent)
{
PPS *pps;
guint8 *mem;
if (p == PPS_END_OF_CHAIN)
return;
pps = g_new (PPS, 1);
pps->sig = PPS_SIG;
mem = get_pps_ptr (f, p, FALSE);
if (!mem) {
printf ("Serious directory error %d\n", p);
f->pps = NULL;
return;
}
#if OLE_DEBUG > 0
printf ("pps_decode_tree: mem (offset)= %#8.8x\n", mem - f->mem);
#endif
pps->name = pps_get_text (mem, PPS_GET_NAME_LEN(mem));
pps->type = PPS_GET_TYPE (mem);
pps->size = PPS_GET_SIZE (mem);
pps->children = NULL;
pps->parent = parent;
pps->idx = 0;
if (!pps->name) { /* Make safe */
printf ("how odd: blank named file in directory\n");
g_free (pps);
return;
}
f->num_pps++;
if (parent) {
#if OLE_DEBUG > 0
printf ("Inserting '%s' into '%s'\n", pps->name, parent->name);
#endif
parent->children = g_list_insert_sorted (parent->children, pps,
(GCompareFunc)pps_compare_func);
}
else {
#if OLE_DEBUG > 0
printf ("Setting root to '%s'\n", pps->name);
#endif
f->pps = g_list_append (0, pps);
}
if (PPS_GET_NEXT(mem) != PPS_END_OF_CHAIN)
pps_decode_tree (f, PPS_GET_NEXT(mem), parent);
if (PPS_GET_PREV(mem) != PPS_END_OF_CHAIN)
pps_decode_tree (f, PPS_GET_PREV(mem), parent);
if (PPS_GET_DIR (mem) != PPS_END_OF_CHAIN)
pps_decode_tree (f, PPS_GET_DIR(mem), pps);
pps->start = PPS_GET_STARTBLOCK (mem);
#if OLE_DEBUG > 1
printf ("PPS decode : '%s'\n", pps->name?pps->name:"Null");
ms_ole_dump (mem, PPS_BLOCK_SIZE);
#endif
return;
}
static int
read_pps (MsOle *f)
{
PPS *pps;
g_return_val_if_fail (f, 0);
f->num_pps = 0;
pps_decode_tree (f, PPS_ROOT_INDEX, NULL);
if (!f->pps || g_list_length (f->pps) < 1 ||
g_list_length (f->pps) > 1) {
printf ("Invalid root chain\n");
return 0;
} else if (!f->pps->data) {
printf ("No root entry\n");
return 0;
}
/* Fiddle root, perhaps our get_text is broken */
/* perhaps it is just an MS oddity in coding */
pps = f->pps->data;
if (pps->name)
g_free (pps->name);
pps->name = g_strdup ("Root Entry");
{ /* Free up the root chain */
BLP blk, last;
last = blk = GET_ROOT_STARTBLOCK (f);
while (blk != END_OF_CHAIN) {
last = blk;
blk = NEXT_BB (f, blk);
g_array_index (f->bb, BLP, last) = UNUSED_BLOCK;
}
}
if (!f->pps) {
printf ("Root directory too small\n");
return 0;
}
return 1;
}
/**
* Write the blocks main data recursively.
**/
static void
pps_encode_tree_initial (MsOle *f, GList *list, PPS_IDX *p)
{
int lp, max;
guint8 *mem;
PPS *pps;
g_return_if_fail (list);
g_return_if_fail (list->data);
pps = list->data;
pps->idx = *p;
(*p)++;
#if OLE_DEBUG > 0
printf ("encoding '%s' as %d\n", pps->name, pps->idx);
#endif
mem = get_pps_ptr (f, pps->idx, TRUE);
/* Blank stuff I don't understand */
for (lp=0;lp<PPS_BLOCK_SIZE;lp++)
MS_OLE_SET_GUINT8(mem+lp, 0);
if (pps->name) {
max = strlen (pps->name);
if (max >= (PPS_BLOCK_SIZE/4))
max = (PPS_BLOCK_SIZE/4);
for (lp=0;lp<max;lp++)
MS_OLE_SET_GUINT16(mem + lp*2, pps->name[lp]);
} else {
printf ("No name %d\n", *p);
max = -1;
}
PPS_SET_NAME_LEN(mem, (max+1)*2);
/* Magic numbers */
if (pps->idx == PPS_ROOT_INDEX) { /* Only Root */
MS_OLE_SET_GUINT32 (mem + 0x50, 0x00020900);
MS_OLE_SET_GUINT32 (mem + 0x58, 0x000000c0);
MS_OLE_SET_GUINT32 (mem + 0x5c, 0x46000000);
MS_OLE_SET_GUINT8 (mem + 0x43, 0x01); /* or zero ? */
} else if (pps->size >= BB_THRESHOLD) {
MS_OLE_SET_GUINT32 (mem + 0x50, 0x00020900);
MS_OLE_SET_GUINT8 (mem + 0x43, 0x01);
} else {
MS_OLE_SET_GUINT32 (mem + 0x64, 0x09299c3c);
MS_OLE_SET_GUINT32 (mem + 0x6c, 0x09299c3c);
MS_OLE_SET_GUINT8 (mem + 0x43, 0x00);
}
PPS_SET_TYPE (mem, pps->type);
PPS_SET_SIZE (mem, pps->size);
PPS_SET_STARTBLOCK(mem, pps->start);
PPS_SET_NEXT (mem, PPS_END_OF_CHAIN);
PPS_SET_PREV (mem, PPS_END_OF_CHAIN);
PPS_SET_DIR (mem, PPS_END_OF_CHAIN);
#if OLE_DEBUG > 1
printf ("Encode '%s' as \n", pps->name);
ms_ole_dump (mem, PPS_BLOCK_SIZE);
#endif
if (pps->children)
pps_encode_tree_initial (f, pps->children, p);
if (g_list_next (list))
pps_encode_tree_initial (f, g_list_next(list), p);
}
/*
* Chain the blocks together afterwards
*/
static void
pps_encode_tree_chain (MsOle *f, GList *list)
{
PPS *parent; /* parent's PPS */
int len; /* how many childrens are there */
GList *lchildren; /* visited children */
PPS *children; /* visited children's PPS */
PPS *next; /* next children's PPS */
PPS *prev; /* previous children's PPS */
guint8 *mem; /* a PPS in memory */
guint8 *mem_parent; /* a PPS in memory */
gint i;
int half_way;
g_return_if_fail (list);
g_return_if_fail (list->data);
parent = list->data;
len = g_list_length (parent->children);
half_way = len / 2;
lchildren = parent->children;
/* The base node of the directory */
/* Choose the first child */
mem_parent = get_pps_ptr (f, parent->idx, TRUE);
if (len == 1) {
PPS_SET_DIR (mem_parent, ((PPS *)(lchildren->data))->idx);
#if OLE_DEBUG > 1
printf ("tenix3 Final encode '%s' as \n",
((PPS *)(parent))->name);
ms_ole_dump (mem_parent, PPS_BLOCK_SIZE);
printf ("tenix3 Final encode '%s' as \n",
((PPS *)(lchildren->data))->name);
ms_ole_dump (get_pps_ptr (f, ((PPS *)(lchildren->data))->idx, FALSE),
PPS_BLOCK_SIZE);
#endif
return;
}
#if OLE_DEBUG > 1
if (len == 0)
printf ("Empty directory '%s'\n", ((PPS *)(children))->name);
#endif
i = 0;
for (; lchildren; lchildren = g_list_next (lchildren)) {
children = lchildren->data;
if (children->type == MsOleStorageT)
pps_encode_tree_chain (f, lchildren);
if (i == half_way)
PPS_SET_DIR (mem_parent, ((PPS *)(children))->idx);
mem = get_pps_ptr (f, children->idx, TRUE);
if (i == half_way) {
if (g_list_previous (lchildren)) {
prev = g_list_previous(lchildren)->data;
PPS_SET_PREV (mem, prev->idx);
}
if (g_list_next (lchildren)) {
next = g_list_next (lchildren)->data;
PPS_SET_NEXT (mem, next->idx);
}
} else if (i < half_way) {
if (g_list_previous(lchildren)) {
prev = g_list_previous (lchildren)->data;
PPS_SET_PREV (mem, prev->idx);
}
} else /* i > half_way */ {
if (g_list_next(lchildren)) {
next = g_list_next (lchildren)->data;
PPS_SET_NEXT (mem, next->idx);
}
}
#if OLE_DEBUG > 1
printf ("tenix1 Final encode '%s' as \n",
((PPS *)(children))->name);
ms_ole_dump (mem, PPS_BLOCK_SIZE);
#endif
i++;
}
#if OLE_DEBUG > 1
printf ("tenix2 Final encode '%s' as \n", ((PPS *)(parent))->name);
ms_ole_dump (mem_parent, PPS_BLOCK_SIZE);
#endif
}
static int
write_pps (MsOle *f)
{
int lp;
PPS_IDX idx;
BLP blk = END_OF_CHAIN;
BLP last = END_OF_CHAIN;
/* Build the root chain */
for (lp=0;lp<(f->num_pps+(BB_BLOCK_SIZE/PPS_BLOCK_SIZE)-1)/(BB_BLOCK_SIZE/PPS_BLOCK_SIZE);lp++) {
last = blk;
blk = next_free_bb (f);
g_assert (g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK);
if (last != END_OF_CHAIN)
g_array_index (f->bb, BLP, last) = blk;
else {
#if OLE_DEBUG > 0
printf ("Set root block to %d\n", blk);
#endif
SET_ROOT_STARTBLOCK (f, blk);
}
g_array_index (f->bb, BLP, blk) = END_OF_CHAIN;
}
g_assert (GET_ROOT_STARTBLOCK(f) != END_OF_CHAIN);
idx = PPS_ROOT_INDEX;
pps_encode_tree_initial (f, f->pps, &idx);
pps_encode_tree_chain (f, f->pps);
f->pps = 0;
f->num_pps = 0;
return 1;
}
static int
read_sb (MsOle *f)
{
BLP ptr;
int lastidx, idx;
PPS *root;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->pps, 0);
root = f->pps->data;
g_return_val_if_fail (root, 0);
f->sbf = g_array_new (FALSE, FALSE, sizeof(BLP));
f->sb = g_array_new (FALSE, FALSE, sizeof(BLP));
/* List of big blocks in SB file */
ptr = root->start;
#if OLE_DEBUG > 0
printf ("Starting Small block file at %d\n", root->start);
#endif
while (ptr != END_OF_CHAIN) {
if (ptr == UNUSED_BLOCK ||
ptr == SPECIAL_BLOCK) {
printf ("Corrupt small block file: serious error, "
"invalid block in chain\n");
g_array_free (f->sbf, TRUE);
f->sbf = 0;
return 0;
}
g_array_append_val (f->sbf, ptr);
ptr = NEXT_BB (f, ptr);
}
/* Description of small blocks */
lastidx = -1;
idx = 0;
ptr = GET_SBD_STARTBLOCK (f);
if (f->sbf->len == 0 && ptr != END_OF_CHAIN) {
printf ("No small block file, but small block depot start block exists!: "
"ignore depot, since there's no small block files after all.\n");
ptr = END_OF_CHAIN;
}
while (ptr != END_OF_CHAIN) {
guint32 lp;
if (ptr == UNUSED_BLOCK ||
ptr == SPECIAL_BLOCK) {
printf ("Corrupt file descriptor: serious error, "
"invalid block in chain\n");
g_array_free (f->sb, TRUE);
f->sb = 0;
return 0;
}
for (lp=0;lp<BB_BLOCK_SIZE/4;lp++) {
BLP p = MS_OLE_GET_GUINT32 (BB_R_PTR(f, ptr) + lp*4);
g_array_append_val (f->sb, p);
if (p != UNUSED_BLOCK)
lastidx = idx;
idx++;
}
ptr = NEXT_BB (f, ptr);
}
if (lastidx>0)
g_array_set_size (f->sb, lastidx+1);
if (f->sbf->len * BB_BLOCK_SIZE < f->sb->len*SB_BLOCK_SIZE) {
printf ("Not enough small block file for descriptors\n"
"sbf->len == %d, sb->len == %d\n", f->sbf->len,
f->sb->len);
return 0;
}
return 1;
}
static int
write_sb (MsOle *f)
{
guint32 lp, lastused;
PPS *root;
BLP sbd_start = END_OF_CHAIN;
BLP sbf_start = END_OF_CHAIN;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->pps, 0);
root = f->pps->data;
if (f->sbf->len * BB_BLOCK_SIZE < f->sb->len*SB_BLOCK_SIZE) {
printf ("Not enough descriptor / blocks being written %d %d\n",
f->sbf->len, f->sb->len);
}
if (f->sbf->len>0)
sbf_start = g_array_index (f->sbf, BLP, 0);
lastused = END_OF_CHAIN;
for (lp=0;lp<f->sb->len;lp++) {
if (g_array_index (f->sb, BLP, lp) != UNUSED_BLOCK)
lastused = lp;
}
if (lastused != END_OF_CHAIN) { /* Bother writing stuff */
guint8 *mem = 0;
guint32 num_sbdf = (lastused + (BB_BLOCK_SIZE/4)-1) /
(BB_BLOCK_SIZE/4);
BLP blk = END_OF_CHAIN, last;
#if OLE_DEBUG > 0
printf ("Num SB descriptor blocks : %d\n", num_sbdf);
#endif
for (lp=0;lp<num_sbdf*(BB_BLOCK_SIZE/4);lp++) {
BLP set;
if (lp%(BB_BLOCK_SIZE/4) == 0) {
last = blk;
blk = next_free_bb(f);
if (!lp)
sbd_start = blk;
if (last != END_OF_CHAIN)
g_array_index (f->bb, BLP, last) = blk;
g_array_index (f->bb, BLP, blk) = END_OF_CHAIN;
mem = BB_W_PTR (f, blk);
}
if (lp<f->sb->len)
set = g_array_index (f->sb, BLP, lp);
else
set = UNUSED_BLOCK;
MS_OLE_SET_GUINT32 (mem + (lp%(BB_BLOCK_SIZE/4))*4, set);
}
} else {
#if OLE_DEBUG > 0
printf ("Blank SB allocation\n");
#endif
sbf_start = END_OF_CHAIN;
}
root->start = sbf_start;
SET_SBD_STARTBLOCK (f, sbd_start);
g_array_free (f->sb, TRUE);
g_array_free (f->sbf, TRUE);
f->sb = 0;
f->sbf = 0;
return 1;
}
static int
ms_ole_setup (MsOle *f)
{
if (!f->ole_mmap) {
guint32 i;
f->bbattr = g_ptr_array_new ();
for (i = 0; i <(f->length / BB_BLOCK_SIZE) + 1; i++)
g_ptr_array_add (f->bbattr, bb_blk_attr_new(i));
}
if (read_bb (f) &&
read_pps (f) &&
read_sb (f)) {
#if OLE_DEBUG > 1
printf ("Just read header of\n");
dump_header (f);
#endif
return 1;
}
return 0;
}
static int
ms_ole_cleanup (MsOle *f)
{
if (f->mode != 'w') /* Nothing to write */
return 1;
#if OLE_DEBUG > 1
printf ("About to write header of: \n");
dump_header (f);
#endif
if (write_sb (f) &&
write_pps (f) &&
write_bb (f))
return 1;
return 0;
}
static MsOle *
new_null_msole ()
{
MsOle *f = g_new0 (MsOle, 1);
f->mem = (guint8 *)0xdeadbeef;
f->length = 0;
f->mode = 'r';
f->bb = 0;
f->bbattr = 0;
f->sb = 0;
f->sbf = 0;
f->pps = 0;
f->dirty = 0;
return f;
}
/**
* ms_ole_ref:
* @fs: filesystem object.
*
* Increment by one the count of references to the filesystem.
**/
void
ms_ole_ref (MsOle *fs)
{
g_return_if_fail (fs != NULL);
fs->ref_count++;
}
/**
* ms_ole_unref:
* @fs: filesystem object.
*
* Decrement by one the count of references to the filesystem.
**/
void
ms_ole_unref (MsOle *fs)
{
g_return_if_fail (fs != NULL);
fs->ref_count--;
}
/**
* ms_ole_open_vfs:
* @fs: filesystem object.
* @path: path to the filesystem-in-the file on the actual filesystem.
* @try_mmap: TRUE if try to mmap(2) the filesystem-in-a-file,
* instead of opening.
* @wrappers: system functions wrappers, %NULL if standard functions are used.
*
* Opens the filesystem-in-the-file @path and creates the filesystem object @fs.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_open_vfs (MsOle **f, const char *name, gboolean try_mmap,
MsOleSysWrappers *wrappers)
{
#ifdef HAVE_MMAP
int prot = PROT_READ | PROT_WRITE;
#endif
int file;
if (!f)
return MS_OLE_ERR_BADARG;
#if OLE_DEBUG > 0
printf ("New OLE file '%s'\n", name);
#endif
*f = new_null_msole();
take_wrapper_functions (*f, wrappers);
(*f)->file_des = file = (*f)->syswrap->open2 (name, O_RDWR);
(*f)->ref_count = 0;
(*f)->mode = 'w';
if (file == -1) {
(*f)->file_des = file = (*f)->syswrap->open2 (name, O_RDONLY);
(*f)->mode = 'r';
prot &= ~PROT_WRITE;
}
if ((file == -1) || !((*f)->syswrap->isregfile (file))) {
/* FIXME tenix is not a memory leak not to close file? */
printf ("No such file '%s'\n", name);
g_free (*f) ;
return MS_OLE_ERR_EXIST;
}
if ((*f)->syswrap->getfilesize( file, &((*f)->length) )) {
printf ("Couldn't get the size of file '%s'\n", name);
(*f)->syswrap->close (file) ;
g_free (*f) ;
return MS_OLE_ERR_EXIST;
}
if ((*f)->length <= 0x4c) { /* Bad show */
#if OLE_DEBUG > 0
printf ("File '%s' too short\n", name);
#endif
(*f)->syswrap->close (file) ;
g_free (*f) ;
return MS_OLE_ERR_FORMAT;
}
if (try_mmap) {
#ifdef HAVE_MMAP
(*f)->ole_mmap = TRUE;
(*f)->mem = mmap (0, (*f)->length, prot, MAP_SHARED, file, 0);
if (!(*f)->mem || (caddr_t)(*f)->mem == (caddr_t)MAP_FAILED) {
#endif
// g_warning ("I can't mmap that file, falling back to slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
if (!(*f)->mem
|| ((*f)->syswrap->read (file, (*f)->mem, BB_BLOCK_SIZE)
== -1)) {
printf ("Error reading header\n");
g_free (*f);
return MS_OLE_ERR_EXIST;
}
#ifdef HAVE_MMAP
}
#endif
} else /* !try_mmap */ {
// g_warning ("I won't mmap that file, using a slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
if (!(*f)->mem
|| ((*f)->syswrap->read (file, (*f)->mem, BB_BLOCK_SIZE)
== -1)) {
printf ("Error reading header\n");
g_free (*f);
return MS_OLE_ERR_EXIST;
}
} /* try_mmap */
if (MS_OLE_GET_GUINT32((*f)->mem ) != 0xe011cfd0 ||
MS_OLE_GET_GUINT32((*f)->mem + 4) != 0xe11ab1a1) {
#if OLE_DEBUG > 0
printf ("Failed OLE2 magic number %x %x\n",
MS_OLE_GET_GUINT32((*f)->mem), MS_OLE_GET_GUINT32((*f)->mem+4));
#endif
ms_ole_destroy (f);
return MS_OLE_ERR_FORMAT;
}
if ((*f)->length % BB_BLOCK_SIZE)
printf ("Warning file '%s':%d non-integer number of blocks\n",
name, (*f)->length);
if (!ms_ole_setup (*f)) {
printf ("'%s' : duff file !\n", name);
ms_ole_destroy (f);
return MS_OLE_ERR_FORMAT;
}
g_assert ((*f)->bb->len < (*f)->length/BB_BLOCK_SIZE);
#if OLE_DEBUG > 0
printf ("New OLE file '%s'\n", name);
#endif
/* If writing then when destroy commit it */
return MS_OLE_ERR_OK;
}
MsOleErr ms_ole_open_vfs_body (MsOle **f, const char *name, gboolean try_mmap, MsOleSysWrappers *wrappers, char *jp_buf_ptr, size_t jp_buf_len)
{
#ifdef HAVE_MMAP
int prot = PROT_READ | PROT_WRITE;
#endif
int file;
if (!f)
return MS_OLE_ERR_BADARG;
#if OLE_DEBUG > 0
printf ("New OLE file '%s'\n", name);
#endif
*f = new_null_msole();
jp_msOle = *f;
(*f)->buf = jp_buf_ptr;
(*f)->len = jp_buf_len;
(*f)->idx = 0;
// take_wrapper_functions (*f, wrappers);
take_wrapper_functions (*f, &default_wrappers_body);
(*f)->file_des = file = (*f)->syswrap->open2 (name, O_RDWR);
(*f)->ref_count = 0;
(*f)->mode = 'w';
if (file == -1) {
(*f)->file_des = file = (*f)->syswrap->open2 (name, O_RDONLY);
(*f)->mode = 'r';
prot &= ~PROT_WRITE;
}
if ((file == -1) || !((*f)->syswrap->isregfile (file))) {
/* FIXME tenix is not a memory leak not to close file? */
printf ("No such file '%s'\n", name);
g_free (*f) ;
return MS_OLE_ERR_EXIST;
}
if ((*f)->syswrap->getfilesize( file, &((*f)->length) )) {
printf ("Couldn't get the size of file '%s'\n", name);
(*f)->syswrap->close (file) ;
g_free (*f) ;
return MS_OLE_ERR_EXIST;
}
if ((*f)->length <= 0x4c) { /* Bad show */
#if OLE_DEBUG > 0
printf ("File '%s' too short\n", name);
#endif
(*f)->syswrap->close (file) ;
g_free (*f) ;
return MS_OLE_ERR_FORMAT;
}
if (try_mmap) {
#ifdef HAVE_MMAP
(*f)->ole_mmap = TRUE;
(*f)->mem = mmap (0, (*f)->length, prot, MAP_SHARED, file, 0);
if (!(*f)->mem || (caddr_t)(*f)->mem == (caddr_t)MAP_FAILED) {
#endif
// g_warning ("I can't mmap that file, falling back to slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
if (!(*f)->mem
|| ((*f)->syswrap->read (file, (*f)->mem, BB_BLOCK_SIZE)
== -1)) {
printf ("Error reading header\n");
g_free (*f);
return MS_OLE_ERR_EXIST;
}
#ifdef HAVE_MMAP
}
#endif
} else /* !try_mmap */ {
// g_warning ("I won't mmap that file, using a slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
if (!(*f)->mem
|| ((*f)->syswrap->read (file, (*f)->mem, BB_BLOCK_SIZE)
== -1)) {
printf ("Error reading header\n");
g_free (*f);
return MS_OLE_ERR_EXIST;
}
} /* try_mmap */
if (MS_OLE_GET_GUINT32((*f)->mem ) != 0xe011cfd0 ||
MS_OLE_GET_GUINT32((*f)->mem + 4) != 0xe11ab1a1) {
#if OLE_DEBUG > 0
printf ("Failed OLE2 magic number %x %x\n",
MS_OLE_GET_GUINT32((*f)->mem), MS_OLE_GET_GUINT32((*f)->mem+4));
#endif
ms_ole_destroy (f);
return MS_OLE_ERR_FORMAT;
}
if ((*f)->length % BB_BLOCK_SIZE)
printf ("Warning file '%s':%d non-integer number of blocks\n", name, (*f)->length);
if (!ms_ole_setup (*f)) {
printf ("'%s' : duff file !\n", name);
ms_ole_destroy (f);
return MS_OLE_ERR_FORMAT;
}
g_assert ((*f)->bb->len < (*f)->length/BB_BLOCK_SIZE);
#if OLE_DEBUG > 0
printf ("New OLE file '%s'\n", name);
#endif
/* If writing then when destroy commit it */
return MS_OLE_ERR_OK;
}
/**
* ms_ole_create_vfs:
* @fs: filesystem object.
* @path: path to the filesystem-in-the file on the actual filesystem.
* @try_mmap: TRUE if try to mmap(2) the filesystem-in-a-file,
* instead of opening.
* @wrappers: system functions wrappers, %NULL if standard functions are used.
*
* Creates the filesystem-in-the-file @path and creates the filesystem @fs.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_create_vfs (MsOle **f, const char *name, gboolean try_mmap,
MsOleSysWrappers *wrappers)
{
int file, zero=0;
int init_blocks = 1, lp;
if (!f)
return MS_OLE_ERR_BADARG;
*f = new_null_msole ();
take_wrapper_functions (*f, wrappers);
if ((file = (*f)->syswrap->open3 (name,
O_RDWR|O_CREAT|O_TRUNC|O_NONBLOCK,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP))
== -1) {
printf ("Can't create file '%s'\n", name);
g_free (*f);
*f = NULL;
return MS_OLE_ERR_PERM;
}
if (((*f)->syswrap->lseek (file, BB_BLOCK_SIZE * init_blocks - 1,
SEEK_SET) == (off_t)-1) ||
((*f)->syswrap->write (file, &zero, 1) == -1)) {
printf ("Serious error extending file to %d bytes\n",
BB_BLOCK_SIZE*init_blocks);
g_free (*f);
*f = NULL;
return MS_OLE_ERR_SPACE;
}
(*f)->ref_count = 0;
(*f)->file_des = file;
(*f)->mode = 'w';
if ((*f)->syswrap->getfilesize (file, &((*f)->length))) {
printf ("Warning couldn't get the size of the file '%s'\n",
name);
}
if ((*f)->length % BB_BLOCK_SIZE)
printf ("Warning file %d non-integer number of blocks\n",
(*f)->length);
if (try_mmap) {
#ifdef HAVE_MMAP
(*f)->ole_mmap = TRUE;
(*f)->mem = mmap (0, (*f)->length, PROT_READ|PROT_WRITE,
MAP_SHARED, file, 0);
if (!(*f)->mem || (caddr_t)(*f)->mem == (caddr_t)MAP_FAILED) {
#endif
// g_warning ("I can't mmap that file, falling back to slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
#ifdef HAVE_MMAP
}
#endif
} else /* !try_mmap */ {
// g_warning ("I won't mmap that file, using a slower method");
(*f)->ole_mmap = FALSE;
(*f)->mem = g_new (guint8, BB_BLOCK_SIZE);
} /* try_mmap */
/* The header block */
for (lp = 0; lp < BB_BLOCK_SIZE / 4; lp++)
MS_OLE_SET_GUINT32((*f)->mem + lp * 4,
(lp < (0x52 / 4)) ? 0: UNUSED_BLOCK);
MS_OLE_SET_GUINT32((*f)->mem, 0xe011cfd0); /* Magic number */
MS_OLE_SET_GUINT32((*f)->mem + 4, 0xe11ab1a1);
/* More magic numbers */
MS_OLE_SET_GUINT32((*f)->mem + 0x18, 0x0003003e);
MS_OLE_SET_GUINT32((*f)->mem + 0x1c, 0x0009fffe);
MS_OLE_SET_GUINT32((*f)->mem + 0x20, 0x6);
MS_OLE_SET_GUINT32((*f)->mem + 0x38, 0x00001000);
/* MS_OLE_SET_GUINT32((*f)->mem + 0x40, 0x1); */
MS_OLE_SET_GUINT32((*f)->mem + 0x44, 0xfffffffe);
SET_NUM_BBD_BLOCKS (*f, 0);
SET_ROOT_STARTBLOCK (*f, END_OF_CHAIN);
SET_SBD_STARTBLOCK (*f, END_OF_CHAIN);
{
PPS *p;
(*f)->bb = g_array_new (FALSE, FALSE, sizeof(BLP));
(*f)->sb = g_array_new (FALSE, FALSE, sizeof(BLP));
(*f)->sbf = g_array_new (FALSE, FALSE, sizeof(BLP));
p = g_new(PPS, 1);
p->sig = PPS_SIG;
p->name = g_strdup ("Root Entry");
p->start = END_OF_CHAIN;
p->type = MsOleRootT;
p->size = 0;
p->children = NULL;
p->parent = NULL;
(*f)->pps = g_list_append (0, p);
(*f)->num_pps = 1;
if ((*f)->ole_mmap)
(*f)->bbattr = NULL;
else
(*f)->bbattr = g_ptr_array_new ();
}
g_assert ((*f)->bb->len < (*f)->length/BB_BLOCK_SIZE);
return MS_OLE_ERR_OK;
}
static void
destroy_pps (GList *l)
{
GList *tmp;
for (tmp = l; tmp; tmp = g_list_next (tmp)) {
PPS *pps = tmp->data;
if (pps->name)
g_free (pps->name);
destroy_pps (pps->children);
g_free (pps);
}
g_list_free (l);
}
/**
* ms_ole_destroy:
* @fs: filesystem object.
*
* Closes the filesystem @fs and truncates any free blocks.
**/
void
ms_ole_destroy (MsOle **ptr)
{
MsOle *f = *ptr;
#if OLE_DEBUG > 0
printf ("FIXME: should truncate to remove unused blocks\n");
#endif
if (f) {
if (f->ref_count != 0)
g_warning ("Unclosed files exist on this OLE stream");
if (f->dirty)
ms_ole_cleanup (f);
if (f->mem == (void *)0xdeadbeef)
f->mem = NULL;
else if (f->ole_mmap) {
#ifdef HAVE_MMAP
munmap (f->mem, f->length);
#else
g_warning ("Unmapping while we dont have mmap call");
#endif
} else {
guint32 i;
for (i = 0; (f->bbattr) && (i < f->bbattr->len); i++) {
BBBlkAttr *attr = g_ptr_array_index (f->bbattr, i);
if (f->dirty && attr->dirty)
write_cache_block (f, attr);
g_free (attr->data);
attr->data = 0;
}
if (f->dirty) {
f->syswrap->lseek (f->file_des, 0, SEEK_SET);
f->syswrap->write (f->file_des, f->mem,
BB_BLOCK_SIZE);
}
g_free (f->mem);
f->mem = 0;
}
destroy_pps (f->pps);
f->syswrap->close (f->file_des);
g_free (f);
#if OLE_DEBUG > 0
printf ("Closing OLE file\n");
#endif
}
*ptr = NULL;
}
/**
* ms_ole_dump:
* @ptr: memory area to be dumped.
* @len: how many bytes will be dumped.
*
* Dump @len bytes from the memory location given by @ptr.
**/
void
ms_ole_dump (guint8 const *ptr, guint32 len)
{
guint32 lp,lp2;
guint32 off;
for (lp = 0;lp<(len+15)/16;lp++)
{
printf ("%8x | ", lp*16);
for (lp2=0;lp2<16;lp2++) {
off = lp2 + (lp<<4);
off<len?printf("%2x ", ptr[off]):printf("XX ");
}
printf ("| ");
for (lp2=0;lp2<16;lp2++) {
off = lp2 + (lp<<4);
printf ("%c", off<len?(ptr[off]>'!'&&ptr[off]<127?ptr[off]:'.'):'*');
}
printf ("\n");
}
}
/*
* Redundant stream check function.
*/
static void
check_stream (MsOleStream *s)
{
BLP blk;
guint32 idx;
PPS *p;
MsOle *f;
g_return_if_fail (s);
g_return_if_fail (s->file);
f = s->file;
p = s->pps;
g_return_if_fail (p);
blk = p->start;
idx = 0;
if (s->type == MsOleSmallBlock) {
while (blk != END_OF_CHAIN) {
g_assert (g_array_index (s->blocks, BLP, idx) ==
blk);
#if OLE_DEBUG > 2
ms_ole_dump (GET_SB_R_PTR(f, blk), SB_BLOCK_SIZE);
#endif
blk = NEXT_SB (f, blk);
idx++;
}
} else {
while (blk != END_OF_CHAIN) {
g_assert (g_array_index (s->blocks, BLP, idx) ==
blk);
#if OLE_DEBUG > 2
ms_ole_dump (BB_R_PTR(f, blk), BB_BLOCK_SIZE);
#endif
blk = NEXT_BB (f, blk);
idx++;
}
}
}
static MsOlePos
tell_pos (MsOleStream *s)
{
return s->position;
}
/*
* Free the allocation chains, and free up the blocks.
* "It was for freedom that Christ has set us free."
* Galatians 5:11
*/
static void
free_allocation (MsOle *f, guint32 startblock, gboolean is_big_block_stream)
{
g_return_if_fail (f);
#if OLE_DEBUG > 0
printf ("Free allocation %d : (%d)\n", startblock,
is_big_block_stream);
#endif
if (is_big_block_stream)
{
BLP p = startblock;
printf ("FIXME: this should also free up blocks\n");
while (p != END_OF_CHAIN) {
BLP next = NEXT_BB (f,p);
if (next == p) {
printf ("Serious bug: cyclic ring in BB allocation\n");
return;
} else if (p == SPECIAL_BLOCK ||
p == UNUSED_BLOCK) {
printf ("Serious bug: Special / Unused block "
"in BB allocation\n");
return;
}
g_array_index (f->bb, BLP, p) = UNUSED_BLOCK;
p = next;
}
}
else
{
BLP p = startblock;
while (p != END_OF_CHAIN) {
BLP next = NEXT_SB (f,p);
if (next == p) {
printf ("Serious bug: cyclic ring in SB allocation\n");
return;
} else if (p == SPECIAL_BLOCK ||
p == UNUSED_BLOCK) {
printf ("Serious bug: Special / Unused block "
"in SB allocation\n");
return;
}
g_array_index (f->sb, BLP, p) = UNUSED_BLOCK;
p = next;
}
/* Seek forwards to find blank sbf blocks */
{
guint32 lp;
BLP lastused = END_OF_CHAIN;
for (lp=0;lp<f->sb->len;lp++) {
if (g_array_index (f->sb, BLP, lp) != UNUSED_BLOCK)
lastused = lp;
}
if (lastused == END_OF_CHAIN) {
for (lp=0;lp<f->sbf->len;lp++) {
BLP sbfd = g_array_index (f->sbf, BLP, lp);
g_array_index (f->bb, BLP, sbfd) = UNUSED_BLOCK;
}
g_array_set_size (f->sbf, 0);
g_array_set_size (f->sb, 0);
} else {
guint32 sbf_needed = (lastused+(BB_BLOCK_SIZE/SB_BLOCK_SIZE)-1) /
(BB_BLOCK_SIZE/SB_BLOCK_SIZE);
if (sbf_needed == f->sbf->len)
return;
for (lp=sbf_needed;lp<f->sbf->len;lp++) {
BLP sbfd = g_array_index (f->sbf, BLP, lp);
g_array_index (f->bb, BLP, sbfd) = UNUSED_BLOCK;
}
g_array_set_size (f->sbf, sbf_needed);
g_array_set_size (f->sb, lastused+1);
}
}
}
}
/**
* ms_ole_lseek:
* @s: stream object.
* @bytes: number of bytes to set the stream pointer.
* @type: relative from where the stream pointer will be set.
*
* Set the stream pointer for @s as many as @bytes bytes according to @type.
*
* Return value: the new position of the stream pointer.
**/
static MsOleSPos
ms_ole_lseek (MsOleStream *s, MsOleSPos bytes, MsOleSeek type)
{
/* FIXME tenix improve limits detection: avoid gint vs guint limits */
MsOleSPos newpos;
g_return_val_if_fail (s, -1);
newpos = s->position;
if (type == MsOleSeekSet)
newpos = bytes;
else if (type == MsOleSeekCur)
newpos += bytes;
else
newpos = s->size - bytes;
if (newpos > s->size || newpos < 0) {
g_warning ("Invalid seek");
return -1;
}
s->position = newpos;
return newpos;
}
/*
* Returns:
* NULL - on error
*/
static guint8*
ms_ole_read_ptr_bb (MsOleStream *s, MsOlePos length)
{
int blklen;
guint8 *ans;
guint32 len=length;
int blockidx = s->position/BB_BLOCK_SIZE;
g_return_val_if_fail (s, NULL);
if (!s->blocks || blockidx >= s->blocks->len) {
printf ("Reading from NULL file\n");
return NULL;
}
blklen = BB_BLOCK_SIZE - s->position%BB_BLOCK_SIZE;
if (len > blklen && !s->file->ole_mmap)
return NULL;
while (len > blklen) {
len -= blklen;
blklen = BB_BLOCK_SIZE;
if (blockidx >= (s->blocks->len - 1)
|| (ms_array_index (s->blocks, BLP, blockidx)
!= blockidx + 1))
return NULL;
blockidx++;
}
/* Straight map, simply return a pointer */
ans = BB_R_PTR (s->file, ms_array_index (s->blocks, BLP,
s->position/BB_BLOCK_SIZE))
+ s->position%BB_BLOCK_SIZE;
ms_ole_lseek (s, length, MsOleSeekCur);
if (libole2_debug)
check_stream (s);
return ans;
}
/*
* Returns:
* NULL - on error
*/
static guint8*
ms_ole_read_ptr_sb (MsOleStream *s, MsOlePos length)
{
int blklen;
guint8 *ans;
guint32 len=length;
int blockidx = s->position/SB_BLOCK_SIZE;
g_return_val_if_fail (s, NULL);
if (!s->blocks || blockidx >= s->blocks->len) {
printf ("Reading from NULL file\n");
return NULL;
}
blklen = SB_BLOCK_SIZE - s->position%SB_BLOCK_SIZE;
if (len > blklen && !s->file->ole_mmap)
return NULL;
while (len > blklen) {
len -= blklen;
blklen = SB_BLOCK_SIZE;
if (blockidx >= (s->blocks->len - 1)
|| (ms_array_index (s->blocks, BLP, blockidx)
!= blockidx + 1))
return NULL;
blockidx++;
}
/* Straight map, simply return a pointer */
ans = GET_SB_R_PTR (s->file, ms_array_index (s->blocks, BLP,
s->position/SB_BLOCK_SIZE))
+ s->position%SB_BLOCK_SIZE;
ms_ole_lseek (s, length, MsOleSeekCur);
if (libole2_debug)
check_stream (s);
return ans;
}
/*
* Returns:
* zero - on error
* no zero - on success
*/
static gint
ms_ole_read_copy_bb (MsOleStream *s, guint8 *ptr, MsOlePos length)
{
guint8 *src;
int offset = s->position % BB_BLOCK_SIZE;
int blkidx = s->position / BB_BLOCK_SIZE;
g_return_val_if_fail (s, 0);
g_return_val_if_fail (ptr, 0);
if (!s->blocks) {
printf ("Reading from NULL file\n");
return 0;
}
while (length > 0)
{
BLP block;
int cpylen = BB_BLOCK_SIZE - offset;
if (cpylen > length)
cpylen = length;
if (s->position + cpylen > s->size
|| blkidx == s->blocks->len) {
#if OLE_DEBUG > 0
printf ("Trying 2 to read beyond end of stream %d+%d %d\n",
s->position, cpylen, s->size);
#endif
return 0;
}
g_assert (blkidx < s->blocks->len);
block = ms_array_index (s->blocks, BLP, blkidx);
src = BB_R_PTR (s->file, block) + offset;
memcpy (ptr, src, cpylen);
ptr += cpylen;
length -= cpylen;
offset = 0;
blkidx++;
s->position+=cpylen;
}
if (libole2_debug)
check_stream (s);
return 1;
}
/*
* Returns:
* zero - on error
* no zero - on success
*/
static gint
ms_ole_read_copy_sb (MsOleStream *s, guint8 *ptr, MsOlePos length)
{
int offset = s->position%SB_BLOCK_SIZE;
int blkidx = s->position/SB_BLOCK_SIZE;
guint8 *src;
g_return_val_if_fail (s, 0);
g_return_val_if_fail (ptr, 0);
if (!s->blocks) {
printf ("Reading from NULL file\n");
return 0;
}
while (length > 0)
{
int cpylen = SB_BLOCK_SIZE - offset;
BLP block;
if (cpylen>length)
cpylen = length;
if (s->position + cpylen > s->size
|| blkidx == s->blocks->len) {
#if OLE_DEBUG > 0
printf ("Trying 3 to read beyond end of stream %d+%d %d\n",
s->position, cpylen, s->size);
#endif
return 0;
}
g_assert (blkidx < s->blocks->len);
block = ms_array_index (s->blocks, BLP, blkidx);
src = GET_SB_R_PTR(s->file, block) + offset;
memcpy (ptr, src, cpylen);
ptr += cpylen;
length -= cpylen;
offset = 0;
blkidx++;
s->position+=cpylen;
}
if (libole2_debug)
check_stream (s);
return 1;
}
static void
ms_ole_append_block (MsOleStream *s)
{
BLP block;
BLP lastblk = END_OF_CHAIN;
BLP eoc = END_OF_CHAIN;
if (s->type==MsOleSmallBlock) {
if (!s->blocks)
s->blocks = g_array_new (FALSE, FALSE, sizeof(BLP));
else if (s->blocks->len>0)
lastblk = ms_array_index (s->blocks, BLP, s->blocks->len-1);
block = next_free_sb (s->file);
g_array_append_val (s->blocks, block);
if (lastblk != END_OF_CHAIN) { /* Link onwards */
g_array_index (s->file->sb, BLP, lastblk) = block;
#if OLE_DEBUG > 1
printf ("Chained Small block %d to previous block %d\n", block, lastblk);
#endif
} else { /* First block in a file */
PPS *p = s->pps;
#if OLE_DEBUG > 0
printf ("Set first Small block to %d\n", block);
#endif
p->start = block;
}
g_array_index (s->file->sb, BLP, block) = eoc;
} else {
if (!s->blocks)
s->blocks = g_array_new (FALSE, FALSE, sizeof(BLP));
else if (s->blocks->len>0)
lastblk = ms_array_index (s->blocks, BLP, s->blocks->len-1);
block = next_free_bb (s->file);
#if OLE_DEBUG > 0
{
int lp;
g_assert (g_array_index (s->file->bb, BLP, block) == UNUSED_BLOCK);
for (lp=0;lp<s->blocks->len;lp++)
g_assert (g_array_index (s->blocks, BLP, lp) != block);
}
#endif
g_array_append_val (s->blocks, block);
if (lastblk != END_OF_CHAIN) { /* Link onwards */
g_array_index (s->file->bb, BLP, lastblk) = block;
#if OLE_DEBUG > 1
printf ("Chained Big block %d to block %d\n", block, lastblk);
#endif
} else { /* First block in a file */
PPS *p = s->pps;
#if OLE_DEBUG > 0
printf ("Set first Big block to %d\n", block);
#endif
p->start = block;
}
g_array_index (s->file->bb, BLP, block) = eoc;
}
}
/* FIXME: I'm sure these functions should fail gracefully somehow :-) */
static MsOlePos
ms_ole_write_bb (MsOleStream *s, guint8 *ptr, MsOlePos length)
{
guint8 *dest;
gint32 lengthen;
guint32 bytes = length;
int offset = s->position%BB_BLOCK_SIZE;
guint32 blkidx = s->position/BB_BLOCK_SIZE;
s->file->dirty = 1;
while (bytes > 0) {
BLP block;
int cpylen = BB_BLOCK_SIZE - offset;
if (cpylen > bytes)
cpylen = bytes;
if (!s->blocks || blkidx >= s->blocks->len)
ms_ole_append_block (s);
g_assert (blkidx < s->blocks->len);
block = ms_array_index (s->blocks, BLP, blkidx);
dest = BB_W_PTR(s->file, block) + offset;
#if OLE_DEBUG > 1
printf ("Copy %d bytes to block %d\n", cpylen, block);
#endif
memcpy (dest, ptr, cpylen);
ptr += cpylen;
bytes -= cpylen;
offset = 0;
blkidx++;
}
lengthen = s->position - s->size + length;
if (lengthen > 0)
s->size += lengthen;
s->lseek (s, length, MsOleSeekCur);
if (libole2_debug)
check_stream (s);
return length;
}
/* FIXME: I'm sure these functions should fail gracefully somehow :-) */
static MsOlePos
ms_ole_write_sb (MsOleStream *s, guint8 *ptr, MsOlePos length)
{
guint8 *dest;
int offset = s->position%SB_BLOCK_SIZE;
guint32 blkidx = s->position/SB_BLOCK_SIZE;
guint32 bytes = length;
gint32 lengthen;
s->file->dirty = 1;
while (bytes > 0) {
BLP block;
int cpylen = SB_BLOCK_SIZE - offset;
if (cpylen > bytes)
cpylen = bytes;
if (!s->blocks || blkidx >= s->blocks->len)
ms_ole_append_block (s);
g_assert (s->blocks);
g_assert (blkidx < s->blocks->len);
block = ms_array_index (s->blocks, BLP, blkidx);
dest = GET_SB_W_PTR(s->file, block) + offset;
g_assert (cpylen >= 0);
memcpy (dest, ptr, cpylen);
ptr += cpylen;
bytes -= cpylen;
lengthen = s->position + length - bytes - s->size;
if (lengthen > 0)
s->size += lengthen;
/* Must be exactly filling the block */
if (s->size >= BB_THRESHOLD)
{
PPS *p = s->pps;
MsOlePos oldlen;
guint8 *buffer;
buffer = g_new (guint8, s->size);
s->lseek (s, 0, MsOleSeekSet);
oldlen = s->size;
s->read_copy (s, buffer, oldlen);
free_allocation (s->file, p->start, 0);
p->start = END_OF_CHAIN;
#if OLE_DEBUG > 1
printf ("\n\n--- Converting ---\n\n\n");
#endif
s->read_copy = ms_ole_read_copy_bb;
s->read_ptr = ms_ole_read_ptr_bb;
s->lseek = ms_ole_lseek;
s->tell = tell_pos;
s->write = ms_ole_write_bb;
g_assert (s->size % SB_BLOCK_SIZE == 0);
/* Convert the file to BBlocks */
s->size = 0;
s->position = 0;
s->type = MsOleLargeBlock;
g_array_free (s->blocks, TRUE);
s->blocks = 0;
s->write (s, buffer, oldlen);
/* Continue the interrupted write */
ms_ole_write_bb (s, ptr, bytes);
bytes = 0;
#if OLE_DEBUG > 1
printf ("\n\n--- Done ---\n\n\n");
#endif
g_free (buffer);
return length;
}
offset = 0;
blkidx++;
if (libole2_debug)
check_stream (s);
}
s->lseek (s, length, MsOleSeekCur);
return length;
}
/**
* pps_create:
* @f: ole file handle.
* @p: returned pps.
* @parent: parent pps.
* @name: its name.
* @type: the type.
*
* Creates a storage or stream.
*
* Return value: error status.
**/
static MsOleErr
pps_create (MsOle *f, GList **p, GList *parent, const char *name,
MsOleType type)
{
PPS *pps, *par;
if (!p || !parent || !parent->data || !name) {
g_warning ("duff arguments to pps_create");
return MS_OLE_ERR_BADARG;
}
pps = g_new (PPS, 1);
if (!pps)
return MS_OLE_ERR_MEM;
pps->sig = PPS_SIG;
pps->name = g_strdup (name);
pps->type = type;
pps->size = 0;
pps->start = END_OF_CHAIN;
pps->children = NULL;
pps->parent = parent->data;
par = (PPS *)parent->data;
par->children = g_list_insert_sorted (par->children, pps,
(GCompareFunc)pps_compare_func);
*p = g_list_find (par->children, pps);
f->num_pps++;
return MS_OLE_ERR_OK;
}
/**
* find_in_pps:
* @l: the parent storage chain element.
*
* Find the right Stream ... John 4:13-14 ...
* in a storage
*
* Return value: %NULL if not found or pointer to the child list
**/
static GList *
find_in_pps (GList *l, const char *name)
{
PPS *pps;
GList *cur;
g_return_val_if_fail (l != NULL, NULL);
g_return_val_if_fail (l->data != NULL, NULL);
pps = l->data;
g_return_val_if_fail (IS_PPS (pps), NULL);
if (pps->type == MsOleStorageT ||
pps->type == MsOleRootT)
cur = pps->children;
else {
g_warning ("trying to enter a stream '%s'",
pps->name?pps->name:"no name");
return NULL;
}
for ( ;cur ; cur = g_list_next (cur)) {
PPS *pps = cur->data;
g_return_val_if_fail (IS_PPS (pps), NULL);
if (!pps->name)
continue;
if (!g_strcasecmp (pps->name, name))
return cur;
}
return NULL;
}
/**
* path_to_pps:
* @pps: pointer to pps to return value in.
* @f: ole file hande.
* @path: path to find.
* @file: file to find in path.
* @create_if_not_found: create the pps with the given path if not found.
*
* Locates a stream or storage with the given path.
*
* Return value: a #MsOleErr code.
**/
static MsOleErr
path_to_pps (PPS **pps, MsOle *f, const char *path,
const char *file,
gboolean create_if_not_found)
{
guint lp;
gchar **dirs;
GList *cur, *parent;
g_return_val_if_fail (f != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (path != NULL, MS_OLE_ERR_BADARG);
dirs = g_strsplit (path, "/", -1);
g_return_val_if_fail (dirs != NULL, MS_OLE_ERR_BADARG);
parent = cur = f->pps;
for (lp = 0; dirs[lp]; lp++) {
if (dirs[lp][0] == '\0' || !cur) {
g_free (dirs[lp]);
continue;
}
parent = cur;
cur = find_in_pps (parent, dirs[lp]);
if (!cur && create_if_not_found &&
pps_create (f, &cur, parent, dirs[lp], MsOleStorageT) !=
MS_OLE_ERR_OK)
cur = NULL;
/* else carry on not finding them before dropping out */
g_free (dirs[lp]);
}
g_free (dirs);
if (!cur || !cur->data)
return MS_OLE_ERR_EXIST;
if (file[0] == '\0') { /* We just want a directory */
*pps = cur->data;
g_return_val_if_fail (IS_PPS (cur->data), MS_OLE_ERR_INVALID);
return MS_OLE_ERR_OK;
}
parent = cur;
cur = find_in_pps (parent, file);
/* now the file */
if (!cur) {
if (create_if_not_found) {
MsOleErr result;
result = pps_create (f, &cur, parent, file,
MsOleStreamT);
if (result == MS_OLE_ERR_OK) {
*pps = cur->data;
g_return_val_if_fail (IS_PPS (cur->data),
MS_OLE_ERR_INVALID);
return MS_OLE_ERR_OK;
} else
return result;
}
return MS_OLE_ERR_EXIST;
}
if (cur && cur->data) {
*pps = cur->data;
g_return_val_if_fail (IS_PPS (cur->data), MS_OLE_ERR_INVALID);
return MS_OLE_ERR_OK;
}
return MS_OLE_ERR_EXIST;
}
/**
* ms_ole_unlink:
* @fs: filesystem object.
* @path: path of the stream or directory to delete.
*
* Delete the stream or directory @path on the filesystem @fs.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_unlink (MsOle *f, const char *path)
{
g_warning ("Unimplemented");
/* FIXME missing implementation, or at least a better error code =-) */
return MS_OLE_ERR_NOTEMPTY;
}
/**
* ms_ole_directory:
* @names: array where the names are storesd, it's %NULL ended.
* @fs: filesystem object.
* @dirpath: directory path.
*
* Gets the names of the streams and directories in the directory @dirpath.
*
* Returns: a #MsOleErr code.
**/
MsOleErr
ms_ole_directory (char ***names, MsOle *f, const char *path)
{
char **ans;
PPS *pps;
MsOleErr result;
GList *l;
int lp;
g_return_val_if_fail (f != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (path != NULL, MS_OLE_ERR_BADARG);
if ((result = path_to_pps (&pps, f, path, "", FALSE)) !=
MS_OLE_ERR_OK)
return result;
if (!pps)
return MS_OLE_ERR_INVALID;
l = pps->children;
ans = g_new (char *, g_list_length (l) + 1);
lp = 0;
for (; l; l = g_list_next (l)) {
pps = (PPS *)l->data;
if (!pps->name)
continue;
ans[lp] = g_strdup (pps->name);
lp++;
}
ans[lp] = NULL;
*names = ans;
return MS_OLE_ERR_OK;
}
/**
* ms_ole_stat:
* @stat: stat information.
* @fs: filesystem object.
* @dirpath: directory path.
* @name: stream or directory name.
*
* Gets information about the stream or the directory which is in the directory
* @dirpath and its name is @file.
*
* Returns: a #MsOleErr code.
**/
MsOleErr
ms_ole_stat (MsOleStat *stat, MsOle *f, const char *path,
const char *file)
{
PPS *pps;
MsOleErr result;
g_return_val_if_fail (f != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (file != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (path != NULL, MS_OLE_ERR_BADARG);
g_return_val_if_fail (stat != NULL, MS_OLE_ERR_BADARG);
if ((result = path_to_pps (&pps, f, path, file, FALSE)) !=
MS_OLE_ERR_OK)
return result;
if (!pps)
return MS_OLE_ERR_INVALID;
stat->type = pps->type;
stat->size = pps->size;
return MS_OLE_ERR_OK;
}
/**
* ms_ole_stream_open:
* @stream: stream object.
* @fs: filesystem object.
* @dirpath: directory of the stream.
* @name: stream name.
* @mode: mode of opening stream.
*
* Opens the stream in @dirpath with the name @name and creates the stream
* object @stream. If @mode is '%r' it opens read only, and if it is '%w'
* it opens for write only.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_stream_open (MsOleStream ** const stream, MsOle *f,
const char *path, const char *fname, char mode)
{
PPS *p;
MsOleStream *s;
int lp, panic=0;
MsOleErr result;
if (!stream)
return MS_OLE_ERR_BADARG;
*stream = NULL;
if (!path || !f)
return MS_OLE_ERR_BADARG;
if (mode == 'w' && f->mode != 'w') {
printf ("Opening stream '%c' when file is '%c' only\n",
mode, f->mode);
return MS_OLE_ERR_PERM;
}
if ((result = path_to_pps (&p, f, path, fname, (mode == 'w'))) !=
MS_OLE_ERR_OK)
return result;
s = g_new0 (MsOleStream, 1);
s->file = f;
s->pps = p;
s->position = 0;
s->size = p->size;
s->blocks = NULL;
#if OLE_DEBUG > 0
printf ("Parsing blocks\n");
#endif
if (s->size >= BB_THRESHOLD) {
BLP b = p->start;
s->read_copy = ms_ole_read_copy_bb;
s->read_ptr = ms_ole_read_ptr_bb;
s->lseek = ms_ole_lseek;
s->tell = tell_pos;
s->write = ms_ole_write_bb;
s->blocks = g_array_new (FALSE, FALSE, sizeof(BLP));
s->type = MsOleLargeBlock;
for (lp = 0; !panic & (lp < (s->size + BB_BLOCK_SIZE - 1) / BB_BLOCK_SIZE); lp++) {
g_array_append_val (s->blocks, b);
#if OLE_DEBUG > 1
printf ("Block %d\n", b);
#endif
if (b == END_OF_CHAIN ||
b == SPECIAL_BLOCK ||
b == UNUSED_BLOCK) {
printf ("Panic: broken stream, truncating to block %d\n", lp);
s->size = (lp-1)*BB_BLOCK_SIZE;
panic = 1;
#if OLE_DEBUG > 0
if (b == END_OF_CHAIN)
printf ("Warning: bad file length in '%s'\n", p->name);
else if (b == SPECIAL_BLOCK)
printf ("Warning: special block in '%s'\n", p->name);
else if (b == UNUSED_BLOCK)
printf ("Warning: unused block in '%s'\n", p->name);
#endif
} else
b = NEXT_BB (f, b);
}
if (b != END_OF_CHAIN) {
BLP next;
printf ("Panic: extra unused blocks on end of '%s', wiping it\n",
p->name);
while (b != END_OF_CHAIN &&
b != UNUSED_BLOCK &&
b != SPECIAL_BLOCK) {
next = NEXT_BB (f, b);
g_array_index (f->bb, BLP, b) = END_OF_CHAIN;
b = next;
}
}
} else {
BLP b = p->start;
s->read_copy = ms_ole_read_copy_sb;
s->read_ptr = ms_ole_read_ptr_sb;
s->lseek = ms_ole_lseek;
s->tell = tell_pos;
s->write = ms_ole_write_sb;
if (s->size>0)
s->blocks = g_array_new (FALSE, FALSE, sizeof(BLP));
else
s->blocks = NULL;
s->type = MsOleSmallBlock;
for (lp = 0; !panic & (lp < (s->size + SB_BLOCK_SIZE - 1) / SB_BLOCK_SIZE); lp++) {
g_array_append_val (s->blocks, b);
#if OLE_DEBUG > 0
printf ("Block %d\n", b);
#endif
if (b == END_OF_CHAIN ||
b == SPECIAL_BLOCK ||
b == UNUSED_BLOCK) {
printf ("Panic: broken stream, truncating to block %d\n", lp);
s->size = (lp-1)*SB_BLOCK_SIZE;
panic = 1;
#if OLE_DEBUG > 0
if (b == END_OF_CHAIN)
printf ("Warning: bad file length in '%s'\n", p->name);
else if (b == SPECIAL_BLOCK)
printf ("Warning: special block in '%s'\n", p->name);
else if (b == UNUSED_BLOCK)
printf ("Warning: unused block in '%s'\n", p->name);
#endif
} else
b = NEXT_SB (f, b);
}
if (b != END_OF_CHAIN) {
BLP next;
printf ("Panic: extra unused blocks on end of '%s', wiping it\n",
p->name);
while (b != END_OF_CHAIN &&
b != UNUSED_BLOCK &&
b != SPECIAL_BLOCK) {
next = NEXT_SB (f, b);
g_array_index (f->sb, BLP, b) = END_OF_CHAIN;
b = next;
}
if (b != END_OF_CHAIN)
printf ("Panic: even more serious block error\n");
}
}
*stream = s;
ms_ole_ref (s->file);
return MS_OLE_ERR_OK;
}
/**
* ms_ole_stream_duplicate:
* @stream_copy: stream object copy.
* @stream: stream object to be duplicated.
*
* Duplicates the stream object @stream.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_stream_duplicate (MsOleStream **s, const MsOleStream * const stream)
{
if (!s || !stream)
return MS_OLE_ERR_BADARG;
/* Lets face it having two pointers to the same file is a nightmare anyway :-) */
g_warning ("Do NOT use this function, it is unsafe with the blocks array");
if (!(*s = g_new (MsOleStream, 1)))
return MS_OLE_ERR_MEM;
memcpy (*s, stream, sizeof (MsOleStream));
ms_ole_ref (stream->file);
return MS_OLE_ERR_OK;
}
/**
* ms_ole_stream_close:
* @stream: stream object to be closed.
*
* Closes the @stream.
*
* Return value: a #MsOleErr code.
**/
MsOleErr
ms_ole_stream_close (MsOleStream **s)
{
if (*s) {
if ((*s)->file && (*s)->file->mode == 'w')
((PPS *)(*s)->pps)->size = (*s)->size;
if ((*s)->blocks)
g_array_free ((*s)->blocks, TRUE);
ms_ole_unref ((*s)->file);
g_free (*s);
*s = NULL;
return MS_OLE_ERR_OK;
}
return MS_OLE_ERR_BADARG;
}
--- Added File ms-ole.h in package CMF ---
/**
* ms-ole.h: MS Office OLE support for Gnumeric
*
* Authors:
* Michael Meeks (michael@imaginator.com)
* Arturo Tena (arturo@directmail.org)
**/
#ifndef MS_OLE_H
#define MS_OLE_H
/* This should be done in glib */
#ifndef _WIN32
# include <fcntl.h> /* for mode_t */
#else
typedef unsigned long mode_t;
typedef size_t ssize_t;
typedef /* signed */ long off_t;
#endif
#include <glib.h>
typedef enum {
MS_OLE_ERR_OK,
MS_OLE_ERR_EXIST,
MS_OLE_ERR_INVALID,
MS_OLE_ERR_FORMAT,
MS_OLE_ERR_PERM,
MS_OLE_ERR_MEM,
MS_OLE_ERR_SPACE,
MS_OLE_ERR_NOTEMPTY,
MS_OLE_ERR_BADARG
} MsOleErr;
typedef enum {
MsOleSeekSet,
MsOleSeekCur,
MsOleSeekEnd
} MsOleSeek;
typedef enum {
MsOleStorageT = 1,
MsOleStreamT = 2,
MsOleRootT = 5
} MsOleType;
typedef guint32 MsOlePos;
typedef gint32 MsOleSPos;
/*
#ifdef G_HAVE_GINT64
typedef guint64 MsOlePos;
typedef gint64 MsOleSPos;
#else
typedef guint32 MsOlePos;
typedef gint32 MsOleSPos;
#endif
*/
typedef struct _MsOle MsOle;
typedef struct _MsOleStat MsOleStat;
typedef struct _MsOleStream MsOleStream;
typedef struct _MsOleSysWrappers MsOleSysWrappers;
struct _MsOleSysWrappers {
int (*open2) (const char *pathname, int flags);
int (*open3) (const char *pathname, int flags, mode_t mode);
ssize_t (*read) (int fd, void *buf, size_t count);
int (*close) (int fd);
ssize_t (*write) (int fd, const void *buf, size_t count);
off_t (*lseek) (int fd, off_t offset, int whence);
int (*isregfile) (int fd);
int (*getfilesize) (int fd, guint32 *size);
};
struct _MsOleStat {
MsOleType type;
MsOlePos size;
};
#define ms_ole_open(fs,path) ms_ole_open_vfs ((fs), (path), TRUE, NULL)
extern MsOleErr ms_ole_open_vfs (MsOle **fs,
const char *path,
gboolean try_mmap,
MsOleSysWrappers *wrappers);
#define ms_ole_create(fs,path) ms_ole_create_vfs ((fs), (path), TRUE, NULL)
extern MsOleErr ms_ole_create_vfs (MsOle **fs,
const char *path,
int try_mmap,
MsOleSysWrappers *wrappers);
extern void ms_ole_destroy (MsOle **fs);
extern MsOleErr ms_ole_unlink (MsOle *fs,
const char *path);
extern MsOleErr ms_ole_directory (char ***names,
MsOle *fs,
const char *dirpath);
extern MsOleErr ms_ole_stat (MsOleStat *stat,
MsOle *fs,
const char *dirpath,
const char *name);
struct _MsOleStream {
MsOlePos size;
gint (*read_copy) (MsOleStream *stream,
guint8 *ptr,
MsOlePos length);
guint8 * (*read_ptr) (MsOleStream *stream,
MsOlePos length);
MsOleSPos (*lseek) (MsOleStream *stream,
MsOleSPos bytes,
MsOleSeek type);
MsOlePos (*tell) (MsOleStream *stream);
MsOlePos (*write) (MsOleStream *stream,
guint8 *ptr,
MsOlePos length);
/**
* Private.
**/
enum {
MsOleSmallBlock,
MsOleLargeBlock
} type;
MsOle *file;
void *pps; /* Straight PPS */
GArray *blocks; /* A list of the blocks in the file
if NULL: no file */
MsOlePos position; /* Current offset into file.
Points to the next byte to read */
};
#define MS_OLE_GET_GUINT8(p) (*((const guint8 *)(p) + 0))
#define MS_OLE_GET_GUINT16(p) (guint16)(*((const guint8 *)(p)+0) | \
(*((const guint8 *)(p)+1)<<8))
#define MS_OLE_GET_GUINT32(p) (guint32)(*((const guint8 *)(p)+0) | \
(*((const guint8 *)(p)+1)<<8) | \
(*((const guint8 *)(p)+2)<<16) | \
(*((const guint8 *)(p)+3)<<24))
#define MS_OLE_GET_GUINT64(p) (MS_OLE_GET_GUINT32(p) | \
(((guint32)MS_OLE_GET_GUINT32((const guint8 *)(p)+4))<<32))
#define MS_OLE_SET_GUINT8(p,n) (*((guint8 *)(p) + 0) = n)
#define MS_OLE_SET_GUINT16(p,n) ((*((guint8 *)(p)+0)=((n)&0xff)), \
(*((guint8 *)(p)+1)=((n)>>8)&0xff))
#define MS_OLE_SET_GUINT32(p,n) ((*((guint8 *)(p)+0)=((n))&0xff), \
(*((guint8 *)(p)+1)=((n)>>8)&0xff), \
(*((guint8 *)(p)+2)=((n)>>16)&0xff), \
(*((guint8 *)(p)+3)=((n)>>24)&0xff))
extern MsOleErr ms_ole_stream_open (MsOleStream ** const stream,
MsOle *fs,
const char *dirpath,
const char *name,
char mode);
extern MsOleErr ms_ole_stream_close (MsOleStream ** const stream);
extern MsOleErr ms_ole_stream_duplicate (MsOleStream ** const stream_copy,
const MsOleStream *
const stream);
extern void ms_ole_dump (guint8 const *ptr,
guint32 len);
extern void ms_ole_ref (MsOle *fs);
extern void ms_ole_unref (MsOle *fs);
extern void ms_ole_debug (MsOle *fs,
int magic);
#endif /* MS_OLE_H */
--- Added File ole.c in package CMF ---
//----------------------------------------------------------------------------//
// ole.c
// John Platten
// 01.12.01
//----------------------------------------------------------------------------//
#include <stdio.h>
#include "ms-ole.h"
#include "ms-ole-summary.h"
//----------------------------------------------------------------------------//
// GLOBALS
//----------------------------------------------------------------------------//
char str[512];
//----------------------------------------------------------------------------//
// PROTOTYPES
//----------------------------------------------------------------------------//
MsOle * _ms_ole_open (char *fileName);
MsOle * _ms_ole_open_body (char * jp_buf_ptr, int jp_buf_len);
void _ms_ole_destroy (MsOle *ole);
MsOleSummary * _ms_ole_summary_open (MsOle *ole);
void _ms_ole_summary_close (MsOleSummary *summary);
MsOleSummary * _ms_ole_docsummary_open (MsOle *f);
char * _ms_ole_summary_get_string (MsOleSummary *summary, int propertyId);
int _ms_ole_summary_get_long (MsOleSummary *summary, int propertyId);
short int _ms_ole_summary_get_short (MsOleSummary *summary, int propertyId);
char * _ms_ole_summary_get_time (MsOleSummary *summary, int propertyId);
//----------------------------------------------------------------------------//
MsOle * _ms_ole_open (char *fileName)
{
MsOle *ole = NULL;
ms_ole_open_vfs(&ole, fileName, FALSE, NULL);
// if (!ole) fprintf(stderr, ":ERROR:ms_ole_open_vfs:msOleErr:%x\n", ole);
return ole;
}
//----------------------------------------------------------------------------//
MsOle * _ms_ole_open_body (char * jp_buf_ptr, int jp_buf_len)
{
MsOle * msOle = NULL;
MsOleErr msOleErr;
char * fileName = "junk";
msOleErr = ms_ole_open_vfs_body(&msOle, fileName, FALSE, NULL, jp_buf_ptr, jp_buf_len);
// if (!msOle) fprintf(stderr, ":ERROR:ms_ole_open_vfs:msOleErr:%x\n", msOleErr);
return msOle;
}
//----------------------------------------------------------------------------//
void _ms_ole_destroy (MsOle *ole)
{
MsOle * myOle = ole;
ms_ole_destroy(&myOle);
}
//----------------------------------------------------------------------------//
MsOleSummary * _ms_ole_summary_open (MsOle *ole)
{
MsOleSummary *summary = NULL;
summary = ms_ole_summary_open(ole);
// if (!summary) fprintf(stderr, ":ERROR:_ms_ole_summary_open:summary:%x\n", summary);
return summary;
}
//----------------------------------------------------------------------------//
void _ms_ole_summary_close (MsOleSummary *summary)
{
ms_ole_summary_close(summary);
}
//----------------------------------------------------------------------------//
MsOleSummary * _ms_ole_docsummary_open (MsOle *f)
{
return ms_ole_docsummary_open(f);
}
//----------------------------------------------------------------------------//
char * _ms_ole_summary_get_string (MsOleSummary *summary, int propertyId)
{
char *str = NULL;
gboolean ret = FALSE;
return ms_ole_summary_get_string(summary, propertyId, &ret);
}
//----------------------------------------------------------------------------//
int _ms_ole_summary_get_long (MsOleSummary *summary, int propertyId)
{
gboolean ret = FALSE;
return ms_ole_summary_get_long(summary, propertyId, &ret);
}
//----------------------------------------------------------------------------//
short int _ms_ole_summary_get_short (MsOleSummary *summary, int propertyId)
{
gboolean ret = FALSE;
return ms_ole_summary_get_short(summary, propertyId, &ret);
}
//----------------------------------------------------------------------------//
char * _ms_ole_summary_get_time (MsOleSummary *summary, int propertyId)
{
GTimeVal timeval;
gboolean ret = FALSE;
timeval = ms_ole_summary_get_time(summary, propertyId, &ret);
strcpy(str, ctime(&timeval.tv_sec));
str[strlen(str)-1] = '\0';
return str;
}
//----------------------------------------------------------------------------//
--- Added File ole.i in package CMF ---
%module ole
%{
#include "ms-ole.h"
#include "ms-ole-summary.h"
%}
MsOle * _ms_ole_open (char *fileName);
MsOle * _ms_ole_open_body (char * jp_buf_ptr, int jp_buf_len);
void _ms_ole_destroy (MsOle *ole);
MsOleSummary * _ms_ole_summary_open (MsOle *ole);
void _ms_ole_summary_close (MsOleSummary *summary);
MsOleSummary * _ms_ole_docsummary_open (MsOle *f);
char * _ms_ole_summary_get_string (MsOleSummary *summary, int propertyId);
int _ms_ole_summary_get_long (MsOleSummary *summary, int propertyId);
short int _ms_ole_summary_get_short (MsOleSummary *summary, int propertyId);
char * _ms_ole_summary_get_time (MsOleSummary *summary, int propertyId);
--- Added File ole_wrap.c in package CMF ---
/*
* FILE : ole_wrap.c
*
* This file was automatically generated by :
* Simplified Wrapper and Interface Generator (SWIG)
* Version 1.1 (Build 883)
*
* Portions Copyright (c) 1995-1998
* The University of Utah and The Regents of the University of California.
* Permission is granted to distribute this file in any manner provided
* this notice remains intact.
*
* Do not make changes to this file--changes will be lost!
*
*/
#define SWIGCODE
/* Implementation : PYTHON */
#define SWIGPYTHON
/***********************************************************************
* $Header: /cvs-repository/Packages/Products/DCProject/CMF_MS_Files/src/libole/ole_wrap.c,v 1.1 2001/05/30 14:39:19 jack Exp $
* swig_lib/python/python.cfg
*
* Contains variable linking and pointer type-checking code.
************************************************************************/
#include <string.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "Python.h"
/* Definitions for Windows/Unix exporting */
#if defined(_WIN32) || defined(__WIN32__)
# if defined(_MSC_VER)
# define SWIGEXPORT(a) __declspec(dllexport) a
# else
# if defined(__BORLANDC__)
# define SWIGEXPORT(a) a _export
# else
# define SWIGEXPORT(a) a
# endif
# endif
#else
# define SWIGEXPORT(a) a
#endif
#ifdef SWIG_GLOBAL
#define SWIGSTATICRUNTIME(a) SWIGEXPORT(a)
#else
#define SWIGSTATICRUNTIME(a) static a
#endif
typedef struct {
char *name;
PyObject *(*get_attr)(void);
int (*set_attr)(PyObject *);
} swig_globalvar;
typedef struct swig_varlinkobject {
PyObject_HEAD
swig_globalvar **vars;
int nvars;
int maxvars;
} swig_varlinkobject;
/* ----------------------------------------------------------------------
swig_varlink_repr()
Function for python repr method
---------------------------------------------------------------------- */
static PyObject *
swig_varlink_repr(swig_varlinkobject *v)
{
v = v;
return PyString_FromString("<Global variables>");
}
/* ---------------------------------------------------------------------
swig_varlink_print()
Print out all of the global variable names
--------------------------------------------------------------------- */
static int
swig_varlink_print(swig_varlinkobject *v, FILE *fp, int flags)
{
int i = 0;
flags = flags;
fprintf(fp,"Global variables { ");
while (v->vars[i]) {
fprintf(fp,"%s", v->vars[i]->name);
i++;
if (v->vars[i]) fprintf(fp,", ");
}
fprintf(fp," }\n");
return 0;
}
/* --------------------------------------------------------------------
swig_varlink_getattr
This function gets the value of a variable and returns it as a
PyObject. In our case, we'll be looking at the datatype and
converting into a number or string
-------------------------------------------------------------------- */
static PyObject *
swig_varlink_getattr(swig_varlinkobject *v, char *n)
{
int i = 0;
char temp[128];
while (v->vars[i]) {
if (strcmp(v->vars[i]->name,n) == 0) {
return (*v->vars[i]->get_attr)();
}
i++;
}
sprintf(temp,"C global variable %s not found.", n);
PyErr_SetString(PyExc_NameError,temp);
return NULL;
}
/* -------------------------------------------------------------------
swig_varlink_setattr()
This function sets the value of a variable.
------------------------------------------------------------------- */
static int
swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p)
{
char temp[128];
int i = 0;
while (v->vars[i]) {
if (strcmp(v->vars[i]->name,n) == 0) {
return (*v->vars[i]->set_attr)(p);
}
i++;
}
sprintf(temp,"C global variable %s not found.", n);
PyErr_SetString(PyExc_NameError,temp);
return 1;
}
statichere PyTypeObject varlinktype = {
/* PyObject_HEAD_INIT(&PyType_Type) Note : This doesn't work on some machines */
PyObject_HEAD_INIT(0)
0,
"varlink", /* Type name */
sizeof(swig_varlinkobject), /* Basic size */
0, /* Itemsize */
0, /* Deallocator */
(printfunc) swig_varlink_print, /* Print */
(getattrfunc) swig_varlink_getattr, /* get attr */
(setattrfunc) swig_varlink_setattr, /* Set attr */
0, /* tp_compare */
(reprfunc) swig_varlink_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_mapping*/
0, /* tp_hash */
};
/* Create a variable linking object for use later */
SWIGSTATICRUNTIME(PyObject *)
SWIG_newvarlink(void)
{
swig_varlinkobject *result = 0;
result = PyMem_NEW(swig_varlinkobject,1);
varlinktype.ob_type = &PyType_Type; /* Patch varlinktype into a PyType */
result->ob_type = &varlinktype;
/* _Py_NewReference(result); Does not seem to be necessary */
result->nvars = 0;
result->maxvars = 64;
result->vars = (swig_globalvar **) malloc(64*sizeof(swig_globalvar *));
result->vars[0] = 0;
result->ob_refcnt = 0;
Py_XINCREF((PyObject *) result);
return ((PyObject*) result);
}
SWIGSTATICRUNTIME(void)
SWIG_addvarlink(PyObject *p, char *name,
PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p))
{
swig_varlinkobject *v;
v= (swig_varlinkobject *) p;
if (v->nvars >= v->maxvars -1) {
v->maxvars = 2*v->maxvars;
v->vars = (swig_globalvar **) realloc(v->vars,v->maxvars*sizeof(swig_globalvar *));
if (v->vars == NULL) {
fprintf(stderr,"SWIG : Fatal error in initializing Python module.\n");
exit(1);
}
}
v->vars[v->nvars] = (swig_globalvar *) malloc(sizeof(swig_globalvar));
v->vars[v->nvars]->name = (char *) malloc(strlen(name)+1);
strcpy(v->vars[v->nvars]->name,name);
v->vars[v->nvars]->get_attr = get_attr;
v->vars[v->nvars]->set_attr = set_attr;
v->nvars++;
v->vars[v->nvars] = 0;
}
/* -----------------------------------------------------------------------------
* Pointer type-checking
* ----------------------------------------------------------------------------- */
/* SWIG pointer structure */
typedef struct SwigPtrType {
char *name; /* Datatype name */
int len; /* Length (used for optimization) */
void *(*cast)(void *); /* Pointer casting function */
struct SwigPtrType *next; /* Linked list pointer */
} SwigPtrType;
/* Pointer cache structure */
typedef struct {
int stat; /* Status (valid) bit */
SwigPtrType *tp; /* Pointer to type structure */
char name[256]; /* Given datatype name */
char mapped[256]; /* Equivalent name */
} SwigCacheType;
static int SwigPtrMax = 64; /* Max entries that can be currently held */
static int SwigPtrN = 0; /* Current number of entries */
static int SwigPtrSort = 0; /* Status flag indicating sort */
static int SwigStart[256]; /* Starting positions of types */
static SwigPtrType *SwigPtrTable = 0; /* Table containing pointer equivalences */
/* Cached values */
#define SWIG_CACHESIZE 8
#define SWIG_CACHEMASK 0x7
static SwigCacheType SwigCache[SWIG_CACHESIZE];
static int SwigCacheIndex = 0;
static int SwigLastCache = 0;
/* Sort comparison function */
static int swigsort(const void *data1, const void *data2) {
SwigPtrType *d1 = (SwigPtrType *) data1;
SwigPtrType *d2 = (SwigPtrType *) data2;
return strcmp(d1->name,d2->name);
}
/* Register a new datatype with the type-checker */
SWIGSTATICRUNTIME(void)
SWIG_RegisterMapping(char *origtype, char *newtype, void *(*cast)(void *)) {
int i;
SwigPtrType *t = 0,*t1;
/* Allocate the pointer table if necessary */
if (!SwigPtrTable) {
SwigPtrTable = (SwigPtrType *) malloc(SwigPtrMax*sizeof(SwigPtrType));
}
/* Grow the table */
if (SwigPtrN >= SwigPtrMax) {
SwigPtrMax = 2*SwigPtrMax;
SwigPtrTable = (SwigPtrType *) realloc((char *) SwigPtrTable,SwigPtrMax*sizeof(SwigPtrType));
}
for (i = 0; i < SwigPtrN; i++) {
if (strcmp(SwigPtrTable[i].name,origtype) == 0) {
t = &SwigPtrTable[i];
break;
}
}
if (!t) {
t = &SwigPtrTable[SwigPtrN++];
t->name = origtype;
t->len = strlen(t->name);
t->cast = 0;
t->next = 0;
}
/* Check for existing entries */
while (t->next) {
if ((strcmp(t->name,newtype) == 0)) {
if (cast) t->cast = cast;
return;
}
t = t->next;
}
t1 = (SwigPtrType *) malloc(sizeof(SwigPtrType));
t1->name = newtype;
t1->len = strlen(t1->name);
t1->cast = cast;
t1->next = 0;
t->next = t1;
SwigPtrSort = 0;
}
/* Make a pointer value string */
SWIGSTATICRUNTIME(void)
SWIG_MakePtr(char *c, const void *ptr, char *type) {
static char hex[17] = "0123456789abcdef";
unsigned long p, s;
char result[24], *r;
r = result;
p = (unsigned long) ptr;
if (p > 0) {
while (p > 0) {
s = p & 0xf;
*(r++) = hex[s];
p = p >> 4;
}
*r = '_';
while (r >= result)
*(c++) = *(r--);
strcpy (c, type);
} else {
strcpy (c, "NULL");
}
}
/* Function for getting a pointer value */
SWIGSTATICRUNTIME(char *)
SWIG_GetPtr(char *c, void **ptr, char *t)
{
unsigned long p;
char temp_type[256], *name;
int i, len, start, end;
SwigPtrType *sp,*tp;
SwigCacheType *cache;
register int d;
p = 0;
/* Pointer values must start with leading underscore */
if (*c != '_') {
*ptr = (void *) 0;
if (strcmp(c,"NULL") == 0) return (char *) 0;
else c;
}
c++;
/* Extract hex value from pointer */
while (d = *c) {
if ((d >= '0') && (d <= '9'))
p = (p << 4) + (d - '0');
else if ((d >= 'a') && (d <= 'f'))
p = (p << 4) + (d - ('a'-10));
else
break;
c++;
}
*ptr = (void *) p;
if ((!t) || (strcmp(t,c)==0)) return (char *) 0;
if (!SwigPtrSort) {
qsort((void *) SwigPtrTable, SwigPtrN, sizeof(SwigPtrType), swigsort);
for (i = 0; i < 256; i++) SwigStart[i] = SwigPtrN;
for (i = SwigPtrN-1; i >= 0; i--) SwigStart[(int) (SwigPtrTable[i].name[1])] = i;
for (i = 255; i >= 1; i--) {
if (SwigStart[i-1] > SwigStart[i])
SwigStart[i-1] = SwigStart[i];
}
SwigPtrSort = 1;
for (i = 0; i < SWIG_CACHESIZE; i++) SwigCache[i].stat = 0;
}
/* First check cache for matches. Uses last cache value as starting point */
cache = &SwigCache[SwigLastCache];
for (i = 0; i < SWIG_CACHESIZE; i++) {
if (cache->stat && (strcmp(t,cache->name) == 0) && (strcmp(c,cache->mapped) == 0)) {
cache->stat++;
if (cache->tp->cast) *ptr = (*(cache->tp->cast))(*ptr);
return (char *) 0;
}
SwigLastCache = (SwigLastCache+1) & SWIG_CACHEMASK;
if (!SwigLastCache) cache = SwigCache;
else cache++;
}
/* Type mismatch. Look through type-mapping table */
start = SwigStart[(int) t[1]];
end = SwigStart[(int) t[1]+1];
sp = &SwigPtrTable[start];
/* Try to find a match */
while (start <= end) {
if (strncmp(t,sp->name,sp->len) == 0) {
name = sp->name;
len = sp->len;
tp = sp->next;
/* Try to find entry for our given datatype */
while(tp) {
if (tp->len >= 255) {
return c;
}
strcpy(temp_type,tp->name);
strncat(temp_type,t+len,255-tp->len);
if (strcmp(c,temp_type) == 0) {
strcpy(SwigCache[SwigCacheIndex].mapped,c);
strcpy(SwigCache[SwigCacheIndex].name,t);
SwigCache[SwigCacheIndex].stat = 1;
SwigCache[SwigCacheIndex].tp = tp;
SwigCacheIndex = SwigCacheIndex & SWIG_CACHEMASK;
/* Get pointer value */
*ptr = (void *) p;
if (tp->cast) *ptr = (*(tp->cast))(*ptr);
return (char *) 0;
}
tp = tp->next;
}
}
sp++;
start++;
}
return c;
}
/* New object-based GetPointer function. This uses the Python abstract
* object interface to automatically dereference the 'this' attribute
* of shadow objects. */
SWIGSTATICRUNTIME(char *)
SWIG_GetPtrObj(PyObject *obj, void **ptr, char *type) {
PyObject *sobj = obj;
char *str;
if (!PyString_Check(obj)) {
sobj = PyObject_GetAttrString(obj,"this");
if (!sobj) return "";
}
str = PyString_AsString(sobj);
return SWIG_GetPtr(str,ptr,type);
}
#ifdef __cplusplus
}
#endif
#define SWIG_init initole
#define SWIG_name "ole"
#include "ms-ole.h"
#include "ms-ole-summary.h"
#ifdef __cplusplus
extern "C" {
#endif
static PyObject *_wrap__ms_ole_open(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOle * _result;
char * _arg0;
char _ptemp[128];
self = self;
if(!PyArg_ParseTuple(args,"s:_ms_ole_open",&_arg0))
return NULL;
_result = (MsOle *)_ms_ole_open(_arg0);
if (_result) {
SWIG_MakePtr(_ptemp, (char *) _result,"_MsOle_p");
_resultobj = Py_BuildValue("s",_ptemp);
} else {
Py_INCREF(Py_None);
_resultobj = Py_None;
}
return _resultobj;
}
static PyObject *_wrap__ms_ole_open_body(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOle * _result;
char * _arg0;
int _arg1;
char _ptemp[128];
self = self;
if(!PyArg_ParseTuple(args,"s#:_ms_ole_open_body",&_arg0,&_arg1))
return NULL;
_result = (MsOle *)_ms_ole_open_body(_arg0,_arg1);
if (_result) {
SWIG_MakePtr(_ptemp, (char *) _result,"_MsOle_p");
_resultobj = Py_BuildValue("s",_ptemp);
} else {
Py_INCREF(Py_None);
_resultobj = Py_None;
}
return _resultobj;
}
static PyObject *_wrap__ms_ole_destroy(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOle * _arg0;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"O:_ms_ole_destroy",&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOle_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_destroy. Expected _MsOle_p.");
return NULL;
}
}
_ms_ole_destroy(_arg0);
Py_INCREF(Py_None);
_resultobj = Py_None;
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_open(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOleSummary * _result;
MsOle * _arg0;
PyObject * _argo0 = 0;
char _ptemp[128];
self = self;
if(!PyArg_ParseTuple(args,"O:_ms_ole_summary_open",&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOle_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_open. Expected _MsOle_p.");
return NULL;
}
}
_result = (MsOleSummary *)_ms_ole_summary_open(_arg0);
if (_result) {
SWIG_MakePtr(_ptemp, (char *) _result,"_MsOleSummary_p");
_resultobj = Py_BuildValue("s",_ptemp);
} else {
Py_INCREF(Py_None);
_resultobj = Py_None;
}
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_close(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOleSummary * _arg0;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"O:_ms_ole_summary_close",&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_close. Expected _MsOleSummary_p.");
return NULL;
}
}
_ms_ole_summary_close(_arg0);
Py_INCREF(Py_None);
_resultobj = Py_None;
return _resultobj;
}
static PyObject *_wrap__ms_ole_docsummary_open(PyObject *self, PyObject *args) {
PyObject * _resultobj;
MsOleSummary * _result;
MsOle * _arg0;
PyObject * _argo0 = 0;
char _ptemp[128];
self = self;
if(!PyArg_ParseTuple(args,"O:_ms_ole_docsummary_open",&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOle_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_docsummary_open. Expected _MsOle_p.");
return NULL;
}
}
_result = (MsOleSummary *)_ms_ole_docsummary_open(_arg0);
if (_result) {
SWIG_MakePtr(_ptemp, (char *) _result,"_MsOleSummary_p");
_resultobj = Py_BuildValue("s",_ptemp);
} else {
Py_INCREF(Py_None);
_resultobj = Py_None;
}
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_get_string(PyObject *self, PyObject *args) {
PyObject * _resultobj;
char * _result;
MsOleSummary * _arg0;
int _arg1;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"Oi:_ms_ole_summary_get_string",&_argo0,&_arg1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_get_string. Expected _MsOleSummary_p.");
return NULL;
}
}
_result = (char *)_ms_ole_summary_get_string(_arg0,_arg1);
_resultobj = Py_BuildValue("s", _result);
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_get_long(PyObject *self, PyObject *args) {
PyObject * _resultobj;
int _result;
MsOleSummary * _arg0;
int _arg1;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"Oi:_ms_ole_summary_get_long",&_argo0,&_arg1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_get_long. Expected _MsOleSummary_p.");
return NULL;
}
}
_result = (int )_ms_ole_summary_get_long(_arg0,_arg1);
_resultobj = Py_BuildValue("i",_result);
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_get_short(PyObject *self, PyObject *args) {
PyObject * _resultobj;
short _result;
MsOleSummary * _arg0;
int _arg1;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"Oi:_ms_ole_summary_get_short",&_argo0,&_arg1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_get_short. Expected _MsOleSummary_p.");
return NULL;
}
}
_result = (short )_ms_ole_summary_get_short(_arg0,_arg1);
_resultobj = Py_BuildValue("h",_result);
return _resultobj;
}
static PyObject *_wrap__ms_ole_summary_get_time(PyObject *self, PyObject *args) {
PyObject * _resultobj;
char * _result;
MsOleSummary * _arg0;
int _arg1;
PyObject * _argo0 = 0;
self = self;
if(!PyArg_ParseTuple(args,"Oi:_ms_ole_summary_get_time",&_argo0,&_arg1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_MsOleSummary_p")) {
PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of _ms_ole_summary_get_time. Expected _MsOleSummary_p.");
return NULL;
}
}
_result = (char *)_ms_ole_summary_get_time(_arg0,_arg1);
_resultobj = Py_BuildValue("s", _result);
return _resultobj;
}
static PyMethodDef oleMethods[] = {
{ "_ms_ole_summary_get_time", _wrap__ms_ole_summary_get_time, METH_VARARGS },
{ "_ms_ole_summary_get_short", _wrap__ms_ole_summary_get_short, METH_VARARGS },
{ "_ms_ole_summary_get_long", _wrap__ms_ole_summary_get_long, METH_VARARGS },
{ "_ms_ole_summary_get_string", _wrap__ms_ole_summary_get_string, METH_VARARGS },
{ "_ms_ole_docsummary_open", _wrap__ms_ole_docsummary_open, METH_VARARGS },
{ "_ms_ole_summary_close", _wrap__ms_ole_summary_close, METH_VARARGS },
{ "_ms_ole_summary_open", _wrap__ms_ole_summary_open, METH_VARARGS },
{ "_ms_ole_destroy", _wrap__ms_ole_destroy, METH_VARARGS },
{ "_ms_ole_open_body", _wrap__ms_ole_open_body, METH_VARARGS },
{ "_ms_ole_open", _wrap__ms_ole_open, METH_VARARGS },
{ NULL, NULL }
};
#ifdef __cplusplus
}
#endif
/*
* This table is used by the pointer type-checker
*/
static struct { char *n1; char *n2; void *(*pcnv)(void *); } _swig_mapping[] = {
{ "_signed_long","_long",0},
{ "_long","_unsigned_long",0},
{ "_long","_signed_long",0},
{ "_unsigned_long","_long",0},
{ "_signed_int","_int",0},
{ "_unsigned_short","_short",0},
{ "_signed_short","_short",0},
{ "_unsigned_int","_int",0},
{ "_short","_unsigned_short",0},
{ "_short","_signed_short",0},
{ "_int","_unsigned_int",0},
{ "_int","_signed_int",0},
{0,0,0}};
static PyObject *SWIG_globals;
#ifdef __cplusplus
extern "C"
#endif
SWIGEXPORT(void) initole() {
PyObject *m, *d;
SWIG_globals = SWIG_newvarlink();
m = Py_InitModule("ole", oleMethods);
d = PyModule_GetDict(m);
{
int i;
for (i = 0; _swig_mapping[i].n1; i++)
SWIG_RegisterMapping(_swig_mapping[i].n1,_swig_mapping[i].n2,_swig_mapping[i].pcnv);
}
}
--- Added File setup.py in package CMF ---
#!/usr/bin/env python
from distutils.core import setup, Extension
setup(name = "ole",
version = "1.0",
description = "libole2 Interface",
author = "John Platten",
author_email = "jplatten@digicool.com",
ext_modules =
[('ole',
{ 'sources':
['ole_wrap.c',
'ole.c',
'version.c',
'ms-ole.c',
'ms-ole-vba.c',
'ms-ole-summary.c'],
'include_dirs': ['.'],
'includes':
['config.h',
'glibconfig.h',
'libole2.h',
'ms-ole.h',
'ms-ole-vba.h',
'ms-ole-summary.h'],
'libraries': ["glib"],
}
)]
)
--- Added File test-ole.c in package CMF ---
/**
* test-ole.c: OLE2 file format helper program,
* good for dumping OLE streams, and
* corresponding biff records, and hopefuly
* some more ...
*
* Author:
* Michael Meeks (michael@imaginator.com)
**/
#define TEST_DEBUG 0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* For ctime() */
#include <time.h>
#include <ms-ole.h>
#include <ms-ole-vba.h>
#include <ms-ole-summary.h>
#define BIFF_TYPES_FILE "biff-types.h"
#if TEST_DEBUG > 0
static char delim[]=":";
#else
static char delim[]=" ";
#endif
static char **arg_data = NULL;
static int arg_cur = 0;
typedef struct {
guint16 opcode;
char *name;
} GENERIC_TYPE;
static GPtrArray *biff_types = NULL;
static char *cur_dir = NULL;
static void
read_types (char *fname, GPtrArray **types)
{
FILE *file = fopen(fname, "r");
char buffer[1024];
*types = g_ptr_array_new ();
if (!file) {
char *newname = g_strconcat ("../", fname, NULL);
file = fopen (newname, "r");
}
if (!file) {
printf ("Can't find vital file '%s'\n", fname);
return;
}
while (!feof(file)) {
char *p;
fgets(buffer,1023,file);
for (p=buffer;*p;p++)
if (*p=='0' && *(p+1)=='x') {
GENERIC_TYPE *bt = g_new (GENERIC_TYPE,1);
char *name, *pt;
bt->opcode=strtol(p+2,0,16);
pt = buffer;
while (*pt && *pt != '#') pt++; /* # */
while (*pt && !isspace(*pt)) pt++; /* define */
while (*pt && isspace(*pt)) pt++; /* ' ' */
while (*pt && *pt != '_') pt++; /* BIFF_ */
name = *pt?pt+1:pt;
while (*pt && !isspace(*pt)) pt++;
bt->name=g_strndup(name, (pt-name));
g_ptr_array_add (*types, bt);
break;
}
}
fclose (file);
}
static char*
get_biff_opcode_name (guint16 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>0xff) {
if (bt->opcode == opcode)
return bt->name;
} else {
if (bt->opcode == (opcode&0xff))
return bt->name;
}
}
return "Unknown";
}
static void
list_files (MsOle *ole)
{
char **names;
MsOleErr result;
int lp;
result = ms_ole_directory (&names, ole, cur_dir);
if (result != MS_OLE_ERR_OK) {
g_warning ("Failed dir");
return;
}
if (!names[0])
printf ("Empty directory\n");
for (lp = 0; names[lp]; lp++) {
MsOleStat s;
result = ms_ole_stat (&s, ole, cur_dir, names[lp]);
if (s.type == MsOleStreamT)
if (names[lp][0] < 0x30) {
printf ("'\\%x%s' : length %d bytes\n",
names[lp][0], names[lp] + 1, s.size);
} else {
printf ("'%s : length %d bytes\n",
names[lp], s.size);
}
else
if (names[lp][0] < 0x30) {
printf ("'\\%d[%s]' : Storage ( directory )\n",
names[lp][0], names [lp] + 1);
} else {
printf ("'[%s] : Storage ( directory )\n",
names [lp]);
}
}
}
static void
list_commands ()
{
printf ("command can be one or all of:\n");
printf (" * ls: list files\n");
printf (" * cd: enter storage\n");
printf (" * biff <stream name>: dump biff records, merging continues\n");
printf (" * biffraw <stream name>: dump biff records no merge + raw data\n");
printf (" * dump <stream name>: dump stream\n");
printf (" * summary : dump summary info\n");
printf (" * docsummary : dump document summary info\n");
printf (" * debug : dump internal ole library status\n");
printf (" * tree : dump the tree\n");
printf (" * vba : attempt to dump vba \n");
printf (" Raw transfer commands\n");
printf (" * get <stream name> <fname>\n");
printf (" * put <fname> <stream name>\n");
printf (" * copyin [<fname>,]...\n");
printf (" * copyout [<fname>,]...\n");
printf (" * quit,exit,bye: exit\n");
}
static void
syntax_error (char *err)
{
if (err) {
printf("Error: '%s'\n",err);
exit(1);
}
printf ("Sytax:\n");
printf (" ole <ole-file> [-i] [commands...]\n\n");
printf (" -i: Interactive, queries for fresh commands\n\n");
list_commands ();
exit(1);
}
/* ---------------------------- End cut ---------------------------- */
static gboolean
simple_regexp (const char *regexp, const char *fname)
{
int i;
gboolean ret = TRUE;
g_return_val_if_fail (fname != NULL, FALSE);
g_return_val_if_fail (regexp != NULL, FALSE);
for (i = 0; regexp [i] && fname [i]; i++) {
if (regexp [i] == '.')
continue;
if (toupper (regexp [i]) != toupper (fname [i])) {
ret = FALSE;
break;
}
}
if (regexp [i] && regexp [i] == '*')
ret = TRUE;
else if (!regexp [i] && fname [i])
ret = FALSE;
/* if (ret)
printf ("'%s' matched '%s'\n", regexp, fname);*/
return ret;
}
/*
* This should take a path to check the directory out there.
*/
static char *
get_regexp_name (const char *regexp, const char *path, MsOle *ole)
{
char *res = NULL;
char **names;
MsOleErr result;
int lp;
result = ms_ole_directory (&names, ole, path);
if (result != MS_OLE_ERR_OK) {
g_warning ("Failed dir");
return NULL;
}
if (!names [0])
printf ("Empty directory\n");
for (lp = 0; names[lp]; lp++) {
if (simple_regexp (regexp, names [lp])) {
res = g_strdup (names [lp]);
break;
}
}
return res;
}
static void
enter_dir (MsOle *ole)
{
char *newpath, *ptr, *p;
p = arg_data [arg_cur++];
if (!p) {
printf ("Takes a directory argument\n");
return;
}
if (!g_strcasecmp (p, "..")) {
guint lp;
char **tmp;
GString *newp = g_string_new ("");
tmp = g_strsplit (cur_dir, "/", -1);
lp = 0;
if (!tmp[lp])
return;
while (tmp[lp+1]) {
g_string_sprintfa (newp, "%s/", tmp[lp]);
lp++;
}
g_free (cur_dir);
cur_dir = newp->str;
g_string_free (newp, FALSE);
} else {
MsOleStat s;
MsOleErr result;
ptr = get_regexp_name (p, cur_dir, ole);
if (!ptr)
return;
newpath = g_strconcat (cur_dir, ptr, "/", NULL);
result = ms_ole_stat (&s, ole, newpath, "");
if (result == MS_OLE_ERR_EXIST) {
printf ("Storage '%s' not found\n", ptr);
g_free (newpath);
return;
}
if (result != MS_OLE_ERR_OK) {
g_warning ("internal error");
g_free (newpath);
return;
}
if (s.type == MsOleStreamT) {
printf ("Trying to enter a stream. (%d)\n", s.type);
g_free (newpath);
return;
}
g_free (cur_dir);
cur_dir = newpath;
}
}
static MsOleErr
test_stream_open (MsOleStream ** const stream, MsOle *f,
const char *path, const char *fname, char mode)
{
MsOleErr err;
char *name;
name = get_regexp_name (fname, path, f);
if (name) {
err = ms_ole_stream_open (stream, f, path, name, mode);
g_free (name);
} else /* Fall back to original */
err = ms_ole_stream_open (stream, f, fname, name, mode);
return err;
}
static void
do_dump (MsOle *ole)
{
char *ptr;
MsOleStream *stream;
guint8 *buffer;
gchar *tname;
ptr = arg_data [arg_cur++];
if (!ptr) {
printf ("Need a stream name\n");
return;
}
tname = g_strdup (ptr);
if (strcmp(tname, "SummaryInformation") == 0) {
printf ("Changing name to prepend 005\n");
tname = "\05SummaryInformation";
}
if (strcmp(tname, "DocumentSummaryInformation") == 0) {
printf ("Changing name to prepend 005\n");
tname = "\05DocumentSummaryInformation";
}
if (test_stream_open (&stream, ole, cur_dir, tname, 'r') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", ptr);
return;
}
buffer = g_malloc (stream->size);
stream->read_copy (stream, buffer, stream->size);
printf ("Stream : '%s' length 0x%x\n", ptr, stream->size);
if (buffer)
ms_ole_dump (buffer, stream->size);
else
printf ("Failed read\n");
ms_ole_stream_close (&stream);
}
/*
* This is a massively cut down version ...
*/
typedef struct {
guint16 opcode;
guint32 length; /* NB. can be extended by a continue opcode */
guint8 *data;
guint32 streamPos;
MsOleStream *pos;
} BiffQuery;
static BiffQuery *
ms_biff_query_new (MsOleStream *ptr)
{
BiffQuery *bq ;
if (!ptr)
return 0;
bq = g_new0 (BiffQuery, 1);
bq->opcode = 0;
bq->length = 0;
bq->pos = ptr;
return bq;
}
static int
ms_biff_query_next (BiffQuery *bq)
{
guint8 tmp[4];
int ans=1;
if (!bq || bq->pos->position >= bq->pos->size)
return 0;
if (bq->data)
g_free (bq->data);
bq->streamPos = bq->pos->position;
if (!bq->pos->read_copy (bq->pos, tmp, 4))
return 0;
bq->opcode = MS_OLE_GET_GUINT16 (tmp);
bq->length = MS_OLE_GET_GUINT16 (tmp+2);
if (bq->length > 0) {
bq->data = g_new0 (guint8, bq->length);
if (!bq->pos->read_copy(bq->pos, bq->data, bq->length)) {
ans = 0;
g_free (bq->data);
bq->length = 0;
}
}
if (!bq->length) {
bq->data = NULL;
return 1;
}
return (ans);
}
static void
do_biff (MsOle *ole)
{
char *ptr;
MsOleStream *stream;
ptr = arg_data[arg_cur++];
if (!ptr) {
printf ("Need a stream name\n");
return;
}
if (test_stream_open (&stream, ole, cur_dir, ptr, 'r') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", ptr);
return;
}
{
BiffQuery *q = ms_biff_query_new (stream);
guint16 last_opcode=0xffff;
guint32 last_length=0;
guint32 count=0;
while (ms_biff_query_next(q)) {
if (q->opcode == last_opcode &&
q->length == last_length)
count++;
else {
if (count>0)
printf (" x %d\n", count+1);
else
printf ("\n");
count=0;
printf ("Opcode 0x%3x : %15s, length %d",
q->opcode, get_biff_opcode_name (q->opcode), q->length);
}
last_opcode=q->opcode;
last_length=q->length;
}
printf ("\n");
ms_ole_stream_close (&stream);
}
}
static void
do_biff_raw (MsOle *ole)
{
char *ptr;
MsOleStream *stream;
ptr = arg_data[arg_cur++];
if (!ptr) {
printf ("Need a stream name\n");
return;
}
if (test_stream_open (&stream, ole, cur_dir, ptr, 'r') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", ptr);
return;
}
{
guint8 data[4], *buffer;
buffer = g_new (guint8, 65550);
while (stream->read_copy (stream, data, 4)) {
guint32 len=MS_OLE_GET_GUINT16(data+2);
/* printf ("0x%4x Opcode 0x%3x : %15s, length 0x%x (=%d)\n", stream->position,
MS_OLE_GET_GUINT16(data), get_biff_opcode_name (MS_OLE_GET_GUINT16(data)),
len, len);*/
printf ("Opcode 0x%3x : %15s, length 0x%x (=%d)\n",
MS_OLE_GET_GUINT16(data), get_biff_opcode_name (MS_OLE_GET_GUINT16(data)),
len, len);
stream->read_copy (stream, buffer, len);
ms_ole_dump (buffer, len);
buffer[0]=0;
buffer[len-1]=0;
}
ms_ole_stream_close (&stream);
}
}
static void
really_get (MsOle *ole, char *from, char *to)
{
MsOleStream *stream;
if (test_stream_open (&stream, ole, cur_dir, from, 'r') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", from);
return;
} else {
guint8 *buffer = g_malloc (stream->size);
FILE *f = fopen (to, "w");
stream->read_copy (stream, buffer, stream->size);
printf ("Stream : '%s' length 0x%x\n", from, stream->size);
if (f && buffer) {
fwrite (buffer, 1, stream->size, f);
fclose (f);
} else
printf ("Failed write to '%s'\n", to);
ms_ole_stream_close (&stream);
}
}
static void
do_get (MsOle *ole)
{
char *from, *to;
from = arg_data[arg_cur++];
if (!from)
to = NULL;
else
to = arg_data[arg_cur++];
really_get (ole, from, to);
}
static void
really_put (MsOle *ole, char *from, char *to)
{
MsOleStream *stream;
char buffer[8200];
if (!from || !to) {
printf ("Null name\n");
return;
}
if (test_stream_open (&stream, ole, cur_dir, to, 'w') !=
MS_OLE_ERR_OK) {
printf ("Error opening '%s'\n", to);
return;
} else {
FILE *f = fopen (from, "r");
size_t len;
int block=0;
if (!f || !stream) {
printf ("Failed write\n");
return;
}
stream->lseek (stream, 0, MsOleSeekSet);
do {
guint32 lenr = 1+ (int)(8192.0*rand()/(RAND_MAX+1.0));
len = fread (buffer, 1, lenr, f);
printf ("Transfering block %d = %d bytes\n", block++, len);
stream->write (stream, buffer, len);
} while (!feof(f) && len>0);
fclose (f);
ms_ole_stream_close (&stream);
}
}
static void
do_summary (MsOle *ole)
{
MsOleSummary *si;
MsOleSummaryPreview preview;
gboolean ok;
gchar *txt;
guint32 num;
GTimeVal timeval;
si = ms_ole_summary_open (ole);
if (!si) {
printf ("No summary information\n");
return;
}
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_TITLE, &ok);
if (ok)
printf ("The title is %s\n", txt);
else
printf ("no title found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_SUBJECT, &ok);
if (ok)
printf ("The subject is %s\n", txt);
else
printf ("no subject found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_AUTHOR, &ok);
if (ok)
printf ("The author is %s\n", txt);
else
printf ("no author found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_KEYWORDS, &ok);
if (ok)
printf ("The keywords are %s\n", txt);
else
printf ("no keywords found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_COMMENTS, &ok);
if (ok)
printf ("The comments are %s\n", txt);
else
printf ("no comments found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_TEMPLATE, &ok);
if (ok)
printf ("The template was %s\n", txt);
else
printf ("no template found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_LASTAUTHOR, &ok);
if (ok)
printf ("The last author was %s\n", txt);
else
printf ("no last author found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_REVNUMBER, &ok);
if (ok)
printf ("The rev no was %s\n", txt);
else
printf ("no rev no found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_APPNAME, &ok);
if (ok)
printf ("The app name was %s\n", txt);
else
printf ("no app name found\n");
g_free (txt);
timeval = ms_ole_summary_get_time (si, MS_OLE_SUMMARY_TOTAL_EDITTIME, &ok);
if (ok)
printf ("Total edit time is %ld", timeval.tv_sec);
else
printf ("no total edit time found\n");
timeval = ms_ole_summary_get_time (si, MS_OLE_SUMMARY_LASTPRINTED, &ok);
if (ok)
printf ("Last printed at %s", ctime (&timeval.tv_sec));
else
printf ("no last printed time found\n");
timeval = ms_ole_summary_get_time (si, MS_OLE_SUMMARY_CREATED, &ok);
if (ok)
printf ("Was created at %s", ctime (&timeval.tv_sec));
else
printf ("no creation time found\n");
timeval = ms_ole_summary_get_time (si, MS_OLE_SUMMARY_LASTSAVED, &ok);
if (ok)
printf ("Last saved at %s", ctime (&timeval.tv_sec));
else
printf ("no last saved time found\n");
num = ms_ole_summary_get_long (si, MS_OLE_SUMMARY_PAGECOUNT, &ok);
if (ok)
printf ("PageCount is %d\n", num);
else
printf ("no pagecount found\n");
num = ms_ole_summary_get_long (si, MS_OLE_SUMMARY_WORDCOUNT, &ok);
if (ok)
printf ("WordCount is %d\n", num);
else
printf ("no wordcount found\n");
num = ms_ole_summary_get_long (si, MS_OLE_SUMMARY_CHARCOUNT, &ok);
if (ok)
printf ("CharCount is %d\n", num);
else
printf ("no charcount found\n");
num = ms_ole_summary_get_long (si, MS_OLE_SUMMARY_SECURITY, &ok);
if (ok)
printf ("Security is %d\n", num);
else
printf ("no security found\n");
num = ms_ole_summary_get_short (si, MS_OLE_SUMMARY_CODEPAGE, &ok);
if (ok)
printf ("CodePage is %d\n", num);
else
printf ("no codepage found\n");
preview = ms_ole_summary_get_preview (si, MS_OLE_SUMMARY_THUMBNAIL, &ok);
if (ok) {
printf ("preview is %d bytes long\n", preview.len);
ms_ole_summary_preview_destroy (preview);
} else
printf ("no preview found\n");
ms_ole_summary_close (si);
}
static void
do_docsummary (MsOle *ole)
{
MsOleSummary *si;
gboolean ok;
gchar *txt;
si = ms_ole_docsummary_open (ole);
if (!si) {
printf ("No document summary information\n");
return;
}
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_CATEGORY, &ok);
if (ok)
printf ("The category is %s\n", txt);
else
printf ("no category found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_PRESFORMAT, &ok);
if (ok)
printf ("The presformat is %s\n", txt);
else
printf ("no presformat found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_MANAGER, &ok);
if (ok)
printf ("The manager is %s\n", txt);
else
printf ("no manager found\n");
g_free (txt);
txt = ms_ole_summary_get_string (si, MS_OLE_SUMMARY_COMPANY, &ok);
if (ok)
printf ("The company is %s\n", txt);
else
printf ("no company found\n");
g_free (txt);
ms_ole_summary_close (si);
}
static void
do_put (MsOle *ole)
{
char *from, *to;
from = arg_data[arg_cur++];
if (!from)
to = NULL;
else
to = arg_data[arg_cur++];
if (!from || !to) {
printf ("put <filename> <stream>\n");
return;
}
really_put (ole, from, to);
}
static void
do_copyin (MsOle *ole)
{
char *from;
do {
from = arg_data[arg_cur++];
if (from)
really_put (ole, from, from);
} while (from);
}
static void
do_copyout (MsOle *ole)
{
char *from;
do {
from = arg_data[arg_cur++];
if (from)
really_get (ole, from, from);
} while (from);
}
static void
dump_vba (MsOle *f)
{
const char *vbapath = "/_VBA_PROJECT_CUR";
char **dir;
char *txt;
int i;
int module_count;
MsOleStream *s;
MsOleStat st;
if (ms_ole_stat (&st, f, vbapath, "") != MS_OLE_ERR_OK ||
st.type == MsOleStreamT) {
printf ("No valid VBA found\n");
return;
}
if (test_stream_open (&s, f, vbapath, "PROJECT", 'r') !=
MS_OLE_ERR_OK) {
printf ("No project file... wierd\n");
} else {
txt = g_new (guint8, s->size);
if (!s->read_copy (s, txt, s->size))
printf ("Failed to read project stream\n");
else {
printf ("----------\n");
printf ("Project file:\n");
printf ("%s", txt);
printf ("----------\n");
}
ms_ole_stream_close (&s);
g_free (txt);
}
txt = g_strconcat (vbapath, "/VBA", NULL);
if (ms_ole_directory (&dir, f, txt) != MS_OLE_ERR_OK) {
printf ("No VBA subdirectory found");
g_free (txt);
return;
}
module_count = 0;
for (i = 0; dir [i]; i++) {
if (test_stream_open (&s, f, txt, dir[i], 'r') !=
MS_OLE_ERR_OK)
printf ("Error opening %s\n", dir [i]);
else {
MsOleVba *vba;
vba = ms_ole_vba_open (s);
if (!vba)
g_warning ("Stream '%s' not VBA", dir [i]);
else {
module_count++;
while (!ms_ole_vba_eof (vba))
printf ("%c", ms_ole_vba_getc (vba));
}
ms_ole_vba_close (vba);
ms_ole_stream_close (&s);
}
}
if (!module_count)
printf ("Strange no modules found\n");
g_free (txt);
}
int
main_original (int argc, char **argv)
{
MsOle *ole;
int lp, exit = 0, interact = 0;
char *buffer = g_new (char, 1024) ;
if (argc<2)
syntax_error(0);
printf ("Ole file '%s'\n", argv[1]);
if (ms_ole_open_vfs (&ole, argv[1], TRUE, NULL)
!= MS_OLE_ERR_OK) {
printf ("Creating new file '%s'\n", argv[1]);
if (ms_ole_create_vfs (&ole, argv[1], TRUE, NULL)
!= MS_OLE_ERR_OK)
syntax_error ("Can't open file or create new one");
}
if (argc<=2)
syntax_error ("Need command or -i");
if (argc>2 && argv[argc-1][0]=='-'
&& argv[argc-1][1]=='i')
interact=1;
else {
char *str=g_strdup(argv[2]) ;
for (lp=3;lp<argc;lp++)
str = g_strconcat(str," ",argv[lp],NULL); /* FIXME Mega leak :-) */
buffer = str; /* and again */
}
cur_dir = g_strdup ("/");
do
{
char *ptr;
if (interact) {
fprintf (stdout,"> ");
fflush (stdout);
fgets (buffer, 1023, stdin);
}
arg_data = g_strsplit (g_strchomp (buffer), delim, -1);
arg_cur = 0;
if (!arg_data && interact) continue;
if (!interact)
printf ("Command : '%s'\n", arg_data[0]);
ptr = arg_data[arg_cur++];
if (!ptr)
continue;
if (g_strcasecmp (ptr, "ls") == 0)
list_files (ole);
else if (g_strcasecmp (ptr, "cd") == 0)
enter_dir (ole);
else if (g_strcasecmp (ptr, "dump") == 0)
do_dump (ole);
else if (g_strcasecmp (ptr, "biff") == 0)
do_biff (ole);
else if (g_strcasecmp (ptr, "biffraw") == 0)
do_biff_raw (ole);
else if (g_strcasecmp (ptr, "get") == 0)
do_get (ole);
else if (g_strcasecmp (ptr, "put") == 0)
do_put (ole);
else if (g_strcasecmp (ptr, "copyin") == 0)
do_copyin (ole);
else if (g_strcasecmp (ptr, "copyout") == 0)
do_copyout (ole);
else if (g_strcasecmp (ptr, "summary") == 0)
do_summary (ole);
else if (g_strcasecmp (ptr, "docsummary") == 0)
do_docsummary (ole);
else if (g_strcasecmp (ptr, "debug") == 0)
ms_ole_debug (ole, 1);
else if (g_strcasecmp (ptr, "tree") == 0)
ms_ole_debug (ole, 2);
else if (g_strcasecmp (ptr, "vba") == 0)
dump_vba (ole);
else if (g_strcasecmp (ptr,"help") == 0 ||
g_strcasecmp (ptr,"?") == 0 ||
g_strcasecmp (ptr,"info") == 0 ||
g_strcasecmp (ptr,"man") == 0)
list_commands ();
else if (g_strcasecmp (ptr,"exit") == 0 ||
g_strcasecmp (ptr,"quit") == 0 ||
g_strcasecmp (ptr,"q") == 0 ||
g_strcasecmp (ptr,"bye") == 0)
exit = 1;
}
while (!exit && interact);
ms_ole_destroy (&ole);
return 0;
}
//----------------------------------------------------------------------------//
int main_file (int argc, char **argv)
{
MsOle *ole;
// int lp, exit = 0, interact = 0;
// char *buffer = g_new (char, 1024) ;
printf("\n");
ms_ole_open_vfs (&ole, argv[1], FALSE, NULL);
do_summary (ole);
do_docsummary (ole);
ms_ole_destroy (&ole);
printf("\n");
return 0;
}
//----------------------------------------------------------------------------//
#define JP_MAX_BUF_LEN 100000
unsigned char jp_buf_buf[JP_MAX_BUF_LEN+1];
MsOle *jp_msOle;
int main_body (int argc, char **argv)
{
MsOle *msOle;
MsOleErr msOleErr;
int fd;
unsigned char *jp_buf_ptr;
size_t jp_buf_len;
fd = open(argv[1], O_RDONLY);
jp_buf_ptr = jp_buf_buf;
jp_buf_len = read(fd, jp_buf_ptr, JP_MAX_BUF_LEN);
close(fd);
msOleErr = ms_ole_open_vfs_body (&jp_msOle, argv[1], FALSE, NULL, jp_buf_ptr, jp_buf_len);
do_summary(jp_msOle);
do_docsummary(jp_msOle);
ms_ole_destroy(&jp_msOle);
}
//----------------------------------------------------------------------------//
int main (int argc, char **argv)
{
printf("\n");
main_file(argc, argv);
main_body(argc, argv);
printf("\n");
return 0;
}
//----------------------------------------------------------------------------//
--- Added File version.c in package CMF ---
int libole2_major_version = 0;
int libole2_minor_version = 1;
int libole2_micro_version = 7;