Hi Jody,

we've added property-write support to libgsf and are contributing it
under LGPL. We're hope that you review the changes and commit them to
CVS. Please find a patch against last thursday's CVS-HEAD in the
attached message.

The author of the patch is Manuel Mausz, thus please contact him
directly for questions regarding the code.


greetings,

 / karl
--- Begin Message ---
libgsf write support
diff -ur libgsf-cvs/AUTHORS libgsflinux/AUTHORS
--- libgsf-cvs/AUTHORS	2002-05-23 08:00:17.000000000 +0200
+++ libgsflinux/AUTHORS	2005-03-24 18:16:47.000000000 +0100
@@ -1 +1,2 @@
 Jody Goldberg            <[EMAIL PROTECTED]>
+Manuel Mausz             <[EMAIL PROTECTED]>
diff -ur libgsf-cvs/ChangeLog libgsflinux/ChangeLog
--- libgsf-cvs/ChangeLog	2005-03-23 04:39:25.000000000 +0100
+++ libgsflinux/ChangeLog	2005-03-24 18:13:20.000000000 +0100
@@ -1,3 +1,21 @@
+2005-03-24  Manuel Mausz  <[EMAIL PROTECTED]>
+
+	* gsf/gsf-docprop-vector.[ch] (_GsfDocPropVector): Moved to header file
+	(_GsfDocPropVectorClass): Moved to header file
+
+	* gsf/gsf-msole-utils.[ch] (gsf_msole_metadata_write_real): Add msole
+	property write support. Codepage support is in TODO.
+	(gsf_msole_metadata_write_prop): New function. Write a single property.
+	(add_props): New function. Adds a property to a struct.
+	(msole_gsf_name_to_prop_id): New function. Returns the id of a known
+	property.
+	(msole_gsf_name_to_prop_type): New function. Returns the type of a known
+	property.
+	(GsfMSOleMetaDataProp_real): New struct.
+	(AddPropsStruct): New struct.
+
+	* gsf/gsf-utils.h (GSF_LE_SET_GUINT64): New macro.
+
 2005-03-22  Morten Welinder  <[EMAIL PROTECTED]>
 
 	* gsf/gsf-libxml.c (close_tag_if_neccessary): New function.
diff -ur libgsf-cvs/gsf/gsf-docprop-vector.c libgsflinux/gsf/gsf-docprop-vector.c
--- libgsf-cvs/gsf/gsf-docprop-vector.c	2005-03-22 23:49:25.000000000 +0100
+++ libgsflinux/gsf/gsf-docprop-vector.c	2005-03-24 15:41:33.000000000 +0100
@@ -23,17 +23,6 @@
 #include <gsf/gsf-docprop-vector.h>
 #include <stdio.h>
 
-struct _GsfDocPropVectorClass {
-	GObjectClass  parent_class;
-};
-
-struct _GsfDocPropVector {
-	GObject      parent;      /* this MUST be the first member */
-
-	GValueArray *gva;
-};
-
-
 /*
  * Local function prototypes.
  */
diff -ur libgsf-cvs/gsf/gsf-docprop-vector.h libgsflinux/gsf/gsf-docprop-vector.h
--- libgsf-cvs/gsf/gsf-docprop-vector.h	2005-03-06 00:18:49.000000000 +0100
+++ libgsflinux/gsf/gsf-docprop-vector.h	2005-03-24 15:41:26.000000000 +0100
@@ -34,7 +34,15 @@
 #define IS_GSF_DOCPROP_VECTOR(obj)         (G_TYPE_CHECK_VALUE_TYPE((obj), GSF_DOCPROP_VECTOR_TYPE))
 #define IS_GSF_DOCPROP_VECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GSF_DOCPROP_VECTOR_TYPE))
 
+struct _GsfDocPropVectorClass {
+	GObjectClass  parent_class;
+};
 
+struct _GsfDocPropVector {
+	GObject      parent;      /* this MUST be the first member */
+
+	GValueArray *gva;
+};
 
 typedef struct _GsfDocPropVectorClass GsfDocPropVectorClass;
 typedef struct _GsfDocPropVector      GsfDocPropVector;
diff -ur libgsf-cvs/gsf/gsf-msole-utils.c libgsflinux/gsf/gsf-msole-utils.c
--- libgsf-cvs/gsf/gsf-msole-utils.c	2005-03-06 06:31:00.000000000 +0100
+++ libgsflinux/gsf/gsf-msole-utils.c	2005-03-24 18:16:31.000000000 +0100
@@ -5,6 +5,7 @@
  * Copyright (C) 2002-2004 Jody Goldberg ([EMAIL PROTECTED])
  * Copyright (C) 2002-2003 Dom Lachowicz ([EMAIL PROTECTED])
  * excel_iconv* family of functions (C) 2001 by Vlad Harchev <[EMAIL PROTECTED]>
