/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * god-property-table.c: MS Office Graphic Object support * * Copyright (C) 2000-2004 * Jody Goldberg (jody@gnome.org) * Michael Meeks (mmeeks@gnu.org) * Christopher James Lahey * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ #include #include #include #include #include #include static GObjectClass *parent_class; struct GodPropertyTablePrivate_ { GHashTable *attrs; }; #define GR_END 0x00 #define GR_MACRO 0x04 #define GR_COMMAND_BUTTON 0x05 #define GR_GROUP 0x06 #define GR_CLIPBOARD_FORMAT 0x07 #define GR_PICTURE_OPTIONS 0x08 #define GR_PICTURE_FORMULA 0x09 #define GR_CHECKBOX_LINK 0x0A #define GR_RADIO_BUTTON 0x0B #define GR_SCROLLBAR 0x0C #define GR_NOTE_STRUCTURE 0x0D #define GR_SCROLLBAR_FORMULA 0x0E #define GR_GROUP_BOX_DATA 0x0F #define GR_EDIT_CONTROL_DATA 0x10 #define GR_RADIO_BUTTON_DATA 0x11 #define GR_CHECKBOX_DATA 0x12 #define GR_LISTBOX_DATA 0x13 #define GR_CHECKBOX_FORMULA 0x14 #define GR_COMMON_OBJ_DATA 0x15 static GValue * g_value_new (GType type) { GValue *value = g_new0 (GValue, 1); g_value_init (value, type); return value; } static void g_value_free (gpointer data) { GValue *value = data; g_value_unset (value); g_free (value); } void god_property_table_set (GodPropertyTable *prop_table, GodPropertyID id, GValue *value) { g_hash_table_insert (prop_table->priv->attrs, g_strdup(id), value); } GValue * god_property_table_get (GodPropertyTable *prop_table, GodPropertyID id) { g_return_val_if_fail (prop_table != NULL, NULL); return g_hash_table_lookup (prop_table->priv->attrs, id); } void god_property_table_set_flag (GodPropertyTable *prop_table, GodPropertyID id, gboolean val) { GValue *value = g_value_new(G_TYPE_BOOLEAN); g_value_set_boolean (value, val); god_property_table_set (prop_table, id, value); } void god_property_table_set_uint (GodPropertyTable *prop_table, GodPropertyID id, guint32 val) { GValue *value = g_value_new(G_TYPE_UINT); g_value_set_uint (value, val); god_property_table_set (prop_table, id, value); } void god_property_table_set_int (GodPropertyTable *prop_table, GodPropertyID id, gint32 val) { GValue *value = g_value_new(G_TYPE_INT); g_value_set_int (value, val); god_property_table_set (prop_table, id, value); } void god_property_table_set_length (GodPropertyTable *prop_table, GodPropertyID id, go_unit_t val) { GValue *value = g_value_new(G_TYPE_INT64); g_value_set_int64 (value, val); god_property_table_set (prop_table, id, value); } void god_property_table_set_pointer (GodPropertyTable *prop_table, GodPropertyID id, gpointer val) { GValue *value = g_value_new(G_TYPE_POINTER); g_value_set_pointer (value, val); god_property_table_set (prop_table, id, value); } void god_property_table_set_array (GodPropertyTable *prop_table, GodPropertyID id, GArray *val) { GValue *value = g_value_new(G_TYPE_POINTER); g_value_set_pointer (value, val); god_property_table_set (prop_table, id, value); } void god_property_table_set_markup (GodPropertyTable *prop_table, GodPropertyID id, PangoAttrList *list) { GValue *value = g_value_new (PANGO_TYPE_ATTR_LIST); g_value_set_pointer (value, list); god_property_table_set (prop_table, id, value); } gboolean god_property_table_get_flag (GodPropertyTable *prop_table, GodPropertyID id, gboolean default_value) { GValue *value; g_return_val_if_fail (prop_table != NULL, default_value); value = g_hash_table_lookup (prop_table->priv->attrs, id); if (value == NULL) return default_value; g_return_val_if_fail (G_VALUE_HOLDS_BOOLEAN (value), default_value); return g_value_get_boolean (value); } guint32 god_property_table_get_uint (GodPropertyTable *prop_table, GodPropertyID id, guint32 default_value) { GValue *value; g_return_val_if_fail (prop_table != NULL, default_value); value = g_hash_table_lookup (prop_table->priv->attrs, id); if (value == NULL) return default_value; g_return_val_if_fail (G_VALUE_HOLDS_UINT (value), default_value); return g_value_get_uint (value); } gint32 god_property_table_get_int (GodPropertyTable *prop_table, GodPropertyID id, gint32 default_value) { GValue *value; g_return_val_if_fail (prop_table != NULL, default_value); value = g_hash_table_lookup (prop_table->priv->attrs, id); if (value == NULL) return default_value; g_return_val_if_fail (G_VALUE_HOLDS_INT (value), default_value); return g_value_get_int (value); } go_unit_t god_property_table_get_length (GodPropertyTable *prop_table, GodPropertyID id, go_unit_t default_value) { GValue *value; g_return_val_if_fail (prop_table != NULL, default_value); value = g_hash_table_lookup (prop_table->priv->attrs, id); if (value == NULL) return default_value; g_return_val_if_fail (G_VALUE_HOLDS_INT64 (value), default_value); return g_value_get_int64 (value); } gpointer god_property_table_get_pointer (GodPropertyTable *prop_table, GodPropertyID id, gpointer default_value) { GValue *value; g_return_val_if_fail (prop_table != NULL, default_value); value = g_hash_table_lookup (prop_table->priv->attrs, id); if (value == NULL) return default_value; g_return_val_if_fail (G_VALUE_HOLDS_POINTER (value), default_value); return g_value_get_pointer (value); } GArray * god_property_table_get_array (GodPropertyTable *prop_table, GodPropertyID id, GArray *default_value) { GValue *value; g_return_val_if_fail (prop_table != NULL, default_value); value = g_hash_table_lookup (prop_table->priv->attrs, id); if (value == NULL) return default_value; g_return_val_if_fail (G_VALUE_HOLDS_POINTER (value), default_value); return g_value_get_pointer (value); } PangoAttrList * god_property_table_get_markup (GodPropertyTable *prop_table, GodPropertyID id, PangoAttrList *default_value) { GValue *value; g_return_val_if_fail (prop_table != NULL, default_value); value = g_hash_table_lookup (prop_table->priv->attrs, id); if (value == NULL) return default_value; g_return_val_if_fail (G_VALUE_HOLDS_POINTER (value), default_value); return g_value_get_pointer (value); } GodPropertyTable * god_property_table_new (void) { GodPropertyTable *prop_table; prop_table = g_object_new (GOD_PROPERTY_TABLE_TYPE, NULL); return prop_table; } static void god_property_table_init (GObject *object) { GodPropertyTable *prop_table = GOD_PROPERTY_TABLE (object); prop_table->priv = g_new0 (GodPropertyTablePrivate, 1); prop_table->priv->attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_value_free); } static void god_property_table_finalize (GObject *object) { GodPropertyTable *prop_table = GOD_PROPERTY_TABLE (object); g_hash_table_destroy (prop_table->priv->attrs); g_free (prop_table->priv); prop_table->priv = NULL; G_OBJECT_CLASS (parent_class)->finalize (object); } static void god_property_table_class_init (GodPropertyTableClass *class) { GObjectClass *object_class; object_class = (GObjectClass *) class; parent_class = g_type_class_peek_parent (class); object_class->finalize = god_property_table_finalize; } GSF_CLASS (GodPropertyTable, god_property_table, god_property_table_class_init, god_property_table_init, G_TYPE_OBJECT) #if 0 /********************************************************************************/ GODrawingPropertyTable * ms_obj_new (GODrawingPropertyTableAttrBag *attrs) { GODrawingPropertyTable *obj = g_new0 (GODrawingPropertyTable, 1); obj->excel_type = (unsigned)-1; /* Set to undefined */ obj->excel_type_name = NULL; obj->id = -1; obj->gnum_obj = NULL; obj->attrs = (attrs != NULL) ? attrs : ms_obj_attr_bag_new (); obj->combo_in_autofilter = FALSE; obj->is_linked = FALSE; obj->comment_pos.col = obj->comment_pos.row = -1; return obj; } void ms_obj_delete (GODrawingPropertyTable *obj) { if (obj) { if (obj->gnum_obj) { g_object_unref (obj->gnum_obj); obj->gnum_obj = NULL; } if (obj->attrs) { ms_obj_attr_bag_destroy (obj->attrs); obj->attrs = NULL; } g_free (obj); } } /* S59EOE.HTM */ char * ms_read_TXO (BiffQuery *q) { static char const * const orientations [] = { "Left to right", "Top to Bottom", "Bottom to Top on Side", "Top to Bottom on Side" }; static char const * const haligns [] = { "At left", "Horizontaly centered", "At right", "Horizontaly justified" }; static char const * const valigns [] = { "At top", "Verticaly centered", "At bottom", "Verticaly justified" }; guint16 const options = GSF_LE_GET_GUINT16 (q->data); guint16 const orient = GSF_LE_GET_GUINT16 (q->data + 2); guint16 const text_len = GSF_LE_GET_GUINT16 (q->data + 10); /* guint16 const num_formats = GSF_LE_GET_GUINT16 (q->data + 12);*/ int const halign = (options >> 1) & 0x7; int const valign = (options >> 4) & 0x7; char *text; guint16 peek_op; if (text_len == 0) return NULL; g_return_val_if_fail (orient <= 3, NULL); g_return_val_if_fail (1 <= halign && halign <= 4, NULL); g_return_val_if_fail (1 <= valign && valign <= 4, NULL); if (ms_biff_query_peek_next (q, &peek_op) && peek_op == BIFF_CONTINUE) { ms_biff_query_next (q); if ((int)q->length < text_len) { g_warning ("Broken continue in TXO record"); text = g_strdup ("Broken continue"); } else text = ms_biff_get_chars (q->data + 1, text_len, *(q->data) != 0); if (ms_biff_query_peek_next (q, &peek_op) && peek_op == BIFF_CONTINUE) ms_biff_query_next (q); else g_warning ("Unusual, TXO text with no formatting has 0x%x @ 0x%x", peek_op, q->streamPos); } else { if (text_len > 0) g_warning ("TXO len of %d but no continue", text_len); text = g_strdup (""); } #ifndef NO_DEBUG_EXCEL if (ms_excel_object_debug > 0) { printf ("{ TextObject\n"); printf ("Text '%s'\n", text); printf ("is %s, %s & %s;\n", orientations[orient], haligns[halign], valigns[valign]); printf ("}; /* TextObject */\n"); } #endif return text; } #ifndef NO_DEBUG_EXCEL #define ms_obj_dump(data, len, data_left, name) ms_obj_dump_impl (data, len, data_left, name) static void ms_obj_dump_impl (guint8 const *data, int len, int data_left, char const *name) { if (ms_excel_object_debug < 2) return; printf ("{ %s \n", name); if (len+4 > data_left) { printf ("/* invalid length %d (0x%x) > %d(0x%x)*/\n", len+4, len+4, data_left, data_left); len = data_left - 4; } if (ms_excel_object_debug > 2) gsf_mem_dump (data, len+4); printf ("}; /* %s */\n", name); } #else #define ms_obj_dump (data, len, data_left, name) #endif /* S59DAD.HTM */ static gboolean ms_obj_read_pre_biff8_obj (BiffQuery *q, MSContainer *container, GODrawingPropertyTable *obj) { guint16 peek_op, tmp, len; guint8 const *data; gboolean const has_fmla = GSF_LE_GET_GUINT16 (q->data+26) != 0; /* undocumented */ gboolean const has_name = GSF_LE_GET_GUINT16 (q->data+30) != 0; #if 0 guint16 const flags = GSF_LE_GET_GUINT16(q->data+8); #endif guint8 *anchor = g_malloc (MS_ANCHOR_SIZE); memcpy (anchor, q->data+8, MS_ANCHOR_SIZE); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_ptr (MS_OBJ_ATTR_ANCHOR, anchor)); obj->excel_type = GSF_LE_GET_GUINT16(q->data + 4); obj->id = GSF_LE_GET_GUINT32(q->data + 6); switch (obj->excel_type) { case 0: /* group */ break; case 1: /* line */ tmp = GSF_LE_GET_GUINT8 (q->data+40); if (GSF_LE_GET_GUINT16 (q->data + 10) == 0 && GSF_LE_GET_GUINT16 (q->data + 14) < 20) { g_warning("%hhu", tmp); } if (GSF_LE_GET_GUINT8 (q->data+38) & 0x0F) ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_flag (MS_OBJ_ATTR_ARROW_END)); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_FILL_COLOR, 0x80000000 | GSF_LE_GET_GUINT8 (q->data+34))); if (tmp == 1 || tmp == 2) ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_flag (MS_OBJ_ATTR_FLIP_H)); if (tmp >= 2) ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_flag (MS_OBJ_ATTR_FLIP_V)); break; case 2: /* rectangle */ break; case 3: /* oval */ break; case 4: /* arc */ break; case 5: /* chart */ break; case 6: /* textbox */ /* gsf_mem_dump (q->data+34, q->length - 34); */ if (GSF_LE_GET_GUINT8 (q->data+36) > 0) { ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_flag (MS_OBJ_ATTR_FILLED)); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_FILL_COLOR, 0x80000000 | GSF_LE_GET_GUINT8 (q->data+35))); } ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_FONT_COLOR, 0x80000000 | GSF_LE_GET_GUINT8 (q->data+34))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_OUTLINE_COLOR, 0x80000000 | GSF_LE_GET_GUINT8 (q->data+38))); /* only pull in the text if it exists */ len = GSF_LE_GET_GUINT16 (q->data + 44); if (len > 0) { data = q->data + 70; g_return_val_if_fail ((unsigned)(data - q->data) < q->length, TRUE); g_return_val_if_fail (!has_fmla, TRUE); /* how would this happen */ /* skip the obj name if defined */ if (has_name) { data += *data + ((*data & 0x1) ? 1 : 2); /* padding byte */ g_return_val_if_fail ((unsigned)(data - q->data) < q->length, TRUE); } ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_ptr (MS_OBJ_ATTR_TEXT, g_strndup (data, len))); } break; case 7: /* button */ break; case 8: /* picture */ break; case 9: /* polygon */ ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_FILL_COLOR, 0x80000000 | GSF_LE_GET_GUINT8 (q->data+35))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_OUTLINE_COLOR, 0x80000000 | GSF_LE_GET_GUINT8 (q->data+38))); if (ms_biff_query_peek_next (q, &peek_op) && peek_op == BIFF_COORDLIST) { unsigned i, n; guint tmp; GArray *array; ms_biff_query_next (q); n = q->length / 2; array = g_array_set_size ( g_array_new (FALSE, FALSE, sizeof (double)), n + 2); for (i = 0; i < n ; i++) { tmp = GSF_LE_GET_GUINT16 (q->data + 2*i); g_array_index (array, double, i) = (double)tmp/ 16384.; } g_array_index (array, double, i) = g_array_index (array, double, 0); g_array_index (array, double, i+1) = g_array_index (array, double, 1); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_array (MS_OBJ_ATTR_POLYGON_COORDS, array)); } break; case 0xB : /* check box */ break; case 0xC : /* option button */ break; case 0xD : /* edit box */ break; case 0xE : /* label */ break; case 0xF : /* dialog frame */ break; case 0x10 : /* spinner & scrollbar (layout is the same) */ case 0x11 : ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_VALUE, GSF_LE_GET_GUINT16 (q->data+48))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_MIN, GSF_LE_GET_GUINT16 (q->data+50))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_MAX, GSF_LE_GET_GUINT16 (q->data+52))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_INC, GSF_LE_GET_GUINT16 (q->data+54))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_PAGE, GSF_LE_GET_GUINT16 (q->data+56))); { GnmExpr const *ref; guint16 len; guint8 const *last = q->data + q->length; guint8 const *ptr = q->data + 64; ptr += 1 + *ptr; /* object name */ if ((ptr - q->data) & 1) ptr++; /* align on word */ if (ptr >= last) break; ptr += 2 + GSF_LE_GET_GUINT16 (ptr); /* the macro */ if ((ptr - q->data) & 1) ptr++; /* align on word */ if (ptr >= last) break; len = GSF_LE_GET_GUINT16 (ptr+2); /* the assigned macro */ ref = ms_container_parse_expr (container, ptr + 8, len); if (ref != NULL) ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_expr (MS_OBJ_ATTR_LINKED_TO_CELL, ref)); } break; case 0x12 : /* list box */ break; case 0x13 : /* group box */ break; case 0x14 : /* drop down */ obj->combo_in_autofilter = (GSF_LE_GET_GUINT16 (q->data + 8) & 0x8000) ? TRUE : FALSE; break; default : ; } return FALSE; } /* S59DAD.HTM */ static gboolean ms_obj_read_biff8_obj (BiffQuery *q, MSContainer *container, GODrawingPropertyTable *obj) { guint8 *data; gint32 data_len_left; gboolean hit_end = FALSE; gboolean next_biff_record_maybe_imdata = FALSE; g_return_val_if_fail (q, TRUE); g_return_val_if_fail (q->ls_op == BIFF_OBJ, TRUE); data = q->data; data_len_left = q->length; #if 0 ms_biff_query_dump (q); #endif /* Scan through the pseudo BIFF substream */ while (data_len_left > 0 && !hit_end) { guint16 const record_type = GSF_LE_GET_GUINT16(data); /* All the sub-records seem to have this layout * 2001/Mar/29 JEG : liars. Ok not all records have this * layout. Create a list box. It seems to do something * unique. It acts like an end, and has no length specified. */ guint16 len = GSF_LE_GET_GUINT16(data+2); /* 1st record must be COMMON_OBJ*/ g_return_val_if_fail (obj->excel_type >= 0 || record_type == GR_COMMON_OBJ_DATA, TRUE); switch (record_type) { case GR_END: g_return_val_if_fail (len == 0, TRUE); /* ms_obj_dump (data, len, data_len_left, "ObjEnd"); */ hit_end = TRUE; break; case GR_MACRO : ms_obj_dump (data, len, data_len_left, "MacroObject"); break; case GR_COMMAND_BUTTON : ms_obj_dump (data, len, data_len_left, "CommandButton"); break; case GR_GROUP : ms_obj_dump (data, len, data_len_left, "Group"); break; case GR_CLIPBOARD_FORMAT : ms_obj_dump (data, len, data_len_left, "ClipboardFmt"); break; case GR_PICTURE_OPTIONS : if (len == 2) { guint16 opt = GSF_LE_GET_GUINT16 (data + 4); obj->is_linked = (opt & 0x2) ? TRUE : FALSE; #ifndef NO_DEBUG_EXCEL if (ms_excel_object_debug >= 1) { printf ("{ /* PictOpt */\n"); printf ("value = %x;\n", opt); printf ("}; /* PictOpt */\n"); } #endif } else { /* no docs on this so be careful */ g_warning ("PictOpt record with size other than 2"); } next_biff_record_maybe_imdata = TRUE; break; case GR_PICTURE_FORMULA : ms_obj_dump (data, len, data_len_left, "PictFormula"); break; case GR_CHECKBOX_LINK : ms_obj_dump (data, len, data_len_left, "CheckboxLink"); break; case GR_RADIO_BUTTON : ms_obj_dump (data, len, data_len_left, "RadioButton"); break; case GR_SCROLLBAR : ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_VALUE, GSF_LE_GET_GUINT16 (data+8))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_MIN, GSF_LE_GET_GUINT16 (data+10))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_MAX, GSF_LE_GET_GUINT16 (data+12))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_INC, GSF_LE_GET_GUINT16 (data+14))); ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_PAGE, GSF_LE_GET_GUINT16 (data+16))); ms_obj_dump (data, len, data_len_left, "ScrollBar"); break; case GR_NOTE_STRUCTURE : ms_obj_dump (data, len, data_len_left, "Note"); break; case GR_SCROLLBAR_FORMULA : { guint16 const expr_len = GSF_LE_GET_GUINT16 (data+4); GnmExpr const *ref = ms_container_parse_expr (container, data+10, expr_len); if (ref != NULL) ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_expr (MS_OBJ_ATTR_LINKED_TO_CELL, ref)); ms_obj_dump (data, len, data_len_left, "ScrollbarFmla"); break; } case GR_GROUP_BOX_DATA : ms_obj_dump (data, len, data_len_left, "GroupBoxData"); break; case GR_EDIT_CONTROL_DATA : ms_obj_dump (data, len, data_len_left, "EditCtrlData"); break; case GR_RADIO_BUTTON_DATA : ms_obj_dump (data, len, data_len_left, "RadioData"); break; case GR_CHECKBOX_DATA : ms_obj_dump (data, len, data_len_left, "CheckBoxData"); break; case GR_LISTBOX_DATA : { /* FIXME : find some docs for this * It seems as if list box data does not conform to * the docs. It acts like an end and has no size. */ hit_end = TRUE; len = data_len_left - 4; ms_obj_dump (data, len, data_len_left, "ListBoxData"); break; } case GR_CHECKBOX_FORMULA : { guint16 const expr_len = GSF_LE_GET_GUINT16 (data+4); GnmExpr const *ref = ms_container_parse_expr (container, data+10, expr_len); if (ref != NULL) ms_obj_attr_bag_insert (obj->attrs, ms_obj_attr_new_expr (MS_OBJ_ATTR_LINKED_TO_CELL, ref)); ms_obj_dump (data, len, data_len_left, "CheckBoxFmla"); break; } case GR_COMMON_OBJ_DATA : { guint16 const options =GSF_LE_GET_GUINT16 (data+8); /* Multiple objects in 1 record ?? */ g_return_val_if_fail (obj->excel_type == -1, TRUE); obj->excel_type = GSF_LE_GET_GUINT16(data+4); obj->id = GSF_LE_GET_GUINT16(data+6); /* Undocumented. It appears that combos for filters are marked * with flag 0x100 */ obj->combo_in_autofilter = (obj->excel_type == 0x14) && (options & 0x100); #ifndef NO_DEBUG_EXCEL /* only print when debug is enabled */ if (ms_excel_object_debug == 0) break; printf ("OBJECT TYPE = %d\n", obj->excel_type); if (options&0x0001) printf ("Locked;\n"); if (options&0x0010) printf ("Printable;\n"); if (options&0x2000) printf ("AutoFilled;\n"); if (options&0x4000) printf ("AutoLines;\n"); if (ms_excel_object_debug > 4) { /* According to the docs this should not fail * but there appears to be a flag at 0x200 for * scrollbars and 0x100 for combos * associated with filters. */ if ((options & 0x9fee) != 0) printf ("WARNING : Why is option not 0 (%x)\n", options & 0x9fee); } #endif } break; default: printf ("ERROR : Unknown Obj record 0x%x len 0x%x dll %d;\n", record_type, len, data_len_left); } if (data_len_left < len+4) printf ("record len %d (0x%x) > %d\n", len+4, len+4, data_len_left); /* FIXME : We need a structure akin to the escher code to do this properly */ for (data_len_left -= len+4; data_len_left < 0; ) { guint16 peek_op; printf ("deficit of %d\n", data_len_left); /* FIXME : what do we expect here ?? * I've seen what seem to be embedded drawings * but I am not sure what is embedding what. */ if (!ms_biff_query_peek_next (q, &peek_op) || (peek_op != BIFF_CONTINUE && peek_op != BIFF_MS_O_DRAWING && peek_op != BIFF_TXO && peek_op != BIFF_OBJ)) { printf ("0x%x vs 0x%x\n", q->opcode, peek_op); return TRUE; } ms_biff_query_next (q); data_len_left += q->length; printf ("merged in 0x%x with len %d\n", q->opcode, q->length); } data = q->data + q->length - data_len_left; } /* The ftEnd record should have been the last */ if (data_len_left > 0) { printf("OBJ : unexpected extra data after Object End record;\n"); gsf_mem_dump (data, data_len_left); return TRUE; } /* Catch underflow too */ g_return_val_if_fail (data_len_left == 0, TRUE); /* FIXME : Throw away the IMDATA that may follow. * I am not sure when the IMDATA does follow, or how to display it, * but very careful in case it is not there. */ if (next_biff_record_maybe_imdata) { guint16 op; if (ms_biff_query_peek_next (q, &op) && op == BIFF_IMDATA) { printf ("Reading trailing IMDATA;\n"); ms_biff_query_next (q); excel_read_IMDATA (q, FALSE); } } return FALSE; } /** * ms_read_OBJ : * @q : The biff record to start with. * @container : The object's container * @attrs : an OPTIONAL hash of object attributes. */ void ms_read_OBJ (BiffQuery *q, MSContainer *container, GODrawingPropertyTableAttrBag *attrs) { static char const * const object_type_names[] = { "Group", /* 0x00 */ "Line", /* 0x01 */ "Rectangle", /* 0x02 */ "Oval", /* 0x03 */ "Arc", /* 0x04 */ "Chart", /* 0x05 */ "TextBox", /* 0x06 */ "Button", /* 0x07 */ "Picture", /* 0x08 */ "Polygon", /* 0x09 */ NULL, /* 0x0A */ "CheckBox", /* 0x0B */ "Option", /* 0x0C */ "Edit", /* 0x0D */ "Label", /* 0x0E */ "Dialog", /* 0x0F */ "Spinner", /* 0x10 */ "Scroll", /* 0x11 */ "List", /* 0x12 */ "Group", /* 0x13 */ "Combo", /* 0x14 */ NULL, NULL, NULL, NULL, /* 0x15 - 0x18 */ "Comment", /* 0x19 */ NULL, NULL, NULL, NULL, /* 0x1A - 0x1D */ "MS Drawing" /* 0x1E */ }; gboolean errors; GODrawingPropertyTable *obj = ms_obj_new (attrs); #ifndef NO_DEBUG_EXCEL if (ms_excel_object_debug > 0) printf ("{ /* OBJ start */\n"); #endif errors = (container->ver >= MS_BIFF_V8) ? ms_obj_read_biff8_obj (q, container, obj) : ms_obj_read_pre_biff8_obj (q, container, obj); if (errors) { #ifndef NO_DEBUG_EXCEL if (ms_excel_object_debug > 0) printf ("}; /* OBJ error 1 */\n"); #endif ms_obj_delete (obj); return; } obj->excel_type_name = NULL; if (obj->excel_type < (int)G_N_ELEMENTS (object_type_names)) obj->excel_type_name = object_type_names [obj->excel_type]; if (obj->excel_type_name == NULL) obj->excel_type_name = "Unknown"; #ifndef NO_DEBUG_EXCEL if (ms_excel_object_debug > 0) { printf ("Object (%d) is a '%s'\n", obj->id, obj->excel_type_name); printf ("}; /* OBJ end */\n"); } #endif if (container->vtbl->create_obj != NULL) obj->gnum_obj = (*container->vtbl->create_obj) (container, obj); /* Chart, There should be a BOF next */ if (obj->excel_type == 0x5 && ms_excel_chart_read_BOF (q, container, obj->gnum_obj)) { ms_obj_delete (obj); return; } #if 0 g_warning ("registered obj %d\n", obj->id); #endif ms_container_add_obj (container, obj); } #endif