4 * ms-obj.c: MS Excel Object support for Gnumeric
7 * Jody Goldberg (jody@gnome.org)
8 * Michael Meeks (michael@ximian.com)
10 * (C) 1998-2001 Michael Meeks
11 * (C) 2002-2005 Jody Goldberg
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
29 #include <gnumeric-config.h>
36 #include "ms-escher.h"
37 #include "ms-excel-util.h"
38 #include "ms-formula-write.h"
41 #include <parse-util.h>
42 #include <sheet-object-widget.h>
44 #include <gsf/gsf-utils.h>
49 #define GR_COMMAND_BUTTON 0x05
51 #define GR_CLIPBOARD_FORMAT 0x07
52 #define GR_PICTURE_OPTIONS 0x08
53 #define GR_PICTURE_FORMULA 0x09
54 #define GR_CHECKBOX_LINK 0x0A
55 #define GR_RADIO_BUTTON 0x0B
56 #define GR_SCROLLBAR 0x0C
57 #define GR_NOTE_STRUCTURE 0x0D
58 #define GR_SCROLLBAR_FORMULA 0x0E
59 #define GR_GROUP_BOX_DATA 0x0F
60 #define GR_EDIT_CONTROL_DATA 0x10
61 #define GR_RADIO_BUTTON_DATA 0x11
62 #define GR_CHECKBOX_DATA 0x12
63 #define GR_LISTBOX_DATA 0x13
64 #define GR_CHECKBOX_FORMULA 0x14
65 #define GR_COMMON_OBJ_DATA 0x15
68 ms_obj_attr_new_flag (MSObjAttrID id
)
70 MSObjAttr
*res
= g_new (MSObjAttr
, 1);
72 g_return_val_if_fail ((id
& MS_OBJ_ATTR_MASK
) == 0, NULL
);
74 /* be anal about constness */
75 *((MSObjAttrID
*)&(res
->id
)) = id
;
81 ms_obj_attr_new_uint (MSObjAttrID id
, guint32 val
)
83 MSObjAttr
*res
= g_new (MSObjAttr
, 1);
85 g_return_val_if_fail ((id
& MS_OBJ_ATTR_MASK
) == MS_OBJ_ATTR_IS_INT_MASK
, NULL
);
87 /* be anal about constness */
88 *((MSObjAttrID
*)&(res
->id
)) = id
;
93 ms_obj_attr_new_ptr (MSObjAttrID id
, gpointer val
)
95 MSObjAttr
*res
= g_new (MSObjAttr
, 1);
97 g_return_val_if_fail ((id
& MS_OBJ_ATTR_MASK
) == MS_OBJ_ATTR_IS_PTR_MASK
, NULL
);
99 /* be anal about constness */
100 *((MSObjAttrID
*)&(res
->id
)) = id
;
106 ms_obj_attr_new_array (MSObjAttrID id
, GArray
*array
)
108 MSObjAttr
*res
= g_new (MSObjAttr
, 1);
110 g_return_val_if_fail ((id
& MS_OBJ_ATTR_MASK
) == MS_OBJ_ATTR_IS_GARRAY_MASK
, NULL
);
112 /* be anal about constness */
113 *((MSObjAttrID
*)&(res
->id
)) = id
;
114 res
->v
.v_array
= array
;
119 ms_obj_attr_new_expr (MSObjAttrID id
, GnmExprTop
const *texpr
)
121 MSObjAttr
*res
= g_new (MSObjAttr
, 1);
123 g_return_val_if_fail ((id
& MS_OBJ_ATTR_MASK
) == MS_OBJ_ATTR_IS_EXPR_MASK
, NULL
);
125 /* be anal about constness */
126 *((MSObjAttrID
*)&(res
->id
)) = id
;
127 res
->v
.v_texpr
= texpr
;
132 ms_obj_attr_new_markup (MSObjAttrID id
, PangoAttrList
*markup
)
134 MSObjAttr
*res
= g_new (MSObjAttr
, 1);
136 g_return_val_if_fail ((id
& MS_OBJ_ATTR_MASK
) == MS_OBJ_ATTR_IS_PANGO_ATTR_LIST_MASK
, NULL
);
138 /* be anal about constness */
139 *((MSObjAttrID
*)&(res
->id
)) = id
;
140 res
->v
.v_markup
= markup
;
141 pango_attr_list_ref (markup
);
146 ms_obj_attr_new_gobject (MSObjAttrID id
, GObject
*object
)
148 MSObjAttr
*res
= g_new (MSObjAttr
, 1);
150 g_return_val_if_fail ((id
& MS_OBJ_ATTR_MASK
) == MS_OBJ_ATTR_IS_GOBJECT_MASK
, NULL
);
152 *((MSObjAttrID
*)&(res
->id
)) = id
;
153 res
->v
.v_object
= object
;
154 g_object_ref (object
);
159 ms_obj_attr_get_uint (MSObjAttrBag
*attrs
, MSObjAttrID id
, guint32 default_value
)
163 g_return_val_if_fail (attrs
!= NULL
, default_value
);
164 g_return_val_if_fail (id
& MS_OBJ_ATTR_IS_INT_MASK
, default_value
);
166 attr
= ms_obj_attr_bag_lookup (attrs
, id
);
168 return default_value
;
169 return attr
->v
.v_uint
;
173 ms_obj_attr_get_int (MSObjAttrBag
*attrs
, MSObjAttrID id
, gint32 default_value
)
177 g_return_val_if_fail (attrs
!= NULL
, default_value
);
178 g_return_val_if_fail (id
& MS_OBJ_ATTR_IS_INT_MASK
, default_value
);
180 attr
= ms_obj_attr_bag_lookup (attrs
, id
);
182 return default_value
;
183 return attr
->v
.v_int
;
187 ms_obj_attr_get_ptr (MSObjAttrBag
*attrs
, MSObjAttrID id
,
188 gpointer
*res
, gboolean steal
)
192 g_return_val_if_fail (attrs
!= NULL
, FALSE
);
193 g_return_val_if_fail (id
& MS_OBJ_ATTR_IS_PTR_MASK
, FALSE
);
195 if (NULL
== (attr
= ms_obj_attr_bag_lookup (attrs
, id
)))
198 *res
= attr
->v
.v_ptr
;
200 attr
->v
.v_ptr
= NULL
;
206 ms_obj_attr_get_array (MSObjAttrBag
*attrs
, MSObjAttrID id
,
207 GArray
*default_value
, gboolean steal
)
212 g_return_val_if_fail (attrs
!= NULL
, default_value
);
213 g_return_val_if_fail (id
& MS_OBJ_ATTR_IS_GARRAY_MASK
, default_value
);
215 attr
= ms_obj_attr_bag_lookup (attrs
, id
);
217 return default_value
;
218 res
= attr
->v
.v_array
;
220 attr
->v
.v_array
= NULL
;
225 ms_obj_attr_get_expr (MSObjAttrBag
*attrs
, MSObjAttrID id
,
226 GnmExprTop
const *default_value
, gboolean steal
)
229 GnmExprTop
const *res
;
231 g_return_val_if_fail (attrs
!= NULL
, default_value
);
232 g_return_val_if_fail (id
& MS_OBJ_ATTR_IS_EXPR_MASK
, default_value
);
234 attr
= ms_obj_attr_bag_lookup (attrs
, id
);
236 return default_value
;
237 res
= attr
->v
.v_texpr
;
239 attr
->v
.v_texpr
= NULL
;
244 ms_obj_attr_get_markup (MSObjAttrBag
*attrs
, MSObjAttrID id
,
245 PangoAttrList
*default_value
, gboolean steal
)
250 g_return_val_if_fail (attrs
!= NULL
, default_value
);
251 g_return_val_if_fail (id
& MS_OBJ_ATTR_IS_PANGO_ATTR_LIST_MASK
, default_value
);
253 attr
= ms_obj_attr_bag_lookup (attrs
, id
);
255 return default_value
;
256 res
= attr
->v
.v_markup
;
258 attr
->v
.v_markup
= NULL
;
263 ms_obj_attr_get_gobject (MSObjAttrBag
*attrs
, MSObjAttrID id
)
267 g_return_val_if_fail (attrs
!= NULL
, NULL
);
268 g_return_val_if_fail (id
& MS_OBJ_ATTR_IS_GOBJECT_MASK
, NULL
);
270 attr
= ms_obj_attr_bag_lookup (attrs
, id
);
273 return attr
->v
.v_object
;
277 ms_obj_attr_destroy (MSObjAttr
*attr
)
280 if ((attr
->id
& MS_OBJ_ATTR_IS_PTR_MASK
) &&
281 attr
->v
.v_ptr
!= NULL
) {
282 g_free (attr
->v
.v_ptr
);
283 attr
->v
.v_ptr
= NULL
;
284 } else if ((attr
->id
& MS_OBJ_ATTR_IS_GARRAY_MASK
) &&
285 attr
->v
.v_array
!= NULL
) {
286 g_array_free (attr
->v
.v_array
, TRUE
);
287 attr
->v
.v_array
= NULL
;
288 } else if ((attr
->id
& MS_OBJ_ATTR_IS_EXPR_MASK
) &&
289 attr
->v
.v_texpr
!= NULL
) {
290 gnm_expr_top_unref (attr
->v
.v_texpr
);
291 attr
->v
.v_texpr
= NULL
;
292 } else if ((attr
->id
& MS_OBJ_ATTR_IS_PANGO_ATTR_LIST_MASK
) &&
293 attr
->v
.v_markup
!= NULL
) {
294 pango_attr_list_unref (attr
->v
.v_markup
);
295 attr
->v
.v_markup
= NULL
;
296 } else if ((attr
->id
& MS_OBJ_ATTR_IS_GOBJECT_MASK
) &&
297 attr
->v
.v_object
!= NULL
) {
298 g_object_unref (attr
->v
.v_object
);
299 attr
->v
.v_object
= NULL
;
306 cb_ms_obj_attr_hash (gconstpointer key
)
308 return ((MSObjAttr
const *)key
)->id
;
312 cb_ms_obj_attr_cmp (gconstpointer a
, gconstpointer b
)
314 return ((MSObjAttr
const *)a
)->id
== ((MSObjAttr
const *)b
)->id
;
318 ms_obj_attr_bag_new (void)
320 return g_hash_table_new (cb_ms_obj_attr_hash
, cb_ms_obj_attr_cmp
);
324 cb_ms_obj_attr_destroy (gpointer key
, gpointer value
, gpointer ignored
)
326 ms_obj_attr_destroy (value
);
329 ms_obj_attr_bag_destroy (MSObjAttrBag
*attrs
)
332 g_hash_table_foreach (attrs
, cb_ms_obj_attr_destroy
, NULL
);
333 g_hash_table_destroy (attrs
);
339 ms_obj_attr_bag_insert (MSObjAttrBag
*attrs
, MSObjAttr
*attr
)
341 g_return_if_fail (!g_hash_table_lookup (attrs
, attr
));
342 g_hash_table_insert (attrs
, attr
, attr
);
346 ms_obj_attr_bag_lookup (MSObjAttrBag
*attrs
, MSObjAttrID id
)
349 MSObjAttr attr
= {0, {0}};
350 *((MSObjAttrID
*)&(attr
.id
)) = id
;
351 return g_hash_table_lookup (attrs
, &attr
);
356 /********************************************************************************/
359 ms_obj_new (MSObjAttrBag
*attrs
)
361 MSObj
*obj
= g_new0 (MSObj
, 1);
363 obj
->excel_type
= (unsigned)-1; /* Set to undefined */
364 obj
->excel_type_name
= NULL
;
366 obj
->gnum_obj
= NULL
;
367 obj
->attrs
= (attrs
!= NULL
) ? attrs
: ms_obj_attr_bag_new ();
368 obj
->auto_combo
= FALSE
;
369 obj
->is_linked
= FALSE
;
370 obj
->comment_pos
.col
= obj
->comment_pos
.row
= -1;
376 ms_obj_delete (MSObj
*obj
)
380 g_object_unref (obj
->gnum_obj
);
381 obj
->gnum_obj
= NULL
;
384 ms_obj_attr_bag_destroy (obj
->attrs
);
392 ms_read_TXO (BiffQuery
*q
, MSContainer
*c
, PangoAttrList
**markup
)
394 static char const * const orientations
[] = {
397 "Bottom to Top on Side",
398 "Top to Bottom on Side"
400 static char const * const haligns
[] = {
401 "At left", "Horizontally centered",
402 "At right", "Horizontally justified"
404 static char const * const valigns
[] = {
405 "At top", "Vertically centered",
406 "At bottom", "Vertically justified"
409 guint16 options
, orient
, text_len
;
414 gboolean continue_seen
= FALSE
;
418 XL_CHECK_CONDITION_VAL (q
->length
>= 14, g_strdup (""));
420 options
= GSF_LE_GET_GUINT16 (q
->data
);
421 orient
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
422 text_len
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
423 /* guint16 const num_formats = GSF_LE_GET_GUINT16 (q->data + 12);*/
424 halign
= (options
>> 1) & 0x7;
425 valign
= (options
>> 4) & 0x7;
430 accum
= g_string_new ("");
431 while (ms_biff_query_peek_next (q
, &op
) && op
== BIFF_CONTINUE
) {
435 continue_seen
= TRUE
;
436 ms_biff_query_next (q
);
440 use_utf16
= q
->data
[0] != 0;
441 maxlen
= (q
->length
- 1) / (use_utf16
? 2 : 1);
442 text
= excel_get_chars (c
->importer
,
443 q
->data
+ 1, MIN (text_len
, maxlen
), use_utf16
, NULL
);
444 g_string_append (accum
, text
);
446 if (text_len
<= maxlen
)
450 text
= g_string_free (accum
, FALSE
);
452 if (ms_biff_query_peek_next (q
, &op
) && op
== BIFF_CONTINUE
) {
453 ms_biff_query_next (q
);
454 *markup
= ms_container_read_markup (c
, q
->data
, q
->length
,
457 g_warning ("Unusual, TXO text with no formatting has 0x%x @ 0x%lx",
458 op
, (long)q
->streamPos
);
461 g_warning ("TXO len of %d but no continue", text_len
);
464 #ifndef NO_DEBUG_EXCEL
465 if (ms_excel_object_debug
> 0) {
466 char const *o_msg
= (orient
<= 3) ? orientations
[orient
] : "unknown orientation";
467 char const *h_msg
= (1 <= halign
&& halign
<= 4) ? haligns
[halign
-1] : "unknown h-align";
468 char const *v_msg
= (1 <= valign
&& valign
<= 4) ? valigns
[valign
-1] : "unknown v-align";
470 g_printerr ("{ TextObject\n");
471 g_printerr ("Text '%s'\n", text
);
472 g_printerr ("is %s(%d), %s(%d) & %s(%d);\n",
473 o_msg
, orient
, h_msg
, halign
, v_msg
, valign
);
474 g_printerr ("}; /* TextObject */\n");
480 #ifndef NO_DEBUG_EXCEL
482 ms_obj_dump (guint8
const *data
, int len
, int data_left
, char const *name
)
484 if (ms_excel_object_debug
< 2)
487 g_printerr ("{ %s \n", name
);
488 if (len
+4 > data_left
) {
489 g_printerr ("/* invalid length %d (0x%x) > %d(0x%x)*/\n",
490 len
+4, len
+4, data_left
, data_left
);
493 if (ms_excel_object_debug
> 2)
494 gsf_mem_dump (data
, len
+4);
495 g_printerr ("}; /* %s */\n", name
);
498 #define ms_obj_dump (data, len, data_left, name) do { } while (0)
501 static guint8
const *
502 ms_obj_read_expr (MSObj
*obj
, MSObjAttrID id
, MSContainer
*c
,
503 guint8
const *data
, guint8
const *last
)
506 GnmExprTop
const *ref
;
508 if (ms_excel_object_debug
> 2)
509 gsf_mem_dump (data
, last
-data
);
511 /* <u16 length> <u32 calcid?> <var expr> */
512 g_return_val_if_fail ((data
+ 2) <= last
, NULL
);
513 len
= GSF_LE_GET_GUINT16 (data
);
515 /* looks like they sometimes skip the calc id if there is expr */
516 if (len
== 0 && (data
+ 2) == last
)
519 g_return_val_if_fail ((data
+ 6 + len
) <= last
, NULL
);
520 if (NULL
== (ref
= ms_container_parse_expr (c
, data
+ 6, len
)))
522 ms_obj_attr_bag_insert (obj
->attrs
,
523 ms_obj_attr_new_expr (id
, ref
));
524 return data
+ 6 + len
;
529 read_pre_biff8_read_text (BiffQuery
*q
, MSContainer
*c
, MSObj
*obj
,
531 unsigned len
, unsigned txo_len
)
533 PangoAttrList
*markup
= NULL
;
534 GByteArray
*markup_data
= NULL
;
542 remaining
= q
->data
+ q
->length
- first
;
544 /* CONTINUE handling here is very odd.
545 * If the text needs CONTINUEs but the markup does not, the markup is
546 * stored at the end of the OBJ rather than after the text. */
547 if (txo_len
> 0 && txo_len
< remaining
) {
548 markup_data
= g_byte_array_new ();
549 g_byte_array_append (markup_data
, q
->data
+ q
->length
- txo_len
, txo_len
);
550 remaining
-= txo_len
;
553 str
= excel_get_chars (c
->importer
, first
, MIN (remaining
, len
), FALSE
, NULL
);
554 if (len
> remaining
) {
555 GString
*accum
= g_string_new (str
);
558 while (ms_biff_query_peek_next (q
, &op
) && op
== BIFF_CONTINUE
) {
559 ms_biff_query_next (q
);
560 str
= excel_get_chars (c
->importer
, q
->data
,
561 MIN (q
->length
, len
), FALSE
, NULL
);
562 g_string_append (accum
, str
);
568 str
= g_string_free (accum
, FALSE
);
569 if (len
> q
->length
) {
573 first
= q
->data
+ len
;
576 if (((first
- q
->data
) & 1))
577 first
++; /* pad to word bound */
579 ms_obj_attr_bag_insert (obj
->attrs
,
580 ms_obj_attr_new_ptr (MS_OBJ_ATTR_TEXT
, str
));
582 if (NULL
!= markup_data
) {
583 markup
= ms_container_read_markup (c
, markup_data
->data
, markup_data
->len
,
585 g_byte_array_free (markup_data
, TRUE
);
586 } else if (txo_len
> 0) {
587 remaining
= q
->data
+ q
->length
- first
;
588 if (txo_len
> remaining
) {
589 GByteArray
*accum
= g_byte_array_new ();
590 g_byte_array_append (accum
, first
, remaining
);
591 txo_len
-= remaining
;
592 while (ms_biff_query_peek_next (q
, &op
) && op
== BIFF_CONTINUE
) {
593 ms_biff_query_next (q
);
594 g_byte_array_append (accum
, q
->data
, MIN (q
->length
, txo_len
));
595 if (txo_len
<= q
->length
)
597 txo_len
-= q
->length
;
599 first
= q
->data
+ txo_len
;
600 markup
= ms_container_read_markup (c
, accum
->data
, accum
->len
,
602 g_byte_array_free (accum
, TRUE
);
604 markup
= ms_container_read_markup (c
, first
, txo_len
,
609 if (NULL
!= markup
) {
610 ms_obj_attr_bag_insert (obj
->attrs
,
611 ms_obj_attr_new_markup (MS_OBJ_ATTR_MARKUP
, markup
));
612 pango_attr_list_unref (markup
);
618 static guint8
const *
619 read_pre_biff8_read_expr (BiffQuery
*q
, MSContainer
*c
, MSObj
*obj
,
620 guint8
const *data
, unsigned total_len
) /* including extras */
624 XL_CHECK_CONDITION_VAL (total_len
<= q
->length
- (data
- q
->data
), data
);
626 ms_obj_read_expr (obj
, MS_OBJ_ATTR_LINKED_TO_CELL
, c
,
627 data
, data
+ total_len
);
628 data
+= total_len
; /* use total_len not the stated expression len */
629 if (((data
- q
->data
) & 1) && data
< q
->data
+ q
->length
)
630 data
++; /* pad to word bound */
634 static guint8
const *
635 read_pre_biff8_read_name_and_fmla (BiffQuery
*q
, MSContainer
*c
, MSObj
*obj
,
636 gboolean has_name
, unsigned offset
)
641 XL_CHECK_CONDITION_VAL (q
->length
>= 28, NULL
);
642 fmla_len
= GSF_LE_GET_GUINT16 (q
->data
+26);
643 XL_CHECK_CONDITION_VAL (q
->length
>= offset
+ 2 + fmla_len
, NULL
);
645 data
= q
->data
+ offset
;
648 guint8
const *last
= q
->data
+ q
->length
;
649 unsigned len
= *data
++;
652 g_return_val_if_fail (last
- data
>= len
, NULL
);
654 str
= excel_get_chars (c
->importer
, data
, len
, FALSE
, NULL
);
656 if (((data
- q
->data
) & 1) && data
< last
)
657 data
++; /* pad to word bound */
659 ms_obj_attr_bag_insert (obj
->attrs
,
660 ms_obj_attr_new_ptr (MS_OBJ_ATTR_OBJ_NAME
, str
));
662 return read_pre_biff8_read_expr (q
, c
, obj
, data
, fmla_len
);
666 ms_obj_read_pre_biff8_obj (BiffQuery
*q
, MSContainer
*c
, MSObj
*obj
)
668 guint8
const *last
= q
->data
+ q
->length
;
669 guint16 peek_op
, tmp
, len
;
670 unsigned txo_len
, if_empty
;
675 XL_CHECK_CONDITION_VAL (q
->length
>= 26, TRUE
);
677 has_name
= (q
->length
>= 32 &&
678 GSF_LE_GET_GUINT16 (q
->data
+30) != 0); /* undocumented */
680 guint16
const flags
= GSF_LE_GET_GUINT16(q
->data
+8);
682 anchor
= g_malloc (MS_ANCHOR_SIZE
);
683 memcpy (anchor
, q
->data
+8, MS_ANCHOR_SIZE
);
684 ms_obj_attr_bag_insert (obj
->attrs
,
685 ms_obj_attr_new_ptr (MS_OBJ_ATTR_ANCHOR
, anchor
));
687 obj
->excel_type
= GSF_LE_GET_GUINT16(q
->data
+ 4);
688 obj
->id
= GSF_LE_GET_GUINT32(q
->data
+ 6);
690 switch (obj
->excel_type
) {
694 XL_CHECK_CONDITION_VAL (q
->data
+ 41 <= last
, TRUE
);
695 tmp
= GSF_LE_GET_GUINT8 (q
->data
+38) & 0x0F;
697 ms_obj_attr_bag_insert (obj
->attrs
,
698 ms_obj_attr_new_uint (MS_OBJ_ATTR_ARROW_END
, tmp
));
699 ms_obj_attr_bag_insert (obj
->attrs
,
700 ms_obj_attr_new_uint (MS_OBJ_ATTR_OUTLINE_COLOR
,
701 0x80000000 | GSF_LE_GET_GUINT8 (q
->data
+34)));
702 tmp
= GSF_LE_GET_GUINT8 (q
->data
+35);
703 ms_obj_attr_bag_insert (obj
->attrs
,
704 ms_obj_attr_new_uint (MS_OBJ_ATTR_OUTLINE_STYLE
,
705 ((tmp
== 0xff) ? 0 : tmp
+1)));
707 tmp
= GSF_LE_GET_GUINT8 (q
->data
+40);
708 if (tmp
== 1 || tmp
== 2)
709 ms_obj_attr_bag_insert (obj
->attrs
,
710 ms_obj_attr_new_flag (MS_OBJ_ATTR_FLIP_H
));
712 ms_obj_attr_bag_insert (obj
->attrs
,
713 ms_obj_attr_new_flag (MS_OBJ_ATTR_FLIP_V
));
714 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
,
715 (obj
->excel_type
== MSOT_LINE
) ? 42 : 44);
722 XL_CHECK_CONDITION_VAL (q
->data
+ 36 <= last
, TRUE
);
723 ms_obj_attr_bag_insert (obj
->attrs
,
724 ms_obj_attr_new_uint (MS_OBJ_ATTR_FILL_BACKGROUND
,
725 0x80000000 | GSF_LE_GET_GUINT8 (q
->data
+34)));
726 ms_obj_attr_bag_insert (obj
->attrs
,
727 ms_obj_attr_new_uint (MS_OBJ_ATTR_FILL_COLOR
,
728 0x80000000 | GSF_LE_GET_GUINT8 (q
->data
+35)));
729 if (GSF_LE_GET_GUINT8 (q
->data
+36) == 0)
730 ms_obj_attr_bag_insert (obj
->attrs
,
731 ms_obj_attr_new_flag (MS_OBJ_ATTR_UNFILLED
));
733 tmp
= GSF_LE_GET_GUINT8 (q
->data
+39);
734 ms_obj_attr_bag_insert (obj
->attrs
,
735 ms_obj_attr_new_uint (MS_OBJ_ATTR_OUTLINE_STYLE
,
736 ((tmp
== 0xff) ? 0 : tmp
+1)));
737 ms_obj_attr_bag_insert (obj
->attrs
,
738 ms_obj_attr_new_uint (MS_OBJ_ATTR_OUTLINE_COLOR
,
739 0x80000000 | GSF_LE_GET_GUINT8 (q
->data
+38)));
740 ms_obj_attr_bag_insert (obj
->attrs
,
741 ms_obj_attr_new_uint (MS_OBJ_ATTR_OUTLINE_WIDTH
,
742 GSF_LE_GET_GUINT8 (q
->data
+40) * 256));
744 if (obj
->excel_type
== MSOT_TEXTBOX
) {
745 g_return_val_if_fail (q
->data
+ 52 <= last
, TRUE
);
746 len
= GSF_LE_GET_GUINT16 (q
->data
+ 44);
747 txo_len
= GSF_LE_GET_GUINT16 (q
->data
+ 48);
748 if_empty
= GSF_LE_GET_GUINT16 (q
->data
+ 50);
750 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 70);
751 if (read_pre_biff8_read_text (q
, c
, obj
, data
, len
, txo_len
))
754 ms_obj_attr_bag_insert (obj
->attrs
,
755 ms_obj_attr_new_markup (MS_OBJ_ATTR_MARKUP
,
756 ms_container_get_markup (c
, if_empty
)));
758 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 44);
762 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 62);
766 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 70);
769 /* 50 uint16 cbPictFmla, 60 name len, name, fmla (respect cbMacro), fmla (cbPictFmla) */
770 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 60);
774 /* 66 name len, name, fmla (respect cbMacro) */
775 ms_obj_attr_bag_insert (obj
->attrs
,
776 ms_obj_attr_new_uint (MS_OBJ_ATTR_FILL_COLOR
,
777 0x80000000 | GSF_LE_GET_GUINT8 (q
->data
+35)));
778 ms_obj_attr_bag_insert (obj
->attrs
,
779 ms_obj_attr_new_uint (MS_OBJ_ATTR_OUTLINE_COLOR
,
780 0x80000000 | GSF_LE_GET_GUINT8 (q
->data
+38)));
782 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 66);
784 if (ms_biff_query_peek_next (q
, &peek_op
) &&
785 peek_op
== BIFF_COORDLIST
) {
790 ms_biff_query_next (q
);
792 array
= g_array_set_size (
793 g_array_new (FALSE
, FALSE
, sizeof (double)), n
+ 2);
795 for (i
= 0; i
< n
; i
++) {
796 tmp
= GSF_LE_GET_GUINT16 (q
->data
+ 2*i
);
797 g_array_index (array
, double, i
) = (double)tmp
/ 16384.;
799 g_array_index (array
, double, i
) = g_array_index (array
, double, 0);
800 g_array_index (array
, double, i
+1) = g_array_index (array
, double, 1);
801 ms_obj_attr_bag_insert (obj
->attrs
,
802 ms_obj_attr_new_array (MS_OBJ_ATTR_POLYGON_COORDS
, array
));
807 /* 76 name len, name, cbfmla1 (IGNORE cbMacro), fmla1, cbfmla2, fmla2, cbtext, text */
809 case MSOT_OPTION
: /* option button */
810 /* 88 name len, name, cbfmla1 (IGNORE cbMacro), fmla1, cbfmla2, fmla2, cbtext, text */
813 /* 70 name len, name, fmla (respect cbMacro), cbtext, text */
814 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 70);
817 /* 70 name len, name, fmla (respect cbMacro), cbtext, text */
818 len
= GSF_LE_GET_GUINT16 (q
->data
+ 44);
819 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 70);
820 if (read_pre_biff8_read_text (q
, c
, obj
, data
, len
, 16))
823 case MSOT_DIALOG
: /* dialog frame */
824 /* 70 name len, name, fmla (respect cbMacro) */
825 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 70);
829 /* 68 name len, name, cbfmla1 (IGNORE cbMacro), fmla1, cbfmla2, fmla2 */
830 ms_obj_attr_bag_insert (obj
->attrs
,
831 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_VALUE
,
832 GSF_LE_GET_GUINT16 (q
->data
+48)));
833 ms_obj_attr_bag_insert (obj
->attrs
,
834 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_MIN
,
835 GSF_LE_GET_GUINT16 (q
->data
+50)));
836 ms_obj_attr_bag_insert (obj
->attrs
,
837 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_MAX
,
838 GSF_LE_GET_GUINT16 (q
->data
+52)));
839 ms_obj_attr_bag_insert (obj
->attrs
,
840 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_INC
,
841 GSF_LE_GET_GUINT16 (q
->data
+54)));
842 ms_obj_attr_bag_insert (obj
->attrs
,
843 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_PAGE
,
844 GSF_LE_GET_GUINT16 (q
->data
+56)));
845 ms_obj_attr_bag_insert (obj
->attrs
,
846 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_HORIZ
,
847 GSF_LE_GET_GUINT16 (q
->data
+58)));
850 guint8
const *last
= q
->data
+ q
->length
;
851 guint8
const *ptr
= q
->data
+ 64;
853 ptr
+= 1 + *ptr
; /* object name */
854 if ((ptr
- q
->data
) & 1) ptr
++; /* align on word */
855 if (ptr
>= last
) break;
857 ptr
+= 2 + GSF_LE_GET_GUINT16 (ptr
); /* the macro */
858 if ((ptr
- q
->data
) & 1) ptr
++; /* align on word */
859 if (ptr
>= last
) break;
861 (void) ms_obj_read_expr (obj
, MS_OBJ_ATTR_LINKED_TO_CELL
, c
,
866 /* 88 name len, name, cbfmla1 (IGNORE cbMacro), fmla1, cbfmla2, fmla2, cbfmla3, fmla3 */
869 /* 82 name len, name, fmla (respect cbMacro), cbtext, text */
870 data
= read_pre_biff8_read_name_and_fmla (q
, c
, obj
, has_name
, 82);
873 /* 110 name len, name, cbfmla1 (IGNORE cbMacro), fmla1, cbfmla2, fmla2, cbfmla3, fmla3 */
875 (GSF_LE_GET_GUINT16 (q
->data
+ 8) & 0x8000) ? TRUE
: FALSE
;
881 if (obj
->excel_type
== MSOT_PICTURE
) { /* picture */
883 if (ms_biff_query_peek_next (q
, &op
) && op
== BIFF_IMDATA
) {
886 ms_biff_query_next (q
);
887 pixbuf
= excel_read_IMDATA (q
, FALSE
);
889 ms_obj_attr_bag_insert (obj
->attrs
,
890 ms_obj_attr_new_gobject
893 g_object_unref (pixbuf
);
901 ms_obj_map_forms_obj (MSObj
*obj
, MSContainer
*c
,
902 guint8
const *data
, guint8
const *last
)
907 gboolean has_result_link
;
908 gboolean has_source_link
; /* requires has_result_link */
909 } const map_forms
[] = {
910 { "ScrollBar.1", MSOT_SCROLLBAR
, TRUE
, FALSE
},
911 { "CheckBox.1", MSOT_CHECKBOX
, TRUE
, FALSE
},
912 { "TextBox.1", MSOT_TEXTBOX
, FALSE
, FALSE
},
913 { "CommandButton.1", MSOT_BUTTON
, FALSE
, FALSE
},
914 { "OptionButton.1", MSOT_OPTION
, TRUE
, FALSE
},
915 { "ListBox.1", MSOT_LIST
, TRUE
, TRUE
},
916 { "ComboBox.1", MSOT_COMBO
, TRUE
, TRUE
},
917 { "ToggleButton.1", MSOT_TOGGLE
, TRUE
, FALSE
},
918 { "SpinButton.1", MSOT_SPINNER
, TRUE
, FALSE
},
919 { "Label.1", MSOT_LABEL
, FALSE
, FALSE
},
920 { "Image.1", MSOT_PICTURE
, FALSE
, FALSE
}
926 if (last
- data
< 16)
928 type
= excel_get_text (c
->importer
, data
+ 16,
929 GSF_LE_GET_GUINT16 (data
+ 14),
930 &len
, NULL
, last
- data
);
931 if (NULL
== type
|| strncmp (type
, "Forms.", 6)) {
936 #ifndef NO_DEBUG_EXCEL
937 if (ms_excel_object_debug
> 0) {
938 g_printerr ("'%s' = %d\n", type
, len
);
939 if (ms_excel_object_debug
> 4)
940 gsf_mem_dump (data
, last
-data
);
944 for (i
= G_N_ELEMENTS (map_forms
); i
-- > 0 ; )
945 if (map_forms
[i
].excel_type
> 0 &&
946 !strcmp (type
+6, map_forms
[i
].key
))
953 obj
->excel_type
= map_forms
[i
].excel_type
;
954 #ifndef NO_DEBUG_EXCEL
955 if (ms_excel_object_debug
> 0)
956 g_printerr ("found = %s\n", map_forms
[i
].key
);
959 if (map_forms
[i
].has_result_link
) {
960 /* round to word length */
961 data
= ms_obj_read_expr (obj
, MS_OBJ_ATTR_LINKED_TO_CELL
, c
,
962 data
+ 16 + len
+ (len
&1) + 14, last
);
963 if (NULL
!= data
&& map_forms
[i
].has_source_link
)
964 ms_obj_read_expr (obj
, MS_OBJ_ATTR_INPUT_FROM
, c
,
970 ms_obj_read_biff8_obj (BiffQuery
*q
, MSContainer
*c
, MSObj
*obj
)
973 gint32 data_len_left
;
974 gboolean hit_end
= FALSE
;
975 gboolean next_biff_record_maybe_imdata
= FALSE
;
977 g_return_val_if_fail (q
, TRUE
);
978 g_return_val_if_fail (q
->opcode
== BIFF_OBJ
, TRUE
);
981 data_len_left
= q
->length
;
984 ms_biff_query_dump (q
);
987 /* Scan through the pseudo BIFF substream */
988 while (data_len_left
>= 4 && !hit_end
) {
989 guint16
const record_type
= GSF_LE_GET_GUINT16(data
);
991 /* All the sub-records seem to have this layout
992 * 2001/Mar/29 JEG : liars. Ok not all records have this
993 * layout. Create a list box. It seems to do something
994 * unique. It acts like an end, and has no length specified.
996 guint16 len
= GSF_LE_GET_GUINT16(data
+2);
998 // The would-be "len" field has different meaning for
1000 if (record_type
!= GR_LISTBOX_DATA
)
1001 XL_CHECK_CONDITION_VAL (data_len_left
>= 4 + len
, TRUE
);
1003 /* 1st record must be COMMON_OBJ*/
1004 XL_CHECK_CONDITION_VAL (obj
->excel_type
>= 0 ||
1005 record_type
== GR_COMMON_OBJ_DATA
,
1008 switch (record_type
) {
1010 XL_CHECK_CONDITION_VAL (len
== 0, TRUE
);
1011 /* ms_obj_dump (data, len, data_len_left, "ObjEnd"); */
1016 ms_obj_read_expr (obj
, MS_OBJ_ATTR_MACRO_EXPR
, c
,
1017 data
+4, data
+ 4 + len
);
1018 ms_obj_dump (data
, len
, data_len_left
, "MacroObject");
1021 case GR_COMMAND_BUTTON
:
1022 ms_obj_dump (data
, len
, data_len_left
, "CommandButton");
1026 ms_obj_dump (data
, len
, data_len_left
, "Group");
1029 case GR_CLIPBOARD_FORMAT
:
1030 ms_obj_dump (data
, len
, data_len_left
, "ClipboardFmt");
1033 case GR_PICTURE_OPTIONS
:
1035 guint16 opt
= GSF_LE_GET_GUINT16 (data
+ 4);
1037 obj
->is_linked
= (opt
& 0x2) ? TRUE
: FALSE
;
1038 #ifndef NO_DEBUG_EXCEL
1039 if (ms_excel_object_debug
>= 1) {
1040 g_printerr ("{ /* PictOpt */\n");
1041 g_printerr ("value = %x;\n", opt
);
1042 g_printerr ("}; /* PictOpt */\n");
1046 /* no docs on this so be careful */
1047 g_warning ("PictOpt record with size other than 2");
1050 next_biff_record_maybe_imdata
= TRUE
;
1053 case GR_PICTURE_FORMULA
:
1054 /* Check for form objects stored here for no apparent reason */
1055 if (obj
->excel_type
== 8)
1056 ms_obj_map_forms_obj (obj
, c
, data
+4, data
+4+len
);
1059 case GR_CHECKBOX_LINK
:
1060 ms_obj_dump (data
, len
, data_len_left
, "CheckboxLink");
1063 case GR_RADIO_BUTTON
:
1064 ms_obj_dump (data
, len
, data_len_left
, "RadioButton");
1068 XL_CHECK_CONDITION_VAL (data_len_left
>= 20, TRUE
);
1069 ms_obj_attr_bag_insert (obj
->attrs
,
1070 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_VALUE
,
1071 GSF_LE_GET_GUINT16 (data
+8)));
1072 ms_obj_attr_bag_insert (obj
->attrs
,
1073 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_MIN
,
1074 GSF_LE_GET_GUINT16 (data
+10)));
1075 ms_obj_attr_bag_insert (obj
->attrs
,
1076 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_MAX
,
1077 GSF_LE_GET_GUINT16 (data
+12)));
1078 ms_obj_attr_bag_insert (obj
->attrs
,
1079 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_INC
,
1080 GSF_LE_GET_GUINT16 (data
+14)));
1081 ms_obj_attr_bag_insert (obj
->attrs
,
1082 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_PAGE
,
1083 GSF_LE_GET_GUINT16 (data
+16)));
1084 ms_obj_attr_bag_insert (obj
->attrs
,
1085 ms_obj_attr_new_uint (MS_OBJ_ATTR_SCROLLBAR_HORIZ
,
1086 GSF_LE_GET_GUINT16 (data
+18)));
1087 ms_obj_dump (data
, len
, data_len_left
, "ScrollBar");
1090 case GR_NOTE_STRUCTURE
:
1091 ms_obj_dump (data
, len
, data_len_left
, "Note");
1094 case GR_SCROLLBAR_FORMULA
:
1095 ms_obj_read_expr (obj
, MS_OBJ_ATTR_LINKED_TO_CELL
, c
,
1096 data
+4, data
+ 4 + len
);
1097 ms_obj_dump (data
, len
, data_len_left
, "ScrollbarFmla");
1100 case GR_GROUP_BOX_DATA
:
1101 ms_obj_dump (data
, len
, data_len_left
, "GroupBoxData");
1104 case GR_EDIT_CONTROL_DATA
:
1105 ms_obj_dump (data
, len
, data_len_left
, "EditCtrlData");
1108 case GR_RADIO_BUTTON_DATA
:
1109 ms_obj_dump (data
, len
, data_len_left
, "RadioData");
1112 case GR_CHECKBOX_DATA
:
1113 ms_obj_dump (data
, len
, data_len_left
, "CheckBoxData");
1116 case GR_LISTBOX_DATA
:
1117 if (!obj
->auto_combo
)
1118 ms_obj_read_expr (obj
, MS_OBJ_ATTR_INPUT_FROM
, c
,
1119 data
+6, data
+ data_len_left
);
1122 * It seems as if list box data does not conform to
1123 * the docs. It acts like an end and has no size.
1126 len
= data_len_left
- 4;
1128 #warning "We should import selection too, see ms_objv8_write_list_data"
1130 ms_obj_dump (data
, len
, data_len_left
, "ListBoxData");
1133 case GR_CHECKBOX_FORMULA
:
1134 ms_obj_read_expr (obj
, MS_OBJ_ATTR_LINKED_TO_CELL
, c
,
1135 data
+4, data
+ 4 + len
);
1136 ms_obj_dump (data
, len
, data_len_left
, "CheckBoxFmla");
1139 case GR_COMMON_OBJ_DATA
: {
1142 XL_CHECK_CONDITION_VAL (data_len_left
>= 10, TRUE
);
1144 options
= GSF_LE_GET_GUINT16 (data
+8);
1146 /* Multiple objects in 1 record ?? */
1147 XL_CHECK_CONDITION_VAL (obj
->excel_type
== -1, TRUE
);
1149 obj
->excel_type
= GSF_LE_GET_GUINT16(data
+4);
1150 obj
->id
= GSF_LE_GET_GUINT16(data
+6);
1152 // "P" flag in FtCmo.
1154 (obj
->excel_type
== 0x14) && (options
& 0x100);
1156 #ifndef NO_DEBUG_EXCEL
1157 /* only print when debug is enabled */
1158 if (ms_excel_object_debug
== 0)
1161 g_printerr ("OBJECT TYPE = %d, id = %d;\n", obj
->excel_type
, obj
->id
);
1163 g_printerr ("Locked;\n");
1165 g_printerr ("Printable;\n");
1167 g_printerr ("AutoFilled;\n");
1169 g_printerr ("AutoLines;\n");
1171 if (ms_excel_object_debug
> 4) {
1172 /* According to the docs this should not fail
1173 * but there appears to be a flag at 0x200 for
1174 * scrollbars and 0x100 for combos associated
1176 if ((options
& 0x9eee) != 0)
1177 g_printerr ("Unknown option flag : %x;\n",
1185 g_printerr ("ERROR : Unknown Obj record 0x%x len 0x%x dll %d;\n",
1186 record_type
, len
, data_len_left
);
1189 if (data_len_left
< len
+4)
1190 g_printerr ("record len %d (0x%x) > %d\n", len
+4, len
+4, data_len_left
);
1192 /* FIXME : We need a structure akin to the escher code to do this properly */
1193 for (data_len_left
-= len
+4; data_len_left
< 0; ) {
1196 g_printerr ("deficit of %d\n", data_len_left
);
1198 /* FIXME : what do we expect here ??
1199 * I've seen what seem to be embedded drawings
1200 * but I am not sure what is embedding what.
1202 if (!ms_biff_query_peek_next (q
, &peek_op
) ||
1203 (peek_op
!= BIFF_CONTINUE
&&
1204 peek_op
!= BIFF_MS_O_DRAWING
&&
1205 peek_op
!= BIFF_TXO
&&
1206 peek_op
!= BIFF_OBJ
)) {
1207 g_printerr ("0x%x vs 0x%x\n", q
->opcode
, peek_op
);
1211 ms_biff_query_next (q
);
1212 data_len_left
+= q
->length
;
1213 g_printerr ("merged in 0x%x with len %d\n", q
->opcode
, q
->length
);
1215 data
= q
->data
+ q
->length
- data_len_left
;
1218 /* The ftEnd record should have been the last */
1219 if (data_len_left
> 0) {
1220 g_printerr("OBJ : unexpected extra data after Object End record;\n");
1221 gsf_mem_dump (data
, data_len_left
);
1225 /* Catch underflow too */
1226 XL_CHECK_CONDITION_VAL (data_len_left
== 0, TRUE
);
1228 /* FIXME : Throw away the IMDATA that may follow.
1229 * I am not sure when the IMDATA does follow, or how to display it,
1230 * but very careful in case it is not there. */
1231 if (next_biff_record_maybe_imdata
) {
1234 if (ms_biff_query_peek_next (q
, &op
) && op
== BIFF_IMDATA
) {
1237 ms_biff_query_next (q
);
1238 pixbuf
= excel_read_IMDATA (q
, FALSE
);
1240 g_object_unref (pixbuf
);
1249 * @q: The biff record to start with.
1250 * @c: The object's container
1251 * @attrs: an optional hash of object attributes.
1253 * This function takes ownership of attrs.
1255 * Returns: %TRUE on success.
1258 ms_read_OBJ (BiffQuery
*q
, MSContainer
*c
, MSObjAttrBag
*attrs
)
1260 static char const * const object_type_names
[] = {
1263 "Rectangle", /* 0x02 */
1267 "TextBox", /* 0x06 */
1268 "Button", /* 0x07 */
1269 "Picture", /* 0x08 */
1270 "Polygon", /* 0x09 */
1272 "CheckBox", /* 0x0B */
1273 "Option", /* 0x0C */
1276 "Dialog", /* 0x0F */
1277 "Spinner", /* 0x10 */
1278 "Scroll", /* 0x11 */
1282 NULL
, NULL
, NULL
, NULL
, /* 0x15 - 0x18 */
1283 "Comment", /* 0x19 */
1284 NULL
, NULL
, NULL
, NULL
, /* 0x1A - 0x1D */
1285 "MS Drawing" /* 0x1E */
1291 /* no decent docs for this */
1292 if (c
->importer
->ver
<= MS_BIFF_V4
)
1295 #ifndef NO_DEBUG_EXCEL
1296 if (ms_excel_object_debug
> 0)
1297 g_printerr ("{ /* OBJ start */\n");
1299 obj
= ms_obj_new (attrs
);
1300 /* When called from escher (@attrs != NULL) use the biff8 variant.
1301 * When embdedded directly in the stream (@attrs == NULL) the OBJ
1302 * record appears to be in the old format. (#546887) */
1303 errors
= (NULL
!= attrs
)
1304 ? ms_obj_read_biff8_obj (q
, c
, obj
)
1305 : ms_obj_read_pre_biff8_obj (q
, c
, obj
);
1308 #ifndef NO_DEBUG_EXCEL
1309 if (ms_excel_object_debug
> 0)
1310 g_printerr ("}; /* OBJ error 1 */\n");
1312 ms_obj_delete (obj
);
1316 obj
->excel_type_name
= NULL
;
1317 if ((size_t)obj
->excel_type
< G_N_ELEMENTS (object_type_names
))
1318 obj
->excel_type_name
= object_type_names
[obj
->excel_type
];
1319 if (obj
->excel_type_name
== NULL
)
1320 obj
->excel_type_name
= "Unknown";
1322 #ifndef NO_DEBUG_EXCEL
1323 if (ms_excel_object_debug
> 0) {
1324 g_printerr ("Object (%d) is a '%s'\n", obj
->id
, obj
->excel_type_name
);
1325 g_printerr ("}; /* OBJ end */\n");
1329 if (c
->vtbl
->create_obj
!= NULL
)
1330 obj
->gnum_obj
= c
->vtbl
->create_obj (c
, obj
);
1332 /* Chart, There should be a BOF next */
1333 if (obj
->excel_type
== 0x5) {
1334 if (ms_excel_chart_read_BOF (q
, c
, obj
->gnum_obj
)) {
1335 ms_obj_delete (obj
);
1340 ms_container_add_obj (c
, obj
);
1345 /**********************************************************************/
1348 ms_objv8_write_common (BiffPut
*bp
, int id
, int type
, guint16 flags
)
1351 GSF_LE_SET_GUINT16 (buf
+ 0, 0x15); /* common record */
1352 GSF_LE_SET_GUINT16 (buf
+ 2, 0x12); /* len 0x12 */
1353 GSF_LE_SET_GUINT16 (buf
+ 4, type
);
1354 GSF_LE_SET_GUINT16 (buf
+ 6, id
);
1355 GSF_LE_SET_GUINT16 (buf
+ 8, flags
);
1357 GSF_LE_SET_GUINT32 (buf
+ 10, 0);
1358 /* docs say 0, but n the wild this is some sort of pointer ?*/
1359 GSF_LE_SET_GUINT32 (buf
+ 14, 0);
1360 GSF_LE_SET_GUINT32 (buf
+ 18, 0);
1361 ms_biff_put_var_write (bp
, buf
, sizeof buf
);
1365 ms_objv8_write_scrollbar_old (BiffPut
*bp
)
1367 /* no docs, but some guesses. See above */
1368 static guint8
const data
[] = {
1376 1, 0, /* increment */
1382 ms_biff_put_var_write (bp
, data
, sizeof data
);
1386 ms_objv8_write_listbox (BiffPut
*bp
, guint8 lct
, gboolean filtered
)
1388 static guint8
const data
[] = {
1389 0x13, 0, // GR_LISTBOX_DATA
1390 0xee, 0x1f, /* totally contradicts docs, see above */
1393 0, 0, // Nothing selected
1394 1, // Flags (fUseCB)
1397 2, 0, 8, 0, 0x40, 0, 0, 0, 0, 0 // LbsDropData
1399 guint8 buf
[sizeof data
];
1400 memcpy (buf
, data
, sizeof data
);
1402 GSF_LE_SET_GUINT16 (buf
+ 14, 0xa);
1403 GSF_LE_SET_GUINT8 (buf
+ 11, lct
);
1404 ms_biff_put_var_write (bp
, buf
, sizeof data
);
1408 ms_objv8_write_note (BiffPut
*bp
)
1410 static guint8
const data
[] = {
1412 0x16, 0, /* length 0x16 */
1414 /* no idea, and no docs */
1415 54 80 79 64 08 0a
77 4f b3 d2
6b
26 88 2a
22 1a
00 00 10 00 00 00
1416 46 2d
5a
01 10 5c e7
46 9b
97 e2
7e
49 7f
08 b8
00 00 bf
00 08 00
1418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1420 guint8 buf
[sizeof data
];
1422 memcpy (buf
, data
, sizeof data
);
1423 ms_biff_put_var_write (bp
, buf
, sizeof data
);
1427 ms_objv8_write_checkbox_data (BiffPut
*bp
, gboolean active
)
1431 GSF_LE_SET_GUINT16 (cboxdata
, GR_CHECKBOX_DATA
);
1432 GSF_LE_SET_GUINT16 (cboxdata
+ 2, sizeof (cboxdata
) - 4);
1433 GSF_LE_SET_GUINT16 (cboxdata
+ 4, active
);
1434 GSF_LE_SET_GUINT16 (cboxdata
+ 6, 0); /* accel */
1435 GSF_LE_SET_GUINT16 (cboxdata
+ 8, 0); /* reserved */
1436 GSF_LE_SET_GUINT16 (cboxdata
+ 10, 2); /* 3d display. */
1437 ms_biff_put_var_write (bp
, cboxdata
, sizeof cboxdata
);
1441 ms_objv8_write_checkbox_link (BiffPut
*bp
, gboolean active
)
1445 GSF_LE_SET_GUINT16 (data
, GR_CHECKBOX_LINK
);
1446 GSF_LE_SET_GUINT16 (data
+ 2, sizeof (data
) - 4);
1447 GSF_LE_SET_GUINT16 (data
+ 4, active
); /* ? */
1448 GSF_LE_SET_GUINT16 (data
+ 6, 0x12b0); /* ? */
1449 GSF_LE_SET_GUINT16 (data
+ 8, 0x01ce); /* ? */
1450 GSF_LE_SET_GUINT16 (data
+ 10, 0);
1451 GSF_LE_SET_GUINT16 (data
+ 12, 0);
1452 GSF_LE_SET_GUINT16 (data
+ 14, 2); /* style? */
1453 ms_biff_put_var_write (bp
, data
, sizeof data
);
1457 ms_objv8_write_link_fmla (BiffPut
*bp
, guint16 typ
,
1458 ExcelWriteSheet
*esheet
,
1459 GnmExprTop
const *texpr
)
1462 unsigned pos
, end_pos
;
1466 GSF_LE_SET_GUINT16 (hfmla
, typ
);
1467 GSF_LE_SET_GUINT16 (hfmla
+ 2, 0); /* record len */
1468 GSF_LE_SET_GUINT16 (hfmla
+ 4, 0); /* formula len */
1469 GSF_LE_SET_GUINT32 (hfmla
+ 6, 0); /* calcid? */
1470 ms_biff_put_var_write (bp
, hfmla
, sizeof hfmla
);
1471 fmla_len
= excel_write_formula (esheet
->ewb
,
1473 esheet
->gnum_sheet
, 0, 0,
1474 EXCEL_CALLED_FROM_OBJ
);
1476 ms_biff_put_var_write (bp
, "", 1);
1477 end_pos
= bp
->curpos
;
1478 ms_biff_put_var_seekto (bp
, pos
);
1479 GSF_LE_SET_GUINT16 (hfmla
+ 2, (fmla_len
+ 7) & ~1);
1480 GSF_LE_SET_GUINT16 (hfmla
+ 4, fmla_len
);
1481 ms_biff_put_var_write (bp
, hfmla
, sizeof hfmla
);
1482 ms_biff_put_var_seekto (bp
, end_pos
);
1486 ms_objv8_write_macro_fmla (BiffPut
*bp
,
1487 ExcelWriteSheet
*esheet
,
1488 GnmExprTop
const *texpr
)
1491 unsigned pos
, end_pos
;
1495 GSF_LE_SET_GUINT16 (hfmla
, GR_MACRO
);
1496 GSF_LE_SET_GUINT16 (hfmla
+ 2, 0); /* record len */
1497 GSF_LE_SET_GUINT16 (hfmla
+ 4, 0); /* formula len */
1498 GSF_LE_SET_GUINT32 (hfmla
+ 6, 0); /* calcid? */
1499 ms_biff_put_var_write (bp
, hfmla
, sizeof hfmla
);
1500 fmla_len
= excel_write_formula (esheet
->ewb
,
1502 esheet
->gnum_sheet
, 0, 0,
1503 EXCEL_CALLED_FROM_OBJ
);
1505 ms_biff_put_var_write (bp
, "", 1);
1506 end_pos
= bp
->curpos
;
1507 ms_biff_put_var_seekto (bp
, pos
);
1508 GSF_LE_SET_GUINT16 (hfmla
+ 2, (fmla_len
+ 7) & ~1);
1509 GSF_LE_SET_GUINT16 (hfmla
+ 4, fmla_len
);
1510 ms_biff_put_var_write (bp
, hfmla
, sizeof hfmla
);
1511 ms_biff_put_var_seekto (bp
, end_pos
);
1515 ms_objv8_write_macro_ref (BiffPut
*bp
,
1516 ExcelWriteSheet
*esheet
,
1517 GnmNamedExpr
*macro_nexpr
)
1519 GnmExprTop
const *texpr
=
1521 (gnm_expr_new_name (macro_nexpr
,
1524 ms_objv8_write_macro_fmla (bp
, esheet
, texpr
);
1525 gnm_expr_top_unref (texpr
);
1529 ms_objv8_write_checkbox (BiffPut
*bp
,
1531 ExcelWriteSheet
*esheet
,
1532 GnmExprTop
const *link_texpr
,
1533 GnmNamedExpr
*macro_nexpr
)
1535 ms_objv8_write_checkbox_link (bp
, active
);
1537 ms_objv8_write_link_fmla (bp
, GR_CHECKBOX_FORMULA
,
1538 esheet
, link_texpr
);
1539 if (0 && macro_nexpr
)
1540 ms_objv8_write_macro_ref (bp
, esheet
, macro_nexpr
);
1541 ms_objv8_write_checkbox_data (bp
, active
);
1545 ms_objv8_write_radiobutton_rec (BiffPut
*bp
)
1549 GSF_LE_SET_GUINT16 (rb
, GR_RADIO_BUTTON
);
1550 GSF_LE_SET_GUINT16 (rb
+ 2, sizeof (rb
) - 4);
1551 GSF_LE_SET_GUINT32 (rb
+ 4, 0); /* ignore */
1552 GSF_LE_SET_GUINT16 (rb
+ 8, 0); /* ignore */
1553 ms_biff_put_var_write (bp
, rb
, sizeof rb
);
1557 ms_objv8_write_radiobutton_data (BiffPut
*bp
, guint16 nobj
, gboolean first
)
1561 GSF_LE_SET_GUINT16 (rb
, GR_RADIO_BUTTON_DATA
);
1562 GSF_LE_SET_GUINT16 (rb
+ 2, sizeof (rb
) - 4);
1563 GSF_LE_SET_GUINT16 (rb
+ 4, nobj
);
1564 GSF_LE_SET_GUINT16 (rb
+ 6, !!first
);
1565 ms_biff_put_var_write (bp
, rb
, sizeof rb
);
1569 ms_objv8_write_radiobutton (BiffPut
*bp
,
1571 ExcelWriteSheet
*esheet
,
1572 GnmExprTop
const *link_texpr
,
1573 GnmNamedExpr
*macro_nexpr
)
1575 ms_objv8_write_checkbox_link (bp
, active
);
1576 ms_objv8_write_radiobutton_rec (bp
);
1578 ms_objv8_write_link_fmla (bp
, GR_CHECKBOX_FORMULA
,
1579 esheet
, link_texpr
);
1580 if (0 && macro_nexpr
)
1581 ms_objv8_write_macro_ref (bp
, esheet
, macro_nexpr
);
1582 ms_objv8_write_checkbox_data (bp
, active
);
1583 ms_objv8_write_radiobutton_data (bp
, 0, TRUE
);
1587 ms_objv8_write_adjustment (BiffPut
*bp
,
1588 GtkAdjustment
*adj
, gboolean horiz
)
1592 GSF_LE_SET_GUINT16 (data
, GR_SCROLLBAR
);
1593 GSF_LE_SET_GUINT16 (data
+ 2, sizeof (data
) - 4);
1594 GSF_LE_SET_GUINT32 (data
+ 4, 0); /* Unused */
1595 #define SQUEEZE(f) ((guint16)CLAMP(f, -32768, 32767))
1596 GSF_LE_SET_GUINT16 (data
+ 8, SQUEEZE (gtk_adjustment_get_value (adj
)));
1597 GSF_LE_SET_GINT16 (data
+ 10, SQUEEZE (gtk_adjustment_get_lower (adj
)));
1598 GSF_LE_SET_GINT16 (data
+ 12, SQUEEZE (gtk_adjustment_get_upper (adj
) + gtk_adjustment_get_step_increment (adj
)));
1599 GSF_LE_SET_GINT16 (data
+ 14, SQUEEZE (gtk_adjustment_get_step_increment (adj
)));
1600 GSF_LE_SET_GINT16 (data
+ 16, SQUEEZE (gtk_adjustment_get_page_increment (adj
)));
1602 GSF_LE_SET_GINT16 (data
+ 18, !!horiz
);
1603 GSF_LE_SET_GINT16 (data
+ 20, 15); /* widget in pixels */
1604 GSF_LE_SET_GINT16 (data
+ 22, 0x0001); /* draw */
1606 ms_biff_put_var_write (bp
, data
, sizeof data
);
1610 ms_objv8_write_spinbutton (BiffPut
*bp
,
1611 ExcelWriteSheet
*esheet
,
1612 GtkAdjustment
*adj
, gboolean horiz
,
1613 GnmExprTop
const *link_texpr
,
1614 GnmNamedExpr
*macro_nexpr
)
1616 ms_objv8_write_adjustment (bp
, adj
, horiz
);
1618 ms_objv8_write_link_fmla (bp
, GR_SCROLLBAR_FORMULA
,
1619 esheet
, link_texpr
);
1620 if (0 && macro_nexpr
)
1621 ms_objv8_write_macro_ref (bp
, esheet
, macro_nexpr
);
1625 ms_objv8_write_scrollbar (BiffPut
*bp
,
1626 ExcelWriteSheet
*esheet
,
1627 GtkAdjustment
*adj
, gboolean horiz
,
1628 GnmExprTop
const *link_texpr
,
1629 GnmNamedExpr
*macro_nexpr
)
1631 ms_objv8_write_adjustment (bp
, adj
, horiz
);
1633 ms_objv8_write_link_fmla (bp
, GR_SCROLLBAR_FORMULA
,
1634 esheet
, link_texpr
);
1635 if (0 && macro_nexpr
)
1636 ms_objv8_write_macro_ref (bp
, esheet
, macro_nexpr
);
1640 ms_objv8_write_list_data (BiffPut
*bp
,
1641 ExcelWriteSheet
*esheet
,
1642 GnmExprTop
const *texpr
,
1643 guint16 N
, guint16 selected
)
1647 unsigned pos
, end_pos
;
1654 GSF_LE_SET_GUINT16 (hfmla
, GR_LISTBOX_DATA
);
1655 GSF_LE_SET_GUINT16 (hfmla
+ 2, 0x1fcc); /* ??? */
1656 GSF_LE_SET_GUINT16 (hfmla
+ 4, 0); /* record len */
1657 GSF_LE_SET_GUINT16 (hfmla
+ 6, 0); /* formula len */
1658 GSF_LE_SET_GUINT32 (hfmla
+ 8, 0); /* calcid? */
1659 ms_biff_put_var_write (bp
, hfmla
, sizeof hfmla
);
1661 fmla_len
= excel_write_formula (esheet
->ewb
,
1663 esheet
->gnum_sheet
, 0, 0,
1664 EXCEL_CALLED_FROM_OBJ
);
1666 ms_biff_put_var_write (bp
, "", 1);
1667 GSF_LE_SET_GUINT16 (hfmla
+ 6, fmla_len
);
1669 /* Needs testing. */
1670 ms_biff_put_var_write (bp
, "\0", 2);
1674 end_pos
= bp
->curpos
;
1675 ms_biff_put_var_seekto (bp
, pos
);
1676 GSF_LE_SET_GUINT16 (hfmla
+ 4, (fmla_len
+ 7) & ~1);
1677 ms_biff_put_var_write (bp
, hfmla
, sizeof hfmla
);
1678 ms_biff_put_var_seekto (bp
, end_pos
);
1680 selection
= g_new0 (char, N
);
1681 for (ui
= 0; ui
< N
; ui
++)
1682 selection
[ui
] = (ui
+ 1 == selected
);
1684 GSF_LE_SET_GUINT16 (data
, N
);
1685 GSF_LE_SET_GUINT16 (data
+ 2, selected
); /* iSel */
1686 GSF_LE_SET_GUINT16 (data
+ 4, style
);
1687 GSF_LE_SET_GUINT16 (data
+ 6, 0); /* edit object id */
1688 ms_biff_put_var_write (bp
, data
, sizeof data
);
1689 ms_biff_put_var_write (bp
, selection
, N
);
1695 ms_objv8_write_list (BiffPut
*bp
,
1696 ExcelWriteSheet
*esheet
,
1698 GnmExprTop
const *res_texpr
,
1699 GnmExprTop
const *data_texpr
,
1700 GnmNamedExpr
*macro_nexpr
)
1702 ms_objv8_write_adjustment (bp
, adj
, FALSE
);
1704 ms_objv8_write_link_fmla (bp
, GR_SCROLLBAR_FORMULA
,
1706 if (0 && macro_nexpr
)
1707 ms_objv8_write_macro_ref (bp
, esheet
, macro_nexpr
);
1708 ms_objv8_write_list_data (bp
, esheet
, data_texpr
,
1709 (guint16
)gtk_adjustment_get_upper (adj
) - 1,
1710 (guint16
)gtk_adjustment_get_value (adj
));
1714 ms_objv8_write_button (BiffPut
*bp
,
1715 ExcelWriteSheet
*esheet
,
1716 GnmNamedExpr
*macro_nexpr
)
1718 if (0 && macro_nexpr
)
1719 ms_objv8_write_macro_ref (bp
, esheet
, macro_nexpr
);