2 * ms-excel-read.c: MS Excel import
5 * Jody Goldberg (jody@gnome.org)
6 * Michael Meeks (michael@ximian.com)
8 * (C) 1998-2001 Michael Meeks
9 * (C) 2002-2008 Jody Goldberg
10 * (C) 2013-2013 Morten Welinder
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) version 3.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
27 #include <gnumeric-config.h>
31 #include "ms-formula-read.h"
32 #include "ms-excel-read.h"
35 #include "ms-escher.h"
36 #include "ms-excel-util.h"
37 #include "ms-excel-xf.h"
38 #include "formula-types.h"
41 #include <workbook-view.h>
43 #include <sheet-view.h>
44 #include <sheet-style.h>
45 #include <sheet-merge.h>
46 #include <sheet-filter.h>
50 #include <style-conditions.h>
51 #include <style-font.h>
52 #include <gnm-format.h>
53 #include <print-info.h>
54 #include <selection.h>
55 #include <validation.h>
56 #include <input-msg.h>
57 #include <parse-util.h> /* for cell_name */
60 #include <expr-name.h>
63 #include <application.h>
64 #include <command-context.h>
65 #include <sheet-object-cell-comment.h>
66 #include <sheet-object-widget.h>
67 #include <gnm-so-line.h>
68 #include <gnm-so-filled.h>
69 #include <gnm-so-polygon.h>
70 #include <sheet-object-graph.h>
71 #include <sheet-object-image.h>
72 #include <goffice/goffice.h>
74 #include <gsf/gsf-input.h>
75 #include <gsf/gsf-utils.h>
76 #include <gsf/gsf-msole-utils.h>
77 #include <glib/gi18n-lib.h>
78 #include <glib/gstdio.h>
83 #define G_LOG_DOMAIN "gnumeric:read"
86 ExcelReadSheet
*esheet
;
88 guint32 streamStartPos
;
91 GnmSheetType gnm_type
;
92 GnmSheetVisibility visibility
;
95 #define N_BYTES_BETWEEN_PROGRESS_UPDATES 0x1000
96 #define BMP_HDR_SIZE 14
99 * Check whether the product of the first two arguments exceeds
100 * the third. The function should be overflow-proof.
103 product_gt (size_t count
, size_t itemsize
, size_t space
)
105 return itemsize
> 0 &&
106 (count
> G_MAXUINT
/ itemsize
|| count
* itemsize
> space
);
110 record_size_barf (size_t count
, size_t itemsize
, size_t space
,
113 g_warning ("File is most likely corrupted.\n"
114 "(Requested %u*%u bytes, but only %u bytes left in record.\n"
115 "The problem occurred in %s.)",
116 (unsigned)count
, (unsigned)itemsize
,
121 #define XL_NEED_BYTES(count) XL_NEED_ITEMS(count,1)
123 #define XL_NEED_ITEMS(count__,size__) \
125 size_t count_ = (count__); \
126 size_t size_ = (size__); \
127 size_t space_ = q->length - (data - q->data); \
128 if (G_UNLIKELY (product_gt (count_, size_, space_))) { \
129 record_size_barf (count_, size_, space_, G_STRFUNC); \
135 /* #define NO_DEBUG_EXCEL */
136 #ifndef NO_DEBUG_EXCEL
137 #define d(level, code) do { if (ms_excel_read_debug > level) { code } } while (0)
139 #define d(level, code)
142 #define XL_GETROW(p) (GSF_LE_GET_GUINT16(p->data + 0))
143 #define XL_GETCOL(p) (GSF_LE_GET_GUINT16(p->data + 2))
145 char const *excel_builtin_formats
[EXCEL_BUILTIN_FORMAT_LEN
] = {
146 /* 0x00 */ "General",
150 /* 0x04 */ "#,##0.00",
151 /* 0x05 */ "$#,##0_);($#,##0)",
152 /* 0x06 */ "$#,##0_);[Red]($#,##0)",
153 /* 0x07 */ "$#,##0.00_);($#,##0.00)",
154 /* 0x08 */ "$#,##0.00_);[Red]($#,##0.00)",
157 /* 0x0b */ "0.00E+00",
159 /* 0x0d */ "# ?" "?/?" "?", /* Don't accidentally use trigraph. */
161 /* 0x0f */ "d-mmm-yy",
164 /* 0x12 */ "h:mm AM/PM",
165 /* 0x13 */ "h:mm:ss AM/PM",
167 /* 0x15 */ "h:mm:ss",
168 /* 0x16 */ "m/d/yy h:mm",
169 /* 0x17 */ NULL
, /* 0x17-0x24 reserved for intl versions */
183 /* 0x25 */ "#,##0_);(#,##0)",
184 /* 0x26 */ "#,##0_);[Red](#,##0)",
185 /* 0x27 */ "#,##0.00_);(#,##0.00)",
186 /* 0x28 */ "#,##0.00_);[Red](#,##0.00)",
187 /* 0x29 */ "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
188 /* 0x2a */ "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
189 /* 0x2b */ "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
190 /* 0x2c */ "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
192 /* 0x2e */ "[h]:mm:ss",
193 /* 0x2f */ "mm:ss.0",
194 /* 0x30 */ "##0.0E+0",
198 static PangoAttrList
*empty_attr_list
;
201 esheet_ver (ExcelReadSheet
const *esheet
)
203 return esheet
->container
.importer
->ver
;
207 gnm_xl_importer_set_version (GnmXLImporter
*importer
, MsBiffVersion ver
)
209 g_return_if_fail (NULL
!= importer
);
210 g_return_if_fail (MS_BIFF_V_UNKNOWN
== importer
->ver
);
215 gnm_xl_importer_set_codepage (GnmXLImporter
*importer
, int codepage
)
218 if (codepage
== 1200 || codepage
== 1201)
219 /* this is 'compressed' unicode. unicode characters 0000->00FF
220 * which looks the same as 8859-1. What does Little endian vs
221 * bigendian have to do with this. There is only 1 byte, and it would
222 * certainly not be useful to keep the low byte as 0.
224 str_iconv
= g_iconv_open ("UTF-8", "ISO-8859-1");
226 str_iconv
= gsf_msole_iconv_open_for_import (codepage
);
228 if (str_iconv
== (GIConv
)(-1)) {
229 g_warning ("missing converter for codepage %u\n"
230 "falling back to 1252", codepage
);
231 str_iconv
= gsf_msole_iconv_open_for_import (1252);
234 if (importer
->str_iconv
!= (GIConv
)(-1))
235 gsf_iconv_close (importer
->str_iconv
);
236 importer
->str_iconv
= str_iconv
;
238 /* Store the codepage to make export easier, might
239 * cause problems with double stream files because
240 * we'll lose the codepage in the biff8 version */
241 g_object_set_data (G_OBJECT (importer
->wb
), "excel-codepage",
242 GINT_TO_POINTER (codepage
));
244 d (0, g_printerr ("%s\n", gsf_msole_language_for_lid (
245 gsf_msole_codepage_to_lid (codepage
))););
249 excel_wb_get_fmt (GnmXLImporter
*importer
, unsigned idx
)
251 char const *ans
= NULL
;
252 BiffFormatData
const *d
= g_hash_table_lookup (importer
->format_table
,
253 GUINT_TO_POINTER (idx
));
257 else if (idx
<= 0x31) {
258 ans
= excel_builtin_formats
[idx
];
260 g_printerr ("Foreign undocumented format\n");
262 g_printerr ("Unknown format: 0x%x\n", idx
);
265 GOFormat
*fmt
= gnm_format_import
267 GNM_FORMAT_IMPORT_NULL_INVALID
|
268 GNM_FORMAT_IMPORT_PATCHUP_INCOMPLETE
);
270 g_warning ("Ignoring invalid format [%s]", ans
);
271 fmt
= go_format_general ();
281 excel_cell_fetch (BiffQuery
*q
, ExcelReadSheet
*esheet
)
284 Sheet
*sheet
= esheet
->sheet
;
286 XL_CHECK_CONDITION_VAL (q
->length
>= 4, NULL
);
291 XL_CHECK_CONDITION_VAL (col
< gnm_sheet_get_max_cols (sheet
), NULL
);
292 XL_CHECK_CONDITION_VAL (row
< gnm_sheet_get_max_rows (sheet
), NULL
);
294 return sheet_cell_fetch (sheet
, col
, row
);
297 static GnmExprTop
const *
298 ms_sheet_parse_expr_internal (ExcelReadSheet
*esheet
, guint8
const *data
, int length
)
300 GnmExprTop
const *texpr
;
302 g_return_val_if_fail (length
> 0, NULL
);
304 texpr
= excel_parse_formula (&esheet
->container
, esheet
, 0, 0,
305 data
, length
, 0 /* FIXME */,
307 if (ms_excel_read_debug
> 8) {
310 Sheet
*sheet
= esheet
->sheet
;
311 Workbook
*wb
= (sheet
== NULL
) ? esheet
->container
.importer
->wb
: NULL
;
313 tmp
= gnm_expr_top_as_string (texpr
,
314 parse_pos_init (&pp
, wb
, sheet
, 0, 0),
315 gnm_conventions_default
);
316 g_printerr ("%s\n", tmp
? tmp
: "(null)");
323 static GnmExprTop
const *
324 ms_sheet_parse_expr (MSContainer
*container
, guint8
const *data
, int length
)
326 return ms_sheet_parse_expr_internal ((ExcelReadSheet
*)container
,
331 ms_sheet_get_sheet (MSContainer
const *container
)
333 return ((ExcelReadSheet
const *)container
)->sheet
;
337 ms_sheet_get_fmt (MSContainer
const *container
, unsigned indx
)
339 return excel_wb_get_fmt (container
->importer
, indx
);
343 ms_sheet_map_color (ExcelReadSheet
const *esheet
, MSObj
const *obj
, MSObjAttrID id
,
344 GOColor default_val
, gboolean
*pauto
)
347 MSObjAttr
*attr
= ms_obj_attr_bag_lookup (obj
->attrs
, id
);
350 if (pauto
) *pauto
= TRUE
;
354 if ((~0x7ffffff) & attr
->v
.v_uint
) {
355 GnmColor
*c
= excel_palette_get (esheet
->container
.importer
,
356 (0x7ffffff & attr
->v
.v_uint
));
358 r
= GO_COLOR_UINT_R (c
->go_color
);
359 g
= GO_COLOR_UINT_G (c
->go_color
);
360 b
= GO_COLOR_UINT_B (c
->go_color
);
361 style_color_unref (c
);
363 r
= (attr
->v
.v_uint
) & 0xff;
364 g
= (attr
->v
.v_uint
>> 8) & 0xff;
365 b
= (attr
->v
.v_uint
>> 16) & 0xff;
368 if (pauto
) *pauto
= FALSE
;
370 return GO_COLOR_FROM_RGBA (r
,g
,b
,0xff);
374 * ms_sheet_obj_anchor_to_pos:
375 * @points Array which receives anchor coordinates in points
379 * Converts anchor coordinates in Excel units to points. Anchor
380 * coordinates are x and y of upper left and lower right corner. Each
381 * is expressed as a pair: Row/cell number + position within cell as
382 * fraction of cell dimension.
384 * NOTE: According to docs, position within cell is expressed as
385 * 1/1024 of cell dimension. However, this doesn't seem to be true
386 * vertically, for Excel 97. We use 256 for >= XL97 and 1024 for
390 ms_sheet_obj_anchor_to_pos (Sheet
const * sheet
,
391 G_GNUC_UNUSED MsBiffVersion
const ver
,
392 guint8
const *raw_anchor
,
393 GnmRange
*range
, double offset
[4], GnmSOAnchorMode
*mode
)
396 * gnm_float const row_denominator = (ver >= MS_BIFF_V8) ? 256. : 1024.;
398 * chap03-1.xls suggests that XL95 uses 256 too
399 * Do we have any tests that confirm the docs contention of 1024 ?
405 g_printerr ("anchored to %s\n", sheet
->name_unquoted
);
406 gsf_mem_dump (raw_anchor
, 18);
409 switch (raw_anchor
[0]) {
411 *mode
= GNM_SO_ANCHOR_ONE_CELL
;
414 *mode
= GNM_SO_ANCHOR_ABSOLUTE
;
417 *mode
= GNM_SO_ANCHOR_TWO_CELLS
;
420 /* Ignore the first 2 bytes. What are they ? */
421 /* Dec/1/2000 JEG: I have not researched it, but this may have some
422 * flags indicating whether or not the object is anchored to the cell
426 /* Words 0, 4, 8, 12: The row/col of the corners */
427 /* Words 2, 6, 10, 14: distance from cell edge */
428 for (i
= 0; i
< 4; i
++, raw_anchor
+= 4) {
429 int const pos
= GSF_LE_GET_GUINT16 (raw_anchor
);
430 int const nths
= GSF_LE_GET_GUINT16 (raw_anchor
+ 2);
433 g_printerr ("%d/%d cell %s from ",
434 nths
, (i
& 1) ? 256 : 1024,
435 (i
& 1) ? "widths" : "heights");
437 g_printerr ("row %d;\n", pos
+ 1);
439 g_printerr ("col %s (%d);\n", col_name (pos
), pos
);
442 if (i
& 1) { /* odds are rows */
443 offset
[i
] = nths
/ 256.;
445 range
->start
.row
= pos
;
447 range
->end
.row
= pos
;
449 offset
[i
] = nths
/ 1024.;
451 range
->start
.col
= pos
;
453 range
->end
.col
= pos
;
461 handle_arrow_head (SheetObject
*so
, const char *prop_name
,
463 MSObjAttrBag
*attrs
, MSObjAttrID typid
,
464 MSObjAttrID wid
, MSObjAttrID lid
)
467 int w
= ms_obj_attr_get_int (attrs
, wid
, 1);
468 int l
= ms_obj_attr_get_int (attrs
, lid
, 1);
469 int typ
= ms_obj_attr_get_int (attrs
, typid
, 0);
470 xls_arrow_from_xl (&arrow
, width
, typ
, l
, w
);
471 g_object_set (so
, prop_name
, &arrow
, NULL
);
475 excel_fill_bmp_header(guint8
*bmphdr
, guint8
*data
, guint32 len
)
482 GSF_LE_SET_GUINT32 (bmphdr
+ 2, len
+ BMP_HDR_SIZE
);
483 GSF_LE_SET_GUINT16 (bmphdr
+ 6, 0);
484 GSF_LE_SET_GUINT16 (bmphdr
+ 8, 0);
485 bpp
= len
>= 20 ? GSF_LE_GET_GUINT16 (data
+ 18) : 1;
487 case 24: offset
= 0; break;
488 case 8: offset
= 256 * 3; break;
489 case 4: offset
= 16 * 3; break;
490 default: offset
= 2 * 3; break;
492 offset
+= BMP_HDR_SIZE
+ 2;
493 GSF_LE_SET_GUINT32 (bmphdr
+ 10, offset
);
497 ms_sheet_realize_obj (MSContainer
*container
, MSObj
*obj
)
500 PangoAttrList
*markup
;
502 ExcelReadSheet
*esheet
;
503 MSObjAttr
*attr
, *flip_h
, *flip_v
;
504 GODrawingAnchorDir direction
;
505 SheetObjectAnchor anchor
;
508 GnmSOAnchorMode mode
= GNM_SO_ANCHOR_TWO_CELLS
;
512 if (obj
->gnum_obj
== NULL
)
516 g_return_val_if_fail (container
!= NULL
, TRUE
);
517 esheet
= (ExcelReadSheet
*)container
;
519 /* our comment object is too weak. This anchor is for the text box,
520 * we need to store the indicator */
521 if (obj
->excel_type
== 0x19 &&
522 obj
->comment_pos
.col
>= 0 && obj
->comment_pos
.row
>= 0) {
523 cell_comment_set_pos (GNM_CELL_COMMENT (obj
->gnum_obj
),
526 attr
= ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_ANCHOR
);
528 g_printerr ("MISSING anchor for obj %p with id %d of type %s\n", (void *)obj
, obj
->id
, obj
->excel_type_name
);
532 if (ms_sheet_obj_anchor_to_pos (esheet
->sheet
, container
->importer
->ver
,
533 attr
->v
.v_ptr
, &range
, offsets
, &mode
))
536 flip_h
= ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_FLIP_H
);
537 flip_v
= ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_FLIP_V
);
539 ((flip_h
== NULL
) ? GOD_ANCHOR_DIR_RIGHT
: 0) |
540 ((flip_v
== NULL
) ? GOD_ANCHOR_DIR_DOWN
: 0);
542 sheet_object_anchor_init (&anchor
, &range
, offsets
, direction
, GNM_SO_ANCHOR_TWO_CELLS
);
543 sheet_object_set_anchor (so
, &anchor
);
545 sheet_object_set_sheet (so
, esheet
->sheet
);
546 if (mode
!= GNM_SO_ANCHOR_TWO_CELLS
)
547 sheet_object_set_anchor_mode (so
, &mode
);
551 if (ms_obj_attr_get_ptr (obj
->attrs
, MS_OBJ_ATTR_TEXT
, &label
, FALSE
))
552 g_object_set (G_OBJECT (so
), "text", label
, NULL
);
557 if (ms_obj_attr_get_ptr (obj
->attrs
, MS_OBJ_ATTR_OBJ_NAME
, &name
, FALSE
))
558 g_object_set (G_OBJECT (so
), "name", name
, NULL
);
561 markup
= ms_obj_attr_get_markup (obj
->attrs
, MS_OBJ_ATTR_MARKUP
, NULL
, FALSE
);
563 g_object_set (so
, "markup", markup
, NULL
);
565 switch (obj
->excel_type
) {
572 style
= go_style_new ();
573 style
->line
.color
= ms_sheet_map_color
574 (esheet
, obj
, MS_OBJ_ATTR_OUTLINE_COLOR
,
575 GO_COLOR_BLACK
, &style
->line
.auto_color
);
576 style
->line
.width
= ms_obj_attr_get_uint (obj
->attrs
,
577 MS_OBJ_ATTR_OUTLINE_WIDTH
, 0) / 256.;
578 style
->line
.auto_dash
=
579 (ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_OUTLINE_HIDE
) != NULL
);
580 style
->line
.dash_type
= style
->line
.auto_dash
582 : ms_escher_xl_to_line_type (ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_OUTLINE_STYLE
, 0));
584 width
= style
->line
.auto_width
? 0 : style
->line
.width
;
585 g_object_set (G_OBJECT (so
), "style", style
, NULL
);
586 g_object_unref (style
);
588 handle_arrow_head (so
, "start-arrow", width
,
590 MS_OBJ_ATTR_ARROW_START
,
591 MS_OBJ_ATTR_ARROW_START_WIDTH
,
592 MS_OBJ_ATTR_ARROW_START_LENGTH
);
593 handle_arrow_head (so
, "end-arrow", width
,
595 MS_OBJ_ATTR_ARROW_END
,
596 MS_OBJ_ATTR_ARROW_END_WIDTH
,
597 MS_OBJ_ATTR_ARROW_END_LENGTH
);
602 g_object_set (G_OBJECT (so
), "points",
603 ms_obj_attr_get_array (obj
->attrs
, MS_OBJ_ATTR_POLYGON_COORDS
, NULL
, TRUE
),
611 style
= go_style_new ();
612 style
->line
.color
= ms_sheet_map_color
613 (esheet
, obj
, MS_OBJ_ATTR_OUTLINE_COLOR
,
614 GO_COLOR_BLACK
, &style
->line
.auto_color
);
615 style
->line
.width
= ms_obj_attr_get_uint (obj
->attrs
,
616 MS_OBJ_ATTR_OUTLINE_WIDTH
, 0) / 256.;
617 style
->line
.auto_dash
= FALSE
;
618 style
->line
.dash_type
= (ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_OUTLINE_HIDE
) != NULL
)
620 : ms_escher_xl_to_line_type (ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_OUTLINE_STYLE
, 0));
621 style
->fill
.pattern
.back
= ms_sheet_map_color
622 (esheet
, obj
, MS_OBJ_ATTR_FILL_COLOR
,
623 GO_COLOR_WHITE
, &style
->fill
.auto_back
);
624 style
->fill
.pattern
.fore
= ms_sheet_map_color
625 (esheet
, obj
, MS_OBJ_ATTR_FILL_BACKGROUND
,
626 GO_COLOR_BLACK
, &style
->fill
.auto_fore
);
627 /* fill type needs work, we now suppot more than solid color */
628 style
->fill
.type
= ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_UNFILLED
)
629 ? GO_STYLE_FILL_NONE
: GO_STYLE_FILL_PATTERN
;
630 if (style
->fill
.type
!= GO_STYLE_FILL_PATTERN
)
631 style
->fill
.auto_type
= FALSE
;
633 g_object_set (G_OBJECT (so
), "style", style
, NULL
);
634 g_object_unref (style
);
638 /* NOTE : We should not need to do anything for charts */
645 double crop_left
= 0.0;
646 double crop_top
= 0.0;
647 double crop_right
= 0.0;
648 double crop_bottom
= 0.0;
650 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
651 MS_OBJ_ATTR_BLIP_ID
)) != NULL
) {
652 MSEscherBlip
*blip
= ms_container_get_blip (container
,
655 if (blip
->type
&& !strcmp (blip
->type
, "dib")) {
656 guint8
*data
= g_malloc(blip
->data_len
+ BMP_HDR_SIZE
);
658 excel_fill_bmp_header(data
, blip
->data
, blip
->data_len
);
659 memcpy(data
+ BMP_HDR_SIZE
, blip
->data
, blip
->data_len
);
660 sheet_object_image_set_image (GNM_SO_IMAGE (so
),
661 blip
->type
, data
, blip
->data_len
+ BMP_HDR_SIZE
);
665 sheet_object_image_set_image (GNM_SO_IMAGE (so
),
666 blip
->type
, blip
->data
, blip
->data_len
);
669 } else if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
670 MS_OBJ_ATTR_IMDATA
)) != NULL
) {
671 GdkPixbuf
*pixbuf
= GDK_PIXBUF (attr
->v
.v_object
);
677 gdk_pixbuf_save_to_buffer
678 (pixbuf
, &buf
, &buf_size
, "png",
681 sheet_object_image_set_image
683 "png", buf
, buf_size
);
688 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
689 MS_OBJ_ATTR_BLIP_CROP_LEFT
)) != NULL
)
690 crop_left
= (double) attr
->v
.v_uint
/ 65536.;
691 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
692 MS_OBJ_ATTR_BLIP_CROP_RIGHT
)) != NULL
)
693 crop_right
= (double) attr
->v
.v_uint
/ 65536.;
694 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
695 MS_OBJ_ATTR_BLIP_CROP_TOP
)) != NULL
)
696 crop_top
= (double) attr
->v
.v_uint
/ 65536.;
697 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
698 MS_OBJ_ATTR_BLIP_CROP_BOTTOM
)) != NULL
)
699 crop_bottom
= (double) attr
->v
.v_uint
/ 65536.;
701 sheet_object_image_set_crop (GNM_SO_IMAGE (so
),
702 crop_left
, crop_top
, crop_right
, crop_bottom
);
708 sheet_widget_checkbox_set_link (obj
->gnum_obj
,
709 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_LINKED_TO_CELL
, NULL
, FALSE
));
713 sheet_widget_radio_button_set_link (obj
->gnum_obj
,
714 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_LINKED_TO_CELL
, NULL
, FALSE
));
719 sheet_widget_adjustment_set_details (obj
->gnum_obj
,
720 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_LINKED_TO_CELL
, NULL
, FALSE
),
721 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_VALUE
, 0),
722 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_MIN
, 0),
723 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_MAX
, 100) - 1,
724 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_INC
, 1),
725 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_PAGE
, 10));
726 sheet_widget_adjustment_set_horizontal (obj
->gnum_obj
,
727 ms_obj_attr_get_uint (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_HORIZ
, FALSE
));
732 sheet_widget_list_base_set_links (obj
->gnum_obj
,
733 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_LINKED_TO_CELL
, NULL
, FALSE
),
734 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_INPUT_FROM
, NULL
, FALSE
));
737 case MSOT_COMMENT
: /* cell comment text box */
741 d (2, g_printerr ("EXCEL: unhandled excel object of type %s (0x%x) id = %d.",
742 obj
->excel_type_name
, obj
->excel_type
, obj
->id
););
750 ms_sheet_create_obj (MSContainer
*container
, MSObj
*obj
)
752 SheetObject
*so
= NULL
;
757 g_return_val_if_fail (container
!= NULL
, NULL
);
759 switch (obj
->excel_type
) {
762 so
= g_object_new (GNM_SO_LINE_TYPE
, NULL
);
765 case 0x00: /* draw the group border */
770 so
= g_object_new (GNM_SO_FILLED_TYPE
,
771 "is-oval", obj
->excel_type
== 3,
776 so
= sheet_object_graph_new (NULL
);
781 so
= g_object_new (sheet_widget_button_get_type (), NULL
);
784 so
= g_object_new (GNM_SO_IMAGE_TYPE
, NULL
); /* Picture */
787 so
= g_object_new (GNM_SO_POLYGON_TYPE
, NULL
);
790 so
= g_object_new (sheet_widget_checkbox_get_type (), NULL
);
793 so
= g_object_new (sheet_widget_radio_button_get_type (), NULL
);
796 so
= g_object_new (sheet_widget_spinbutton_get_type (), NULL
);
799 so
= g_object_new (sheet_widget_scrollbar_get_type (), NULL
);
802 so
= g_object_new (sheet_widget_list_get_type (), NULL
);
805 /* ignore combos associateed with filters */
807 ExcelReadSheet
*esheet
= (ExcelReadSheet
*)container
;
809 if (!obj
->auto_combo
)
810 so
= g_object_new (sheet_widget_combo_get_type (), NULL
);
812 /* ok, there are combos to go with the autofilter it can stay */
813 else if (esheet
!= NULL
)
814 esheet
->filter
= NULL
;
819 so
= g_object_new (cell_comment_get_type (), NULL
);
822 /* Gnumeric specific addition to handle toggle button controls */
824 so
= g_object_new (sheet_widget_toggle_button_get_type (), NULL
);
828 g_warning ("EXCEL: unhandled excel object of type %s (0x%x) id = %d.",
829 obj
->excel_type_name
, obj
->excel_type
, obj
->id
);
838 * @esheet ExcelReadSheet
840 * Excel only saves margins when any of the margins differs from the
841 * default. So we must initialize the margins to Excel's defaults, which
843 * Top, bottom: 1 in - 72 pt
844 * Left, right: 3/4 in - 48 pt
845 * Header, footer: 1/2 in - 36 pt
848 excel_init_margins (ExcelReadSheet
*esheet
)
850 GnmPrintInformation
*pi
;
854 g_return_if_fail (esheet
!= NULL
);
855 g_return_if_fail (esheet
->sheet
!= NULL
);
856 g_return_if_fail (esheet
->sheet
->print_info
!= NULL
);
858 pi
= esheet
->sheet
->print_info
;
859 print_info_set_edge_to_below_header (pi
,GO_IN_TO_PT (1.0));
860 print_info_set_edge_to_above_footer (pi
,GO_IN_TO_PT (1.0));
862 points
= GO_IN_TO_PT (0.75);
863 short_points
= GO_IN_TO_PT (0.5);
864 print_info_set_margins (pi
, short_points
, short_points
, points
, points
);
868 excel_shared_formula_free (XLSharedFormula
*sf
)
876 static ExcelReadSheet
*
877 excel_sheet_new (GnmXLImporter
*importer
, char const *sheet_name
, GnmSheetType type
)
879 static MSContainerClass
const vtbl
= {
880 &ms_sheet_realize_obj
,
881 &ms_sheet_create_obj
,
882 &ms_sheet_parse_expr
,
887 int rows
= (importer
->ver
>= MS_BIFF_V8
? XLS_MaxRow_V8
: XLS_MaxRow_V7
);
888 ExcelReadSheet
*esheet
;
891 sheet
= workbook_sheet_by_name (importer
->wb
, sheet_name
);
895 for (ui
= 0; ui
< importer
->excel_sheets
->len
; ui
++) {
896 ExcelReadSheet
*es
= g_ptr_array_index (importer
->excel_sheets
, ui
);
897 if (es
->sheet
== sheet
) {
898 g_warning ("Duplicate definition of sheet %s\n", sheet_name
);
903 sheet
= sheet_new_with_type (importer
->wb
, sheet_name
, type
,
905 workbook_sheet_attach (importer
->wb
, sheet
);
906 d (1, g_printerr ("Adding sheet '%s'\n", sheet_name
););
909 /* Flag a respan here in case nothing else does */
910 sheet_flag_recompute_spans (sheet
);
912 esheet
= g_new (ExcelReadSheet
, 1);
913 esheet
->sheet
= sheet
;
914 esheet
->filter
= NULL
;
915 esheet
->freeze_panes
= FALSE
;
916 esheet
->active_pane
= 3; /* The default */
917 esheet
->shared_formulae
= g_hash_table_new_full
918 ((GHashFunc
)&gnm_cellpos_hash
,
919 (GCompareFunc
)&gnm_cellpos_equal
,
920 NULL
, (GDestroyNotify
) &excel_shared_formula_free
);
921 esheet
->tables
= g_hash_table_new_full
922 ((GHashFunc
)&gnm_cellpos_hash
,
923 (GCompareFunc
)&gnm_cellpos_equal
,
924 NULL
, (GDestroyNotify
) g_free
);
925 esheet
->biff2_prev_xf_index
= -1;
927 excel_init_margins (esheet
);
928 ms_container_init (&esheet
->container
, &vtbl
,
929 &importer
->container
, importer
);
930 g_ptr_array_add (importer
->excel_sheets
, esheet
);
936 excel_unexpected_biff (BiffQuery
*q
, char const *state
,
939 #ifndef NO_DEBUG_EXCEL
940 if (debug_level
> 1) {
941 g_print ("Unexpected Opcode in %s: 0x%hx, length 0x%x\n",
942 state
, q
->opcode
, q
->length
);
944 gsf_mem_dump (q
->data
, q
->length
);
950 * excel_read_string_header :
951 * @data: a pointer to the start of the string header
952 * @maxlen: the length of the data area
953 * @use_utf16: Is the content in 8 or 16 bit chars
954 * @n_markup: number of trailing markup records
955 * @has_extended: Is there trailing extended string info (eg japanese PHONETIC)
958 * returns the length of the header (in bytes)
961 excel_read_string_header (guint8
const *data
, guint32 maxlen
,
964 gboolean
*has_extended
,
965 unsigned *post_data_len
)
970 if (G_UNLIKELY (maxlen
< 1))
973 header
= GSF_LE_GET_GUINT8 (data
);
974 if (((header
& 0xf2) != 0))
977 *use_utf16
= (header
& 0x1) != 0;
979 if ((header
& 0x8) != 0) {
980 if (G_UNLIKELY (maxlen
< 3))
982 *n_markup
= GSF_LE_GET_GUINT16 (data
+ 1);
983 *post_data_len
= *n_markup
* 4; /* 4 bytes per */
991 *has_extended
= (header
& 0x4) != 0;
995 if (G_UNLIKELY (maxlen
< len
+ 4))
997 len_ext_rst
= GSF_LE_GET_GUINT32 (data
+ len
); /* A byte length */
998 *post_data_len
+= len_ext_rst
;
1001 d (4, g_printerr ("Extended string support unimplemented; "
1002 "ignoring %u bytes\n", len_ext_rst
););
1008 *use_utf16
= *has_extended
= FALSE
;
1011 g_warning ("Invalid string record.");
1016 excel_get_chars (GnmXLImporter
const *importer
,
1017 guint8
const *ptr
, size_t length
, gboolean use_utf16
, guint16
const *codepage
)
1021 GIConv str_iconv
= importer
->str_iconv
;
1024 gunichar2
*uni_text
= g_alloca (sizeof (gunichar2
)*length
);
1026 for (i
= 0; i
< length
; i
++, ptr
+= 2)
1027 uni_text
[i
] = GSF_LE_GET_GUINT16 (ptr
);
1028 ans
= g_utf16_to_utf8 (uni_text
, length
, NULL
, NULL
, NULL
);
1030 size_t outbytes
= (length
+ 2) * 8;
1031 char *outbuf
= g_new (char, outbytes
+ 1);
1032 char *ptr2
= (char *)ptr
;
1035 if (NULL
!= codepage
)
1036 str_iconv
= gsf_msole_iconv_open_for_import (*codepage
);
1038 &ptr2
, &length
, &outbuf
, &outbytes
);
1040 g_iconv_close (str_iconv
);
1044 ans
= g_realloc (ans
, i
+ 1);
1050 excel_get_text (GnmXLImporter
const *importer
,
1051 guint8
const *pos
, guint32 length
,
1052 guint32
*byte_length
, guint16
const *codepage
, guint32 maxlen
)
1056 unsigned byte_len
, trailing_data_len
, n_markup
, str_len_bytes
;
1057 gboolean use_utf16
, has_extended
;
1059 if (byte_length
== NULL
)
1060 byte_length
= &byte_len
;
1062 if (importer
->ver
>= MS_BIFF_V8
) {
1063 *byte_length
= 1; /* the header */
1066 ptr
= pos
+ excel_read_string_header
1068 &use_utf16
, &n_markup
, &has_extended
,
1069 &trailing_data_len
);
1070 *byte_length
+= trailing_data_len
;
1072 *byte_length
= 0; /* no header */
1075 trailing_data_len
= 0;
1076 use_utf16
= has_extended
= FALSE
;
1081 str_len_bytes
= (use_utf16
? 2 : 1) * length
;
1083 if (*byte_length
> maxlen
) {
1084 *byte_length
= maxlen
;
1086 } else if (maxlen
- *byte_length
< str_len_bytes
) {
1087 *byte_length
= maxlen
;
1088 length
= (maxlen
- *byte_length
) / (use_utf16
? 2 : 1);
1090 *byte_length
+= str_len_bytes
;
1092 ans
= excel_get_chars (importer
, ptr
, length
, use_utf16
, codepage
);
1095 g_printerr ("String len %d, byte length %d: %s %s %s:\n",
1096 length
, *byte_length
,
1097 (use_utf16
? "UTF16" : "1byte"),
1098 ((n_markup
> 0) ? "has markup" :""),
1099 (has_extended
? "has extended phonetic info" : ""));
1100 gsf_mem_dump (pos
, *byte_length
);
1107 excel_biff_text (GnmXLImporter
const *importer
,
1108 const BiffQuery
*q
, guint32 ofs
, guint32 length
)
1110 XL_CHECK_CONDITION_VAL (q
->length
>= ofs
, NULL
);
1112 return excel_get_text (importer
, q
->data
+ ofs
, length
,
1113 NULL
, NULL
, q
->length
- ofs
);
1117 excel_biff_text_1 (GnmXLImporter
const *importer
,
1118 const BiffQuery
*q
, guint32 ofs
)
1122 XL_CHECK_CONDITION_VAL (q
->length
>= (ofs
+ 1), NULL
);
1124 length
= GSF_LE_GET_GUINT8 (q
->data
+ ofs
);
1127 return excel_get_text (importer
, q
->data
+ ofs
, length
,
1128 NULL
, NULL
, q
->length
- ofs
);
1132 excel_biff_text_2 (GnmXLImporter
const *importer
,
1133 const BiffQuery
*q
, guint32 ofs
)
1137 XL_CHECK_CONDITION_VAL (q
->length
>= (ofs
+ 2), NULL
);
1139 length
= GSF_LE_GET_GUINT16 (q
->data
+ ofs
);
1142 return excel_get_text (importer
, q
->data
+ ofs
, length
,
1143 NULL
, NULL
, q
->length
- ofs
);
1147 unsigned first
, last
;
1148 PangoAttrList
*accum
;
1152 append_markup (PangoAttribute
*src
, TXORun
*run
)
1154 if (run
->last
> run
->first
) {
1155 PangoAttribute
*dst
= pango_attribute_copy (src
);
1156 dst
->start_index
= run
->first
; /* inclusive */
1157 dst
->end_index
= run
->last
; /* exclusive */
1158 pango_attr_list_change (run
->accum
, dst
);
1164 excel_read_LABEL_markup (BiffQuery
*q
, ExcelReadSheet
*esheet
,
1165 char const *str
, unsigned str_len
)
1167 guint8
const * const end
= q
->data
+ q
->length
;
1168 guint8
const *ptr
= q
->data
+ 8 + str_len
;
1169 MSContainer
const *c
= &esheet
->container
;
1172 unsigned int clen
= g_utf8_strlen (str
, -1);
1175 g_printerr ("strlen=%d len=%d\n", str_len
, (int)strlen (str
));
1176 ms_biff_query_dump (q
);
1179 txo_run
.last
= strlen (str
);
1181 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
1182 XL_CHECK_CONDITION_VAL (ptr
+2 <= end
, NULL
);
1183 n
= 4 * GSF_LE_GET_GUINT16 (ptr
);
1186 XL_CHECK_CONDITION_VAL (ptr
+ n
== end
, NULL
);
1188 txo_run
.accum
= pango_attr_list_new ();
1194 o
= GSF_LE_GET_GUINT16 (ptr
+ n
);
1195 l
= GSF_LE_GET_GUINT16 (ptr
+ n
+ 2);
1196 XL_CHECK_CONDITION_VAL (o
<= clen
,
1197 go_format_new_markup (txo_run
.accum
, FALSE
));
1199 txo_run
.first
= g_utf8_offset_to_pointer (str
, o
) - str
;
1200 XL_CHECK_CONDITION_VAL (txo_run
.first
< txo_run
.last
,
1201 go_format_new_markup (txo_run
.accum
, FALSE
));
1203 pango_attr_list_filter (ms_container_get_markup (c
, l
),
1204 (PangoAttrFilterFunc
) append_markup
,
1206 txo_run
.last
= txo_run
.first
;
1209 XL_CHECK_CONDITION_VAL (ptr
+1 <= end
, NULL
);
1210 n
= 2 * GSF_LE_GET_GUINT8 (ptr
);
1213 XL_CHECK_CONDITION_VAL (ptr
+ n
== end
, NULL
);
1215 txo_run
.accum
= pango_attr_list_new ();
1218 txo_run
.first
= g_utf8_offset_to_pointer (str
,
1219 GSF_LE_GET_GUINT8 (ptr
+ n
)) - str
;
1220 pango_attr_list_filter (ms_container_get_markup (
1221 c
, GSF_LE_GET_GUINT8 (ptr
+ n
+ 1)),
1222 (PangoAttrFilterFunc
) append_markup
, &txo_run
);
1223 txo_run
.last
= txo_run
.first
;
1226 return go_format_new_markup (txo_run
.accum
, FALSE
);
1230 * NB. Whilst the string proper is split, and whilst we get several headers,
1231 * it seems that the attributes appear in a single block after the end
1232 * of the string, which may also be split over continues.
1235 sst_read_string (BiffQuery
*q
, MSContainer
const *c
,
1236 ExcelStringEntry
*res
, guint32 offset
)
1238 guint32 get_len
, chars_left
, total_len
, total_end_len
= 0;
1239 unsigned i
, post_data_len
, n_markup
, total_n_markup
= 0;
1240 gboolean use_utf16
, has_extended
;
1241 char *str
, *old_res
, *res_str
= NULL
;
1243 offset
= ms_biff_query_bound_check (q
, offset
, 2);
1244 if (offset
== (guint32
)-1)
1246 XL_CHECK_CONDITION_VAL (offset
< q
->length
, offset
);
1247 total_len
= GSF_LE_GET_GUINT16 (q
->data
+ offset
);
1250 offset
= ms_biff_query_bound_check (q
, offset
, 1);
1251 if (offset
== (guint32
)-1) {
1255 offset
+= excel_read_string_header
1256 (q
->data
+ offset
, q
->length
- offset
,
1257 &use_utf16
, &n_markup
, &has_extended
,
1259 total_end_len
+= post_data_len
;
1260 total_n_markup
+= n_markup
;
1261 chars_left
= (q
->length
- offset
) / (use_utf16
? 2 : 1);
1262 get_len
= (chars_left
> total_len
) ? total_len
: chars_left
;
1263 total_len
-= get_len
;
1265 str
= excel_get_chars (c
->importer
,
1266 q
->data
+ offset
, get_len
, use_utf16
, NULL
);
1267 offset
+= get_len
* (use_utf16
? 2 : 1);
1269 /* Handle corrupted string. */
1271 str
= g_strdup ("");
1273 if (res_str
!= NULL
) {
1275 res_str
= g_strconcat (old_res
, str
, NULL
);
1280 } while (total_len
> 0);
1282 if (total_n_markup
> 0) {
1284 PangoAttrList
*prev_markup
= NULL
;
1286 txo_run
.accum
= pango_attr_list_new ();
1288 for (i
= total_n_markup
; i
-- > 0 ; offset
+= 4) {
1289 offset
= ms_biff_query_bound_check (q
, offset
, 4);
1290 if (offset
== (guint32
)-1) {
1292 pango_attr_list_unref (txo_run
.accum
);
1295 if ((q
->length
>= offset
+ 4)) {
1296 guint16 o
= GSF_LE_GET_GUINT16 (q
->data
+ offset
);
1297 size_t l
= strlen (res_str
);
1298 txo_run
.last
= g_utf8_offset_to_pointer (res_str
, MIN (o
, l
)) - res_str
;
1299 if (prev_markup
!= NULL
)
1300 pango_attr_list_filter (prev_markup
,
1301 (PangoAttrFilterFunc
) append_markup
, &txo_run
);
1302 txo_run
.first
= txo_run
.last
;
1303 prev_markup
= ms_container_get_markup (
1304 c
, GSF_LE_GET_GUINT16 (q
->data
+ offset
+ 2));
1306 g_warning ("A TXO entry is across CONTINUEs. We need to handle those properly");
1308 txo_run
.last
= G_MAXINT
;
1309 pango_attr_list_filter (prev_markup
,
1310 (PangoAttrFilterFunc
) append_markup
, &txo_run
);
1311 res
->markup
= go_format_new_markup (txo_run
.accum
, FALSE
);
1313 total_end_len
-= 4*total_n_markup
;
1316 res
->content
= go_string_new_nocopy (res_str
);
1317 return offset
+ total_end_len
;
1321 excel_read_SST (BiffQuery
*q
, GnmXLImporter
*importer
)
1324 unsigned i
, sst_len
;
1326 XL_CHECK_CONDITION (q
->length
>= 8);
1329 g_printerr ("SST total = %u, sst = %u\n",
1330 GSF_LE_GET_GUINT32 (q
->data
+ 0),
1331 GSF_LE_GET_GUINT32 (q
->data
+ 4));
1332 gsf_mem_dump (q
->data
, q
->length
);
1335 sst_len
= GSF_LE_GET_GUINT32 (q
->data
+ 4);
1336 XL_CHECK_CONDITION (sst_len
< INT_MAX
/ sizeof (ExcelStringEntry
));
1338 importer
->sst_len
= sst_len
;
1339 importer
->sst
= g_new0 (ExcelStringEntry
, importer
->sst_len
);
1342 for (i
= 0; i
< importer
->sst_len
; i
++) {
1343 offset
= sst_read_string (q
, &importer
->container
, importer
->sst
+ i
, offset
);
1344 if (offset
== (guint32
)-1)
1347 if (importer
->sst
[i
].content
== NULL
)
1348 d (4, g_printerr ("Blank string in table at 0x%x.\n", i
););
1349 #ifndef NO_DEBUG_EXCEL
1350 else if (ms_excel_read_debug
> 4)
1351 g_printerr ("%s\n", importer
->sst
[i
].content
->str
);
1357 excel_read_EXSST (BiffQuery
*q
, GnmXLImporter
*importer
)
1359 XL_CHECK_CONDITION (q
->length
>= 2);
1360 d (10, g_printerr ("Bucketsize = %hu,\tnum buckets = %d\n",
1361 GSF_LE_GET_GUINT16 (q
->data
), (q
->length
- 2) / 8););
1365 excel_read_1904 (BiffQuery
*q
, GnmXLImporter
*importer
)
1367 XL_CHECK_CONDITION (q
->length
>= 2);
1368 if (GSF_LE_GET_GUINT16 (q
->data
) == 1)
1369 workbook_set_1904 (importer
->wb
, TRUE
);
1373 xls_value_new_err (GnmEvalPos
const *pos
, guint8 err
)
1376 case 0: return value_new_error_NULL (pos
);
1377 case 7: return value_new_error_DIV0 (pos
);
1378 case 15: return value_new_error_VALUE (pos
);
1379 case 23: return value_new_error_REF (pos
);
1380 case 29: return value_new_error_NAME (pos
);
1381 case 36: return value_new_error_NUM (pos
);
1382 case 42: return value_new_error_NA (pos
);
1383 default: return value_new_error (pos
, _("#UNKNOWN!"));
1388 ms_biff_bof_data_new (BiffQuery
*q
)
1390 MsBiffBofData
*ans
= g_new (MsBiffBofData
, 1);
1392 if (q
->length
>= 4) {
1394 /* Determine type from BOF */
1395 switch (q
->opcode
) {
1396 case BIFF_BOF_v0
: ans
->version
= MS_BIFF_V2
; break;
1397 case BIFF_BOF_v2
: ans
->version
= MS_BIFF_V3
; break;
1398 case BIFF_BOF_v4
: ans
->version
= MS_BIFF_V4
; break;
1401 g_printerr ("Complicated BIFF version 0x%x\n",
1402 GSF_LE_GET_GUINT16 (q
->non_decrypted_data
));
1403 gsf_mem_dump (q
->non_decrypted_data
, q
->length
);
1406 switch (GSF_LE_GET_GUINT16 (q
->non_decrypted_data
)) {
1408 ans
->version
= MS_BIFF_V8
;
1410 case 0x0500: /* * OR ebiff7: FIXME ? ! */
1411 ans
->version
= MS_BIFF_V7
;
1413 /* The following are non-standard records written
1414 by buggy tools. Taken from OO docs. */
1416 ans
->version
= MS_BIFF_V4
;
1419 ans
->version
= MS_BIFF_V3
;
1424 ans
->version
= MS_BIFF_V2
;
1427 g_printerr ("Unknown BIFF sub-number 0x%X in BOF %x\n",
1428 GSF_LE_GET_GUINT16 (q
->non_decrypted_data
), q
->opcode
);
1429 ans
->version
= MS_BIFF_V_UNKNOWN
;
1434 g_printerr ("Unknown BIFF number in BOF %x\n", q
->opcode
);
1435 ans
->version
= MS_BIFF_V_UNKNOWN
;
1436 g_printerr ("Biff version %d\n", ans
->version
);
1438 switch (GSF_LE_GET_GUINT16 (q
->non_decrypted_data
+ 2)) {
1439 case 0x0005: ans
->type
= MS_BIFF_TYPE_Workbook
; break;
1440 case 0x0006: ans
->type
= MS_BIFF_TYPE_VBModule
; break;
1441 case 0x0010: ans
->type
= MS_BIFF_TYPE_Worksheet
; break;
1442 case 0x0020: ans
->type
= MS_BIFF_TYPE_Chart
; break;
1443 case 0x0040: ans
->type
= MS_BIFF_TYPE_Macrosheet
; break;
1444 case 0x0100: ans
->type
= MS_BIFF_TYPE_Workspace
; break;
1446 ans
->type
= MS_BIFF_TYPE_Unknown
;
1447 g_printerr ("Unknown BIFF type in BOF %x\n", GSF_LE_GET_GUINT16 (q
->non_decrypted_data
+ 2));
1450 /* Now store in the directory array: */
1451 d (2, g_printerr ("BOF %x, %d == %d, %d\n", q
->opcode
, q
->length
,
1452 ans
->version
, ans
->type
););
1454 g_printerr ("Not a BOF !\n");
1455 ans
->version
= MS_BIFF_V_UNKNOWN
;
1456 ans
->type
= MS_BIFF_TYPE_Unknown
;
1463 ms_biff_bof_data_destroy (MsBiffBofData
*data
)
1469 excel_read_BOUNDSHEET (BiffQuery
*q
, GnmXLImporter
*importer
)
1471 BiffBoundsheetData
*bs
;
1472 char const *default_name
= "Unknown%d";
1473 gboolean oldstyle
= (importer
->ver
<= MS_BIFF_V4
);
1475 XL_CHECK_CONDITION (q
->length
>= (oldstyle
? 1 : 6));
1477 bs
= g_new0 (BiffBoundsheetData
, 1);
1478 bs
->gnm_type
= GNM_SHEET_DATA
;
1481 bs
->streamStartPos
= 0; /* Excel 4 doesn't tell us */
1482 bs
->type
= MS_BIFF_TYPE_Worksheet
;
1483 default_name
= _("Sheet%d");
1484 bs
->visibility
= GNM_SHEET_VISIBILITY_VISIBLE
;
1485 bs
->name
= excel_biff_text_1 (importer
, q
, 0);
1487 if (importer
->ver
> MS_BIFF_V8
)
1488 g_printerr ("Unknown BIFF Boundsheet spec. Assuming same as Biff7 FIXME\n");
1489 bs
->streamStartPos
= GSF_LE_GET_GUINT32 (q
->non_decrypted_data
);
1491 /* NOTE : MS Docs appear wrong. It is visibility _then_ type */
1492 switch (GSF_LE_GET_GUINT8 (q
->data
+ 5)) {
1493 case 0: bs
->type
= MS_BIFF_TYPE_Worksheet
;
1494 default_name
= _("Sheet%d");
1496 case 1: bs
->type
= MS_BIFF_TYPE_Macrosheet
;
1497 bs
->gnm_type
= GNM_SHEET_XLM
;
1498 default_name
= _("Macro%d");
1500 case 2: bs
->type
= MS_BIFF_TYPE_Chart
;
1501 bs
->gnm_type
= GNM_SHEET_OBJECT
;
1502 default_name
= _("Chart%d");
1504 case 6: bs
->type
= MS_BIFF_TYPE_VBModule
;
1505 default_name
= _("Module%d");
1508 g_printerr ("Unknown boundsheet type: %d\n", GSF_LE_GET_GUINT8 (q
->data
+ 4));
1509 bs
->type
= MS_BIFF_TYPE_Unknown
;
1511 switch ((GSF_LE_GET_GUINT8 (q
->data
+ 4)) & 0x3) {
1512 case 0: bs
->visibility
= GNM_SHEET_VISIBILITY_VISIBLE
;
1514 case 1: bs
->visibility
= GNM_SHEET_VISIBILITY_HIDDEN
;
1516 case 2: bs
->visibility
= GNM_SHEET_VISIBILITY_VERY_HIDDEN
;
1519 g_printerr ("Unknown sheet hiddenness %d\n", (GSF_LE_GET_GUINT8 (q
->data
+ 4)) & 0x3);
1520 bs
->visibility
= GNM_SHEET_VISIBILITY_VISIBLE
;
1523 /* TODO: find some documentation on this.
1524 * Sample data and OpenCalc imply that the docs are incorrect. It
1525 * seems like the name length is 1 byte. Loading sample sheets in
1526 * other locales universally seem to treat the first byte as a length
1527 * and the second as the unicode flag header.
1529 bs
->name
= excel_biff_text_1 (importer
, q
, 6);
1532 /* TODO: find some documentation on this.
1533 * It appears that if the name is null it defaults to Sheet%d?
1534 * However, we have only one test case and no docs.
1536 if (bs
->name
== NULL
|| bs
->name
[0] == 0) {
1538 bs
->name
= g_strdup_printf (default_name
,
1539 importer
->boundsheet_sheet_by_index
->len
+ 1);
1543 case MS_BIFF_TYPE_Worksheet
:
1544 case MS_BIFF_TYPE_Macrosheet
:
1545 case MS_BIFF_TYPE_Chart
:
1546 bs
->esheet
= excel_sheet_new (importer
, bs
->name
, bs
->gnm_type
);
1548 if (bs
->esheet
&& bs
->esheet
->sheet
)
1549 g_object_set (bs
->esheet
->sheet
,
1550 "visibility", bs
->visibility
,
1557 bs
->index
= importer
->boundsheet_sheet_by_index
->len
;
1558 g_ptr_array_add (importer
->boundsheet_sheet_by_index
, bs
->esheet
? bs
->esheet
->sheet
: NULL
);
1559 g_hash_table_insert (importer
->boundsheet_data_by_stream
,
1560 GUINT_TO_POINTER (bs
->streamStartPos
), bs
);
1562 d (1, g_printerr ("Boundsheet: %d) '%s' %p, %d:%d\n", bs
->index
,
1563 bs
->name
, bs
->esheet
, bs
->type
, bs
->visibility
););
1567 biff_boundsheet_data_destroy (BiffBoundsheetData
*d
)
1574 excel_read_FORMAT (BiffQuery
*q
, GnmXLImporter
*importer
)
1576 MsBiffVersion
const ver
= importer
->ver
;
1579 if (ver
>= MS_BIFF_V7
) {
1580 XL_CHECK_CONDITION (q
->length
>= 4);
1582 d
= g_new (BiffFormatData
, 1);
1583 d
->idx
= GSF_LE_GET_GUINT16 (q
->data
);
1584 d
->name
= (ver
>= MS_BIFF_V8
)
1585 ? excel_biff_text_2 (importer
, q
, 2)
1586 : excel_biff_text_1 (importer
, q
, 2);
1588 size_t minlen
= (ver
>= MS_BIFF_V4
? 3 : 1);
1589 XL_CHECK_CONDITION (q
->length
>= minlen
);
1591 d
= g_new (BiffFormatData
, 1);
1592 /* no usable index */
1593 d
->idx
= g_hash_table_size (importer
->format_table
);
1594 d
->name
= (ver
>= MS_BIFF_V4
)
1595 ? excel_biff_text_1 (importer
, q
, 2)
1596 : excel_biff_text_1 (importer
, q
, 0);
1599 d (3, g_printerr ("Format data: 0x%x == '%s'\n", d
->idx
, d
->name
););
1601 g_hash_table_insert (importer
->format_table
, GUINT_TO_POINTER (d
->idx
), d
);
1605 excel_read_FONT (BiffQuery
*q
, GnmXLImporter
*importer
)
1607 MsBiffVersion
const ver
= importer
->ver
;
1612 XL_CHECK_CONDITION (q
->length
>= 4);
1614 fd
= g_new (ExcelFont
, 1);
1615 fd
->height
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
1616 data
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
1617 fd
->italic
= (data
& 0x2) == 0x2;
1618 fd
->struck_out
= (data
& 0x8) == 0x8;
1619 fd
->script
= GO_FONT_SCRIPT_STANDARD
;
1620 fd
->underline
= XLS_ULINE_NONE
;
1621 fd
->codepage
= 1252;
1623 if (ver
<= MS_BIFF_V2
) {
1626 fd
->boldness
= (data
& 0x1) ? 0x2bc : 0x190;
1627 fd
->underline
= (data
& 0x4) ? XLS_ULINE_SINGLE
: XLS_ULINE_NONE
;
1628 fd
->fontname
= excel_biff_text_1 (importer
, q
, 4);
1629 if (ms_biff_query_peek_next (q
, &opcode
) &&
1630 opcode
== BIFF_FONT_COLOR
) {
1631 ms_biff_query_next (q
);
1632 XL_CHECK_CONDITION (q
->length
>= 2);
1633 fd
->color_idx
= GSF_LE_GET_GUINT16 (q
->data
);
1635 fd
->color_idx
= 0x7f;
1636 cp
= gnm_font_override_codepage (fd
->fontname
);
1637 fd
->codepage
= (cp
> 0 ? cp
: 1252);
1638 } else if (ver
<= MS_BIFF_V4
) /* Guess */ {
1640 XL_CHECK_CONDITION (q
->length
>= 6);
1641 fd
->color_idx
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
1642 fd
->boldness
= (data
& 0x1) ? 0x2bc : 0x190;
1643 fd
->underline
= (data
& 0x4) ? XLS_ULINE_SINGLE
: XLS_ULINE_NONE
;
1644 fd
->fontname
= excel_biff_text_1 (importer
, q
, 6);
1645 cp
= gnm_font_override_codepage (fd
->fontname
);
1646 fd
->codepage
= (cp
> 0 ? cp
: 1252);
1648 XL_CHECK_CONDITION (q
->length
>= 13);
1650 fd
->color_idx
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
1651 fd
->boldness
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
1652 data
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
1654 case 0: fd
->script
= GO_FONT_SCRIPT_STANDARD
; break;
1655 case 1: fd
->script
= GO_FONT_SCRIPT_SUPER
; break;
1656 case 2: fd
->script
= GO_FONT_SCRIPT_SUB
; break;
1658 g_printerr ("Unknown script %d\n", data
);
1662 data1
= GSF_LE_GET_GUINT8 (q
->data
+ 10);
1664 case 0: fd
->underline
= XLS_ULINE_NONE
; break;
1665 case 1: fd
->underline
= XLS_ULINE_SINGLE
; break;
1666 case 2: fd
->underline
= XLS_ULINE_DOUBLE
; break;
1667 case 0x21: fd
->underline
= XLS_ULINE_SINGLE_ACC
; break; /* single accounting */
1668 case 0x22: fd
->underline
= XLS_ULINE_DOUBLE_ACC
; break; /* double accounting */
1670 g_printerr ("Unknown uline %#x\n", (int)data1
);
1673 fd
->fontname
= excel_biff_text_1 (importer
, q
, 14);
1675 data1
= GSF_LE_GET_GUINT8 (q
->data
+ 12);
1678 int cp
= gnm_font_override_codepage (fd
->fontname
);
1683 if (importer
->codepage_override
> 0) {
1684 fd
->codepage
= importer
->codepage_override
;
1690 case 255: fd
->codepage
= 1252; break; /* ANSI Latin, System Default, OEM Latin I */
1691 case 77: fd
->codepage
= 10000; break; /* Apple */
1692 case 128: fd
->codepage
= 932; break; /* Japanese Shift-JIS */
1693 case 129: fd
->codepage
= 949; break; /* Korean Hangul */
1694 case 130: fd
->codepage
= 1361; break; /* Korean Johab */
1695 case 134: fd
->codepage
= 936; break; /* Chinese Simplified */
1696 case 136: fd
->codepage
= 950; break; /* Chinese Traditional */
1697 case 161: fd
->codepage
= 1253; break; /* Greek */
1698 case 162: fd
->codepage
= 1254; break; /* Turkish */
1699 case 163: fd
->codepage
= 1258; break; /* Vietnamese */
1700 case 177: fd
->codepage
= 1255; break; /* Hebrew */
1701 case 178: fd
->codepage
= 1256; break; /* Arabic */
1702 case 186: fd
->codepage
= 1257; break; /* Baltic */
1703 case 204: fd
->codepage
= 1251; break; /* Russian */
1704 case 222: fd
->codepage
= 874; break; /* Thai */
1705 case 238: fd
->codepage
= 1250; break; /* Central European */
1707 g_printerr ("Unknown charset %#x\n", (int) data1
);
1711 fd
->color_idx
&= 0x7f; /* Undocumented but a good idea */
1713 if (fd
->fontname
== NULL
) {
1714 /* Note sure why -- see #418868. */
1715 fd
->fontname
= g_strdup ("Arial");
1721 fd
->index
= g_hash_table_size (importer
->font_data
);
1722 if (fd
->index
>= 4) /* Weird: for backwards compatibility */
1724 d (1, g_printerr ("Insert font '%s' (%d) size %d pts color %d\n",
1725 fd
->fontname
, fd
->index
, fd
->height
/ 20, fd
->color_idx
););
1726 d (3, g_printerr ("Font color = 0x%x\n", fd
->color_idx
););
1728 g_hash_table_insert (importer
->font_data
,
1729 GINT_TO_POINTER (fd
->index
), fd
);
1734 excel_font_free (ExcelFont
*fd
)
1736 if (NULL
!= fd
->attrs
) {
1737 pango_attr_list_unref (fd
->attrs
);
1740 if (NULL
!= fd
->go_font
) {
1741 go_font_unref (fd
->go_font
);
1744 g_free (fd
->fontname
);
1749 biff_format_data_destroy (BiffFormatData
*d
)
1755 /** Default color table for BIFF5/BIFF7. */
1756 ExcelPaletteEntry
const excel_default_palette_v7
[] = {
1757 { 0, 0, 0}, {255,255,255}, {255, 0, 0}, { 0,255, 0},
1758 { 0, 0,255}, {255,255, 0}, {255, 0,255}, { 0,255,255},
1760 {128, 0, 0}, { 0,128, 0}, { 0, 0,128}, {128,128, 0},
1761 {128, 0,128}, { 0,128,128}, {192,192,192}, {128,128,128},
1763 {128,128,255}, {128, 32, 96}, {255,255,192}, {160,224,224},
1764 { 96, 0,128}, {255,128,128}, { 0,128,192}, {192,192,255},
1766 { 0, 0,128}, {255, 0,255}, {255,255, 0}, { 0,255,255},
1767 {128, 0,128}, {128, 0, 0}, { 0,128,128}, { 0, 0,255},
1769 { 0,204,255}, {105,255,255}, {204,255,204}, {255,255,153},
1770 {166,202,240}, {204,156,204}, {204,153,255}, {227,227,227},
1772 { 51,102,255}, { 51,204,204}, { 51,153, 51}, {153,153, 51},
1773 {153,102, 51}, {153,102,102}, {102,102,153}, {150,150,150},
1775 { 51, 51,204}, { 51,102,102}, { 0, 51, 0}, { 51, 51, 0},
1776 {102, 51, 0}, {153, 51,102}, { 51, 51,153}, { 66, 66, 66}
1779 ExcelPaletteEntry
const excel_default_palette_v8
[] = {
1780 { 0, 0, 0}, {255,255,255}, {255, 0, 0}, { 0,255, 0},
1781 { 0, 0,255}, {255,255, 0}, {255, 0,255}, { 0,255,255},
1783 {128, 0, 0}, { 0,128, 0}, { 0, 0,128}, {128,128, 0},
1784 {128, 0,128}, { 0,128,128}, {192,192,192}, {128,128,128},
1786 {153,153,255}, {153, 51,102}, {255,255,204}, {204,255,255},
1787 {102, 0,102}, {255,128,128}, { 0,102,204}, {204,204,255},
1789 { 0, 0,128}, {255, 0,255}, {255,255, 0}, { 0,255,255},
1790 {128, 0,128}, {128, 0, 0}, { 0,128,128}, { 0, 0,255},
1792 { 0,204,255}, {204,255,255}, {204,255,204}, {255,255,153},
1793 {153,204,255}, {255,153,204}, {204,153,255}, {255,204,153},
1795 { 51,102,255}, { 51,204,204}, {153,204, 0}, {255,204, 0},
1796 {255,153, 0}, {255,102, 0}, {102,102,153}, {150,150,150},
1798 { 0, 51,102}, { 51,153,102}, { 0, 51, 0}, { 51, 51, 0},
1799 {153, 51, 0}, {153, 51,102}, { 51, 51,153}, { 51, 51, 51}
1803 excel_palette_get (GnmXLImporter
*importer
, gint idx
)
1807 /* return black on failure */
1808 g_return_val_if_fail (importer
!= NULL
, style_color_black ());
1810 if (NULL
== (pal
= importer
->palette
)) {
1811 int entries
= EXCEL_DEF_PAL_LEN
;
1812 ExcelPaletteEntry
const *defaults
= (importer
->ver
>= MS_BIFF_V8
)
1813 ? excel_default_palette_v8
: excel_default_palette_v7
;
1815 pal
= importer
->palette
= g_new (ExcelPalette
, 1);
1816 pal
->length
= entries
;
1817 pal
->red
= g_new (int, entries
);
1818 pal
->green
= g_new (int, entries
);
1819 pal
->blue
= g_new (int, entries
);
1820 pal
->gnm_colors
= g_new (GnmColor
*, entries
);
1822 while (--entries
>= 0) {
1823 pal
->red
[entries
] = defaults
[entries
].r
;
1824 pal
->green
[entries
] = defaults
[entries
].g
;
1825 pal
->blue
[entries
] = defaults
[entries
].b
;
1826 pal
->gnm_colors
[entries
] = NULL
;
1830 /* NOTE: not documented but seems close
1831 * If you find a normative reference please forward it.
1833 * The color index field seems to use
1834 * 8-63 = Palette index 0-55
1835 * 64 = auto pattern, auto border
1836 * 65 = auto background
1839 * 65 is always white, and 127 always black. 64 is black
1840 * if the fDefaultHdr flag in WINDOW2 is unset, otherwise it's
1841 * the grid color from WINDOW2.
1844 d (4, g_printerr ("Color Index %d\n", idx
););
1846 if (idx
== 1 || idx
== 65)
1847 return style_color_white ();
1850 case 64: /* system text ? */
1851 case 81: /* tooltip text */
1852 case 0x7fff: /* system text ? */
1853 return style_color_black ();
1855 case 65: /* system back ? */
1856 return style_color_white ();
1858 case 80: /* tooltip background */
1859 return gnm_color_new_rgb8 (0xff, 0xff, 0xe0);
1861 case 2: return gnm_color_new_rgb8 (0xff, 0, 0); /* red */
1862 case 3: return gnm_color_new_rgb8 ( 0, 0xff, 0); /* green */
1863 case 4: return gnm_color_new_rgb8 ( 0, 0, 0xff); /* blue */
1864 case 5: return gnm_color_new_rgb8 (0xff, 0xff, 0); /* yellow */
1865 case 6: return gnm_color_new_rgb8 (0xff, 0, 0xff); /* magenta */
1866 case 7: return gnm_color_new_rgb8 ( 0, 0xff, 0xff); /* cyan */
1872 if (idx
< 0 || pal
->length
<= idx
) {
1873 g_warning ("EXCEL: color index (%d) is out of range (8..%d). Defaulting to black",
1874 idx
+ 8, pal
->length
+8);
1875 return style_color_black ();
1878 if (pal
->gnm_colors
[idx
] == NULL
) {
1879 pal
->gnm_colors
[idx
] =
1880 gnm_color_new_rgb8 (pal
->red
[idx
],
1883 g_return_val_if_fail (pal
->gnm_colors
[idx
],
1884 style_color_black ());
1886 const GnmColor
*c
= pal
->gnm_colors
[idx
];
1887 g_printerr ("New color in slot %d: RGBA = %x,%x,%x,%x\n",
1889 GO_COLOR_UINT_R (c
->go_color
),
1890 GO_COLOR_UINT_G (c
->go_color
),
1891 GO_COLOR_UINT_B (c
->go_color
),
1892 GO_COLOR_UINT_A (c
->go_color
));
1896 style_color_ref (pal
->gnm_colors
[idx
]);
1897 return pal
->gnm_colors
[idx
];
1901 excel_palette_destroy (ExcelPalette
*pal
)
1906 g_free (pal
->green
);
1908 for (lp
= 0; lp
< pal
->length
; lp
++)
1909 style_color_unref (pal
->gnm_colors
[lp
]);
1910 g_free (pal
->gnm_colors
);
1915 excel_read_PALETTE (BiffQuery
*q
, GnmXLImporter
*importer
)
1920 XL_CHECK_CONDITION (q
->length
>= 2);
1921 len
= GSF_LE_GET_GUINT16 (q
->data
);
1922 XL_CHECK_CONDITION (q
->length
>= 2u + len
* 4u);
1924 pal
= g_new (ExcelPalette
, 1);
1926 pal
->red
= g_new (int, len
);
1927 pal
->green
= g_new (int, len
);
1928 pal
->blue
= g_new (int, len
);
1929 pal
->gnm_colors
= g_new (GnmColor
*, len
);
1931 d (3, g_printerr ("New palette with %d entries\n", len
););
1933 for (lp
= 0; lp
< len
; lp
++) {
1934 guint32 num
= GSF_LE_GET_GUINT32 (q
->data
+ 2 + lp
* 4);
1936 /* NOTE the order of bytes is different from what one would
1938 pal
->blue
[lp
] = (num
& 0x00ff0000) >> 16;
1939 pal
->green
[lp
] = (num
& 0x0000ff00) >> 8;
1940 pal
->red
[lp
] = (num
& 0x000000ff) >> 0;
1941 d (5, g_printerr ("Colour %d: 0x%8x (%x,%x,%x)\n", lp
,
1942 num
, pal
->red
[lp
], pal
->green
[lp
], pal
->blue
[lp
]););
1944 pal
->gnm_colors
[lp
] = NULL
;
1946 if (importer
->palette
)
1947 excel_palette_destroy (importer
->palette
);
1948 importer
->palette
= pal
;
1953 * Search for a font record from its index in the workbooks font table
1954 * NB. index 4 is omitted supposedly for backwards compatiblity
1955 * Returns the font color if there is one.
1958 excel_font_get (GnmXLImporter
const *importer
, unsigned font_idx
)
1960 ExcelFont
const *fd
=
1961 g_hash_table_lookup (importer
->font_data
,
1962 GINT_TO_POINTER (font_idx
));
1964 g_warning ("Invalid font index %d\n", font_idx
);
1966 fd
= g_hash_table_lookup (importer
->font_data
,
1967 GINT_TO_POINTER (0));
1974 excel_font_get_gofont (ExcelFont
const *efont
)
1976 if (NULL
== efont
->go_font
) {
1977 PangoFontDescription
*desc
= pango_font_description_new ();
1979 d (1, { g_printerr ("EFONT: %s %d %d %d\n",
1984 #warning FINISH when GOFont is smarter
1985 pango_font_description_set_family (desc
, efont
->fontname
);
1986 pango_font_description_set_weight (desc
, efont
->boldness
);
1987 pango_font_description_set_style (desc
,
1988 efont
->italic
? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
);
1989 pango_font_description_set_size (desc
,
1990 efont
->height
* PANGO_SCALE
/ 20);
1992 ((ExcelFont
*)efont
)->go_font
= go_font_new_by_desc (desc
);
1994 return efont
->go_font
;
1997 static BiffXFData
const *
1998 excel_get_xf (ExcelReadSheet
*esheet
, unsigned xfidx
)
2000 GPtrArray
const * const p
= esheet
->container
.importer
->XF_cell_records
;
2002 g_return_val_if_fail (p
!= NULL
, NULL
);
2004 if (esheet_ver (esheet
) == MS_BIFF_V2
) {
2005 /* ignore the replicated info that comes with the index
2006 * we've already parsed the XF record */
2008 if (xfidx
== 0x3f) {
2009 if (esheet
->biff2_prev_xf_index
< 0) {
2010 g_warning ("extension xf with no preceding old_xf record, using default as fallback");
2013 xfidx
= esheet
->biff2_prev_xf_index
;
2017 if (xfidx
>= p
->len
) {
2018 XL_CHECK_CONDITION_VAL (p
->len
> 0, NULL
);
2019 g_warning ("XL: Xf index 0x%X is not in the range[0..0x%X)", xfidx
, p
->len
);
2022 /* FIXME: when we can handle styles too deal with this correctly */
2023 /* g_return_val_if_fail (xf->xftype == MS_BIFF_X_CELL, NULL); */
2024 return g_ptr_array_index (p
, xfidx
);
2028 xls_uline_to_gnm_underline (MsBiffFontUnderline mul
)
2030 g_return_val_if_fail (mul
>= XLS_ULINE_NONE
, UNDERLINE_NONE
);
2031 g_return_val_if_fail (mul
<= XLS_ULINE_DOUBLE_ACC
, UNDERLINE_NONE
);
2034 case XLS_ULINE_SINGLE
:
2035 return UNDERLINE_SINGLE
;
2036 case XLS_ULINE_DOUBLE
:
2037 return UNDERLINE_DOUBLE
;
2038 case XLS_ULINE_SINGLE_ACC
:
2039 return UNDERLINE_SINGLE_LOW
;
2040 case XLS_ULINE_DOUBLE_ACC
:
2041 return UNDERLINE_DOUBLE_LOW
;
2042 case XLS_ULINE_NONE
:
2044 return UNDERLINE_NONE
;
2049 /* Adds a ref the result */
2051 excel_get_style_from_xf (ExcelReadSheet
*esheet
, BiffXFData
const *xf
)
2053 ExcelFont
const *fd
;
2054 GnmColor
*pattern_color
, *back_color
, *font_color
;
2055 int pattern_index
, back_index
, font_index
;
2062 /* If we've already done the conversion use the cached style */
2063 if (xf
->mstyle
!= NULL
) {
2064 gnm_style_ref (xf
->mstyle
);
2068 /* Create a new style and fill it in */
2069 mstyle
= gnm_style_new_default ();
2072 if (xf
->style_format
)
2073 gnm_style_set_format (mstyle
, xf
->style_format
);
2076 gnm_style_set_contents_locked (mstyle
, xf
->locked
);
2077 gnm_style_set_contents_hidden (mstyle
, xf
->hidden
);
2080 gnm_style_set_align_v (mstyle
, xf
->valign
);
2081 gnm_style_set_align_h (mstyle
, xf
->halign
);
2082 gnm_style_set_wrap_text (mstyle
, xf
->wrap_text
);
2083 gnm_style_set_shrink_to_fit (mstyle
, xf
->shrink_to_fit
);
2084 gnm_style_set_indent (mstyle
, xf
->indent
);
2085 gnm_style_set_rotation (mstyle
, xf
->rotation
);
2086 gnm_style_set_text_dir (mstyle
, xf
->text_dir
);
2089 fd
= excel_font_get (esheet
->container
.importer
, xf
->font_idx
);
2091 gnm_style_set_font_name (mstyle
, fd
->fontname
);
2092 gnm_style_set_font_size (mstyle
, fd
->height
/ 20.0);
2093 gnm_style_set_font_bold (mstyle
, fd
->boldness
>= 0x2bc);
2094 gnm_style_set_font_italic (mstyle
, fd
->italic
);
2095 gnm_style_set_font_strike (mstyle
, fd
->struck_out
);
2096 gnm_style_set_font_script (mstyle
, fd
->script
);
2097 gnm_style_set_font_uline
2098 (mstyle
, xls_uline_to_gnm_underline (fd
->underline
));
2099 font_index
= fd
->color_idx
;
2101 font_index
= 127; /* Default to Black */
2104 gnm_style_set_pattern (mstyle
, xf
->fill_pattern_idx
);
2106 /* Solid patterns seem to reverse the meaning */
2107 if (xf
->fill_pattern_idx
== 1) {
2108 pattern_index
= xf
->pat_backgnd_col
;
2109 back_index
= xf
->pat_foregnd_col
;
2111 pattern_index
= xf
->pat_foregnd_col
;
2112 back_index
= xf
->pat_backgnd_col
;
2115 d (4, g_printerr ("back = %d, pat = %d, font = %d, pat_style = %d\n",
2116 back_index
, pattern_index
, font_index
, xf
->fill_pattern_idx
););
2118 if (font_index
== 127)
2119 font_color
= style_color_auto_font ();
2121 font_color
= excel_palette_get (esheet
->container
.importer
, font_index
);
2123 switch (back_index
) {
2125 back_color
= sheet_style_get_auto_pattern_color (esheet
->sheet
);
2128 back_color
= style_color_auto_back ();
2131 back_color
= excel_palette_get (esheet
->container
.importer
, back_index
);
2135 switch (pattern_index
) {
2136 case 64: /* Normal case for auto pattern color */
2137 pattern_color
= sheet_style_get_auto_pattern_color
2141 /* Mutated form, also observed in the wild, but only for
2142 solid fill. I. e.: this color is not visible. */
2143 pattern_color
= style_color_auto_back ();
2146 pattern_color
= excel_palette_get (esheet
->container
.importer
, pattern_index
);
2150 g_return_val_if_fail (back_color
&& pattern_color
&& font_color
, NULL
);
2152 d (4, g_printerr ("back = #%02x%02x%02x, pat = #%02x%02x%02x, font = #%02x%02x%02x, pat_style = %d\n",
2153 GO_COLOR_UINT_R (back_color
->go_color
),
2154 GO_COLOR_UINT_G (back_color
->go_color
),
2155 GO_COLOR_UINT_B (back_color
->go_color
),
2156 GO_COLOR_UINT_R (pattern_color
->go_color
),
2157 GO_COLOR_UINT_G (pattern_color
->go_color
),
2158 GO_COLOR_UINT_B (pattern_color
->go_color
),
2159 GO_COLOR_UINT_R (font_color
->go_color
),
2160 GO_COLOR_UINT_G (font_color
->go_color
),
2161 GO_COLOR_UINT_B (font_color
->go_color
),
2162 xf
->fill_pattern_idx
););
2164 gnm_style_set_font_color (mstyle
, font_color
);
2165 gnm_style_set_back_color (mstyle
, back_color
);
2166 gnm_style_set_pattern_color (mstyle
, pattern_color
);
2169 for (i
= 0; i
< STYLE_ORIENT_MAX
; i
++) {
2170 GnmStyle
*tmp
= mstyle
;
2171 GnmStyleElement
const t
= MSTYLE_BORDER_TOP
+ i
;
2172 GnmStyleBorderLocation
const sbl
= GNM_STYLE_BORDER_TOP
+ i
;
2173 int const color_index
= xf
->border_color
[i
];
2176 switch (color_index
) {
2178 color
= sheet_style_get_auto_pattern_color
2180 d (4, g_printerr ("border with color_index=%d\n",
2184 color
= style_color_auto_back ();
2185 /* We haven't seen this yet.
2186 We know that 64 and 127 occur in the wild */
2187 d (4, g_printerr ("border with color_index=%d\n",
2191 color
= style_color_auto_font ();
2194 color
= excel_palette_get (esheet
->container
.importer
, color_index
);
2197 gnm_style_set_border (tmp
, t
,
2198 gnm_style_border_fetch (xf
->border_type
[i
],
2200 gnm_style_border_get_orientation (sbl
)));
2203 /* Set the cache (const_cast) */
2204 ((BiffXFData
*)xf
)->mstyle
= mstyle
;
2205 gnm_style_ref (mstyle
);
2210 excel_choose_border (GnmBorder
*b1
, GnmBorder
*b2
)
2212 /* double > thick > medium > medium-dash > medium-dash-dot > slanted dash-dot >
2213 medium dash-dot-dot > thin > dashed > dotted > dash-dot > dash-dot-dot > hair */
2214 static int choice
[GNM_STYLE_BORDER_SLANTED_DASH_DOT
+ 1]
2215 [GNM_STYLE_BORDER_SLANTED_DASH_DOT
+ 1]
2216 = { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* GNM_STYLE_BORDER_NONE */
2217 { 1,0,0,1,1,0,0,1,0,1,0,1,0,0 }, /* GNM_STYLE_BORDER_THIN */
2218 { 1,1,0,1,1,0,0,1,1,1,1,1,1,1 }, /* GNM_STYLE_BORDER_MEDIUM */
2219 { 1,0,0,0,1,0,0,1,0,1,0,1,0,0 }, /* GNM_STYLE_BORDER_DASHED */
2220 { 1,0,0,0,0,0,0,1,0,1,0,1,0,0 }, /* GNM_STYLE_BORDER_DOTTED */
2221 { 1,1,1,1,1,0,0,1,1,1,1,1,1,1 }, /* GNM_STYLE_BORDER_THICK */
2222 { 1,1,1,1,1,1,0,1,1,1,1,1,1,1 }, /* GNM_STYLE_BORDER_DOUBLE */
2223 { 1,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* GNM_STYLE_BORDER_HAIR */
2224 { 1,1,0,1,1,0,0,1,0,1,1,1,1,1 }, /* GNM_STYLE_BORDER_MEDIUM_DASH */
2225 { 1,0,0,0,0,0,0,1,0,0,0,1,0,0 }, /* GNM_STYLE_BORDER_DASH_DOT */
2226 { 1,1,0,1,1,0,0,1,0,1,0,1,1,1 }, /* GNM_STYLE_BORDER_MEDIUM_DASH_DOT */
2227 { 1,0,0,0,0,0,0,1,0,0,0,0,0,0 }, /* GNM_STYLE_BORDER_DASH_DOT_DOT */
2228 { 1,1,0,1,1,0,0,1,0,1,0,1,0,0 }, /* GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT */
2229 { 1,1,0,1,1,0,0,1,0,1,0,1,1,0 } /* GNM_STYLE_BORDER_SLANTED_DASH_DOT */
2232 return (choice
[b1
->line_type
][b2
->line_type
]) ? b1
: b2
;
2235 static BiffXFData
const *
2236 excel_set_xf (ExcelReadSheet
*esheet
, BiffQuery
*q
)
2239 BiffXFData
const *xf
;
2241 Sheet
*sheet
= esheet
->sheet
;
2243 XL_CHECK_CONDITION_VAL (q
->length
>= 6, NULL
);
2244 col
= XL_GETCOL (q
);
2245 row
= XL_GETROW (q
);
2246 xf
= excel_get_xf (esheet
, GSF_LE_GET_GUINT16 (q
->data
+ 4));
2247 XL_CHECK_CONDITION_VAL (col
< gnm_sheet_get_max_cols (sheet
), xf
);
2248 XL_CHECK_CONDITION_VAL (row
< gnm_sheet_get_max_rows (sheet
), xf
);
2249 mstyle
= excel_get_style_from_xf (esheet
, xf
);
2251 d (3, g_printerr ("%s!%s%d = xf(0x%hx) = style (%p) [LEN = %u]\n", sheet
->name_unquoted
,
2252 col_name (col
), row
+ 1, GSF_LE_GET_GUINT16 (q
->data
+ 4), mstyle
, q
->length
););
2254 if (mstyle
!= NULL
) {
2255 GnmBorder
*top_b
, *left_b
;
2257 sheet_style_set_pos (sheet
, col
, row
, mstyle
);
2259 /* In Excel & Gnumeric generated xls-files we do not have a conflict */
2260 /* between borders of adjacent cells, but according to bug #660605 */
2261 /* there are xls files in the wild that have a conflict. We need to */
2262 /* resolve these conflicts to ensure consistent behaviour when we edit */
2263 /* borders and to provide the expected border appearance. */
2265 top_b
= gnm_style_get_border (mstyle
, MSTYLE_BORDER_TOP
);
2266 left_b
= gnm_style_get_border (mstyle
, MSTYLE_BORDER_LEFT
);
2268 if ((row
> 0 && top_b
!= NULL
&& top_b
->line_type
!= GNM_STYLE_BORDER_NONE
) ||
2269 (col
> 0 && left_b
!= NULL
&& left_b
->line_type
!= GNM_STYLE_BORDER_NONE
)) {
2270 GnmBorder
**overlay
= g_new0 (GnmBorder
*, GNM_STYLE_BORDER_EDGE_MAX
);
2274 top_b
!= NULL
&& top_b
->line_type
!= GNM_STYLE_BORDER_NONE
) {
2275 GnmStyle
const *previous
= sheet_style_get (sheet
, col
, row
- 1);
2276 if (previous
!= NULL
) {
2277 GnmBorder
*prev_b
= gnm_style_get_border
2278 (previous
, MSTYLE_BORDER_BOTTOM
);
2279 if (prev_b
!= NULL
&&
2280 prev_b
->line_type
!= GNM_STYLE_BORDER_NONE
&&
2281 prev_b
->line_type
!= top_b
->line_type
)
2282 overlay
[GNM_STYLE_BORDER_TOP
] =
2283 gnm_style_border_ref
2284 (excel_choose_border (top_b
, prev_b
));
2288 left_b
!= NULL
&& left_b
->line_type
!= GNM_STYLE_BORDER_NONE
) {
2289 GnmStyle
const *previous
= sheet_style_get (sheet
, col
- 1, row
);
2290 if (previous
!= NULL
) {
2291 GnmBorder
*prev_b
= gnm_style_get_border
2292 (previous
, MSTYLE_BORDER_RIGHT
);
2293 if (prev_b
!= NULL
&&
2294 prev_b
->line_type
!= GNM_STYLE_BORDER_NONE
&&
2295 prev_b
->line_type
!= left_b
->line_type
)
2296 overlay
[GNM_STYLE_BORDER_LEFT
] =
2297 gnm_style_border_ref
2298 (excel_choose_border (left_b
, prev_b
));
2302 /* We are using sheet_style_apply_border rather than */
2303 /* sheet_style_apply_pos since it clears the appropriate */
2304 /* adjacent borders */
2305 range_init (&range
, col
, row
, col
, row
);
2306 sheet_style_apply_border (sheet
, &range
, overlay
);
2307 gnm_style_border_unref (overlay
[GNM_STYLE_BORDER_TOP
]);
2308 gnm_style_border_unref (overlay
[GNM_STYLE_BORDER_LEFT
]);
2316 excel_set_xf_segment (ExcelReadSheet
*esheet
,
2317 int start_col
, int end_col
,
2318 int start_row
, int end_row
, unsigned xfidx
)
2321 GnmStyle
*mstyle
= excel_get_style_from_xf (esheet
,
2322 excel_get_xf (esheet
, xfidx
));
2327 range
.start
.col
= start_col
;
2328 range
.start
.row
= start_row
;
2329 range
.end
.col
= end_col
;
2330 range
.end
.row
= end_row
;
2331 sheet_style_set_range (esheet
->sheet
, &range
, mstyle
);
2334 g_printerr ("%s!", esheet
->sheet
->name_unquoted
);
2335 range_dump (&range
, "");
2336 g_printerr (" = xf(%d)\n", xfidx
);
2340 static GnmStyleBorderType
2341 biff_xf_map_border (int b
)
2345 return GNM_STYLE_BORDER_NONE
;
2347 return GNM_STYLE_BORDER_THIN
;
2348 case 2: /* Medium */
2349 return GNM_STYLE_BORDER_MEDIUM
;
2350 case 3: /* Dashed */
2351 return GNM_STYLE_BORDER_DASHED
;
2352 case 4: /* Dotted */
2353 return GNM_STYLE_BORDER_DOTTED
;
2355 return GNM_STYLE_BORDER_THICK
;
2356 case 6: /* Double */
2357 return GNM_STYLE_BORDER_DOUBLE
;
2359 return GNM_STYLE_BORDER_HAIR
;
2360 case 8: /* Medium Dashed */
2361 return GNM_STYLE_BORDER_MEDIUM_DASH
;
2362 case 9: /* Dash Dot */
2363 return GNM_STYLE_BORDER_DASH_DOT
;
2364 case 10: /* Medium Dash Dot */
2365 return GNM_STYLE_BORDER_MEDIUM_DASH_DOT
;
2366 case 11: /* Dash Dot Dot */
2367 return GNM_STYLE_BORDER_DASH_DOT_DOT
;
2368 case 12: /* Medium Dash Dot Dot */
2369 return GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT
;
2370 case 13: /* Slanted Dash Dot*/
2371 return GNM_STYLE_BORDER_SLANTED_DASH_DOT
;
2373 g_printerr ("Unknown border style %d\n", b
);
2374 return GNM_STYLE_BORDER_NONE
;
2378 excel_map_pattern_index_from_excel (int const i
)
2380 static int const map_from_excel
[] = {
2383 10, 9, 11, 12, 13, 14,
2384 15, 16, 17, 18, 5, 6
2387 /* Default to Solid if out of range */
2388 XL_CHECK_CONDITION_VAL (i
>= 0 && i
< (int)G_N_ELEMENTS (map_from_excel
), 0);
2390 return map_from_excel
[i
];
2394 halign_from_excel (guint e
)
2397 case 0: return GNM_HALIGN_GENERAL
;
2398 case 1: return GNM_HALIGN_LEFT
;
2399 case 2: return GNM_HALIGN_CENTER
;
2400 case 3: return GNM_HALIGN_RIGHT
;
2401 case 4: return GNM_HALIGN_FILL
;
2402 case 5: return GNM_HALIGN_JUSTIFY
;
2403 case 6: return GNM_HALIGN_CENTER_ACROSS_SELECTION
;
2404 case 7: return GNM_HALIGN_DISTRIBUTED
;
2407 g_printerr ("Unknown halign %d\n", e
);
2408 return GNM_HALIGN_GENERAL
;
2413 valign_from_excel (guint e
)
2416 case 0: return GNM_VALIGN_TOP
;
2417 case 1: return GNM_VALIGN_CENTER
;
2418 case 2: return GNM_VALIGN_BOTTOM
;
2419 case 3: return GNM_VALIGN_JUSTIFY
;
2420 case 4: return GNM_VALIGN_DISTRIBUTED
;
2422 g_printerr ("Unknown valign %d\n", e
);
2423 return GNM_VALIGN_TOP
;
2428 rotation_from_excel_v8 (guint e
)
2433 return 360 + 90 - e
;
2439 rotation_from_excel_v7 (guint e
)
2451 excel_read_XF_OLD (BiffQuery
*q
, GnmXLImporter
*importer
)
2457 d ( 2, g_printerr ("XF # %d\n", importer
->XF_cell_records
->len
); );
2458 d ( 2, gsf_mem_dump (q
->data
, q
->length
); );
2460 XL_CHECK_CONDITION (q
->length
>= (importer
->ver
>= MS_BIFF_V3
? 12 : 4));
2462 xf
= g_new0 (BiffXFData
, 1);
2463 xf
->font_idx
= q
->data
[0];
2464 xf
->format_idx
= (importer
->ver
>= MS_BIFF_V3
)
2465 ? q
->data
[1] : (q
->data
[2] & 0x3f);
2466 xf
->style_format
= (xf
->format_idx
> 0)
2467 ? excel_wb_get_fmt (importer
, xf
->format_idx
) : NULL
;
2468 xf
->is_simple_format
= xf
->style_format
== NULL
||
2469 go_format_is_simple (xf
->style_format
);
2471 if (importer
->ver
>= MS_BIFF_V3
) {
2472 xf
->locked
= (q
->data
[2] & 0x1) != 0;
2473 xf
->hidden
= (q
->data
[2] & 0x2) != 0;
2474 xf
->xftype
= (q
->data
[2] & 0x4)
2475 ? MS_BIFF_X_STYLE
: MS_BIFF_X_CELL
;
2477 xf
->locked
= (q
->data
[1] & 0x40) != 0;
2478 xf
->hidden
= (q
->data
[1] & 0x80) != 0;
2479 xf
->xftype
= MS_BIFF_X_CELL
;
2481 xf
->parentstyle
= 0; /* TODO extract for biff 3 and biff4 */
2482 xf
->format
= MS_BIFF_F_MS
;
2483 xf
->wrap_text
= FALSE
;
2484 xf
->shrink_to_fit
= FALSE
;
2487 xf
->halign
= GNM_HALIGN_GENERAL
;
2489 data
= (importer
->ver
>= MS_BIFF_V3
) ? q
->data
[4] : q
->data
[3];
2490 switch (data
& 0x07) {
2492 case 0: xf
->halign
= GNM_HALIGN_GENERAL
; break;
2493 case 1: xf
->halign
= GNM_HALIGN_LEFT
; break;
2494 case 2: xf
->halign
= GNM_HALIGN_CENTER
; break;
2495 case 3: xf
->halign
= GNM_HALIGN_RIGHT
; break;
2496 case 4: xf
->halign
= GNM_HALIGN_FILL
; break;
2497 case 5: xf
->halign
= GNM_HALIGN_JUSTIFY
; break;
2498 case 6: xf
->halign
= GNM_HALIGN_CENTER_ACROSS_SELECTION
; break;
2501 xf
->valign
= GNM_VALIGN_BOTTOM
;
2504 xf
->differences
= 0;
2505 xf
->text_dir
= GNM_TEXT_DIR_CONTEXT
;
2507 if (importer
->ver
>= MS_BIFF_V4
) {
2508 xf
->wrap_text
= (data
& 0x0008) != 0;
2509 switch (data
& 0x30) {
2510 case 0x00: xf
->valign
= GNM_VALIGN_TOP
; break;
2511 case 0x10: xf
->valign
= GNM_VALIGN_CENTER
; break;
2513 case 0x20: xf
->valign
= GNM_VALIGN_BOTTOM
; break;
2515 switch (data
& 0xc0) {
2516 case 0x00: xf
->rotation
= 0; break;
2517 case 0x40: xf
->rotation
= -1; break;
2518 case 0x80: xf
->rotation
= 90; break;
2519 case 0xc0: xf
->rotation
= 270; break;
2521 } else if (importer
->ver
>= MS_BIFF_V3
) {
2522 xf
->wrap_text
= (data
& 0x0008) != 0;
2524 xf
->valign
= GNM_VALIGN_TOP
;
2527 if (importer
->ver
>= MS_BIFF_V3
) {
2528 data
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
2529 xf
->pat_backgnd_col
= (data
& 0xf800) >> 11;
2530 if (xf
->pat_backgnd_col
>= 24)
2531 xf
->pat_backgnd_col
+= 40; /* Defaults */
2532 xf
->pat_foregnd_col
= (data
& 0x07c0) >> 6;
2533 if (xf
->pat_foregnd_col
>= 24)
2534 xf
->pat_foregnd_col
+= 40; /* Defaults */
2535 xf
->fill_pattern_idx
=
2536 excel_map_pattern_index_from_excel(data
& 0x001f);
2538 data
= GSF_LE_GET_GUINT8 (q
->data
+ 10);
2539 xf
->border_type
[STYLE_BOTTOM
] = biff_xf_map_border(data
& 0x07);
2540 subdata
= data
>> 3;
2541 xf
->border_color
[STYLE_BOTTOM
] = (subdata
==24) ? 64 : subdata
;
2542 data
= GSF_LE_GET_GUINT8 (q
->data
+ 8);
2543 xf
->border_type
[STYLE_TOP
] = biff_xf_map_border(data
& 0x07);
2544 subdata
= data
>> 3;
2545 xf
->border_color
[STYLE_TOP
] = (subdata
==24) ? 64 : subdata
;
2546 data
= GSF_LE_GET_GUINT8 (q
->data
+ 9);
2547 xf
->border_type
[STYLE_LEFT
] = biff_xf_map_border(data
& 0x07);
2548 subdata
= data
>> 3;
2549 xf
->border_color
[STYLE_LEFT
] = (subdata
==24) ? 64 : subdata
;
2550 data
= GSF_LE_GET_GUINT8 (q
->data
+ 11);
2551 xf
->border_type
[STYLE_RIGHT
] = biff_xf_map_border (data
& 0x07);
2552 subdata
= data
>> 3;
2553 xf
->border_color
[STYLE_RIGHT
] = (subdata
==24) ? 64 : subdata
;
2554 } else /* MS_BIFF_V2 */ {
2555 xf
->pat_foregnd_col
= 0;
2556 xf
->pat_backgnd_col
= 1;
2559 xf
->border_type
[STYLE_LEFT
] = (data
& 0x08) ? 1 : 0;
2560 xf
->border_color
[STYLE_LEFT
] = 0;
2561 xf
->border_type
[STYLE_RIGHT
] = (data
& 0x10) ? 1: 0;
2562 xf
->border_color
[STYLE_RIGHT
] = 0;
2563 xf
->border_type
[STYLE_TOP
] = (data
& 0x20) ? 1: 0;
2564 xf
->border_color
[STYLE_TOP
] = 0;
2565 xf
->border_type
[STYLE_BOTTOM
] = (data
& 0x40) ? 1: 0;
2566 xf
->border_color
[STYLE_BOTTOM
] = 0;
2567 xf
->fill_pattern_idx
= (data
& 0x80) ? 5: 0;
2570 xf
->border_type
[STYLE_DIAGONAL
] = 0;
2571 xf
->border_color
[STYLE_DIAGONAL
] = 0;
2572 xf
->border_type
[STYLE_REV_DIAGONAL
] = 0;
2573 xf
->border_color
[STYLE_REV_DIAGONAL
] = 0;
2575 /* Init the cache */
2578 g_ptr_array_add (importer
->XF_cell_records
, xf
);
2582 excel_read_XF (BiffQuery
*q
, GnmXLImporter
*importer
)
2585 guint32 data
, subdata
;
2587 if (importer
->ver
>= MS_BIFF_V8
)
2588 XL_CHECK_CONDITION (q
->length
>= 20);
2590 XL_CHECK_CONDITION (q
->length
>= 16);
2592 xf
= g_new (BiffXFData
, 1);
2593 xf
->font_idx
= GSF_LE_GET_GUINT16 (q
->data
);
2594 xf
->format_idx
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
2595 xf
->style_format
= (xf
->format_idx
> 0)
2596 ? excel_wb_get_fmt (importer
, xf
->format_idx
) : NULL
;
2597 xf
->is_simple_format
= xf
->style_format
== NULL
||
2598 go_format_is_simple (xf
->style_format
);
2600 data
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
2601 xf
->locked
= (data
& 0x0001) != 0;
2602 xf
->hidden
= (data
& 0x0002) != 0;
2603 xf
->xftype
= (data
& 0x0004) ? MS_BIFF_X_STYLE
: MS_BIFF_X_CELL
;
2604 xf
->format
= (data
& 0x0008) ? MS_BIFF_F_LOTUS
: MS_BIFF_F_MS
;
2605 xf
->parentstyle
= (data
& 0xfff0) >> 4;
2607 if (xf
->xftype
== MS_BIFF_X_CELL
&& xf
->parentstyle
!= 0) {
2608 /* TODO Add support for parent styles
2609 * XL implements a simple form of inheritance with styles.
2610 * If a style's parent changes a value and the child has not
2611 * overridden that value explicitly the child gets updated.
2615 data
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
2616 xf
->halign
= halign_from_excel (data
& 0x0007);
2617 xf
->wrap_text
= (data
& 0x0008) != 0;
2618 xf
->valign
= valign_from_excel ((data
& 0x0070) >> 4);
2619 xf
->rotation
= (importer
->ver
>= MS_BIFF_V8
)
2620 ? rotation_from_excel_v8 (data
>> 8)
2621 : rotation_from_excel_v7 ((data
>> 8) & 3);
2623 if (importer
->ver
>= MS_BIFF_V8
) {
2624 guint16
const data
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
2626 /* FIXME: This code seems irrelevant for merging.
2627 * The undocumented record MERGECELLS appears to be the correct source.
2628 * Nothing seems to set the merge flags.
2630 /* gboolean const merge = (data & 0x20) ? TRUE : FALSE; */
2632 xf
->indent
= data
& 0x0f;
2633 xf
->shrink_to_fit
= (data
& 0x10) ? TRUE
: FALSE
;
2635 subdata
= (data
& 0x00C0) >> 10;
2637 default: g_warning ("Unknown text direction %d.", subdata
);
2639 case 0: xf
->text_dir
= GNM_TEXT_DIR_CONTEXT
; break;
2640 case 1: xf
->text_dir
= GNM_TEXT_DIR_LTR
; break;
2641 case 2: xf
->text_dir
= GNM_TEXT_DIR_RTL
; break;
2644 xf
->text_dir
= GNM_TEXT_DIR_CONTEXT
;
2645 xf
->shrink_to_fit
= FALSE
;
2649 xf
->differences
= data
& 0xFC00;
2651 if (importer
->ver
>= MS_BIFF_V8
) { /* Very different */
2652 int has_diagonals
, diagonal_style
;
2653 data
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
2655 xf
->border_type
[STYLE_LEFT
] = biff_xf_map_border (subdata
& 0xf);
2656 subdata
= subdata
>> 4;
2657 xf
->border_type
[STYLE_RIGHT
] = biff_xf_map_border (subdata
& 0xf);
2658 subdata
= subdata
>> 4;
2659 xf
->border_type
[STYLE_TOP
] = biff_xf_map_border (subdata
& 0xf);
2660 subdata
= subdata
>> 4;
2661 xf
->border_type
[STYLE_BOTTOM
] = biff_xf_map_border (subdata
& 0xf);
2662 subdata
= subdata
>> 4;
2664 data
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
2666 xf
->border_color
[STYLE_LEFT
] = (subdata
& 0x7f);
2667 subdata
= subdata
>> 7;
2668 xf
->border_color
[STYLE_RIGHT
] = (subdata
& 0x7f);
2669 subdata
= (data
& 0xc000) >> 14;
2670 has_diagonals
= subdata
& 0x3;
2672 data
= GSF_LE_GET_GUINT32 (q
->data
+ 14);
2674 xf
->border_color
[STYLE_TOP
] = (subdata
& 0x7f);
2675 subdata
= subdata
>> 7;
2676 xf
->border_color
[STYLE_BOTTOM
] = (subdata
& 0x7f);
2677 subdata
= subdata
>> 7;
2679 /* Assign the colors whether we have a border or not. We will
2680 * handle that later */
2681 xf
->border_color
[STYLE_DIAGONAL
] =
2682 xf
->border_color
[STYLE_REV_DIAGONAL
] = (subdata
& 0x7f);
2684 /* Ok. Now use the flag from above to assign borders */
2685 diagonal_style
= biff_xf_map_border (((data
& 0x01e00000) >> 21) & 0xf);
2686 xf
->border_type
[STYLE_DIAGONAL
] = (has_diagonals
& 0x2)
2687 ? diagonal_style
: GNM_STYLE_BORDER_NONE
;
2688 xf
->border_type
[STYLE_REV_DIAGONAL
] = (has_diagonals
& 0x1)
2689 ? diagonal_style
: GNM_STYLE_BORDER_NONE
;
2691 xf
->fill_pattern_idx
=
2692 excel_map_pattern_index_from_excel ((data
>>26) & 0x3f);
2694 data
= GSF_LE_GET_GUINT16 (q
->data
+ 18);
2695 xf
->pat_foregnd_col
= (data
& 0x007f);
2696 xf
->pat_backgnd_col
= (data
& 0x3f80) >> 7;
2698 d (2, g_printerr ("Color f=0x%x b=0x%x pat=0x%x\n",
2699 xf
->pat_foregnd_col
,
2700 xf
->pat_backgnd_col
,
2701 xf
->fill_pattern_idx
););
2703 } else { /* Biff 7 */
2704 data
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
2705 xf
->pat_foregnd_col
= (data
& 0x007f);
2706 /* Documentation is wrong, background color is one bit more
2707 * than documented */
2708 xf
->pat_backgnd_col
= (data
& 0x3f80) >> 7;
2710 data
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
2711 xf
->fill_pattern_idx
=
2712 excel_map_pattern_index_from_excel (data
& 0x3f);
2714 d (2, g_printerr ("Color f=0x%x b=0x%x pat=0x%x\n",
2715 xf
->pat_foregnd_col
,
2716 xf
->pat_backgnd_col
,
2717 xf
->fill_pattern_idx
););
2719 /* Luckily this maps nicely onto the new set. */
2720 xf
->border_type
[STYLE_BOTTOM
] = biff_xf_map_border ((data
& 0x1c0) >> 6);
2721 xf
->border_color
[STYLE_BOTTOM
] = (data
& 0xfe00) >> 9;
2723 data
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
2725 xf
->border_type
[STYLE_TOP
] = biff_xf_map_border (subdata
& 0x07);
2726 subdata
= subdata
>> 3;
2727 xf
->border_type
[STYLE_LEFT
] = biff_xf_map_border (subdata
& 0x07);
2728 subdata
= subdata
>> 3;
2729 xf
->border_type
[STYLE_RIGHT
] = biff_xf_map_border (subdata
& 0x07);
2731 subdata
= subdata
>> 3;
2732 xf
->border_color
[STYLE_TOP
] = subdata
;
2734 data
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
2736 xf
->border_color
[STYLE_LEFT
] = (subdata
& 0x7f);
2737 subdata
= subdata
>> 7;
2738 xf
->border_color
[STYLE_RIGHT
] = (subdata
& 0x7f);
2740 /* Init the diagonals which were not availabile in Biff7 */
2741 xf
->border_type
[STYLE_DIAGONAL
] =
2742 xf
->border_type
[STYLE_REV_DIAGONAL
] = 0;
2743 xf
->border_color
[STYLE_DIAGONAL
] =
2744 xf
->border_color
[STYLE_REV_DIAGONAL
] = 127;
2747 /* Init the cache */
2750 g_ptr_array_add (importer
->XF_cell_records
, xf
);
2751 d (2, g_printerr ("XF(0x%04x): S=%d L=%d H=%d L=%d xty=%d Font=%d Fmt=%d Fg=%d Bg=%d Pat=%d\n",
2752 importer
->XF_cell_records
->len
- 1,
2753 xf
->is_simple_format
, xf
->locked
, xf
->hidden
, xf
->format
,
2757 xf
->pat_foregnd_col
,
2758 xf
->pat_backgnd_col
,
2759 xf
->fill_pattern_idx
););
2763 excel_read_XF_INDEX (BiffQuery
*q
, ExcelReadSheet
*esheet
)
2765 XL_CHECK_CONDITION (q
->length
>= 2);
2766 esheet
->biff2_prev_xf_index
= GSF_LE_GET_GUINT16 (q
->data
);
2770 biff_xf_data_destroy (BiffXFData
*xf
)
2772 go_format_unref (xf
->style_format
);
2773 xf
->style_format
= NULL
;
2776 gnm_style_unref (xf
->mstyle
);
2782 static GnmExprTop
const *
2783 excel_formula_shared (BiffQuery
*q
, ExcelReadSheet
*esheet
, GnmCell
*cell
)
2785 guint16 opcode
, data_len
, data_ofs
, array_data_len
;
2788 GnmExprTop
const *texpr
;
2791 if (!ms_biff_query_peek_next (q
, &opcode
) ||
2792 !(opcode
== BIFF_SHRFMLA
||
2793 opcode
== BIFF_ARRAY_v0
|| opcode
== BIFF_ARRAY_v2
||
2794 opcode
== BIFF_TABLE_v0
|| opcode
== BIFF_TABLE_v2
)) {
2795 g_warning ("EXCEL: unexpected record '0x%x' after a formula in '%s'.",
2796 opcode
, cell_name (cell
));
2799 ms_biff_query_next (q
);
2801 XL_CHECK_CONDITION_VAL (q
->length
>= 6, NULL
);
2802 xls_read_range8 (&r
, q
->data
);
2804 if (opcode
== BIFF_TABLE_v0
|| opcode
== BIFF_TABLE_v2
) {
2806 GnmExprList
*args
= NULL
;
2810 XL_CHECK_CONDITION_VAL (q
->length
>= 16, NULL
);
2812 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
2814 d (2, { range_dump (&r
, " <-- contains data table\n");
2815 gsf_mem_dump (q
->data
, q
->length
); });
2817 dt
= g_new0 (XLDataTable
, 1);
2819 dt
->c_in
.row
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
2820 dt
->c_in
.col
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
2821 dt
->r_in
.row
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
2822 dt
->r_in
.col
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
2823 g_hash_table_replace (esheet
->tables
, &dt
->table
.start
, dt
);
2825 args
= gnm_expr_list_append
2827 gnm_expr_new_cellref
2828 (gnm_cellref_init (&ref
, NULL
,
2829 dt
->c_in
.col
- r
.start
.col
,
2830 dt
->c_in
.row
- r
.start
.row
, TRUE
)));
2832 args
= gnm_expr_list_append
2834 gnm_expr_new_cellref
2835 (gnm_cellref_init (&ref
, NULL
,
2836 dt
->r_in
.col
- r
.start
.col
,
2837 dt
->r_in
.row
- r
.start
.row
, TRUE
)));
2839 GnmExpr
const *missing
= gnm_expr_new_constant (value_new_empty ());
2841 ? gnm_expr_list_append (args
, missing
)
2842 : gnm_expr_list_prepend (args
, missing
);
2844 texpr
= gnm_expr_top_new (gnm_expr_new_funcall (gnm_func_lookup ("table", NULL
), args
));
2845 gnm_cell_set_array (esheet
->sheet
, &r
, texpr
);
2846 gnm_expr_top_unref (texpr
);
2850 d (2, range_dump (&r
, " <-- contains a shared formula\n"););
2852 is_array
= (q
->opcode
!= BIFF_SHRFMLA
);
2854 data_ofs
= (esheet_ver (esheet
) > MS_BIFF_V4
&& is_array
) ? 14 : 10;
2855 XL_CHECK_CONDITION_VAL (q
->length
>= data_ofs
, NULL
);
2856 data
= q
->data
+ data_ofs
;
2857 data_len
= GSF_LE_GET_GUINT16 (q
->data
+ (data_ofs
- 2));
2858 XL_CHECK_CONDITION_VAL (q
->length
>= data_ofs
+ data_len
, NULL
);
2859 array_data_len
= data_len
> 0 ? q
->length
- (data_ofs
+ data_len
) : 0;
2861 texpr
= excel_parse_formula (&esheet
->container
, esheet
,
2862 r
.start
.col
, r
.start
.row
,
2863 data
, data_len
, array_data_len
,
2866 if (g_hash_table_lookup (esheet
->shared_formulae
, &cell
->pos
)) {
2867 g_printerr ("Duplicate shared formula for cell %s\n", cell_name (cell
));
2869 XLSharedFormula
*sf
= g_new (XLSharedFormula
, 1);
2871 /* WARNING: Do NOT use the upper left corner as the hashkey.
2872 * For some bizzare reason XL appears to sometimes not
2873 * flag the formula as shared until later.
2874 * Use the location of the cell we are reading as the key.
2876 sf
->key
= cell
->pos
;
2877 sf
->is_array
= is_array
;
2878 sf
->data
= data_len
> 0 ? g_memdup (data
, data_len
+ array_data_len
) : NULL
;
2879 sf
->data_len
= data_len
;
2880 sf
->array_data_len
= array_data_len
;
2881 sf
->being_parsed
= FALSE
;
2883 d (1, g_printerr ("Shared formula, extent %s\n", range_as_string (&r
)););
2885 g_hash_table_insert (esheet
->shared_formulae
, &sf
->key
, sf
);
2888 g_return_val_if_fail (texpr
!= NULL
, NULL
);
2891 gnm_cell_set_array (esheet
->sheet
, &r
, texpr
);
2892 gnm_expr_top_unref (texpr
);
2899 * NOTE: There must be _no_ path through this function that does not set the
2903 excel_read_FORMULA (BiffQuery
*q
, ExcelReadSheet
*esheet
)
2905 /* Pre-retrieve incase this is a string */
2906 gboolean array_elem
, is_string
= FALSE
;
2907 guint16 col
, row
, options
;
2908 guint16 expr_length
;
2910 guint8
const *val_dat
= q
->data
+ 6;
2911 GnmExprTop
const *texpr
;
2913 GnmValue
*val
= NULL
;
2915 XL_CHECK_CONDITION (q
->length
>= 16);
2916 col
= XL_GETCOL (q
);
2917 row
= XL_GETROW (q
);
2918 options
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
2920 excel_set_xf (esheet
, q
);
2922 cell
= excel_cell_fetch (q
, esheet
);
2926 /* TODO TODO TODO: Wishlist
2927 * We should make an array of minimum sizes for each BIFF type
2928 * and have this checking done there.
2930 if (esheet_ver (esheet
) >= MS_BIFF_V5
) {
2931 XL_CHECK_CONDITION (q
->length
>= 22);
2932 expr_length
= GSF_LE_GET_GUINT16 (q
->data
+ 20);
2935 /* TODO : it would be nice to figure out how to allocate recalc tags.
2936 * that would avoid the scary
2937 * 'this file was calculated with a different version of XL'
2938 * warning when exiting without changing. */
2939 d (1, g_printerr ("Formula in %s!%s has recalc tag 0x%x;\n",
2940 esheet
->sheet
->name_quoted
, cell_name (cell
),
2941 GSF_LE_GET_GUINT32 (q
->data
+ 16)););
2943 } else if (esheet_ver (esheet
) >= MS_BIFF_V3
) {
2944 XL_CHECK_CONDITION (q
->length
>= 18);
2945 expr_length
= GSF_LE_GET_GUINT16 (q
->data
+ 16);
2948 XL_CHECK_CONDITION (q
->length
>= 17);
2949 expr_length
= GSF_LE_GET_GUINT8 (q
->data
+ 16);
2951 val_dat
++; /* compensate for the 3 byte style */
2953 XL_CHECK_CONDITION (q
->length
>= offset
+ expr_length
);
2955 /* Get the current value so that we can format, do this BEFORE handling
2956 * shared/array formulas or strings in case we need to go to the next
2958 if (GSF_LE_GET_GUINT16 (val_dat
+ 6) != 0xffff) {
2959 val
= value_new_float (gsf_le_get_double (val_dat
));
2961 guint8
const val_type
= GSF_LE_GET_GUINT8 (val_dat
);
2963 case 0: is_string
= TRUE
; break;
2964 case 1: val
= value_new_bool (GSF_LE_GET_GUINT8 (val_dat
+ 2) != 0);
2966 case 2: val
= xls_value_new_err (NULL
, GSF_LE_GET_GUINT8 (val_dat
+ 2));
2968 case 3: val
= value_new_empty (); /* Empty (Undocumented) */
2971 g_printerr ("Unknown type (%x) for cell's (%s) current val\n",
2972 val_type
, cell_name (cell
));
2976 texpr
= excel_parse_formula (&esheet
->container
, esheet
, col
, row
,
2977 q
->data
+ offset
, expr_length
,
2978 q
->length
- (offset
+ expr_length
),
2979 FALSE
, &array_elem
);
2981 /* dump the trailing array and natural language data */
2982 gsf_mem_dump (q
->data
+ offset
+ expr_length
,
2983 q
->length
- offset
- expr_length
);
2986 /* Error was flaged by parse_formula */
2987 if (texpr
== NULL
&& !array_elem
)
2988 texpr
= excel_formula_shared (q
, esheet
, cell
);
2992 if (ms_biff_query_peek_next (q
, &opcode
) &&
2993 (opcode
== BIFF_STRING_v0
|| opcode
== BIFF_STRING_v2
)) {
2995 if (ms_biff_query_next (q
)) {
2997 * NOTE: the Excel developers kit docs are
2998 * WRONG. There is an article that
2999 * clarifies the behaviour to be the std
3000 * unicode format rather than the pure
3001 * length version the docs describe.
3003 * NOTE : Apparently some apps actually store a
3004 * 0 length string record for an empty.
3005 * DAMN! this was us! we were screwing
3006 * up when exporting ""
3008 guint16
const len
= (q
->length
>= 2) ? GSF_LE_GET_GUINT16 (q
->data
) : 0;
3011 v
= excel_biff_text (esheet
->container
.importer
, q
, 2, len
);
3014 * Pre-Biff8 seems to use len=0
3015 * Should that be a string or an EMPTY?
3020 val
= value_new_string_nocopy (v
);
3023 val
= value_new_error (eval_pos_init_cell (&ep
, cell
),
3025 g_warning ("EXCEL: invalid STRING record in %s",
3029 /* There should be a STRING record here */
3031 val
= value_new_error (eval_pos_init_cell (&ep
, cell
),
3033 g_warning ("EXCEL: missing STRING record for %s",
3038 /* We MUST have a value */
3041 val
= value_new_error (eval_pos_init_cell (&ep
, cell
),
3043 g_warning ("EXCEL: Invalid state. Missing Value in %s?",
3047 if (gnm_cell_is_array (cell
)) {
3048 /* Array expressions were already stored in the cells (without
3049 * recalc), and without a value. Handle either the first
3050 * instance or the followers.
3052 gnm_cell_assign_value (cell
, val
);
3053 } else if (!gnm_cell_has_expr (cell
)) {
3054 /* Just in case things screwed up, at least save the value */
3055 if (texpr
!= NULL
) {
3056 gnm_cell_set_expr_and_value (cell
, texpr
, val
, TRUE
);
3057 gnm_expr_top_unref (texpr
);
3059 gnm_cell_assign_value (cell
, val
);
3062 * NOTE: Only the expression is screwed.
3063 * The value and format can still be set.
3065 g_warning ("EXCEL: Multiple expressions for cell %s!%s",
3066 esheet
->sheet
->name_quoted
, cell_name (cell
));
3067 gnm_cell_set_value (cell
, val
);
3069 gnm_expr_top_unref (texpr
);
3077 cell_queue_recalc (cell
);
3081 excel_sheet_shared_formula (ExcelReadSheet
const *esheet
,
3082 GnmCellPos
const *key
)
3084 g_return_val_if_fail (esheet
!= NULL
, NULL
);
3086 d (5, g_printerr ("FIND SHARED: %s\n", cellpos_as_string (key
)););
3088 return g_hash_table_lookup (esheet
->shared_formulae
, key
);
3092 excel_sheet_data_table (ExcelReadSheet
const *esheet
,
3093 GnmCellPos
const *key
)
3095 g_return_val_if_fail (esheet
!= NULL
, NULL
);
3097 d (5, g_printerr ("FIND DATA TABLE: %s\n", cellpos_as_string (key
)););
3099 return g_hash_table_lookup (esheet
->tables
, key
);
3103 excel_sheet_insert_val (ExcelReadSheet
*esheet
, BiffQuery
*q
, GnmValue
*v
)
3105 GnmCell
*cell
= excel_cell_fetch (q
, esheet
);
3108 (void)excel_set_xf (esheet
, q
);
3109 gnm_cell_set_value (cell
, v
);
3115 excel_read_NOTE (BiffQuery
*q
, ExcelReadSheet
*esheet
)
3118 Sheet
*sheet
= esheet
->sheet
;
3121 XL_CHECK_CONDITION (q
->length
>= 4);
3123 row
= XL_GETROW (q
);
3124 col
= XL_GETCOL (q
);
3125 XL_CHECK_CONDITION (col
< gnm_sheet_get_max_cols (sheet
));
3126 XL_CHECK_CONDITION (row
< gnm_sheet_get_max_rows (sheet
));
3127 pos
.row
= XL_GETROW (q
);
3128 pos
.col
= XL_GETCOL (q
);
3130 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
3131 guint16 options
, obj_id
;
3136 XL_CHECK_CONDITION (q
->length
>= 8);
3137 options
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3138 hidden
= (options
& 0x2)==0;
3139 obj_id
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
3141 /* Docs claim that only 0x2 is valid, all other flags should
3142 * be 0 but we have seen examples with 0x100 'pusiuhendused juuli 2003.xls'
3144 * docs mention 0x002 == hidden
3145 * real life adds 0x080 == ???
3146 * real life adds 0x100 == no indicator visible ??? */
3147 if (options
& 0xe7d)
3148 g_warning ("unknown flag on NOTE record %hx", options
);
3150 author
= excel_biff_text_2 (esheet
->container
.importer
, q
, 8);
3151 d (1, g_printerr ("Comment at %s%d id %d options"
3152 " 0x%x hidden %d by '%s'\n",
3153 col_name (pos
.col
), pos
.row
+ 1,
3154 obj_id
, options
, hidden
, author
););
3156 obj
= ms_container_get_obj (&esheet
->container
, obj_id
);
3158 cell_comment_author_set (GNM_CELL_COMMENT (obj
->gnum_obj
), author
);
3159 obj
->comment_pos
= pos
;
3161 /* hmm, how did this happen ? we should have seen
3162 * some escher records earlier */
3163 cell_set_comment (sheet
, &pos
, author
, NULL
, NULL
);
3170 XL_CHECK_CONDITION (q
->length
>= 6);
3171 len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3172 comment
= g_string_sized_new (len
);
3174 for (; len
> 2048 ; len
-= 2048) {
3177 g_string_append (comment
,
3178 excel_biff_text (esheet
->container
.importer
,
3181 if (!ms_biff_query_peek_next (q
, &opcode
) ||
3182 opcode
!= BIFF_NOTE
|| !ms_biff_query_next (q
) ||
3184 XL_GETROW (q
) != 0xffff || XL_GETCOL (q
) != 0) {
3185 g_warning ("Invalid Comment record");
3186 g_string_free (comment
, TRUE
);
3190 g_string_append (comment
, excel_biff_text (esheet
->container
.importer
, q
, 6, len
));
3192 d (2, g_printerr ("Comment in %s%d: '%s'\n",
3193 col_name (pos
.col
), pos
.row
+ 1, comment
->str
););
3195 cell_set_comment (sheet
, &pos
, NULL
, comment
->str
, NULL
);
3196 g_string_free (comment
, TRUE
);
3201 excel_sheet_destroy (ExcelReadSheet
*esheet
)
3206 if (esheet
->shared_formulae
!= NULL
) {
3207 g_hash_table_destroy (esheet
->shared_formulae
);
3208 esheet
->shared_formulae
= NULL
;
3210 if (esheet
->tables
!= NULL
) {
3211 g_hash_table_destroy (esheet
->tables
);
3212 esheet
->tables
= NULL
;
3215 /* There appear to be workbooks like guai.xls that have a filter NAME
3216 * defined but no visible combos, so we remove a filter if it has no
3218 if (esheet
->filter
!= NULL
) {
3219 gnm_filter_remove (esheet
->filter
);
3220 gnm_filter_unref (esheet
->filter
);
3221 esheet
->filter
= NULL
;
3224 ms_container_finalize (&esheet
->container
);
3229 static GnmExprTop
const *
3230 ms_wb_parse_expr (MSContainer
*container
, guint8
const *data
, int length
)
3232 ExcelReadSheet dummy_sheet
;
3233 memset (&dummy_sheet
, 0, sizeof (dummy_sheet
));
3234 dummy_sheet
.container
.importer
= (GnmXLImporter
*)container
;
3235 return ms_sheet_parse_expr_internal (&dummy_sheet
, data
, length
);
3239 ms_wb_get_fmt (MSContainer
const *container
, unsigned indx
)
3241 return excel_wb_get_fmt (((GnmXLImporter
*)container
), indx
);
3245 add_attr (PangoAttrList
*attr_list
, PangoAttribute
*attr
)
3247 attr
->start_index
= 0;
3248 attr
->end_index
= 0;
3249 pango_attr_list_insert (attr_list
, attr
);
3252 static PangoAttrList
*
3253 ms_wb_get_font_markup (MSContainer
const *c
, unsigned indx
)
3255 GnmXLImporter
*importer
= (GnmXLImporter
*)c
;
3256 ExcelFont
const *fd
= excel_font_get (importer
, indx
);
3258 if (fd
== NULL
|| indx
== 0)
3259 return empty_attr_list
;
3261 if (fd
->attrs
== NULL
) {
3262 ExcelFont
const *fd0
= excel_font_get (importer
, 0);
3263 PangoAttrList
*attrs
;
3265 attrs
= pango_attr_list_new ();
3266 if (strcmp (fd
->fontname
, fd0
->fontname
) != 0)
3267 add_attr (attrs
, pango_attr_family_new (fd
->fontname
));
3268 if (fd
->height
!= fd0
->height
)
3269 add_attr (attrs
, pango_attr_size_new (fd
->height
* PANGO_SCALE
/ 20));
3270 if (fd
->boldness
!= fd0
->boldness
)
3271 add_attr (attrs
, pango_attr_weight_new (fd
->boldness
));
3272 if (fd
->italic
!= fd0
->italic
)
3273 add_attr (attrs
, pango_attr_style_new (fd
->italic
? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
));
3274 if (fd
->struck_out
!= fd0
->struck_out
)
3275 add_attr (attrs
, pango_attr_strikethrough_new (fd
->struck_out
));
3276 if (fd
->underline
!= fd0
->underline
) {
3277 PangoUnderline underline
= gnm_translate_underline_to_pango
3278 (xls_uline_to_gnm_underline (fd
->underline
));
3279 add_attr (attrs
, pango_attr_underline_new (underline
));
3282 switch (fd
->script
) {
3283 case GO_FONT_SCRIPT_SUB
:
3284 add_attr (attrs
, go_pango_attr_subscript_new (TRUE
));
3287 case GO_FONT_SCRIPT_STANDARD
:
3288 /* Just assume fd0 is standard. */
3290 case GO_FONT_SCRIPT_SUPER
:
3291 add_attr (attrs
, go_pango_attr_superscript_new (TRUE
));
3295 if (fd
->color_idx
!= fd0
->color_idx
) {
3296 GnmColor
*color
= (fd
->color_idx
== 127)
3297 ? style_color_black ()
3298 : excel_palette_get (importer
, fd
->color_idx
);
3299 add_attr (attrs
, go_color_to_pango (color
->go_color
, TRUE
));
3300 style_color_unref (color
);
3303 ((ExcelFont
*)fd
)->attrs
= attrs
;
3310 gnm_xl_get_codepage (char const *enc
)
3312 /* These names must match charset_trans_array in go-charmap-sel.c */
3316 } charset_trans_array
[] = {
3320 {"ISO-8859-6-E", 0},
3321 {"ISO-8859-6-I", 0},
3322 {"x-mac-arabic", 0},
3323 {"windows-1256", 1256},
3327 {"windows-1257", 1257},
3332 {"windows-1250", 1250},
3337 {"windows-936", 936},
3341 {"x-mac-croatian", 0},
3346 {"x-mac-cyrillic", 0},
3347 {"windows-1251", 1251},
3350 {"x-mac-ukrainian", 0},
3351 {"ANSI_X3.4-1968#ASCII", 0},
3356 {"windows-1253", 0},
3357 {"x-mac-gujarati", 0},
3358 {"x-mac-gurmukhi", 0},
3360 {"ISO-8859-8-E", 0},
3361 {"ISO-8859-8-I", 0},
3362 {"x-mac-hebrew", 0},
3363 {"windows-1255", 1255},
3364 {"x-mac-devanagari", 0},
3365 {"x-mac-icelandic", 0},
3372 {"x-windows-949", 0},
3374 {"x-mac-romanian", 0},
3380 {"x-mac-turkish", 0},
3381 {"windows-1254", 1254},
3388 {"x-user-defined", 0},
3389 {"x-viet-tcvn5712", 0},
3392 {"windows-1258", 1258},
3398 {"windows-1252", 1252},
3400 {"x-imap4-modified-utf7", 0},
3408 for (i
= 0; i
< G_N_ELEMENTS(charset_trans_array
); i
++)
3409 if (0 == strcmp (enc
, charset_trans_array
[i
].name
))
3410 return charset_trans_array
[i
].codepage
;
3415 static GnmXLImporter
*
3416 gnm_xl_importer_new (GOIOContext
*context
, WorkbookView
*wb_view
, char const *opt_enc
)
3418 static MSContainerClass
const vtbl
= {
3423 &ms_wb_get_font_markup
3426 GnmXLImporter
*importer
= g_new (GnmXLImporter
, 1);
3428 importer
->ver
= MS_BIFF_V_UNKNOWN
;
3429 importer
->context
= context
;
3430 importer
->wbv
= wb_view
;
3431 importer
->wb
= wb_view_get_workbook (wb_view
);
3432 importer
->str_iconv
= (GIConv
)(-1);
3433 importer
->codepage_override
= gnm_xl_get_codepage (opt_enc
);
3434 gnm_xl_importer_set_codepage (importer
, (importer
->codepage_override
> 0) ?
3435 importer
->codepage_override
: 1252); /* set a default */
3437 importer
->expr_sharer
= gnm_expr_sharer_new ();
3438 importer
->v8
.supbook
= g_array_new (FALSE
, FALSE
, sizeof (ExcelSupBook
));
3439 importer
->v8
.externsheet
= NULL
;
3441 importer
->names
= g_ptr_array_new ();
3442 importer
->num_name_records
= 0;
3444 importer
->boundsheet_sheet_by_index
= g_ptr_array_new ();
3445 importer
->boundsheet_data_by_stream
= g_hash_table_new_full (
3446 g_direct_hash
, g_direct_equal
,
3447 NULL
, (GDestroyNotify
) biff_boundsheet_data_destroy
);
3448 importer
->font_data
= g_hash_table_new_full (
3449 g_direct_hash
, g_direct_equal
,
3450 NULL
, (GDestroyNotify
)excel_font_free
);
3451 importer
->excel_sheets
= g_ptr_array_new ();
3452 importer
->XF_cell_records
= g_ptr_array_new ();
3453 importer
->pivot
.cache_by_index
= g_ptr_array_new ();
3454 importer
->pivot
.slicer
= NULL
;
3455 importer
->pivot
.field_count
= 0;
3456 importer
->pivot
.record_count
= 0;
3457 importer
->format_table
= g_hash_table_new_full (
3458 g_direct_hash
, g_direct_equal
,
3459 NULL
, (GDestroyNotify
)biff_format_data_destroy
);
3460 importer
->palette
= NULL
;
3461 importer
->sst
= NULL
;
3462 importer
->sst_len
= 0;
3464 ms_container_init (&importer
->container
, &vtbl
, NULL
, importer
);
3469 excel_workbook_reset_style (GnmXLImporter
*importer
)
3473 g_hash_table_destroy (importer
->font_data
);
3474 importer
->font_data
= g_hash_table_new_full (
3475 g_direct_hash
, g_direct_equal
,
3476 NULL
, (GDestroyNotify
)excel_font_free
);
3478 for (i
= 0; i
< importer
->XF_cell_records
->len
; i
++)
3479 biff_xf_data_destroy (g_ptr_array_index (importer
->XF_cell_records
, i
));
3480 g_ptr_array_free (importer
->XF_cell_records
, TRUE
);
3481 importer
->XF_cell_records
= g_ptr_array_new ();
3483 g_hash_table_destroy (importer
->format_table
);
3484 importer
->format_table
= g_hash_table_new_full (
3485 g_direct_hash
, g_direct_equal
,
3486 NULL
, (GDestroyNotify
)biff_format_data_destroy
);
3490 gnm_xl_importer_free (GnmXLImporter
*importer
)
3493 GSList
*real_order
= NULL
;
3496 for (i
= importer
->boundsheet_sheet_by_index
->len
; i
-- > 0 ; ) {
3497 sheet
= g_ptr_array_index (importer
->boundsheet_sheet_by_index
, i
);
3499 real_order
= g_slist_prepend (real_order
, sheet
);
3502 if (real_order
!= NULL
) {
3503 workbook_sheet_reorder (importer
->wb
, real_order
);
3504 g_slist_free (real_order
);
3507 gnm_expr_sharer_destroy (importer
->expr_sharer
);
3509 g_hash_table_destroy (importer
->boundsheet_data_by_stream
);
3510 importer
->boundsheet_data_by_stream
= NULL
;
3511 g_ptr_array_free (importer
->boundsheet_sheet_by_index
, TRUE
);
3512 importer
->boundsheet_sheet_by_index
= NULL
;
3514 for (i
= 0; i
< importer
->excel_sheets
->len
; i
++)
3515 excel_sheet_destroy (g_ptr_array_index (importer
->excel_sheets
, i
));
3516 g_ptr_array_free (importer
->excel_sheets
, TRUE
);
3517 importer
->excel_sheets
= NULL
;
3519 if (NULL
!= importer
->pivot
.slicer
) {
3520 g_object_unref (importer
->pivot
.slicer
);
3521 importer
->pivot
.slicer
= NULL
;
3523 for (i
= 0; i
< importer
->pivot
.cache_by_index
->len
; i
++) {
3524 GObject
*cache
= g_ptr_array_index (importer
->pivot
.cache_by_index
, i
);
3526 g_object_unref (cache
);
3528 g_ptr_array_free (importer
->pivot
.cache_by_index
, TRUE
);
3529 importer
->pivot
.cache_by_index
= NULL
;
3531 for (i
= 0; i
< importer
->XF_cell_records
->len
; i
++)
3532 biff_xf_data_destroy (g_ptr_array_index (importer
->XF_cell_records
, i
));
3533 g_ptr_array_free (importer
->XF_cell_records
, TRUE
);
3534 importer
->XF_cell_records
= NULL
;
3536 g_hash_table_destroy (importer
->font_data
);
3537 importer
->font_data
= NULL
;
3539 g_hash_table_destroy (importer
->format_table
);
3540 importer
->format_table
= NULL
;
3542 if (importer
->palette
) {
3543 excel_palette_destroy (importer
->palette
);
3544 importer
->palette
= NULL
;
3547 for (i
= 0; i
< importer
->v8
.supbook
->len
; i
++ ) {
3548 ExcelSupBook
*sup
= &(g_array_index (importer
->v8
.supbook
,
3550 for (j
= 0; j
< sup
->externname
->len
; j
++ ) {
3551 GnmNamedExpr
*nexpr
= g_ptr_array_index (sup
->externname
, j
);
3553 expr_name_unref (nexpr
);
3555 g_ptr_array_free (sup
->externname
, TRUE
);
3557 g_array_free (importer
->v8
.supbook
, TRUE
);
3558 importer
->v8
.supbook
= NULL
;
3559 if (importer
->v8
.externsheet
!= NULL
) {
3560 g_array_free (importer
->v8
.externsheet
, TRUE
);
3561 importer
->v8
.externsheet
= NULL
;
3564 if (importer
->sst
!= NULL
) {
3565 unsigned i
= importer
->sst_len
;
3567 go_string_unref (importer
->sst
[i
].content
);
3568 go_format_unref (importer
->sst
[i
].markup
);
3570 g_free (importer
->sst
);
3573 for (i
= importer
->names
->len
; i
-- > 0 ; ) {
3574 GnmNamedExpr
*nexpr
= g_ptr_array_index (importer
->names
, i
);
3578 /* NAME placeholders need removal, EXTERNNAME
3579 * placeholders will no be active */
3580 if (expr_name_is_active (nexpr
) &&
3581 expr_name_is_placeholder (nexpr
) &&
3582 /* FIXME: Why do we need this? */
3583 nexpr
->ref_count
== 2) {
3584 d (1, g_printerr ("Removing name %s\n", expr_name_name (nexpr
)););
3585 expr_name_remove (nexpr
);
3587 expr_name_unref (nexpr
);
3589 g_ptr_array_free (importer
->names
, TRUE
);
3590 importer
->names
= NULL
;
3592 if (importer
->str_iconv
!= (GIConv
)(-1)) {
3593 gsf_iconv_close (importer
->str_iconv
);
3594 importer
->str_iconv
= (GIConv
)(-1);
3597 ms_container_finalize (&importer
->container
);
3602 * Unpacks a MS Excel RK structure,
3605 biff_get_rk (guint8
const *ptr
)
3609 eIEEE
= 0, eIEEEx100
= 1, eInt
= 2, eIntx100
= 3
3612 number
= GSF_LE_GET_GUINT32 (ptr
);
3613 type
= (number
& 0x3);
3622 /* Think carefully about big/little endian issues before
3623 changing this code. */
3624 for (lp
= 0; lp
< 4; lp
++) {
3625 tmp
[lp
+ 4]= (lp
> 0) ? ptr
[lp
]: (ptr
[lp
] & 0xfc);
3629 answer
= (gnm_float
)gsf_le_get_double (tmp
);
3630 return value_new_float (type
== eIEEEx100
? answer
/ 100 : answer
);
3633 return value_new_int (number
>> 2);
3636 if ((number
% 100) == 0)
3637 return value_new_int (number
/ 100);
3639 return value_new_float ((gnm_float
)number
/ 100);
3645 excel_builtin_name (guint8
const *ptr
)
3648 case 0x00: return "Consolidate_Area";
3649 case 0x01: return "Auto_Open";
3650 case 0x02: return "Auto_Close";
3651 case 0x03: return "Extract";
3652 case 0x04: return "Database";
3653 case 0x05: return "Criteria";
3654 case 0x06: return "Print_Area";
3655 case 0x07: return "Print_Titles";
3656 case 0x08: return "Recorder";
3657 case 0x09: return "Data_Form";
3658 case 0x0A: return "Auto_Activate";
3659 case 0x0B: return "Auto_Deactivate";
3660 case 0x0C: return "Sheet_Title";
3661 case 0x0D: return "_FilterDatabase";
3664 g_warning ("Unknown builtin named expression %d", (int)*ptr
);
3669 static GnmNamedExpr
*
3670 excel_parse_name (GnmXLImporter
*importer
, Sheet
*sheet
, char *name
,
3671 guint8
const *expr_data
, unsigned expr_len
,
3672 unsigned array_data_len
,
3673 gboolean link_to_container
,
3677 GnmNamedExpr
*nexpr
;
3678 GnmExprTop
const *texpr
= NULL
;
3681 g_return_val_if_fail (name
!= NULL
, NULL
);
3683 parse_pos_init (&pp
, importer
->wb
, sheet
, 0, 0);
3685 if (expr_len
== 0) {
3686 /* This seems to indicate a placeholder for an unknown name */
3687 texpr
= gnm_expr_top_new_constant (value_new_error_NAME (NULL
));
3689 texpr
= excel_parse_formula (&importer
->container
, NULL
, 0, 0,
3690 expr_data
, expr_len
,
3694 if (texpr
== NULL
) {
3695 go_io_warning (importer
->context
, _("Failure parsing name '%s'"), name
);
3696 texpr
= gnm_expr_top_new_constant (value_new_error_REF (NULL
));
3698 char *tmp
= gnm_expr_top_as_string
3699 (texpr
, &pp
, gnm_conventions_default
);
3700 g_printerr ("Expression: %s\n", tmp
);
3705 if (0 == strcmp (name
, "Print_Area")) {
3706 GnmValue
*val
= gnm_expr_get_range (texpr
->expr
);
3707 if (val
!= NULL
&& VALUE_IS_CELLRANGE (val
)) {
3710 if (sheet
== NULL
) {
3711 Sheet
*start_sheet
, *end_sheet
;
3714 /* Turn a global Print_Area name into a local
3715 name for the sheet it specifies. This
3716 triggers on the file from 632050. */
3717 gnm_rangeref_normalize_pp (value_get_rangeref (val
),
3722 if (start_sheet
&& end_sheet
== start_sheet
) {
3723 sheet
= start_sheet
;
3725 gnm_expr_top_unref (texpr
);
3726 texpr
= gnm_expr_top_new_constant (value_new_cellrange_r (NULL
, &dest
));
3733 range_init_rangeref (&r
, value_get_rangeref (val
));
3734 height
= range_height (&r
);
3735 width
= range_width (&r
);
3736 if (height
== gnm_sheet_get_max_rows (sheet
) &&
3737 width
== gnm_sheet_get_max_cols (sheet
)) {
3738 gnm_expr_top_unref (texpr
);
3743 value_release (val
);
3745 /* Completely ignore Print_Area settings of #REF! */
3746 if (texpr
== NULL
|| gnm_expr_top_is_err (texpr
, GNM_ERROR_REF
)) {
3747 if (texpr
) gnm_expr_top_unref (texpr
);
3752 nexpr
= expr_name_add (&pp
, name
,
3754 &err
, link_to_container
, stub
);
3755 if (nexpr
== NULL
) {
3756 go_io_warning (importer
->context
, "%s", err
);
3765 excel_read_name_str (GnmXLImporter
*importer
,
3766 guint8
const *data
, unsigned datalen
, unsigned *name_len
, gboolean is_builtin
)
3768 gboolean use_utf16
, has_extended
;
3769 unsigned trailing_data_len
, n_markup
;
3772 /* Lovely, they put suffixes on builtins. Then those !#$^
3773 * dipsticks put the unicode header _before_ the builtin id
3774 * and stored the id as a character (possibly two byte).
3775 * NOTE : len is in _characters_ (not bytes) does not include
3777 if (is_builtin
&& *name_len
) {
3778 guint8
const *str
= data
;
3779 char const *builtin
;
3782 if (importer
->ver
< MS_BIFF_V8
) {
3783 use_utf16
= has_extended
= FALSE
;
3784 n_markup
= trailing_data_len
= 0;
3786 int hlen
= excel_read_string_header
3788 &use_utf16
, &n_markup
, &has_extended
,
3789 &trailing_data_len
);
3794 clen
= use_utf16
? 2 : 1;
3796 /* pull out the magic builtin enum */
3797 if (datalen
>= clen
) {
3798 builtin
= excel_builtin_name (str
);
3804 if (--(*name_len
)) {
3807 *name_len
= MIN (*name_len
, datalen
/ clen
);
3808 tmp
= excel_get_chars (importer
, str
, *name_len
, use_utf16
, NULL
);
3809 name
= g_strconcat (builtin
, tmp
, NULL
);
3811 *name_len
= clen
* (*name_len
);
3813 name
= g_strdup (builtin
);
3815 *name_len
+= str
- data
;
3816 } else /* converts char len to byte len, and handles header */
3817 name
= excel_get_text (importer
, data
, *name_len
, name_len
, NULL
, datalen
);
3822 excel_read_EXTERNNAME (BiffQuery
*q
, MSContainer
*container
)
3824 MsBiffVersion
const ver
= container
->importer
->ver
;
3825 GnmNamedExpr
*nexpr
= NULL
;
3827 unsigned array_data_len
= 0; /* Is this always true? */
3830 g_printerr ("EXTERNNAME\n");
3831 gsf_mem_dump (q
->data
, q
->length
); });
3833 /* use biff version to differentiate, not the record version because
3834 * the version is the same for very old and new, with _v2 used for
3835 * some intermediate variants */
3836 if (ver
>= MS_BIFF_V7
) {
3837 unsigned expr_len
= 0;
3838 guint8
const *expr_data
= NULL
;
3842 XL_CHECK_CONDITION (q
->length
>= 7);
3844 flags
= GSF_LE_GET_GUINT8 (q
->data
);
3845 namelen
= GSF_LE_GET_GUINT8 (q
->data
+ 6);
3847 name
= excel_read_name_str (container
->importer
, q
->data
+ 7, q
->length
- 7, &namelen
, flags
&1);
3848 if ((flags
& (~1)) == 0) { /* all flags but builtin must be 0 */
3849 if (7 + 2 + namelen
<= q
->length
) {
3850 unsigned el
= GSF_LE_GET_GUINT16 (q
->data
+ 7 + namelen
);
3851 if (7 + 2 + namelen
+ el
<= q
->length
) {
3853 expr_data
= q
->data
+ 9 + namelen
;
3855 go_io_warning (container
->importer
->context
,
3856 _("Incorrect expression for name '%s': content will be lost.\n"),
3859 } else if ((flags
& 0x10) == 0) /* DDE */
3860 go_io_warning (container
->importer
->context
,
3861 _("DDE links are not supported yet.\nName '%s' will be lost.\n"),
3862 name
? name
: "NULL");
3864 go_io_warning (container
->importer
->context
,
3865 _("OLE links are not supported yet.\nName '%s' will be lost.\n"),
3866 name
? name
: "NULL");
3868 nexpr
= excel_parse_name (container
->importer
, NULL
,
3869 name
, expr_data
, expr_len
,
3870 array_data_len
, FALSE
, NULL
);
3871 } else if (ver
>= MS_BIFF_V5
) {
3872 XL_CHECK_CONDITION (q
->length
>= 7);
3874 name
= excel_biff_text_1 (container
->importer
, q
, 6);
3875 nexpr
= excel_parse_name (container
->importer
, NULL
,
3876 name
, NULL
, 0, array_data_len
,
3879 XL_CHECK_CONDITION (q
->length
>= 3);
3881 name
= excel_biff_text_1 (container
->importer
, q
, 2);
3882 nexpr
= excel_parse_name (container
->importer
, NULL
,
3883 name
, NULL
, 0, array_data_len
,
3887 /* nexpr is potentially NULL if there was an error */
3888 if (ver
>= MS_BIFF_V8
) {
3889 GnmXLImporter
*importer
= container
->importer
;
3890 ExcelSupBook
const *sup
;
3892 g_return_if_fail (importer
->v8
.supbook
->len
> 0);
3894 /* The name is associated with the last SUPBOOK records seen */
3895 sup
= &(g_array_index (importer
->v8
.supbook
, ExcelSupBook
,
3896 importer
->v8
.supbook
->len
-1));
3897 g_ptr_array_add (sup
->externname
, nexpr
);
3899 GPtrArray
*externnames
= container
->v7
.externnames
;
3900 if (externnames
== NULL
)
3901 externnames
= container
->v7
.externnames
= g_ptr_array_new ();
3902 g_ptr_array_add (externnames
, nexpr
);
3907 /* Do some error checking to handle the magic name associated with an
3908 * autofilter in a sheet. Do not make it an error.
3909 * We have lots of examples of things that are not autofilters.
3912 excel_prepare_autofilter (GnmXLImporter
*importer
, GnmNamedExpr
*nexpr
)
3914 if (nexpr
->pos
.sheet
!= NULL
) {
3915 GnmValue
*v
= gnm_expr_top_get_range (nexpr
->texpr
);
3918 gboolean valid
= gnm_sheet_range_from_value (&r
, v
);
3924 ExcelReadSheet
*esheet
;
3926 filter
= gnm_filter_new (r
.sheet
, &r
.range
);
3927 expr_name_remove (nexpr
);
3929 for (i
= 0 ; i
< importer
->excel_sheets
->len
; i
++) {
3930 esheet
= g_ptr_array_index (importer
->excel_sheets
, i
);
3931 if (esheet
->sheet
== r
.sheet
) {
3932 g_return_if_fail (esheet
->filter
== NULL
);
3933 esheet
->filter
= filter
;
3943 excel_read_NAME (BiffQuery
*q
, GnmXLImporter
*importer
, ExcelReadSheet
*esheet
)
3945 MsBiffVersion
const ver
= importer
->ver
;
3946 GnmNamedExpr
*nexpr
= NULL
;
3947 guint16 expr_len
, sheet_index
, flags
= 0;
3949 gboolean builtin_name
= FALSE
;
3951 /* length in characters (not bytes) in the same pos for all versions */
3953 /* guint8 kb_shortcut = GSF_LE_GET_GUINT8 (q->data + 2); */
3954 /* int fn_grp_idx = (flags & 0xfc0)>>6; */
3956 XL_CHECK_CONDITION (q
->length
>= 4);
3958 name_len
= GSF_LE_GET_GUINT8 (q
->data
+ 3);
3961 g_printerr ("NAME\n");
3962 gsf_mem_dump (q
->data
, q
->length
); });
3964 if (ver
>= MS_BIFF_V2
) {
3965 flags
= GSF_LE_GET_GUINT16 (q
->data
);
3966 builtin_name
= (flags
& 0x0020) != 0;
3969 /* use biff version to differentiate, not the record version because
3970 * the version is the same for very old and new, with _v2 used for
3971 * some intermediate variants */
3972 if (ver
>= MS_BIFF_V8
) {
3973 XL_CHECK_CONDITION (q
->length
>= 14);
3974 expr_len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3975 sheet_index
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
3976 data
= q
->data
+ 14;
3977 } else if (ver
>= MS_BIFF_V7
) {
3978 XL_CHECK_CONDITION (q
->length
>= 14);
3979 expr_len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3980 /* opencalc docs claim 8 is the right one, XL docs say 6 == 8
3981 * pivot.xls suggests that at least for local builtin names 6
3982 * is correct and 8 is bogus for == biff7 */
3983 sheet_index
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
3984 data
= q
->data
+ 14;
3985 } else if (ver
>= MS_BIFF_V3
) {
3986 XL_CHECK_CONDITION (q
->length
>= 6);
3987 expr_len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3989 sheet_index
= 0; /* no sheets */
3991 XL_CHECK_CONDITION (q
->length
>= 5);
3992 expr_len
= GSF_LE_GET_GUINT8 (q
->data
+ 4);
3994 sheet_index
= 0; /* no sheets */
3997 XL_NEED_BYTES (name_len
);
3998 name
= excel_read_name_str (importer
, data
, q
->length
- (data
- q
->data
), &name_len
, builtin_name
);
3999 XL_NEED_BYTES (name_len
);
4003 unsigned array_data_len
;
4004 Sheet
*sheet
= NULL
;
4005 d (1, g_printerr ("NAME=%s, sheet_index=%d flags=0x%x\n",
4006 name
, sheet_index
, flags
););
4007 if (sheet_index
> 0) {
4008 /* NOTE : the docs lie the index for biff7 is
4009 * indeed a reference to the externsheet
4010 * however we have examples in biff8 that can
4011 * only to be explained by a 1 based index to
4012 * the boundsheets. Which is not unreasonable
4013 * given that these are local names */
4014 if (importer
->ver
>= MS_BIFF_V8
) {
4015 if (sheet_index
<= importer
->boundsheet_sheet_by_index
->len
&&
4017 sheet
= g_ptr_array_index (importer
->boundsheet_sheet_by_index
, sheet_index
-1);
4019 g_warning ("So much for that theory 2");
4021 sheet
= excel_externsheet_v7 (&importer
->container
, sheet_index
);
4024 if (sheet
== XL_EXTERNSHEET_MAGIC_SELFREF
)
4025 sheet
= esheet
? esheet
->sheet
: NULL
;
4026 else if (sheet
== XL_EXTERNSHEET_MAGIC_DELETED
)
4029 /* do we have a stub from a forward decl ? */
4030 if (importer
->num_name_records
< importer
->names
->len
)
4031 nexpr
= g_ptr_array_index (importer
->names
, importer
->num_name_records
);
4033 XL_NEED_BYTES (expr_len
);
4034 array_data_len
= expr_len
? q
->length
- (data
- q
->data
) - expr_len
: 0;
4035 nexpr
= excel_parse_name (importer
, sheet
,
4036 name
, data
, expr_len
,
4037 array_data_len
, TRUE
, nexpr
);
4041 /* Add a ref to keep it around after the excel-sheet/wb goes
4042 * away. externnames do not get references and are unrefed
4043 * after import finishes, which destroys them if they are not
4045 if (nexpr
!= NULL
) {
4046 expr_name_ref (nexpr
);
4047 nexpr
->is_hidden
= (flags
& 0x0001) ? TRUE
: FALSE
;
4049 /* Undocumented magic.
4050 * XL stores a hidden name with the details of an autofilter */
4051 if (nexpr
->is_hidden
&& !strcmp (expr_name_name (nexpr
), "_FilterDatabase"))
4052 excel_prepare_autofilter (importer
, nexpr
);
4053 /* g_warning ("flags = %hx, state = %s\n", flags, global ? "global" : "sheet"); */
4055 else if ((flags
& 0xE) == 0xE) /* Function & VB-Proc & Proc */
4056 gnm_func_add_placeholder (importer
->wb
,
4057 expr_name_name (nexpr
), "VBA");
4061 /* nexpr is potentially NULL if there was an error */
4062 if (importer
->num_name_records
< importer
->names
->len
)
4063 g_ptr_array_index (importer
->names
, importer
->num_name_records
) = nexpr
;
4064 else if (importer
->num_name_records
== importer
->names
->len
)
4065 g_ptr_array_add (importer
->names
, nexpr
);
4066 importer
->num_name_records
++;
4069 guint8 menu_txt_len
= GSF_LE_GET_GUINT8 (q
->data
+ 10);
4070 guint8 descr_txt_len
= GSF_LE_GET_GUINT8 (q
->data
+ 11);
4071 guint8 help_txt_len
= GSF_LE_GET_GUINT8 (q
->data
+ 12);
4072 guint8 status_txt_len
= GSF_LE_GET_GUINT8 (q
->data
+ 13);
4073 const guint8
*end
= q
->data
+ q
->length
;
4079 menu_txt
= excel_get_text (importer
, data
, menu_txt_len
, NULL
, NULL
, end
- data
);
4080 data
+= menu_txt_len
;
4081 descr_txt
= excel_get_text (importer
, data
, descr_txt_len
, NULL
, NULL
, end
- data
);
4082 data
+= descr_txt_len
;
4083 help_txt
= excel_get_text (importer
, data
, help_txt_len
, NULL
, NULL
, end
- data
);
4084 data
+= help_txt_len
;
4085 status_txt
= excel_get_text (importer
, data
, status_txt_len
, NULL
, NULL
, end
- data
);
4087 g_printerr ("Name record: '%s', '%s', '%s', '%s', '%s'\n",
4088 nexpr
? expr_name_name (nexpr
) : "(null)",
4089 menu_txt
? menu_txt
: "(null)",
4090 descr_txt
? descr_txt
: "(null)",
4091 help_txt
? help_txt
: "(null)",
4092 status_txt
? status_txt
: "(null)");
4094 if ((flags
& 0x0001) != 0) g_printerr (" Hidden");
4095 if ((flags
& 0x0002) != 0) g_printerr (" Function");
4096 if ((flags
& 0x0004) != 0) g_printerr (" VB-Proc");
4097 if ((flags
& 0x0008) != 0) g_printerr (" Proc");
4098 if ((flags
& 0x0010) != 0) g_printerr (" CalcExp");
4099 if ((flags
& 0x0020) != 0) g_printerr (" BuiltIn");
4100 if ((flags
& 0x1000) != 0) g_printerr (" BinData");
4106 g_free (status_txt
);
4111 excel_read_XCT (BiffQuery
*q
, GnmXLImporter
*importer
)
4113 guint16 last_col
, opcode
;
4117 Sheet
*sheet
= NULL
;
4122 if (importer
->ver
>= MS_BIFF_V8
) {
4125 XL_CHECK_CONDITION (q
->length
== 4);
4127 count
= GSF_LE_GET_GINT16 (q
->data
);
4128 supbook
= GSF_LE_GET_GUINT16 (q
->data
+2);
4130 XL_CHECK_CONDITION (q
->length
== 2);
4132 count
= GSF_LE_GET_GINT16 (q
->data
);
4135 if (count
< 0) /* WHAT THE HECK DOES NEGATIVE MEAN ?? */
4139 eval_pos_init_sheet (&ep
, sheet
);
4141 while (count
-- > 0) {
4142 if (!ms_biff_query_peek_next (q
, &opcode
)) {
4143 g_warning ("Expected a CRN record");
4145 } else if (opcode
!= BIFF_CRN
) {
4146 g_warning ("Expected a CRN record not a %hx", opcode
);
4149 ms_biff_query_next (q
);
4151 XL_CHECK_CONDITION (q
->length
>= 4);
4153 ep
.eval
.col
= GSF_LE_GET_GUINT8 (q
->data
+0);
4154 last_col
= GSF_LE_GET_GUINT8 (q
->data
+1);
4155 ep
.eval
.row
= GSF_LE_GET_GUINT16 (q
->data
+2);
4157 /* ignore content for sheets that are already loaded */
4161 for (data
= q
->data
+ 4; ep
.eval
.col
<= last_col
; ep
.eval
.col
++) {
4169 v
= value_new_float (GSF_LE_GET_DOUBLE (data
));
4175 v
= value_new_string_nocopy (
4176 excel_get_text (importer
, data
, len
, NULL
, NULL
, q
->data
+ q
->length
- data
));
4182 v
= value_new_bool (GSF_LE_GET_GUINT16 (data
) != 0);
4189 v
= xls_value_new_err (&ep
, GSF_LE_GET_GUINT16 (data
));
4195 g_warning ("Unknown oper type 0x%x in a CRN record", oper
);
4200 cell
= sheet_cell_fetch (sheet
, ep
.eval
.col
, ep
.eval
.row
);
4202 gnm_cell_set_value (cell
, v
);
4210 static XL_font_width
const *
4211 xl_find_fontspec (ExcelReadSheet
*esheet
, double *size20
)
4213 /* Use the 'Normal' Style which is by definition the 0th */
4214 BiffXFData
const *xf
= excel_get_xf (esheet
, 0);
4215 ExcelFont
const *fd
= (xf
!= NULL
)
4216 ? excel_font_get (esheet
->container
.importer
, xf
->font_idx
)
4218 *size20
= (fd
!= NULL
) ? (fd
->height
/ (20. * 10.)) : 1.;
4219 return xl_lookup_font_specs ((fd
!= NULL
) ? fd
->fontname
: "Arial");
4223 * get_row_height_units:
4224 * @height height in Excel units
4226 * Converts row height from Excel units to points. Returns height in points.
4228 * Excel specifies row height in 1/20 of a point.
4230 * What we now print out is just 0.5% shorter than theoretical
4231 * height. The height of what Excel prints out varies in mysterious
4232 * ways. Sometimes it is close to theoretical, sometimes it is a few %
4233 * shorter. I don't see any point in correcting for the 0.5% until we
4234 * know the whole story.
4237 get_row_height_units (guint16 height
)
4239 return 1. / 20. * height
;
4243 excel_read_ROW (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4245 guint16 row
, height
;
4249 gboolean is_std_height
;
4251 XL_CHECK_CONDITION (q
->length
>= (q
->opcode
== BIFF_ROW_v2
? 16 : 8));
4253 row
= GSF_LE_GET_GUINT16 (q
->data
);
4255 /* Unnecessary info for now.
4256 * do we want to preallocate based on this info?
4258 guint16
const start_col
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4259 guint16
const end_col
= GSF_LE_GET_GUINT16 (q
->data
+ 4) - 1;
4261 height
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
4263 /* If the bit is on it indicates that the row is of 'standard' height.
4264 * However the remaining bits still include the size.
4266 is_std_height
= (height
& 0x8000) != 0;
4268 if (q
->opcode
== BIFF_ROW_v2
) {
4269 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
4270 flags2
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
4272 xf
= flags2
& 0xfff;
4275 g_printerr ("Row %d height 0x%x, flags=0x%x 0x%x;\n", row
+ 1, height
, flags
, flags2
);
4277 g_printerr ("%s\n", "Is Std Height;\n");
4278 if (flags2
& 0x1000)
4279 g_printerr ("%s\n", "Top thick;\n");
4280 if (flags2
& 0x2000)
4281 g_printerr ("%s\n", "Bottom thick;\n");
4284 /* TODO: Put mechanism in place to handle thick margins */
4285 /* TODO: Columns actually set the size even when it is the default.
4286 * Which approach is better?
4288 if (!is_std_height
) {
4289 double hu
= get_row_height_units (height
);
4290 sheet_row_set_size_pts (esheet
->sheet
, row
, hu
,
4291 (flags
& 0x40) ? TRUE
: FALSE
);
4295 colrow_set_visibility (esheet
->sheet
, FALSE
, FALSE
, row
, row
);
4299 excel_set_xf_segment (esheet
,
4300 0, gnm_sheet_get_max_cols (esheet
->sheet
) - 1,
4302 d (1, g_printerr ("row %d has flags 0x%x a default style %hd;\n",
4303 row
+ 1, flags
, xf
););
4306 if ((unsigned)(flags
& 0x17) > 0)
4307 col_row_info_set_outline (sheet_row_fetch (esheet
->sheet
, row
),
4308 (unsigned)(flags
& 0x7), flags
& 0x10);
4312 excel_read_TAB_COLOR (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4314 /* this is a guess, but the only field I see
4315 * changing seems to be the colour.
4318 0 | 62 8 0 0 0 0 0 0 0 0 0 0 14 0 0 0 | b
...............
4319 10 | 0 0 0 XX XX XX XX XX XX XX XX XX XX XX XX
| ...************
4321 office
12 seems to add
8 bytes
4325 GnmColor
*text_color
;
4328 XL_CHECK_CONDITION (q
->length
>= 20);
4330 /* be conservative for now, we have not seen a palette larger than 56
4331 * so this is largely moot, this is probably a uint32
4333 color_index
= GSF_LE_GET_GUINT8 (q
->data
+ 16);
4334 color
= excel_palette_get (esheet
->container
.importer
, color_index
);
4335 contrast
= GO_COLOR_UINT_R (color
->go_color
) +
4336 GO_COLOR_UINT_G (color
->go_color
) +
4337 GO_COLOR_UINT_B (color
->go_color
);
4338 if (contrast
>= 0x180)
4339 text_color
= style_color_black ();
4341 text_color
= style_color_white ();
4342 g_object_set (esheet
->sheet
,
4343 "tab-foreground", text_color
,
4344 "tab-background", color
,
4346 d (1, g_printerr ("%s tab colour = %08x\n",
4347 esheet
->sheet
->name_unquoted
,
4350 style_color_unref (text_color
);
4351 style_color_unref (color
);
4355 excel_read_COLINFO (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4358 double scale
, width
;
4359 guint16 firstcol
, lastcol
;
4361 guint16 xf
, options
;
4362 gboolean hidden
, customWidth
, bestFit
, collapsed
;
4363 unsigned outline_level
;
4364 XL_font_width
const *spec
;
4366 XL_CHECK_CONDITION (q
->length
>= 10);
4368 firstcol
= GSF_LE_GET_GUINT16 (q
->data
);
4369 lastcol
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4370 charwidths
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
4371 xf
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
4372 options
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
4373 hidden
= (options
& 0x0001) != 0;
4374 customWidth
= (options
& 0x0002) != 0; /* undocumented */
4375 bestFit
= (options
& 0x0004) != 0; /* undocumented */
4376 collapsed
= (options
& 0x1000) != 0;
4377 outline_level
= (unsigned)((options
>> 8) & 0x7);
4378 spec
= xl_find_fontspec (esheet
, &scale
);
4380 XL_CHECK_CONDITION (firstcol
< gnm_sheet_get_max_cols (esheet
->sheet
));
4381 g_return_if_fail (spec
!= NULL
);
4383 /* Widths appear to be quoted including margins and the leading
4384 * gridline that gnumeric expects. The charwidths here are not
4385 * strictly linear. So I measured in increments of -2 -1 0 1 2 around
4386 * the default width when using each font @ 10pts as
4387 * the Normal Style. The pixel calculation is then reduced to
4389 * (default_size + ((quoted_width - baseline) / step))
4390 * * scale : fonts != 10pts
4391 * * 72/96 : value in pts so that zoom is not a factor
4393 * NOTE: These measurements do NOT correspond to what is shown to the
4395 width
= 8. * spec
->defcol_unit
+
4396 (double)(charwidths
- spec
->colinfo_baseline
) / spec
->colinfo_step
;
4397 width
*= scale
* 72./96.;
4399 if (width
<= 0) { /* Columns are of default width */
4400 width
= esheet
->sheet
->cols
.default_style
.size_pts
;
4402 } else if (width
< 4) /* gnumeric can not draw without a margin */
4406 g_printerr ("Column Formatting %s!%s of width "
4407 "%u/256 characters (%f pts)\n",
4408 esheet
->sheet
->name_quoted
,
4409 cols_name (firstcol
, lastcol
), charwidths
, width
);
4410 g_printerr ("Options 0x%hx, default style %hu\n", options
, xf
);
4413 /* NOTE: seems like this is inclusive firstcol, inclusive lastcol */
4414 if (lastcol
>= gnm_sheet_get_max_cols (esheet
->sheet
))
4415 lastcol
= gnm_sheet_get_max_cols (esheet
->sheet
) - 1;
4416 for (i
= firstcol
; i
<= lastcol
; i
++) {
4417 sheet_col_set_size_pts (esheet
->sheet
, i
, width
,
4418 customWidth
&& !bestFit
);
4419 if (outline_level
> 0 || collapsed
)
4420 col_row_info_set_outline (sheet_col_fetch (esheet
->sheet
, i
),
4421 outline_level
, collapsed
);
4425 excel_set_xf_segment (esheet
, firstcol
, lastcol
,
4426 0, gnm_sheet_get_max_rows (esheet
->sheet
) - 1, xf
);
4429 colrow_set_visibility (esheet
->sheet
, TRUE
, FALSE
,
4433 /* Add a bmp header so that gdk-pixbuf can do the work */
4435 excel_read_os2bmp (BiffQuery
*q
, guint32 image_len
)
4438 GdkPixbufLoader
*loader
= NULL
;
4439 GdkPixbuf
*pixbuf
= NULL
;
4440 gboolean ret
= FALSE
;
4441 guint8 bmphdr
[BMP_HDR_SIZE
];
4443 XL_CHECK_CONDITION_VAL (q
->length
>= 8 && image_len
< q
->length
- 8, NULL
);
4445 loader
= gdk_pixbuf_loader_new_with_type ("bmp", &err
);
4448 excel_fill_bmp_header(bmphdr
, q
->data
, image_len
);
4449 ret
= gdk_pixbuf_loader_write (loader
, bmphdr
, sizeof bmphdr
, &err
);
4451 ret
= gdk_pixbuf_loader_write (loader
, q
->data
+8,
4453 gdk_pixbuf_loader_close (loader
, ret
? &err
: NULL
);
4455 pixbuf
= gdk_pixbuf_loader_get_pixbuf (loader
);
4456 g_object_ref (pixbuf
);
4458 g_message ("Unable to read OS/2 BMP image: %s\n",
4462 g_object_unref (loader
);
4466 /* When IMDATA or BG_PIC is bitmap, the format is OS/2 BMP, but the
4467 * 14 bytes header is missing.
4470 excel_read_IMDATA (BiffQuery
*q
, gboolean keep_image
)
4473 GdkPixbuf
*pixbuf
= NULL
;
4476 XL_CHECK_CONDITION_VAL (q
->length
>= 8, NULL
);
4478 format
= GSF_LE_GET_GUINT16 (q
->data
);
4479 image_len
= GSF_LE_GET_GUINT32 (q
->data
+ 4);
4482 case 0x2: break; /* Windows metafile/Mac pict */
4483 case 0x9: /* OS/2 BMP sans header */
4485 pixbuf
= excel_read_os2bmp (q
, image_len
);
4488 case 0xe: break; /* Native format */
4489 default: break; /* Unknown format */
4492 /* Dump formats which weren't handled above to file */
4493 if (format
!= 0x9) {
4494 char const *from_name
;
4495 char const *format_name
;
4496 guint16
const format
= GSF_LE_GET_GUINT16 (q
->data
);
4497 guint16
const from_env
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4500 case 1: from_name
= "Windows"; break;
4501 case 2: from_name
= "Macintosh"; break;
4502 default: from_name
= "Unknown environment?"; break;
4506 format_name
= (from_env
== 1) ? "windows metafile" : "mac pict";
4509 case 0xe: format_name
= "'native format'"; break;
4510 default: format_name
= "Unknown format?"; break;
4515 static int count
= 0;
4516 char *file_name
= g_strdup_printf ("imdata%d", count
++);
4517 g_printerr ("Picture from %s in %s format\n",
4518 from_name
, format_name
);
4520 f
= g_fopen (file_name
, "w");
4521 fwrite (q
->data
+8, 1, q
->length
-8, f
);
4531 excel_read_SELECTION (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4533 GnmCellPos edit_pos
;
4534 unsigned pane_number
, i
, j
, num_refs
;
4535 SheetView
*sv
= sheet_get_view (esheet
->sheet
, esheet
->container
.importer
->wbv
);
4538 XL_CHECK_CONDITION (q
->length
>= 9);
4539 pane_number
= GSF_LE_GET_GUINT8 (q
->data
);
4540 edit_pos
.row
= GSF_LE_GET_GUINT16 (q
->data
+ 1);
4541 edit_pos
.col
= GSF_LE_GET_GUINT16 (q
->data
+ 3);
4542 j
= GSF_LE_GET_GUINT16 (q
->data
+ 5);
4543 num_refs
= GSF_LE_GET_GUINT16 (q
->data
+ 7);
4544 XL_CHECK_CONDITION (q
->length
>= 9 + 6 * num_refs
);
4546 if (pane_number
!= esheet
->active_pane
)
4549 /* FIXME: docs say that consequtive records with the same pane
4550 number should be treated as one. No file with this has been
4553 d (5, g_printerr ("Start selection in pane #%d\n", pane_number
););
4554 d (5, g_printerr ("Cursor: %s in Ref #%d\n", cellpos_as_string (&edit_pos
),
4557 g_return_if_fail (sv
!= NULL
);
4559 sv_selection_reset (sv
);
4560 for (i
= 0; i
<= num_refs
; i
++) {
4562 unsigned i0
= (i
== num_refs
) ? j
: i
;
4564 /* Skip the active; then read it last. */
4565 if (i
== j
|| i0
>= num_refs
)
4568 xls_read_range8 (&r
, q
->data
+ 9 + 6 * i0
);
4570 d (5, g_printerr ("Ref %d = %s\n", i
, range_as_string (&r
)););
4572 tmp
= (i
== num_refs
) ? edit_pos
: r
.start
;
4573 sv_selection_add_full (sv
,
4575 r
.start
.col
, r
.start
.row
,
4576 r
.end
.col
, r
.end
.row
,
4577 GNM_SELECTION_MODE_ADD
);
4580 if (sv
->selections
== NULL
) {
4581 /* See bug 632050 */
4582 sv_selection_add_pos (sv
, 0, 0,
4583 GNM_SELECTION_MODE_ADD
);
4584 d (5, g_printerr ("No selection\n"););
4587 d (5, g_printerr ("Done selection\n"););
4591 excel_read_DEF_ROW_HEIGHT (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4594 guint16 height
= 0; /* must be 16 bit */
4595 double height_units
;
4597 if (q
->opcode
!= BIFF_DEFAULTROWHEIGHT_v0
) {
4598 XL_CHECK_CONDITION (q
->length
>= 4);
4599 flags
= GSF_LE_GET_GUINT16 (q
->data
);
4600 height
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4602 XL_CHECK_CONDITION (q
->length
>= 2);
4603 height
= GSF_LE_GET_GUINT16 (q
->data
);
4604 height
&= 0x7fff; /* there seems to be a flag in the top bit */
4607 height_units
= get_row_height_units (height
);
4609 g_printerr ("Default row height %3.3g;\n", height_units
);
4611 g_printerr (" + extra space above;\n");
4613 g_printerr (" + extra space below;\n");
4616 sheet_row_set_default_size_pts (esheet
->sheet
, height_units
);
4620 excel_read_DEF_COL_WIDTH (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4624 XL_font_width
const *spec
= xl_find_fontspec (esheet
, &scale
);
4626 XL_CHECK_CONDITION (q
->length
>= 2);
4627 charwidths
= GSF_LE_GET_GUINT16 (q
->data
);
4628 d (0, g_printerr ("Default column width %hu characters\n", charwidths
););
4630 /* According to the tooltip the default width is 8.43 character widths
4631 * and 64 pixels wide (Arial 10) which appears to include margins, and
4632 * the leading gridline That is saved as 8 char widths for
4633 * DEL_COL_WIDTH and 9.14 widths for COLINFO */
4634 sheet_col_set_default_size_pts (esheet
->sheet
,
4635 charwidths
* spec
->defcol_unit
* scale
* 72./96.);
4638 /* we could get this implicitly from the cols/rows
4639 * but this is faster
4642 excel_read_GUTS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4644 int col_gut
, row_gut
;
4646 XL_CHECK_CONDITION (q
->length
== 8);
4648 /* ignore the specification of how wide/tall the gutters are */
4649 row_gut
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
4650 d (2, g_printerr ("row_gut = %d", row_gut
););
4653 col_gut
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
4654 d (2, g_printerr ("col_gut = %d\n", col_gut
););
4657 sheet_colrow_gutter (esheet
->sheet
, TRUE
, col_gut
);
4658 sheet_colrow_gutter (esheet
->sheet
, FALSE
, row_gut
);
4662 excel_read_SETUP (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4664 GnmPrintInformation
*pi
= esheet
->sheet
->print_info
;
4666 gboolean rotate_paper
= FALSE
;
4667 gboolean portrait_orientation
= TRUE
;
4669 XL_CHECK_CONDITION (q
->length
>= 12);
4671 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
4672 pi
->print_across_then_down
= (flags
& 0x1) != 0;
4673 pi
->print_black_and_white
= (flags
& 0x8) != 0;
4675 if (0 == (flags
& 0x4)) {
4676 guint16 papersize
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
4677 const char *paper_name
=
4678 xls_paper_name (papersize
, &rotate_paper
);
4680 d (2, g_printerr ("Paper size %hu --> %s\n",
4682 paper_name
? paper_name
: "-"););
4684 if (paper_name
!= NULL
)
4685 print_info_set_paper (pi
, paper_name
);
4687 pi
->scaling
.percentage
.x
= pi
->scaling
.percentage
.y
=
4688 GSF_LE_GET_GUINT16 (q
->data
+ 2);
4689 pi
->start_page
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
4690 pi
->scaling
.dim
.cols
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
4691 pi
->scaling
.dim
.rows
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
4692 if (pi
->scaling
.percentage
.x
< 1. || pi
->scaling
.percentage
.x
> 1000.) {
4693 if (pi
->scaling
.percentage
.x
!= 0) {
4694 /* 0 seems to be 'auto' */
4695 g_warning ("setting invalid print scaling (%f) to 100%%",
4696 pi
->scaling
.percentage
.x
);
4698 pi
->scaling
.percentage
.x
= pi
->scaling
.percentage
.y
= 100.;
4701 if (esheet_ver (esheet
) == MS_BIFF_V4
|| 0 == (flags
& 0x40))
4702 portrait_orientation
= (flags
& 0x2) != 0;
4704 portrait_orientation
= !portrait_orientation
;
4706 print_info_set_paper_orientation (pi
, portrait_orientation
4707 ? GTK_PAGE_ORIENTATION_PORTRAIT
4708 : GTK_PAGE_ORIENTATION_LANDSCAPE
);
4711 if (esheet_ver (esheet
) > MS_BIFF_V4
) {
4712 XL_CHECK_CONDITION (q
->length
>= 34);
4714 pi
->print_as_draft
= (flags
& 0x10) != 0;
4715 pi
->comment_placement
= (flags
& 0x20)
4716 ? GNM_PRINT_COMMENTS_IN_PLACE
: GNM_PRINT_COMMENTS_NONE
;
4717 print_info_set_margin_header (pi
,
4718 GO_IN_TO_PT (gsf_le_get_double (q
->data
+ 16)));
4719 print_info_set_margin_footer (pi
,
4720 GO_IN_TO_PT (gsf_le_get_double (q
->data
+ 24)));
4721 if (0 == (flags
& 0x4))
4722 pi
->n_copies
= GSF_LE_GET_GUINT16 (q
->data
+ 32);
4723 d (2, g_printerr ("resolution %hu vert. res. %hu\n",
4724 GSF_LE_GET_GUINT16 (q
->data
+ 12),
4725 GSF_LE_GET_GUINT16 (q
->data
+ 14)););
4728 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
4729 if ((flags
& 0x200) &&
4730 pi
->comment_placement
== GNM_PRINT_COMMENTS_IN_PLACE
)
4731 pi
->comment_placement
= GNM_PRINT_COMMENTS_AT_END
;
4732 switch ((flags
>> 10) & 3) {
4733 case 0 : pi
->error_display
= GNM_PRINT_ERRORS_AS_DISPLAYED
; break;
4734 case 1 : pi
->error_display
= GNM_PRINT_ERRORS_AS_BLANK
; break;
4735 case 2 : pi
->error_display
= GNM_PRINT_ERRORS_AS_DASHES
; break;
4736 case 3 : pi
->error_display
= GNM_PRINT_ERRORS_AS_NA
; break;
4742 excel_read_MULRK (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4744 guint32 col
, row
, lastcol
;
4745 guint8
const *ptr
= q
->data
;
4747 BiffXFData
const *xf
;
4750 XL_CHECK_CONDITION (q
->length
>= 4 + 6 + 2);
4752 row
= GSF_LE_GET_GUINT16 (q
->data
);
4753 col
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4755 lastcol
= GSF_LE_GET_GUINT16 (q
->data
+ q
->length
- 2);
4757 XL_CHECK_CONDITION (lastcol
>= col
);
4758 XL_CHECK_CONDITION (lastcol
< (guint32
)gnm_sheet_get_max_cols (esheet
->sheet
));
4760 if (q
->length
!= 4 + 6 * (lastcol
- col
+ 1) + 2) {
4761 int guess
= col
+ (q
->length
- (4 + 2)) / 6 - 1;
4762 g_warning ("MULRK with strange size: %d vs %d", lastcol
, guess
);
4763 lastcol
= MIN (lastcol
, (guint32
)MAX (guess
, 0));
4766 for (; col
<= lastcol
; col
++) {
4768 /* 2byte XF, 4 byte RK */
4769 v
= biff_get_rk (ptr
+ 2);
4770 xf
= excel_get_xf (esheet
, GSF_LE_GET_GUINT16 (ptr
));
4771 mstyle
= excel_get_style_from_xf (esheet
, xf
);
4773 sheet_style_set_pos (esheet
->sheet
, col
, row
, mstyle
);
4774 if (xf
&& xf
->is_simple_format
)
4775 value_set_fmt (v
, xf
->style_format
);
4776 cell
= sheet_cell_fetch (esheet
->sheet
, col
, row
);
4778 gnm_cell_set_value (cell
, v
);
4786 excel_read_MULBLANK (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4788 /* This is an educated guess, docs are not terribly clear */
4789 int firstcol
, lastcol
, row
;
4790 guint8
const *ptr
= (q
->data
+ q
->length
- 2);
4791 int i
, range_end
, prev_xf
, xf_index
;
4793 XL_CHECK_CONDITION (q
->length
>= 6);
4794 firstcol
= XL_GETCOL (q
);
4795 row
= XL_GETROW (q
);
4796 lastcol
= GSF_LE_GET_GUINT16 (ptr
);
4798 g_printerr ("Cells in row %d are blank starting at col %s until col ",
4799 row
+ 1, col_name (firstcol
));
4800 g_printerr ("%s;\n",
4801 col_name (lastcol
));
4804 if (lastcol
< firstcol
) {
4809 XL_CHECK_CONDITION (q
->length
>= 4u + 2u * (lastcol
- firstcol
+ 1));
4811 range_end
= i
= lastcol
;
4815 xf_index
= GSF_LE_GET_GUINT16 (ptr
);
4817 g_printerr (" xf (%s) = 0x%x", col_name (i
), xf_index
);
4822 if (prev_xf
!= xf_index
) {
4824 excel_set_xf_segment (esheet
, i
+ 1, range_end
,
4829 } while (--i
>= firstcol
);
4830 excel_set_xf_segment (esheet
, firstcol
, range_end
,
4832 d (2, g_printerr ("\n"););
4836 xls_read_range32 (GnmRange
*r
, guint8
const *data
)
4838 r
->start
.row
= GSF_LE_GET_GUINT32 (data
+ 0);
4839 r
->end
.row
= GSF_LE_GET_GUINT32 (data
+ 4);
4840 r
->start
.col
= GSF_LE_GET_GUINT16 (data
+ 8);
4841 r
->end
.col
= GSF_LE_GET_GUINT16 (data
+ 10);
4843 r
->start
.row
= CLAMP (r
->start
.row
, 0, GNM_MAX_ROWS
- 1);
4844 r
->end
.row
= CLAMP (r
->end
.row
, 0, GNM_MAX_ROWS
- 1);
4845 r
->start
.col
= CLAMP (r
->start
.col
, 0, GNM_MAX_COLS
- 1);
4846 r
->end
.col
= CLAMP (r
->end
.col
, 0, GNM_MAX_COLS
- 1);
4848 d (4, range_dump (r
, ";\n"););
4852 xls_read_range16 (GnmRange
*r
, guint8
const *data
)
4854 r
->start
.row
= GSF_LE_GET_GUINT16 (data
+ 0);
4855 r
->end
.row
= GSF_LE_GET_GUINT16 (data
+ 2);
4856 r
->start
.col
= GSF_LE_GET_GUINT16 (data
+ 4);
4857 r
->end
.col
= GSF_LE_GET_GUINT16 (data
+ 6);
4859 r
->start
.row
= CLAMP (r
->start
.row
, 0, GNM_MAX_ROWS
- 1);
4860 r
->end
.row
= CLAMP (r
->end
.row
, 0, GNM_MAX_ROWS
- 1);
4861 r
->start
.col
= CLAMP (r
->start
.col
, 0, GNM_MAX_COLS
- 1);
4862 r
->end
.col
= CLAMP (r
->end
.col
, 0, GNM_MAX_COLS
- 1);
4864 d (4, range_dump (r
, ";\n"););
4868 xls_read_range8 (GnmRange
*r
, guint8
const *data
)
4870 r
->start
.row
= GSF_LE_GET_GUINT16 (data
+ 0);
4871 r
->end
.row
= GSF_LE_GET_GUINT16 (data
+ 2);
4872 r
->start
.col
= GSF_LE_GET_GUINT8 (data
+ 4);
4873 r
->end
.col
= GSF_LE_GET_GUINT8 (data
+ 5);
4874 d (4, range_dump (r
, ";\n"););
4878 * No documentation exists for this record, but this makes
4879 * sense given the other record formats.
4882 excel_read_MERGECELLS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4885 guint8
const *data
= q
->data
+ 2;
4889 XL_CHECK_CONDITION (q
->length
>= 2);
4890 num_merged
= GSF_LE_GET_GUINT16 (q
->data
);
4891 XL_CHECK_CONDITION (q
->length
== (unsigned int)(2 + 8 * num_merged
));
4893 for (; num_merged
-- > 0 ; data
+= 8) {
4894 xls_read_range16 (&r
, data
);
4895 overlap
= gnm_sheet_merge_get_overlap (esheet
->sheet
, &r
);
4897 GnmRange
*r2
= overlap
->data
;
4899 /* Unmerge r2, then merge (r U r2) */
4901 /* Do this early because the _remove can kill r2. */
4902 r
= range_union (&r
, r2
);
4904 gnm_sheet_merge_remove (esheet
->sheet
, r2
);
4905 g_slist_free (overlap
);
4907 gnm_sheet_merge_add (esheet
->sheet
, &r
, FALSE
,
4908 GO_CMD_CONTEXT (esheet
->container
.importer
->context
));
4913 excel_read_DIMENSIONS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4916 const char *key
= "DIMENSION";
4921 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
4922 XL_CHECK_CONDITION (q
->length
>= 12);
4923 xls_read_range32 (&r
, q
->data
);
4925 XL_CHECK_CONDITION (q
->length
>= 8);
4926 xls_read_range16 (&r
, q
->data
);
4929 if (range_width (&r
) <= 1 || range_height (&r
) <= 1) {
4930 g_object_set_data (G_OBJECT (esheet
->sheet
), key
, NULL
);
4931 d (1, g_printerr ("Dimension = -\n"););
4935 d (1, g_printerr ("Dimension = %s\n", range_as_string (&r
)););
4937 /* Hack: we need to get this information out to
4938 table_cellregion_read */
4939 g_object_set_data_full (G_OBJECT (esheet
->sheet
),
4940 key
, gnm_range_dup (&r
),
4945 static MSContainer
*
4946 sheet_container (ExcelReadSheet
*esheet
)
4948 ms_container_set_blips (&esheet
->container
, esheet
->container
.importer
->container
.blips
);
4949 return &esheet
->container
;
4953 excel_read_sheet_PROTECT (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4955 gboolean is_protected
= TRUE
;
4957 /* MS Docs fail to mention that in some stream this
4958 * record can have size zero. I assume the in that
4959 * case its existence is the flag. */
4961 is_protected
= (1 == GSF_LE_GET_GUINT16 (q
->data
));
4963 esheet
->sheet
->is_protected
= is_protected
;
4965 return is_protected
;
4969 excel_read_workbook_PROTECT (BiffQuery
*q
, WorkbookView
*wb_view
)
4971 gboolean is_protected
= TRUE
;
4973 /* MS Docs fail to mention that in some stream this
4974 * record can have size zero. I assume the in that
4975 * case its existence is the flag. */
4977 is_protected
= (1 == GSF_LE_GET_GUINT16 (q
->data
));
4979 wb_view
->is_protected
= is_protected
;
4981 return is_protected
;
4985 excel_read_WSBOOL (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4989 XL_CHECK_CONDITION (q
->length
== 2);
4991 options
= GSF_LE_GET_GUINT16 (q
->data
);
4992 /* 0x0001 automatic page breaks are visible */
4993 /* 0x0010 the sheet is a dialog sheet */
4994 /* 0x0020 automatic styles are not applied to an outline */
4995 esheet
->sheet
->outline_symbols_below
= 0 != (options
& 0x040);
4996 esheet
->sheet
->outline_symbols_right
= 0 != (options
& 0x080);
4997 if (NULL
!= esheet
->sheet
->print_info
)
4998 esheet
->sheet
->print_info
->scaling
.type
=
4999 (options
& 0x100) ? PRINT_SCALE_FIT_PAGES
: PRINT_SCALE_PERCENTAGE
;
5001 /* 0x0200 biff 3-4 0 == save external linked values, 1 == do not save */
5002 /* XL docs wrong 0xc00 no 0x600, OOo docs wrong no distinct row vs col */
5003 esheet
->sheet
->display_outlines
= 0 != (options
& 0xc00);
5005 /* Biff4 0x3000 window arrangement
5007 * 1b == arrange horiz
5008 * 10b == arrange vert
5011 /* biff 4-8 0x4000, 0 == std expr eval, 1 == alt expr eval ? */
5012 /* biff 4-8 0x8000, 0 == std fmla entry, 1 == alt fmla entry ? */
5016 excel_read_CALCCOUNT (BiffQuery
*q
, GnmXLImporter
*importer
)
5020 XL_CHECK_CONDITION (q
->length
== 2);
5022 count
= GSF_LE_GET_GUINT16 (q
->data
);
5024 workbook_iteration_max_number (importer
->wb
, count
);
5028 excel_read_CALCMODE (BiffQuery
*q
, GnmXLImporter
*importer
)
5030 XL_CHECK_CONDITION (q
->length
== 2);
5031 workbook_set_recalcmode (importer
->wb
,
5032 GSF_LE_GET_GUINT16 (q
->data
) != 0);
5036 excel_read_DELTA (BiffQuery
*q
, GnmXLImporter
*importer
)
5040 XL_CHECK_CONDITION (q
->length
== 8);
5042 tolerance
= gsf_le_get_double (q
->data
);
5043 XL_CHECK_CONDITION (tolerance
>= 0);
5045 workbook_iteration_tolerance (importer
->wb
, tolerance
);
5049 excel_read_ITERATION (BiffQuery
*q
, GnmXLImporter
*importer
)
5053 XL_CHECK_CONDITION (q
->length
== 2);
5055 enabled
= GSF_LE_GET_GUINT16 (q
->data
);
5056 workbook_iteration_enabled (importer
->wb
, enabled
!= 0);
5060 excel_read_PANE (BiffQuery
*q
, ExcelReadSheet
*esheet
, WorkbookView
*wb_view
)
5062 XL_CHECK_CONDITION (q
->length
== 10);
5063 if (esheet
->freeze_panes
) {
5064 guint16 x
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
5065 guint16 y
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
5066 guint16 rwTop
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
5067 guint16 colLeft
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
5068 SheetView
*sv
= sheet_get_view (esheet
->sheet
, esheet
->container
.importer
->wbv
);
5069 GnmCellPos frozen
, unfrozen
;
5071 esheet
->active_pane
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
5072 if (esheet
->active_pane
> 3) {
5073 g_warning ("Invalid pane '%u' selected", esheet
->active_pane
);
5074 esheet
->active_pane
= 3;
5077 g_return_if_fail (sv
!= NULL
);
5079 frozen
= unfrozen
= sv
->initial_top_left
;
5083 colLeft
= sv
->initial_top_left
.col
;
5087 rwTop
= sv
->initial_top_left
.row
;
5088 gnm_sheet_view_freeze_panes (sv
, &frozen
, &unfrozen
);
5089 gnm_sheet_view_set_initial_top_left (sv
, colLeft
, rwTop
);
5091 g_warning ("EXCEL : no support for split panes yet (%s)", esheet
->sheet
->name_unquoted
);
5096 excel_read_WINDOW2 (BiffQuery
*q
, ExcelReadSheet
*esheet
, WorkbookView
*wb_view
)
5098 SheetView
*sv
= sheet_get_view (esheet
->sheet
, esheet
->container
.importer
->wbv
);
5099 guint16 top_row
= 0;
5100 guint16 left_col
= 0;
5101 guint32 biff_pat_col
;
5102 gboolean set_grid_color
;
5104 if (q
->opcode
== BIFF_WINDOW2_v2
) {
5107 XL_CHECK_CONDITION (q
->length
>= 10);
5109 options
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
5110 esheet
->sheet
->display_formulas
= ((options
& 0x0001) != 0);
5111 esheet
->sheet
->hide_grid
= ((options
& 0x0002) == 0);
5112 esheet
->sheet
->hide_col_header
=
5113 esheet
->sheet
->hide_row_header
= ((options
& 0x0004) == 0);
5114 esheet
->freeze_panes
= ((options
& 0x0008) != 0);
5115 esheet
->sheet
->hide_zero
= ((options
& 0x0010) == 0);
5116 set_grid_color
= (options
& 0x0020) == 0;
5117 g_object_set (esheet
->sheet
, "text-is-rtl", (options
& 0x0040) != 0, NULL
);
5119 top_row
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
5120 left_col
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
5121 biff_pat_col
= GSF_LE_GET_GUINT32 (q
->data
+ 6);
5123 d (0, if (options
& 0x0200) g_printerr ("Sheet flag selected\n"););
5124 if (options
& 0x0400)
5125 wb_view_sheet_focus (wb_view
, esheet
->sheet
);
5127 if (esheet_ver (esheet
) >= MS_BIFF_V8
&& q
->length
>= 14) {
5129 guint16
const pageBreakZoom
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
5130 guint16
const normalZoom
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
5131 g_printerr ("%hx %hx\n", normalZoom
, pageBreakZoom
);
5135 XL_CHECK_CONDITION (q
->length
>= 14);
5137 esheet
->sheet
->display_formulas
= (q
->data
[0] != 0);
5138 esheet
->sheet
->hide_grid
= (q
->data
[1] == 0);
5139 esheet
->sheet
->hide_col_header
=
5140 esheet
->sheet
->hide_row_header
= (q
->data
[2] == 0);
5141 esheet
->freeze_panes
= (q
->data
[3] != 0);
5142 esheet
->sheet
->hide_zero
= (q
->data
[4] == 0);
5143 set_grid_color
= (q
->data
[9] == 0);
5145 top_row
= GSF_LE_GET_GUINT16 (q
->data
+ 5);
5146 left_col
= GSF_LE_GET_GUINT16 (q
->data
+ 7);
5147 biff_pat_col
= GSF_LE_GET_GUINT32 (q
->data
+ 10);
5150 if (set_grid_color
) {
5151 GnmColor
*pattern_color
;
5152 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
5153 /* Get style color from palette*/
5154 pattern_color
= excel_palette_get (
5155 esheet
->container
.importer
,
5156 biff_pat_col
& 0x7f);
5160 r
= (guint8
) biff_pat_col
;
5161 g
= (guint8
) (biff_pat_col
>> 8);
5162 b
= (guint8
) (biff_pat_col
>> 16);
5163 pattern_color
= gnm_color_new_rgb8 (r
, g
, b
);
5165 d (2, g_printerr ("auto pattern color "
5167 pattern_color
->go_color
););
5168 sheet_style_set_auto_pattern_color (
5169 esheet
->sheet
, pattern_color
);
5172 g_return_if_fail (sv
!= NULL
);
5174 /* until we import multiple views unfreeze just in case a previous view
5176 gnm_sheet_view_freeze_panes (sv
, NULL
, NULL
);
5178 /* NOTE : This is top left of screen even if frozen, modify when
5180 gnm_sheet_view_set_initial_top_left (sv
, left_col
, top_row
);
5184 excel_read_CF_border (GnmStyle
*style
, ExcelReadSheet
*esheet
,
5185 GnmStyleBorderLocation type
,
5186 unsigned xl_pat_index
, unsigned xl_color_index
)
5188 GnmStyleElement elem
= GNM_STYLE_BORDER_LOCATION_TO_STYLE_ELEMENT (type
);
5189 gnm_style_set_border (style
, elem
,
5190 gnm_style_border_fetch (biff_xf_map_border (xl_pat_index
),
5191 excel_palette_get (esheet
->container
.importer
,
5193 gnm_style_border_get_orientation (type
)));
5197 excel_read_CF (BiffQuery
*q
, ExcelReadSheet
*esheet
, GnmStyleConditions
*sc
,
5198 GnmXLImporter
*importer
)
5201 guint16 expr0_len
,expr1_len
;
5205 GnmStyleCond
*cond
= NULL
;
5207 GnmStyle
*overlay
= NULL
;
5209 XL_CHECK_CONDITION (q
->length
>= 12);
5211 type
= GSF_LE_GET_GUINT8 (q
->data
+ 0);
5212 op
= GSF_LE_GET_GUINT8 (q
->data
+ 1);
5213 expr0_len
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
5214 expr1_len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
5215 flags
= GSF_LE_GET_GUINT32 (q
->data
+ 6);
5216 flags2
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
5218 XL_CHECK_CONDITION (q
->length
>= 10u + expr0_len
+ expr1_len
);
5221 gsf_mem_dump (q
->data
+6, 6);
5222 g_printerr ("cond type = %d, op type = %d, flags = 0x%08x\n", (int)type
, (int)op
, flags
);
5227 case 0x01: cop
= GNM_STYLE_COND_BETWEEN
; break;
5228 case 0x02: cop
= GNM_STYLE_COND_NOT_BETWEEN
; break;
5229 case 0x03: cop
= GNM_STYLE_COND_EQUAL
; break;
5230 case 0x04: cop
= GNM_STYLE_COND_NOT_EQUAL
; break;
5231 case 0x05: cop
= GNM_STYLE_COND_GT
; break;
5232 case 0x06: cop
= GNM_STYLE_COND_LT
; break;
5233 case 0x07: cop
= GNM_STYLE_COND_GTE
; break;
5234 case 0x08: cop
= GNM_STYLE_COND_LTE
; break;
5236 g_warning ("EXCEL : Unknown condition (%d) for conditional format in sheet %s.",
5237 op
, esheet
->sheet
->name_unquoted
);
5242 cop
= GNM_STYLE_COND_CUSTOM
;
5246 g_warning ("EXCEL : Unknown condition type (%d) for format in sheet %s.",
5247 (int)type
, esheet
->sheet
->name_unquoted
);
5251 cond
= gnm_style_cond_new (cop
, esheet
->sheet
);
5253 if (expr0_len
> 0) {
5254 GnmExprTop
const *texpr
=
5255 ms_sheet_parse_expr_internal
5257 q
->data
+ q
->length
- expr0_len
- expr1_len
,
5259 gnm_style_cond_set_expr (cond
, texpr
, 0);
5260 gnm_expr_top_unref (texpr
);
5262 if (expr1_len
> 0) {
5263 GnmExprTop
const *texpr
=
5264 ms_sheet_parse_expr_internal
5266 q
->data
+ q
->length
- expr1_len
,
5268 gnm_style_cond_set_expr (cond
, texpr
, 1);
5269 gnm_expr_top_unref (texpr
);
5272 /* Reverse the alternate-expression treatment on save. */
5273 gnm_style_cond_canonicalize (cond
);
5275 /* UNDOCUMENTED : the format of the conditional format
5279 * 0xff : I'll guess fonts
5280 * uint8 : 0xff = no border
5286 * uint8 : 0x3f == no background elements,
5287 * 0x3b == background
5288 * 0x3a == background & pattern
5289 * 0x38 == background & pattern & pattern colour
5290 * uint8 : 0x04 = font | 0x10 = border | 0x20 = colour
5297 * Similar to XF from biff7
5300 overlay
= gnm_style_new ();
5302 offset
= 6 /* CF record header */ + 6; /* format header */
5304 if (flags
& 0x02000000) { /* number format */
5305 gboolean ignore
= (flags
& 0x00080000) != 0;
5307 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 2, goto fail
;);
5310 /* Format as string */
5311 guint bytes
= GSF_LE_GET_GUINT16 (q
->data
+ offset
);
5313 char *xlfmt
= excel_biff_text_2 (importer
, q
, offset
+ 2);
5314 GOFormat
*fmt
= go_format_new_from_XL (xlfmt
);
5315 gnm_style_set_format (overlay
, fmt
);
5316 go_format_unref (fmt
);
5321 /* Format as index */
5326 if (flags
& 0x04000000) { /* font */
5327 guint32 size
, colour
;
5328 guint8 tmp8
, font_flags
;
5329 guint8
const *data
= q
->data
+ offset
;
5331 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 64 + 54, goto fail
;);
5333 if (data
[0] && GSF_LE_GET_GUINT16 (data
+ 116) > 0) {
5334 char *font
= excel_biff_text_1
5335 (importer
, q
, offset
);
5336 gnm_style_set_font_name (overlay
, font
);
5342 if (0xFFFFFFFF != (size
= GSF_LE_GET_GUINT32 (data
)))
5343 gnm_style_set_font_size (overlay
, size
/ 20.);
5344 if (0xFFFFFFFF != (colour
= GSF_LE_GET_GUINT32 (data
+ 16)))
5345 gnm_style_set_font_color (overlay
,
5346 excel_palette_get (esheet
->container
.importer
,
5349 if (0 == GSF_LE_GET_GUINT8 (data
+ 36)) {
5350 gnm_style_set_font_bold (overlay
,
5351 GSF_LE_GET_GUINT16 (data
+ 8) >= 0x2bc);
5354 tmp8
= GSF_LE_GET_GUINT8 (data
+ 4);
5355 font_flags
= GSF_LE_GET_GUINT8 (data
+ 24);
5356 if (0 == (font_flags
& 2))
5357 gnm_style_set_font_italic (overlay
, 0 != (tmp8
& 2));
5359 if (0 == (font_flags
& 0x80))
5360 gnm_style_set_font_strike (overlay
, 0 != (tmp8
& 0x80));
5362 if (0 == GSF_LE_GET_GUINT8 (data
+ 28)) {
5363 switch (GSF_LE_GET_GUINT8 (data
+ 10)) {
5364 default : g_printerr ("Unknown script %d\n", GSF_LE_GET_GUINT8 (data
));
5366 case 0: gnm_style_set_font_script (overlay
, GO_FONT_SCRIPT_STANDARD
); break;
5367 case 1: gnm_style_set_font_script (overlay
, GO_FONT_SCRIPT_SUPER
); break;
5368 case 2: gnm_style_set_font_script (overlay
, GO_FONT_SCRIPT_SUB
); break;
5371 if (0 == GSF_LE_GET_GUINT8 (data
+ 32)) {
5372 MsBiffFontUnderline mul
;
5373 switch (GSF_LE_GET_GUINT8 (data
+ 12)) {
5376 mul
= XLS_ULINE_NONE
;
5379 mul
= XLS_ULINE_SINGLE
;
5382 mul
= XLS_ULINE_DOUBLE
;
5385 mul
= XLS_ULINE_SINGLE_ACC
;
5388 mul
= XLS_ULINE_DOUBLE_ACC
;
5391 gnm_style_set_font_uline
5393 xls_uline_to_gnm_underline (mul
));
5397 g_printerr ("%s\n", "Font");
5398 gsf_mem_dump (data
, 54);
5404 if (flags
& 0x08000000) { /* alignment block */
5407 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 8, goto fail
;);
5408 d1
= GSF_LE_GET_GUINT16 (q
->data
+ offset
);
5409 d2
= GSF_LE_GET_GUINT16 (q
->data
+ offset
+ 2);
5411 if (0 == (flags
& 0x1))
5412 gnm_style_set_align_h (overlay
,
5413 halign_from_excel ((d1
>> 0) & 7));
5415 if (0 == (flags
& 0x2))
5416 gnm_style_set_align_v (overlay
,
5417 valign_from_excel ((d1
>> 4) & 7));
5419 if (0 == (flags
& 0x4))
5420 gnm_style_set_wrap_text (overlay
, ((d1
>> 3) & 1));
5422 if (0 == (flags
& 0x8)) {
5423 int r
= (esheet_ver (esheet
) >= MS_BIFF_V8
5424 ? rotation_from_excel_v8 (d1
>> 8)
5425 : rotation_from_excel_v7 (d1
>> 8));
5426 gnm_style_set_rotation (overlay
, r
);
5429 if (0 == (flags
& 0x20))
5430 gnm_style_set_indent (overlay
, ((d2
>> 0) & 0xf));
5432 if (0 == (flags
& 0x40))
5433 gnm_style_set_shrink_to_fit (overlay
, ((d2
>> 4) & 1));
5438 if (flags
& 0x10000000) { /* borders */
5441 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 8, goto fail
;);
5442 d0
= GSF_LE_GET_GUINT32 (q
->data
+ offset
);
5443 d1
= GSF_LE_GET_GUINT32 (q
->data
+ offset
+ 4);
5445 if (0 == (flags
& 0x0400))
5446 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_LEFT
,
5449 if (0 == (flags
& 0x0800))
5450 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_RIGHT
,
5453 if (0 == (flags
& 0x1000))
5454 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_TOP
,
5457 if (0 == (flags
& 0x2000))
5458 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_BOTTOM
,
5461 if (0 == (flags
& 0x4000) && (d0
& 0x80000000)) {
5462 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_DIAG
,
5466 if (0 == (flags
& 0x8000) && (d0
& 0x40000000))
5467 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_REV_DIAG
,
5474 if (flags
& 0x20000000) { /* pattern */
5475 guint32 background_flags
;
5478 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 4, goto fail
;);
5479 background_flags
= GSF_LE_GET_GUINT32 (q
->data
+ offset
);
5481 if (0 == (flags
& 0x10000))
5482 gnm_style_set_pattern (overlay
,
5483 pattern
= excel_map_pattern_index_from_excel (
5484 (background_flags
>> 10) & 0x3F));
5485 if (0 == (flags
& 0x20000))
5486 gnm_style_set_pattern_color (overlay
,
5487 excel_palette_get (esheet
->container
.importer
,
5488 (background_flags
>> 16) & 0x7F));
5489 if (0 == (flags
& 0x40000))
5490 gnm_style_set_back_color (overlay
,
5491 excel_palette_get (esheet
->container
.importer
,
5492 (background_flags
>> 23) & 0x7F));
5497 if (flags
& 0x40000000) { /* protection */
5501 XL_CHECK_CONDITION_FULL (q
->length
== offset
+ expr0_len
+ expr1_len
, goto fail
;);
5503 d (1, gnm_style_dump (overlay
););
5505 gnm_style_cond_set_overlay (cond
, overlay
);
5506 gnm_style_unref (overlay
);
5507 gnm_style_conditions_insert (sc
, cond
, -1);
5508 gnm_style_cond_free (cond
);
5513 gnm_style_cond_free (cond
);
5515 gnm_style_unref (overlay
);
5519 excel_read_CONDFMT (BiffQuery
*q
, ExcelReadSheet
*esheet
,
5520 GnmXLImporter
*importer
)
5522 guint16 num_fmts
, num_areas
;
5525 GnmStyleConditions
*sc
;
5528 GSList
*ptr
, *regions
= NULL
;
5530 XL_CHECK_CONDITION (q
->length
>= 14);
5532 num_fmts
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
5533 num_areas
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
5535 d (1, g_printerr ("Num areas == %hu\n", num_areas
););
5537 /* The bounding box or the region containing all conditional formats.
5538 * It seems like this region is 0,0 -> 0xffff,0xffff when there are no
5542 xls_read_range16 (®ion
, q
->data
+4);
5545 data
= q
->data
+ 14;
5546 for (i
= 0 ; i
< num_areas
&& (data
+8) <= (q
->data
+ q
->length
) ; i
++, data
+= 8) {
5547 xls_read_range16 (®ion
, data
);
5548 regions
= g_slist_prepend (regions
, gnm_range_dup (®ion
));
5551 XL_CHECK_CONDITION (data
== q
->data
+ q
->length
);
5553 sc
= gnm_style_conditions_new (esheet
->sheet
);
5554 for (i
= 0 ; i
< num_fmts
; i
++) {
5556 if (!ms_biff_query_peek_next (q
, &next
) || next
!= BIFF_CF
) {
5557 g_object_unref (sc
);
5558 g_slist_free_full (regions
, g_free
);
5559 g_warning ("EXCEL: missing CF record");
5562 ms_biff_query_next (q
);
5563 excel_read_CF (q
, esheet
, sc
, importer
);
5566 style
= gnm_style_new ();
5567 gnm_style_set_conditions (style
, sc
);
5568 for (ptr
= regions
; ptr
!= NULL
; ptr
= ptr
->next
) {
5569 gnm_style_ref (style
);
5570 sheet_style_apply_range (esheet
->sheet
, ptr
->data
, style
);
5573 gnm_style_unref (style
);
5574 g_slist_free (regions
);
5578 excel_read_DV (BiffQuery
*q
, ExcelReadSheet
*esheet
)
5580 GnmExprTop
const *texpr1
= NULL
;
5581 GnmExprTop
const *texpr2
= NULL
;
5582 int expr1_len
, expr2_len
;
5583 char *input_msg
, *error_msg
, *input_title
, *error_title
;
5584 guint32 options
, len
;
5585 guint8
const *data
, *expr1_dat
, *expr2_dat
;
5586 guint8
const *end
= q
->data
+ q
->length
;
5589 ValidationStyle style
;
5590 ValidationType type
;
5592 GSList
*ptr
, *ranges
= NULL
;
5595 XL_CHECK_CONDITION (q
->length
>= 4);
5596 options
= GSF_LE_GET_GUINT32 (q
->data
);
5599 XL_CHECK_CONDITION (data
+3 <= end
);
5600 input_title
= excel_get_text (esheet
->container
.importer
, data
+ 2,
5601 GSF_LE_GET_GUINT16 (data
), &len
, NULL
,
5605 XL_CHECK_CONDITION (data
+3 <= end
);
5606 error_title
= excel_get_text (esheet
->container
.importer
, data
+ 2,
5607 GSF_LE_GET_GUINT16 (data
), &len
, NULL
,
5611 XL_CHECK_CONDITION (data
+3 <= end
);
5612 input_msg
= excel_get_text (esheet
->container
.importer
, data
+ 2,
5613 GSF_LE_GET_GUINT16 (data
), &len
, NULL
,
5617 XL_CHECK_CONDITION (data
+3 <= end
);
5618 error_msg
= excel_get_text (esheet
->container
.importer
, data
+ 2,
5619 GSF_LE_GET_GUINT16 (data
), &len
, NULL
,
5624 g_printerr ("Input Title : '%s'\n", input_title
);
5625 g_printerr ("Input Msg : '%s'\n", input_msg
);
5626 g_printerr ("Error Title : '%s'\n", error_title
);
5627 g_printerr ("Error Msg : '%s'\n", error_msg
);
5630 XL_CHECK_CONDITION (data
+4 <= end
);
5631 expr1_len
= GSF_LE_GET_GUINT16 (data
);
5632 d (5, g_printerr ("Unknown1 = %hx\n", GSF_LE_GET_GUINT16 (data
+2)););
5633 expr1_dat
= data
+ 4; /* TODO : What are the missing 2 bytes ? */
5634 data
+= expr1_len
+ 4;
5636 XL_CHECK_CONDITION (data
+4 <= end
);
5637 expr2_len
= GSF_LE_GET_GUINT16 (data
);
5638 d (5, g_printerr ("Unknown2 = %hx\n", GSF_LE_GET_GUINT16 (data
+2)););
5639 expr2_dat
= data
+ 4; /* TODO : What are the missing 2 bytes ? */
5640 data
+= expr2_len
+ 4;
5642 XL_CHECK_CONDITION (data
+2 < end
);
5643 i
= GSF_LE_GET_GUINT16 (data
);
5645 XL_CHECK_CONDITION ((end
- data
) / 8 >= i
);
5647 for (; i
-- > 0 ; data
+= 8) {
5648 xls_read_range16 (&r
, data
);
5649 ranges
= g_slist_prepend (ranges
, gnm_range_dup (&r
));
5652 /* these enums align, but lets be explicit so that the filter
5653 * is easier to read.
5655 switch (options
& 0x0f) {
5656 case 0 : type
= GNM_VALIDATION_TYPE_ANY
; break;
5657 case 1 : type
= GNM_VALIDATION_TYPE_AS_INT
; break;
5658 case 2 : type
= GNM_VALIDATION_TYPE_AS_NUMBER
; break;
5659 case 3 : type
= GNM_VALIDATION_TYPE_IN_LIST
; break;
5660 case 4 : type
= GNM_VALIDATION_TYPE_AS_DATE
; break;
5661 case 5 : type
= GNM_VALIDATION_TYPE_AS_TIME
; break;
5662 case 6 : type
= GNM_VALIDATION_TYPE_TEXT_LENGTH
; break;
5663 case 7 : type
= GNM_VALIDATION_TYPE_CUSTOM
; break;
5665 g_warning ("EXCEL : Unknown constraint type %d", options
& 0x0f);
5669 switch ((options
>> 4) & 0x07) {
5670 case 0 : style
= GNM_VALIDATION_STYLE_STOP
; break;
5671 case 1 : style
= GNM_VALIDATION_STYLE_WARNING
; break;
5672 case 2 : style
= GNM_VALIDATION_STYLE_INFO
; break;
5674 g_warning ("EXCEL : Unknown validation style %d",
5675 (options
>> 4) & 0x07);
5678 if (!(options
& 0x80000))
5679 style
= GNM_VALIDATION_STYLE_NONE
;
5681 if (type
== GNM_VALIDATION_TYPE_CUSTOM
|| type
== GNM_VALIDATION_TYPE_IN_LIST
)
5682 op
= GNM_VALIDATION_OP_NONE
;
5684 switch ((options
>> 20) & 0x0f) {
5685 case 0: op
= GNM_VALIDATION_OP_BETWEEN
; break;
5686 case 1: op
= GNM_VALIDATION_OP_NOT_BETWEEN
; break;
5687 case 2: op
= GNM_VALIDATION_OP_EQUAL
; break;
5688 case 3: op
= GNM_VALIDATION_OP_NOT_EQUAL
; break;
5689 case 4: op
= GNM_VALIDATION_OP_GT
; break;
5690 case 5: op
= GNM_VALIDATION_OP_LT
; break;
5691 case 6: op
= GNM_VALIDATION_OP_GTE
; break;
5692 case 7: op
= GNM_VALIDATION_OP_LTE
; break;
5694 g_warning ("EXCEL : Unknown constraint operator %d",
5695 (options
>> 20) & 0x0f);
5699 if (ranges
!= NULL
) {
5700 GnmRange
const *r
= ranges
->data
;
5707 texpr1
= excel_parse_formula (&esheet
->container
, esheet
,
5709 expr1_dat
, expr1_len
, 0 /* FIXME */,
5713 texpr2
= excel_parse_formula (&esheet
->container
, esheet
,
5715 expr2_dat
, expr2_len
, 0 /* FIXME */,
5718 d (1, g_printerr ("style = %d, type = %d, op = %d\n",
5721 mstyle
= gnm_style_new ();
5722 gnm_style_set_validation
5724 gnm_validation_new (style
, type
, op
,
5726 error_title
, error_msg
,
5729 options
& 0x0100, 0 == (options
& 0x0200)));
5730 if (options
& 0x40000)
5731 gnm_style_set_input_msg (mstyle
,
5732 gnm_input_msg_new (input_msg
, input_title
));
5734 for (ptr
= ranges
; ptr
!= NULL
; ptr
= ptr
->next
) {
5735 GnmRange
*r
= ptr
->data
;
5736 gnm_style_ref (mstyle
);
5737 sheet_style_apply_range (esheet
->sheet
, r
, mstyle
);
5738 d (1, range_dump (r
, "\n"););
5741 g_slist_free (ranges
);
5742 gnm_style_unref (mstyle
);
5745 g_free (input_title
);
5746 g_free (error_title
);
5750 excel_read_DVAL (BiffQuery
*q
, ExcelReadSheet
*esheet
)
5753 guint32 input_coord_x
, input_coord_y
, drop_down_id
, dv_count
;
5756 XL_CHECK_CONDITION (q
->length
== 18);
5758 options
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
5759 input_coord_x
= GSF_LE_GET_GUINT32 (q
->data
+ 2);
5760 input_coord_y
= GSF_LE_GET_GUINT32 (q
->data
+ 6);
5761 drop_down_id
= GSF_LE_GET_GUINT32 (q
->data
+ 10);
5762 dv_count
= GSF_LE_GET_GUINT32 (q
->data
+ 14);
5764 d (5, if (options
& 0x1) g_printerr ("DV input window is closed\n"););
5765 d (5, if (options
& 0x2) g_printerr ("DV input window is pinned\n"););
5766 d (5, if (options
& 0x4) g_printerr ("DV info has been cached ??\n"););
5768 for (i
= 0 ; i
< dv_count
; i
++) {
5770 if (!ms_biff_query_peek_next (q
, &next
) || next
!= BIFF_DV
) {
5771 g_warning ("EXCEL: missing DV record");
5774 ms_biff_query_next (q
);
5775 excel_read_DV (q
, esheet
);
5780 excel_read_SHEETPROTECTION (BiffQuery
*q
, Sheet
*sheet
)
5784 g_return_if_fail (sheet
!= NULL
);
5788 XL_CHECK_CONDITION (q
->length
>= 19);
5790 if (q
->length
>= 23) {
5791 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 19);
5792 sheet
->protected_allow
.edit_objects
= (flags
& (1 << 0)) != 0;
5793 sheet
->protected_allow
.edit_scenarios
= (flags
& (1 << 1)) != 0;
5794 sheet
->protected_allow
.cell_formatting
= (flags
& (1 << 2)) != 0;
5795 sheet
->protected_allow
.column_formatting
= (flags
& (1 << 3)) != 0;
5796 sheet
->protected_allow
.row_formatting
= (flags
& (1 << 4)) != 0;
5797 sheet
->protected_allow
.insert_columns
= (flags
& (1 << 5)) != 0;
5798 sheet
->protected_allow
.insert_rows
= (flags
& (1 << 6)) != 0;
5799 sheet
->protected_allow
.insert_hyperlinks
= (flags
& (1 << 7)) != 0;
5800 sheet
->protected_allow
.delete_columns
= (flags
& (1 << 8)) != 0;
5801 sheet
->protected_allow
.delete_rows
= (flags
& (1 << 9)) != 0;
5802 sheet
->protected_allow
.select_locked_cells
= (flags
& (1 << 10)) != 0;
5803 sheet
->protected_allow
.sort_ranges
= (flags
& (1 << 11)) != 0;
5804 sheet
->protected_allow
.edit_auto_filters
= (flags
& (1 << 12)) != 0;
5805 sheet
->protected_allow
.edit_pivottable
= (flags
& (1 << 13)) != 0;
5806 sheet
->protected_allow
.select_unlocked_cells
= (flags
& (1 << 14)) != 0;
5810 /***********************************************************************/
5813 read_utf16_str (int word_len
, guint8
const *data
)
5816 gunichar2
*uni_text
= g_alloca (word_len
* sizeof (gunichar2
));
5818 /* be wary about endianness */
5819 for (i
= 0 ; i
< word_len
; i
++, data
+= 2)
5820 uni_text
[i
] = GSF_LE_GET_GUINT16 (data
);
5822 return (guchar
*)g_utf16_to_utf8 (uni_text
, word_len
, NULL
, NULL
, NULL
);
5826 * XL (at least XL 2000) stores URLs exactly as input by the user. No
5827 * quoting, no mime encoding of email headers. If cgi parameters are
5828 * separated by '&', '&' is stored, not '&'. An email subject in
5829 * cyrillic characters is stored as cyrillic characters, not as an
5830 * RFC 2047 MIME encoded header.
5833 excel_read_HLINK (BiffQuery
*q
, ExcelReadSheet
*esheet
)
5835 static guint8
const stdlink_guid
[] = {
5836 0xd0, 0xc9, 0xea, 0x79, 0xf9, 0xba, 0xce, 0x11,
5837 0x8c, 0x82, 0x00, 0xaa, 0x00, 0x4b, 0xa9, 0x0b,
5839 0x02, 0x00, 0x00, 0x00
5841 static guint8
const url_guid
[] = {
5842 0xe0, 0xc9, 0xea, 0x79, 0xf9, 0xba, 0xce, 0x11,
5843 0x8c, 0x82, 0x00, 0xaa, 0x00, 0x4b, 0xa9, 0x0b,
5845 static guint8
const file_guid
[] = {
5846 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5847 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46,
5850 guint32 options
, len
;
5851 guint16 next_opcode
;
5852 guint8
const *data
= q
->data
;
5853 guchar
*label
= NULL
;
5854 guchar
*target_base
= NULL
;
5855 guchar
*mark
= NULL
;
5857 GnmHLink
*link
= NULL
;
5859 XL_CHECK_CONDITION (q
->length
> 32);
5861 xls_read_range16 (&r
, data
);
5862 options
= GSF_LE_GET_GUINT32 (data
+ 28);
5864 XL_CHECK_CONDITION (!memcmp (data
+ 8, stdlink_guid
, sizeof (stdlink_guid
)));
5869 range_dump (&r
, "");
5870 g_printerr (" = hlink options(0x%04x)\n", options
);
5873 if ((options
& 0x14) == 0x14) { /* label */
5874 XL_NEED_ITEMS (1, 4);
5875 len
= GSF_LE_GET_GUINT32 (data
);
5877 XL_NEED_ITEMS (len
, 2);
5878 label
= read_utf16_str (len
, data
);
5880 d (1, g_printerr ("label = %s\n", label
););
5883 if (options
& 0x80) { /* target_base */
5884 XL_NEED_ITEMS (1, 4);
5885 len
= GSF_LE_GET_GUINT32 (data
);
5887 XL_NEED_ITEMS (len
, 2);
5888 target_base
= read_utf16_str (len
, data
);
5890 d (1, g_printerr ("target_base = %s\n", target_base
););
5893 if (options
& 0x8) { /* 'text mark' */
5894 XL_NEED_ITEMS (1, 4);
5895 len
= GSF_LE_GET_GUINT32 (data
);
5898 XL_NEED_ITEMS (len
, 2);
5899 mark
= read_utf16_str (len
, data
);
5901 d (1, g_printerr ("mark = %s\n", mark
););
5904 if ((options
& 0x163) == 0x003 && !memcmp (data
, url_guid
, sizeof (url_guid
))) {
5907 data
+= sizeof (url_guid
);
5908 XL_NEED_ITEMS (1, 4);
5909 len
= GSF_LE_GET_GUINT32 (data
);
5912 XL_NEED_BYTES (len
);
5913 url
= read_utf16_str (len
/2, data
);
5914 if (NULL
!= url
&& 0 == g_ascii_strncasecmp (url
, "mailto:", 7))
5915 link
= gnm_hlink_new (gnm_hlink_email_get_type (), esheet
->sheet
);
5917 link
= gnm_hlink_new (gnm_hlink_url_get_type (), esheet
->sheet
);
5918 gnm_hlink_set_target (link
, url
);
5922 } else if ((options
& 0x1e1) == 0x001 && !memcmp (data
, file_guid
, sizeof (file_guid
))) {
5927 data
+= sizeof (file_guid
);
5930 up
= GSF_LE_GET_GUINT16 (data
+ 0);
5931 len
= GSF_LE_GET_GUINT32 (data
+ 2);
5932 d (1, g_printerr ("# leading ../ %d len 0x%04x\n",
5936 XL_NEED_BYTES (len
);
5939 XL_NEED_BYTES (16 + 12 + 6);
5941 len
= GSF_LE_GET_GUINT32 (data
);
5944 XL_NEED_BYTES (len
);
5945 path
= read_utf16_str (len
/2, data
);
5946 accum
= g_string_new (NULL
);
5948 g_string_append (accum
, "..\\");
5949 g_string_append (accum
, path
);
5951 link
= gnm_hlink_new (gnm_hlink_external_get_type (), esheet
->sheet
);
5952 gnm_hlink_set_target (link
, accum
->str
);
5953 g_string_free (accum
, TRUE
);
5956 } else if ((options
& 0x1e3) == 0x103) {
5959 XL_NEED_ITEMS (1, 4);
5960 len
= GSF_LE_GET_GUINT32 (data
);
5963 XL_NEED_BYTES (len
);
5964 path
= read_utf16_str (len
/2, data
);
5965 link
= gnm_hlink_new (gnm_hlink_external_get_type (), esheet
->sheet
);
5966 gnm_hlink_set_target (link
, path
);
5969 } else if ((options
& 0x1eb) == 0x008) {
5970 link
= gnm_hlink_new (gnm_hlink_cur_wb_get_type (), esheet
->sheet
);
5971 gnm_hlink_set_target (link
, mark
);
5973 g_warning ("Unknown hlink type 0x%x", options
);
5976 if (ms_biff_query_peek_next (q
, &next_opcode
) &&
5977 next_opcode
== BIFF_LINK_TIP
) {
5978 ms_biff_query_next (q
);
5979 /* according to OO the bytes 2..10 are the range for the tip */
5980 XL_CHECK_CONDITION (q
->length
> 10);
5981 tip
= read_utf16_str ((q
->length
- 10)/ 2, q
->data
+ 10);
5985 GnmStyle
*style
= gnm_style_new ();
5986 gnm_hlink_set_tip (link
, tip
);
5987 gnm_style_set_hlink (style
, link
);
5988 sheet_style_apply_range (esheet
->sheet
, &r
, style
);
5993 g_free (target_base
);
5998 excel_read_CODENAME (BiffQuery
*q
, GnmXLImporter
*importer
, ExcelReadSheet
*esheet
)
6003 XL_CHECK_CONDITION (q
->length
>= 2);
6005 codename
= excel_biff_text_2 (importer
, q
, 0);
6006 obj
= esheet
? G_OBJECT (esheet
->sheet
) : G_OBJECT (importer
->wb
);
6007 g_object_set_data_full (obj
, CODENAME_KEY
, codename
, g_free
);
6011 excel_read_BG_PIC (BiffQuery
*q
,
6012 ExcelReadSheet
*esheet
)
6014 /* undocumented, looks similar to IMDATA */
6015 GdkPixbuf
*background
= excel_read_IMDATA (q
, TRUE
);
6016 if (background
!= NULL
)
6017 g_object_unref (background
);
6021 read_DOPER (guint8
const *doper
, gboolean is_equal
,
6022 unsigned *str_len
, GnmFilterOp
*op
)
6024 static GnmFilterOp
const ops
[] = {
6026 GNM_FILTER_OP_EQUAL
,
6029 GNM_FILTER_OP_NOT_EQUAL
,
6032 GnmValue
*res
= NULL
;
6035 *op
= GNM_FILTER_UNUSED
;
6037 case 0: return NULL
; /* ignore */
6039 case 2: res
= biff_get_rk (doper
+ 2);
6041 case 4: res
= value_new_float (GSF_LE_GET_DOUBLE (doper
+2));
6043 case 6: *str_len
= doper
[6];
6046 case 8: if (doper
[2])
6047 res
= xls_value_new_err (NULL
, doper
[3]);
6049 res
= value_new_bool (doper
[3] ? TRUE
: FALSE
);
6052 case 0xC: *op
= GNM_FILTER_OP_BLANKS
;
6054 case 0xE: *op
= GNM_FILTER_OP_NON_BLANKS
;
6058 g_return_val_if_fail (doper
[1] > 0 && doper
[1] <=6, NULL
);
6059 *op
= ops
[doper
[1] - 1];
6065 excel_read_AUTOFILTER (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6068 GnmFilterCondition
*cond
= NULL
;
6071 /* XL only supports 1 filter per sheet */
6072 g_return_if_fail (esheet
->sheet
->filters
!= NULL
);
6073 g_return_if_fail (esheet
->sheet
->filters
->data
!= NULL
);
6074 g_return_if_fail (esheet
->sheet
->filters
->next
== NULL
);
6076 XL_CHECK_CONDITION (q
->length
>= 4);
6077 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
6079 filter
= esheet
->sheet
->filters
->data
;
6081 if (esheet_ver (esheet
) >= MS_BIFF_V8
&& flags
& 0x10)
6082 /* it's a top/bottom n */
6083 cond
= gnm_filter_condition_new_bucket (
6084 (flags
& 0x20) ? TRUE
: FALSE
,
6085 (flags
& 0x40) ? FALSE
: TRUE
,
6087 (flags
>> 7) & 0x1ff);
6090 unsigned len0
, len1
;
6091 GnmFilterOp op0
, op1
;
6093 guint8
const *end
= q
->data
+ q
->length
;
6096 XL_CHECK_CONDITION (q
->length
>= 24);
6097 v0
= read_DOPER (q
->data
+ 4, flags
& 4, &len0
, &op0
);
6098 v1
= read_DOPER (q
->data
+ 14, flags
& 8, &len1
, &op1
);
6100 data
= q
->data
+ 24;
6102 v0
= value_new_string_nocopy (
6103 excel_get_text (esheet
->container
.importer
, data
, len0
, NULL
, NULL
, end
- data
));
6107 v1
= value_new_string_nocopy (
6108 excel_get_text (esheet
->container
.importer
, data
, len1
, NULL
, NULL
, end
- data
));
6110 /* Survive fuzzed files. */
6111 if (op0
== GNM_FILTER_UNUSED
)
6112 op0
= GNM_FILTER_OP_BLANKS
;
6114 if (op1
== GNM_FILTER_UNUSED
) {
6115 cond
= gnm_filter_condition_new_single (op0
, v0
);
6116 value_release (v1
); /* paranoia */
6118 /* NOTE : Docs are backwards */
6119 cond
= gnm_filter_condition_new_double
6120 (op0
, v0
, (flags
& 3) ? FALSE
: TRUE
, op1
, v1
);
6124 gnm_filter_set_condition (filter
,
6125 GSF_LE_GET_GUINT16 (q
->data
), cond
, FALSE
);
6129 excel_read_SCL (BiffQuery
*q
, Sheet
*sheet
)
6131 unsigned num
, denom
;
6133 XL_CHECK_CONDITION (q
->length
== 4);
6135 num
= GSF_LE_GET_GUINT16 (q
->data
);
6136 denom
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
6138 XL_CHECK_CONDITION (denom
!= 0);
6140 g_object_set (sheet
, "zoom-factor", num
/ (double)denom
, NULL
);
6144 * excel_externsheet_v8 :
6146 * WARNING WARNING WARNING
6148 * This function can and will return intentionally INVALID pointers in some
6149 * cases. You need to check for XL_EXTERNSHEET_MAGIC_SELFREF
6150 * It should only happen for external names to deal with 'reference self'
6151 * supbook entries. However, you never know.
6153 * you also need to check for XL_EXTERNSHEET_MAGIC_DELETED which indicates deleted
6155 * WARNING WARNING WARNING
6157 ExcelExternSheetV8
const *
6158 excel_externsheet_v8 (GnmXLImporter
const *importer
, guint16 i
)
6160 d (2, g_printerr ("externv8 %hd\n", i
););
6162 g_return_val_if_fail (importer
->v8
.externsheet
!= NULL
, NULL
);
6164 if (i
>= importer
->v8
.externsheet
->len
) {
6165 g_warning ("%hd >= %u\n", i
, importer
->v8
.externsheet
->len
);
6169 return &(g_array_index (importer
->v8
.externsheet
, ExcelExternSheetV8
, i
));
6173 supbook_get_sheet (GnmXLImporter
*importer
, gint16 sup_index
, unsigned i
)
6175 if (sup_index
< 0) {
6176 g_warning ("external references not supported yet.");
6180 /* 0xffff == deleted */
6182 return XL_EXTERNSHEET_MAGIC_DELETED
; /* magic value */
6184 /* WARNING : 0xfffe record for local names kludge a solution */
6186 return XL_EXTERNSHEET_MAGIC_SELFREF
; /* magic value */
6188 g_return_val_if_fail ((unsigned)sup_index
< importer
->v8
.supbook
->len
, NULL
);
6190 switch (g_array_index (importer
->v8
.supbook
, ExcelSupBook
, sup_index
).type
) {
6191 case EXCEL_SUP_BOOK_SELFREF
: {
6193 g_return_val_if_fail (i
< importer
->boundsheet_sheet_by_index
->len
, NULL
);
6194 sheet
= g_ptr_array_index (importer
->boundsheet_sheet_by_index
, i
);
6195 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
6198 case EXCEL_SUP_BOOK_STD
:
6199 g_warning ("external references not supported yet.");
6201 case EXCEL_SUP_BOOK_PLUGIN
:
6202 g_warning ("strange external reference.");
6206 return XL_EXTERNSHEET_MAGIC_DELETED
; /* pretend "deleted" */
6210 excel_read_EXTERNSHEET_v8 (BiffQuery
const *q
, GnmXLImporter
*importer
)
6212 ExcelExternSheetV8
*v8
;
6214 unsigned i
, num
, first
, last
;
6216 XL_CHECK_CONDITION (importer
->ver
>= MS_BIFF_V8
);
6217 g_return_if_fail (importer
->v8
.externsheet
== NULL
);
6219 XL_CHECK_CONDITION (q
->length
>= 2);
6220 num
= GSF_LE_GET_GUINT16 (q
->data
);
6221 XL_CHECK_CONDITION (q
->length
>= 2 + num
* 6);
6223 d (2, g_printerr ("ExternSheet (%d entries)\n", num
););
6224 d (10, gsf_mem_dump (q
->data
, q
->length
););
6226 importer
->v8
.externsheet
= g_array_set_size (
6227 g_array_new (FALSE
, FALSE
, sizeof (ExcelExternSheetV8
)), num
);
6229 for (i
= 0; i
< num
; i
++) {
6230 sup_index
= GSF_LE_GET_GINT16 (q
->data
+ 2 + i
* 6 + 0);
6231 first
= GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
* 6 + 2);
6232 last
= GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
* 6 + 4);
6234 d (2, g_printerr ("ExternSheet: sup = %hd First sheet 0x%x, Last sheet 0x%x\n",
6235 sup_index
, first
, last
););
6237 v8
= &g_array_index(importer
->v8
.externsheet
, ExcelExternSheetV8
, i
);
6238 v8
->supbook
= sup_index
;
6239 v8
->first
= supbook_get_sheet (importer
, sup_index
, first
);
6240 v8
->last
= supbook_get_sheet (importer
, sup_index
, last
);
6241 d (2, g_printerr ("\tFirst sheet %p, Last sheet %p\n",
6242 v8
->first
, v8
->last
););
6247 * excel_externsheet_v7 :
6251 excel_externsheet_v7 (MSContainer
const *container
, gint16 idx
)
6253 GPtrArray
const *externsheets
;
6255 d (2, g_printerr ("externv7 %hd\n", idx
););
6257 externsheets
= container
->v7
.externsheets
;
6258 g_return_val_if_fail (externsheets
!= NULL
, NULL
);
6259 g_return_val_if_fail (idx
> 0, NULL
);
6260 g_return_val_if_fail (idx
<= (int)externsheets
->len
, NULL
);
6262 return g_ptr_array_index (externsheets
, idx
-1);
6266 excel_read_EXTERNSHEET_v7 (BiffQuery
const *q
, MSContainer
*container
)
6268 Sheet
*sheet
= NULL
;
6271 XL_CHECK_CONDITION (q
->length
>= 2);
6273 type
= GSF_LE_GET_GUINT8 (q
->data
+ 1);
6276 g_printerr ("extern v7 %p\n", container
);
6277 gsf_mem_dump (q
->data
, q
->length
); });
6280 case 2: sheet
= ms_container_sheet (container
);
6282 g_warning ("What does this mean ?");
6285 /* Type 3 is undocumented magic. It is used to forward declare sheet
6286 * names in the current workbook */
6288 unsigned len
= GSF_LE_GET_GUINT8 (q
->data
);
6291 /* opencalc screws up its export, overstating
6292 * the length by 1 */
6293 if (len
+ 2 > q
->length
)
6294 len
= q
->length
- 2;
6296 name
= excel_biff_text (container
->importer
, q
, 2, len
);
6299 sheet
= workbook_sheet_by_name (container
->importer
->wb
, name
);
6300 if (sheet
== NULL
) {
6301 /* There was a bug in 1.0.x export that spewed the quoted name
6302 * includling internal backquoting */
6303 if (name
[0] == '\'') {
6304 GString
*fixed
= g_string_new (NULL
);
6305 if (NULL
!= go_strunescape (fixed
, name
) &&
6306 NULL
!= (sheet
= workbook_sheet_by_name (container
->importer
->wb
, fixed
->str
))) {
6308 name
= g_string_free (fixed
, FALSE
);
6310 g_string_free (fixed
, TRUE
);
6313 if (sheet
== NULL
) {
6314 sheet
= sheet_new (container
->importer
->wb
,
6318 workbook_sheet_attach (container
->importer
->wb
, sheet
);
6325 case 4: /* undocumented. Seems to be used as a placeholder for names */
6326 sheet
= XL_EXTERNSHEET_MAGIC_SELFREF
;
6329 case 0x3a : /* undocumented magic. seems to indicate the sheet for an
6330 * addin with functions. 01 3a
6331 * the same as SUPBOOK
6333 if (*q
->data
== 1 && q
->length
== 2)
6337 /* Fix when we get placeholders to external workbooks */
6338 d (1, gsf_mem_dump (q
->data
, q
->length
););
6339 go_io_warning_unsupported_feature (container
->importer
->context
,
6340 _("external references"));
6343 if (container
->v7
.externsheets
== NULL
)
6344 container
->v7
.externsheets
= g_ptr_array_new ();
6345 g_ptr_array_add (container
->v7
.externsheets
, sheet
);
6349 excel_read_EXTERNSHEET (BiffQuery
const *q
, GnmXLImporter
*importer
,
6350 const MsBiffBofData
*ver
)
6352 XL_CHECK_CONDITION (ver
!= NULL
);
6354 if (ver
->version
>= MS_BIFF_V8
)
6355 excel_read_EXTERNSHEET_v8 (q
, importer
);
6357 excel_read_EXTERNSHEET_v7 (q
, &importer
->container
);
6361 /* FILEPASS, ask the user for a password if necessary
6362 * return value is an error string, or NULL for success
6365 excel_read_FILEPASS (BiffQuery
*q
, GnmXLImporter
*importer
)
6367 /* files with workbook protection are encrypted using a
6368 * static password (why ?? ). */
6369 if (ms_biff_query_set_decrypt(q
, importer
->ver
, "VelvetSweatshop"))
6373 guint8
*passwd
= go_cmd_context_get_password (
6374 GO_CMD_CONTEXT (importer
->context
),
6375 go_doc_get_uri (GO_DOC (importer
->wb
)));
6379 return _("No password supplied");
6381 ok
= ms_biff_query_set_decrypt (q
, importer
->ver
, passwd
);
6382 go_destroy_password (passwd
);
6390 excel_read_LABEL (BiffQuery
*q
, ExcelReadSheet
*esheet
, gboolean has_markup
)
6393 guint in_len
, str_len
;
6395 BiffXFData
const *xf
;
6396 ExcelFont
const *fd
;
6397 GnmCell
*cell
= excel_cell_fetch (q
, esheet
);
6402 XL_CHECK_CONDITION (q
->length
>= 8);
6403 in_len
= (q
->opcode
== BIFF_LABEL_v0
)
6404 ? GSF_LE_GET_GUINT8 (q
->data
+ 7)
6405 : GSF_LE_GET_GUINT16 (q
->data
+ 6);
6406 XL_CHECK_CONDITION (q
->length
- 8 >= in_len
);
6408 xf
= excel_set_xf (esheet
, q
);
6411 fd
= excel_font_get (esheet
->container
.importer
, xf
->font_idx
);
6413 txt
= excel_get_text (esheet
->container
.importer
, q
->data
+ 8,
6414 in_len
, &str_len
, fd
? &fd
->codepage
: NULL
,
6417 d (0, g_printerr ("%s in %s;\n",
6418 has_markup
? "formatted string" : "string",
6419 cell_name (cell
)););
6422 GOFormat
*fmt
= NULL
;
6424 fmt
= excel_read_LABEL_markup (q
, esheet
, txt
, str_len
);
6426 /* might free txt, do not do this until after parsing markup */
6427 v
= value_new_string_nocopy (txt
);
6429 value_set_fmt (v
, fmt
);
6430 go_format_unref (fmt
);
6432 gnm_cell_set_value (cell
, v
);
6437 excel_read_BOOLERR (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6439 unsigned base
= (q
->opcode
== BIFF_BOOLERR_v0
) ? 7 : 6;
6442 XL_CHECK_CONDITION (q
->length
>= base
+ 2);
6444 if (GSF_LE_GET_GUINT8 (q
->data
+ base
+ 1)) {
6446 eval_pos_init (&ep
, esheet
->sheet
, XL_GETCOL (q
), XL_GETROW (q
));
6447 v
= xls_value_new_err (&ep
, GSF_LE_GET_GUINT8 (q
->data
+ base
));
6449 v
= value_new_bool (GSF_LE_GET_GUINT8 (q
->data
+ base
));
6450 excel_sheet_insert_val (esheet
, q
, v
);
6454 excel_read_HEADER_FOOTER (GnmXLImporter
const *importer
,
6455 BiffQuery
*q
, ExcelReadSheet
*esheet
,
6458 GnmPrintInformation
*pi
= esheet
->sheet
->print_info
;
6463 if (importer
->ver
>= MS_BIFF_V8
)
6464 str
= excel_biff_text_2 (importer
, q
, 0);
6466 str
= excel_biff_text_1 (importer
, q
, 0);
6468 d (2, g_printerr ("%s == '%s'\n", is_header
? "header" : "footer", str
););
6470 xls_header_footer_import (is_header
? &pi
->header
: &pi
->footer
,
6478 excel_read_REFMODE (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6482 XL_CHECK_CONDITION (q
->length
>= 2);
6483 mode
= GSF_LE_GET_GUINT16 (q
->data
);
6484 g_object_set (esheet
->sheet
, "use-r1c1", mode
== 0, NULL
);
6488 excel_read_PAGE_BREAK (BiffQuery
*q
, ExcelReadSheet
*esheet
, gboolean is_vert
)
6491 unsigned step
= (esheet_ver (esheet
) >= MS_BIFF_V8
) ? 6 : 2;
6493 GnmPageBreaks
*breaks
;
6495 XL_CHECK_CONDITION (q
->length
>= 2);
6496 count
= GSF_LE_GET_GUINT16 (q
->data
);
6497 XL_CHECK_CONDITION (q
->length
>= 2 + count
* step
);
6498 breaks
= gnm_page_breaks_new (is_vert
);
6500 /* 1) Ignore the first/last info for >= biff8
6501 * 2) Assume breaks are manual in the absence of any information */
6502 for (i
= 0; i
< count
; i
++) {
6503 gnm_page_breaks_append_break (breaks
,
6504 GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
*step
), GNM_PAGE_BREAK_MANUAL
);
6506 g_printerr ("%d %d:%d\n",
6507 GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
*step
),
6508 GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
*step
+ 2),
6509 GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
*step
+ 4));
6512 print_info_set_breaks (esheet
->sheet
->print_info
, breaks
);
6516 excel_read_INTEGER (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6518 XL_CHECK_CONDITION (q
->length
>= 7 + 2);
6519 excel_sheet_insert_val
6521 value_new_int (GSF_LE_GET_GUINT16 (q
->data
+ 7)));
6525 excel_read_NUMBER (BiffQuery
*q
, ExcelReadSheet
*esheet
, size_t ofs
)
6527 XL_CHECK_CONDITION (q
->length
>= ofs
+ 8);
6528 excel_sheet_insert_val
6530 value_new_float (gsf_le_get_double (q
->data
+ ofs
)));
6534 excel_read_MARGIN (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6537 GnmPrintInformation
*pi
= esheet
->sheet
->print_info
;
6539 XL_CHECK_CONDITION (q
->length
>= 8);
6540 m
= GO_IN_TO_PT (gsf_le_get_double (q
->data
));
6542 switch (q
->opcode
) {
6543 case BIFF_LEFT_MARGIN
: print_info_set_margin_left (pi
, m
); break;
6544 case BIFF_RIGHT_MARGIN
: print_info_set_margin_right (pi
, m
); break;
6545 case BIFF_TOP_MARGIN
: print_info_set_edge_to_below_header (pi
, m
); break;
6546 case BIFF_BOTTOM_MARGIN
: print_info_set_edge_to_above_footer (pi
, m
); break;
6547 default: g_assert_not_reached ();
6553 excel_read_PRINTHEADERS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6555 XL_CHECK_CONDITION (q
->length
>= 2);
6556 esheet
->sheet
->print_info
->print_titles
=
6557 (GSF_LE_GET_GUINT16 (q
->data
) == 1);
6561 excel_read_PRINTGRIDLINES (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6563 XL_CHECK_CONDITION (q
->length
>= 2);
6564 esheet
->sheet
->print_info
->print_grid_lines
=
6565 (GSF_LE_GET_GUINT16 (q
->data
) == 1);
6569 excel_read_HCENTER (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6571 XL_CHECK_CONDITION (q
->length
>= 2);
6572 esheet
->sheet
->print_info
->center_horizontally
=
6573 GSF_LE_GET_GUINT16 (q
->data
) == 0x1;
6577 excel_read_VCENTER (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6579 XL_CHECK_CONDITION (q
->length
>= 2);
6580 esheet
->sheet
->print_info
->center_vertically
=
6581 GSF_LE_GET_GUINT16 (q
->data
) == 0x1;
6585 excel_read_PLS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6587 XL_CHECK_CONDITION (q
->length
>= 2);
6588 if (GSF_LE_GET_GUINT16 (q
->data
) == 0x00) {
6590 * q->data + 2 -> q->data + q->length
6591 * map to a DEVMODE structure see MS' SDK.
6593 } else if (GSF_LE_GET_GUINT16 (q
->data
) == 0x01) {
6595 * q's data maps to a TPrint structure
6596 * see Inside Macintosh Vol II p 149.
6602 excel_read_RK (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6604 XL_CHECK_CONDITION (q
->length
>= 6 + 4);
6605 excel_sheet_insert_val (esheet
, q
,
6606 biff_get_rk (q
->data
+ 6));
6610 excel_read_LABELSST (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6614 XL_CHECK_CONDITION (q
->length
>= 6 + 4);
6615 i
= GSF_LE_GET_GUINT32 (q
->data
+ 6);
6617 if (esheet
->container
.importer
->sst
&& i
< esheet
->container
.importer
->sst_len
) {
6619 GOString
*str
= esheet
->container
.importer
->sst
[i
].content
;
6620 /* ? Why would there be a NULL ? */
6622 go_string_ref (str
);
6623 v
= value_new_string_str (str
);
6624 d (2, g_printerr ("str=%s\n", str
->str
););
6626 v
= value_new_string ("");
6627 if (esheet
->container
.importer
->sst
[i
].markup
!= NULL
)
6628 value_set_fmt (v
, esheet
->container
.importer
->sst
[i
].markup
);
6629 excel_sheet_insert_val (esheet
, q
, v
);
6631 g_warning ("string index 0x%u >= 0x%x\n",
6632 i
, esheet
->container
.importer
->sst_len
);
6636 excel_read_sheet (BiffQuery
*q
, GnmXLImporter
*importer
,
6637 WorkbookView
*wb_view
, ExcelReadSheet
*esheet
)
6639 MsBiffVersion
const ver
= importer
->ver
;
6641 g_return_val_if_fail (importer
!= NULL
, FALSE
);
6642 g_return_val_if_fail (esheet
!= NULL
, FALSE
);
6643 g_return_val_if_fail (esheet
->sheet
!= NULL
, FALSE
);
6644 g_return_val_if_fail (esheet
->sheet
->print_info
!= NULL
, FALSE
);
6646 d (1, g_printerr ("----------------- '%s' -------------\n",
6647 esheet
->sheet
->name_unquoted
););
6649 if (ver
<= MS_BIFF_V4
) {
6650 /* Style is per-sheet in early Excel - default TODO */
6651 excel_workbook_reset_style (importer
);
6653 /* Apply the default style */
6654 GnmStyle
*mstyle
= excel_get_style_from_xf (esheet
,
6655 excel_get_xf (esheet
, 15));
6656 if (mstyle
!= NULL
) {
6658 range_init_full_sheet (&r
, esheet
->sheet
);
6659 sheet_style_set_range (esheet
->sheet
, &r
, mstyle
);
6663 for (; ms_biff_query_next (q
) ;
6664 go_io_value_progress_update (importer
->context
, q
->streamPos
)) {
6667 const char *opname
= biff_opcode_name (q
->opcode
);
6668 g_printerr ("Opcode: 0x%x %s\n",
6670 opname
? opname
: "unknown");
6673 switch (q
->opcode
) {
6674 case BIFF_DIMENSIONS_v0
: break; /* ignore ancient XL2 variant */
6675 case BIFF_DIMENSIONS_v2
: excel_read_DIMENSIONS (q
, esheet
); break;
6679 (void)excel_set_xf (esheet
, q
);
6683 excel_read_INTEGER (q
, esheet
);
6685 case BIFF_NUMBER_v0
:
6686 excel_read_NUMBER (q
, esheet
, 7);
6688 case BIFF_NUMBER_v2
:
6689 excel_read_NUMBER (q
, esheet
, 6);
6694 excel_read_LABEL (q
, esheet
, FALSE
);
6697 case BIFF_BOOLERR_v0
:
6698 case BIFF_BOOLERR_v2
:
6699 excel_read_BOOLERR (q
, esheet
);
6702 case BIFF_FORMULA_v0
:
6703 case BIFF_FORMULA_v2
:
6704 case BIFF_FORMULA_v4
: excel_read_FORMULA (q
, esheet
); break;
6705 /* case STRING : is handled elsewhere since it always follows FORMULA */
6707 case BIFF_ROW_v2
: excel_read_ROW (q
, esheet
); break;
6708 case BIFF_EOF
: goto success
;
6710 /* NOTE : bytes 12 & 16 appear to require the non decrypted data */
6712 case BIFF_INDEX_v2
: break;
6714 case BIFF_CALCCOUNT
: excel_read_CALCCOUNT (q
, importer
); break;
6715 case BIFF_CALCMODE
: excel_read_CALCMODE (q
,importer
); break;
6717 case BIFF_PRECISION
:
6720 /* FIXME: implement in gnumeric */
6721 /* state of 'Precision as Displayed' option */
6722 guint16
const data
= GSF_LE_GET_GUINT16 (q
->data
);
6723 gboolean
const prec_as_displayed
= (data
== 0);
6728 case BIFF_REFMODE
: excel_read_REFMODE (q
, esheet
); break;
6729 case BIFF_DELTA
: excel_read_DELTA (q
, importer
); break;
6730 case BIFF_ITERATION
: excel_read_ITERATION (q
, importer
); break;
6731 case BIFF_OBJPROTECT
:
6732 case BIFF_PROTECT
: excel_read_sheet_PROTECT (q
, esheet
); break;
6735 if (q
->length
== 2) {
6736 d (2, g_printerr ("sheet password '%hx'\n",
6737 GSF_LE_GET_GUINT16 (q
->data
)););
6743 case BIFF_HEADER
: excel_read_HEADER_FOOTER (importer
, q
, esheet
, TRUE
); break;
6744 case BIFF_FOOTER
: excel_read_HEADER_FOOTER (importer
, q
, esheet
, FALSE
); break;
6746 case BIFF_EXTERNCOUNT
: /* ignore */ break;
6747 case BIFF_EXTERNSHEET
: /* These cannot be biff8 */
6748 excel_read_EXTERNSHEET_v7 (q
, &esheet
->container
);
6751 case BIFF_VERTICALPAGEBREAKS
: excel_read_PAGE_BREAK (q
, esheet
, TRUE
); break;
6752 case BIFF_HORIZONTALPAGEBREAKS
: excel_read_PAGE_BREAK (q
, esheet
, FALSE
); break;
6754 case BIFF_NOTE
: excel_read_NOTE (q
, esheet
); break;
6755 case BIFF_SELECTION
: excel_read_SELECTION (q
, esheet
); break;
6756 case BIFF_EXTERNNAME_v0
:
6757 case BIFF_EXTERNNAME_v2
:
6758 excel_read_EXTERNNAME (q
, &esheet
->container
);
6760 case BIFF_DEFAULTROWHEIGHT_v0
:
6761 case BIFF_DEFAULTROWHEIGHT_v2
:
6762 excel_read_DEF_ROW_HEIGHT (q
, esheet
);
6765 case BIFF_LEFT_MARGIN
:
6766 case BIFF_RIGHT_MARGIN
:
6767 case BIFF_TOP_MARGIN
:
6768 case BIFF_BOTTOM_MARGIN
:
6769 excel_read_MARGIN (q
, esheet
);
6772 case BIFF_PRINTHEADERS
:
6773 excel_read_PRINTHEADERS (q
, esheet
);
6776 case BIFF_PRINTGRIDLINES
:
6777 excel_read_PRINTGRIDLINES (q
, esheet
);
6780 case BIFF_WINDOW1
: break; /* what does this do for a sheet ? */
6781 case BIFF_WINDOW2_v0
:
6782 case BIFF_WINDOW2_v2
:
6783 excel_read_WINDOW2 (q
, esheet
, wb_view
);
6785 case BIFF_BACKUP
: break;
6786 case BIFF_PANE
: excel_read_PANE (q
, esheet
, wb_view
); break;
6788 case BIFF_PLS
: excel_read_PLS (q
, esheet
); break;
6790 case BIFF_DEFCOLWIDTH
: excel_read_DEF_COL_WIDTH (q
, esheet
); break;
6792 case BIFF_OBJ
: ms_read_OBJ (q
, sheet_container (esheet
), NULL
); break;
6794 case BIFF_SAVERECALC
: break;
6795 case BIFF_TAB_COLOR
: excel_read_TAB_COLOR (q
, esheet
); break;
6796 case BIFF_COLINFO
: excel_read_COLINFO (q
, esheet
); break;
6798 case BIFF_RK
: excel_read_RK (q
, esheet
); break;
6801 GdkPixbuf
*pixbuf
= excel_read_IMDATA (q
, FALSE
);
6803 g_object_unref (pixbuf
);
6806 case BIFF_GUTS
: excel_read_GUTS (q
, esheet
); break;
6807 case BIFF_WSBOOL
: excel_read_WSBOOL (q
, esheet
); break;
6808 case BIFF_GRIDSET
: break;
6810 case BIFF_HCENTER
: excel_read_HCENTER (q
, esheet
); break;
6811 case BIFF_VCENTER
: excel_read_VCENTER (q
, esheet
); break;
6813 case BIFF_COUNTRY
: break;
6814 case BIFF_STANDARDWIDTH
: break; /* the 'standard width dialog' ? */
6815 case BIFF_FILTERMODE
: break;
6816 case BIFF_AUTOFILTERINFO
: break;
6817 case BIFF_AUTOFILTER
: excel_read_AUTOFILTER (q
, esheet
); break;
6818 case BIFF_SCL
: excel_read_SCL (q
, esheet
->sheet
); break;
6819 case BIFF_SETUP
: excel_read_SETUP (q
, esheet
); break;
6820 case BIFF_GCW
: break;
6821 case BIFF_SCENMAN
: break;
6822 case BIFF_SCENARIO
: break;
6823 case BIFF_MULRK
: excel_read_MULRK (q
, esheet
); break;
6824 case BIFF_MULBLANK
: excel_read_MULBLANK (q
, esheet
); break;
6826 case BIFF_RSTRING
: excel_read_LABEL (q
, esheet
, TRUE
); break;
6828 case BIFF_DBCELL
: break; /* Can be ignored on read side */
6830 case BIFF_BG_PIC
: excel_read_BG_PIC (q
, esheet
); break;
6831 case BIFF_MERGECELLS
: excel_read_MERGECELLS (q
, esheet
); break;
6833 case BIFF_MS_O_DRAWING
:
6834 case BIFF_MS_O_DRAWING_GROUP
:
6835 case BIFF_MS_O_DRAWING_SELECTION
:
6836 ms_escher_parse (q
, sheet_container (esheet
), FALSE
);
6838 case BIFF_PHONETIC
: break;
6841 excel_read_LABELSST (q
, esheet
);
6844 case BIFF_XF_OLD_v0
:
6845 case BIFF_XF_OLD_v2
:
6846 case BIFF_XF_OLD_v4
:
6847 excel_read_XF_OLD (q
, importer
);
6850 excel_read_XF_INDEX (q
, esheet
);
6854 case BIFF_NAME_v2
: excel_read_NAME (q
, importer
, esheet
); break;
6856 case BIFF_FONT_v2
: excel_read_FONT (q
, importer
); break;
6857 case BIFF_FORMAT_v0
:
6858 case BIFF_FORMAT_v4
: excel_read_FORMAT (q
, importer
); break;
6859 case BIFF_STYLE
: break;
6860 case BIFF_1904
: excel_read_1904 (q
, importer
); break;
6861 case BIFF_FILEPASS
: {
6862 const char *problem
= excel_read_FILEPASS (q
, importer
);
6863 if (problem
!= NULL
) {
6864 go_cmd_context_error_import (GO_CMD_CONTEXT (importer
->context
), problem
);
6871 excel_read_CONDFMT (q
, esheet
, importer
);
6874 g_warning ("Found a CF record without a CONDFMT ??");
6876 case BIFF_DVAL
: excel_read_DVAL (q
, esheet
); break;
6877 case BIFF_HLINK
: excel_read_HLINK (q
, esheet
); break;
6878 case BIFF_CODENAME
: excel_read_CODENAME (q
, importer
, esheet
); break;
6881 g_warning ("Found a DV record without a DVal ??");
6882 excel_read_DV (q
, esheet
);
6885 case BIFF_SXVIEWEX9
:
6886 /* Seems to contain pivot table autoformat indicies, plus ?? */
6887 /* samples/excel/dbfuns.xls has as sample of this record
6888 * and I added code in OOo */
6891 case BIFF_SHEETPROTECTION
:
6892 excel_read_SHEETPROTECTION (q
, esheet
->sheet
);
6895 /* HACK: it seems that in older versions of XL the
6896 * charts did not have a wrapper object. the first
6897 * record in the sequence of chart records was a
6898 * CHART_UNITS followed by CHART_CHART. We play off of
6899 * that. When we encounter a CHART_units record we
6900 * jump to the chart handler which then starts parsing
6901 * at the NEXT record.
6903 case BIFF_CHART_units
: {
6904 SheetObject
*obj
= sheet_object_graph_new (NULL
);
6905 ms_excel_chart_read (q
, sheet_container (esheet
),
6907 sheet_object_set_sheet (obj
, esheet
->sheet
);
6908 g_object_unref (obj
);
6911 case BIFF_SXVIEW
: xls_read_SXVIEW (q
, esheet
); break;
6912 case BIFF_SXVD
: xls_read_SXVD (q
, esheet
); break;
6913 case BIFF_SXVDEX
: break; /* pulled in with SXVD */
6914 case BIFF_SXVI
: break; /* pulled in with SXVD */
6915 case BIFF_SXIVD
: xls_read_SXIVD (q
, esheet
); break;
6918 excel_unexpected_biff (q
, "Sheet", ms_excel_read_debug
);
6922 g_printerr ("Error, hit end without EOF\n");
6927 /* We need a sheet to extract styles, so store the workbook default as
6928 * soon as we parse a sheet. It is a kludge, but not terribly costly */
6929 g_object_set_data_full (G_OBJECT (importer
->wb
),
6930 "xls-default-style",
6931 excel_get_style_from_xf (esheet
, excel_get_xf (esheet
, 0)),
6932 (GDestroyNotify
) gnm_style_unref
);
6937 * NOTE : MS Docs are incorrect
6939 * unsigned short num_tabs;
6940 * unsigned short num_characters_in_book;
6941 * unsigned char flag_for_unicode; 0 or 1
6942 * var encoded string stored as 1 or 2 byte characters
6945 excel_read_SUPBOOK (BiffQuery
*q
, GnmXLImporter
*importer
)
6947 unsigned numTabs
, len
;
6949 guint32 byte_length
, ofs
;
6950 ExcelSupBook
*new_supbook
;
6953 XL_CHECK_CONDITION (q
->length
>= 4);
6954 numTabs
= GSF_LE_GET_GUINT16 (q
->data
);
6955 len
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
6957 i
= importer
->v8
.supbook
->len
;
6958 g_array_set_size (importer
->v8
.supbook
, i
+ 1);
6959 new_supbook
= &g_array_index (importer
->v8
.supbook
, ExcelSupBook
, i
);
6961 d (2, g_printerr ("supbook %d has %d sheets\n", i
, numTabs
););
6963 new_supbook
->externname
= g_ptr_array_new ();
6964 new_supbook
->wb
= NULL
;
6966 if (q
->length
== 4 && len
== 0x0401) {
6967 d (2, g_printerr ("\t is self referential\n"););
6968 new_supbook
->type
= EXCEL_SUP_BOOK_SELFREF
;
6971 if (q
->length
== 4 && len
== 0x3A01) {
6972 d (2, g_printerr ("\t is a plugin\n"););
6973 new_supbook
->type
= EXCEL_SUP_BOOK_PLUGIN
;
6977 new_supbook
->type
= EXCEL_SUP_BOOK_STD
;
6978 XL_CHECK_CONDITION (q
->length
>= 5);
6980 bookname
= excel_get_text (importer
, q
->data
+ 4, len
,
6981 &byte_length
, NULL
, q
->length
- 4);
6982 d (2, g_printerr ("\trefers to %s\n", bookname
););
6985 * (1) a single space -- "unused"
6986 * (2) a single nul -- self referencing
6987 * (3) an OLE-link VirtualPath
6988 * (4) any other VirtualPath -- external workbook
6990 if (len
== 1 && *bookname
== 0) {
6991 new_supbook
->type
= EXCEL_SUP_BOOK_SELFREF
;
6992 } else if (len
== 1 && *bookname
== ' ') {
6997 ofs
= 4 + byte_length
;
6998 XL_CHECK_CONDITION (ofs
<= q
->length
);
7000 for (t
= 0; t
< numTabs
; t
++) {
7004 XL_CHECK_CONDITION (ofs
+ 2 <= q
->length
);
7006 length
= GSF_LE_GET_GUINT16 (q
->data
+ ofs
);
7008 name
= excel_get_text (importer
, q
->data
+ ofs
, length
,
7009 &byte_length
, NULL
, q
->length
- ofs
);
7010 d (2, g_printerr ("\tSheet %d -> %s\n", t
, name
););
7016 #warning "create a workbook and sheets when we have a facility for merging things"
7020 excel_read_WINDOW1 (BiffQuery
*q
, WorkbookView
*wb_view
)
7022 if (q
->length
>= 16) {
7024 /* In 1/20ths of a point */
7025 guint16
const xPos
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
7026 guint16
const yPos
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
7028 guint16
const width
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
7029 guint16
const height
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
7030 guint16
const options
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
7032 /* duplicated in the WINDOW2 record */
7033 guint16
const selTab
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
7035 guint16
const firstTab
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
7036 guint16
const tabsSel
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
7038 /* (width of tab)/(width of horizontal scroll bar) / 1000 */
7039 guint16
const ratio
= GSF_LE_GET_GUINT16 (q
->data
+ 16);
7043 * We are sizing the window including the toolbars,
7044 * menus, and notbook tabs. Excel does not.
7046 * NOTE: This is the size of the MDI sub-window, not the size of
7047 * the containing excel window.
7049 wb_view_preferred_size (wb_view
,
7050 .5 + width
* gnm_app_display_dpi_get (TRUE
) / (72. * 20.),
7051 .5 + height
* gnm_app_display_dpi_get (FALSE
) / (72. * 20.));
7053 if (options
& 0x0001)
7054 g_printerr ("Unsupported: Hidden workbook\n");
7055 if (options
& 0x0002)
7056 g_printerr ("Unsupported: Iconic workbook\n");
7058 g_object_set (G_OBJECT (wb_view
),
7059 "show-horizontal-scrollbar", !!(options
& 0x0008),
7060 "show-vertical-scrollbar", !!(options
& 0x0010),
7061 "show-notebook-tabs", !!(options
& 0x0020),
7067 excel_read_BOF (BiffQuery
*q
,
7068 GnmXLImporter
*importer
,
7069 WorkbookView
*wb_view
,
7070 GOIOContext
*context
,
7071 MsBiffBofData
**version
, unsigned *current_sheet
)
7073 /* The first BOF seems to be OK, the rest lie ? */
7074 MsBiffVersion vv
= MS_BIFF_V_UNKNOWN
;
7075 MsBiffBofData
*ver
= *version
;
7076 char const *version_desc
= NULL
;
7080 ms_biff_bof_data_destroy (ver
);
7082 *version
= ver
= ms_biff_bof_data_new (q
);
7083 if (vv
!= MS_BIFF_V_UNKNOWN
)
7086 if (ver
->type
== MS_BIFF_TYPE_Workbook
) {
7087 gnm_xl_importer_set_version (importer
, ver
->version
);
7088 if (ver
->version
>= MS_BIFF_V8
) {
7090 XL_CHECK_CONDITION (q
->length
>= 8);
7091 ver
= GSF_LE_GET_GUINT32 (q
->data
+ 4);
7092 if (ver
== 0x4107cd18)
7093 version_desc
= "Excel 2000 ?";
7095 version_desc
= "Excel 97 +";
7096 } else if (ver
->version
>= MS_BIFF_V7
)
7097 version_desc
= "Excel 95";
7098 else if (ver
->version
>= MS_BIFF_V5
)
7099 version_desc
= "Excel 5.x";
7100 else if (ver
->version
>= MS_BIFF_V4
)
7101 version_desc
= "Excel 4.x";
7102 else if (ver
->version
>= MS_BIFF_V3
)
7103 version_desc
= "Excel 3.x - shouldn't happen";
7104 else if (ver
->version
>= MS_BIFF_V2
)
7105 version_desc
= "Excel 2.x - shouldn't happen";
7106 } else if (ver
->type
== MS_BIFF_TYPE_Worksheet
||
7107 ver
->type
== MS_BIFF_TYPE_Chart
) {
7108 BiffBoundsheetData
*bs
= g_hash_table_lookup (
7109 importer
->boundsheet_data_by_stream
, GINT_TO_POINTER (q
->streamPos
));
7110 ExcelReadSheet
*esheet
;
7112 if (ver
->version
> MS_BIFF_V4
) /* be anal */
7113 g_printerr ("Sheet offset in stream of 0x%lx not found in list\n",
7114 (long)q
->streamPos
);
7115 if (*current_sheet
>= importer
->excel_sheets
->len
) {
7116 esheet
= excel_sheet_new (importer
, "Worksheet", GNM_SHEET_DATA
);
7117 /* Top level worksheets existed up to & including 4.x */
7118 gnm_xl_importer_set_version (importer
, ver
->version
);
7119 if (ver
->version
>= MS_BIFF_V5
)
7120 version_desc
= ">= Excel 5 with no BOUNDSHEET ?? - shouldn't happen";
7121 else if (ver
->version
>= MS_BIFF_V4
)
7122 version_desc
= "Excel 4.x single worksheet";
7123 else if (ver
->version
>= MS_BIFF_V3
)
7124 version_desc
= "Excel 3.x single worksheet";
7125 else if (ver
->version
>= MS_BIFF_V2
)
7126 version_desc
= "Excel 2.x single worksheet";
7128 esheet
= g_ptr_array_index (importer
->excel_sheets
, *current_sheet
);
7130 esheet
= bs
->esheet
;
7132 g_return_if_fail (esheet
!= NULL
);
7135 if (ver
->type
== MS_BIFF_TYPE_Worksheet
) {
7136 excel_read_sheet (q
, importer
, wb_view
, esheet
);
7137 ms_container_realize_objs (sheet_container (esheet
));
7138 /* reverse the sheet objects satck order */
7139 esheet
->sheet
->sheet_objects
= g_slist_reverse (esheet
->sheet
->sheet_objects
);
7141 SheetObject
*obj
= sheet_object_graph_new (NULL
);
7142 ms_excel_chart_read (q
, sheet_container (esheet
),
7143 obj
, esheet
->sheet
);
7144 sheet_object_set_sheet (obj
, esheet
->sheet
);
7145 g_object_unref (obj
);
7148 } else if (ver
->type
== MS_BIFF_TYPE_VBModule
||
7149 ver
->type
== MS_BIFF_TYPE_Macrosheet
) {
7150 /* Skip contents of Module, or MacroSheet */
7151 if (ver
->type
!= MS_BIFF_TYPE_Macrosheet
)
7152 version_desc
= "VB Module";
7155 version_desc
= "XLM Macrosheet";
7158 while (ms_biff_query_next (q
) && q
->opcode
!= BIFF_EOF
)
7159 d (5, ms_biff_query_dump (q
););
7160 if (q
->opcode
!= BIFF_EOF
)
7161 g_warning ("EXCEL: file format error. Missing BIFF_EOF");
7162 } else if (ver
->type
== MS_BIFF_TYPE_Workspace
) {
7163 /* Multiple sheets, XLW format from Excel 4.0 */
7164 version_desc
= "Excel 4.x workbook";
7165 gnm_xl_importer_set_version (importer
, ver
->version
);
7167 g_printerr ("Unknown BOF (%x)\n", ver
->type
);
7169 if (NULL
!= version_desc
) {
7170 d (1, g_printerr ("%s\n", version_desc
););
7175 excel_read_CODEPAGE (BiffQuery
*q
, GnmXLImporter
*importer
)
7177 /* This seems to appear within a workbook */
7178 /* MW: And on Excel seems to drive the display
7179 of currency amounts. */
7180 XL_CHECK_CONDITION (q
->length
>= 2);
7181 gnm_xl_importer_set_codepage (importer
,
7182 GSF_LE_GET_GUINT16 (q
->data
));
7186 excel_read_RECALCID (BiffQuery
*q
, GnmXLImporter
*importer
)
7190 XL_CHECK_CONDITION (q
->length
>= 8);
7191 engine
= GSF_LE_GET_GUINT32 (q
->data
+ 4);
7197 excel_read_UNCALCED (BiffQuery
*q
, GnmXLImporter
*importer
)
7202 excel_read_workbook (GOIOContext
*context
, WorkbookView
*wb_view
,
7204 gboolean
*is_double_stream_file
,
7205 char const *opt_enc
)
7207 GnmXLImporter
*importer
;
7209 MsBiffBofData
*ver
= NULL
;
7210 unsigned current_sheet
= 0;
7211 const char *problem_loading
= NULL
;
7212 gboolean stop_loading
= FALSE
;
7213 gboolean prev_was_eof
= FALSE
;
7215 go_io_progress_message (context
, _("Reading file..."));
7216 go_io_value_progress_set (context
, gsf_input_size (input
), N_BYTES_BETWEEN_PROGRESS_UPDATES
);
7217 q
= ms_biff_query_new (input
);
7219 importer
= gnm_xl_importer_new (context
, wb_view
, opt_enc
);
7221 *is_double_stream_file
= FALSE
;
7222 if (ms_biff_query_next (q
) &&
7223 (q
->opcode
== BIFF_BOF_v0
||
7224 q
->opcode
== BIFF_BOF_v2
||
7225 q
->opcode
== BIFF_BOF_v4
||
7226 q
->opcode
== BIFF_BOF_v8
))
7227 excel_read_BOF (q
, importer
, wb_view
, context
,
7228 &ver
, ¤t_sheet
);
7229 while (!stop_loading
&& /* we have not hit the end */
7230 problem_loading
== NULL
&& /* there were no problems so far */
7231 ms_biff_query_next (q
)) { /* we can load the record */
7234 const char *opname
= biff_opcode_name (q
->opcode
);
7235 g_printerr ("Opcode: 0x%x %s\n",
7237 opname
? opname
: "unknown");
7240 switch (q
->opcode
) {
7245 excel_read_BOF (q
, importer
, wb_view
, context
, &ver
, ¤t_sheet
);
7249 prev_was_eof
= TRUE
;
7250 d (0, g_printerr ("End of worksheet spec.\n"););
7254 case BIFF_FONT_v2
: excel_read_FONT (q
, importer
); break;
7255 case BIFF_WINDOW1
: excel_read_WINDOW1 (q
, wb_view
); break;
7256 case BIFF_BOUNDSHEET
: excel_read_BOUNDSHEET (q
, importer
); break;
7257 case BIFF_PALETTE
: excel_read_PALETTE (q
, importer
); break;
7259 case BIFF_XF_OLD_v0
:
7260 case BIFF_XF_OLD_v2
:
7261 case BIFF_XF_OLD_v4
: excel_read_XF_OLD (q
, importer
); break;
7262 case BIFF_XF
: excel_read_XF (q
, importer
); break;
7264 case BIFF_EXTERNCOUNT
: /* ignore */ break;
7265 case BIFF_EXTERNSHEET
:
7266 excel_read_EXTERNSHEET (q
, importer
, ver
);
7269 case BIFF_PRECISION
: {
7271 /* FIXME: implement in gnumeric */
7272 /* state of 'Precision as Displayed' option */
7273 guint16
const data
= GSF_LE_GET_GUINT16 (q
->data
);
7274 gboolean
const prec_as_displayed
= (data
== 0);
7279 case BIFF_FORMAT_v0
:
7280 case BIFF_FORMAT_v4
: excel_read_FORMAT (q
, importer
); break;
7282 case BIFF_BACKUP
: break;
7283 case BIFF_CODEPAGE
: /* DUPLICATE 42 */
7284 excel_read_CODEPAGE (q
, importer
);
7287 case BIFF_OBJPROTECT
:
7289 excel_read_workbook_PROTECT (q
, wb_view
);
7295 case BIFF_FILEPASS
: /* All records after this are encrypted */
7296 problem_loading
= excel_read_FILEPASS(q
, importer
);
7302 case BIFF_WINDOWPROTECT
:
7305 case BIFF_EXTERNNAME_v0
:
7306 case BIFF_EXTERNNAME_v2
: excel_read_EXTERNNAME (q
, &importer
->container
); break;
7308 case BIFF_NAME_v2
: excel_read_NAME (q
, importer
, NULL
); break;
7309 case BIFF_XCT
: excel_read_XCT (q
, importer
); break;
7311 case BIFF_WRITEACCESS
:
7314 case BIFF_HIDEOBJ
: break;
7315 case BIFF_FNGROUPCOUNT
: break;
7316 case BIFF_MMS
: break;
7318 /* Flags that the project has some VBA */
7319 case BIFF_OBPROJ
: break;
7320 case BIFF_BOOKBOOL
: break;
7321 case BIFF_COUNTRY
: break;
7322 case BIFF_INTERFACEHDR
: break;
7323 case BIFF_INTERFACEEND
: break;
7324 case BIFF_TOOLBARHDR
: break;
7325 case BIFF_TOOLBAREND
: break;
7327 case BIFF_1904
: excel_read_1904 (q
, importer
); break;
7329 case BIFF_SELECTION
: /* 0, NOT 10 */
7332 case BIFF_DIMENSIONS_v0
:
7333 /* Ignore files that pad the end with zeros */
7335 stop_loading
= TRUE
;
7339 case BIFF_DIMENSIONS_v2
:
7340 excel_read_DIMENSIONS (q
, NULL
);
7343 case BIFF_OBJ
: ms_read_OBJ (q
, &importer
->container
, NULL
); break;
7344 case BIFF_SCL
: break;
7345 case BIFF_TABIDCONF
: break;
7346 case BIFF_MS_O_DRAWING
:
7347 case BIFF_MS_O_DRAWING_GROUP
:
7348 case BIFF_MS_O_DRAWING_SELECTION
:
7349 ms_escher_parse (q
, &importer
->container
, FALSE
);
7353 d (1, g_printerr ("%smenu with %d sub items",
7354 (GSF_LE_GET_GUINT8 (q
->data
+ 6) == 1) ? "" : "Placeholder ",
7355 GSF_LE_GET_GUINT8 (q
->data
+ 5)););
7358 case BIFF_SST
: excel_read_SST (q
, importer
); break;
7359 case BIFF_EXTSST
: excel_read_EXSST (q
, importer
); break;
7361 case BIFF_DSF
: /* stored in the biff8 workbook */
7362 case BIFF_XL5MODIFY
: /* stored in the biff5/7 book */
7364 gboolean dsf
= (q
->length
>= 2 &&
7365 GSF_LE_GET_GUINT16 (q
->data
));
7366 d (0, g_printerr ("Double stream file : %d\n",
7369 *is_double_stream_file
= TRUE
;
7374 d (0, g_printerr ("%s\n", "XL 2000 file"););
7377 case BIFF_RECALCID
: excel_read_RECALCID (q
, importer
); break;
7378 case BIFF_UNCALCED
: excel_read_UNCALCED (q
, importer
); break;
7379 case BIFF_REFRESHALL
: break;
7380 case BIFF_CODENAME
: excel_read_CODENAME (q
, importer
, NULL
); break;
7381 case BIFF_PROT4REVPASS
: break;
7383 case BIFF_USESELFS
: break;
7384 case BIFF_TABID
: break;
7389 case BIFF_SUPBOOK
: excel_read_SUPBOOK (q
, importer
); break;
7391 case BIFF_SXStreamID
: xls_read_SXStreamID (importer
, q
, gsf_input_container (input
)); break;
7394 excel_unexpected_biff (q
, "Workbook", ms_excel_read_debug
);
7397 /* check here in case any of the handlers read additional records */
7398 prev_was_eof
= (q
->opcode
== BIFF_EOF
);
7401 ms_biff_query_destroy (q
);
7403 ms_biff_bof_data_destroy (ver
);
7404 go_io_progress_unset (context
);
7406 d (1, g_printerr ("finished read\n"););
7408 gnm_xl_importer_free (importer
);
7410 /* If we were forced to stop then the load failed */
7411 if (problem_loading
!= NULL
)
7412 go_cmd_context_error_import (GO_CMD_CONTEXT (context
), problem_loading
);
7416 static GSList
*formats
;
7419 * These are special in that they appear to be saved as macros.
7420 * Excel will only recognize them when saved as macros: neither
7421 * externname as "IFERROR" nor "_xlfn.IFERROR" will work.
7423 static const ExcelFuncDesc excel97_func_desc
[] = {
7424 { 0xff, "_xlfn.AVERAGEIF", -1, -1, XL_XLM
},
7425 { 0xff, "_xlfn.AVERAGEIFS", -1, -1, XL_XLM
},
7426 { 0xff, "_xlfn.CUBEKPIMEMBER", -1, -1, XL_XLM
},
7427 { 0xff, "_xlfn.CUBEMEMBER", -1, -1, XL_XLM
},
7428 { 0xff, "_xlfn.CUBEMEMBERPROPERTY", -1, -1, XL_XLM
},
7429 { 0xff, "_xlfn.CUBERANKEDMEMBER", -1, -1, XL_XLM
},
7430 { 0xff, "_xlfn.CUBESET", -1, -1, XL_XLM
},
7431 { 0xff, "_xlfn.CUBESETCOUNT", -1, -1, XL_XLM
},
7432 { 0xff, "_xlfn.CUBEVALUE", -1, -1, XL_XLM
},
7433 { 0xff, "_xlfn.COUNTIFS", -1, -1, XL_XLM
},
7434 { 0xff, "_xlfn.IFERROR", 2, 2, XL_XLM
, 2, 'V', "VV" },
7435 { 0xff, "_xlfn.SUMIFS", -1, -1, XL_XLM
}
7439 excel_read_init (void)
7442 int mbd
= go_locale_month_before_day ();
7445 fmt
= go_format_new_magic (GO_FORMAT_MAGIC_SHORT_DATE
);
7446 formats
= g_slist_prepend (formats
, fmt
);
7447 excel_builtin_formats
[0x0e] = go_format_as_XL (fmt
);
7449 fmt
= go_format_new_magic (GO_FORMAT_MAGIC_MEDIUM_DATE
);
7450 formats
= g_slist_prepend (formats
, fmt
);
7451 excel_builtin_formats
[0x0f] = go_format_as_XL (fmt
);
7453 /* Doesn't seem to have a name. */
7454 excel_builtin_formats
[0x10] = mbd
? "d-mmm" : "mmm-d";
7456 fmt
= go_format_new_magic (GO_FORMAT_MAGIC_SHORT_DATETIME
);
7457 formats
= g_slist_prepend (formats
, fmt
);
7458 excel_builtin_formats
[0x16] = go_format_as_XL (fmt
);
7460 excel_func_by_name
= g_hash_table_new (g_str_hash
, g_str_equal
);
7461 for (i
= 0; i
< excel_func_desc_size
; i
++) {
7462 const ExcelFuncDesc
*efd
= excel_func_desc
+ i
;
7463 const char *name
= efd
->name
;
7464 GnmFunc
*func
= gnm_func_lookup (name
, NULL
);
7468 name
= gnm_func_get_name (func
, FALSE
);
7470 g_assert (g_hash_table_lookup (excel_func_by_name
, name
) ==
7472 g_hash_table_insert (excel_func_by_name
,
7477 for (i
= 0; i
< (int)G_N_ELEMENTS(excel97_func_desc
); i
++) {
7478 const ExcelFuncDesc
*efd
= excel97_func_desc
+ i
;
7479 const char *excel_name
= efd
->name
;
7480 const char *gnm_name
= strchr (excel_name
, '.') + 1;
7481 GnmFunc
*func
= gnm_func_lookup (gnm_name
, NULL
);
7485 gnm_name
= gnm_func_get_name (func
, FALSE
);
7487 g_assert (g_hash_table_lookup (excel_func_by_name
, gnm_name
) ==
7489 g_hash_table_insert (excel_func_by_name
,
7494 empty_attr_list
= pango_attr_list_new ();
7498 excel_read_cleanup (void)
7500 g_hash_table_destroy (excel_func_by_name
);
7501 excel_func_by_name
= NULL
;
7503 g_slist_free_full (formats
, (GDestroyNotify
)go_format_unref
);
7506 pango_attr_list_unref (empty_attr_list
);
7507 empty_attr_list
= NULL
;