+ * write support (C) 2005 by Fabalabs Software GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2.1 of the GNU Lesser General Public
@@ -134,6 +135,14 @@
 } GsfMSOleMetaDataProp;
 
 typedef struct {
+	GValue	        *value;
+	char const	*dict_name;
+	guint32		id;
+	gsf_off_t	offset;
+	GsfMSOleVariantType type;
+} GsfMSOleMetaDataProp_real;
+
+typedef struct {
 	GsfMSOleMetaDataType type;
 	gsf_off_t   offset;
 	guint32	    size, num_props;
@@ -142,6 +151,16 @@
 	GHashTable *dict;
 } GsfMSOleMetaDataSection;
 
+typedef struct {
+	GsfMSOleMetaDataProp_real *props;
+	guint32		udef_props;
+	guint32		it;
+	guint32		count;
+	guint32		dict_count;
+	gsf_off_t	offset;
+	gsf_off_t	dict_offset;
+} AddPropsStruct;
+
 /*
  * DocumentSummaryInformation properties
  */
@@ -248,6 +267,81 @@
 	return NULL;
 }
 
+static guint32
+msole_gsf_name_to_prop_id (char const *name)
+{
+	GsfMSOleMetaDataPropMap const *map = NULL;
+	unsigned i = 0;
+
+	map = component_props;
+	i = G_N_ELEMENTS (component_props);
+	while (i-- > 0) {
+		if (!strncmp(map[i].gsf_name, name, strlen(map[i].gsf_name)))
+			return map[i].id;
+	}
+
+	map = document_props;
+	i = G_N_ELEMENTS (document_props);
+	while (i-- > 0) {
+		if (!strncmp(map[i].gsf_name, name, strlen(map[i].gsf_name)))
+			return map[i].id;
+	}
+
+	map = common_props;
+	i = G_N_ELEMENTS (common_props);
+	while (i-- > 0) {
+		if (!strncmp(map[i].gsf_name, name, strlen(map[i].gsf_name)))
+			return map[i].id;
+	}
+
+	return 0xFFFFFFFF;
+}
+
+static GsfMSOleVariantType
+msole_gsf_name_to_prop_type (char const *name)
+{
+	GsfMSOleMetaDataPropMap const *map = NULL;
+	unsigned i = 0;
+
+	if (name == NULL)
+	      return VT_UNKNOWN;
+
+	map = component_props;
+	i = G_N_ELEMENTS (component_props);
+	while (i-- > 0) {
+		if (!strncmp(map[i].gsf_name, name, strlen(map[i].gsf_name)))
+			return map[i].prefered_type;
+	}
+
+	map = document_props;
+	i = G_N_ELEMENTS (document_props);
+	while (i-- > 0) {
+		if (!strncmp(map[i].gsf_name, name, strlen(map[i].gsf_name)))
+			return map[i].prefered_type;
+	}
+
+	map = common_props;
+	i = G_N_ELEMENTS (common_props);
+	while (i-- > 0) {
+		if (!strncmp(map[i].gsf_name, name, strlen(map[i].gsf_name)))
+			return map[i].prefered_type;
+	}
+
+	return VT_UNKNOWN;
+}
+
+static guint32
+gsf_align_to_32bit(gsf_off_t offset) {
+	guint32 ret;
+	guint32 tmp;
+
+	ret = 0;
+	if ((tmp = offset % 4) > 0)
+		ret = 4 - tmp;
+
+	return ret;
+}
+
 static GValue *
 msole_prop_parse (GsfMSOleMetaDataSection *section,
 		  guint32 type, guint8 const **data, guint8 const *data_end)
@@ -986,6 +1080,742 @@
 	return FALSE;
 }
 
