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 +Manuel Mausz 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 + + * 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 * 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 #include -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 (jody gnome org) * Copyright (C) 2002-2003 Dom Lachowicz (cinamod hotmail com) * excel_iconv* family of functions (C) 2001 by Vlad Harchev + * 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; igva, 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; igva, 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