+static void
+add_props(gpointer name, gpointer value, gpointer user_data)
+{
+	if (memcmp(name, GSF_META_NAME_LANGUAGE, sizeof(GSF_META_NAME_LANGUAGE)) &&
+	    memcmp(name, GSF_META_NAME_DICTIONARY, sizeof(GSF_META_NAME_DICTIONARY))) {
+
+		gboolean error = FALSE;
+		guint32 it = ((AddPropsStruct *)user_data)->it;
+
+		GsfMSOleMetaDataProp_real *props = NULL;
+		props = &((AddPropsStruct *)user_data)->props[it];
+
+		gsf_off_t offset;
+		GValue *tmp = NULL;
+
+		GsfDocPropVector *vector = NULL;
+		guint vector_num_values = 1;
+		guint i;
+
+		/* allocate the value */
+		props->value = (GValue *)value;
+
+		/* allocate predefined ids or add it to the dictionary */
+		guint32 id;
+		id = msole_gsf_name_to_prop_id((char *)name);
+		if (id < 0xFFFFFFFF) {
+			props->dict_name = NULL;
+			props->id = id;
+			((AddPropsStruct *)user_data)->count++;
+			offset = ((AddPropsStruct *)user_data)->offset;
+		}
+		else {
+			props->dict_name = (char*)name;
+			props->id = ((AddPropsStruct *)user_data)->dict_count + ((AddPropsStruct *)user_data)->udef_props;
+			((AddPropsStruct *)user_data)->dict_count++;
+			offset = ((AddPropsStruct *)user_data)->dict_offset;
+			d (g_warning("name not found (%s) - generate an id (=%d)", (char *)name, props->id););
+		}
+		it++;
+
+		/* calculate offset */
+		props->offset = offset;
+
+		/* we have an vector */
+		if (IS_GSF_DOCPROP_VECTOR((GValue *)value)) {
+			vector = gsf_value_get_docprop_vector((GValue *)value);
+			vector_num_values = vector->gva->n_values;
+		}
+
+		for (i=0; i < vector_num_values; i++) {
+			if (vector != NULL)
+				(GValue *)value = g_value_array_get_nth (vector->gva, i);
+
+			switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE((GValue *)value))) {
+				case G_TYPE_BOOLEAN:
+					props->type = VT_BOOL;
+					offset += 1;
+					offset += 3; /* 3x \0 */
+					break;
+
+				case G_TYPE_UCHAR:
+					props->type = VT_UI1;
+					offset += 1;
+					break;
+
+				case G_TYPE_INT:
+					switch(msole_gsf_name_to_prop_type((char *)name)) {
+						case VT_I2:
+							props->type = VT_I2;
+							offset += 2;
+							break;
+
+						case VT_I4:
+							props->type = VT_I4;
+							offset += 4;
+							break;
+
+						default:
+							props->type = VT_I4;
+							offset += 4;
+							break;
+					}
+					break;
+
+				case G_TYPE_UINT:
+					switch(msole_gsf_name_to_prop_type((char *)name)) {
+						case VT_UI2:
+							props->type = VT_UI2;
+							offset += 2;
+							break;
+
+						case VT_UI4:
+							props->type = VT_UI4;
+							offset += 4;
+							break;
+
+						default:
+							props->type = VT_UI4;
+							offset += 4;
+							break;
+					}
+					break;
+
+				case G_TYPE_FLOAT:
+					props->type = VT_R4;
+					offset += 4;
+					break;
+
+				case G_TYPE_DOUBLE:
+					props->type = VT_R8;
+					offset += 8;
+					break;
+
+				case G_TYPE_STRING:
+					props->type = VT_LPSTR;
+					offset += 4; /* length of string */
+					offset += strlen((char *)g_value_get_string((GValue *)value)) + 1; /* \0 */
+					break;
+
+				case G_TYPE_BOXED:
+					props->type = VT_FILETIME;
+					offset += 8;
+					break;
+
+				case G_TYPE_POINTER:
+					tmp = (GValue *)g_value_get_pointer((GValue *)value);
+					props->type = msole_gsf_name_to_prop_type((char *)name);
+					offset += g_value_get_uint(&tmp[0]) - 1 /* \0 */ - 4 /* type definition */;
+					break;
+
+				default:
+					g_warning ("Unknown property type for property: %s", (char *)name);
+					error = TRUE;
+					break;
+			}
+		}
+
+		if (error) {
+			/* if error occured, count backwards */
+			g_warning("leaving this property out");
+			if (props->id >= ((AddPropsStruct *)user_data)->udef_props)
+				((AddPropsStruct *)user_data)->dict_count--;
+			else
+				((AddPropsStruct *)user_data)->count--;
+			it--;
+		}
+		else {
+			offset += sizeof(guint32); /* sizeof type definition */
+
+			if (vector != NULL) {
+				props->type = VT_VECTOR;
+				offset += sizeof(guint32); /* sizeof count */
+
+				if (!memcmp(name, GSF_META_NAME_DOCUMENT_PARTS, sizeof(GSF_META_NAME_DOCUMENT_PARTS)))
+				      props->type = VT_VECTOR | VT_LPSTR;
+				else if (!memcmp(name, GSF_META_NAME_HEADING_PAIRS, sizeof(GSF_META_NAME_HEADING_PAIRS))) {
+				      offset += sizeof(guint32) * vector_num_values; /* type definition of variant */
+				      props->type = VT_VECTOR | VT_VARIANT;
+				}
+			}
+
+			/* save offset in struct */
+			if (props->id >= ((AddPropsStruct *)user_data)->udef_props)
+				((AddPropsStruct *)user_data)->dict_offset = offset;
+			else
+				((AddPropsStruct *)user_data)->offset = offset;
+		}
+
+		/* set iterator in struct */
+		((AddPropsStruct *)user_data)->it = it;
+	}
+}
+
+static gboolean
+gsf_msole_metadata_write_prop(GsfOutput *out, GsfMSOleMetaDataProp_real *prop)
+{
+	gboolean success = TRUE;
+	GsfTimestamp const *timestamp = NULL;
+	GsfDocPropVector *vector = NULL;
+	guint32 vector_num;
+	GsfMSOleMetaDataProp_real *vector_prop = NULL;
+	guint64 timet_value = 0;
+	guint32 length = 0;
+	guint8 buf[8];
+	GValue *tmp;
+	guint32 i;
+
+
+	GSF_LE_SET_GUINT32 (buf+0, prop->type);
+	if (!gsf_output_write (out, 4, buf))
+		success = FALSE;
+
+	if (success) {
+		switch (prop->type) {
+			case VT_BOOL:
+				/* 0=false, -1=true */
+				if (g_value_get_boolean((GValue *)prop->value) == TRUE)
+					GSF_LE_SET_GINT8(buf+0, -1);
+				else
+					GSF_LE_SET_GINT8(buf+0, 0);
+				buf[1] = 0;
+				buf[2] = 0;
+				buf[3] = 0;
+				if (!gsf_output_write (out, 4, buf))
+					success = FALSE;
+				break;
+
+			case VT_UI1:
+				GSF_LE_SET_GUINT8(buf+0, g_value_get_uchar((GValue *)prop->value));
+				if (!gsf_output_write (out, 1, buf))
+					success = FALSE;
+				break;
+
+			case VT_I2:
+				GSF_LE_SET_GINT16(buf+0, g_value_get_int((GValue *)prop->value));
+				if (!gsf_output_write (out, 2, buf))
+					success = FALSE;
+				break;
+
+			case VT_I4:
+				GSF_LE_SET_GINT32(buf+0, g_value_get_int((GValue *)prop->value));
+				if (!gsf_output_write (out, 4, buf))
+					success = FALSE;
+				break;
+
+			case VT_UI2:
+				GSF_LE_SET_GUINT16(buf+0, g_value_get_uint((GValue *)prop->value));
+				if (!gsf_output_write (out, 2, buf))
+					success = FALSE;
+				break;
+
+			case VT_UI4:
+				GSF_LE_SET_GUINT16(buf+0, g_value_get_uint((GValue *)prop->value));
+				if (!gsf_output_write (out, 4, buf))
+					success = FALSE;
+				break;
+
+			case VT_R4:
+				GSF_LE_SET_FLOAT(buf+0, g_value_get_float((GValue *)prop->value));
+				if (!gsf_output_write (out, 4, buf))
+					success = FALSE;
+				break;
+
+			case VT_R8:
+				GSF_LE_SET_DOUBLE(buf+0, g_value_get_double((GValue *)prop->value));
+				if (!gsf_output_write (out, 8, buf))
+					success = FALSE;
+				break;
+
+			case VT_LPSTR:
+				/* write the length of the string */
+				length = strlen((char *)g_value_get_string((GValue *)prop->value));
+				GSF_LE_SET_GINT32(buf+0, length + 1 /* \0 */);
+				if (!gsf_output_write (out, 4, buf))
+					success = FALSE;
+
+				/* write the string */
+				if (!gsf_output_write (out, length, (char *)g_value_get_string((GValue *)prop->value)))
+					success = FALSE;
+
+				/* append an \0 */
+				buf[0] = 0;
+				if (!gsf_output_write (out, 1, buf))
+					success = FALSE;
+				break;
+
+			case VT_FILETIME:
+				timestamp = (GsfTimestamp const *)g_value_get_boxed((GValue *)prop->value);
+				timet_value = (time_t)timestamp->timet;
+
+#ifdef _MSC_VER
+				timet_value += 11644473600i64;
+#else
+				timet_value += 11644473600ULL;
+#endif
+				timet_value *= 10000000;
+
+				GSF_LE_SET_GUINT64(buf+0, timet_value);
+				if (!gsf_output_write (out, 8, buf))
+					success = FALSE;
+				break;
+
+			case VT_VECTOR | VT_VARIANT:
+				vector = gsf_value_get_docprop_vector((GValue *)prop->value);
+				vector_num = vector->gva->n_values;
+
+				GSF_LE_SET_GUINT32(buf+0, vector_num);
+				if (!gsf_output_write (out, 4, buf))
+				      success = FALSE;
+
+				for(i=0; i<vector_num; i++) {
+					tmp = g_value_array_get_nth (vector->gva, i);
+					vector_prop = g_new (GsfMSOleMetaDataProp_real, 1);
+					vector_prop->value = tmp;
+
+					switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(tmp))) {
+						case G_TYPE_BOOLEAN:
+							vector_prop->type = VT_BOOL;
+							break;
+
+						case G_TYPE_UCHAR:
+							vector_prop->type = VT_UI1;
+							break;
+
+						case G_TYPE_INT:
+							vector_prop->type = msole_gsf_name_to_prop_type(prop->dict_name);
+							if (vector_prop->type == VT_UNKNOWN)
+							      vector_prop->type = VT_I4;
+							break;
+
+						case G_TYPE_UINT:
+							vector_prop->type = msole_gsf_name_to_prop_type(prop->dict_name);
+							if (vector_prop->type == VT_UNKNOWN)
+							      vector_prop->type = VT_UI4;
+							break;
+
+						case G_TYPE_FLOAT:
+							vector_prop->type = VT_R4;
+							break;
+
+						case G_TYPE_DOUBLE:
+							vector_prop->type = VT_R8;
+							break;
+
+						case G_TYPE_STRING:
+							vector_prop->type = VT_LPSTR;
+							break;
+
+						case G_TYPE_BOXED:
+							vector_prop->type = VT_FILETIME;
+							break;
+
+						default:
+							vector_prop->type = VT_NULL;
+					}
+
+					gsf_msole_metadata_write_prop(out, vector_prop);
+					if (vector_prop != NULL)
+					      g_free(vector_prop);
+				}
+
+				break;
+
+			case VT_VECTOR | VT_LPSTR:
+				/* NOTE: don't write the type here */
+				vector = gsf_value_get_docprop_vector((GValue *)prop->value);
+				vector_num = vector->gva->n_values;
+
+				GSF_LE_SET_GUINT32(buf+0, vector_num);
+				if (!gsf_output_write (out, 4, buf))
+				      success = FALSE;
+
+				for(i=0; i<vector_num; i++) {
+					tmp = g_value_array_get_nth (vector->gva, i);
+
+					/* write the length of the string */
+					length = strlen((char *)g_value_get_string(tmp));
+					GSF_LE_SET_GINT32(buf+0, length + 1 /* \0 */);
+					if (!gsf_output_write (out, 4, buf))
+						success = FALSE;
+
+					/* write the string */
+					if (!gsf_output_write (out, length, (char *)g_value_get_string(tmp)))
+						success = FALSE;
+
+					/* append an \0 */
+					buf[0] = 0;
+					if (!gsf_output_write (out, 1, buf))
+						success = FALSE;
+				}
+				break;
+
+			default:
+				g_warning("Can't write datatype. unknown");
+				break;
+		}
+	}
+
+	return success;
+}
+
+gboolean
+gsf_msole_metadata_write_real (GsfOutput *out, GsfDocMetaData *meta_data,
+	gboolean doc_not_component, GError **err)
+{
+	gboolean success = TRUE;
+	gsf_off_t offset = 0;
+	guint8 header[] = {
+		0xfe, 0xff, /* byte order */
+		0, 0,   /* no one seems to use version 1 */
+		0x04, 0x0a, 0x02, 0x00, /* win32 version (xp = a04, nt/2k = 04 ?) */
+		0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* clasid = 0 */
+	};
+
+
+	/*
+	 * prepare
+	 */
+	guint32 section_count = 0; /* count of sections */
+	guint32 byte_count = 0;    /* count of bytes in a section */
+	guint32 props_count = 0;   /* count of propertys global */
+	guint32 section_props_count = 0; /* count of propertys in a section */
+	gsf_off_t section_offset = 0;
+	gsf_off_t index_offset = 0;
+	guint32 udef_props = 30;   /* id start of user defined ids
+	                              must be higher than the id of the last defined property */
+	guint8 buf[8];
+	guint8 const *guid;
+	guint32 i;
+
+	section_offset += sizeof(byte_count);  /* size of section byte count */
+	section_offset += sizeof(props_count); /* size of property count */
+
+	/*
+	 * check and save codepage into props_codepage
+	 * do this first cause of the encoding
+	 */
+	GsfMSOleMetaDataProp_real *props_codepage = NULL;
+	GsfDocProp *prop_codepage = NULL;
+	if (success) {
+		prop_codepage = gsf_doc_meta_data_get_prop(meta_data, GSF_META_NAME_LANGUAGE);
+		if (prop_codepage != NULL) {
+			if (prop_codepage->val->g_type != G_TYPE_INT) {
+				g_warning ("value of property with name=%s is not an valid codepage", GSF_META_NAME_LANGUAGE);
+				success = FALSE;
+			}
+			else {
+				props_codepage = g_new (GsfMSOleMetaDataProp_real, 1);
+				props_codepage->id = msole_gsf_name_to_prop_id(GSF_META_NAME_LANGUAGE);
+				props_codepage->offset = 0;
+			}
+		}
+	}
+
+	/* get number of propertys and allocate struct */
+	GsfMSOleMetaDataProp_real *props = NULL;
+	if (success) {
+		props_count = gsf_doc_meta_data_size (meta_data);
+		if (prop_codepage != NULL)
+			props_count--;
+		props = g_new (GsfMSOleMetaDataProp_real, props_count);
+	}
+
+	/* insert ids and offsets into props[] (only for id !=0, 1, >0xFFFFFFFF) */
+	AddPropsStruct *props_struct = NULL;
+	if (success) {
+		props_struct = g_new (AddPropsStruct, 1);
+		props_struct->props = props;
+		props_struct->udef_props = udef_props;
+		props_struct->it = 0;
+		props_struct->count = 0;
+		props_struct->dict_count = 0;
+		props_struct->offset = section_offset;
+		props_struct->dict_offset = section_offset;
+		gsf_doc_meta_data_foreach(meta_data, add_props, props_struct);
+	}
+
+
+	/*
+	 * Write Header
+	 */
+
+	/* write static header */
+	if (success) {
+		if (!gsf_output_write (out, sizeof (header), header))
+			success = FALSE;
+		offset += sizeof (header);
+	}
+
+	/* write section count */
+	if (success) {
+		section_count = 1;
+		if (props_struct->dict_count > 0)
+			section_count = 2;
+
+		buf[0] = section_count;
+		buf[1] = 0;
+		buf[2] = 0;
+		buf[3] = 0;
+		if (!gsf_output_write (out, 4, buf))
+			success = FALSE;
+		offset += 4;
+	}
+
+
+	/*
+	 * Write Section Info
+	 */
+
+	/* write unqiue format id  (see msdn) */
+	if (success) {
+		guid = doc_not_component ? document_guid : component_guid;
+		if (!gsf_output_write (out, 16, guid))
+			success = FALSE;
+		offset += 16;
+	}
+
+	/* write offset */
+	if (success) {
+		/* we need to write the user_guid if we have a dictionary,
+		 * so we add the size to the offset */
+		if (props_struct->dict_count > 0) {
+			offset += sizeof (user_guid);
+			offset += 4;
+		}
+
+		GSF_LE_SET_GUINT32 (buf, offset + 4 /* size of offset itself */);
+		if (!gsf_output_write (out, 4, buf))
+			success = FALSE;
+		offset += 4;
+	}
+
+	/* calc section header */
+	if (success) {
+		byte_count = props_struct->offset;
+
+		section_props_count = props_struct->count;
+		if (prop_codepage != NULL)
+			section_props_count++;
+
+		index_offset = 8; /* section header itself */
+		index_offset += (section_props_count * (sizeof(guint32) /* property id */ + sizeof(guint32) /* property offset */));
+	}
+
+	/* write user_guid if dictionary exist */
+	if (success) {
+		if (props_struct->dict_count > 0) {
+			if (!gsf_output_write (out, sizeof (user_guid), user_guid))
+				success = FALSE;
+
+			GSF_LE_SET_GUINT32 (buf+0, byte_count + index_offset + offset);
+			if (!gsf_output_write (out, 4, buf))
+				success = FALSE;
+		}
+	}
+
+	/*  write secion header */
+	if (success) {
+		GSF_LE_SET_GUINT32 (buf+0, byte_count + index_offset); /* byte count */
+		GSF_LE_SET_GUINT32 (buf+4, section_props_count);       /* propertys count */
+		if (!gsf_output_write (out, 8, buf))
+			success = FALSE;
+	}
+
+	/* write codepage index */
+	if (success) {
+		if (prop_codepage != NULL) {
+			props_codepage->offset = index_offset;
+			GSF_LE_SET_GUINT32 (buf+0, props_codepage->id);
+			GSF_LE_SET_GUINT32 (buf+4, props_codepage->offset);
+			if (!gsf_output_write (out, 8, buf))
+				success = FALSE;
+		}
+	}
+
+	/* write property index */
+	if (success) {
+		for (i=0; i < props_count; i++) {
+			if ((props_struct->props)[i].dict_name == NULL) {
+				GSF_LE_SET_GUINT32 (buf+0, (props_struct->props)[i].id);
+				GSF_LE_SET_GUINT32 (buf+4, (props_struct->props)[i].offset + index_offset);
+				if (!gsf_output_write (out, 8, buf))
+					success = FALSE;
+			}
+			if (!success)
+				break;
+		}
+	}
+
+	/* write codepage
+	 * TODO: write codepage support!
+	 */
+	if (success) {
+		if (prop_codepage != NULL) {
+			// TODO: GSF_META_NAME_LANGUAGE = VT_UI2 - msdn says VT_I2
+			//GSF_LE_SET_GUINT32 (buf+0, msole_gsf_name_to_prop_type(GSF_META_NAME_LANGUAGE);
+			GSF_LE_SET_GUINT32 (buf+0, VT_I2);
+			GSF_LE_SET_GUINT32 (buf+4, g_value_get_int(prop_codepage->val));
+			if (!gsf_output_write (out, 8, buf))
+				success = FALSE;
+		}
+	}
+
+	/* write propertys */
+	if (success) {
+		for (i=0; i < props_count; i++) {
+			if ((props_struct->props)[i].dict_name == NULL)
+				success = gsf_msole_metadata_write_prop(out, &(props_struct->props)[i]);
+			if (!success)
+				break;
+		}
+	}
+
+
+	/*
+	 * Write 2. Section
+	 */
+	guint32 length = 0;
+	guint32 dict_size = 0;
+	if (section_count >= 2) {
+		/* calculate sizeof dictionary */
+		if (success) {
+			dict_size = 4;
+			for (i=0; i < props_count; i++) {
+				if ((props_struct->props)[i].dict_name != NULL) {
+					dict_size += 4; /* property id */
+					dict_size += 4; /* lengt of string */
+					dict_size += strlen((props_struct->props)[i].dict_name) + 1; /* \0 */
+				}
+			}
+		}
+
+		/* write section header */
+		if (success) {
+			byte_count = props_struct->dict_offset;
+			byte_count += dict_size;
+			section_props_count = props_struct->dict_count;
+			section_props_count++; /* dictionary */
+			index_offset = 8; /* section header itself */
+			if (prop_codepage != NULL)
+				section_props_count++;
+			index_offset += (section_props_count * (sizeof(guint32) /* property id */ + sizeof(guint32) /* property offset */));
+			GSF_LE_SET_GUINT32 (buf+0, byte_count + index_offset); /* byte count */
+			GSF_LE_SET_GUINT32 (buf+4, section_props_count);  /* propertys count */
+			if (!gsf_output_write (out, 8, buf))
+				success = FALSE;
+		}
+
+		/* write dictionary index */
+		if (success) {
+			GSF_LE_SET_GUINT32 (buf+0, 0);
+			GSF_LE_SET_GUINT32 (buf+4, index_offset);
+			if (!gsf_output_write (out, 8, buf))
+				success = FALSE;
+
+			index_offset += dict_size; /* sizeof dictionary */
+		}
+
+		/* write codepage index */
+		if (success) {
+			if (prop_codepage != NULL) {
+				props_codepage->offset = index_offset;
+				GSF_LE_SET_GUINT32 (buf+0, props_codepage->id);
+				GSF_LE_SET_GUINT32 (buf+4, props_codepage->offset);
+				if (!gsf_output_write (out, 8, buf))
+					success = FALSE;
+			}
+		}
+
+		/* write property index */
+		if (success) {
+			for (i=0; i < props_count; i++) {
+				if ((props_struct->props)[i].dict_name != NULL) {
+					GSF_LE_SET_GUINT32 (buf+0, (props_struct->props)[i].id - udef_props + 2);
+					GSF_LE_SET_GUINT32 (buf+4, (props_struct->props)[i].offset + index_offset);
+					if (!gsf_output_write (out, 8, buf))
+						success = FALSE;
+				}
+				if (!success)
+					break;
+			}
+		}
+
+		/* write dictionary */
+		if (success) {
+			GSF_LE_SET_GUINT32 (buf+0, props_struct->dict_count);
+			if (!gsf_output_write (out, 4, buf))
+				success = FALSE;
+
+			for (i=0; i < props_count; i++) {
+				if ((props_struct->props)[i].dict_name != NULL) {
+					length = strlen((props_struct->props)[i].dict_name);
+					GSF_LE_SET_GUINT32 (buf+0, (props_struct->props)[i].id - udef_props + 2);
+					GSF_LE_SET_GUINT32 (buf+4, length + 1 /* \0 */);
+					if (!gsf_output_write (out, 8, buf))
+						success = FALSE;
+
+					/* write the string */
+					if (!gsf_output_write (out, length, (props_struct->props)[i].dict_name) )
+						success = FALSE;
+
+					/* append an \0 */
+					buf[0] = 0;
+					if (!gsf_output_write (out, 1, buf))
+						success = FALSE;
+				}
+			}
+		}
+
+		/* write codepage
+		 * TODO: write codepage support!
+		 */
+		if (success) {
+			if (prop_codepage != NULL) {
+				// TODO: GSF_META_NAME_LANGUAGE = VT_UI2 - msdn says VT_I2
+				//GSF_LE_SET_GUINT32 (buf+0, msole_gsf_name_to_prop_type(GSF_META_NAME_LANGUAGE);
+				GSF_LE_SET_GUINT32 (buf+0, VT_I2);
+				GSF_LE_SET_GUINT32 (buf+4, g_value_get_int(prop_codepage->val));
+				if (!gsf_output_write (out, 8, buf))
+					success = FALSE;
+			}
+		}
+
+		/* write propertys */
+		if (success) {
+			for (i=0; i < props_count; i++) {
+				if ((props_struct->props)[i].dict_name != NULL)
+					success = gsf_msole_metadata_write_prop(out, &(props_struct->props)[i]);
+				if (!success)
+					break;
+			}
+		}
+	}
+
+	/* output error */
+	if (!success) {
+		if (err != NULL)
+			*err = g_error_copy (gsf_output_error (out));
+	}
+
+	/* free some stuff */
+	if (prop_codepage != NULL)
+		g_free(prop_codepage);
+
+	if (props_codepage != NULL)
+		g_free(props_codepage);
+
+	if (props != NULL)
+		g_free (props);
+
+	if (props_struct != NULL)
+		g_free (props_struct);
+
+	return success;
+}
+
 typedef struct {
 	char const *tag;
 	guint	lid;
diff -ur libgsf-cvs/gsf/gsf-msole-utils.h libgsflinux/gsf/gsf-msole-utils.h
--- libgsf-cvs/gsf/gsf-msole-utils.h	2004-11-02 18:32:41.000000000 +0100
+++ libgsflinux/gsf/gsf-msole-utils.h	2005-03-24 13:13:46.000000000 +0100
@@ -31,6 +31,8 @@
 GsfDocMetaData* gsf_msole_metadata_read_real	(GsfInput *in,   GError **err);
 gboolean        gsf_msole_metadata_write	(GsfOutput *out, gboolean doc_not_component,
 				          	 GError **err);
+gboolean	gsf_msole_metadata_write_real	(GsfOutput *out, GsfDocMetaData *meta_data,
+						 gboolean doc_not_component, GError **err);
 
 guint           gsf_msole_lid_for_language	(char const *lang);
 guint           gsf_msole_codepage_to_lid	(int codepage);
diff -ur libgsf-cvs/gsf/gsf-utils.h libgsflinux/gsf/gsf-utils.h
--- libgsf-cvs/gsf/gsf-utils.h	2004-02-01 19:08:19.000000000 +0100
+++ libgsflinux/gsf/gsf-utils.h	2005-03-24 12:16:19.000000000 +0100
@@ -56,6 +56,15 @@
 	 (*((guint8 *)(p) + 1) = ((dat) >>  8) & 0xff),	\
 	 (*((guint8 *)(p) + 2) = ((dat) >> 16) & 0xff),	\
 	 (*((guint8 *)(p) + 3) = ((dat) >> 24) & 0xff))
+#define GSF_LE_SET_GUINT64(p, dat)			\
+	((*((guint8 *)(p) + 0) = ((dat))       & 0xff),	\
+	 (*((guint8 *)(p) + 1) = ((dat) >>  8) & 0xff),	\
+	 (*((guint8 *)(p) + 2) = ((dat) >> 16) & 0xff),	\
+	 (*((guint8 *)(p) + 3) = ((dat) >> 24) & 0xff),	\
+	 (*((guint8 *)(p) + 4) = ((dat) >> 32) & 0xff),	\
+	 (*((guint8 *)(p) + 5) = ((dat) >> 40) & 0xff),	\
+	 (*((guint8 *)(p) + 6) = ((dat) >> 48) & 0xff),	\
+	 (*((guint8 *)(p) + 7) = ((dat) >> 56) & 0xff))
 #define GSF_LE_SET_GINT8(p,dat) GSF_LE_SET_GUINT8((p),(dat))
 #define GSF_LE_SET_GINT16(p,dat) GSF_LE_SET_GUINT16((p),(dat))
 #define GSF_LE_SET_GINT32(p,dat) GSF_LE_SET_GUINT32((p),(dat))
diff -ur libgsf-cvs/TODO libgsflinux/TODO
--- libgsf-cvs/TODO	2004-11-16 16:40:12.000000000 +0100
+++ libgsflinux/TODO	2005-03-24 18:14:29.000000000 +0100
@@ -3,6 +3,7 @@
     - rework proposed meta data framework to support improved understanding of
       MS Office
     - Complete MS property set read and write
+      (complete codepage support for writing)
     - work on GsfOutput error handling to propagate errors up the stack.
       Maybe something signal based ?
     - for the stdio output check that we can actually write to the target file

--- End Message ---

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
gnumeric-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gnumeric-list

Reply via email to