1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * ms-excel-read.c: MS Excel import
6 * Jody Goldberg (jody@gnome.org)
7 * Michael Meeks (michael@ximian.com)
9 * (C) 1998-2001 Michael Meeks
10 * (C) 2002-2008 Jody Goldberg
11 * (C) 2013-2013 Morten Welinder
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of the
16 * License, or (at your option) version 3.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
28 #include <gnumeric-config.h>
32 #include "ms-formula-read.h"
33 #include "ms-excel-read.h"
36 #include "ms-escher.h"
37 #include "ms-excel-util.h"
38 #include "ms-excel-xf.h"
39 #include "formula-types.h"
42 #include <workbook-view.h>
44 #include <sheet-view.h>
45 #include <sheet-style.h>
46 #include <sheet-merge.h>
47 #include <sheet-filter.h>
51 #include <style-conditions.h>
52 #include "style-font.h"
53 #include <gnm-format.h>
54 #include <print-info.h>
55 #include <selection.h>
56 #include <validation.h>
57 #include <input-msg.h>
58 #include <parse-util.h> /* for cell_name */
61 #include <expr-name.h>
64 #include <application.h>
65 #include <command-context.h>
66 #include <sheet-object-cell-comment.h>
67 #include <sheet-object-widget.h>
68 #include <gnm-so-line.h>
69 #include <gnm-so-filled.h>
70 #include <gnm-so-polygon.h>
71 #include <sheet-object-graph.h>
72 #include <sheet-object-image.h>
73 #include <goffice/goffice.h>
75 #include <gsf/gsf-input.h>
76 #include <gsf/gsf-utils.h>
77 #include <gsf/gsf-msole-utils.h>
78 #include <glib/gi18n-lib.h>
79 #include <glib/gstdio.h>
84 #define G_LOG_DOMAIN "gnumeric:read"
87 ExcelReadSheet
*esheet
;
89 guint32 streamStartPos
;
92 GnmSheetType gnm_type
;
93 GnmSheetVisibility visibility
;
96 #define N_BYTES_BETWEEN_PROGRESS_UPDATES 0x1000
97 #define BMP_HDR_SIZE 14
100 * Check whether the product of the first two arguments exceeds
101 * the third. The function should be overflow-proof.
104 product_gt (size_t count
, size_t itemsize
, size_t space
)
106 return itemsize
> 0 &&
107 (count
> G_MAXUINT
/ itemsize
|| count
* itemsize
> space
);
111 record_size_barf (size_t count
, size_t itemsize
, size_t space
,
114 g_warning ("File is most likely corrupted.\n"
115 "(Requested %u*%u bytes, but only %u bytes left in record.\n"
116 "The problem occurred in %s.)",
117 (unsigned)count
, (unsigned)itemsize
,
122 #define XL_NEED_BYTES(count) XL_NEED_ITEMS(count,1)
124 #define XL_NEED_ITEMS(count__,size__) \
126 size_t count_ = (count__); \
127 size_t size_ = (size__); \
128 size_t space_ = q->length - (data - q->data); \
129 if (G_UNLIKELY (product_gt (count_, size_, space_))) { \
130 record_size_barf (count_, size_, space_, G_STRFUNC); \
136 /* #define NO_DEBUG_EXCEL */
137 #ifndef NO_DEBUG_EXCEL
138 #define d(level, code) do { if (ms_excel_read_debug > level) { code } } while (0)
140 #define d(level, code)
143 #define XL_GETROW(p) (GSF_LE_GET_GUINT16(p->data + 0))
144 #define XL_GETCOL(p) (GSF_LE_GET_GUINT16(p->data + 2))
146 char const *excel_builtin_formats
[EXCEL_BUILTIN_FORMAT_LEN
] = {
147 /* 0x00 */ "General",
151 /* 0x04 */ "#,##0.00",
152 /* 0x05 */ "$#,##0_);($#,##0)",
153 /* 0x06 */ "$#,##0_);[Red]($#,##0)",
154 /* 0x07 */ "$#,##0.00_);($#,##0.00)",
155 /* 0x08 */ "$#,##0.00_);[Red]($#,##0.00)",
158 /* 0x0b */ "0.00E+00",
160 /* 0x0d */ "# ?" "?/?" "?", /* Don't accidentally use trigraph. */
162 /* 0x0f */ "d-mmm-yy",
165 /* 0x12 */ "h:mm AM/PM",
166 /* 0x13 */ "h:mm:ss AM/PM",
168 /* 0x15 */ "h:mm:ss",
169 /* 0x16 */ "m/d/yy h:mm",
170 /* 0x17 */ NULL
, /* 0x17-0x24 reserved for intl versions */
184 /* 0x25 */ "#,##0_);(#,##0)",
185 /* 0x26 */ "#,##0_);[Red](#,##0)",
186 /* 0x27 */ "#,##0.00_);(#,##0.00)",
187 /* 0x28 */ "#,##0.00_);[Red](#,##0.00)",
188 /* 0x29 */ "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
189 /* 0x2a */ "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
190 /* 0x2b */ "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
191 /* 0x2c */ "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
193 /* 0x2e */ "[h]:mm:ss",
194 /* 0x2f */ "mm:ss.0",
195 /* 0x30 */ "##0.0E+0",
199 static PangoAttrList
*empty_attr_list
;
202 esheet_ver (ExcelReadSheet
const *esheet
)
204 return esheet
->container
.importer
->ver
;
208 gnm_xl_importer_set_version (GnmXLImporter
*importer
, MsBiffVersion ver
)
210 g_return_if_fail (NULL
!= importer
);
211 g_return_if_fail (MS_BIFF_V_UNKNOWN
== importer
->ver
);
216 gnm_xl_importer_set_codepage (GnmXLImporter
*importer
, int codepage
)
219 if (codepage
== 1200 || codepage
== 1201)
220 /* this is 'compressed' unicode. unicode characters 0000->00FF
221 * which looks the same as 8859-1. What does Little endian vs
222 * bigendian have to do with this. There is only 1 byte, and it would
223 * certainly not be useful to keep the low byte as 0.
225 str_iconv
= g_iconv_open ("UTF-8", "ISO-8859-1");
227 str_iconv
= gsf_msole_iconv_open_for_import (codepage
);
229 if (str_iconv
== (GIConv
)(-1)) {
230 g_warning ("missing converter for codepage %u\n"
231 "falling back to 1252", codepage
);
232 str_iconv
= gsf_msole_iconv_open_for_import (1252);
235 if (importer
->str_iconv
!= (GIConv
)(-1))
236 gsf_iconv_close (importer
->str_iconv
);
237 importer
->str_iconv
= str_iconv
;
239 /* Store the codepage to make export easier, might
240 * cause problems with double stream files because
241 * we'll lose the codepage in the biff8 version */
242 g_object_set_data (G_OBJECT (importer
->wb
), "excel-codepage",
243 GINT_TO_POINTER (codepage
));
245 d (0, g_printerr ("%s\n", gsf_msole_language_for_lid (
246 gsf_msole_codepage_to_lid (codepage
))););
250 excel_wb_get_fmt (GnmXLImporter
*importer
, unsigned idx
)
252 char const *ans
= NULL
;
253 BiffFormatData
const *d
= g_hash_table_lookup (importer
->format_table
,
254 GUINT_TO_POINTER (idx
));
258 else if (idx
<= 0x31) {
259 ans
= excel_builtin_formats
[idx
];
261 g_printerr ("Foreign undocumented format\n");
263 g_printerr ("Unknown format: 0x%x\n", idx
);
266 GOFormat
*fmt
= gnm_format_import
268 GNM_FORMAT_IMPORT_NULL_INVALID
|
269 GNM_FORMAT_IMPORT_PATCHUP_INCOMPLETE
);
271 g_warning ("Ignoring invalid format [%s]", ans
);
272 fmt
= go_format_general ();
282 excel_cell_fetch (BiffQuery
*q
, ExcelReadSheet
*esheet
)
285 Sheet
*sheet
= esheet
->sheet
;
287 XL_CHECK_CONDITION_VAL (q
->length
>= 4, NULL
);
292 XL_CHECK_CONDITION_VAL (col
< gnm_sheet_get_max_cols (sheet
), NULL
);
293 XL_CHECK_CONDITION_VAL (row
< gnm_sheet_get_max_rows (sheet
), NULL
);
295 return sheet_cell_fetch (sheet
, col
, row
);
298 static GnmExprTop
const *
299 ms_sheet_parse_expr_internal (ExcelReadSheet
*esheet
, guint8
const *data
, int length
)
301 GnmExprTop
const *texpr
;
303 g_return_val_if_fail (length
> 0, NULL
);
305 texpr
= excel_parse_formula (&esheet
->container
, esheet
, 0, 0,
306 data
, length
, 0 /* FIXME */,
308 if (ms_excel_read_debug
> 8) {
311 Sheet
*sheet
= esheet
->sheet
;
312 Workbook
*wb
= (sheet
== NULL
) ? esheet
->container
.importer
->wb
: NULL
;
314 tmp
= gnm_expr_top_as_string (texpr
,
315 parse_pos_init (&pp
, wb
, sheet
, 0, 0),
316 gnm_conventions_default
);
317 g_printerr ("%s\n", tmp
? tmp
: "(null)");
324 static GnmExprTop
const *
325 ms_sheet_parse_expr (MSContainer
*container
, guint8
const *data
, int length
)
327 return ms_sheet_parse_expr_internal ((ExcelReadSheet
*)container
,
332 ms_sheet_get_sheet (MSContainer
const *container
)
334 return ((ExcelReadSheet
const *)container
)->sheet
;
338 ms_sheet_get_fmt (MSContainer
const *container
, unsigned indx
)
340 return excel_wb_get_fmt (container
->importer
, indx
);
344 ms_sheet_map_color (ExcelReadSheet
const *esheet
, MSObj
const *obj
, MSObjAttrID id
,
345 GOColor default_val
, gboolean
*pauto
)
348 MSObjAttr
*attr
= ms_obj_attr_bag_lookup (obj
->attrs
, id
);
351 if (pauto
) *pauto
= TRUE
;
355 if ((~0x7ffffff) & attr
->v
.v_uint
) {
356 GnmColor
*c
= excel_palette_get (esheet
->container
.importer
,
357 (0x7ffffff & attr
->v
.v_uint
));
359 r
= GO_COLOR_UINT_R (c
->go_color
);
360 g
= GO_COLOR_UINT_G (c
->go_color
);
361 b
= GO_COLOR_UINT_B (c
->go_color
);
362 style_color_unref (c
);
364 r
= (attr
->v
.v_uint
) & 0xff;
365 g
= (attr
->v
.v_uint
>> 8) & 0xff;
366 b
= (attr
->v
.v_uint
>> 16) & 0xff;
369 if (pauto
) *pauto
= FALSE
;
371 return GO_COLOR_FROM_RGBA (r
,g
,b
,0xff);
375 * ms_sheet_obj_anchor_to_pos:
376 * @points Array which receives anchor coordinates in points
380 * Converts anchor coordinates in Excel units to points. Anchor
381 * coordinates are x and y of upper left and lower right corner. Each
382 * is expressed as a pair: Row/cell number + position within cell as
383 * fraction of cell dimension.
385 * NOTE: According to docs, position within cell is expressed as
386 * 1/1024 of cell dimension. However, this doesn't seem to be true
387 * vertically, for Excel 97. We use 256 for >= XL97 and 1024 for
391 ms_sheet_obj_anchor_to_pos (Sheet
const * sheet
,
392 G_GNUC_UNUSED MsBiffVersion
const ver
,
393 guint8
const *raw_anchor
,
394 GnmRange
*range
, double offset
[4], GnmSOAnchorMode
*mode
)
397 * gnm_float const row_denominator = (ver >= MS_BIFF_V8) ? 256. : 1024.;
399 * chap03-1.xls suggests that XL95 uses 256 too
400 * Do we have any tests that confirm the docs contention of 1024 ?
406 g_printerr ("anchored to %s\n", sheet
->name_unquoted
);
407 gsf_mem_dump (raw_anchor
, 18);
410 switch (raw_anchor
[0]) {
412 *mode
= GNM_SO_ANCHOR_ONE_CELL
;
415 *mode
= GNM_SO_ANCHOR_ABSOLUTE
;
418 *mode
= GNM_SO_ANCHOR_TWO_CELLS
;
421 /* Ignore the first 2 bytes. What are they ? */
422 /* Dec/1/2000 JEG: I have not researched it, but this may have some
423 * flags indicating whether or not the object is anchored to the cell
427 /* Words 0, 4, 8, 12: The row/col of the corners */
428 /* Words 2, 6, 10, 14: distance from cell edge */
429 for (i
= 0; i
< 4; i
++, raw_anchor
+= 4) {
430 int const pos
= GSF_LE_GET_GUINT16 (raw_anchor
);
431 int const nths
= GSF_LE_GET_GUINT16 (raw_anchor
+ 2);
434 g_printerr ("%d/%d cell %s from ",
435 nths
, (i
& 1) ? 256 : 1024,
436 (i
& 1) ? "widths" : "heights");
438 g_printerr ("row %d;\n", pos
+ 1);
440 g_printerr ("col %s (%d);\n", col_name (pos
), pos
);
443 if (i
& 1) { /* odds are rows */
444 offset
[i
] = nths
/ 256.;
446 range
->start
.row
= pos
;
448 range
->end
.row
= pos
;
450 offset
[i
] = nths
/ 1024.;
452 range
->start
.col
= pos
;
454 range
->end
.col
= pos
;
462 handle_arrow_head (SheetObject
*so
, const char *prop_name
,
464 MSObjAttrBag
*attrs
, MSObjAttrID typid
,
465 MSObjAttrID wid
, MSObjAttrID lid
)
468 int w
= ms_obj_attr_get_int (attrs
, wid
, 1);
469 int l
= ms_obj_attr_get_int (attrs
, lid
, 1);
470 int typ
= ms_obj_attr_get_int (attrs
, typid
, 0);
471 xls_arrow_from_xl (&arrow
, width
, typ
, l
, w
);
472 g_object_set (so
, prop_name
, &arrow
, NULL
);
476 excel_fill_bmp_header(guint8
*bmphdr
, guint8
*data
, guint32 len
)
483 GSF_LE_SET_GUINT32 (bmphdr
+ 2, len
+ BMP_HDR_SIZE
);
484 GSF_LE_SET_GUINT16 (bmphdr
+ 6, 0);
485 GSF_LE_SET_GUINT16 (bmphdr
+ 8, 0);
486 bpp
= len
>= 20 ? GSF_LE_GET_GUINT16 (data
+ 18) : 1;
488 case 24: offset
= 0; break;
489 case 8: offset
= 256 * 3; break;
490 case 4: offset
= 16 * 3; break;
491 default: offset
= 2 * 3; break;
493 offset
+= BMP_HDR_SIZE
+ 2;
494 GSF_LE_SET_GUINT32 (bmphdr
+ 10, offset
);
498 ms_sheet_realize_obj (MSContainer
*container
, MSObj
*obj
)
501 PangoAttrList
*markup
;
503 ExcelReadSheet
*esheet
;
504 MSObjAttr
*attr
, *flip_h
, *flip_v
;
505 GODrawingAnchorDir direction
;
506 SheetObjectAnchor anchor
;
509 GnmSOAnchorMode mode
= GNM_SO_ANCHOR_TWO_CELLS
;
513 if (obj
->gnum_obj
== NULL
)
517 g_return_val_if_fail (container
!= NULL
, TRUE
);
518 esheet
= (ExcelReadSheet
*)container
;
520 /* our comment object is too weak. This anchor is for the text box,
521 * we need to store the indicator */
522 if (obj
->excel_type
== 0x19 &&
523 obj
->comment_pos
.col
>= 0 && obj
->comment_pos
.row
>= 0) {
524 cell_comment_set_pos (GNM_CELL_COMMENT (obj
->gnum_obj
),
527 attr
= ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_ANCHOR
);
529 g_printerr ("MISSING anchor for obj %p with id %d of type %s\n", (void *)obj
, obj
->id
, obj
->excel_type_name
);
533 if (ms_sheet_obj_anchor_to_pos (esheet
->sheet
, container
->importer
->ver
,
534 attr
->v
.v_ptr
, &range
, offsets
, &mode
))
537 flip_h
= ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_FLIP_H
);
538 flip_v
= ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_FLIP_V
);
540 ((flip_h
== NULL
) ? GOD_ANCHOR_DIR_RIGHT
: 0) |
541 ((flip_v
== NULL
) ? GOD_ANCHOR_DIR_DOWN
: 0);
543 sheet_object_anchor_init (&anchor
, &range
, offsets
, direction
, GNM_SO_ANCHOR_TWO_CELLS
);
544 sheet_object_set_anchor (so
, &anchor
);
546 sheet_object_set_sheet (so
, esheet
->sheet
);
547 if (mode
!= GNM_SO_ANCHOR_TWO_CELLS
)
548 sheet_object_set_anchor_mode (so
, &mode
);
552 if (ms_obj_attr_get_ptr (obj
->attrs
, MS_OBJ_ATTR_TEXT
, &label
, FALSE
))
553 g_object_set (G_OBJECT (so
), "text", label
, NULL
);
558 if (ms_obj_attr_get_ptr (obj
->attrs
, MS_OBJ_ATTR_OBJ_NAME
, &name
, FALSE
))
559 g_object_set (G_OBJECT (so
), "name", name
, NULL
);
562 markup
= ms_obj_attr_get_markup (obj
->attrs
, MS_OBJ_ATTR_MARKUP
, NULL
, FALSE
);
564 g_object_set (so
, "markup", markup
, NULL
);
566 switch (obj
->excel_type
) {
573 style
= go_style_new ();
574 style
->line
.color
= ms_sheet_map_color
575 (esheet
, obj
, MS_OBJ_ATTR_OUTLINE_COLOR
,
576 GO_COLOR_BLACK
, &style
->line
.auto_color
);
577 style
->line
.width
= ms_obj_attr_get_uint (obj
->attrs
,
578 MS_OBJ_ATTR_OUTLINE_WIDTH
, 0) / 256.;
579 style
->line
.auto_dash
=
580 (ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_OUTLINE_HIDE
) != NULL
);
581 style
->line
.dash_type
= style
->line
.auto_dash
583 : ms_escher_xl_to_line_type (ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_OUTLINE_STYLE
, 0));
585 width
= style
->line
.auto_width
? 0 : style
->line
.width
;
586 g_object_set (G_OBJECT (so
), "style", style
, NULL
);
587 g_object_unref (style
);
589 handle_arrow_head (so
, "start-arrow", width
,
591 MS_OBJ_ATTR_ARROW_START
,
592 MS_OBJ_ATTR_ARROW_START_WIDTH
,
593 MS_OBJ_ATTR_ARROW_START_LENGTH
);
594 handle_arrow_head (so
, "end-arrow", width
,
596 MS_OBJ_ATTR_ARROW_END
,
597 MS_OBJ_ATTR_ARROW_END_WIDTH
,
598 MS_OBJ_ATTR_ARROW_END_LENGTH
);
603 g_object_set (G_OBJECT (so
), "points",
604 ms_obj_attr_get_array (obj
->attrs
, MS_OBJ_ATTR_POLYGON_COORDS
, NULL
, TRUE
),
612 style
= go_style_new ();
613 style
->line
.color
= ms_sheet_map_color
614 (esheet
, obj
, MS_OBJ_ATTR_OUTLINE_COLOR
,
615 GO_COLOR_BLACK
, &style
->line
.auto_color
);
616 style
->line
.width
= ms_obj_attr_get_uint (obj
->attrs
,
617 MS_OBJ_ATTR_OUTLINE_WIDTH
, 0) / 256.;
618 style
->line
.auto_dash
= FALSE
;
619 style
->line
.dash_type
= (ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_OUTLINE_HIDE
) != NULL
)
621 : ms_escher_xl_to_line_type (ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_OUTLINE_STYLE
, 0));
622 style
->fill
.pattern
.back
= ms_sheet_map_color
623 (esheet
, obj
, MS_OBJ_ATTR_FILL_COLOR
,
624 GO_COLOR_WHITE
, &style
->fill
.auto_back
);
625 style
->fill
.pattern
.fore
= ms_sheet_map_color
626 (esheet
, obj
, MS_OBJ_ATTR_FILL_BACKGROUND
,
627 GO_COLOR_BLACK
, &style
->fill
.auto_fore
);
628 /* fill type needs work, we now suppot more than solid color */
629 style
->fill
.type
= ms_obj_attr_bag_lookup (obj
->attrs
, MS_OBJ_ATTR_UNFILLED
)
630 ? GO_STYLE_FILL_NONE
: GO_STYLE_FILL_PATTERN
;
631 if (style
->fill
.type
!= GO_STYLE_FILL_PATTERN
)
632 style
->fill
.auto_type
= FALSE
;
634 g_object_set (G_OBJECT (so
), "style", style
, NULL
);
635 g_object_unref (style
);
639 /* NOTE : We should not need to do anything for charts */
646 double crop_left
= 0.0;
647 double crop_top
= 0.0;
648 double crop_right
= 0.0;
649 double crop_bottom
= 0.0;
651 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
652 MS_OBJ_ATTR_BLIP_ID
)) != NULL
) {
653 MSEscherBlip
*blip
= ms_container_get_blip (container
,
656 if (blip
->type
&& !strcmp (blip
->type
, "dib")) {
657 guint8
*data
= g_malloc(blip
->data_len
+ BMP_HDR_SIZE
);
659 excel_fill_bmp_header(data
, blip
->data
, blip
->data_len
);
660 memcpy(data
+ BMP_HDR_SIZE
, blip
->data
, blip
->data_len
);
661 sheet_object_image_set_image (GNM_SO_IMAGE (so
),
662 blip
->type
, data
, blip
->data_len
+ BMP_HDR_SIZE
);
666 sheet_object_image_set_image (GNM_SO_IMAGE (so
),
667 blip
->type
, blip
->data
, blip
->data_len
);
670 } else if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
671 MS_OBJ_ATTR_IMDATA
)) != NULL
) {
672 GdkPixbuf
*pixbuf
= GDK_PIXBUF (attr
->v
.v_object
);
678 gdk_pixbuf_save_to_buffer
679 (pixbuf
, &buf
, &buf_size
, "png",
682 sheet_object_image_set_image
684 "png", buf
, buf_size
);
689 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
690 MS_OBJ_ATTR_BLIP_CROP_LEFT
)) != NULL
)
691 crop_left
= (double) attr
->v
.v_uint
/ 65536.;
692 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
693 MS_OBJ_ATTR_BLIP_CROP_RIGHT
)) != NULL
)
694 crop_right
= (double) attr
->v
.v_uint
/ 65536.;
695 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
696 MS_OBJ_ATTR_BLIP_CROP_TOP
)) != NULL
)
697 crop_top
= (double) attr
->v
.v_uint
/ 65536.;
698 if ((attr
= ms_obj_attr_bag_lookup (obj
->attrs
,
699 MS_OBJ_ATTR_BLIP_CROP_BOTTOM
)) != NULL
)
700 crop_bottom
= (double) attr
->v
.v_uint
/ 65536.;
702 sheet_object_image_set_crop (GNM_SO_IMAGE (so
),
703 crop_left
, crop_top
, crop_right
, crop_bottom
);
709 sheet_widget_checkbox_set_link (obj
->gnum_obj
,
710 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_LINKED_TO_CELL
, NULL
, FALSE
));
714 sheet_widget_radio_button_set_link (obj
->gnum_obj
,
715 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_LINKED_TO_CELL
, NULL
, FALSE
));
720 sheet_widget_adjustment_set_details (obj
->gnum_obj
,
721 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_LINKED_TO_CELL
, NULL
, FALSE
),
722 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_VALUE
, 0),
723 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_MIN
, 0),
724 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_MAX
, 100) - 1,
725 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_INC
, 1),
726 ms_obj_attr_get_int (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_PAGE
, 10));
727 sheet_widget_adjustment_set_horizontal (obj
->gnum_obj
,
728 ms_obj_attr_get_uint (obj
->attrs
, MS_OBJ_ATTR_SCROLLBAR_HORIZ
, FALSE
));
733 sheet_widget_list_base_set_links (obj
->gnum_obj
,
734 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_LINKED_TO_CELL
, NULL
, FALSE
),
735 ms_obj_attr_get_expr (obj
->attrs
, MS_OBJ_ATTR_INPUT_FROM
, NULL
, FALSE
));
738 case MSOT_COMMENT
: /* cell comment text box */
742 d (2, g_printerr ("EXCEL: unhandled excel object of type %s (0x%x) id = %d.",
743 obj
->excel_type_name
, obj
->excel_type
, obj
->id
););
751 ms_sheet_create_obj (MSContainer
*container
, MSObj
*obj
)
753 SheetObject
*so
= NULL
;
758 g_return_val_if_fail (container
!= NULL
, NULL
);
760 switch (obj
->excel_type
) {
763 so
= g_object_new (GNM_SO_LINE_TYPE
, NULL
);
766 case 0x00: /* draw the group border */
771 so
= g_object_new (GNM_SO_FILLED_TYPE
,
772 "is-oval", obj
->excel_type
== 3,
777 so
= sheet_object_graph_new (NULL
);
782 so
= g_object_new (sheet_widget_button_get_type (), NULL
);
785 so
= g_object_new (GNM_SO_IMAGE_TYPE
, NULL
); /* Picture */
788 so
= g_object_new (GNM_SO_POLYGON_TYPE
, NULL
);
791 so
= g_object_new (sheet_widget_checkbox_get_type (), NULL
);
794 so
= g_object_new (sheet_widget_radio_button_get_type (), NULL
);
797 so
= g_object_new (sheet_widget_spinbutton_get_type (), NULL
);
800 so
= g_object_new (sheet_widget_scrollbar_get_type (), NULL
);
803 so
= g_object_new (sheet_widget_list_get_type (), NULL
);
806 /* ignore combos associateed with filters */
808 ExcelReadSheet
*esheet
= (ExcelReadSheet
*)container
;
810 if (!obj
->auto_combo
)
811 so
= g_object_new (sheet_widget_combo_get_type (), NULL
);
813 /* ok, there are combos to go with the autofilter it can stay */
814 else if (esheet
!= NULL
)
815 esheet
->filter
= NULL
;
820 so
= g_object_new (cell_comment_get_type (), NULL
);
823 /* Gnumeric specific addition to handle toggle button controls */
825 so
= g_object_new (sheet_widget_toggle_button_get_type (), NULL
);
829 g_warning ("EXCEL: unhandled excel object of type %s (0x%x) id = %d.",
830 obj
->excel_type_name
, obj
->excel_type
, obj
->id
);
839 * @esheet ExcelReadSheet
841 * Excel only saves margins when any of the margins differs from the
842 * default. So we must initialize the margins to Excel's defaults, which
844 * Top, bottom: 1 in - 72 pt
845 * Left, right: 3/4 in - 48 pt
846 * Header, footer: 1/2 in - 36 pt
849 excel_init_margins (ExcelReadSheet
*esheet
)
851 GnmPrintInformation
*pi
;
855 g_return_if_fail (esheet
!= NULL
);
856 g_return_if_fail (esheet
->sheet
!= NULL
);
857 g_return_if_fail (esheet
->sheet
->print_info
!= NULL
);
859 pi
= esheet
->sheet
->print_info
;
860 print_info_set_edge_to_below_header (pi
,GO_IN_TO_PT (1.0));
861 print_info_set_edge_to_above_footer (pi
,GO_IN_TO_PT (1.0));
863 points
= GO_IN_TO_PT (0.75);
864 short_points
= GO_IN_TO_PT (0.5);
865 print_info_set_margins (pi
, short_points
, short_points
, points
, points
);
869 excel_shared_formula_free (XLSharedFormula
*sf
)
877 static ExcelReadSheet
*
878 excel_sheet_new (GnmXLImporter
*importer
, char const *sheet_name
, GnmSheetType type
)
880 static MSContainerClass
const vtbl
= {
881 &ms_sheet_realize_obj
,
882 &ms_sheet_create_obj
,
883 &ms_sheet_parse_expr
,
888 int rows
= (importer
->ver
>= MS_BIFF_V8
? XLS_MaxRow_V8
: XLS_MaxRow_V7
);
889 ExcelReadSheet
*esheet
;
892 sheet
= workbook_sheet_by_name (importer
->wb
, sheet_name
);
896 for (ui
= 0; ui
< importer
->excel_sheets
->len
; ui
++) {
897 ExcelReadSheet
*es
= g_ptr_array_index (importer
->excel_sheets
, ui
);
898 if (es
->sheet
== sheet
) {
899 g_warning ("Duplicate definition of sheet %s\n", sheet_name
);
904 sheet
= sheet_new_with_type (importer
->wb
, sheet_name
, type
,
906 workbook_sheet_attach (importer
->wb
, sheet
);
907 d (1, g_printerr ("Adding sheet '%s'\n", sheet_name
););
910 /* Flag a respan here in case nothing else does */
911 sheet_flag_recompute_spans (sheet
);
913 esheet
= g_new (ExcelReadSheet
, 1);
914 esheet
->sheet
= sheet
;
915 esheet
->filter
= NULL
;
916 esheet
->freeze_panes
= FALSE
;
917 esheet
->active_pane
= 3; /* The default */
918 esheet
->shared_formulae
= g_hash_table_new_full
919 ((GHashFunc
)&gnm_cellpos_hash
,
920 (GCompareFunc
)&gnm_cellpos_equal
,
921 NULL
, (GDestroyNotify
) &excel_shared_formula_free
);
922 esheet
->tables
= g_hash_table_new_full
923 ((GHashFunc
)&gnm_cellpos_hash
,
924 (GCompareFunc
)&gnm_cellpos_equal
,
925 NULL
, (GDestroyNotify
) g_free
);
926 esheet
->biff2_prev_xf_index
= -1;
928 excel_init_margins (esheet
);
929 ms_container_init (&esheet
->container
, &vtbl
,
930 &importer
->container
, importer
);
931 g_ptr_array_add (importer
->excel_sheets
, esheet
);
937 excel_unexpected_biff (BiffQuery
*q
, char const *state
,
940 #ifndef NO_DEBUG_EXCEL
941 if (debug_level
> 1) {
942 g_print ("Unexpected Opcode in %s: 0x%hx, length 0x%x\n",
943 state
, q
->opcode
, q
->length
);
945 gsf_mem_dump (q
->data
, q
->length
);
951 * excel_read_string_header :
952 * @data: a pointer to the start of the string header
953 * @maxlen: the length of the data area
954 * @use_utf16: Is the content in 8 or 16 bit chars
955 * @n_markup: number of trailing markup records
956 * @has_extended: Is there trailing extended string info (eg japanese PHONETIC)
959 * returns the length of the header (in bytes)
962 excel_read_string_header (guint8
const *data
, guint32 maxlen
,
965 gboolean
*has_extended
,
966 unsigned *post_data_len
)
971 if (G_UNLIKELY (maxlen
< 1))
974 header
= GSF_LE_GET_GUINT8 (data
);
975 if (((header
& 0xf2) != 0))
978 *use_utf16
= (header
& 0x1) != 0;
980 if ((header
& 0x8) != 0) {
981 if (G_UNLIKELY (maxlen
< 3))
983 *n_markup
= GSF_LE_GET_GUINT16 (data
+ 1);
984 *post_data_len
= *n_markup
* 4; /* 4 bytes per */
992 *has_extended
= (header
& 0x4) != 0;
996 if (G_UNLIKELY (maxlen
< len
+ 4))
998 len_ext_rst
= GSF_LE_GET_GUINT32 (data
+ len
); /* A byte length */
999 *post_data_len
+= len_ext_rst
;
1002 d (4, g_printerr ("Extended string support unimplemented; "
1003 "ignoring %u bytes\n", len_ext_rst
););
1009 *use_utf16
= *has_extended
= FALSE
;
1012 g_warning ("Invalid string record.");
1017 excel_get_chars (GnmXLImporter
const *importer
,
1018 guint8
const *ptr
, size_t length
, gboolean use_utf16
, guint16
const *codepage
)
1022 GIConv str_iconv
= importer
->str_iconv
;
1025 gunichar2
*uni_text
= g_alloca (sizeof (gunichar2
)*length
);
1027 for (i
= 0; i
< length
; i
++, ptr
+= 2)
1028 uni_text
[i
] = GSF_LE_GET_GUINT16 (ptr
);
1029 ans
= g_utf16_to_utf8 (uni_text
, length
, NULL
, NULL
, NULL
);
1031 size_t outbytes
= (length
+ 2) * 8;
1032 char *outbuf
= g_new (char, outbytes
+ 1);
1033 char *ptr2
= (char *)ptr
;
1036 if (NULL
!= codepage
)
1037 str_iconv
= gsf_msole_iconv_open_for_import (*codepage
);
1039 &ptr2
, &length
, &outbuf
, &outbytes
);
1041 g_iconv_close (str_iconv
);
1045 ans
= g_realloc (ans
, i
+ 1);
1051 excel_get_text (GnmXLImporter
const *importer
,
1052 guint8
const *pos
, guint32 length
,
1053 guint32
*byte_length
, guint16
const *codepage
, guint32 maxlen
)
1057 unsigned byte_len
, trailing_data_len
, n_markup
, str_len_bytes
;
1058 gboolean use_utf16
, has_extended
;
1060 if (byte_length
== NULL
)
1061 byte_length
= &byte_len
;
1063 if (importer
->ver
>= MS_BIFF_V8
) {
1064 *byte_length
= 1; /* the header */
1067 ptr
= pos
+ excel_read_string_header
1069 &use_utf16
, &n_markup
, &has_extended
,
1070 &trailing_data_len
);
1071 *byte_length
+= trailing_data_len
;
1073 *byte_length
= 0; /* no header */
1076 trailing_data_len
= 0;
1077 use_utf16
= has_extended
= FALSE
;
1082 str_len_bytes
= (use_utf16
? 2 : 1) * length
;
1084 if (*byte_length
> maxlen
) {
1085 *byte_length
= maxlen
;
1087 } else if (maxlen
- *byte_length
< str_len_bytes
) {
1088 *byte_length
= maxlen
;
1089 length
= (maxlen
- *byte_length
) / (use_utf16
? 2 : 1);
1091 *byte_length
+= str_len_bytes
;
1093 ans
= excel_get_chars (importer
, ptr
, length
, use_utf16
, codepage
);
1096 g_printerr ("String len %d, byte length %d: %s %s %s:\n",
1097 length
, *byte_length
,
1098 (use_utf16
? "UTF16" : "1byte"),
1099 ((n_markup
> 0) ? "has markup" :""),
1100 (has_extended
? "has extended phonetic info" : ""));
1101 gsf_mem_dump (pos
, *byte_length
);
1108 excel_biff_text (GnmXLImporter
const *importer
,
1109 const BiffQuery
*q
, guint32 ofs
, guint32 length
)
1111 XL_CHECK_CONDITION_VAL (q
->length
>= ofs
, NULL
);
1113 return excel_get_text (importer
, q
->data
+ ofs
, length
,
1114 NULL
, NULL
, q
->length
- ofs
);
1118 excel_biff_text_1 (GnmXLImporter
const *importer
,
1119 const BiffQuery
*q
, guint32 ofs
)
1123 XL_CHECK_CONDITION_VAL (q
->length
>= (ofs
+ 1), NULL
);
1125 length
= GSF_LE_GET_GUINT8 (q
->data
+ ofs
);
1128 return excel_get_text (importer
, q
->data
+ ofs
, length
,
1129 NULL
, NULL
, q
->length
- ofs
);
1133 excel_biff_text_2 (GnmXLImporter
const *importer
,
1134 const BiffQuery
*q
, guint32 ofs
)
1138 XL_CHECK_CONDITION_VAL (q
->length
>= (ofs
+ 2), NULL
);
1140 length
= GSF_LE_GET_GUINT16 (q
->data
+ ofs
);
1143 return excel_get_text (importer
, q
->data
+ ofs
, length
,
1144 NULL
, NULL
, q
->length
- ofs
);
1148 unsigned first
, last
;
1149 PangoAttrList
*accum
;
1153 append_markup (PangoAttribute
*src
, TXORun
*run
)
1155 if (run
->last
> run
->first
) {
1156 PangoAttribute
*dst
= pango_attribute_copy (src
);
1157 dst
->start_index
= run
->first
; /* inclusive */
1158 dst
->end_index
= run
->last
; /* exclusive */
1159 pango_attr_list_change (run
->accum
, dst
);
1165 excel_read_LABEL_markup (BiffQuery
*q
, ExcelReadSheet
*esheet
,
1166 char const *str
, unsigned str_len
)
1168 guint8
const * const end
= q
->data
+ q
->length
;
1169 guint8
const *ptr
= q
->data
+ 8 + str_len
;
1170 MSContainer
const *c
= &esheet
->container
;
1173 unsigned int clen
= g_utf8_strlen (str
, -1);
1176 g_printerr ("strlen=%d len=%d\n", str_len
, (int)strlen (str
));
1177 ms_biff_query_dump (q
);
1180 txo_run
.last
= strlen (str
);
1182 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
1183 XL_CHECK_CONDITION_VAL (ptr
+2 <= end
, NULL
);
1184 n
= 4 * GSF_LE_GET_GUINT16 (ptr
);
1187 XL_CHECK_CONDITION_VAL (ptr
+ n
== end
, NULL
);
1189 txo_run
.accum
= pango_attr_list_new ();
1195 o
= GSF_LE_GET_GUINT16 (ptr
+ n
);
1196 l
= GSF_LE_GET_GUINT16 (ptr
+ n
+ 2);
1197 XL_CHECK_CONDITION_VAL (o
<= clen
,
1198 go_format_new_markup (txo_run
.accum
, FALSE
));
1200 txo_run
.first
= g_utf8_offset_to_pointer (str
, o
) - str
;
1201 XL_CHECK_CONDITION_VAL (txo_run
.first
< txo_run
.last
,
1202 go_format_new_markup (txo_run
.accum
, FALSE
));
1204 pango_attr_list_filter (ms_container_get_markup (c
, l
),
1205 (PangoAttrFilterFunc
) append_markup
,
1207 txo_run
.last
= txo_run
.first
;
1210 XL_CHECK_CONDITION_VAL (ptr
+1 <= end
, NULL
);
1211 n
= 2 * GSF_LE_GET_GUINT8 (ptr
);
1214 XL_CHECK_CONDITION_VAL (ptr
+ n
== end
, NULL
);
1216 txo_run
.accum
= pango_attr_list_new ();
1219 txo_run
.first
= g_utf8_offset_to_pointer (str
,
1220 GSF_LE_GET_GUINT8 (ptr
+ n
)) - str
;
1221 pango_attr_list_filter (ms_container_get_markup (
1222 c
, GSF_LE_GET_GUINT8 (ptr
+ n
+ 1)),
1223 (PangoAttrFilterFunc
) append_markup
, &txo_run
);
1224 txo_run
.last
= txo_run
.first
;
1227 return go_format_new_markup (txo_run
.accum
, FALSE
);
1231 * NB. Whilst the string proper is split, and whilst we get several headers,
1232 * it seems that the attributes appear in a single block after the end
1233 * of the string, which may also be split over continues.
1236 sst_read_string (BiffQuery
*q
, MSContainer
const *c
,
1237 ExcelStringEntry
*res
, guint32 offset
)
1239 guint32 get_len
, chars_left
, total_len
, total_end_len
= 0;
1240 unsigned i
, post_data_len
, n_markup
, total_n_markup
= 0;
1241 gboolean use_utf16
, has_extended
;
1242 char *str
, *old_res
, *res_str
= NULL
;
1244 offset
= ms_biff_query_bound_check (q
, offset
, 2);
1245 if (offset
== (guint32
)-1)
1247 XL_CHECK_CONDITION_VAL (offset
< q
->length
, offset
);
1248 total_len
= GSF_LE_GET_GUINT16 (q
->data
+ offset
);
1251 offset
= ms_biff_query_bound_check (q
, offset
, 1);
1252 if (offset
== (guint32
)-1) {
1256 offset
+= excel_read_string_header
1257 (q
->data
+ offset
, q
->length
- offset
,
1258 &use_utf16
, &n_markup
, &has_extended
,
1260 total_end_len
+= post_data_len
;
1261 total_n_markup
+= n_markup
;
1262 chars_left
= (q
->length
- offset
) / (use_utf16
? 2 : 1);
1263 get_len
= (chars_left
> total_len
) ? total_len
: chars_left
;
1264 total_len
-= get_len
;
1266 str
= excel_get_chars (c
->importer
,
1267 q
->data
+ offset
, get_len
, use_utf16
, NULL
);
1268 offset
+= get_len
* (use_utf16
? 2 : 1);
1270 /* Handle corrupted string. */
1272 str
= g_strdup ("");
1274 if (res_str
!= NULL
) {
1276 res_str
= g_strconcat (old_res
, str
, NULL
);
1281 } while (total_len
> 0);
1283 if (total_n_markup
> 0) {
1285 PangoAttrList
*prev_markup
= NULL
;
1287 txo_run
.accum
= pango_attr_list_new ();
1289 for (i
= total_n_markup
; i
-- > 0 ; offset
+= 4) {
1290 offset
= ms_biff_query_bound_check (q
, offset
, 4);
1291 if (offset
== (guint32
)-1) {
1293 pango_attr_list_unref (txo_run
.accum
);
1296 if ((q
->length
>= offset
+ 4)) {
1297 guint16 o
= GSF_LE_GET_GUINT16 (q
->data
+ offset
);
1298 size_t l
= strlen (res_str
);
1299 txo_run
.last
= g_utf8_offset_to_pointer (res_str
, MIN (o
, l
)) - res_str
;
1300 if (prev_markup
!= NULL
)
1301 pango_attr_list_filter (prev_markup
,
1302 (PangoAttrFilterFunc
) append_markup
, &txo_run
);
1303 txo_run
.first
= txo_run
.last
;
1304 prev_markup
= ms_container_get_markup (
1305 c
, GSF_LE_GET_GUINT16 (q
->data
+ offset
+ 2));
1307 g_warning ("A TXO entry is across CONTINUEs. We need to handle those properly");
1309 txo_run
.last
= G_MAXINT
;
1310 pango_attr_list_filter (prev_markup
,
1311 (PangoAttrFilterFunc
) append_markup
, &txo_run
);
1312 res
->markup
= go_format_new_markup (txo_run
.accum
, FALSE
);
1314 total_end_len
-= 4*total_n_markup
;
1317 res
->content
= go_string_new_nocopy (res_str
);
1318 return offset
+ total_end_len
;
1322 excel_read_SST (BiffQuery
*q
, GnmXLImporter
*importer
)
1325 unsigned i
, sst_len
;
1327 XL_CHECK_CONDITION (q
->length
>= 8);
1330 g_printerr ("SST total = %u, sst = %u\n",
1331 GSF_LE_GET_GUINT32 (q
->data
+ 0),
1332 GSF_LE_GET_GUINT32 (q
->data
+ 4));
1333 gsf_mem_dump (q
->data
, q
->length
);
1336 sst_len
= GSF_LE_GET_GUINT32 (q
->data
+ 4);
1337 XL_CHECK_CONDITION (sst_len
< INT_MAX
/ sizeof (ExcelStringEntry
));
1339 importer
->sst_len
= sst_len
;
1340 importer
->sst
= g_new0 (ExcelStringEntry
, importer
->sst_len
);
1343 for (i
= 0; i
< importer
->sst_len
; i
++) {
1344 offset
= sst_read_string (q
, &importer
->container
, importer
->sst
+ i
, offset
);
1345 if (offset
== (guint32
)-1)
1348 if (importer
->sst
[i
].content
== NULL
)
1349 d (4, g_printerr ("Blank string in table at 0x%x.\n", i
););
1350 #ifndef NO_DEBUG_EXCEL
1351 else if (ms_excel_read_debug
> 4)
1352 g_printerr ("%s\n", importer
->sst
[i
].content
->str
);
1358 excel_read_EXSST (BiffQuery
*q
, GnmXLImporter
*importer
)
1360 XL_CHECK_CONDITION (q
->length
>= 2);
1361 d (10, g_printerr ("Bucketsize = %hu,\tnum buckets = %d\n",
1362 GSF_LE_GET_GUINT16 (q
->data
), (q
->length
- 2) / 8););
1366 excel_read_1904 (BiffQuery
*q
, GnmXLImporter
*importer
)
1368 XL_CHECK_CONDITION (q
->length
>= 2);
1369 if (GSF_LE_GET_GUINT16 (q
->data
) == 1)
1370 workbook_set_1904 (importer
->wb
, TRUE
);
1374 xls_value_new_err (GnmEvalPos
const *pos
, guint8 err
)
1377 case 0: return value_new_error_NULL (pos
);
1378 case 7: return value_new_error_DIV0 (pos
);
1379 case 15: return value_new_error_VALUE (pos
);
1380 case 23: return value_new_error_REF (pos
);
1381 case 29: return value_new_error_NAME (pos
);
1382 case 36: return value_new_error_NUM (pos
);
1383 case 42: return value_new_error_NA (pos
);
1384 default: return value_new_error (pos
, _("#UNKNOWN!"));
1389 ms_biff_bof_data_new (BiffQuery
*q
)
1391 MsBiffBofData
*ans
= g_new (MsBiffBofData
, 1);
1393 if (q
->length
>= 4) {
1395 /* Determine type from BOF */
1396 switch (q
->opcode
) {
1397 case BIFF_BOF_v0
: ans
->version
= MS_BIFF_V2
; break;
1398 case BIFF_BOF_v2
: ans
->version
= MS_BIFF_V3
; break;
1399 case BIFF_BOF_v4
: ans
->version
= MS_BIFF_V4
; break;
1402 g_printerr ("Complicated BIFF version 0x%x\n",
1403 GSF_LE_GET_GUINT16 (q
->non_decrypted_data
));
1404 gsf_mem_dump (q
->non_decrypted_data
, q
->length
);
1407 switch (GSF_LE_GET_GUINT16 (q
->non_decrypted_data
)) {
1409 ans
->version
= MS_BIFF_V8
;
1411 case 0x0500: /* * OR ebiff7: FIXME ? ! */
1412 ans
->version
= MS_BIFF_V7
;
1414 /* The following are non-standard records written
1415 by buggy tools. Taken from OO docs. */
1417 ans
->version
= MS_BIFF_V4
;
1420 ans
->version
= MS_BIFF_V3
;
1425 ans
->version
= MS_BIFF_V2
;
1428 g_printerr ("Unknown BIFF sub-number 0x%X in BOF %x\n",
1429 GSF_LE_GET_GUINT16 (q
->non_decrypted_data
), q
->opcode
);
1430 ans
->version
= MS_BIFF_V_UNKNOWN
;
1435 g_printerr ("Unknown BIFF number in BOF %x\n", q
->opcode
);
1436 ans
->version
= MS_BIFF_V_UNKNOWN
;
1437 g_printerr ("Biff version %d\n", ans
->version
);
1439 switch (GSF_LE_GET_GUINT16 (q
->non_decrypted_data
+ 2)) {
1440 case 0x0005: ans
->type
= MS_BIFF_TYPE_Workbook
; break;
1441 case 0x0006: ans
->type
= MS_BIFF_TYPE_VBModule
; break;
1442 case 0x0010: ans
->type
= MS_BIFF_TYPE_Worksheet
; break;
1443 case 0x0020: ans
->type
= MS_BIFF_TYPE_Chart
; break;
1444 case 0x0040: ans
->type
= MS_BIFF_TYPE_Macrosheet
; break;
1445 case 0x0100: ans
->type
= MS_BIFF_TYPE_Workspace
; break;
1447 ans
->type
= MS_BIFF_TYPE_Unknown
;
1448 g_printerr ("Unknown BIFF type in BOF %x\n", GSF_LE_GET_GUINT16 (q
->non_decrypted_data
+ 2));
1451 /* Now store in the directory array: */
1452 d (2, g_printerr ("BOF %x, %d == %d, %d\n", q
->opcode
, q
->length
,
1453 ans
->version
, ans
->type
););
1455 g_printerr ("Not a BOF !\n");
1456 ans
->version
= MS_BIFF_V_UNKNOWN
;
1457 ans
->type
= MS_BIFF_TYPE_Unknown
;
1464 ms_biff_bof_data_destroy (MsBiffBofData
*data
)
1470 excel_read_BOUNDSHEET (BiffQuery
*q
, GnmXLImporter
*importer
)
1472 BiffBoundsheetData
*bs
;
1473 char const *default_name
= "Unknown%d";
1474 gboolean oldstyle
= (importer
->ver
<= MS_BIFF_V4
);
1476 XL_CHECK_CONDITION (q
->length
>= (oldstyle
? 1 : 6));
1478 bs
= g_new0 (BiffBoundsheetData
, 1);
1479 bs
->gnm_type
= GNM_SHEET_DATA
;
1482 bs
->streamStartPos
= 0; /* Excel 4 doesn't tell us */
1483 bs
->type
= MS_BIFF_TYPE_Worksheet
;
1484 default_name
= _("Sheet%d");
1485 bs
->visibility
= GNM_SHEET_VISIBILITY_VISIBLE
;
1486 bs
->name
= excel_biff_text_1 (importer
, q
, 0);
1488 if (importer
->ver
> MS_BIFF_V8
)
1489 g_printerr ("Unknown BIFF Boundsheet spec. Assuming same as Biff7 FIXME\n");
1490 bs
->streamStartPos
= GSF_LE_GET_GUINT32 (q
->non_decrypted_data
);
1492 /* NOTE : MS Docs appear wrong. It is visiblity _then_ type */
1493 switch (GSF_LE_GET_GUINT8 (q
->data
+ 5)) {
1494 case 0: bs
->type
= MS_BIFF_TYPE_Worksheet
;
1495 default_name
= _("Sheet%d");
1497 case 1: bs
->type
= MS_BIFF_TYPE_Macrosheet
;
1498 bs
->gnm_type
= GNM_SHEET_XLM
;
1499 default_name
= _("Macro%d");
1501 case 2: bs
->type
= MS_BIFF_TYPE_Chart
;
1502 bs
->gnm_type
= GNM_SHEET_OBJECT
;
1503 default_name
= _("Chart%d");
1505 case 6: bs
->type
= MS_BIFF_TYPE_VBModule
;
1506 default_name
= _("Module%d");
1509 g_printerr ("Unknown boundsheet type: %d\n", GSF_LE_GET_GUINT8 (q
->data
+ 4));
1510 bs
->type
= MS_BIFF_TYPE_Unknown
;
1512 switch ((GSF_LE_GET_GUINT8 (q
->data
+ 4)) & 0x3) {
1513 case 0: bs
->visibility
= GNM_SHEET_VISIBILITY_VISIBLE
;
1515 case 1: bs
->visibility
= GNM_SHEET_VISIBILITY_HIDDEN
;
1517 case 2: bs
->visibility
= GNM_SHEET_VISIBILITY_VERY_HIDDEN
;
1520 g_printerr ("Unknown sheet hiddenness %d\n", (GSF_LE_GET_GUINT8 (q
->data
+ 4)) & 0x3);
1521 bs
->visibility
= GNM_SHEET_VISIBILITY_VISIBLE
;
1524 /* TODO: find some documentation on this.
1525 * Sample data and OpenCalc imply that the docs are incorrect. It
1526 * seems like the name length is 1 byte. Loading sample sheets in
1527 * other locales universally seem to treat the first byte as a length
1528 * and the second as the unicode flag header.
1530 bs
->name
= excel_biff_text_1 (importer
, q
, 6);
1533 /* TODO: find some documentation on this.
1534 * It appears that if the name is null it defaults to Sheet%d?
1535 * However, we have only one test case and no docs.
1537 if (bs
->name
== NULL
|| bs
->name
[0] == 0) {
1539 bs
->name
= g_strdup_printf (default_name
,
1540 importer
->boundsheet_sheet_by_index
->len
+ 1);
1544 case MS_BIFF_TYPE_Worksheet
:
1545 case MS_BIFF_TYPE_Macrosheet
:
1546 case MS_BIFF_TYPE_Chart
:
1547 bs
->esheet
= excel_sheet_new (importer
, bs
->name
, bs
->gnm_type
);
1549 if (bs
->esheet
&& bs
->esheet
->sheet
)
1550 g_object_set (bs
->esheet
->sheet
,
1551 "visibility", bs
->visibility
,
1558 bs
->index
= importer
->boundsheet_sheet_by_index
->len
;
1559 g_ptr_array_add (importer
->boundsheet_sheet_by_index
, bs
->esheet
? bs
->esheet
->sheet
: NULL
);
1560 g_hash_table_insert (importer
->boundsheet_data_by_stream
,
1561 GUINT_TO_POINTER (bs
->streamStartPos
), bs
);
1563 d (1, g_printerr ("Boundsheet: %d) '%s' %p, %d:%d\n", bs
->index
,
1564 bs
->name
, bs
->esheet
, bs
->type
, bs
->visibility
););
1568 biff_boundsheet_data_destroy (BiffBoundsheetData
*d
)
1575 excel_read_FORMAT (BiffQuery
*q
, GnmXLImporter
*importer
)
1577 MsBiffVersion
const ver
= importer
->ver
;
1580 if (ver
>= MS_BIFF_V7
) {
1581 XL_CHECK_CONDITION (q
->length
>= 4);
1583 d
= g_new (BiffFormatData
, 1);
1584 d
->idx
= GSF_LE_GET_GUINT16 (q
->data
);
1585 d
->name
= (ver
>= MS_BIFF_V8
)
1586 ? excel_biff_text_2 (importer
, q
, 2)
1587 : excel_biff_text_1 (importer
, q
, 2);
1589 size_t minlen
= (ver
>= MS_BIFF_V4
? 3 : 1);
1590 XL_CHECK_CONDITION (q
->length
>= minlen
);
1592 d
= g_new (BiffFormatData
, 1);
1593 /* no usable index */
1594 d
->idx
= g_hash_table_size (importer
->format_table
);
1595 d
->name
= (ver
>= MS_BIFF_V4
)
1596 ? excel_biff_text_1 (importer
, q
, 2)
1597 : excel_biff_text_1 (importer
, q
, 0);
1600 d (3, g_printerr ("Format data: 0x%x == '%s'\n", d
->idx
, d
->name
););
1602 g_hash_table_insert (importer
->format_table
, GUINT_TO_POINTER (d
->idx
), d
);
1606 excel_read_FONT (BiffQuery
*q
, GnmXLImporter
*importer
)
1608 MsBiffVersion
const ver
= importer
->ver
;
1613 XL_CHECK_CONDITION (q
->length
>= 4);
1615 fd
= g_new (ExcelFont
, 1);
1616 fd
->height
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
1617 data
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
1618 fd
->italic
= (data
& 0x2) == 0x2;
1619 fd
->struck_out
= (data
& 0x8) == 0x8;
1620 fd
->script
= GO_FONT_SCRIPT_STANDARD
;
1621 fd
->underline
= XLS_ULINE_NONE
;
1622 fd
->codepage
= 1252;
1624 if (ver
<= MS_BIFF_V2
) {
1627 fd
->boldness
= (data
& 0x1) ? 0x2bc : 0x190;
1628 fd
->underline
= (data
& 0x4) ? XLS_ULINE_SINGLE
: XLS_ULINE_NONE
;
1629 fd
->fontname
= excel_biff_text_1 (importer
, q
, 4);
1630 if (ms_biff_query_peek_next (q
, &opcode
) &&
1631 opcode
== BIFF_FONT_COLOR
) {
1632 ms_biff_query_next (q
);
1633 XL_CHECK_CONDITION (q
->length
>= 2);
1634 fd
->color_idx
= GSF_LE_GET_GUINT16 (q
->data
);
1636 fd
->color_idx
= 0x7f;
1637 cp
= gnm_font_override_codepage (fd
->fontname
);
1638 fd
->codepage
= (cp
> 0 ? cp
: 1252);
1639 } else if (ver
<= MS_BIFF_V4
) /* Guess */ {
1641 XL_CHECK_CONDITION (q
->length
>= 6);
1642 fd
->color_idx
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
1643 fd
->boldness
= (data
& 0x1) ? 0x2bc : 0x190;
1644 fd
->underline
= (data
& 0x4) ? XLS_ULINE_SINGLE
: XLS_ULINE_NONE
;
1645 fd
->fontname
= excel_biff_text_1 (importer
, q
, 6);
1646 cp
= gnm_font_override_codepage (fd
->fontname
);
1647 fd
->codepage
= (cp
> 0 ? cp
: 1252);
1649 XL_CHECK_CONDITION (q
->length
>= 13);
1651 fd
->color_idx
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
1652 fd
->boldness
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
1653 data
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
1655 case 0: fd
->script
= GO_FONT_SCRIPT_STANDARD
; break;
1656 case 1: fd
->script
= GO_FONT_SCRIPT_SUPER
; break;
1657 case 2: fd
->script
= GO_FONT_SCRIPT_SUB
; break;
1659 g_printerr ("Unknown script %d\n", data
);
1663 data1
= GSF_LE_GET_GUINT8 (q
->data
+ 10);
1665 case 0: fd
->underline
= XLS_ULINE_NONE
; break;
1666 case 1: fd
->underline
= XLS_ULINE_SINGLE
; break;
1667 case 2: fd
->underline
= XLS_ULINE_DOUBLE
; break;
1668 case 0x21: fd
->underline
= XLS_ULINE_SINGLE_ACC
; break; /* single accounting */
1669 case 0x22: fd
->underline
= XLS_ULINE_DOUBLE_ACC
; break; /* double accounting */
1671 g_printerr ("Unknown uline %#x\n", (int)data1
);
1674 fd
->fontname
= excel_biff_text_1 (importer
, q
, 14);
1676 data1
= GSF_LE_GET_GUINT8 (q
->data
+ 12);
1679 int cp
= gnm_font_override_codepage (fd
->fontname
);
1684 if (importer
->codepage_override
> 0) {
1685 fd
->codepage
= importer
->codepage_override
;
1691 case 255: fd
->codepage
= 1252; break; /* ANSI Latin, System Default, OEM Latin I */
1692 case 77: fd
->codepage
= 10000; break; /* Apple */
1693 case 128: fd
->codepage
= 932; break; /* Japanese Shift-JIS */
1694 case 129: fd
->codepage
= 949; break; /* Korean Hangul */
1695 case 130: fd
->codepage
= 1361; break; /* Korean Johab */
1696 case 134: fd
->codepage
= 936; break; /* Chinese Simplified */
1697 case 136: fd
->codepage
= 950; break; /* Chinese Traditional */
1698 case 161: fd
->codepage
= 1253; break; /* Greek */
1699 case 162: fd
->codepage
= 1254; break; /* Turkish */
1700 case 163: fd
->codepage
= 1258; break; /* Vietnamese */
1701 case 177: fd
->codepage
= 1255; break; /* Hebrew */
1702 case 178: fd
->codepage
= 1256; break; /* Arabic */
1703 case 186: fd
->codepage
= 1257; break; /* Baltic */
1704 case 204: fd
->codepage
= 1251; break; /* Russian */
1705 case 222: fd
->codepage
= 874; break; /* Thai */
1706 case 238: fd
->codepage
= 1250; break; /* Central European */
1708 g_printerr ("Unknown charset %#x\n", (int) data1
);
1712 fd
->color_idx
&= 0x7f; /* Undocumented but a good idea */
1714 if (fd
->fontname
== NULL
) {
1715 /* Note sure why -- see #418868. */
1716 fd
->fontname
= g_strdup ("Arial");
1722 fd
->index
= g_hash_table_size (importer
->font_data
);
1723 if (fd
->index
>= 4) /* Weird: for backwards compatibility */
1725 d (1, g_printerr ("Insert font '%s' (%d) size %d pts color %d\n",
1726 fd
->fontname
, fd
->index
, fd
->height
/ 20, fd
->color_idx
););
1727 d (3, g_printerr ("Font color = 0x%x\n", fd
->color_idx
););
1729 g_hash_table_insert (importer
->font_data
,
1730 GINT_TO_POINTER (fd
->index
), fd
);
1735 excel_font_free (ExcelFont
*fd
)
1737 if (NULL
!= fd
->attrs
) {
1738 pango_attr_list_unref (fd
->attrs
);
1741 if (NULL
!= fd
->go_font
) {
1742 go_font_unref (fd
->go_font
);
1745 g_free (fd
->fontname
);
1750 biff_format_data_destroy (BiffFormatData
*d
)
1756 /** Default color table for BIFF5/BIFF7. */
1757 ExcelPaletteEntry
const excel_default_palette_v7
[] = {
1758 { 0, 0, 0}, {255,255,255}, {255, 0, 0}, { 0,255, 0},
1759 { 0, 0,255}, {255,255, 0}, {255, 0,255}, { 0,255,255},
1761 {128, 0, 0}, { 0,128, 0}, { 0, 0,128}, {128,128, 0},
1762 {128, 0,128}, { 0,128,128}, {192,192,192}, {128,128,128},
1764 {128,128,255}, {128, 32, 96}, {255,255,192}, {160,224,224},
1765 { 96, 0,128}, {255,128,128}, { 0,128,192}, {192,192,255},
1767 { 0, 0,128}, {255, 0,255}, {255,255, 0}, { 0,255,255},
1768 {128, 0,128}, {128, 0, 0}, { 0,128,128}, { 0, 0,255},
1770 { 0,204,255}, {105,255,255}, {204,255,204}, {255,255,153},
1771 {166,202,240}, {204,156,204}, {204,153,255}, {227,227,227},
1773 { 51,102,255}, { 51,204,204}, { 51,153, 51}, {153,153, 51},
1774 {153,102, 51}, {153,102,102}, {102,102,153}, {150,150,150},
1776 { 51, 51,204}, { 51,102,102}, { 0, 51, 0}, { 51, 51, 0},
1777 {102, 51, 0}, {153, 51,102}, { 51, 51,153}, { 66, 66, 66}
1780 ExcelPaletteEntry
const excel_default_palette_v8
[] = {
1781 { 0, 0, 0}, {255,255,255}, {255, 0, 0}, { 0,255, 0},
1782 { 0, 0,255}, {255,255, 0}, {255, 0,255}, { 0,255,255},
1784 {128, 0, 0}, { 0,128, 0}, { 0, 0,128}, {128,128, 0},
1785 {128, 0,128}, { 0,128,128}, {192,192,192}, {128,128,128},
1787 {153,153,255}, {153, 51,102}, {255,255,204}, {204,255,255},
1788 {102, 0,102}, {255,128,128}, { 0,102,204}, {204,204,255},
1790 { 0, 0,128}, {255, 0,255}, {255,255, 0}, { 0,255,255},
1791 {128, 0,128}, {128, 0, 0}, { 0,128,128}, { 0, 0,255},
1793 { 0,204,255}, {204,255,255}, {204,255,204}, {255,255,153},
1794 {153,204,255}, {255,153,204}, {204,153,255}, {255,204,153},
1796 { 51,102,255}, { 51,204,204}, {153,204, 0}, {255,204, 0},
1797 {255,153, 0}, {255,102, 0}, {102,102,153}, {150,150,150},
1799 { 0, 51,102}, { 51,153,102}, { 0, 51, 0}, { 51, 51, 0},
1800 {153, 51, 0}, {153, 51,102}, { 51, 51,153}, { 51, 51, 51}
1804 excel_palette_get (GnmXLImporter
*importer
, gint idx
)
1808 /* return black on failure */
1809 g_return_val_if_fail (importer
!= NULL
, style_color_black ());
1811 if (NULL
== (pal
= importer
->palette
)) {
1812 int entries
= EXCEL_DEF_PAL_LEN
;
1813 ExcelPaletteEntry
const *defaults
= (importer
->ver
>= MS_BIFF_V8
)
1814 ? excel_default_palette_v8
: excel_default_palette_v7
;
1816 pal
= importer
->palette
= g_new (ExcelPalette
, 1);
1817 pal
->length
= entries
;
1818 pal
->red
= g_new (int, entries
);
1819 pal
->green
= g_new (int, entries
);
1820 pal
->blue
= g_new (int, entries
);
1821 pal
->gnm_colors
= g_new (GnmColor
*, entries
);
1823 while (--entries
>= 0) {
1824 pal
->red
[entries
] = defaults
[entries
].r
;
1825 pal
->green
[entries
] = defaults
[entries
].g
;
1826 pal
->blue
[entries
] = defaults
[entries
].b
;
1827 pal
->gnm_colors
[entries
] = NULL
;
1831 /* NOTE: not documented but seems close
1832 * If you find a normative reference please forward it.
1834 * The color index field seems to use
1835 * 8-63 = Palette index 0-55
1836 * 64 = auto pattern, auto border
1837 * 65 = auto background
1840 * 65 is always white, and 127 always black. 64 is black
1841 * if the fDefaultHdr flag in WINDOW2 is unset, otherwise it's
1842 * the grid color from WINDOW2.
1845 d (4, g_printerr ("Color Index %d\n", idx
););
1847 if (idx
== 1 || idx
== 65)
1848 return style_color_white ();
1851 case 64: /* system text ? */
1852 case 81: /* tooltip text */
1853 case 0x7fff: /* system text ? */
1854 return style_color_black ();
1856 case 65: /* system back ? */
1857 return style_color_white ();
1859 case 80: /* tooltip background */
1860 return gnm_color_new_rgb8 (0xff, 0xff, 0xe0);
1862 case 2: return gnm_color_new_rgb8 (0xff, 0, 0); /* red */
1863 case 3: return gnm_color_new_rgb8 ( 0, 0xff, 0); /* green */
1864 case 4: return gnm_color_new_rgb8 ( 0, 0, 0xff); /* blue */
1865 case 5: return gnm_color_new_rgb8 (0xff, 0xff, 0); /* yellow */
1866 case 6: return gnm_color_new_rgb8 (0xff, 0, 0xff); /* magenta */
1867 case 7: return gnm_color_new_rgb8 ( 0, 0xff, 0xff); /* cyan */
1873 if (idx
< 0 || pal
->length
<= idx
) {
1874 g_warning ("EXCEL: color index (%d) is out of range (8..%d). Defaulting to black",
1875 idx
+ 8, pal
->length
+8);
1876 return style_color_black ();
1879 if (pal
->gnm_colors
[idx
] == NULL
) {
1880 pal
->gnm_colors
[idx
] =
1881 gnm_color_new_rgb8 (pal
->red
[idx
],
1884 g_return_val_if_fail (pal
->gnm_colors
[idx
],
1885 style_color_black ());
1887 const GnmColor
*c
= pal
->gnm_colors
[idx
];
1888 g_printerr ("New color in slot %d: RGBA = %x,%x,%x,%x\n",
1890 GO_COLOR_UINT_R (c
->go_color
),
1891 GO_COLOR_UINT_G (c
->go_color
),
1892 GO_COLOR_UINT_B (c
->go_color
),
1893 GO_COLOR_UINT_A (c
->go_color
));
1897 style_color_ref (pal
->gnm_colors
[idx
]);
1898 return pal
->gnm_colors
[idx
];
1902 excel_palette_destroy (ExcelPalette
*pal
)
1907 g_free (pal
->green
);
1909 for (lp
= 0; lp
< pal
->length
; lp
++)
1910 if (pal
->gnm_colors
[lp
])
1911 style_color_unref (pal
->gnm_colors
[lp
]);
1912 g_free (pal
->gnm_colors
);
1917 excel_read_PALETTE (BiffQuery
*q
, GnmXLImporter
*importer
)
1922 XL_CHECK_CONDITION (q
->length
>= 2);
1923 len
= GSF_LE_GET_GUINT16 (q
->data
);
1924 XL_CHECK_CONDITION (q
->length
>= 2u + len
* 4u);
1926 pal
= g_new (ExcelPalette
, 1);
1928 pal
->red
= g_new (int, len
);
1929 pal
->green
= g_new (int, len
);
1930 pal
->blue
= g_new (int, len
);
1931 pal
->gnm_colors
= g_new (GnmColor
*, len
);
1933 d (3, g_printerr ("New palette with %d entries\n", len
););
1935 for (lp
= 0; lp
< len
; lp
++) {
1936 guint32 num
= GSF_LE_GET_GUINT32 (q
->data
+ 2 + lp
* 4);
1938 /* NOTE the order of bytes is different from what one would
1940 pal
->blue
[lp
] = (num
& 0x00ff0000) >> 16;
1941 pal
->green
[lp
] = (num
& 0x0000ff00) >> 8;
1942 pal
->red
[lp
] = (num
& 0x000000ff) >> 0;
1943 d (5, g_printerr ("Colour %d: 0x%8x (%x,%x,%x)\n", lp
,
1944 num
, pal
->red
[lp
], pal
->green
[lp
], pal
->blue
[lp
]););
1946 pal
->gnm_colors
[lp
] = NULL
;
1948 if (importer
->palette
)
1949 excel_palette_destroy (importer
->palette
);
1950 importer
->palette
= pal
;
1955 * Search for a font record from its index in the workbooks font table
1956 * NB. index 4 is omitted supposedly for backwards compatiblity
1957 * Returns the font color if there is one.
1960 excel_font_get (GnmXLImporter
const *importer
, unsigned font_idx
)
1962 ExcelFont
const *fd
=
1963 g_hash_table_lookup (importer
->font_data
,
1964 GINT_TO_POINTER (font_idx
));
1966 g_warning ("Invalid font index %d\n", font_idx
);
1968 fd
= g_hash_table_lookup (importer
->font_data
,
1969 GINT_TO_POINTER (0));
1976 excel_font_get_gofont (ExcelFont
const *efont
)
1978 if (NULL
== efont
->go_font
) {
1979 PangoFontDescription
*desc
= pango_font_description_new ();
1981 d (1, { g_printerr ("EFONT: %s %d %d %d\n",
1986 #warning FINISH when GOFont is smarter
1987 pango_font_description_set_family (desc
, efont
->fontname
);
1988 pango_font_description_set_weight (desc
, efont
->boldness
);
1989 pango_font_description_set_style (desc
,
1990 efont
->italic
? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
);
1991 pango_font_description_set_size (desc
,
1992 efont
->height
* PANGO_SCALE
/ 20);
1994 ((ExcelFont
*)efont
)->go_font
= go_font_new_by_desc (desc
);
1996 return efont
->go_font
;
1999 static BiffXFData
const *
2000 excel_get_xf (ExcelReadSheet
*esheet
, unsigned xfidx
)
2002 GPtrArray
const * const p
= esheet
->container
.importer
->XF_cell_records
;
2004 g_return_val_if_fail (p
!= NULL
, NULL
);
2006 if (esheet_ver (esheet
) == MS_BIFF_V2
) {
2007 /* ignore the replicated info that comes with the index
2008 * we've already parsed the XF record */
2010 if (xfidx
== 0x3f) {
2011 if (esheet
->biff2_prev_xf_index
< 0) {
2012 g_warning ("extension xf with no preceding old_xf record, using default as fallback");
2015 xfidx
= esheet
->biff2_prev_xf_index
;
2019 if (xfidx
>= p
->len
) {
2020 XL_CHECK_CONDITION_VAL (p
->len
> 0, NULL
);
2021 g_warning ("XL: Xf index 0x%X is not in the range[0..0x%X)", xfidx
, p
->len
);
2024 /* FIXME: when we can handle styles too deal with this correctly */
2025 /* g_return_val_if_fail (xf->xftype == MS_BIFF_X_CELL, NULL); */
2026 return g_ptr_array_index (p
, xfidx
);
2030 xls_uline_to_gnm_underline (MsBiffFontUnderline mul
)
2032 g_return_val_if_fail (mul
>= XLS_ULINE_NONE
, UNDERLINE_NONE
);
2033 g_return_val_if_fail (mul
<= XLS_ULINE_DOUBLE_ACC
, UNDERLINE_NONE
);
2036 case XLS_ULINE_SINGLE
:
2037 return UNDERLINE_SINGLE
;
2038 case XLS_ULINE_DOUBLE
:
2039 return UNDERLINE_DOUBLE
;
2040 case XLS_ULINE_SINGLE_ACC
:
2041 return UNDERLINE_SINGLE_LOW
;
2042 case XLS_ULINE_DOUBLE_ACC
:
2043 return UNDERLINE_DOUBLE_LOW
;
2044 case XLS_ULINE_NONE
:
2046 return UNDERLINE_NONE
;
2051 /* Adds a ref the result */
2053 excel_get_style_from_xf (ExcelReadSheet
*esheet
, BiffXFData
const *xf
)
2055 ExcelFont
const *fd
;
2056 GnmColor
*pattern_color
, *back_color
, *font_color
;
2057 int pattern_index
, back_index
, font_index
;
2064 /* If we've already done the conversion use the cached style */
2065 if (xf
->mstyle
!= NULL
) {
2066 gnm_style_ref (xf
->mstyle
);
2070 /* Create a new style and fill it in */
2071 mstyle
= gnm_style_new_default ();
2074 if (xf
->style_format
)
2075 gnm_style_set_format (mstyle
, xf
->style_format
);
2078 gnm_style_set_contents_locked (mstyle
, xf
->locked
);
2079 gnm_style_set_contents_hidden (mstyle
, xf
->hidden
);
2082 gnm_style_set_align_v (mstyle
, xf
->valign
);
2083 gnm_style_set_align_h (mstyle
, xf
->halign
);
2084 gnm_style_set_wrap_text (mstyle
, xf
->wrap_text
);
2085 gnm_style_set_shrink_to_fit (mstyle
, xf
->shrink_to_fit
);
2086 gnm_style_set_indent (mstyle
, xf
->indent
);
2087 gnm_style_set_rotation (mstyle
, xf
->rotation
);
2088 gnm_style_set_text_dir (mstyle
, xf
->text_dir
);
2091 fd
= excel_font_get (esheet
->container
.importer
, xf
->font_idx
);
2093 gnm_style_set_font_name (mstyle
, fd
->fontname
);
2094 gnm_style_set_font_size (mstyle
, fd
->height
/ 20.0);
2095 gnm_style_set_font_bold (mstyle
, fd
->boldness
>= 0x2bc);
2096 gnm_style_set_font_italic (mstyle
, fd
->italic
);
2097 gnm_style_set_font_strike (mstyle
, fd
->struck_out
);
2098 gnm_style_set_font_script (mstyle
, fd
->script
);
2099 gnm_style_set_font_uline
2100 (mstyle
, xls_uline_to_gnm_underline (fd
->underline
));
2101 font_index
= fd
->color_idx
;
2103 font_index
= 127; /* Default to Black */
2106 gnm_style_set_pattern (mstyle
, xf
->fill_pattern_idx
);
2108 /* Solid patterns seem to reverse the meaning */
2109 if (xf
->fill_pattern_idx
== 1) {
2110 pattern_index
= xf
->pat_backgnd_col
;
2111 back_index
= xf
->pat_foregnd_col
;
2113 pattern_index
= xf
->pat_foregnd_col
;
2114 back_index
= xf
->pat_backgnd_col
;
2117 d (4, g_printerr ("back = %d, pat = %d, font = %d, pat_style = %d\n",
2118 back_index
, pattern_index
, font_index
, xf
->fill_pattern_idx
););
2120 if (font_index
== 127)
2121 font_color
= style_color_auto_font ();
2123 font_color
= excel_palette_get (esheet
->container
.importer
, font_index
);
2125 switch (back_index
) {
2127 back_color
= sheet_style_get_auto_pattern_color (esheet
->sheet
);
2130 back_color
= style_color_auto_back ();
2133 back_color
= excel_palette_get (esheet
->container
.importer
, back_index
);
2137 switch (pattern_index
) {
2138 case 64: /* Normal case for auto pattern color */
2139 pattern_color
= sheet_style_get_auto_pattern_color
2143 /* Mutated form, also observed in the wild, but only for
2144 solid fill. I. e.: this color is not visible. */
2145 pattern_color
= style_color_auto_back ();
2148 pattern_color
= excel_palette_get (esheet
->container
.importer
, pattern_index
);
2152 g_return_val_if_fail (back_color
&& pattern_color
&& font_color
, NULL
);
2154 d (4, g_printerr ("back = #%02x%02x%02x, pat = #%02x%02x%02x, font = #%02x%02x%02x, pat_style = %d\n",
2155 GO_COLOR_UINT_R (back_color
->go_color
),
2156 GO_COLOR_UINT_G (back_color
->go_color
),
2157 GO_COLOR_UINT_B (back_color
->go_color
),
2158 GO_COLOR_UINT_R (pattern_color
->go_color
),
2159 GO_COLOR_UINT_G (pattern_color
->go_color
),
2160 GO_COLOR_UINT_B (pattern_color
->go_color
),
2161 GO_COLOR_UINT_R (font_color
->go_color
),
2162 GO_COLOR_UINT_G (font_color
->go_color
),
2163 GO_COLOR_UINT_B (font_color
->go_color
),
2164 xf
->fill_pattern_idx
););
2166 gnm_style_set_font_color (mstyle
, font_color
);
2167 gnm_style_set_back_color (mstyle
, back_color
);
2168 gnm_style_set_pattern_color (mstyle
, pattern_color
);
2171 for (i
= 0; i
< STYLE_ORIENT_MAX
; i
++) {
2172 GnmStyle
*tmp
= mstyle
;
2173 GnmStyleElement
const t
= MSTYLE_BORDER_TOP
+ i
;
2174 GnmStyleBorderLocation
const sbl
= GNM_STYLE_BORDER_TOP
+ i
;
2175 int const color_index
= xf
->border_color
[i
];
2178 switch (color_index
) {
2180 color
= sheet_style_get_auto_pattern_color
2182 d (4, g_printerr ("border with color_index=%d\n",
2186 color
= style_color_auto_back ();
2187 /* We haven't seen this yet.
2188 We know that 64 and 127 occur in the wild */
2189 d (4, g_printerr ("border with color_index=%d\n",
2193 color
= style_color_auto_font ();
2196 color
= excel_palette_get (esheet
->container
.importer
, color_index
);
2199 gnm_style_set_border (tmp
, t
,
2200 gnm_style_border_fetch (xf
->border_type
[i
],
2202 gnm_style_border_get_orientation (sbl
)));
2205 /* Set the cache (const_cast) */
2206 ((BiffXFData
*)xf
)->mstyle
= mstyle
;
2207 gnm_style_ref (mstyle
);
2212 excel_choose_border (GnmBorder
*b1
, GnmBorder
*b2
)
2214 /* double > thick > medium > medium-dash > medium-dash-dot > slanted dash-dot >
2215 medium dash-dot-dot > thin > dashed > dotted > dash-dot > dash-dot-dot > hair */
2216 static int choice
[GNM_STYLE_BORDER_SLANTED_DASH_DOT
+ 1]
2217 [GNM_STYLE_BORDER_SLANTED_DASH_DOT
+ 1]
2218 = { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* GNM_STYLE_BORDER_NONE */
2219 { 1,0,0,1,1,0,0,1,0,1,0,1,0,0 }, /* GNM_STYLE_BORDER_THIN */
2220 { 1,1,0,1,1,0,0,1,1,1,1,1,1,1 }, /* GNM_STYLE_BORDER_MEDIUM */
2221 { 1,0,0,0,1,0,0,1,0,1,0,1,0,0 }, /* GNM_STYLE_BORDER_DASHED */
2222 { 1,0,0,0,0,0,0,1,0,1,0,1,0,0 }, /* GNM_STYLE_BORDER_DOTTED */
2223 { 1,1,1,1,1,0,0,1,1,1,1,1,1,1 }, /* GNM_STYLE_BORDER_THICK */
2224 { 1,1,1,1,1,1,0,1,1,1,1,1,1,1 }, /* GNM_STYLE_BORDER_DOUBLE */
2225 { 1,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* GNM_STYLE_BORDER_HAIR */
2226 { 1,1,0,1,1,0,0,1,0,1,1,1,1,1 }, /* GNM_STYLE_BORDER_MEDIUM_DASH */
2227 { 1,0,0,0,0,0,0,1,0,0,0,1,0,0 }, /* GNM_STYLE_BORDER_DASH_DOT */
2228 { 1,1,0,1,1,0,0,1,0,1,0,1,1,1 }, /* GNM_STYLE_BORDER_MEDIUM_DASH_DOT */
2229 { 1,0,0,0,0,0,0,1,0,0,0,0,0,0 }, /* GNM_STYLE_BORDER_DASH_DOT_DOT */
2230 { 1,1,0,1,1,0,0,1,0,1,0,1,0,0 }, /* GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT */
2231 { 1,1,0,1,1,0,0,1,0,1,0,1,1,0 } /* GNM_STYLE_BORDER_SLANTED_DASH_DOT */
2234 return (choice
[b1
->line_type
][b2
->line_type
]) ? b1
: b2
;
2237 static BiffXFData
const *
2238 excel_set_xf (ExcelReadSheet
*esheet
, BiffQuery
*q
)
2241 BiffXFData
const *xf
;
2243 Sheet
*sheet
= esheet
->sheet
;
2245 XL_CHECK_CONDITION_VAL (q
->length
>= 6, NULL
);
2246 col
= XL_GETCOL (q
);
2247 row
= XL_GETROW (q
);
2248 xf
= excel_get_xf (esheet
, GSF_LE_GET_GUINT16 (q
->data
+ 4));
2249 XL_CHECK_CONDITION_VAL (col
< gnm_sheet_get_max_cols (sheet
), xf
);
2250 XL_CHECK_CONDITION_VAL (row
< gnm_sheet_get_max_rows (sheet
), xf
);
2251 mstyle
= excel_get_style_from_xf (esheet
, xf
);
2253 d (3, g_printerr ("%s!%s%d = xf(0x%hx) = style (%p) [LEN = %u]\n", sheet
->name_unquoted
,
2254 col_name (col
), row
+ 1, GSF_LE_GET_GUINT16 (q
->data
+ 4), mstyle
, q
->length
););
2256 if (mstyle
!= NULL
) {
2257 GnmBorder
*top_b
, *left_b
;
2259 sheet_style_set_pos (sheet
, col
, row
, mstyle
);
2261 /* In Excel & Gnumeric generated xls-files we do not have a conflict */
2262 /* between borders of adjacent cells, but according to bug #660605 */
2263 /* there are xls files in the wild that have a conflict. We need to */
2264 /* resolve these conflicts to ensure consistent behaviour when we edit */
2265 /* borders and to provide the expected border appearance. */
2267 top_b
= gnm_style_get_border (mstyle
, MSTYLE_BORDER_TOP
);
2268 left_b
= gnm_style_get_border (mstyle
, MSTYLE_BORDER_LEFT
);
2270 if ((row
> 0 && top_b
!= NULL
&& top_b
->line_type
!= GNM_STYLE_BORDER_NONE
) ||
2271 (col
> 0 && left_b
!= NULL
&& left_b
->line_type
!= GNM_STYLE_BORDER_NONE
)) {
2272 GnmBorder
**overlay
= g_new0 (GnmBorder
*, GNM_STYLE_BORDER_EDGE_MAX
);
2276 top_b
!= NULL
&& top_b
->line_type
!= GNM_STYLE_BORDER_NONE
) {
2277 GnmStyle
const *previous
= sheet_style_get (sheet
, col
, row
- 1);
2278 if (previous
!= NULL
) {
2279 GnmBorder
*prev_b
= gnm_style_get_border
2280 (previous
, MSTYLE_BORDER_BOTTOM
);
2281 if (prev_b
!= NULL
&&
2282 prev_b
->line_type
!= GNM_STYLE_BORDER_NONE
&&
2283 prev_b
->line_type
!= top_b
->line_type
)
2284 overlay
[GNM_STYLE_BORDER_TOP
] =
2285 gnm_style_border_ref
2286 (excel_choose_border (top_b
, prev_b
));
2290 left_b
!= NULL
&& left_b
->line_type
!= GNM_STYLE_BORDER_NONE
) {
2291 GnmStyle
const *previous
= sheet_style_get (sheet
, col
- 1, row
);
2292 if (previous
!= NULL
) {
2293 GnmBorder
*prev_b
= gnm_style_get_border
2294 (previous
, MSTYLE_BORDER_RIGHT
);
2295 if (prev_b
!= NULL
&&
2296 prev_b
->line_type
!= GNM_STYLE_BORDER_NONE
&&
2297 prev_b
->line_type
!= left_b
->line_type
)
2298 overlay
[GNM_STYLE_BORDER_LEFT
] =
2299 gnm_style_border_ref
2300 (excel_choose_border (left_b
, prev_b
));
2304 /* We are using sheet_style_apply_border rather than */
2305 /* sheet_style_apply_pos since it clears the appropriate */
2306 /* adjacent borders */
2307 range_init (&range
, col
, row
, col
, row
);
2308 sheet_style_apply_border (sheet
, &range
, overlay
);
2309 if (overlay
[GNM_STYLE_BORDER_TOP
])
2310 gnm_style_border_unref (overlay
[GNM_STYLE_BORDER_TOP
]);
2311 if (overlay
[GNM_STYLE_BORDER_LEFT
])
2312 gnm_style_border_unref (overlay
[GNM_STYLE_BORDER_LEFT
]);
2320 excel_set_xf_segment (ExcelReadSheet
*esheet
,
2321 int start_col
, int end_col
,
2322 int start_row
, int end_row
, unsigned xfidx
)
2325 GnmStyle
*mstyle
= excel_get_style_from_xf (esheet
,
2326 excel_get_xf (esheet
, xfidx
));
2331 range
.start
.col
= start_col
;
2332 range
.start
.row
= start_row
;
2333 range
.end
.col
= end_col
;
2334 range
.end
.row
= end_row
;
2335 sheet_style_set_range (esheet
->sheet
, &range
, mstyle
);
2338 g_printerr ("%s!", esheet
->sheet
->name_unquoted
);
2339 range_dump (&range
, "");
2340 g_printerr (" = xf(%d)\n", xfidx
);
2344 static GnmStyleBorderType
2345 biff_xf_map_border (int b
)
2349 return GNM_STYLE_BORDER_NONE
;
2351 return GNM_STYLE_BORDER_THIN
;
2352 case 2: /* Medium */
2353 return GNM_STYLE_BORDER_MEDIUM
;
2354 case 3: /* Dashed */
2355 return GNM_STYLE_BORDER_DASHED
;
2356 case 4: /* Dotted */
2357 return GNM_STYLE_BORDER_DOTTED
;
2359 return GNM_STYLE_BORDER_THICK
;
2360 case 6: /* Double */
2361 return GNM_STYLE_BORDER_DOUBLE
;
2363 return GNM_STYLE_BORDER_HAIR
;
2364 case 8: /* Medium Dashed */
2365 return GNM_STYLE_BORDER_MEDIUM_DASH
;
2366 case 9: /* Dash Dot */
2367 return GNM_STYLE_BORDER_DASH_DOT
;
2368 case 10: /* Medium Dash Dot */
2369 return GNM_STYLE_BORDER_MEDIUM_DASH_DOT
;
2370 case 11: /* Dash Dot Dot */
2371 return GNM_STYLE_BORDER_DASH_DOT_DOT
;
2372 case 12: /* Medium Dash Dot Dot */
2373 return GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT
;
2374 case 13: /* Slanted Dash Dot*/
2375 return GNM_STYLE_BORDER_SLANTED_DASH_DOT
;
2377 g_printerr ("Unknown border style %d\n", b
);
2378 return GNM_STYLE_BORDER_NONE
;
2382 excel_map_pattern_index_from_excel (int const i
)
2384 static int const map_from_excel
[] = {
2387 10, 9, 11, 12, 13, 14,
2388 15, 16, 17, 18, 5, 6
2391 /* Default to Solid if out of range */
2392 XL_CHECK_CONDITION_VAL (i
>= 0 && i
< (int)G_N_ELEMENTS (map_from_excel
), 0);
2394 return map_from_excel
[i
];
2398 halign_from_excel (guint e
)
2401 case 0: return GNM_HALIGN_GENERAL
;
2402 case 1: return GNM_HALIGN_LEFT
;
2403 case 2: return GNM_HALIGN_CENTER
;
2404 case 3: return GNM_HALIGN_RIGHT
;
2405 case 4: return GNM_HALIGN_FILL
;
2406 case 5: return GNM_HALIGN_JUSTIFY
;
2407 case 6: return GNM_HALIGN_CENTER_ACROSS_SELECTION
;
2408 case 7: return GNM_HALIGN_DISTRIBUTED
;
2411 g_printerr ("Unknown halign %d\n", e
);
2412 return GNM_HALIGN_GENERAL
;
2417 valign_from_excel (guint e
)
2420 case 0: return GNM_VALIGN_TOP
;
2421 case 1: return GNM_VALIGN_CENTER
;
2422 case 2: return GNM_VALIGN_BOTTOM
;
2423 case 3: return GNM_VALIGN_JUSTIFY
;
2424 case 4: return GNM_VALIGN_DISTRIBUTED
;
2426 g_printerr ("Unknown valign %d\n", e
);
2427 return GNM_VALIGN_TOP
;
2432 rotation_from_excel_v8 (guint e
)
2437 return 360 + 90 - e
;
2443 rotation_from_excel_v7 (guint e
)
2455 excel_read_XF_OLD (BiffQuery
*q
, GnmXLImporter
*importer
)
2461 d ( 2, g_printerr ("XF # %d\n", importer
->XF_cell_records
->len
); );
2462 d ( 2, gsf_mem_dump (q
->data
, q
->length
); );
2464 XL_CHECK_CONDITION (q
->length
>= (importer
->ver
>= MS_BIFF_V3
? 12 : 4));
2466 xf
= g_new0 (BiffXFData
, 1);
2467 xf
->font_idx
= q
->data
[0];
2468 xf
->format_idx
= (importer
->ver
>= MS_BIFF_V3
)
2469 ? q
->data
[1] : (q
->data
[2] & 0x3f);
2470 xf
->style_format
= (xf
->format_idx
> 0)
2471 ? excel_wb_get_fmt (importer
, xf
->format_idx
) : NULL
;
2472 xf
->is_simple_format
= xf
->style_format
== NULL
||
2473 go_format_is_simple (xf
->style_format
);
2475 if (importer
->ver
>= MS_BIFF_V3
) {
2476 xf
->locked
= (q
->data
[2] & 0x1) != 0;
2477 xf
->hidden
= (q
->data
[2] & 0x2) != 0;
2478 xf
->xftype
= (q
->data
[2] & 0x4)
2479 ? MS_BIFF_X_STYLE
: MS_BIFF_X_CELL
;
2481 xf
->locked
= (q
->data
[1] & 0x40) != 0;
2482 xf
->hidden
= (q
->data
[1] & 0x80) != 0;
2483 xf
->xftype
= MS_BIFF_X_CELL
;
2485 xf
->parentstyle
= 0; /* TODO extract for biff 3 and biff4 */
2486 xf
->format
= MS_BIFF_F_MS
;
2487 xf
->wrap_text
= FALSE
;
2488 xf
->shrink_to_fit
= FALSE
;
2491 xf
->halign
= GNM_HALIGN_GENERAL
;
2493 data
= (importer
->ver
>= MS_BIFF_V3
) ? q
->data
[4] : q
->data
[3];
2494 switch (data
& 0x07) {
2496 case 0: xf
->halign
= GNM_HALIGN_GENERAL
; break;
2497 case 1: xf
->halign
= GNM_HALIGN_LEFT
; break;
2498 case 2: xf
->halign
= GNM_HALIGN_CENTER
; break;
2499 case 3: xf
->halign
= GNM_HALIGN_RIGHT
; break;
2500 case 4: xf
->halign
= GNM_HALIGN_FILL
; break;
2501 case 5: xf
->halign
= GNM_HALIGN_JUSTIFY
; break;
2502 case 6: xf
->halign
= GNM_HALIGN_CENTER_ACROSS_SELECTION
; break;
2505 xf
->valign
= GNM_VALIGN_BOTTOM
;
2508 xf
->differences
= 0;
2509 xf
->text_dir
= GNM_TEXT_DIR_CONTEXT
;
2511 if (importer
->ver
>= MS_BIFF_V4
) {
2512 xf
->wrap_text
= (data
& 0x0008) != 0;
2513 switch (data
& 0x30) {
2514 case 0x00: xf
->valign
= GNM_VALIGN_TOP
; break;
2515 case 0x10: xf
->valign
= GNM_VALIGN_CENTER
; break;
2517 case 0x20: xf
->valign
= GNM_VALIGN_BOTTOM
; break;
2519 switch (data
& 0xc0) {
2520 case 0x00: xf
->rotation
= 0; break;
2521 case 0x40: xf
->rotation
= -1; break;
2522 case 0x80: xf
->rotation
= 90; break;
2523 case 0xc0: xf
->rotation
= 270; break;
2525 } else if (importer
->ver
>= MS_BIFF_V3
) {
2526 xf
->wrap_text
= (data
& 0x0008) != 0;
2528 xf
->valign
= GNM_VALIGN_TOP
;
2531 if (importer
->ver
>= MS_BIFF_V3
) {
2532 data
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
2533 xf
->pat_backgnd_col
= (data
& 0xf800) >> 11;
2534 if (xf
->pat_backgnd_col
>= 24)
2535 xf
->pat_backgnd_col
+= 40; /* Defaults */
2536 xf
->pat_foregnd_col
= (data
& 0x07c0) >> 6;
2537 if (xf
->pat_foregnd_col
>= 24)
2538 xf
->pat_foregnd_col
+= 40; /* Defaults */
2539 xf
->fill_pattern_idx
=
2540 excel_map_pattern_index_from_excel(data
& 0x001f);
2542 data
= GSF_LE_GET_GUINT8 (q
->data
+ 10);
2543 xf
->border_type
[STYLE_BOTTOM
] = biff_xf_map_border(data
& 0x07);
2544 subdata
= data
>> 3;
2545 xf
->border_color
[STYLE_BOTTOM
] = (subdata
==24) ? 64 : subdata
;
2546 data
= GSF_LE_GET_GUINT8 (q
->data
+ 8);
2547 xf
->border_type
[STYLE_TOP
] = biff_xf_map_border(data
& 0x07);
2548 subdata
= data
>> 3;
2549 xf
->border_color
[STYLE_TOP
] = (subdata
==24) ? 64 : subdata
;
2550 data
= GSF_LE_GET_GUINT8 (q
->data
+ 9);
2551 xf
->border_type
[STYLE_LEFT
] = biff_xf_map_border(data
& 0x07);
2552 subdata
= data
>> 3;
2553 xf
->border_color
[STYLE_LEFT
] = (subdata
==24) ? 64 : subdata
;
2554 data
= GSF_LE_GET_GUINT8 (q
->data
+ 11);
2555 xf
->border_type
[STYLE_RIGHT
] = biff_xf_map_border (data
& 0x07);
2556 subdata
= data
>> 3;
2557 xf
->border_color
[STYLE_RIGHT
] = (subdata
==24) ? 64 : subdata
;
2558 } else /* MS_BIFF_V2 */ {
2559 xf
->pat_foregnd_col
= 0;
2560 xf
->pat_backgnd_col
= 1;
2563 xf
->border_type
[STYLE_LEFT
] = (data
& 0x08) ? 1 : 0;
2564 xf
->border_color
[STYLE_LEFT
] = 0;
2565 xf
->border_type
[STYLE_RIGHT
] = (data
& 0x10) ? 1: 0;
2566 xf
->border_color
[STYLE_RIGHT
] = 0;
2567 xf
->border_type
[STYLE_TOP
] = (data
& 0x20) ? 1: 0;
2568 xf
->border_color
[STYLE_TOP
] = 0;
2569 xf
->border_type
[STYLE_BOTTOM
] = (data
& 0x40) ? 1: 0;
2570 xf
->border_color
[STYLE_BOTTOM
] = 0;
2571 xf
->fill_pattern_idx
= (data
& 0x80) ? 5: 0;
2574 xf
->border_type
[STYLE_DIAGONAL
] = 0;
2575 xf
->border_color
[STYLE_DIAGONAL
] = 0;
2576 xf
->border_type
[STYLE_REV_DIAGONAL
] = 0;
2577 xf
->border_color
[STYLE_REV_DIAGONAL
] = 0;
2579 /* Init the cache */
2582 g_ptr_array_add (importer
->XF_cell_records
, xf
);
2586 excel_read_XF (BiffQuery
*q
, GnmXLImporter
*importer
)
2589 guint32 data
, subdata
;
2591 if (importer
->ver
>= MS_BIFF_V8
)
2592 XL_CHECK_CONDITION (q
->length
>= 20);
2594 XL_CHECK_CONDITION (q
->length
>= 16);
2596 xf
= g_new (BiffXFData
, 1);
2597 xf
->font_idx
= GSF_LE_GET_GUINT16 (q
->data
);
2598 xf
->format_idx
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
2599 xf
->style_format
= (xf
->format_idx
> 0)
2600 ? excel_wb_get_fmt (importer
, xf
->format_idx
) : NULL
;
2601 xf
->is_simple_format
= xf
->style_format
== NULL
||
2602 go_format_is_simple (xf
->style_format
);
2604 data
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
2605 xf
->locked
= (data
& 0x0001) != 0;
2606 xf
->hidden
= (data
& 0x0002) != 0;
2607 xf
->xftype
= (data
& 0x0004) ? MS_BIFF_X_STYLE
: MS_BIFF_X_CELL
;
2608 xf
->format
= (data
& 0x0008) ? MS_BIFF_F_LOTUS
: MS_BIFF_F_MS
;
2609 xf
->parentstyle
= (data
& 0xfff0) >> 4;
2611 if (xf
->xftype
== MS_BIFF_X_CELL
&& xf
->parentstyle
!= 0) {
2612 /* TODO Add support for parent styles
2613 * XL implements a simple form of inheritance with styles.
2614 * If a style's parent changes a value and the child has not
2615 * overridden that value explicitly the child gets updated.
2619 data
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
2620 xf
->halign
= halign_from_excel (data
& 0x0007);
2621 xf
->wrap_text
= (data
& 0x0008) != 0;
2622 xf
->valign
= valign_from_excel ((data
& 0x0070) >> 4);
2623 xf
->rotation
= (importer
->ver
>= MS_BIFF_V8
)
2624 ? rotation_from_excel_v8 (data
>> 8)
2625 : rotation_from_excel_v7 ((data
>> 8) & 3);
2627 if (importer
->ver
>= MS_BIFF_V8
) {
2628 guint16
const data
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
2630 /* FIXME: This code seems irrelevant for merging.
2631 * The undocumented record MERGECELLS appears to be the correct source.
2632 * Nothing seems to set the merge flags.
2634 /* gboolean const merge = (data & 0x20) ? TRUE : FALSE; */
2636 xf
->indent
= data
& 0x0f;
2637 xf
->shrink_to_fit
= (data
& 0x10) ? TRUE
: FALSE
;
2639 subdata
= (data
& 0x00C0) >> 10;
2641 default: g_warning ("Unknown text direction %d.", subdata
);
2643 case 0: xf
->text_dir
= GNM_TEXT_DIR_CONTEXT
; break;
2644 case 1: xf
->text_dir
= GNM_TEXT_DIR_LTR
; break;
2645 case 2: xf
->text_dir
= GNM_TEXT_DIR_RTL
; break;
2648 xf
->text_dir
= GNM_TEXT_DIR_CONTEXT
;
2649 xf
->shrink_to_fit
= FALSE
;
2653 xf
->differences
= data
& 0xFC00;
2655 if (importer
->ver
>= MS_BIFF_V8
) { /* Very different */
2656 int has_diagonals
, diagonal_style
;
2657 data
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
2659 xf
->border_type
[STYLE_LEFT
] = biff_xf_map_border (subdata
& 0xf);
2660 subdata
= subdata
>> 4;
2661 xf
->border_type
[STYLE_RIGHT
] = biff_xf_map_border (subdata
& 0xf);
2662 subdata
= subdata
>> 4;
2663 xf
->border_type
[STYLE_TOP
] = biff_xf_map_border (subdata
& 0xf);
2664 subdata
= subdata
>> 4;
2665 xf
->border_type
[STYLE_BOTTOM
] = biff_xf_map_border (subdata
& 0xf);
2666 subdata
= subdata
>> 4;
2668 data
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
2670 xf
->border_color
[STYLE_LEFT
] = (subdata
& 0x7f);
2671 subdata
= subdata
>> 7;
2672 xf
->border_color
[STYLE_RIGHT
] = (subdata
& 0x7f);
2673 subdata
= (data
& 0xc000) >> 14;
2674 has_diagonals
= subdata
& 0x3;
2676 data
= GSF_LE_GET_GUINT32 (q
->data
+ 14);
2678 xf
->border_color
[STYLE_TOP
] = (subdata
& 0x7f);
2679 subdata
= subdata
>> 7;
2680 xf
->border_color
[STYLE_BOTTOM
] = (subdata
& 0x7f);
2681 subdata
= subdata
>> 7;
2683 /* Assign the colors whether we have a border or not. We will
2684 * handle that later */
2685 xf
->border_color
[STYLE_DIAGONAL
] =
2686 xf
->border_color
[STYLE_REV_DIAGONAL
] = (subdata
& 0x7f);
2688 /* Ok. Now use the flag from above to assign borders */
2689 diagonal_style
= biff_xf_map_border (((data
& 0x01e00000) >> 21) & 0xf);
2690 xf
->border_type
[STYLE_DIAGONAL
] = (has_diagonals
& 0x2)
2691 ? diagonal_style
: GNM_STYLE_BORDER_NONE
;
2692 xf
->border_type
[STYLE_REV_DIAGONAL
] = (has_diagonals
& 0x1)
2693 ? diagonal_style
: GNM_STYLE_BORDER_NONE
;
2695 xf
->fill_pattern_idx
=
2696 excel_map_pattern_index_from_excel ((data
>>26) & 0x3f);
2698 data
= GSF_LE_GET_GUINT16 (q
->data
+ 18);
2699 xf
->pat_foregnd_col
= (data
& 0x007f);
2700 xf
->pat_backgnd_col
= (data
& 0x3f80) >> 7;
2702 d (2, g_printerr ("Color f=0x%x b=0x%x pat=0x%x\n",
2703 xf
->pat_foregnd_col
,
2704 xf
->pat_backgnd_col
,
2705 xf
->fill_pattern_idx
););
2707 } else { /* Biff 7 */
2708 data
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
2709 xf
->pat_foregnd_col
= (data
& 0x007f);
2710 /* Documentation is wrong, background color is one bit more
2711 * than documented */
2712 xf
->pat_backgnd_col
= (data
& 0x3f80) >> 7;
2714 data
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
2715 xf
->fill_pattern_idx
=
2716 excel_map_pattern_index_from_excel (data
& 0x3f);
2718 d (2, g_printerr ("Color f=0x%x b=0x%x pat=0x%x\n",
2719 xf
->pat_foregnd_col
,
2720 xf
->pat_backgnd_col
,
2721 xf
->fill_pattern_idx
););
2723 /* Luckily this maps nicely onto the new set. */
2724 xf
->border_type
[STYLE_BOTTOM
] = biff_xf_map_border ((data
& 0x1c0) >> 6);
2725 xf
->border_color
[STYLE_BOTTOM
] = (data
& 0xfe00) >> 9;
2727 data
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
2729 xf
->border_type
[STYLE_TOP
] = biff_xf_map_border (subdata
& 0x07);
2730 subdata
= subdata
>> 3;
2731 xf
->border_type
[STYLE_LEFT
] = biff_xf_map_border (subdata
& 0x07);
2732 subdata
= subdata
>> 3;
2733 xf
->border_type
[STYLE_RIGHT
] = biff_xf_map_border (subdata
& 0x07);
2735 subdata
= subdata
>> 3;
2736 xf
->border_color
[STYLE_TOP
] = subdata
;
2738 data
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
2740 xf
->border_color
[STYLE_LEFT
] = (subdata
& 0x7f);
2741 subdata
= subdata
>> 7;
2742 xf
->border_color
[STYLE_RIGHT
] = (subdata
& 0x7f);
2744 /* Init the diagonals which were not availabile in Biff7 */
2745 xf
->border_type
[STYLE_DIAGONAL
] =
2746 xf
->border_type
[STYLE_REV_DIAGONAL
] = 0;
2747 xf
->border_color
[STYLE_DIAGONAL
] =
2748 xf
->border_color
[STYLE_REV_DIAGONAL
] = 127;
2751 /* Init the cache */
2754 g_ptr_array_add (importer
->XF_cell_records
, xf
);
2755 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",
2756 importer
->XF_cell_records
->len
- 1,
2757 xf
->is_simple_format
, xf
->locked
, xf
->hidden
, xf
->format
,
2761 xf
->pat_foregnd_col
,
2762 xf
->pat_backgnd_col
,
2763 xf
->fill_pattern_idx
););
2767 excel_read_XF_INDEX (BiffQuery
*q
, ExcelReadSheet
*esheet
)
2769 XL_CHECK_CONDITION (q
->length
>= 2);
2770 esheet
->biff2_prev_xf_index
= GSF_LE_GET_GUINT16 (q
->data
);
2774 biff_xf_data_destroy (BiffXFData
*xf
)
2776 go_format_unref (xf
->style_format
);
2777 xf
->style_format
= NULL
;
2780 gnm_style_unref (xf
->mstyle
);
2786 static GnmExprTop
const *
2787 excel_formula_shared (BiffQuery
*q
, ExcelReadSheet
*esheet
, GnmCell
*cell
)
2789 guint16 opcode
, data_len
, data_ofs
, array_data_len
;
2792 GnmExprTop
const *texpr
;
2795 if (!ms_biff_query_peek_next (q
, &opcode
) ||
2796 !(opcode
== BIFF_SHRFMLA
||
2797 opcode
== BIFF_ARRAY_v0
|| opcode
== BIFF_ARRAY_v2
||
2798 opcode
== BIFF_TABLE_v0
|| opcode
== BIFF_TABLE_v2
)) {
2799 g_warning ("EXCEL: unexpected record '0x%x' after a formula in '%s'.",
2800 opcode
, cell_name (cell
));
2803 ms_biff_query_next (q
);
2805 XL_CHECK_CONDITION_VAL (q
->length
>= 6, NULL
);
2806 xls_read_range8 (&r
, q
->data
);
2808 if (opcode
== BIFF_TABLE_v0
|| opcode
== BIFF_TABLE_v2
) {
2810 GnmExprList
*args
= NULL
;
2814 XL_CHECK_CONDITION_VAL (q
->length
>= 16, NULL
);
2816 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
2818 d (2, { range_dump (&r
, " <-- contains data table\n");
2819 gsf_mem_dump (q
->data
, q
->length
); });
2821 dt
= g_new0 (XLDataTable
, 1);
2823 dt
->c_in
.row
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
2824 dt
->c_in
.col
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
2825 dt
->r_in
.row
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
2826 dt
->r_in
.col
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
2827 g_hash_table_replace (esheet
->tables
, &dt
->table
.start
, dt
);
2829 args
= gnm_expr_list_append
2831 gnm_expr_new_cellref
2832 (gnm_cellref_init (&ref
, NULL
,
2833 dt
->c_in
.col
- r
.start
.col
,
2834 dt
->c_in
.row
- r
.start
.row
, TRUE
)));
2836 args
= gnm_expr_list_append
2838 gnm_expr_new_cellref
2839 (gnm_cellref_init (&ref
, NULL
,
2840 dt
->r_in
.col
- r
.start
.col
,
2841 dt
->r_in
.row
- r
.start
.row
, TRUE
)));
2843 GnmExpr
const *missing
= gnm_expr_new_constant (value_new_empty ());
2845 ? gnm_expr_list_append (args
, missing
)
2846 : gnm_expr_list_prepend (args
, missing
);
2848 texpr
= gnm_expr_top_new (gnm_expr_new_funcall (gnm_func_lookup ("table", NULL
), args
));
2849 gnm_cell_set_array (esheet
->sheet
, &r
, texpr
);
2850 gnm_expr_top_unref (texpr
);
2854 d (2, range_dump (&r
, " <-- contains a shared formula\n"););
2856 is_array
= (q
->opcode
!= BIFF_SHRFMLA
);
2858 data_ofs
= (esheet_ver (esheet
) > MS_BIFF_V4
&& is_array
) ? 14 : 10;
2859 XL_CHECK_CONDITION_VAL (q
->length
>= data_ofs
, NULL
);
2860 data
= q
->data
+ data_ofs
;
2861 data_len
= GSF_LE_GET_GUINT16 (q
->data
+ (data_ofs
- 2));
2862 XL_CHECK_CONDITION_VAL (q
->length
>= data_ofs
+ data_len
, NULL
);
2863 array_data_len
= data_len
> 0 ? q
->length
- (data_ofs
+ data_len
) : 0;
2865 texpr
= excel_parse_formula (&esheet
->container
, esheet
,
2866 r
.start
.col
, r
.start
.row
,
2867 data
, data_len
, array_data_len
,
2870 if (g_hash_table_lookup (esheet
->shared_formulae
, &cell
->pos
)) {
2871 g_printerr ("Duplicate shared formula for cell %s\n", cell_name (cell
));
2873 XLSharedFormula
*sf
= g_new (XLSharedFormula
, 1);
2875 /* WARNING: Do NOT use the upper left corner as the hashkey.
2876 * For some bizzare reason XL appears to sometimes not
2877 * flag the formula as shared until later.
2878 * Use the location of the cell we are reading as the key.
2880 sf
->key
= cell
->pos
;
2881 sf
->is_array
= is_array
;
2882 sf
->data
= data_len
> 0 ? g_memdup (data
, data_len
+ array_data_len
) : NULL
;
2883 sf
->data_len
= data_len
;
2884 sf
->array_data_len
= array_data_len
;
2885 sf
->being_parsed
= FALSE
;
2887 d (1, g_printerr ("Shared formula, extent %s\n", range_as_string (&r
)););
2889 g_hash_table_insert (esheet
->shared_formulae
, &sf
->key
, sf
);
2892 g_return_val_if_fail (texpr
!= NULL
, NULL
);
2895 gnm_cell_set_array (esheet
->sheet
, &r
, texpr
);
2896 gnm_expr_top_unref (texpr
);
2903 * NOTE: There must be _no_ path through this function that does not set the
2907 excel_read_FORMULA (BiffQuery
*q
, ExcelReadSheet
*esheet
)
2909 /* Pre-retrieve incase this is a string */
2910 gboolean array_elem
, is_string
= FALSE
;
2911 guint16 col
, row
, options
;
2912 guint16 expr_length
;
2914 guint8
const *val_dat
= q
->data
+ 6;
2915 GnmExprTop
const *texpr
;
2917 GnmValue
*val
= NULL
;
2919 XL_CHECK_CONDITION (q
->length
>= 16);
2920 col
= XL_GETCOL (q
);
2921 row
= XL_GETROW (q
);
2922 options
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
2924 excel_set_xf (esheet
, q
);
2926 cell
= excel_cell_fetch (q
, esheet
);
2930 /* TODO TODO TODO: Wishlist
2931 * We should make an array of minimum sizes for each BIFF type
2932 * and have this checking done there.
2934 if (esheet_ver (esheet
) >= MS_BIFF_V5
) {
2935 XL_CHECK_CONDITION (q
->length
>= 22);
2936 expr_length
= GSF_LE_GET_GUINT16 (q
->data
+ 20);
2939 /* TODO : it would be nice to figure out how to allocate recalc tags.
2940 * that would avoid the scary
2941 * 'this file was calculated with a different version of XL'
2942 * warning when exiting without changing. */
2943 d (1, g_printerr ("Formula in %s!%s has recalc tag 0x%x;\n",
2944 esheet
->sheet
->name_quoted
, cell_name (cell
),
2945 GSF_LE_GET_GUINT32 (q
->data
+ 16)););
2947 } else if (esheet_ver (esheet
) >= MS_BIFF_V3
) {
2948 XL_CHECK_CONDITION (q
->length
>= 18);
2949 expr_length
= GSF_LE_GET_GUINT16 (q
->data
+ 16);
2952 XL_CHECK_CONDITION (q
->length
>= 17);
2953 expr_length
= GSF_LE_GET_GUINT8 (q
->data
+ 16);
2955 val_dat
++; /* compensate for the 3 byte style */
2957 XL_CHECK_CONDITION (q
->length
>= offset
+ expr_length
);
2959 /* Get the current value so that we can format, do this BEFORE handling
2960 * shared/array formulas or strings in case we need to go to the next
2962 if (GSF_LE_GET_GUINT16 (val_dat
+ 6) != 0xffff) {
2963 val
= value_new_float (gsf_le_get_double (val_dat
));
2965 guint8
const val_type
= GSF_LE_GET_GUINT8 (val_dat
);
2967 case 0: is_string
= TRUE
; break;
2968 case 1: val
= value_new_bool (GSF_LE_GET_GUINT8 (val_dat
+ 2) != 0);
2970 case 2: val
= xls_value_new_err (NULL
, GSF_LE_GET_GUINT8 (val_dat
+ 2));
2972 case 3: val
= value_new_empty (); /* Empty (Undocumented) */
2975 g_printerr ("Unknown type (%x) for cell's (%s) current val\n",
2976 val_type
, cell_name (cell
));
2980 texpr
= excel_parse_formula (&esheet
->container
, esheet
, col
, row
,
2981 q
->data
+ offset
, expr_length
,
2982 q
->length
- (offset
+ expr_length
),
2983 FALSE
, &array_elem
);
2985 /* dump the trailing array and natural language data */
2986 gsf_mem_dump (q
->data
+ offset
+ expr_length
,
2987 q
->length
- offset
- expr_length
);
2990 /* Error was flaged by parse_formula */
2991 if (texpr
== NULL
&& !array_elem
)
2992 texpr
= excel_formula_shared (q
, esheet
, cell
);
2996 if (ms_biff_query_peek_next (q
, &opcode
) &&
2997 (opcode
== BIFF_STRING_v0
|| opcode
== BIFF_STRING_v2
)) {
2999 if (ms_biff_query_next (q
)) {
3001 * NOTE: the Excel developers kit docs are
3002 * WRONG. There is an article that
3003 * clarifies the behaviour to be the std
3004 * unicode format rather than the pure
3005 * length version the docs describe.
3007 * NOTE : Apparently some apps actually store a
3008 * 0 length string record for an empty.
3009 * DAMN! this was us! we were screwing
3010 * up when exporting ""
3012 guint16
const len
= (q
->length
>= 2) ? GSF_LE_GET_GUINT16 (q
->data
) : 0;
3015 v
= excel_biff_text (esheet
->container
.importer
, q
, 2, len
);
3018 * Pre-Biff8 seems to use len=0
3019 * Should that be a string or an EMPTY?
3024 val
= value_new_string_nocopy (v
);
3027 val
= value_new_error (eval_pos_init_cell (&ep
, cell
),
3029 g_warning ("EXCEL: invalid STRING record in %s",
3033 /* There should be a STRING record here */
3035 val
= value_new_error (eval_pos_init_cell (&ep
, cell
),
3037 g_warning ("EXCEL: missing STRING record for %s",
3042 /* We MUST have a value */
3045 val
= value_new_error (eval_pos_init_cell (&ep
, cell
),
3047 g_warning ("EXCEL: Invalid state. Missing Value in %s?",
3051 if (gnm_cell_is_array (cell
)) {
3052 /* Array expressions were already stored in the cells (without
3053 * recalc), and without a value. Handle either the first
3054 * instance or the followers.
3056 gnm_cell_assign_value (cell
, val
);
3057 } else if (!gnm_cell_has_expr (cell
)) {
3058 /* Just in case things screwed up, at least save the value */
3059 if (texpr
!= NULL
) {
3060 gnm_cell_set_expr_and_value (cell
, texpr
, val
, TRUE
);
3061 gnm_expr_top_unref (texpr
);
3063 gnm_cell_assign_value (cell
, val
);
3066 * NOTE: Only the expression is screwed.
3067 * The value and format can still be set.
3069 g_warning ("EXCEL: Multiple expressions for cell %s!%s",
3070 esheet
->sheet
->name_quoted
, cell_name (cell
));
3071 gnm_cell_set_value (cell
, val
);
3073 gnm_expr_top_unref (texpr
);
3081 cell_queue_recalc (cell
);
3085 excel_sheet_shared_formula (ExcelReadSheet
const *esheet
,
3086 GnmCellPos
const *key
)
3088 g_return_val_if_fail (esheet
!= NULL
, NULL
);
3090 d (5, g_printerr ("FIND SHARED: %s\n", cellpos_as_string (key
)););
3092 return g_hash_table_lookup (esheet
->shared_formulae
, key
);
3096 excel_sheet_data_table (ExcelReadSheet
const *esheet
,
3097 GnmCellPos
const *key
)
3099 g_return_val_if_fail (esheet
!= NULL
, NULL
);
3101 d (5, g_printerr ("FIND DATA TABLE: %s\n", cellpos_as_string (key
)););
3103 return g_hash_table_lookup (esheet
->tables
, key
);
3107 excel_sheet_insert_val (ExcelReadSheet
*esheet
, BiffQuery
*q
, GnmValue
*v
)
3109 GnmCell
*cell
= excel_cell_fetch (q
, esheet
);
3112 (void)excel_set_xf (esheet
, q
);
3113 gnm_cell_set_value (cell
, v
);
3119 excel_read_NOTE (BiffQuery
*q
, ExcelReadSheet
*esheet
)
3122 Sheet
*sheet
= esheet
->sheet
;
3125 XL_CHECK_CONDITION (q
->length
>= 4);
3127 row
= XL_GETROW (q
);
3128 col
= XL_GETCOL (q
);
3129 XL_CHECK_CONDITION (col
< gnm_sheet_get_max_cols (sheet
));
3130 XL_CHECK_CONDITION (row
< gnm_sheet_get_max_rows (sheet
));
3131 pos
.row
= XL_GETROW (q
);
3132 pos
.col
= XL_GETCOL (q
);
3134 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
3135 guint16 options
, obj_id
;
3140 XL_CHECK_CONDITION (q
->length
>= 8);
3141 options
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3142 hidden
= (options
& 0x2)==0;
3143 obj_id
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
3145 /* Docs claim that only 0x2 is valid, all other flags should
3146 * be 0 but we have seen examples with 0x100 'pusiuhendused juuli 2003.xls'
3148 * docs mention 0x002 == hidden
3149 * real life adds 0x080 == ???
3150 * real life adds 0x100 == no indicator visible ??? */
3151 if (options
& 0xe7d)
3152 g_warning ("unknown flag on NOTE record %hx", options
);
3154 author
= excel_biff_text_2 (esheet
->container
.importer
, q
, 8);
3155 d (1, g_printerr ("Comment at %s%d id %d options"
3156 " 0x%x hidden %d by '%s'\n",
3157 col_name (pos
.col
), pos
.row
+ 1,
3158 obj_id
, options
, hidden
, author
););
3160 obj
= ms_container_get_obj (&esheet
->container
, obj_id
);
3162 cell_comment_author_set (GNM_CELL_COMMENT (obj
->gnum_obj
), author
);
3163 obj
->comment_pos
= pos
;
3165 /* hmm, how did this happen ? we should have seen
3166 * some escher records earlier */
3167 cell_set_comment (sheet
, &pos
, author
, NULL
, NULL
);
3174 XL_CHECK_CONDITION (q
->length
>= 6);
3175 len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3176 comment
= g_string_sized_new (len
);
3178 for (; len
> 2048 ; len
-= 2048) {
3181 g_string_append (comment
,
3182 excel_biff_text (esheet
->container
.importer
,
3185 if (!ms_biff_query_peek_next (q
, &opcode
) ||
3186 opcode
!= BIFF_NOTE
|| !ms_biff_query_next (q
) ||
3188 XL_GETROW (q
) != 0xffff || XL_GETCOL (q
) != 0) {
3189 g_warning ("Invalid Comment record");
3190 g_string_free (comment
, TRUE
);
3194 g_string_append (comment
, excel_biff_text (esheet
->container
.importer
, q
, 6, len
));
3196 d (2, g_printerr ("Comment in %s%d: '%s'\n",
3197 col_name (pos
.col
), pos
.row
+ 1, comment
->str
););
3199 cell_set_comment (sheet
, &pos
, NULL
, comment
->str
, NULL
);
3200 g_string_free (comment
, TRUE
);
3205 excel_sheet_destroy (ExcelReadSheet
*esheet
)
3210 if (esheet
->shared_formulae
!= NULL
) {
3211 g_hash_table_destroy (esheet
->shared_formulae
);
3212 esheet
->shared_formulae
= NULL
;
3214 if (esheet
->tables
!= NULL
) {
3215 g_hash_table_destroy (esheet
->tables
);
3216 esheet
->tables
= NULL
;
3219 /* There appear to be workbooks like guai.xls that have a filter NAME
3220 * defined but no visible combos, so we remove a filter if it has no
3222 if (esheet
->filter
!= NULL
) {
3223 gnm_filter_remove (esheet
->filter
);
3224 gnm_filter_unref (esheet
->filter
);
3225 esheet
->filter
= NULL
;
3228 ms_container_finalize (&esheet
->container
);
3233 static GnmExprTop
const *
3234 ms_wb_parse_expr (MSContainer
*container
, guint8
const *data
, int length
)
3236 ExcelReadSheet dummy_sheet
;
3237 memset (&dummy_sheet
, 0, sizeof (dummy_sheet
));
3238 dummy_sheet
.container
.importer
= (GnmXLImporter
*)container
;
3239 return ms_sheet_parse_expr_internal (&dummy_sheet
, data
, length
);
3243 ms_wb_get_fmt (MSContainer
const *container
, unsigned indx
)
3245 return excel_wb_get_fmt (((GnmXLImporter
*)container
), indx
);
3249 add_attr (PangoAttrList
*attr_list
, PangoAttribute
*attr
)
3251 attr
->start_index
= 0;
3252 attr
->end_index
= 0;
3253 pango_attr_list_insert (attr_list
, attr
);
3256 static PangoAttrList
*
3257 ms_wb_get_font_markup (MSContainer
const *c
, unsigned indx
)
3259 GnmXLImporter
*importer
= (GnmXLImporter
*)c
;
3260 ExcelFont
const *fd
= excel_font_get (importer
, indx
);
3262 if (fd
== NULL
|| indx
== 0)
3263 return empty_attr_list
;
3265 if (fd
->attrs
== NULL
) {
3266 ExcelFont
const *fd0
= excel_font_get (importer
, 0);
3267 PangoAttrList
*attrs
;
3269 attrs
= pango_attr_list_new ();
3270 if (strcmp (fd
->fontname
, fd0
->fontname
) != 0)
3271 add_attr (attrs
, pango_attr_family_new (fd
->fontname
));
3272 if (fd
->height
!= fd0
->height
)
3273 add_attr (attrs
, pango_attr_size_new (fd
->height
* PANGO_SCALE
/ 20));
3274 if (fd
->boldness
!= fd0
->boldness
)
3275 add_attr (attrs
, pango_attr_weight_new (fd
->boldness
));
3276 if (fd
->italic
!= fd0
->italic
)
3277 add_attr (attrs
, pango_attr_style_new (fd
->italic
? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
));
3278 if (fd
->struck_out
!= fd0
->struck_out
)
3279 add_attr (attrs
, pango_attr_strikethrough_new (fd
->struck_out
));
3280 if (fd
->underline
!= fd0
->underline
) {
3281 PangoUnderline underline
= gnm_translate_underline_to_pango
3282 (xls_uline_to_gnm_underline (fd
->underline
));
3283 add_attr (attrs
, pango_attr_underline_new (underline
));
3286 switch (fd
->script
) {
3287 case GO_FONT_SCRIPT_SUB
:
3288 add_attr (attrs
, go_pango_attr_subscript_new (TRUE
));
3291 case GO_FONT_SCRIPT_STANDARD
:
3292 /* Just assume fd0 is standard. */
3294 case GO_FONT_SCRIPT_SUPER
:
3295 add_attr (attrs
, go_pango_attr_superscript_new (TRUE
));
3299 if (fd
->color_idx
!= fd0
->color_idx
) {
3300 GnmColor
*color
= (fd
->color_idx
== 127)
3301 ? style_color_black ()
3302 : excel_palette_get (importer
, fd
->color_idx
);
3303 add_attr (attrs
, go_color_to_pango (color
->go_color
, TRUE
));
3304 style_color_unref (color
);
3307 ((ExcelFont
*)fd
)->attrs
= attrs
;
3314 gnm_xl_get_codepage (char const *enc
)
3316 /* These names must match charset_trans_array in go-charmap-sel.c */
3320 } charset_trans_array
[] = {
3324 {"ISO-8859-6-E", 0},
3325 {"ISO-8859-6-I", 0},
3326 {"x-mac-arabic", 0},
3327 {"windows-1256", 1256},
3331 {"windows-1257", 1257},
3336 {"windows-1250", 1250},
3341 {"windows-936", 936},
3345 {"x-mac-croatian", 0},
3350 {"x-mac-cyrillic", 0},
3351 {"windows-1251", 1251},
3354 {"x-mac-ukrainian", 0},
3355 {"ANSI_X3.4-1968#ASCII", 0},
3360 {"windows-1253", 0},
3361 {"x-mac-gujarati", 0},
3362 {"x-mac-gurmukhi", 0},
3364 {"ISO-8859-8-E", 0},
3365 {"ISO-8859-8-I", 0},
3366 {"x-mac-hebrew", 0},
3367 {"windows-1255", 1255},
3368 {"x-mac-devanagari", 0},
3369 {"x-mac-icelandic", 0},
3376 {"x-windows-949", 0},
3378 {"x-mac-romanian", 0},
3384 {"x-mac-turkish", 0},
3385 {"windows-1254", 1254},
3392 {"x-user-defined", 0},
3393 {"x-viet-tcvn5712", 0},
3396 {"windows-1258", 1258},
3402 {"windows-1252", 1252},
3404 {"x-imap4-modified-utf7", 0},
3412 for (i
= 0; i
< G_N_ELEMENTS(charset_trans_array
); i
++)
3413 if (0 == strcmp (enc
, charset_trans_array
[i
].name
))
3414 return charset_trans_array
[i
].codepage
;
3419 static GnmXLImporter
*
3420 gnm_xl_importer_new (GOIOContext
*context
, WorkbookView
*wb_view
, char const *opt_enc
)
3422 static MSContainerClass
const vtbl
= {
3427 &ms_wb_get_font_markup
3430 GnmXLImporter
*importer
= g_new (GnmXLImporter
, 1);
3432 importer
->ver
= MS_BIFF_V_UNKNOWN
;
3433 importer
->context
= context
;
3434 importer
->wbv
= wb_view
;
3435 importer
->wb
= wb_view_get_workbook (wb_view
);
3436 importer
->str_iconv
= (GIConv
)(-1);
3437 importer
->codepage_override
= gnm_xl_get_codepage (opt_enc
);
3438 gnm_xl_importer_set_codepage (importer
, (importer
->codepage_override
> 0) ?
3439 importer
->codepage_override
: 1252); /* set a default */
3441 importer
->expr_sharer
= gnm_expr_sharer_new ();
3442 importer
->v8
.supbook
= g_array_new (FALSE
, FALSE
, sizeof (ExcelSupBook
));
3443 importer
->v8
.externsheet
= NULL
;
3445 importer
->names
= g_ptr_array_new ();
3446 importer
->num_name_records
= 0;
3448 importer
->boundsheet_sheet_by_index
= g_ptr_array_new ();
3449 importer
->boundsheet_data_by_stream
= g_hash_table_new_full (
3450 g_direct_hash
, g_direct_equal
,
3451 NULL
, (GDestroyNotify
) biff_boundsheet_data_destroy
);
3452 importer
->font_data
= g_hash_table_new_full (
3453 g_direct_hash
, g_direct_equal
,
3454 NULL
, (GDestroyNotify
)excel_font_free
);
3455 importer
->excel_sheets
= g_ptr_array_new ();
3456 importer
->XF_cell_records
= g_ptr_array_new ();
3457 importer
->pivot
.cache_by_index
= g_ptr_array_new ();
3458 importer
->pivot
.slicer
= NULL
;
3459 importer
->pivot
.field_count
= 0;
3460 importer
->pivot
.record_count
= 0;
3461 importer
->format_table
= g_hash_table_new_full (
3462 g_direct_hash
, g_direct_equal
,
3463 NULL
, (GDestroyNotify
)biff_format_data_destroy
);
3464 importer
->palette
= NULL
;
3465 importer
->sst
= NULL
;
3466 importer
->sst_len
= 0;
3468 ms_container_init (&importer
->container
, &vtbl
, NULL
, importer
);
3473 excel_workbook_reset_style (GnmXLImporter
*importer
)
3477 g_hash_table_destroy (importer
->font_data
);
3478 importer
->font_data
= g_hash_table_new_full (
3479 g_direct_hash
, g_direct_equal
,
3480 NULL
, (GDestroyNotify
)excel_font_free
);
3482 for (i
= 0; i
< importer
->XF_cell_records
->len
; i
++)
3483 biff_xf_data_destroy (g_ptr_array_index (importer
->XF_cell_records
, i
));
3484 g_ptr_array_free (importer
->XF_cell_records
, TRUE
);
3485 importer
->XF_cell_records
= g_ptr_array_new ();
3487 g_hash_table_destroy (importer
->format_table
);
3488 importer
->format_table
= g_hash_table_new_full (
3489 g_direct_hash
, g_direct_equal
,
3490 NULL
, (GDestroyNotify
)biff_format_data_destroy
);
3494 gnm_xl_importer_free (GnmXLImporter
*importer
)
3497 GSList
*real_order
= NULL
;
3500 for (i
= importer
->boundsheet_sheet_by_index
->len
; i
-- > 0 ; ) {
3501 sheet
= g_ptr_array_index (importer
->boundsheet_sheet_by_index
, i
);
3503 real_order
= g_slist_prepend (real_order
, sheet
);
3506 if (real_order
!= NULL
) {
3507 workbook_sheet_reorder (importer
->wb
, real_order
);
3508 g_slist_free (real_order
);
3511 gnm_expr_sharer_destroy (importer
->expr_sharer
);
3513 g_hash_table_destroy (importer
->boundsheet_data_by_stream
);
3514 importer
->boundsheet_data_by_stream
= NULL
;
3515 g_ptr_array_free (importer
->boundsheet_sheet_by_index
, TRUE
);
3516 importer
->boundsheet_sheet_by_index
= NULL
;
3518 for (i
= 0; i
< importer
->excel_sheets
->len
; i
++)
3519 excel_sheet_destroy (g_ptr_array_index (importer
->excel_sheets
, i
));
3520 g_ptr_array_free (importer
->excel_sheets
, TRUE
);
3521 importer
->excel_sheets
= NULL
;
3523 if (NULL
!= importer
->pivot
.slicer
) {
3524 g_object_unref (importer
->pivot
.slicer
);
3525 importer
->pivot
.slicer
= NULL
;
3527 for (i
= 0; i
< importer
->pivot
.cache_by_index
->len
; i
++) {
3528 GObject
*cache
= g_ptr_array_index (importer
->pivot
.cache_by_index
, i
);
3530 g_object_unref (cache
);
3532 g_ptr_array_free (importer
->pivot
.cache_by_index
, TRUE
);
3533 importer
->pivot
.cache_by_index
= NULL
;
3535 for (i
= 0; i
< importer
->XF_cell_records
->len
; i
++)
3536 biff_xf_data_destroy (g_ptr_array_index (importer
->XF_cell_records
, i
));
3537 g_ptr_array_free (importer
->XF_cell_records
, TRUE
);
3538 importer
->XF_cell_records
= NULL
;
3540 g_hash_table_destroy (importer
->font_data
);
3541 importer
->font_data
= NULL
;
3543 g_hash_table_destroy (importer
->format_table
);
3544 importer
->format_table
= NULL
;
3546 if (importer
->palette
) {
3547 excel_palette_destroy (importer
->palette
);
3548 importer
->palette
= NULL
;
3551 for (i
= 0; i
< importer
->v8
.supbook
->len
; i
++ ) {
3552 ExcelSupBook
*sup
= &(g_array_index (importer
->v8
.supbook
,
3554 for (j
= 0; j
< sup
->externname
->len
; j
++ ) {
3555 GnmNamedExpr
*nexpr
= g_ptr_array_index (sup
->externname
, j
);
3557 expr_name_unref (nexpr
);
3559 g_ptr_array_free (sup
->externname
, TRUE
);
3561 g_array_free (importer
->v8
.supbook
, TRUE
);
3562 importer
->v8
.supbook
= NULL
;
3563 if (importer
->v8
.externsheet
!= NULL
) {
3564 g_array_free (importer
->v8
.externsheet
, TRUE
);
3565 importer
->v8
.externsheet
= NULL
;
3568 if (importer
->sst
!= NULL
) {
3569 unsigned i
= importer
->sst_len
;
3571 if (importer
->sst
[i
].content
)
3572 go_string_unref (importer
->sst
[i
].content
);
3573 go_format_unref (importer
->sst
[i
].markup
);
3575 g_free (importer
->sst
);
3578 for (i
= importer
->names
->len
; i
-- > 0 ; ) {
3579 GnmNamedExpr
*nexpr
= g_ptr_array_index (importer
->names
, i
);
3583 /* NAME placeholders need removal, EXTERNNAME
3584 * placeholders will no be active */
3585 if (expr_name_is_active (nexpr
) &&
3586 expr_name_is_placeholder (nexpr
) &&
3587 /* FIXME: Why do we need this? */
3588 nexpr
->ref_count
== 2) {
3589 d (1, g_printerr ("Removing name %s\n", expr_name_name (nexpr
)););
3590 expr_name_remove (nexpr
);
3592 expr_name_unref (nexpr
);
3594 g_ptr_array_free (importer
->names
, TRUE
);
3595 importer
->names
= NULL
;
3597 if (importer
->str_iconv
!= (GIConv
)(-1)) {
3598 gsf_iconv_close (importer
->str_iconv
);
3599 importer
->str_iconv
= (GIConv
)(-1);
3602 ms_container_finalize (&importer
->container
);
3607 * Unpacks a MS Excel RK structure,
3610 biff_get_rk (guint8
const *ptr
)
3614 eIEEE
= 0, eIEEEx100
= 1, eInt
= 2, eIntx100
= 3
3617 number
= GSF_LE_GET_GUINT32 (ptr
);
3618 type
= (number
& 0x3);
3627 /* Think carefully about big/little endian issues before
3628 changing this code. */
3629 for (lp
= 0; lp
< 4; lp
++) {
3630 tmp
[lp
+ 4]= (lp
> 0) ? ptr
[lp
]: (ptr
[lp
] & 0xfc);
3634 answer
= (gnm_float
)gsf_le_get_double (tmp
);
3635 return value_new_float (type
== eIEEEx100
? answer
/ 100 : answer
);
3638 return value_new_int (number
>> 2);
3641 if ((number
% 100) == 0)
3642 return value_new_int (number
/ 100);
3644 return value_new_float ((gnm_float
)number
/ 100);
3650 excel_builtin_name (guint8
const *ptr
)
3653 case 0x00: return "Consolidate_Area";
3654 case 0x01: return "Auto_Open";
3655 case 0x02: return "Auto_Close";
3656 case 0x03: return "Extract";
3657 case 0x04: return "Database";
3658 case 0x05: return "Criteria";
3659 case 0x06: return "Print_Area";
3660 case 0x07: return "Print_Titles";
3661 case 0x08: return "Recorder";
3662 case 0x09: return "Data_Form";
3663 case 0x0A: return "Auto_Activate";
3664 case 0x0B: return "Auto_Deactivate";
3665 case 0x0C: return "Sheet_Title";
3666 case 0x0D: return "_FilterDatabase";
3669 g_warning ("Unknown builtin named expression %d", (int)*ptr
);
3674 static GnmNamedExpr
*
3675 excel_parse_name (GnmXLImporter
*importer
, Sheet
*sheet
, char *name
,
3676 guint8
const *expr_data
, unsigned expr_len
,
3677 unsigned array_data_len
,
3678 gboolean link_to_container
,
3682 GnmNamedExpr
*nexpr
;
3683 GnmExprTop
const *texpr
= NULL
;
3686 g_return_val_if_fail (name
!= NULL
, NULL
);
3688 parse_pos_init (&pp
, importer
->wb
, sheet
, 0, 0);
3690 if (expr_len
== 0) {
3691 /* This seems to indicate a placeholder for an unknown name */
3692 texpr
= gnm_expr_top_new_constant (value_new_error_NAME (NULL
));
3694 texpr
= excel_parse_formula (&importer
->container
, NULL
, 0, 0,
3695 expr_data
, expr_len
,
3699 if (texpr
== NULL
) {
3700 go_io_warning (importer
->context
, _("Failure parsing name '%s'"), name
);
3701 texpr
= gnm_expr_top_new_constant (value_new_error_REF (NULL
));
3703 char *tmp
= gnm_expr_top_as_string
3704 (texpr
, &pp
, gnm_conventions_default
);
3705 g_printerr ("Expression: %s\n", tmp
);
3710 if (0 == strcmp (name
, "Print_Area")) {
3711 GnmValue
*val
= gnm_expr_get_range (texpr
->expr
);
3712 if (val
!= NULL
&& VALUE_IS_CELLRANGE (val
)) {
3715 if (sheet
== NULL
) {
3716 Sheet
*start_sheet
, *end_sheet
;
3719 /* Turn a global Print_Area name into a local
3720 name for the sheet it specifies. This
3721 triggers on the file from 632050. */
3722 gnm_rangeref_normalize_pp (value_get_rangeref (val
),
3727 if (start_sheet
&& end_sheet
== start_sheet
) {
3728 sheet
= start_sheet
;
3730 gnm_expr_top_unref (texpr
);
3731 texpr
= gnm_expr_top_new_constant (value_new_cellrange_r (NULL
, &dest
));
3738 range_init_rangeref (&r
, value_get_rangeref (val
));
3739 height
= range_height (&r
);
3740 width
= range_width (&r
);
3741 if (height
== gnm_sheet_get_max_rows (sheet
) &&
3742 width
== gnm_sheet_get_max_cols (sheet
)) {
3743 gnm_expr_top_unref (texpr
);
3748 value_release (val
);
3750 /* Completely ignore Print_Area settings of #REF! */
3751 if (texpr
== NULL
|| gnm_expr_top_is_err (texpr
, GNM_ERROR_REF
)) {
3752 if (texpr
) gnm_expr_top_unref (texpr
);
3757 nexpr
= expr_name_add (&pp
, name
,
3759 &err
, link_to_container
, stub
);
3760 if (nexpr
== NULL
) {
3761 go_io_warning (importer
->context
, "%s", err
);
3770 excel_read_name_str (GnmXLImporter
*importer
,
3771 guint8
const *data
, unsigned datalen
, unsigned *name_len
, gboolean is_builtin
)
3773 gboolean use_utf16
, has_extended
;
3774 unsigned trailing_data_len
, n_markup
;
3777 /* Lovely, they put suffixes on builtins. Then those !#$^
3778 * dipsticks put the unicode header _before_ the builtin id
3779 * and stored the id as a character (possibly two byte).
3780 * NOTE : len is in _characters_ (not bytes) does not include
3782 if (is_builtin
&& *name_len
) {
3783 guint8
const *str
= data
;
3784 char const *builtin
;
3787 if (importer
->ver
< MS_BIFF_V8
) {
3788 use_utf16
= has_extended
= FALSE
;
3789 n_markup
= trailing_data_len
= 0;
3791 int hlen
= excel_read_string_header
3793 &use_utf16
, &n_markup
, &has_extended
,
3794 &trailing_data_len
);
3799 clen
= use_utf16
? 2 : 1;
3801 /* pull out the magic builtin enum */
3802 if (datalen
>= clen
) {
3803 builtin
= excel_builtin_name (str
);
3809 if (--(*name_len
)) {
3812 *name_len
= MIN (*name_len
, datalen
/ clen
);
3813 tmp
= excel_get_chars (importer
, str
, *name_len
, use_utf16
, NULL
);
3814 name
= g_strconcat (builtin
, tmp
, NULL
);
3816 *name_len
= clen
* (*name_len
);
3818 name
= g_strdup (builtin
);
3820 *name_len
+= str
- data
;
3821 } else /* converts char len to byte len, and handles header */
3822 name
= excel_get_text (importer
, data
, *name_len
, name_len
, NULL
, datalen
);
3827 excel_read_EXTERNNAME (BiffQuery
*q
, MSContainer
*container
)
3829 MsBiffVersion
const ver
= container
->importer
->ver
;
3830 GnmNamedExpr
*nexpr
= NULL
;
3832 unsigned array_data_len
= 0; /* Is this always true? */
3835 g_printerr ("EXTERNNAME\n");
3836 gsf_mem_dump (q
->data
, q
->length
); });
3838 /* use biff version to differentiate, not the record version because
3839 * the version is the same for very old and new, with _v2 used for
3840 * some intermediate variants */
3841 if (ver
>= MS_BIFF_V7
) {
3842 unsigned expr_len
= 0;
3843 guint8
const *expr_data
= NULL
;
3847 XL_CHECK_CONDITION (q
->length
>= 7);
3849 flags
= GSF_LE_GET_GUINT8 (q
->data
);
3850 namelen
= GSF_LE_GET_GUINT8 (q
->data
+ 6);
3852 name
= excel_read_name_str (container
->importer
, q
->data
+ 7, q
->length
- 7, &namelen
, flags
&1);
3853 if ((flags
& (~1)) == 0) { /* all flags but builtin must be 0 */
3854 if (7 + 2 + namelen
<= q
->length
) {
3855 unsigned el
= GSF_LE_GET_GUINT16 (q
->data
+ 7 + namelen
);
3856 if (7 + 2 + namelen
+ el
<= q
->length
) {
3858 expr_data
= q
->data
+ 9 + namelen
;
3860 go_io_warning (container
->importer
->context
,
3861 _("Incorrect expression for name '%s': content will be lost.\n"),
3864 } else if ((flags
& 0x10) == 0) /* DDE */
3865 go_io_warning (container
->importer
->context
,
3866 _("DDE links are not supported yet.\nName '%s' will be lost.\n"),
3867 name
? name
: "NULL");
3869 go_io_warning (container
->importer
->context
,
3870 _("OLE links are not supported yet.\nName '%s' will be lost.\n"),
3871 name
? name
: "NULL");
3873 nexpr
= excel_parse_name (container
->importer
, NULL
,
3874 name
, expr_data
, expr_len
,
3875 array_data_len
, FALSE
, NULL
);
3876 } else if (ver
>= MS_BIFF_V5
) {
3877 XL_CHECK_CONDITION (q
->length
>= 7);
3879 name
= excel_biff_text_1 (container
->importer
, q
, 6);
3880 nexpr
= excel_parse_name (container
->importer
, NULL
,
3881 name
, NULL
, 0, array_data_len
,
3884 XL_CHECK_CONDITION (q
->length
>= 3);
3886 name
= excel_biff_text_1 (container
->importer
, q
, 2);
3887 nexpr
= excel_parse_name (container
->importer
, NULL
,
3888 name
, NULL
, 0, array_data_len
,
3892 /* nexpr is potentially NULL if there was an error */
3893 if (ver
>= MS_BIFF_V8
) {
3894 GnmXLImporter
*importer
= container
->importer
;
3895 ExcelSupBook
const *sup
;
3897 g_return_if_fail (importer
->v8
.supbook
->len
> 0);
3899 /* The name is associated with the last SUPBOOK records seen */
3900 sup
= &(g_array_index (importer
->v8
.supbook
, ExcelSupBook
,
3901 importer
->v8
.supbook
->len
-1));
3902 g_ptr_array_add (sup
->externname
, nexpr
);
3904 GPtrArray
*externnames
= container
->v7
.externnames
;
3905 if (externnames
== NULL
)
3906 externnames
= container
->v7
.externnames
= g_ptr_array_new ();
3907 g_ptr_array_add (externnames
, nexpr
);
3912 /* Do some error checking to handle the magic name associated with an
3913 * autofilter in a sheet. Do not make it an error.
3914 * We have lots of examples of things that are not autofilters.
3917 excel_prepare_autofilter (GnmXLImporter
*importer
, GnmNamedExpr
*nexpr
)
3919 if (nexpr
->pos
.sheet
!= NULL
) {
3920 GnmValue
*v
= gnm_expr_top_get_range (nexpr
->texpr
);
3923 gboolean valid
= gnm_sheet_range_from_value (&r
, v
);
3929 ExcelReadSheet
*esheet
;
3931 filter
= gnm_filter_new (r
.sheet
, &r
.range
);
3932 expr_name_remove (nexpr
);
3934 for (i
= 0 ; i
< importer
->excel_sheets
->len
; i
++) {
3935 esheet
= g_ptr_array_index (importer
->excel_sheets
, i
);
3936 if (esheet
->sheet
== r
.sheet
) {
3937 g_return_if_fail (esheet
->filter
== NULL
);
3938 esheet
->filter
= filter
;
3948 excel_read_NAME (BiffQuery
*q
, GnmXLImporter
*importer
, ExcelReadSheet
*esheet
)
3950 MsBiffVersion
const ver
= importer
->ver
;
3951 GnmNamedExpr
*nexpr
= NULL
;
3952 guint16 expr_len
, sheet_index
, flags
= 0;
3954 gboolean builtin_name
= FALSE
;
3956 /* length in characters (not bytes) in the same pos for all versions */
3958 /* guint8 kb_shortcut = GSF_LE_GET_GUINT8 (q->data + 2); */
3959 /* int fn_grp_idx = (flags & 0xfc0)>>6; */
3961 XL_CHECK_CONDITION (q
->length
>= 4);
3963 name_len
= GSF_LE_GET_GUINT8 (q
->data
+ 3);
3966 g_printerr ("NAME\n");
3967 gsf_mem_dump (q
->data
, q
->length
); });
3969 if (ver
>= MS_BIFF_V2
) {
3970 flags
= GSF_LE_GET_GUINT16 (q
->data
);
3971 builtin_name
= (flags
& 0x0020) != 0;
3974 /* use biff version to differentiate, not the record version because
3975 * the version is the same for very old and new, with _v2 used for
3976 * some intermediate variants */
3977 if (ver
>= MS_BIFF_V8
) {
3978 XL_CHECK_CONDITION (q
->length
>= 14);
3979 expr_len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3980 sheet_index
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
3981 data
= q
->data
+ 14;
3982 } else if (ver
>= MS_BIFF_V7
) {
3983 XL_CHECK_CONDITION (q
->length
>= 14);
3984 expr_len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3985 /* opencalc docs claim 8 is the right one, XL docs say 6 == 8
3986 * pivot.xls suggests that at least for local builtin names 6
3987 * is correct and 8 is bogus for == biff7 */
3988 sheet_index
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
3989 data
= q
->data
+ 14;
3990 } else if (ver
>= MS_BIFF_V3
) {
3991 XL_CHECK_CONDITION (q
->length
>= 6);
3992 expr_len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
3994 sheet_index
= 0; /* no sheets */
3996 XL_CHECK_CONDITION (q
->length
>= 5);
3997 expr_len
= GSF_LE_GET_GUINT8 (q
->data
+ 4);
3999 sheet_index
= 0; /* no sheets */
4002 XL_NEED_BYTES (name_len
);
4003 name
= excel_read_name_str (importer
, data
, q
->length
- (data
- q
->data
), &name_len
, builtin_name
);
4004 XL_NEED_BYTES (name_len
);
4008 unsigned array_data_len
;
4009 Sheet
*sheet
= NULL
;
4010 d (1, g_printerr ("NAME=%s, sheet_index=%d flags=0x%x\n",
4011 name
, sheet_index
, flags
););
4012 if (sheet_index
> 0) {
4013 /* NOTE : the docs lie the index for biff7 is
4014 * indeed a reference to the externsheet
4015 * however we have examples in biff8 that can
4016 * only to be explained by a 1 based index to
4017 * the boundsheets. Which is not unreasonable
4018 * given that these are local names */
4019 if (importer
->ver
>= MS_BIFF_V8
) {
4020 if (sheet_index
<= importer
->boundsheet_sheet_by_index
->len
&&
4022 sheet
= g_ptr_array_index (importer
->boundsheet_sheet_by_index
, sheet_index
-1);
4024 g_warning ("So much for that theory 2");
4026 sheet
= excel_externsheet_v7 (&importer
->container
, sheet_index
);
4029 if (sheet
== XL_EXTERNSHEET_MAGIC_SELFREF
)
4030 sheet
= esheet
? esheet
->sheet
: NULL
;
4031 else if (sheet
== XL_EXTERNSHEET_MAGIC_DELETED
)
4034 /* do we have a stub from a forward decl ? */
4035 if (importer
->num_name_records
< importer
->names
->len
)
4036 nexpr
= g_ptr_array_index (importer
->names
, importer
->num_name_records
);
4038 XL_NEED_BYTES (expr_len
);
4039 array_data_len
= expr_len
? q
->length
- (data
- q
->data
) - expr_len
: 0;
4040 nexpr
= excel_parse_name (importer
, sheet
,
4041 name
, data
, expr_len
,
4042 array_data_len
, TRUE
, nexpr
);
4046 /* Add a ref to keep it around after the excel-sheet/wb goes
4047 * away. externnames do not get references and are unrefed
4048 * after import finishes, which destroys them if they are not
4050 if (nexpr
!= NULL
) {
4051 expr_name_ref (nexpr
);
4052 nexpr
->is_hidden
= (flags
& 0x0001) ? TRUE
: FALSE
;
4054 /* Undocumented magic.
4055 * XL stores a hidden name with the details of an autofilter */
4056 if (nexpr
->is_hidden
&& !strcmp (expr_name_name (nexpr
), "_FilterDatabase"))
4057 excel_prepare_autofilter (importer
, nexpr
);
4058 /* g_warning ("flags = %hx, state = %s\n", flags, global ? "global" : "sheet"); */
4060 else if ((flags
& 0xE) == 0xE) /* Function & VB-Proc & Proc */
4061 gnm_func_add_placeholder (importer
->wb
,
4062 expr_name_name (nexpr
), "VBA");
4066 /* nexpr is potentially NULL if there was an error */
4067 if (importer
->num_name_records
< importer
->names
->len
)
4068 g_ptr_array_index (importer
->names
, importer
->num_name_records
) = nexpr
;
4069 else if (importer
->num_name_records
== importer
->names
->len
)
4070 g_ptr_array_add (importer
->names
, nexpr
);
4071 importer
->num_name_records
++;
4074 guint8 menu_txt_len
= GSF_LE_GET_GUINT8 (q
->data
+ 10);
4075 guint8 descr_txt_len
= GSF_LE_GET_GUINT8 (q
->data
+ 11);
4076 guint8 help_txt_len
= GSF_LE_GET_GUINT8 (q
->data
+ 12);
4077 guint8 status_txt_len
= GSF_LE_GET_GUINT8 (q
->data
+ 13);
4078 const guint8
*end
= q
->data
+ q
->length
;
4084 menu_txt
= excel_get_text (importer
, data
, menu_txt_len
, NULL
, NULL
, end
- data
);
4085 data
+= menu_txt_len
;
4086 descr_txt
= excel_get_text (importer
, data
, descr_txt_len
, NULL
, NULL
, end
- data
);
4087 data
+= descr_txt_len
;
4088 help_txt
= excel_get_text (importer
, data
, help_txt_len
, NULL
, NULL
, end
- data
);
4089 data
+= help_txt_len
;
4090 status_txt
= excel_get_text (importer
, data
, status_txt_len
, NULL
, NULL
, end
- data
);
4092 g_printerr ("Name record: '%s', '%s', '%s', '%s', '%s'\n",
4093 nexpr
? expr_name_name (nexpr
) : "(null)",
4094 menu_txt
? menu_txt
: "(null)",
4095 descr_txt
? descr_txt
: "(null)",
4096 help_txt
? help_txt
: "(null)",
4097 status_txt
? status_txt
: "(null)");
4099 if ((flags
& 0x0001) != 0) g_printerr (" Hidden");
4100 if ((flags
& 0x0002) != 0) g_printerr (" Function");
4101 if ((flags
& 0x0004) != 0) g_printerr (" VB-Proc");
4102 if ((flags
& 0x0008) != 0) g_printerr (" Proc");
4103 if ((flags
& 0x0010) != 0) g_printerr (" CalcExp");
4104 if ((flags
& 0x0020) != 0) g_printerr (" BuiltIn");
4105 if ((flags
& 0x1000) != 0) g_printerr (" BinData");
4111 g_free (status_txt
);
4116 excel_read_XCT (BiffQuery
*q
, GnmXLImporter
*importer
)
4118 guint16 last_col
, opcode
;
4122 Sheet
*sheet
= NULL
;
4127 if (importer
->ver
>= MS_BIFF_V8
) {
4130 XL_CHECK_CONDITION (q
->length
== 4);
4132 count
= GSF_LE_GET_GINT16 (q
->data
);
4133 supbook
= GSF_LE_GET_GUINT16 (q
->data
+2);
4135 XL_CHECK_CONDITION (q
->length
== 2);
4137 count
= GSF_LE_GET_GINT16 (q
->data
);
4140 if (count
< 0) /* WHAT THE HECK DOES NEGATIVE MEAN ?? */
4144 eval_pos_init_sheet (&ep
, sheet
);
4146 while (count
-- > 0) {
4147 if (!ms_biff_query_peek_next (q
, &opcode
)) {
4148 g_warning ("Expected a CRN record");
4150 } else if (opcode
!= BIFF_CRN
) {
4151 g_warning ("Expected a CRN record not a %hx", opcode
);
4154 ms_biff_query_next (q
);
4156 XL_CHECK_CONDITION (q
->length
>= 4);
4158 ep
.eval
.col
= GSF_LE_GET_GUINT8 (q
->data
+0);
4159 last_col
= GSF_LE_GET_GUINT8 (q
->data
+1);
4160 ep
.eval
.row
= GSF_LE_GET_GUINT16 (q
->data
+2);
4162 /* ignore content for sheets that are already loaded */
4166 for (data
= q
->data
+ 4; ep
.eval
.col
<= last_col
; ep
.eval
.col
++) {
4174 v
= value_new_float (GSF_LE_GET_DOUBLE (data
));
4180 v
= value_new_string_nocopy (
4181 excel_get_text (importer
, data
, len
, NULL
, NULL
, q
->data
+ q
->length
- data
));
4187 v
= value_new_bool (GSF_LE_GET_GUINT16 (data
) != 0);
4194 v
= xls_value_new_err (&ep
, GSF_LE_GET_GUINT16 (data
));
4200 g_warning ("Unknown oper type 0x%x in a CRN record", oper
);
4205 cell
= sheet_cell_fetch (sheet
, ep
.eval
.col
, ep
.eval
.row
);
4207 gnm_cell_set_value (cell
, v
);
4215 static XL_font_width
const *
4216 xl_find_fontspec (ExcelReadSheet
*esheet
, double *size20
)
4218 /* Use the 'Normal' Style which is by definition the 0th */
4219 BiffXFData
const *xf
= excel_get_xf (esheet
, 0);
4220 ExcelFont
const *fd
= (xf
!= NULL
)
4221 ? excel_font_get (esheet
->container
.importer
, xf
->font_idx
)
4223 *size20
= (fd
!= NULL
) ? (fd
->height
/ (20. * 10.)) : 1.;
4224 return xl_lookup_font_specs ((fd
!= NULL
) ? fd
->fontname
: "Arial");
4228 * get_row_height_units:
4229 * @height height in Excel units
4231 * Converts row height from Excel units to points. Returns height in points.
4233 * Excel specifies row height in 1/20 of a point.
4235 * What we now print out is just 0.5% shorter than theoretical
4236 * height. The height of what Excel prints out varies in mysterious
4237 * ways. Sometimes it is close to theoretical, sometimes it is a few %
4238 * shorter. I don't see any point in correcting for the 0.5% until we
4239 * know the whole story.
4242 get_row_height_units (guint16 height
)
4244 return 1. / 20. * height
;
4248 excel_read_ROW (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4250 guint16 row
, height
;
4254 gboolean is_std_height
;
4256 XL_CHECK_CONDITION (q
->length
>= (q
->opcode
== BIFF_ROW_v2
? 16 : 8));
4258 row
= GSF_LE_GET_GUINT16 (q
->data
);
4260 /* Unnecessary info for now.
4261 * do we want to preallocate based on this info?
4263 guint16
const start_col
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4264 guint16
const end_col
= GSF_LE_GET_GUINT16 (q
->data
+ 4) - 1;
4266 height
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
4268 /* If the bit is on it indicates that the row is of 'standard' height.
4269 * However the remaining bits still include the size.
4271 is_std_height
= (height
& 0x8000) != 0;
4273 if (q
->opcode
== BIFF_ROW_v2
) {
4274 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
4275 flags2
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
4277 xf
= flags2
& 0xfff;
4280 g_printerr ("Row %d height 0x%x, flags=0x%x 0x%x;\n", row
+ 1, height
, flags
, flags2
);
4282 g_printerr ("%s\n", "Is Std Height;\n");
4283 if (flags2
& 0x1000)
4284 g_printerr ("%s\n", "Top thick;\n");
4285 if (flags2
& 0x2000)
4286 g_printerr ("%s\n", "Bottom thick;\n");
4289 /* TODO: Put mechanism in place to handle thick margins */
4290 /* TODO: Columns actually set the size even when it is the default.
4291 * Which approach is better?
4293 if (!is_std_height
) {
4294 double hu
= get_row_height_units (height
);
4295 sheet_row_set_size_pts (esheet
->sheet
, row
, hu
,
4296 (flags
& 0x40) ? TRUE
: FALSE
);
4300 colrow_set_visibility (esheet
->sheet
, FALSE
, FALSE
, row
, row
);
4304 excel_set_xf_segment (esheet
,
4305 0, gnm_sheet_get_max_cols (esheet
->sheet
) - 1,
4307 d (1, g_printerr ("row %d has flags 0x%x a default style %hd;\n",
4308 row
+ 1, flags
, xf
););
4311 if ((unsigned)(flags
& 0x17) > 0)
4312 col_row_info_set_outline (sheet_row_fetch (esheet
->sheet
, row
),
4313 (unsigned)(flags
& 0x7), flags
& 0x10);
4317 excel_read_TAB_COLOR (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4319 /* this is a guess, but the only field I see
4320 * changing seems to be the colour.
4323 0 | 62 8 0 0 0 0 0 0 0 0 0 0 14 0 0 0 | b
...............
4324 10 | 0 0 0 XX XX XX XX XX XX XX XX XX XX XX XX
| ...************
4326 office
12 seems to add
8 bytes
4330 GnmColor
*text_color
;
4333 XL_CHECK_CONDITION (q
->length
>= 20);
4335 /* be conservative for now, we have not seen a palette larger than 56
4336 * so this is largely moot, this is probably a uint32
4338 color_index
= GSF_LE_GET_GUINT8 (q
->data
+ 16);
4339 color
= excel_palette_get (esheet
->container
.importer
, color_index
);
4340 contrast
= GO_COLOR_UINT_R (color
->go_color
) +
4341 GO_COLOR_UINT_G (color
->go_color
) +
4342 GO_COLOR_UINT_B (color
->go_color
);
4343 if (contrast
>= 0x180)
4344 text_color
= style_color_black ();
4346 text_color
= style_color_white ();
4347 g_object_set (esheet
->sheet
,
4348 "tab-foreground", text_color
,
4349 "tab-background", color
,
4351 d (1, g_printerr ("%s tab colour = %08x\n",
4352 esheet
->sheet
->name_unquoted
,
4355 style_color_unref (text_color
);
4356 style_color_unref (color
);
4360 excel_read_COLINFO (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4363 double scale
, width
;
4364 guint16 firstcol
, lastcol
;
4366 guint16 xf
, options
;
4367 gboolean hidden
, customWidth
, bestFit
, collapsed
;
4368 unsigned outline_level
;
4369 XL_font_width
const *spec
;
4371 XL_CHECK_CONDITION (q
->length
>= 10);
4373 firstcol
= GSF_LE_GET_GUINT16 (q
->data
);
4374 lastcol
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4375 charwidths
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
4376 xf
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
4377 options
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
4378 hidden
= (options
& 0x0001) != 0;
4379 customWidth
= (options
& 0x0002) != 0; /* undocumented */
4380 bestFit
= (options
& 0x0004) != 0; /* undocumented */
4381 collapsed
= (options
& 0x1000) != 0;
4382 outline_level
= (unsigned)((options
>> 8) & 0x7);
4383 spec
= xl_find_fontspec (esheet
, &scale
);
4385 XL_CHECK_CONDITION (firstcol
< gnm_sheet_get_max_cols (esheet
->sheet
));
4386 g_return_if_fail (spec
!= NULL
);
4388 /* Widths appear to be quoted including margins and the leading
4389 * gridline that gnumeric expects. The charwidths here are not
4390 * strictly linear. So I measured in increments of -2 -1 0 1 2 around
4391 * the default width when using each font @ 10pts as
4392 * the Normal Style. The pixel calculation is then reduced to
4394 * (default_size + ((quoted_width - baseline) / step))
4395 * * scale : fonts != 10pts
4396 * * 72/96 : value in pts so that zoom is not a factor
4398 * NOTE: These measurements do NOT correspond to what is shown to the
4400 width
= 8. * spec
->defcol_unit
+
4401 (double)(charwidths
- spec
->colinfo_baseline
) / spec
->colinfo_step
;
4402 width
*= scale
* 72./96.;
4404 if (width
<= 0) { /* Columns are of default width */
4405 width
= esheet
->sheet
->cols
.default_style
.size_pts
;
4407 } else if (width
< 4) /* gnumeric can not draw without a margin */
4411 g_printerr ("Column Formatting %s!%s of width "
4412 "%u/256 characters (%f pts)\n",
4413 esheet
->sheet
->name_quoted
,
4414 cols_name (firstcol
, lastcol
), charwidths
, width
);
4415 g_printerr ("Options 0x%hx, default style %hu\n", options
, xf
);
4418 /* NOTE: seems like this is inclusive firstcol, inclusive lastcol */
4419 if (lastcol
>= gnm_sheet_get_max_cols (esheet
->sheet
))
4420 lastcol
= gnm_sheet_get_max_cols (esheet
->sheet
) - 1;
4421 for (i
= firstcol
; i
<= lastcol
; i
++) {
4422 sheet_col_set_size_pts (esheet
->sheet
, i
, width
,
4423 customWidth
&& !bestFit
);
4424 if (outline_level
> 0 || collapsed
)
4425 col_row_info_set_outline (sheet_col_fetch (esheet
->sheet
, i
),
4426 outline_level
, collapsed
);
4430 excel_set_xf_segment (esheet
, firstcol
, lastcol
,
4431 0, gnm_sheet_get_max_rows (esheet
->sheet
) - 1, xf
);
4434 colrow_set_visibility (esheet
->sheet
, TRUE
, FALSE
,
4438 /* Add a bmp header so that gdk-pixbuf can do the work */
4440 excel_read_os2bmp (BiffQuery
*q
, guint32 image_len
)
4443 GdkPixbufLoader
*loader
= NULL
;
4444 GdkPixbuf
*pixbuf
= NULL
;
4445 gboolean ret
= FALSE
;
4446 guint8 bmphdr
[BMP_HDR_SIZE
];
4448 XL_CHECK_CONDITION_VAL (q
->length
>= 8 && image_len
< q
->length
- 8, NULL
);
4450 loader
= gdk_pixbuf_loader_new_with_type ("bmp", &err
);
4453 excel_fill_bmp_header(bmphdr
, q
->data
, image_len
);
4454 ret
= gdk_pixbuf_loader_write (loader
, bmphdr
, sizeof bmphdr
, &err
);
4456 ret
= gdk_pixbuf_loader_write (loader
, q
->data
+8,
4458 gdk_pixbuf_loader_close (loader
, ret
? &err
: NULL
);
4460 pixbuf
= gdk_pixbuf_loader_get_pixbuf (loader
);
4461 g_object_ref (pixbuf
);
4463 g_message ("Unable to read OS/2 BMP image: %s\n",
4467 g_object_unref (loader
);
4471 /* When IMDATA or BG_PIC is bitmap, the format is OS/2 BMP, but the
4472 * 14 bytes header is missing.
4475 excel_read_IMDATA (BiffQuery
*q
, gboolean keep_image
)
4478 GdkPixbuf
*pixbuf
= NULL
;
4481 XL_CHECK_CONDITION_VAL (q
->length
>= 8, NULL
);
4483 format
= GSF_LE_GET_GUINT16 (q
->data
);
4484 image_len
= GSF_LE_GET_GUINT32 (q
->data
+ 4);
4487 case 0x2: break; /* Windows metafile/Mac pict */
4488 case 0x9: /* OS/2 BMP sans header */
4490 pixbuf
= excel_read_os2bmp (q
, image_len
);
4493 case 0xe: break; /* Native format */
4494 default: break; /* Unknown format */
4497 /* Dump formats which weren't handled above to file */
4498 if (format
!= 0x9) {
4499 char const *from_name
;
4500 char const *format_name
;
4501 guint16
const format
= GSF_LE_GET_GUINT16 (q
->data
);
4502 guint16
const from_env
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4505 case 1: from_name
= "Windows"; break;
4506 case 2: from_name
= "Macintosh"; break;
4507 default: from_name
= "Unknown environment?"; break;
4511 format_name
= (from_env
== 1) ? "windows metafile" : "mac pict";
4514 case 0xe: format_name
= "'native format'"; break;
4515 default: format_name
= "Unknown format?"; break;
4520 static int count
= 0;
4521 char *file_name
= g_strdup_printf ("imdata%d", count
++);
4522 g_printerr ("Picture from %s in %s format\n",
4523 from_name
, format_name
);
4525 f
= g_fopen (file_name
, "w");
4526 fwrite (q
->data
+8, 1, q
->length
-8, f
);
4536 excel_read_SELECTION (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4538 GnmCellPos edit_pos
;
4539 unsigned pane_number
, i
, j
, num_refs
;
4540 SheetView
*sv
= sheet_get_view (esheet
->sheet
, esheet
->container
.importer
->wbv
);
4543 XL_CHECK_CONDITION (q
->length
>= 9);
4544 pane_number
= GSF_LE_GET_GUINT8 (q
->data
);
4545 edit_pos
.row
= GSF_LE_GET_GUINT16 (q
->data
+ 1);
4546 edit_pos
.col
= GSF_LE_GET_GUINT16 (q
->data
+ 3);
4547 j
= GSF_LE_GET_GUINT16 (q
->data
+ 5);
4548 num_refs
= GSF_LE_GET_GUINT16 (q
->data
+ 7);
4549 XL_CHECK_CONDITION (q
->length
>= 9 + 6 * num_refs
);
4551 if (pane_number
!= esheet
->active_pane
)
4554 /* FIXME: docs say that consequtive records with the same pane
4555 number should be treated as one. No file with this has been
4558 d (5, g_printerr ("Start selection in pane #%d\n", pane_number
););
4559 d (5, g_printerr ("Cursor: %s in Ref #%d\n", cellpos_as_string (&edit_pos
),
4562 g_return_if_fail (sv
!= NULL
);
4564 sv_selection_reset (sv
);
4565 for (i
= 0; i
<= num_refs
; i
++) {
4567 unsigned i0
= (i
== num_refs
) ? j
: i
;
4569 /* Skip the active; then read it last. */
4570 if (i
== j
|| i0
>= num_refs
)
4573 xls_read_range8 (&r
, q
->data
+ 9 + 6 * i0
);
4575 d (5, g_printerr ("Ref %d = %s\n", i
, range_as_string (&r
)););
4577 tmp
= (i
== num_refs
) ? edit_pos
: r
.start
;
4578 sv_selection_add_full (sv
,
4580 r
.start
.col
, r
.start
.row
,
4581 r
.end
.col
, r
.end
.row
,
4582 GNM_SELECTION_MODE_ADD
);
4585 if (sv
->selections
== NULL
) {
4586 /* See bug 632050 */
4587 sv_selection_add_pos (sv
, 0, 0,
4588 GNM_SELECTION_MODE_ADD
);
4589 d (5, g_printerr ("No selection\n"););
4592 d (5, g_printerr ("Done selection\n"););
4596 excel_read_DEF_ROW_HEIGHT (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4599 guint16 height
= 0; /* must be 16 bit */
4600 double height_units
;
4602 if (q
->opcode
!= BIFF_DEFAULTROWHEIGHT_v0
) {
4603 XL_CHECK_CONDITION (q
->length
>= 4);
4604 flags
= GSF_LE_GET_GUINT16 (q
->data
);
4605 height
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4607 XL_CHECK_CONDITION (q
->length
>= 2);
4608 height
= GSF_LE_GET_GUINT16 (q
->data
);
4609 height
&= 0x7fff; /* there seems to be a flag in the top bit */
4612 height_units
= get_row_height_units (height
);
4614 g_printerr ("Default row height %3.3g;\n", height_units
);
4616 g_printerr (" + extra space above;\n");
4618 g_printerr (" + extra space below;\n");
4621 sheet_row_set_default_size_pts (esheet
->sheet
, height_units
);
4625 excel_read_DEF_COL_WIDTH (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4629 XL_font_width
const *spec
= xl_find_fontspec (esheet
, &scale
);
4631 XL_CHECK_CONDITION (q
->length
>= 2);
4632 charwidths
= GSF_LE_GET_GUINT16 (q
->data
);
4633 d (0, g_printerr ("Default column width %hu characters\n", charwidths
););
4635 /* According to the tooltip the default width is 8.43 character widths
4636 * and 64 pixels wide (Arial 10) which appears to include margins, and
4637 * the leading gridline That is saved as 8 char widths for
4638 * DEL_COL_WIDTH and 9.14 widths for COLINFO */
4639 sheet_col_set_default_size_pts (esheet
->sheet
,
4640 charwidths
* spec
->defcol_unit
* scale
* 72./96.);
4643 /* we could get this implicitly from the cols/rows
4644 * but this is faster
4647 excel_read_GUTS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4649 int col_gut
, row_gut
;
4651 XL_CHECK_CONDITION (q
->length
== 8);
4653 /* ignore the specification of how wide/tall the gutters are */
4654 row_gut
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
4655 d (2, g_printerr ("row_gut = %d", row_gut
););
4658 col_gut
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
4659 d (2, g_printerr ("col_gut = %d\n", col_gut
););
4662 sheet_colrow_gutter (esheet
->sheet
, TRUE
, col_gut
);
4663 sheet_colrow_gutter (esheet
->sheet
, FALSE
, row_gut
);
4667 excel_read_SETUP (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4669 GnmPrintInformation
*pi
= esheet
->sheet
->print_info
;
4671 gboolean rotate_paper
= FALSE
;
4672 gboolean portrait_orientation
= TRUE
;
4674 XL_CHECK_CONDITION (q
->length
>= 12);
4676 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
4677 pi
->print_across_then_down
= (flags
& 0x1) != 0;
4678 pi
->print_black_and_white
= (flags
& 0x8) != 0;
4680 if (0 == (flags
& 0x4)) {
4681 guint16 papersize
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
4682 const char *paper_name
=
4683 xls_paper_name (papersize
, &rotate_paper
);
4685 d (2, g_printerr ("Paper size %hu --> %s\n",
4687 paper_name
? paper_name
: "-"););
4689 if (paper_name
!= NULL
)
4690 print_info_set_paper (pi
, paper_name
);
4692 pi
->scaling
.percentage
.x
= pi
->scaling
.percentage
.y
=
4693 GSF_LE_GET_GUINT16 (q
->data
+ 2);
4694 pi
->start_page
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
4695 pi
->scaling
.dim
.cols
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
4696 pi
->scaling
.dim
.rows
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
4697 if (pi
->scaling
.percentage
.x
< 1. || pi
->scaling
.percentage
.x
> 1000.) {
4698 if (pi
->scaling
.percentage
.x
!= 0) {
4699 /* 0 seems to be 'auto' */
4700 g_warning ("setting invalid print scaling (%f) to 100%%",
4701 pi
->scaling
.percentage
.x
);
4703 pi
->scaling
.percentage
.x
= pi
->scaling
.percentage
.y
= 100.;
4706 if (esheet_ver (esheet
) == MS_BIFF_V4
|| 0 == (flags
& 0x40))
4707 portrait_orientation
= (flags
& 0x2) != 0;
4709 portrait_orientation
= !portrait_orientation
;
4711 print_info_set_paper_orientation (pi
, portrait_orientation
4712 ? GTK_PAGE_ORIENTATION_PORTRAIT
4713 : GTK_PAGE_ORIENTATION_LANDSCAPE
);
4716 if (esheet_ver (esheet
) > MS_BIFF_V4
) {
4717 XL_CHECK_CONDITION (q
->length
>= 34);
4719 pi
->print_as_draft
= (flags
& 0x10) != 0;
4720 pi
->comment_placement
= (flags
& 0x20)
4721 ? GNM_PRINT_COMMENTS_IN_PLACE
: GNM_PRINT_COMMENTS_NONE
;
4722 print_info_set_margin_header (pi
,
4723 GO_IN_TO_PT (gsf_le_get_double (q
->data
+ 16)));
4724 print_info_set_margin_footer (pi
,
4725 GO_IN_TO_PT (gsf_le_get_double (q
->data
+ 24)));
4726 if (0 == (flags
& 0x4))
4727 pi
->n_copies
= GSF_LE_GET_GUINT16 (q
->data
+ 32);
4728 d (2, g_printerr ("resolution %hu vert. res. %hu\n",
4729 GSF_LE_GET_GUINT16 (q
->data
+ 12),
4730 GSF_LE_GET_GUINT16 (q
->data
+ 14)););
4733 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
4734 if ((flags
& 0x200) &&
4735 pi
->comment_placement
== GNM_PRINT_COMMENTS_IN_PLACE
)
4736 pi
->comment_placement
= GNM_PRINT_COMMENTS_AT_END
;
4737 switch ((flags
>> 10) & 3) {
4738 case 0 : pi
->error_display
= GNM_PRINT_ERRORS_AS_DISPLAYED
; break;
4739 case 1 : pi
->error_display
= GNM_PRINT_ERRORS_AS_BLANK
; break;
4740 case 2 : pi
->error_display
= GNM_PRINT_ERRORS_AS_DASHES
; break;
4741 case 3 : pi
->error_display
= GNM_PRINT_ERRORS_AS_NA
; break;
4747 excel_read_MULRK (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4749 guint32 col
, row
, lastcol
;
4750 guint8
const *ptr
= q
->data
;
4752 BiffXFData
const *xf
;
4755 XL_CHECK_CONDITION (q
->length
>= 4 + 6 + 2);
4757 row
= GSF_LE_GET_GUINT16 (q
->data
);
4758 col
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
4760 lastcol
= GSF_LE_GET_GUINT16 (q
->data
+ q
->length
- 2);
4762 XL_CHECK_CONDITION (lastcol
>= col
);
4763 XL_CHECK_CONDITION (lastcol
< (guint32
)gnm_sheet_get_max_cols (esheet
->sheet
));
4765 if (q
->length
!= 4 + 6 * (lastcol
- col
+ 1) + 2) {
4766 int guess
= col
+ (q
->length
- (4 + 2)) / 6 - 1;
4767 g_warning ("MULRK with strange size: %d vs %d", lastcol
, guess
);
4768 lastcol
= MIN (lastcol
, (guint32
)MAX (guess
, 0));
4771 for (; col
<= lastcol
; col
++) {
4773 /* 2byte XF, 4 byte RK */
4774 v
= biff_get_rk (ptr
+ 2);
4775 xf
= excel_get_xf (esheet
, GSF_LE_GET_GUINT16 (ptr
));
4776 mstyle
= excel_get_style_from_xf (esheet
, xf
);
4778 sheet_style_set_pos (esheet
->sheet
, col
, row
, mstyle
);
4779 if (xf
&& xf
->is_simple_format
)
4780 value_set_fmt (v
, xf
->style_format
);
4781 cell
= sheet_cell_fetch (esheet
->sheet
, col
, row
);
4783 gnm_cell_set_value (cell
, v
);
4791 excel_read_MULBLANK (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4793 /* This is an educated guess, docs are not terribly clear */
4794 int firstcol
, lastcol
, row
;
4795 guint8
const *ptr
= (q
->data
+ q
->length
- 2);
4796 int i
, range_end
, prev_xf
, xf_index
;
4798 XL_CHECK_CONDITION (q
->length
>= 6);
4799 firstcol
= XL_GETCOL (q
);
4800 row
= XL_GETROW (q
);
4801 lastcol
= GSF_LE_GET_GUINT16 (ptr
);
4803 g_printerr ("Cells in row %d are blank starting at col %s until col ",
4804 row
+ 1, col_name (firstcol
));
4805 g_printerr ("%s;\n",
4806 col_name (lastcol
));
4809 if (lastcol
< firstcol
) {
4814 XL_CHECK_CONDITION (q
->length
>= 4u + 2u * (lastcol
- firstcol
+ 1));
4816 range_end
= i
= lastcol
;
4820 xf_index
= GSF_LE_GET_GUINT16 (ptr
);
4822 g_printerr (" xf (%s) = 0x%x", col_name (i
), xf_index
);
4827 if (prev_xf
!= xf_index
) {
4829 excel_set_xf_segment (esheet
, i
+ 1, range_end
,
4834 } while (--i
>= firstcol
);
4835 excel_set_xf_segment (esheet
, firstcol
, range_end
,
4837 d (2, g_printerr ("\n"););
4841 xls_read_range32 (GnmRange
*r
, guint8
const *data
)
4843 r
->start
.row
= GSF_LE_GET_GUINT32 (data
+ 0);
4844 r
->end
.row
= GSF_LE_GET_GUINT32 (data
+ 4);
4845 r
->start
.col
= GSF_LE_GET_GUINT16 (data
+ 8);
4846 r
->end
.col
= GSF_LE_GET_GUINT16 (data
+ 10);
4848 r
->start
.row
= CLAMP (r
->start
.row
, 0, GNM_MAX_ROWS
- 1);
4849 r
->end
.row
= CLAMP (r
->end
.row
, 0, GNM_MAX_ROWS
- 1);
4850 r
->start
.col
= CLAMP (r
->start
.col
, 0, GNM_MAX_COLS
- 1);
4851 r
->end
.col
= CLAMP (r
->end
.col
, 0, GNM_MAX_COLS
- 1);
4853 d (4, range_dump (r
, ";\n"););
4857 xls_read_range16 (GnmRange
*r
, guint8
const *data
)
4859 r
->start
.row
= GSF_LE_GET_GUINT16 (data
+ 0);
4860 r
->end
.row
= GSF_LE_GET_GUINT16 (data
+ 2);
4861 r
->start
.col
= GSF_LE_GET_GUINT16 (data
+ 4);
4862 r
->end
.col
= GSF_LE_GET_GUINT16 (data
+ 6);
4864 r
->start
.row
= CLAMP (r
->start
.row
, 0, GNM_MAX_ROWS
- 1);
4865 r
->end
.row
= CLAMP (r
->end
.row
, 0, GNM_MAX_ROWS
- 1);
4866 r
->start
.col
= CLAMP (r
->start
.col
, 0, GNM_MAX_COLS
- 1);
4867 r
->end
.col
= CLAMP (r
->end
.col
, 0, GNM_MAX_COLS
- 1);
4869 d (4, range_dump (r
, ";\n"););
4873 xls_read_range8 (GnmRange
*r
, guint8
const *data
)
4875 r
->start
.row
= GSF_LE_GET_GUINT16 (data
+ 0);
4876 r
->end
.row
= GSF_LE_GET_GUINT16 (data
+ 2);
4877 r
->start
.col
= GSF_LE_GET_GUINT8 (data
+ 4);
4878 r
->end
.col
= GSF_LE_GET_GUINT8 (data
+ 5);
4879 d (4, range_dump (r
, ";\n"););
4883 * No documentation exists for this record, but this makes
4884 * sense given the other record formats.
4887 excel_read_MERGECELLS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4890 guint8
const *data
= q
->data
+ 2;
4894 XL_CHECK_CONDITION (q
->length
>= 2);
4895 num_merged
= GSF_LE_GET_GUINT16 (q
->data
);
4896 XL_CHECK_CONDITION (q
->length
== (unsigned int)(2 + 8 * num_merged
));
4898 for (; num_merged
-- > 0 ; data
+= 8) {
4899 xls_read_range16 (&r
, data
);
4900 overlap
= gnm_sheet_merge_get_overlap (esheet
->sheet
, &r
);
4902 GnmRange
*r2
= overlap
->data
;
4904 /* Unmerge r2, then merge (r U r2) */
4906 /* Do this early because the _remove can kill r2. */
4907 r
= range_union (&r
, r2
);
4909 gnm_sheet_merge_remove (esheet
->sheet
, r2
);
4910 g_slist_free (overlap
);
4912 gnm_sheet_merge_add (esheet
->sheet
, &r
, FALSE
,
4913 GO_CMD_CONTEXT (esheet
->container
.importer
->context
));
4918 excel_read_DIMENSIONS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4921 const char *key
= "DIMENSION";
4926 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
4927 XL_CHECK_CONDITION (q
->length
>= 12);
4928 xls_read_range32 (&r
, q
->data
);
4930 XL_CHECK_CONDITION (q
->length
>= 8);
4931 xls_read_range16 (&r
, q
->data
);
4934 if (range_width (&r
) <= 1 || range_height (&r
) <= 1) {
4935 g_object_set_data (G_OBJECT (esheet
->sheet
), key
, NULL
);
4936 d (1, g_printerr ("Dimension = -\n"););
4940 d (1, g_printerr ("Dimension = %s\n", range_as_string (&r
)););
4942 /* Hack: we need to get this information out to
4943 table_cellregion_read */
4944 g_object_set_data_full (G_OBJECT (esheet
->sheet
),
4945 key
, gnm_range_dup (&r
),
4950 static MSContainer
*
4951 sheet_container (ExcelReadSheet
*esheet
)
4953 ms_container_set_blips (&esheet
->container
, esheet
->container
.importer
->container
.blips
);
4954 return &esheet
->container
;
4958 excel_read_sheet_PROTECT (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4960 gboolean is_protected
= TRUE
;
4962 /* MS Docs fail to mention that in some stream this
4963 * record can have size zero. I assume the in that
4964 * case its existence is the flag. */
4966 is_protected
= (1 == GSF_LE_GET_GUINT16 (q
->data
));
4968 esheet
->sheet
->is_protected
= is_protected
;
4970 return is_protected
;
4974 excel_read_workbook_PROTECT (BiffQuery
*q
, WorkbookView
*wb_view
)
4976 gboolean is_protected
= TRUE
;
4978 /* MS Docs fail to mention that in some stream this
4979 * record can have size zero. I assume the in that
4980 * case its existence is the flag. */
4982 is_protected
= (1 == GSF_LE_GET_GUINT16 (q
->data
));
4984 wb_view
->is_protected
= is_protected
;
4986 return is_protected
;
4990 excel_read_WSBOOL (BiffQuery
*q
, ExcelReadSheet
*esheet
)
4994 XL_CHECK_CONDITION (q
->length
== 2);
4996 options
= GSF_LE_GET_GUINT16 (q
->data
);
4997 /* 0x0001 automatic page breaks are visible */
4998 /* 0x0010 the sheet is a dialog sheet */
4999 /* 0x0020 automatic styles are not applied to an outline */
5000 esheet
->sheet
->outline_symbols_below
= 0 != (options
& 0x040);
5001 esheet
->sheet
->outline_symbols_right
= 0 != (options
& 0x080);
5002 if (NULL
!= esheet
->sheet
->print_info
)
5003 esheet
->sheet
->print_info
->scaling
.type
=
5004 (options
& 0x100) ? PRINT_SCALE_FIT_PAGES
: PRINT_SCALE_PERCENTAGE
;
5006 /* 0x0200 biff 3-4 0 == save external linked values, 1 == do not save */
5007 /* XL docs wrong 0xc00 no 0x600, OOo docs wrong no distinct row vs col */
5008 esheet
->sheet
->display_outlines
= 0 != (options
& 0xc00);
5010 /* Biff4 0x3000 window arrangement
5012 * 1b == arrange horiz
5013 * 10b == arrange vert
5016 /* biff 4-8 0x4000, 0 == std expr eval, 1 == alt expr eval ? */
5017 /* biff 4-8 0x8000, 0 == std fmla entry, 1 == alt fmla entry ? */
5021 excel_read_CALCCOUNT (BiffQuery
*q
, GnmXLImporter
*importer
)
5025 XL_CHECK_CONDITION (q
->length
== 2);
5027 count
= GSF_LE_GET_GUINT16 (q
->data
);
5029 workbook_iteration_max_number (importer
->wb
, count
);
5033 excel_read_CALCMODE (BiffQuery
*q
, GnmXLImporter
*importer
)
5035 XL_CHECK_CONDITION (q
->length
== 2);
5036 workbook_set_recalcmode (importer
->wb
,
5037 GSF_LE_GET_GUINT16 (q
->data
) != 0);
5041 excel_read_DELTA (BiffQuery
*q
, GnmXLImporter
*importer
)
5045 XL_CHECK_CONDITION (q
->length
== 8);
5047 tolerance
= gsf_le_get_double (q
->data
);
5048 XL_CHECK_CONDITION (tolerance
>= 0);
5050 workbook_iteration_tolerance (importer
->wb
, tolerance
);
5054 excel_read_ITERATION (BiffQuery
*q
, GnmXLImporter
*importer
)
5058 XL_CHECK_CONDITION (q
->length
== 2);
5060 enabled
= GSF_LE_GET_GUINT16 (q
->data
);
5061 workbook_iteration_enabled (importer
->wb
, enabled
!= 0);
5065 excel_read_PANE (BiffQuery
*q
, ExcelReadSheet
*esheet
, WorkbookView
*wb_view
)
5067 XL_CHECK_CONDITION (q
->length
== 10);
5068 if (esheet
->freeze_panes
) {
5069 guint16 x
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
5070 guint16 y
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
5071 guint16 rwTop
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
5072 guint16 colLeft
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
5073 SheetView
*sv
= sheet_get_view (esheet
->sheet
, esheet
->container
.importer
->wbv
);
5074 GnmCellPos frozen
, unfrozen
;
5076 esheet
->active_pane
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
5077 if (esheet
->active_pane
> 3) {
5078 g_warning ("Invalid pane '%u' selected", esheet
->active_pane
);
5079 esheet
->active_pane
= 3;
5082 g_return_if_fail (sv
!= NULL
);
5084 frozen
= unfrozen
= sv
->initial_top_left
;
5088 colLeft
= sv
->initial_top_left
.col
;
5092 rwTop
= sv
->initial_top_left
.row
;
5093 sv_freeze_panes (sv
, &frozen
, &unfrozen
);
5094 sv_set_initial_top_left (sv
, colLeft
, rwTop
);
5096 g_warning ("EXCEL : no support for split panes yet (%s)", esheet
->sheet
->name_unquoted
);
5101 excel_read_WINDOW2 (BiffQuery
*q
, ExcelReadSheet
*esheet
, WorkbookView
*wb_view
)
5103 SheetView
*sv
= sheet_get_view (esheet
->sheet
, esheet
->container
.importer
->wbv
);
5104 guint16 top_row
= 0;
5105 guint16 left_col
= 0;
5106 guint32 biff_pat_col
;
5107 gboolean set_grid_color
;
5109 if (q
->opcode
== BIFF_WINDOW2_v2
) {
5112 XL_CHECK_CONDITION (q
->length
>= 10);
5114 options
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
5115 esheet
->sheet
->display_formulas
= ((options
& 0x0001) != 0);
5116 esheet
->sheet
->hide_grid
= ((options
& 0x0002) == 0);
5117 esheet
->sheet
->hide_col_header
=
5118 esheet
->sheet
->hide_row_header
= ((options
& 0x0004) == 0);
5119 esheet
->freeze_panes
= ((options
& 0x0008) != 0);
5120 esheet
->sheet
->hide_zero
= ((options
& 0x0010) == 0);
5121 set_grid_color
= (options
& 0x0020) == 0;
5122 g_object_set (esheet
->sheet
, "text-is-rtl", (options
& 0x0040) != 0, NULL
);
5124 top_row
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
5125 left_col
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
5126 biff_pat_col
= GSF_LE_GET_GUINT32 (q
->data
+ 6);
5128 d (0, if (options
& 0x0200) g_printerr ("Sheet flag selected\n"););
5129 if (options
& 0x0400)
5130 wb_view_sheet_focus (wb_view
, esheet
->sheet
);
5132 if (esheet_ver (esheet
) >= MS_BIFF_V8
&& q
->length
>= 14) {
5134 guint16
const pageBreakZoom
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
5135 guint16
const normalZoom
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
5136 g_printerr ("%hx %hx\n", normalZoom
, pageBreakZoom
);
5140 XL_CHECK_CONDITION (q
->length
>= 14);
5142 esheet
->sheet
->display_formulas
= (q
->data
[0] != 0);
5143 esheet
->sheet
->hide_grid
= (q
->data
[1] == 0);
5144 esheet
->sheet
->hide_col_header
=
5145 esheet
->sheet
->hide_row_header
= (q
->data
[2] == 0);
5146 esheet
->freeze_panes
= (q
->data
[3] != 0);
5147 esheet
->sheet
->hide_zero
= (q
->data
[4] == 0);
5148 set_grid_color
= (q
->data
[9] == 0);
5150 top_row
= GSF_LE_GET_GUINT16 (q
->data
+ 5);
5151 left_col
= GSF_LE_GET_GUINT16 (q
->data
+ 7);
5152 biff_pat_col
= GSF_LE_GET_GUINT32 (q
->data
+ 10);
5155 if (set_grid_color
) {
5156 GnmColor
*pattern_color
;
5157 if (esheet_ver (esheet
) >= MS_BIFF_V8
) {
5158 /* Get style color from palette*/
5159 pattern_color
= excel_palette_get (
5160 esheet
->container
.importer
,
5161 biff_pat_col
& 0x7f);
5165 r
= (guint8
) biff_pat_col
;
5166 g
= (guint8
) (biff_pat_col
>> 8);
5167 b
= (guint8
) (biff_pat_col
>> 16);
5168 pattern_color
= gnm_color_new_rgb8 (r
, g
, b
);
5170 d (2, g_printerr ("auto pattern color "
5172 pattern_color
->go_color
););
5173 sheet_style_set_auto_pattern_color (
5174 esheet
->sheet
, pattern_color
);
5177 g_return_if_fail (sv
!= NULL
);
5179 /* until we import multiple views unfreeze just in case a previous view
5181 sv_freeze_panes (sv
, NULL
, NULL
);
5183 /* NOTE : This is top left of screen even if frozen, modify when
5185 sv_set_initial_top_left (sv
, left_col
, top_row
);
5189 excel_read_CF_border (GnmStyle
*style
, ExcelReadSheet
*esheet
,
5190 GnmStyleBorderLocation type
,
5191 unsigned xl_pat_index
, unsigned xl_color_index
)
5193 GnmStyleElement elem
= GNM_STYLE_BORDER_LOCATION_TO_STYLE_ELEMENT (type
);
5194 gnm_style_set_border (style
, elem
,
5195 gnm_style_border_fetch (biff_xf_map_border (xl_pat_index
),
5196 excel_palette_get (esheet
->container
.importer
,
5198 gnm_style_border_get_orientation (type
)));
5202 excel_read_CF (BiffQuery
*q
, ExcelReadSheet
*esheet
, GnmStyleConditions
*sc
,
5203 GnmXLImporter
*importer
)
5206 guint16 expr0_len
,expr1_len
;
5210 GnmStyleCond
*cond
= NULL
;
5212 GnmStyle
*overlay
= NULL
;
5214 XL_CHECK_CONDITION (q
->length
>= 12);
5216 type
= GSF_LE_GET_GUINT8 (q
->data
+ 0);
5217 op
= GSF_LE_GET_GUINT8 (q
->data
+ 1);
5218 expr0_len
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
5219 expr1_len
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
5220 flags
= GSF_LE_GET_GUINT32 (q
->data
+ 6);
5221 flags2
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
5223 XL_CHECK_CONDITION (q
->length
>= 10u + expr0_len
+ expr1_len
);
5226 gsf_mem_dump (q
->data
+6, 6);
5227 g_printerr ("cond type = %d, op type = %d, flags = 0x%08x\n", (int)type
, (int)op
, flags
);
5232 case 0x01: cop
= GNM_STYLE_COND_BETWEEN
; break;
5233 case 0x02: cop
= GNM_STYLE_COND_NOT_BETWEEN
; break;
5234 case 0x03: cop
= GNM_STYLE_COND_EQUAL
; break;
5235 case 0x04: cop
= GNM_STYLE_COND_NOT_EQUAL
; break;
5236 case 0x05: cop
= GNM_STYLE_COND_GT
; break;
5237 case 0x06: cop
= GNM_STYLE_COND_LT
; break;
5238 case 0x07: cop
= GNM_STYLE_COND_GTE
; break;
5239 case 0x08: cop
= GNM_STYLE_COND_LTE
; break;
5241 g_warning ("EXCEL : Unknown condition (%d) for conditional format in sheet %s.",
5242 op
, esheet
->sheet
->name_unquoted
);
5247 cop
= GNM_STYLE_COND_CUSTOM
;
5251 g_warning ("EXCEL : Unknown condition type (%d) for format in sheet %s.",
5252 (int)type
, esheet
->sheet
->name_unquoted
);
5256 cond
= gnm_style_cond_new (cop
, esheet
->sheet
);
5258 if (expr0_len
> 0) {
5259 GnmExprTop
const *texpr
=
5260 ms_sheet_parse_expr_internal
5262 q
->data
+ q
->length
- expr0_len
- expr1_len
,
5264 gnm_style_cond_set_expr (cond
, texpr
, 0);
5265 gnm_expr_top_unref (texpr
);
5267 if (expr1_len
> 0) {
5268 GnmExprTop
const *texpr
=
5269 ms_sheet_parse_expr_internal
5271 q
->data
+ q
->length
- expr1_len
,
5273 gnm_style_cond_set_expr (cond
, texpr
, 1);
5274 gnm_expr_top_unref (texpr
);
5277 /* Reverse the alternate-expression treatment on save. */
5278 gnm_style_cond_canonicalize (cond
);
5280 /* UNDOCUMENTED : the format of the conditional format
5284 * 0xff : I'll guess fonts
5285 * uint8 : 0xff = no border
5291 * uint8 : 0x3f == no background elements,
5292 * 0x3b == background
5293 * 0x3a == background & pattern
5294 * 0x38 == background & pattern & pattern colour
5295 * uint8 : 0x04 = font | 0x10 = border | 0x20 = colour
5302 * Similar to XF from biff7
5305 overlay
= gnm_style_new ();
5307 offset
= 6 /* CF record header */ + 6; /* format header */
5309 if (flags
& 0x02000000) { /* number format */
5310 gboolean ignore
= (flags
& 0x00080000) != 0;
5312 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 2, goto fail
;);
5315 /* Format as string */
5316 guint bytes
= GSF_LE_GET_GUINT16 (q
->data
+ offset
);
5318 char *xlfmt
= excel_biff_text_2 (importer
, q
, offset
+ 2);
5319 GOFormat
*fmt
= go_format_new_from_XL (xlfmt
);
5320 gnm_style_set_format (overlay
, fmt
);
5321 go_format_unref (fmt
);
5326 /* Format as index */
5331 if (flags
& 0x04000000) { /* font */
5332 guint32 size
, colour
;
5333 guint8 tmp8
, font_flags
;
5334 guint8
const *data
= q
->data
+ offset
;
5336 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 64 + 54, goto fail
;);
5338 if (data
[0] && GSF_LE_GET_GUINT16 (data
+ 116) > 0) {
5339 char *font
= excel_biff_text_1
5340 (importer
, q
, offset
);
5341 gnm_style_set_font_name (overlay
, font
);
5347 if (0xFFFFFFFF != (size
= GSF_LE_GET_GUINT32 (data
)))
5348 gnm_style_set_font_size (overlay
, size
/ 20.);
5349 if (0xFFFFFFFF != (colour
= GSF_LE_GET_GUINT32 (data
+ 16)))
5350 gnm_style_set_font_color (overlay
,
5351 excel_palette_get (esheet
->container
.importer
,
5354 if (0 == GSF_LE_GET_GUINT8 (data
+ 36)) {
5355 gnm_style_set_font_bold (overlay
,
5356 GSF_LE_GET_GUINT16 (data
+ 8) >= 0x2bc);
5359 tmp8
= GSF_LE_GET_GUINT8 (data
+ 4);
5360 font_flags
= GSF_LE_GET_GUINT8 (data
+ 24);
5361 if (0 == (font_flags
& 2))
5362 gnm_style_set_font_italic (overlay
, 0 != (tmp8
& 2));
5364 if (0 == (font_flags
& 0x80))
5365 gnm_style_set_font_strike (overlay
, 0 != (tmp8
& 0x80));
5367 if (0 == GSF_LE_GET_GUINT8 (data
+ 28)) {
5368 switch (GSF_LE_GET_GUINT8 (data
+ 10)) {
5369 default : g_printerr ("Unknown script %d\n", GSF_LE_GET_GUINT8 (data
));
5371 case 0: gnm_style_set_font_script (overlay
, GO_FONT_SCRIPT_STANDARD
); break;
5372 case 1: gnm_style_set_font_script (overlay
, GO_FONT_SCRIPT_SUPER
); break;
5373 case 2: gnm_style_set_font_script (overlay
, GO_FONT_SCRIPT_SUB
); break;
5376 if (0 == GSF_LE_GET_GUINT8 (data
+ 32)) {
5377 MsBiffFontUnderline mul
;
5378 switch (GSF_LE_GET_GUINT8 (data
+ 12)) {
5381 mul
= XLS_ULINE_NONE
;
5384 mul
= XLS_ULINE_SINGLE
;
5387 mul
= XLS_ULINE_DOUBLE
;
5390 mul
= XLS_ULINE_SINGLE_ACC
;
5393 mul
= XLS_ULINE_DOUBLE_ACC
;
5396 gnm_style_set_font_uline
5398 xls_uline_to_gnm_underline (mul
));
5402 g_printerr ("%s\n", "Font");
5403 gsf_mem_dump (data
, 54);
5409 if (flags
& 0x08000000) { /* alignment block */
5412 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 8, goto fail
;);
5413 d1
= GSF_LE_GET_GUINT16 (q
->data
+ offset
);
5414 d2
= GSF_LE_GET_GUINT16 (q
->data
+ offset
+ 2);
5416 if (0 == (flags
& 0x1))
5417 gnm_style_set_align_h (overlay
,
5418 halign_from_excel ((d1
>> 0) & 7));
5420 if (0 == (flags
& 0x2))
5421 gnm_style_set_align_v (overlay
,
5422 valign_from_excel ((d1
>> 4) & 7));
5424 if (0 == (flags
& 0x4))
5425 gnm_style_set_wrap_text (overlay
, ((d1
>> 3) & 1));
5427 if (0 == (flags
& 0x8)) {
5428 int r
= (esheet_ver (esheet
) >= MS_BIFF_V8
5429 ? rotation_from_excel_v8 (d1
>> 8)
5430 : rotation_from_excel_v7 (d1
>> 8));
5431 gnm_style_set_rotation (overlay
, r
);
5434 if (0 == (flags
& 0x20))
5435 gnm_style_set_indent (overlay
, ((d2
>> 0) & 0xf));
5437 if (0 == (flags
& 0x40))
5438 gnm_style_set_shrink_to_fit (overlay
, ((d2
>> 4) & 1));
5443 if (flags
& 0x10000000) { /* borders */
5446 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 8, goto fail
;);
5447 d0
= GSF_LE_GET_GUINT32 (q
->data
+ offset
);
5448 d1
= GSF_LE_GET_GUINT32 (q
->data
+ offset
+ 4);
5450 if (0 == (flags
& 0x0400))
5451 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_LEFT
,
5454 if (0 == (flags
& 0x0800))
5455 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_RIGHT
,
5458 if (0 == (flags
& 0x1000))
5459 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_TOP
,
5462 if (0 == (flags
& 0x2000))
5463 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_BOTTOM
,
5466 if (0 == (flags
& 0x4000) && (d0
& 0x80000000)) {
5467 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_DIAG
,
5471 if (0 == (flags
& 0x8000) && (d0
& 0x40000000))
5472 excel_read_CF_border (overlay
, esheet
, GNM_STYLE_BORDER_REV_DIAG
,
5479 if (flags
& 0x20000000) { /* pattern */
5480 guint32 background_flags
;
5483 XL_CHECK_CONDITION_FULL (q
->length
>= offset
+ 4, goto fail
;);
5484 background_flags
= GSF_LE_GET_GUINT32 (q
->data
+ offset
);
5486 if (0 == (flags
& 0x10000))
5487 gnm_style_set_pattern (overlay
,
5488 pattern
= excel_map_pattern_index_from_excel (
5489 (background_flags
>> 10) & 0x3F));
5490 if (0 == (flags
& 0x20000))
5491 gnm_style_set_pattern_color (overlay
,
5492 excel_palette_get (esheet
->container
.importer
,
5493 (background_flags
>> 16) & 0x7F));
5494 if (0 == (flags
& 0x40000))
5495 gnm_style_set_back_color (overlay
,
5496 excel_palette_get (esheet
->container
.importer
,
5497 (background_flags
>> 23) & 0x7F));
5502 if (flags
& 0x40000000) { /* protection */
5506 XL_CHECK_CONDITION_FULL (q
->length
== offset
+ expr0_len
+ expr1_len
, goto fail
;);
5508 d (1, gnm_style_dump (overlay
););
5510 gnm_style_cond_set_overlay (cond
, overlay
);
5511 gnm_style_unref (overlay
);
5512 gnm_style_conditions_insert (sc
, cond
, -1);
5513 gnm_style_cond_free (cond
);
5518 gnm_style_cond_free (cond
);
5520 gnm_style_unref (overlay
);
5524 excel_read_CONDFMT (BiffQuery
*q
, ExcelReadSheet
*esheet
,
5525 GnmXLImporter
*importer
)
5527 guint16 num_fmts
, num_areas
;
5530 GnmStyleConditions
*sc
;
5533 GSList
*ptr
, *regions
= NULL
;
5535 XL_CHECK_CONDITION (q
->length
>= 14);
5537 num_fmts
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
5538 num_areas
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
5540 d (1, g_printerr ("Num areas == %hu\n", num_areas
););
5542 /* The bounding box or the region containing all conditional formats.
5543 * It seems like this region is 0,0 -> 0xffff,0xffff when there are no
5547 xls_read_range16 (®ion
, q
->data
+4);
5550 data
= q
->data
+ 14;
5551 for (i
= 0 ; i
< num_areas
&& (data
+8) <= (q
->data
+ q
->length
) ; i
++, data
+= 8) {
5552 xls_read_range16 (®ion
, data
);
5553 regions
= g_slist_prepend (regions
, gnm_range_dup (®ion
));
5556 XL_CHECK_CONDITION (data
== q
->data
+ q
->length
);
5558 sc
= gnm_style_conditions_new (esheet
->sheet
);
5559 for (i
= 0 ; i
< num_fmts
; i
++) {
5561 if (!ms_biff_query_peek_next (q
, &next
) || next
!= BIFF_CF
) {
5562 g_object_unref (sc
);
5563 g_slist_free_full (regions
, g_free
);
5564 g_warning ("EXCEL: missing CF record");
5567 ms_biff_query_next (q
);
5568 excel_read_CF (q
, esheet
, sc
, importer
);
5571 style
= gnm_style_new ();
5572 gnm_style_set_conditions (style
, sc
);
5573 for (ptr
= regions
; ptr
!= NULL
; ptr
= ptr
->next
) {
5574 gnm_style_ref (style
);
5575 sheet_style_apply_range (esheet
->sheet
, ptr
->data
, style
);
5578 gnm_style_unref (style
);
5579 g_slist_free (regions
);
5583 excel_read_DV (BiffQuery
*q
, ExcelReadSheet
*esheet
)
5585 GnmExprTop
const *texpr1
= NULL
;
5586 GnmExprTop
const *texpr2
= NULL
;
5587 int expr1_len
, expr2_len
;
5588 char *input_msg
, *error_msg
, *input_title
, *error_title
;
5589 guint32 options
, len
;
5590 guint8
const *data
, *expr1_dat
, *expr2_dat
;
5591 guint8
const *end
= q
->data
+ q
->length
;
5594 ValidationStyle style
;
5595 ValidationType type
;
5597 GSList
*ptr
, *ranges
= NULL
;
5600 XL_CHECK_CONDITION (q
->length
>= 4);
5601 options
= GSF_LE_GET_GUINT32 (q
->data
);
5604 XL_CHECK_CONDITION (data
+3 <= end
);
5605 input_title
= excel_get_text (esheet
->container
.importer
, data
+ 2,
5606 GSF_LE_GET_GUINT16 (data
), &len
, NULL
,
5610 XL_CHECK_CONDITION (data
+3 <= end
);
5611 error_title
= excel_get_text (esheet
->container
.importer
, data
+ 2,
5612 GSF_LE_GET_GUINT16 (data
), &len
, NULL
,
5616 XL_CHECK_CONDITION (data
+3 <= end
);
5617 input_msg
= excel_get_text (esheet
->container
.importer
, data
+ 2,
5618 GSF_LE_GET_GUINT16 (data
), &len
, NULL
,
5622 XL_CHECK_CONDITION (data
+3 <= end
);
5623 error_msg
= excel_get_text (esheet
->container
.importer
, data
+ 2,
5624 GSF_LE_GET_GUINT16 (data
), &len
, NULL
,
5629 g_printerr ("Input Title : '%s'\n", input_title
);
5630 g_printerr ("Input Msg : '%s'\n", input_msg
);
5631 g_printerr ("Error Title : '%s'\n", error_title
);
5632 g_printerr ("Error Msg : '%s'\n", error_msg
);
5635 XL_CHECK_CONDITION (data
+4 <= end
);
5636 expr1_len
= GSF_LE_GET_GUINT16 (data
);
5637 d (5, g_printerr ("Unknown1 = %hx\n", GSF_LE_GET_GUINT16 (data
+2)););
5638 expr1_dat
= data
+ 4; /* TODO : What are the missing 2 bytes ? */
5639 data
+= expr1_len
+ 4;
5641 XL_CHECK_CONDITION (data
+4 <= end
);
5642 expr2_len
= GSF_LE_GET_GUINT16 (data
);
5643 d (5, g_printerr ("Unknown2 = %hx\n", GSF_LE_GET_GUINT16 (data
+2)););
5644 expr2_dat
= data
+ 4; /* TODO : What are the missing 2 bytes ? */
5645 data
+= expr2_len
+ 4;
5647 XL_CHECK_CONDITION (data
+2 < end
);
5648 i
= GSF_LE_GET_GUINT16 (data
);
5650 XL_CHECK_CONDITION ((end
- data
) / 8 >= i
);
5652 for (; i
-- > 0 ; data
+= 8) {
5653 xls_read_range16 (&r
, data
);
5654 ranges
= g_slist_prepend (ranges
, gnm_range_dup (&r
));
5657 /* these enums align, but lets be explicit so that the filter
5658 * is easier to read.
5660 switch (options
& 0x0f) {
5661 case 0 : type
= GNM_VALIDATION_TYPE_ANY
; break;
5662 case 1 : type
= GNM_VALIDATION_TYPE_AS_INT
; break;
5663 case 2 : type
= GNM_VALIDATION_TYPE_AS_NUMBER
; break;
5664 case 3 : type
= GNM_VALIDATION_TYPE_IN_LIST
; break;
5665 case 4 : type
= GNM_VALIDATION_TYPE_AS_DATE
; break;
5666 case 5 : type
= GNM_VALIDATION_TYPE_AS_TIME
; break;
5667 case 6 : type
= GNM_VALIDATION_TYPE_TEXT_LENGTH
; break;
5668 case 7 : type
= GNM_VALIDATION_TYPE_CUSTOM
; break;
5670 g_warning ("EXCEL : Unknown constraint type %d", options
& 0x0f);
5674 switch ((options
>> 4) & 0x07) {
5675 case 0 : style
= GNM_VALIDATION_STYLE_STOP
; break;
5676 case 1 : style
= GNM_VALIDATION_STYLE_WARNING
; break;
5677 case 2 : style
= GNM_VALIDATION_STYLE_INFO
; break;
5679 g_warning ("EXCEL : Unknown validation style %d",
5680 (options
>> 4) & 0x07);
5683 if (!(options
& 0x80000))
5684 style
= GNM_VALIDATION_STYLE_NONE
;
5686 if (type
== GNM_VALIDATION_TYPE_CUSTOM
|| type
== GNM_VALIDATION_TYPE_IN_LIST
)
5687 op
= GNM_VALIDATION_OP_NONE
;
5689 switch ((options
>> 20) & 0x0f) {
5690 case 0: op
= GNM_VALIDATION_OP_BETWEEN
; break;
5691 case 1: op
= GNM_VALIDATION_OP_NOT_BETWEEN
; break;
5692 case 2: op
= GNM_VALIDATION_OP_EQUAL
; break;
5693 case 3: op
= GNM_VALIDATION_OP_NOT_EQUAL
; break;
5694 case 4: op
= GNM_VALIDATION_OP_GT
; break;
5695 case 5: op
= GNM_VALIDATION_OP_LT
; break;
5696 case 6: op
= GNM_VALIDATION_OP_GTE
; break;
5697 case 7: op
= GNM_VALIDATION_OP_LTE
; break;
5699 g_warning ("EXCEL : Unknown constraint operator %d",
5700 (options
>> 20) & 0x0f);
5704 if (ranges
!= NULL
) {
5705 GnmRange
const *r
= ranges
->data
;
5712 texpr1
= excel_parse_formula (&esheet
->container
, esheet
,
5714 expr1_dat
, expr1_len
, 0 /* FIXME */,
5718 texpr2
= excel_parse_formula (&esheet
->container
, esheet
,
5720 expr2_dat
, expr2_len
, 0 /* FIXME */,
5723 d (1, g_printerr ("style = %d, type = %d, op = %d\n",
5726 mstyle
= gnm_style_new ();
5727 gnm_style_set_validation
5729 gnm_validation_new (style
, type
, op
,
5731 error_title
, error_msg
,
5734 options
& 0x0100, 0 == (options
& 0x0200)));
5735 if (options
& 0x40000)
5736 gnm_style_set_input_msg (mstyle
,
5737 gnm_input_msg_new (input_msg
, input_title
));
5739 for (ptr
= ranges
; ptr
!= NULL
; ptr
= ptr
->next
) {
5740 GnmRange
*r
= ptr
->data
;
5741 gnm_style_ref (mstyle
);
5742 sheet_style_apply_range (esheet
->sheet
, r
, mstyle
);
5743 d (1, range_dump (r
, "\n"););
5746 g_slist_free (ranges
);
5747 gnm_style_unref (mstyle
);
5750 g_free (input_title
);
5751 g_free (error_title
);
5755 excel_read_DVAL (BiffQuery
*q
, ExcelReadSheet
*esheet
)
5758 guint32 input_coord_x
, input_coord_y
, drop_down_id
, dv_count
;
5761 XL_CHECK_CONDITION (q
->length
== 18);
5763 options
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
5764 input_coord_x
= GSF_LE_GET_GUINT32 (q
->data
+ 2);
5765 input_coord_y
= GSF_LE_GET_GUINT32 (q
->data
+ 6);
5766 drop_down_id
= GSF_LE_GET_GUINT32 (q
->data
+ 10);
5767 dv_count
= GSF_LE_GET_GUINT32 (q
->data
+ 14);
5769 d (5, if (options
& 0x1) g_printerr ("DV input window is closed\n"););
5770 d (5, if (options
& 0x2) g_printerr ("DV input window is pinned\n"););
5771 d (5, if (options
& 0x4) g_printerr ("DV info has been cached ??\n"););
5773 for (i
= 0 ; i
< dv_count
; i
++) {
5775 if (!ms_biff_query_peek_next (q
, &next
) || next
!= BIFF_DV
) {
5776 g_warning ("EXCEL: missing DV record");
5779 ms_biff_query_next (q
);
5780 excel_read_DV (q
, esheet
);
5785 excel_read_SHEETPROTECTION (BiffQuery
*q
, Sheet
*sheet
)
5789 g_return_if_fail (sheet
!= NULL
);
5793 XL_CHECK_CONDITION (q
->length
>= 19);
5795 if (q
->length
>= 23) {
5796 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 19);
5797 sheet
->protected_allow
.edit_objects
= (flags
& (1 << 0)) != 0;
5798 sheet
->protected_allow
.edit_scenarios
= (flags
& (1 << 1)) != 0;
5799 sheet
->protected_allow
.cell_formatting
= (flags
& (1 << 2)) != 0;
5800 sheet
->protected_allow
.column_formatting
= (flags
& (1 << 3)) != 0;
5801 sheet
->protected_allow
.row_formatting
= (flags
& (1 << 4)) != 0;
5802 sheet
->protected_allow
.insert_columns
= (flags
& (1 << 5)) != 0;
5803 sheet
->protected_allow
.insert_rows
= (flags
& (1 << 6)) != 0;
5804 sheet
->protected_allow
.insert_hyperlinks
= (flags
& (1 << 7)) != 0;
5805 sheet
->protected_allow
.delete_columns
= (flags
& (1 << 8)) != 0;
5806 sheet
->protected_allow
.delete_rows
= (flags
& (1 << 9)) != 0;
5807 sheet
->protected_allow
.select_locked_cells
= (flags
& (1 << 10)) != 0;
5808 sheet
->protected_allow
.sort_ranges
= (flags
& (1 << 11)) != 0;
5809 sheet
->protected_allow
.edit_auto_filters
= (flags
& (1 << 12)) != 0;
5810 sheet
->protected_allow
.edit_pivottable
= (flags
& (1 << 13)) != 0;
5811 sheet
->protected_allow
.select_unlocked_cells
= (flags
& (1 << 14)) != 0;
5815 /***********************************************************************/
5818 read_utf16_str (int word_len
, guint8
const *data
)
5821 gunichar2
*uni_text
= g_alloca (word_len
* sizeof (gunichar2
));
5823 /* be wary about endianness */
5824 for (i
= 0 ; i
< word_len
; i
++, data
+= 2)
5825 uni_text
[i
] = GSF_LE_GET_GUINT16 (data
);
5827 return (guchar
*)g_utf16_to_utf8 (uni_text
, word_len
, NULL
, NULL
, NULL
);
5831 * XL (at least XL 2000) stores URLs exactly as input by the user. No
5832 * quoting, no mime encoding of email headers. If cgi parameters are
5833 * separated by '&', '&' is stored, not '&'. An email subject in
5834 * cyrillic characters is stored as cyrillic characters, not as an
5835 * RFC 2047 MIME encoded header.
5838 excel_read_HLINK (BiffQuery
*q
, ExcelReadSheet
*esheet
)
5840 static guint8
const stdlink_guid
[] = {
5841 0xd0, 0xc9, 0xea, 0x79, 0xf9, 0xba, 0xce, 0x11,
5842 0x8c, 0x82, 0x00, 0xaa, 0x00, 0x4b, 0xa9, 0x0b,
5844 0x02, 0x00, 0x00, 0x00
5846 static guint8
const url_guid
[] = {
5847 0xe0, 0xc9, 0xea, 0x79, 0xf9, 0xba, 0xce, 0x11,
5848 0x8c, 0x82, 0x00, 0xaa, 0x00, 0x4b, 0xa9, 0x0b,
5850 static guint8
const file_guid
[] = {
5851 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5852 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46,
5855 guint32 options
, len
;
5856 guint16 next_opcode
;
5857 guint8
const *data
= q
->data
;
5858 guchar
*label
= NULL
;
5859 guchar
*target_base
= NULL
;
5860 guchar
*mark
= NULL
;
5862 GnmHLink
*link
= NULL
;
5864 XL_CHECK_CONDITION (q
->length
> 32);
5866 xls_read_range16 (&r
, data
);
5867 options
= GSF_LE_GET_GUINT32 (data
+ 28);
5869 XL_CHECK_CONDITION (!memcmp (data
+ 8, stdlink_guid
, sizeof (stdlink_guid
)));
5874 range_dump (&r
, "");
5875 g_printerr (" = hlink options(0x%04x)\n", options
);
5878 if ((options
& 0x14) == 0x14) { /* label */
5879 XL_NEED_ITEMS (1, 4);
5880 len
= GSF_LE_GET_GUINT32 (data
);
5882 XL_NEED_ITEMS (len
, 2);
5883 label
= read_utf16_str (len
, data
);
5885 d (1, g_printerr ("label = %s\n", label
););
5888 if (options
& 0x80) { /* target_base */
5889 XL_NEED_ITEMS (1, 4);
5890 len
= GSF_LE_GET_GUINT32 (data
);
5892 XL_NEED_ITEMS (len
, 2);
5893 target_base
= read_utf16_str (len
, data
);
5895 d (1, g_printerr ("target_base = %s\n", target_base
););
5898 if (options
& 0x8) { /* 'text mark' */
5899 XL_NEED_ITEMS (1, 4);
5900 len
= GSF_LE_GET_GUINT32 (data
);
5903 XL_NEED_ITEMS (len
, 2);
5904 mark
= read_utf16_str (len
, data
);
5906 d (1, g_printerr ("mark = %s\n", mark
););
5909 if ((options
& 0x163) == 0x003 && !memcmp (data
, url_guid
, sizeof (url_guid
))) {
5912 data
+= sizeof (url_guid
);
5913 XL_NEED_ITEMS (1, 4);
5914 len
= GSF_LE_GET_GUINT32 (data
);
5917 XL_NEED_BYTES (len
);
5918 url
= read_utf16_str (len
/2, data
);
5919 if (NULL
!= url
&& 0 == g_ascii_strncasecmp (url
, "mailto:", 7))
5920 link
= gnm_hlink_new (gnm_hlink_email_get_type (), esheet
->sheet
);
5922 link
= gnm_hlink_new (gnm_hlink_url_get_type (), esheet
->sheet
);
5923 gnm_hlink_set_target (link
, url
);
5927 } else if ((options
& 0x1e1) == 0x001 && !memcmp (data
, file_guid
, sizeof (file_guid
))) {
5932 data
+= sizeof (file_guid
);
5935 up
= GSF_LE_GET_GUINT16 (data
+ 0);
5936 len
= GSF_LE_GET_GUINT32 (data
+ 2);
5937 d (1, g_printerr ("# leading ../ %d len 0x%04x\n",
5941 XL_NEED_BYTES (len
);
5944 XL_NEED_BYTES (16 + 12 + 6);
5946 len
= GSF_LE_GET_GUINT32 (data
);
5949 XL_NEED_BYTES (len
);
5950 path
= read_utf16_str (len
/2, data
);
5951 accum
= g_string_new (NULL
);
5953 g_string_append (accum
, "..\\");
5954 g_string_append (accum
, path
);
5956 link
= gnm_hlink_new (gnm_hlink_external_get_type (), esheet
->sheet
);
5957 gnm_hlink_set_target (link
, accum
->str
);
5958 g_string_free (accum
, TRUE
);
5961 } else if ((options
& 0x1e3) == 0x103) {
5964 XL_NEED_ITEMS (1, 4);
5965 len
= GSF_LE_GET_GUINT32 (data
);
5968 XL_NEED_BYTES (len
);
5969 path
= read_utf16_str (len
/2, data
);
5970 link
= gnm_hlink_new (gnm_hlink_external_get_type (), esheet
->sheet
);
5971 gnm_hlink_set_target (link
, path
);
5974 } else if ((options
& 0x1eb) == 0x008) {
5975 link
= gnm_hlink_new (gnm_hlink_cur_wb_get_type (), esheet
->sheet
);
5976 gnm_hlink_set_target (link
, mark
);
5978 g_warning ("Unknown hlink type 0x%x", options
);
5981 if (ms_biff_query_peek_next (q
, &next_opcode
) &&
5982 next_opcode
== BIFF_LINK_TIP
) {
5983 ms_biff_query_next (q
);
5984 /* according to OO the bytes 2..10 are the range for the tip */
5985 XL_CHECK_CONDITION (q
->length
> 10);
5986 tip
= read_utf16_str ((q
->length
- 10)/ 2, q
->data
+ 10);
5990 GnmStyle
*style
= gnm_style_new ();
5991 gnm_hlink_set_tip (link
, tip
);
5992 gnm_style_set_hlink (style
, link
);
5993 sheet_style_apply_range (esheet
->sheet
, &r
, style
);
5998 g_free (target_base
);
6003 excel_read_CODENAME (BiffQuery
*q
, GnmXLImporter
*importer
, ExcelReadSheet
*esheet
)
6008 XL_CHECK_CONDITION (q
->length
>= 2);
6010 codename
= excel_biff_text_2 (importer
, q
, 0);
6011 obj
= esheet
? G_OBJECT (esheet
->sheet
) : G_OBJECT (importer
->wb
);
6012 g_object_set_data_full (obj
, CODENAME_KEY
, codename
, g_free
);
6016 excel_read_BG_PIC (BiffQuery
*q
,
6017 ExcelReadSheet
*esheet
)
6019 /* undocumented, looks similar to IMDATA */
6020 GdkPixbuf
*background
= excel_read_IMDATA (q
, TRUE
);
6021 if (background
!= NULL
)
6022 g_object_unref (background
);
6026 read_DOPER (guint8
const *doper
, gboolean is_equal
,
6027 unsigned *str_len
, GnmFilterOp
*op
)
6029 static GnmFilterOp
const ops
[] = {
6031 GNM_FILTER_OP_EQUAL
,
6034 GNM_FILTER_OP_NOT_EQUAL
,
6037 GnmValue
*res
= NULL
;
6040 *op
= GNM_FILTER_UNUSED
;
6042 case 0: return NULL
; /* ignore */
6044 case 2: res
= biff_get_rk (doper
+ 2);
6046 case 4: res
= value_new_float (GSF_LE_GET_DOUBLE (doper
+2));
6048 case 6: *str_len
= doper
[6];
6051 case 8: if (doper
[2])
6052 res
= xls_value_new_err (NULL
, doper
[3]);
6054 res
= value_new_bool (doper
[3] ? TRUE
: FALSE
);
6057 case 0xC: *op
= GNM_FILTER_OP_BLANKS
;
6059 case 0xE: *op
= GNM_FILTER_OP_NON_BLANKS
;
6063 g_return_val_if_fail (doper
[1] > 0 && doper
[1] <=6, NULL
);
6064 *op
= ops
[doper
[1] - 1];
6070 excel_read_AUTOFILTER (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6073 GnmFilterCondition
*cond
= NULL
;
6076 /* XL only supports 1 filter per sheet */
6077 g_return_if_fail (esheet
->sheet
->filters
!= NULL
);
6078 g_return_if_fail (esheet
->sheet
->filters
->data
!= NULL
);
6079 g_return_if_fail (esheet
->sheet
->filters
->next
== NULL
);
6081 XL_CHECK_CONDITION (q
->length
>= 4);
6082 flags
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
6084 filter
= esheet
->sheet
->filters
->data
;
6086 if (esheet_ver (esheet
) >= MS_BIFF_V8
&& flags
& 0x10)
6087 /* it's a top/bottom n */
6088 cond
= gnm_filter_condition_new_bucket (
6089 (flags
& 0x20) ? TRUE
: FALSE
,
6090 (flags
& 0x40) ? FALSE
: TRUE
,
6092 (flags
>> 7) & 0x1ff);
6095 unsigned len0
, len1
;
6096 GnmFilterOp op0
, op1
;
6098 guint8
const *end
= q
->data
+ q
->length
;
6101 XL_CHECK_CONDITION (q
->length
>= 24);
6102 v0
= read_DOPER (q
->data
+ 4, flags
& 4, &len0
, &op0
);
6103 v1
= read_DOPER (q
->data
+ 14, flags
& 8, &len1
, &op1
);
6105 data
= q
->data
+ 24;
6107 v0
= value_new_string_nocopy (
6108 excel_get_text (esheet
->container
.importer
, data
, len0
, NULL
, NULL
, end
- data
));
6112 v1
= value_new_string_nocopy (
6113 excel_get_text (esheet
->container
.importer
, data
, len1
, NULL
, NULL
, end
- data
));
6115 /* Survive fuzzed files. */
6116 if (op0
== GNM_FILTER_UNUSED
)
6117 op0
= GNM_FILTER_OP_BLANKS
;
6119 if (op1
== GNM_FILTER_UNUSED
) {
6120 cond
= gnm_filter_condition_new_single (op0
, v0
);
6121 value_release (v1
); /* paranoia */
6123 /* NOTE : Docs are backwards */
6124 cond
= gnm_filter_condition_new_double
6125 (op0
, v0
, (flags
& 3) ? FALSE
: TRUE
, op1
, v1
);
6129 gnm_filter_set_condition (filter
,
6130 GSF_LE_GET_GUINT16 (q
->data
), cond
, FALSE
);
6134 excel_read_SCL (BiffQuery
*q
, Sheet
*sheet
)
6136 unsigned num
, denom
;
6138 XL_CHECK_CONDITION (q
->length
== 4);
6140 num
= GSF_LE_GET_GUINT16 (q
->data
);
6141 denom
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
6143 XL_CHECK_CONDITION (denom
!= 0);
6145 g_object_set (sheet
, "zoom-factor", num
/ (double)denom
, NULL
);
6149 * excel_externsheet_v8 :
6151 * WARNING WARNING WARNING
6153 * This function can and will return intentionally INVALID pointers in some
6154 * cases. You need to check for XL_EXTERNSHEET_MAGIC_SELFREF
6155 * It should only happen for external names to deal with 'reference self'
6156 * supbook entries. However, you never know.
6158 * you also need to check for XL_EXTERNSHEET_MAGIC_DELETED which indicates deleted
6160 * WARNING WARNING WARNING
6162 ExcelExternSheetV8
const *
6163 excel_externsheet_v8 (GnmXLImporter
const *importer
, guint16 i
)
6165 d (2, g_printerr ("externv8 %hd\n", i
););
6167 g_return_val_if_fail (importer
->v8
.externsheet
!= NULL
, NULL
);
6169 if (i
>= importer
->v8
.externsheet
->len
) {
6170 g_warning ("%hd >= %u\n", i
, importer
->v8
.externsheet
->len
);
6174 return &(g_array_index (importer
->v8
.externsheet
, ExcelExternSheetV8
, i
));
6178 supbook_get_sheet (GnmXLImporter
*importer
, gint16 sup_index
, unsigned i
)
6180 if (sup_index
< 0) {
6181 g_warning ("external references not supported yet.");
6185 /* 0xffff == deleted */
6187 return XL_EXTERNSHEET_MAGIC_DELETED
; /* magic value */
6189 /* WARNING : 0xfffe record for local names kludge a solution */
6191 return XL_EXTERNSHEET_MAGIC_SELFREF
; /* magic value */
6193 g_return_val_if_fail ((unsigned)sup_index
< importer
->v8
.supbook
->len
, NULL
);
6195 switch (g_array_index (importer
->v8
.supbook
, ExcelSupBook
, sup_index
).type
) {
6196 case EXCEL_SUP_BOOK_SELFREF
: {
6198 g_return_val_if_fail (i
< importer
->boundsheet_sheet_by_index
->len
, NULL
);
6199 sheet
= g_ptr_array_index (importer
->boundsheet_sheet_by_index
, i
);
6200 g_return_val_if_fail (IS_SHEET (sheet
), NULL
);
6203 case EXCEL_SUP_BOOK_STD
:
6204 g_warning ("external references not supported yet.");
6206 case EXCEL_SUP_BOOK_PLUGIN
:
6207 g_warning ("strange external reference.");
6211 return XL_EXTERNSHEET_MAGIC_DELETED
; /* pretend "deleted" */
6215 excel_read_EXTERNSHEET_v8 (BiffQuery
const *q
, GnmXLImporter
*importer
)
6217 ExcelExternSheetV8
*v8
;
6219 unsigned i
, num
, first
, last
;
6221 XL_CHECK_CONDITION (importer
->ver
>= MS_BIFF_V8
);
6222 g_return_if_fail (importer
->v8
.externsheet
== NULL
);
6224 XL_CHECK_CONDITION (q
->length
>= 2);
6225 num
= GSF_LE_GET_GUINT16 (q
->data
);
6226 XL_CHECK_CONDITION (q
->length
>= 2 + num
* 6);
6228 d (2, g_printerr ("ExternSheet (%d entries)\n", num
););
6229 d (10, gsf_mem_dump (q
->data
, q
->length
););
6231 importer
->v8
.externsheet
= g_array_set_size (
6232 g_array_new (FALSE
, FALSE
, sizeof (ExcelExternSheetV8
)), num
);
6234 for (i
= 0; i
< num
; i
++) {
6235 sup_index
= GSF_LE_GET_GINT16 (q
->data
+ 2 + i
* 6 + 0);
6236 first
= GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
* 6 + 2);
6237 last
= GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
* 6 + 4);
6239 d (2, g_printerr ("ExternSheet: sup = %hd First sheet 0x%x, Last sheet 0x%x\n",
6240 sup_index
, first
, last
););
6242 v8
= &g_array_index(importer
->v8
.externsheet
, ExcelExternSheetV8
, i
);
6243 v8
->supbook
= sup_index
;
6244 v8
->first
= supbook_get_sheet (importer
, sup_index
, first
);
6245 v8
->last
= supbook_get_sheet (importer
, sup_index
, last
);
6246 d (2, g_printerr ("\tFirst sheet %p, Last sheet %p\n",
6247 v8
->first
, v8
->last
););
6252 * excel_externsheet_v7 :
6256 excel_externsheet_v7 (MSContainer
const *container
, gint16 idx
)
6258 GPtrArray
const *externsheets
;
6260 d (2, g_printerr ("externv7 %hd\n", idx
););
6262 externsheets
= container
->v7
.externsheets
;
6263 g_return_val_if_fail (externsheets
!= NULL
, NULL
);
6264 g_return_val_if_fail (idx
> 0, NULL
);
6265 g_return_val_if_fail (idx
<= (int)externsheets
->len
, NULL
);
6267 return g_ptr_array_index (externsheets
, idx
-1);
6271 excel_read_EXTERNSHEET_v7 (BiffQuery
const *q
, MSContainer
*container
)
6273 Sheet
*sheet
= NULL
;
6276 XL_CHECK_CONDITION (q
->length
>= 2);
6278 type
= GSF_LE_GET_GUINT8 (q
->data
+ 1);
6281 g_printerr ("extern v7 %p\n", container
);
6282 gsf_mem_dump (q
->data
, q
->length
); });
6285 case 2: sheet
= ms_container_sheet (container
);
6287 g_warning ("What does this mean ?");
6290 /* Type 3 is undocumented magic. It is used to forward declare sheet
6291 * names in the current workbook */
6293 unsigned len
= GSF_LE_GET_GUINT8 (q
->data
);
6296 /* opencalc screws up its export, overstating
6297 * the length by 1 */
6298 if (len
+ 2 > q
->length
)
6299 len
= q
->length
- 2;
6301 name
= excel_biff_text (container
->importer
, q
, 2, len
);
6304 sheet
= workbook_sheet_by_name (container
->importer
->wb
, name
);
6305 if (sheet
== NULL
) {
6306 /* There was a bug in 1.0.x export that spewed the quoted name
6307 * includling internal backquoting */
6308 if (name
[0] == '\'') {
6309 GString
*fixed
= g_string_new (NULL
);
6310 if (NULL
!= go_strunescape (fixed
, name
) &&
6311 NULL
!= (sheet
= workbook_sheet_by_name (container
->importer
->wb
, fixed
->str
))) {
6313 name
= g_string_free (fixed
, FALSE
);
6315 g_string_free (fixed
, TRUE
);
6318 if (sheet
== NULL
) {
6319 sheet
= sheet_new (container
->importer
->wb
,
6323 workbook_sheet_attach (container
->importer
->wb
, sheet
);
6330 case 4: /* undocumented. Seems to be used as a placeholder for names */
6331 sheet
= XL_EXTERNSHEET_MAGIC_SELFREF
;
6334 case 0x3a : /* undocumented magic. seems to indicate the sheet for an
6335 * addin with functions. 01 3a
6336 * the same as SUPBOOK
6338 if (*q
->data
== 1 && q
->length
== 2)
6342 /* Fix when we get placeholders to external workbooks */
6343 d (1, gsf_mem_dump (q
->data
, q
->length
););
6344 go_io_warning_unsupported_feature (container
->importer
->context
,
6345 _("external references"));
6348 if (container
->v7
.externsheets
== NULL
)
6349 container
->v7
.externsheets
= g_ptr_array_new ();
6350 g_ptr_array_add (container
->v7
.externsheets
, sheet
);
6354 excel_read_EXTERNSHEET (BiffQuery
const *q
, GnmXLImporter
*importer
,
6355 const MsBiffBofData
*ver
)
6357 XL_CHECK_CONDITION (ver
!= NULL
);
6359 if (ver
->version
>= MS_BIFF_V8
)
6360 excel_read_EXTERNSHEET_v8 (q
, importer
);
6362 excel_read_EXTERNSHEET_v7 (q
, &importer
->container
);
6366 /* FILEPASS, ask the user for a password if necessary
6367 * return value is an error string, or NULL for success
6370 excel_read_FILEPASS (BiffQuery
*q
, GnmXLImporter
*importer
)
6372 /* files with workbook protection are encrypted using a
6373 * static password (why ?? ). */
6374 if (ms_biff_query_set_decrypt(q
, importer
->ver
, "VelvetSweatshop"))
6378 guint8
*passwd
= go_cmd_context_get_password (
6379 GO_CMD_CONTEXT (importer
->context
),
6380 go_doc_get_uri (GO_DOC (importer
->wb
)));
6384 return _("No password supplied");
6386 ok
= ms_biff_query_set_decrypt (q
, importer
->ver
, passwd
);
6387 go_destroy_password (passwd
);
6395 excel_read_LABEL (BiffQuery
*q
, ExcelReadSheet
*esheet
, gboolean has_markup
)
6398 guint in_len
, str_len
;
6400 BiffXFData
const *xf
;
6401 ExcelFont
const *fd
;
6402 GnmCell
*cell
= excel_cell_fetch (q
, esheet
);
6407 XL_CHECK_CONDITION (q
->length
>= 8);
6408 in_len
= (q
->opcode
== BIFF_LABEL_v0
)
6409 ? GSF_LE_GET_GUINT8 (q
->data
+ 7)
6410 : GSF_LE_GET_GUINT16 (q
->data
+ 6);
6411 XL_CHECK_CONDITION (q
->length
- 8 >= in_len
);
6413 xf
= excel_set_xf (esheet
, q
);
6416 fd
= excel_font_get (esheet
->container
.importer
, xf
->font_idx
);
6418 txt
= excel_get_text (esheet
->container
.importer
, q
->data
+ 8,
6419 in_len
, &str_len
, fd
? &fd
->codepage
: NULL
,
6422 d (0, g_printerr ("%s in %s;\n",
6423 has_markup
? "formatted string" : "string",
6424 cell_name (cell
)););
6427 GOFormat
*fmt
= NULL
;
6429 fmt
= excel_read_LABEL_markup (q
, esheet
, txt
, str_len
);
6431 /* might free txt, do not do this until after parsing markup */
6432 v
= value_new_string_nocopy (txt
);
6434 value_set_fmt (v
, fmt
);
6435 go_format_unref (fmt
);
6437 gnm_cell_set_value (cell
, v
);
6442 excel_read_BOOLERR (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6444 unsigned base
= (q
->opcode
== BIFF_BOOLERR_v0
) ? 7 : 6;
6447 XL_CHECK_CONDITION (q
->length
>= base
+ 2);
6449 if (GSF_LE_GET_GUINT8 (q
->data
+ base
+ 1)) {
6451 eval_pos_init (&ep
, esheet
->sheet
, XL_GETCOL (q
), XL_GETROW (q
));
6452 v
= xls_value_new_err (&ep
, GSF_LE_GET_GUINT8 (q
->data
+ base
));
6454 v
= value_new_bool (GSF_LE_GET_GUINT8 (q
->data
+ base
));
6455 excel_sheet_insert_val (esheet
, q
, v
);
6459 excel_read_HEADER_FOOTER (GnmXLImporter
const *importer
,
6460 BiffQuery
*q
, ExcelReadSheet
*esheet
,
6463 GnmPrintInformation
*pi
= esheet
->sheet
->print_info
;
6468 if (importer
->ver
>= MS_BIFF_V8
)
6469 str
= excel_biff_text_2 (importer
, q
, 0);
6471 str
= excel_biff_text_1 (importer
, q
, 0);
6473 d (2, g_printerr ("%s == '%s'\n", is_header
? "header" : "footer", str
););
6475 xls_header_footer_import (is_header
? &pi
->header
: &pi
->footer
,
6483 excel_read_REFMODE (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6487 XL_CHECK_CONDITION (q
->length
>= 2);
6488 mode
= GSF_LE_GET_GUINT16 (q
->data
);
6489 g_object_set (esheet
->sheet
, "use-r1c1", mode
== 0, NULL
);
6493 excel_read_PAGE_BREAK (BiffQuery
*q
, ExcelReadSheet
*esheet
, gboolean is_vert
)
6496 unsigned step
= (esheet_ver (esheet
) >= MS_BIFF_V8
) ? 6 : 2;
6498 GnmPageBreaks
*breaks
;
6500 XL_CHECK_CONDITION (q
->length
>= 2);
6501 count
= GSF_LE_GET_GUINT16 (q
->data
);
6502 XL_CHECK_CONDITION (q
->length
>= 2 + count
* step
);
6503 breaks
= gnm_page_breaks_new (is_vert
);
6505 /* 1) Ignore the first/last info for >= biff8
6506 * 2) Assume breaks are manual in the absence of any information */
6507 for (i
= 0; i
< count
; i
++) {
6508 gnm_page_breaks_append_break (breaks
,
6509 GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
*step
), GNM_PAGE_BREAK_MANUAL
);
6511 g_printerr ("%d %d:%d\n",
6512 GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
*step
),
6513 GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
*step
+ 2),
6514 GSF_LE_GET_GUINT16 (q
->data
+ 2 + i
*step
+ 4));
6517 print_info_set_breaks (esheet
->sheet
->print_info
, breaks
);
6521 excel_read_INTEGER (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6523 XL_CHECK_CONDITION (q
->length
>= 7 + 2);
6524 excel_sheet_insert_val
6526 value_new_int (GSF_LE_GET_GUINT16 (q
->data
+ 7)));
6530 excel_read_NUMBER (BiffQuery
*q
, ExcelReadSheet
*esheet
, size_t ofs
)
6532 XL_CHECK_CONDITION (q
->length
>= ofs
+ 8);
6533 excel_sheet_insert_val
6535 value_new_float (gsf_le_get_double (q
->data
+ ofs
)));
6539 excel_read_MARGIN (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6542 GnmPrintInformation
*pi
= esheet
->sheet
->print_info
;
6544 XL_CHECK_CONDITION (q
->length
>= 8);
6545 m
= GO_IN_TO_PT (gsf_le_get_double (q
->data
));
6547 switch (q
->opcode
) {
6548 case BIFF_LEFT_MARGIN
: print_info_set_margin_left (pi
, m
); break;
6549 case BIFF_RIGHT_MARGIN
: print_info_set_margin_right (pi
, m
); break;
6550 case BIFF_TOP_MARGIN
: print_info_set_edge_to_below_header (pi
, m
); break;
6551 case BIFF_BOTTOM_MARGIN
: print_info_set_edge_to_above_footer (pi
, m
); break;
6552 default: g_assert_not_reached ();
6558 excel_read_PRINTHEADERS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6560 XL_CHECK_CONDITION (q
->length
>= 2);
6561 esheet
->sheet
->print_info
->print_titles
=
6562 (GSF_LE_GET_GUINT16 (q
->data
) == 1);
6566 excel_read_PRINTGRIDLINES (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6568 XL_CHECK_CONDITION (q
->length
>= 2);
6569 esheet
->sheet
->print_info
->print_grid_lines
=
6570 (GSF_LE_GET_GUINT16 (q
->data
) == 1);
6574 excel_read_HCENTER (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6576 XL_CHECK_CONDITION (q
->length
>= 2);
6577 esheet
->sheet
->print_info
->center_horizontally
=
6578 GSF_LE_GET_GUINT16 (q
->data
) == 0x1;
6582 excel_read_VCENTER (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6584 XL_CHECK_CONDITION (q
->length
>= 2);
6585 esheet
->sheet
->print_info
->center_vertically
=
6586 GSF_LE_GET_GUINT16 (q
->data
) == 0x1;
6590 excel_read_PLS (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6592 XL_CHECK_CONDITION (q
->length
>= 2);
6593 if (GSF_LE_GET_GUINT16 (q
->data
) == 0x00) {
6595 * q->data + 2 -> q->data + q->length
6596 * map to a DEVMODE structure see MS' SDK.
6598 } else if (GSF_LE_GET_GUINT16 (q
->data
) == 0x01) {
6600 * q's data maps to a TPrint structure
6601 * see Inside Macintosh Vol II p 149.
6607 excel_read_RK (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6609 XL_CHECK_CONDITION (q
->length
>= 6 + 4);
6610 excel_sheet_insert_val (esheet
, q
,
6611 biff_get_rk (q
->data
+ 6));
6615 excel_read_LABELSST (BiffQuery
*q
, ExcelReadSheet
*esheet
)
6619 XL_CHECK_CONDITION (q
->length
>= 6 + 4);
6620 i
= GSF_LE_GET_GUINT32 (q
->data
+ 6);
6622 if (esheet
->container
.importer
->sst
&& i
< esheet
->container
.importer
->sst_len
) {
6624 GOString
*str
= esheet
->container
.importer
->sst
[i
].content
;
6625 /* ? Why would there be a NULL ? */
6627 go_string_ref (str
);
6628 v
= value_new_string_str (str
);
6629 d (2, g_printerr ("str=%s\n", str
->str
););
6631 v
= value_new_string ("");
6632 if (esheet
->container
.importer
->sst
[i
].markup
!= NULL
)
6633 value_set_fmt (v
, esheet
->container
.importer
->sst
[i
].markup
);
6634 excel_sheet_insert_val (esheet
, q
, v
);
6636 g_warning ("string index 0x%u >= 0x%x\n",
6637 i
, esheet
->container
.importer
->sst_len
);
6641 excel_read_sheet (BiffQuery
*q
, GnmXLImporter
*importer
,
6642 WorkbookView
*wb_view
, ExcelReadSheet
*esheet
)
6644 MsBiffVersion
const ver
= importer
->ver
;
6646 g_return_val_if_fail (importer
!= NULL
, FALSE
);
6647 g_return_val_if_fail (esheet
!= NULL
, FALSE
);
6648 g_return_val_if_fail (esheet
->sheet
!= NULL
, FALSE
);
6649 g_return_val_if_fail (esheet
->sheet
->print_info
!= NULL
, FALSE
);
6651 d (1, g_printerr ("----------------- '%s' -------------\n",
6652 esheet
->sheet
->name_unquoted
););
6654 if (ver
<= MS_BIFF_V4
) {
6655 /* Style is per-sheet in early Excel - default TODO */
6656 excel_workbook_reset_style (importer
);
6658 /* Apply the default style */
6659 GnmStyle
*mstyle
= excel_get_style_from_xf (esheet
,
6660 excel_get_xf (esheet
, 15));
6661 if (mstyle
!= NULL
) {
6663 range_init_full_sheet (&r
, esheet
->sheet
);
6664 sheet_style_set_range (esheet
->sheet
, &r
, mstyle
);
6668 for (; ms_biff_query_next (q
) ;
6669 go_io_value_progress_update (importer
->context
, q
->streamPos
)) {
6672 const char *opname
= biff_opcode_name (q
->opcode
);
6673 g_printerr ("Opcode: 0x%x %s\n",
6675 opname
? opname
: "unknown");
6678 switch (q
->opcode
) {
6679 case BIFF_DIMENSIONS_v0
: break; /* ignore ancient XL2 variant */
6680 case BIFF_DIMENSIONS_v2
: excel_read_DIMENSIONS (q
, esheet
); break;
6684 (void)excel_set_xf (esheet
, q
);
6688 excel_read_INTEGER (q
, esheet
);
6690 case BIFF_NUMBER_v0
:
6691 excel_read_NUMBER (q
, esheet
, 7);
6693 case BIFF_NUMBER_v2
:
6694 excel_read_NUMBER (q
, esheet
, 6);
6699 excel_read_LABEL (q
, esheet
, FALSE
);
6702 case BIFF_BOOLERR_v0
:
6703 case BIFF_BOOLERR_v2
:
6704 excel_read_BOOLERR (q
, esheet
);
6707 case BIFF_FORMULA_v0
:
6708 case BIFF_FORMULA_v2
:
6709 case BIFF_FORMULA_v4
: excel_read_FORMULA (q
, esheet
); break;
6710 /* case STRING : is handled elsewhere since it always follows FORMULA */
6712 case BIFF_ROW_v2
: excel_read_ROW (q
, esheet
); break;
6713 case BIFF_EOF
: goto success
;
6715 /* NOTE : bytes 12 & 16 appear to require the non decrypted data */
6717 case BIFF_INDEX_v2
: break;
6719 case BIFF_CALCCOUNT
: excel_read_CALCCOUNT (q
, importer
); break;
6720 case BIFF_CALCMODE
: excel_read_CALCMODE (q
,importer
); break;
6722 case BIFF_PRECISION
:
6725 /* FIXME: implement in gnumeric */
6726 /* state of 'Precision as Displayed' option */
6727 guint16
const data
= GSF_LE_GET_GUINT16 (q
->data
);
6728 gboolean
const prec_as_displayed
= (data
== 0);
6733 case BIFF_REFMODE
: excel_read_REFMODE (q
, esheet
); break;
6734 case BIFF_DELTA
: excel_read_DELTA (q
, importer
); break;
6735 case BIFF_ITERATION
: excel_read_ITERATION (q
, importer
); break;
6736 case BIFF_OBJPROTECT
:
6737 case BIFF_PROTECT
: excel_read_sheet_PROTECT (q
, esheet
); break;
6740 if (q
->length
== 2) {
6741 d (2, g_printerr ("sheet password '%hx'\n",
6742 GSF_LE_GET_GUINT16 (q
->data
)););
6748 case BIFF_HEADER
: excel_read_HEADER_FOOTER (importer
, q
, esheet
, TRUE
); break;
6749 case BIFF_FOOTER
: excel_read_HEADER_FOOTER (importer
, q
, esheet
, FALSE
); break;
6751 case BIFF_EXTERNCOUNT
: /* ignore */ break;
6752 case BIFF_EXTERNSHEET
: /* These cannot be biff8 */
6753 excel_read_EXTERNSHEET_v7 (q
, &esheet
->container
);
6756 case BIFF_VERTICALPAGEBREAKS
: excel_read_PAGE_BREAK (q
, esheet
, TRUE
); break;
6757 case BIFF_HORIZONTALPAGEBREAKS
: excel_read_PAGE_BREAK (q
, esheet
, FALSE
); break;
6759 case BIFF_NOTE
: excel_read_NOTE (q
, esheet
); break;
6760 case BIFF_SELECTION
: excel_read_SELECTION (q
, esheet
); break;
6761 case BIFF_EXTERNNAME_v0
:
6762 case BIFF_EXTERNNAME_v2
:
6763 excel_read_EXTERNNAME (q
, &esheet
->container
);
6765 case BIFF_DEFAULTROWHEIGHT_v0
:
6766 case BIFF_DEFAULTROWHEIGHT_v2
:
6767 excel_read_DEF_ROW_HEIGHT (q
, esheet
);
6770 case BIFF_LEFT_MARGIN
:
6771 case BIFF_RIGHT_MARGIN
:
6772 case BIFF_TOP_MARGIN
:
6773 case BIFF_BOTTOM_MARGIN
:
6774 excel_read_MARGIN (q
, esheet
);
6777 case BIFF_PRINTHEADERS
:
6778 excel_read_PRINTHEADERS (q
, esheet
);
6781 case BIFF_PRINTGRIDLINES
:
6782 excel_read_PRINTGRIDLINES (q
, esheet
);
6785 case BIFF_WINDOW1
: break; /* what does this do for a sheet ? */
6786 case BIFF_WINDOW2_v0
:
6787 case BIFF_WINDOW2_v2
:
6788 excel_read_WINDOW2 (q
, esheet
, wb_view
);
6790 case BIFF_BACKUP
: break;
6791 case BIFF_PANE
: excel_read_PANE (q
, esheet
, wb_view
); break;
6793 case BIFF_PLS
: excel_read_PLS (q
, esheet
); break;
6795 case BIFF_DEFCOLWIDTH
: excel_read_DEF_COL_WIDTH (q
, esheet
); break;
6797 case BIFF_OBJ
: ms_read_OBJ (q
, sheet_container (esheet
), NULL
); break;
6799 case BIFF_SAVERECALC
: break;
6800 case BIFF_TAB_COLOR
: excel_read_TAB_COLOR (q
, esheet
); break;
6801 case BIFF_COLINFO
: excel_read_COLINFO (q
, esheet
); break;
6803 case BIFF_RK
: excel_read_RK (q
, esheet
); break;
6806 GdkPixbuf
*pixbuf
= excel_read_IMDATA (q
, FALSE
);
6808 g_object_unref (pixbuf
);
6811 case BIFF_GUTS
: excel_read_GUTS (q
, esheet
); break;
6812 case BIFF_WSBOOL
: excel_read_WSBOOL (q
, esheet
); break;
6813 case BIFF_GRIDSET
: break;
6815 case BIFF_HCENTER
: excel_read_HCENTER (q
, esheet
); break;
6816 case BIFF_VCENTER
: excel_read_VCENTER (q
, esheet
); break;
6818 case BIFF_COUNTRY
: break;
6819 case BIFF_STANDARDWIDTH
: break; /* the 'standard width dialog' ? */
6820 case BIFF_FILTERMODE
: break;
6821 case BIFF_AUTOFILTERINFO
: break;
6822 case BIFF_AUTOFILTER
: excel_read_AUTOFILTER (q
, esheet
); break;
6823 case BIFF_SCL
: excel_read_SCL (q
, esheet
->sheet
); break;
6824 case BIFF_SETUP
: excel_read_SETUP (q
, esheet
); break;
6825 case BIFF_GCW
: break;
6826 case BIFF_SCENMAN
: break;
6827 case BIFF_SCENARIO
: break;
6828 case BIFF_MULRK
: excel_read_MULRK (q
, esheet
); break;
6829 case BIFF_MULBLANK
: excel_read_MULBLANK (q
, esheet
); break;
6831 case BIFF_RSTRING
: excel_read_LABEL (q
, esheet
, TRUE
); break;
6833 case BIFF_DBCELL
: break; /* Can be ignored on read side */
6835 case BIFF_BG_PIC
: excel_read_BG_PIC (q
, esheet
); break;
6836 case BIFF_MERGECELLS
: excel_read_MERGECELLS (q
, esheet
); break;
6838 case BIFF_MS_O_DRAWING
:
6839 case BIFF_MS_O_DRAWING_GROUP
:
6840 case BIFF_MS_O_DRAWING_SELECTION
:
6841 ms_escher_parse (q
, sheet_container (esheet
), FALSE
);
6843 case BIFF_PHONETIC
: break;
6846 excel_read_LABELSST (q
, esheet
);
6849 case BIFF_XF_OLD_v0
:
6850 case BIFF_XF_OLD_v2
:
6851 case BIFF_XF_OLD_v4
:
6852 excel_read_XF_OLD (q
, importer
);
6855 excel_read_XF_INDEX (q
, esheet
);
6859 case BIFF_NAME_v2
: excel_read_NAME (q
, importer
, esheet
); break;
6861 case BIFF_FONT_v2
: excel_read_FONT (q
, importer
); break;
6862 case BIFF_FORMAT_v0
:
6863 case BIFF_FORMAT_v4
: excel_read_FORMAT (q
, importer
); break;
6864 case BIFF_STYLE
: break;
6865 case BIFF_1904
: excel_read_1904 (q
, importer
); break;
6866 case BIFF_FILEPASS
: {
6867 const char *problem
= excel_read_FILEPASS (q
, importer
);
6868 if (problem
!= NULL
) {
6869 go_cmd_context_error_import (GO_CMD_CONTEXT (importer
->context
), problem
);
6876 excel_read_CONDFMT (q
, esheet
, importer
);
6879 g_warning ("Found a CF record without a CONDFMT ??");
6881 case BIFF_DVAL
: excel_read_DVAL (q
, esheet
); break;
6882 case BIFF_HLINK
: excel_read_HLINK (q
, esheet
); break;
6883 case BIFF_CODENAME
: excel_read_CODENAME (q
, importer
, esheet
); break;
6886 g_warning ("Found a DV record without a DVal ??");
6887 excel_read_DV (q
, esheet
);
6890 case BIFF_SXVIEWEX9
:
6891 /* Seems to contain pivot table autoformat indicies, plus ?? */
6892 /* samples/excel/dbfuns.xls has as sample of this record
6893 * and I added code in OOo */
6896 case BIFF_SHEETPROTECTION
:
6897 excel_read_SHEETPROTECTION (q
, esheet
->sheet
);
6900 /* HACK: it seems that in older versions of XL the
6901 * charts did not have a wrapper object. the first
6902 * record in the sequence of chart records was a
6903 * CHART_UNITS followed by CHART_CHART. We play off of
6904 * that. When we encounter a CHART_units record we
6905 * jump to the chart handler which then starts parsing
6906 * at the NEXT record.
6908 case BIFF_CHART_units
: {
6909 SheetObject
*obj
= sheet_object_graph_new (NULL
);
6910 ms_excel_chart_read (q
, sheet_container (esheet
),
6912 sheet_object_set_sheet (obj
, esheet
->sheet
);
6913 g_object_unref (obj
);
6916 case BIFF_SXVIEW
: xls_read_SXVIEW (q
, esheet
); break;
6917 case BIFF_SXVD
: xls_read_SXVD (q
, esheet
); break;
6918 case BIFF_SXVDEX
: break; /* pulled in with SXVD */
6919 case BIFF_SXVI
: break; /* pulled in with SXVD */
6920 case BIFF_SXIVD
: xls_read_SXIVD (q
, esheet
); break;
6923 excel_unexpected_biff (q
, "Sheet", ms_excel_read_debug
);
6927 g_printerr ("Error, hit end without EOF\n");
6932 /* We need a sheet to extract styles, so store the workbook default as
6933 * soon as we parse a sheet. It is a kludge, but not terribly costly */
6934 g_object_set_data_full (G_OBJECT (importer
->wb
),
6935 "xls-default-style",
6936 excel_get_style_from_xf (esheet
, excel_get_xf (esheet
, 0)),
6937 (GDestroyNotify
) gnm_style_unref
);
6942 * NOTE : MS Docs are incorrect
6944 * unsigned short num_tabs;
6945 * unsigned short num_characters_in_book;
6946 * unsigned char flag_for_unicode; 0 or 1
6947 * var encoded string stored as 1 or 2 byte characters
6950 excel_read_SUPBOOK (BiffQuery
*q
, GnmXLImporter
*importer
)
6952 unsigned numTabs
, len
;
6954 guint32 byte_length
, ofs
;
6955 ExcelSupBook
*new_supbook
;
6958 XL_CHECK_CONDITION (q
->length
>= 4);
6959 numTabs
= GSF_LE_GET_GUINT16 (q
->data
);
6960 len
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
6962 i
= importer
->v8
.supbook
->len
;
6963 g_array_set_size (importer
->v8
.supbook
, i
+ 1);
6964 new_supbook
= &g_array_index (importer
->v8
.supbook
, ExcelSupBook
, i
);
6966 d (2, g_printerr ("supbook %d has %d sheets\n", i
, numTabs
););
6968 new_supbook
->externname
= g_ptr_array_new ();
6969 new_supbook
->wb
= NULL
;
6971 if (q
->length
== 4 && len
== 0x0401) {
6972 d (2, g_printerr ("\t is self referential\n"););
6973 new_supbook
->type
= EXCEL_SUP_BOOK_SELFREF
;
6976 if (q
->length
== 4 && len
== 0x3A01) {
6977 d (2, g_printerr ("\t is a plugin\n"););
6978 new_supbook
->type
= EXCEL_SUP_BOOK_PLUGIN
;
6982 new_supbook
->type
= EXCEL_SUP_BOOK_STD
;
6983 XL_CHECK_CONDITION (q
->length
>= 5);
6985 bookname
= excel_get_text (importer
, q
->data
+ 4, len
,
6986 &byte_length
, NULL
, q
->length
- 4);
6987 d (2, g_printerr ("\trefers to %s\n", bookname
););
6990 * (1) a single space -- "unused"
6991 * (2) a single nul -- self referencing
6992 * (3) an OLE-link VirtualPath
6993 * (4) any other VirtualPath -- external workbook
6995 if (len
== 1 && *bookname
== 0) {
6996 new_supbook
->type
= EXCEL_SUP_BOOK_SELFREF
;
6997 } else if (len
== 1 && *bookname
== ' ') {
7002 ofs
= 4 + byte_length
;
7003 XL_CHECK_CONDITION (ofs
<= q
->length
);
7005 for (t
= 0; t
< numTabs
; t
++) {
7009 XL_CHECK_CONDITION (ofs
+ 2 <= q
->length
);
7011 length
= GSF_LE_GET_GUINT16 (q
->data
+ ofs
);
7013 name
= excel_get_text (importer
, q
->data
+ ofs
, length
,
7014 &byte_length
, NULL
, q
->length
- ofs
);
7015 d (2, g_printerr ("\tSheet %d -> %s\n", t
, name
););
7021 #warning "create a workbook and sheets when we have a facility for merging things"
7025 excel_read_WINDOW1 (BiffQuery
*q
, WorkbookView
*wb_view
)
7027 if (q
->length
>= 16) {
7029 /* In 1/20ths of a point */
7030 guint16
const xPos
= GSF_LE_GET_GUINT16 (q
->data
+ 0);
7031 guint16
const yPos
= GSF_LE_GET_GUINT16 (q
->data
+ 2);
7033 guint16
const width
= GSF_LE_GET_GUINT16 (q
->data
+ 4);
7034 guint16
const height
= GSF_LE_GET_GUINT16 (q
->data
+ 6);
7035 guint16
const options
= GSF_LE_GET_GUINT16 (q
->data
+ 8);
7037 /* duplicated in the WINDOW2 record */
7038 guint16
const selTab
= GSF_LE_GET_GUINT16 (q
->data
+ 10);
7040 guint16
const firstTab
= GSF_LE_GET_GUINT16 (q
->data
+ 12);
7041 guint16
const tabsSel
= GSF_LE_GET_GUINT16 (q
->data
+ 14);
7043 /* (width of tab)/(width of horizontal scroll bar) / 1000 */
7044 guint16
const ratio
= GSF_LE_GET_GUINT16 (q
->data
+ 16);
7048 * We are sizing the window including the toolbars,
7049 * menus, and notbook tabs. Excel does not.
7051 * NOTE: This is the size of the MDI sub-window, not the size of
7052 * the containing excel window.
7054 wb_view_preferred_size (wb_view
,
7055 .5 + width
* gnm_app_display_dpi_get (TRUE
) / (72. * 20.),
7056 .5 + height
* gnm_app_display_dpi_get (FALSE
) / (72. * 20.));
7058 if (options
& 0x0001)
7059 g_printerr ("Unsupported: Hidden workbook\n");
7060 if (options
& 0x0002)
7061 g_printerr ("Unsupported: Iconic workbook\n");
7063 g_object_set (G_OBJECT (wb_view
),
7064 "show-horizontal-scrollbar", !!(options
& 0x0008),
7065 "show-vertical-scrollbar", !!(options
& 0x0010),
7066 "show-notebook-tabs", !!(options
& 0x0020),
7072 excel_read_BOF (BiffQuery
*q
,
7073 GnmXLImporter
*importer
,
7074 WorkbookView
*wb_view
,
7075 GOIOContext
*context
,
7076 MsBiffBofData
**version
, unsigned *current_sheet
)
7078 /* The first BOF seems to be OK, the rest lie ? */
7079 MsBiffVersion vv
= MS_BIFF_V_UNKNOWN
;
7080 MsBiffBofData
*ver
= *version
;
7081 char const *version_desc
= NULL
;
7085 ms_biff_bof_data_destroy (ver
);
7087 *version
= ver
= ms_biff_bof_data_new (q
);
7088 if (vv
!= MS_BIFF_V_UNKNOWN
)
7091 if (ver
->type
== MS_BIFF_TYPE_Workbook
) {
7092 gnm_xl_importer_set_version (importer
, ver
->version
);
7093 if (ver
->version
>= MS_BIFF_V8
) {
7095 XL_CHECK_CONDITION (q
->length
>= 8);
7096 ver
= GSF_LE_GET_GUINT32 (q
->data
+ 4);
7097 if (ver
== 0x4107cd18)
7098 version_desc
= "Excel 2000 ?";
7100 version_desc
= "Excel 97 +";
7101 } else if (ver
->version
>= MS_BIFF_V7
)
7102 version_desc
= "Excel 95";
7103 else if (ver
->version
>= MS_BIFF_V5
)
7104 version_desc
= "Excel 5.x";
7105 else if (ver
->version
>= MS_BIFF_V4
)
7106 version_desc
= "Excel 4.x";
7107 else if (ver
->version
>= MS_BIFF_V3
)
7108 version_desc
= "Excel 3.x - shouldn't happen";
7109 else if (ver
->version
>= MS_BIFF_V2
)
7110 version_desc
= "Excel 2.x - shouldn't happen";
7111 } else if (ver
->type
== MS_BIFF_TYPE_Worksheet
||
7112 ver
->type
== MS_BIFF_TYPE_Chart
) {
7113 BiffBoundsheetData
*bs
= g_hash_table_lookup (
7114 importer
->boundsheet_data_by_stream
, GINT_TO_POINTER (q
->streamPos
));
7115 ExcelReadSheet
*esheet
;
7117 if (ver
->version
> MS_BIFF_V4
) /* be anal */
7118 g_printerr ("Sheet offset in stream of 0x%lx not found in list\n",
7119 (long)q
->streamPos
);
7120 if (*current_sheet
>= importer
->excel_sheets
->len
) {
7121 esheet
= excel_sheet_new (importer
, "Worksheet", GNM_SHEET_DATA
);
7122 /* Top level worksheets existed up to & including 4.x */
7123 gnm_xl_importer_set_version (importer
, ver
->version
);
7124 if (ver
->version
>= MS_BIFF_V5
)
7125 version_desc
= ">= Excel 5 with no BOUNDSHEET ?? - shouldn't happen";
7126 else if (ver
->version
>= MS_BIFF_V4
)
7127 version_desc
= "Excel 4.x single worksheet";
7128 else if (ver
->version
>= MS_BIFF_V3
)
7129 version_desc
= "Excel 3.x single worksheet";
7130 else if (ver
->version
>= MS_BIFF_V2
)
7131 version_desc
= "Excel 2.x single worksheet";
7133 esheet
= g_ptr_array_index (importer
->excel_sheets
, *current_sheet
);
7135 esheet
= bs
->esheet
;
7137 g_return_if_fail (esheet
!= NULL
);
7140 if (ver
->type
== MS_BIFF_TYPE_Worksheet
) {
7141 excel_read_sheet (q
, importer
, wb_view
, esheet
);
7142 ms_container_realize_objs (sheet_container (esheet
));
7143 /* reverse the sheet objects satck order */
7144 esheet
->sheet
->sheet_objects
= g_slist_reverse (esheet
->sheet
->sheet_objects
);
7146 SheetObject
*obj
= sheet_object_graph_new (NULL
);
7147 ms_excel_chart_read (q
, sheet_container (esheet
),
7148 obj
, esheet
->sheet
);
7149 sheet_object_set_sheet (obj
, esheet
->sheet
);
7150 g_object_unref (obj
);
7153 } else if (ver
->type
== MS_BIFF_TYPE_VBModule
||
7154 ver
->type
== MS_BIFF_TYPE_Macrosheet
) {
7155 /* Skip contents of Module, or MacroSheet */
7156 if (ver
->type
!= MS_BIFF_TYPE_Macrosheet
)
7157 version_desc
= "VB Module";
7160 version_desc
= "XLM Macrosheet";
7163 while (ms_biff_query_next (q
) && q
->opcode
!= BIFF_EOF
)
7164 d (5, ms_biff_query_dump (q
););
7165 if (q
->opcode
!= BIFF_EOF
)
7166 g_warning ("EXCEL: file format error. Missing BIFF_EOF");
7167 } else if (ver
->type
== MS_BIFF_TYPE_Workspace
) {
7168 /* Multiple sheets, XLW format from Excel 4.0 */
7169 version_desc
= "Excel 4.x workbook";
7170 gnm_xl_importer_set_version (importer
, ver
->version
);
7172 g_printerr ("Unknown BOF (%x)\n", ver
->type
);
7174 if (NULL
!= version_desc
) {
7175 d (1, g_printerr ("%s\n", version_desc
););
7180 excel_read_CODEPAGE (BiffQuery
*q
, GnmXLImporter
*importer
)
7182 /* This seems to appear within a workbook */
7183 /* MW: And on Excel seems to drive the display
7184 of currency amounts. */
7185 XL_CHECK_CONDITION (q
->length
>= 2);
7186 gnm_xl_importer_set_codepage (importer
,
7187 GSF_LE_GET_GUINT16 (q
->data
));
7191 excel_read_RECALCID (BiffQuery
*q
, GnmXLImporter
*importer
)
7195 XL_CHECK_CONDITION (q
->length
>= 8);
7196 engine
= GSF_LE_GET_GUINT32 (q
->data
+ 4);
7202 excel_read_UNCALCED (BiffQuery
*q
, GnmXLImporter
*importer
)
7207 excel_read_workbook (GOIOContext
*context
, WorkbookView
*wb_view
,
7209 gboolean
*is_double_stream_file
,
7210 char const *opt_enc
)
7212 GnmXLImporter
*importer
;
7214 MsBiffBofData
*ver
= NULL
;
7215 unsigned current_sheet
= 0;
7216 const char *problem_loading
= NULL
;
7217 gboolean stop_loading
= FALSE
;
7218 gboolean prev_was_eof
= FALSE
;
7220 go_io_progress_message (context
, _("Reading file..."));
7221 go_io_value_progress_set (context
, gsf_input_size (input
), N_BYTES_BETWEEN_PROGRESS_UPDATES
);
7222 q
= ms_biff_query_new (input
);
7224 importer
= gnm_xl_importer_new (context
, wb_view
, opt_enc
);
7226 *is_double_stream_file
= FALSE
;
7227 if (ms_biff_query_next (q
) &&
7228 (q
->opcode
== BIFF_BOF_v0
||
7229 q
->opcode
== BIFF_BOF_v2
||
7230 q
->opcode
== BIFF_BOF_v4
||
7231 q
->opcode
== BIFF_BOF_v8
))
7232 excel_read_BOF (q
, importer
, wb_view
, context
,
7233 &ver
, ¤t_sheet
);
7234 while (!stop_loading
&& /* we have not hit the end */
7235 problem_loading
== NULL
&& /* there were no problems so far */
7236 ms_biff_query_next (q
)) { /* we can load the record */
7239 const char *opname
= biff_opcode_name (q
->opcode
);
7240 g_printerr ("Opcode: 0x%x %s\n",
7242 opname
? opname
: "unknown");
7245 switch (q
->opcode
) {
7250 excel_read_BOF (q
, importer
, wb_view
, context
, &ver
, ¤t_sheet
);
7254 prev_was_eof
= TRUE
;
7255 d (0, g_printerr ("End of worksheet spec.\n"););
7259 case BIFF_FONT_v2
: excel_read_FONT (q
, importer
); break;
7260 case BIFF_WINDOW1
: excel_read_WINDOW1 (q
, wb_view
); break;
7261 case BIFF_BOUNDSHEET
: excel_read_BOUNDSHEET (q
, importer
); break;
7262 case BIFF_PALETTE
: excel_read_PALETTE (q
, importer
); break;
7264 case BIFF_XF_OLD_v0
:
7265 case BIFF_XF_OLD_v2
:
7266 case BIFF_XF_OLD_v4
: excel_read_XF_OLD (q
, importer
); break;
7267 case BIFF_XF
: excel_read_XF (q
, importer
); break;
7269 case BIFF_EXTERNCOUNT
: /* ignore */ break;
7270 case BIFF_EXTERNSHEET
:
7271 excel_read_EXTERNSHEET (q
, importer
, ver
);
7274 case BIFF_PRECISION
: {
7276 /* FIXME: implement in gnumeric */
7277 /* state of 'Precision as Displayed' option */
7278 guint16
const data
= GSF_LE_GET_GUINT16 (q
->data
);
7279 gboolean
const prec_as_displayed
= (data
== 0);
7284 case BIFF_FORMAT_v0
:
7285 case BIFF_FORMAT_v4
: excel_read_FORMAT (q
, importer
); break;
7287 case BIFF_BACKUP
: break;
7288 case BIFF_CODEPAGE
: /* DUPLICATE 42 */
7289 excel_read_CODEPAGE (q
, importer
);
7292 case BIFF_OBJPROTECT
:
7294 excel_read_workbook_PROTECT (q
, wb_view
);
7300 case BIFF_FILEPASS
: /* All records after this are encrypted */
7301 problem_loading
= excel_read_FILEPASS(q
, importer
);
7307 case BIFF_WINDOWPROTECT
:
7310 case BIFF_EXTERNNAME_v0
:
7311 case BIFF_EXTERNNAME_v2
: excel_read_EXTERNNAME (q
, &importer
->container
); break;
7313 case BIFF_NAME_v2
: excel_read_NAME (q
, importer
, NULL
); break;
7314 case BIFF_XCT
: excel_read_XCT (q
, importer
); break;
7316 case BIFF_WRITEACCESS
:
7319 case BIFF_HIDEOBJ
: break;
7320 case BIFF_FNGROUPCOUNT
: break;
7321 case BIFF_MMS
: break;
7323 /* Flags that the project has some VBA */
7324 case BIFF_OBPROJ
: break;
7325 case BIFF_BOOKBOOL
: break;
7326 case BIFF_COUNTRY
: break;
7327 case BIFF_INTERFACEHDR
: break;
7328 case BIFF_INTERFACEEND
: break;
7329 case BIFF_TOOLBARHDR
: break;
7330 case BIFF_TOOLBAREND
: break;
7332 case BIFF_1904
: excel_read_1904 (q
, importer
); break;
7334 case BIFF_SELECTION
: /* 0, NOT 10 */
7337 case BIFF_DIMENSIONS_v0
:
7338 /* Ignore files that pad the end with zeros */
7340 stop_loading
= TRUE
;
7344 case BIFF_DIMENSIONS_v2
:
7345 excel_read_DIMENSIONS (q
, NULL
);
7348 case BIFF_OBJ
: ms_read_OBJ (q
, &importer
->container
, NULL
); break;
7349 case BIFF_SCL
: break;
7350 case BIFF_TABIDCONF
: break;
7351 case BIFF_MS_O_DRAWING
:
7352 case BIFF_MS_O_DRAWING_GROUP
:
7353 case BIFF_MS_O_DRAWING_SELECTION
:
7354 ms_escher_parse (q
, &importer
->container
, FALSE
);
7358 d (1, g_printerr ("%smenu with %d sub items",
7359 (GSF_LE_GET_GUINT8 (q
->data
+ 6) == 1) ? "" : "Placeholder ",
7360 GSF_LE_GET_GUINT8 (q
->data
+ 5)););
7363 case BIFF_SST
: excel_read_SST (q
, importer
); break;
7364 case BIFF_EXTSST
: excel_read_EXSST (q
, importer
); break;
7366 case BIFF_DSF
: /* stored in the biff8 workbook */
7367 case BIFF_XL5MODIFY
: /* stored in the biff5/7 book */
7369 gboolean dsf
= (q
->length
>= 2 &&
7370 GSF_LE_GET_GUINT16 (q
->data
));
7371 d (0, g_printerr ("Double stream file : %d\n",
7374 *is_double_stream_file
= TRUE
;
7379 d (0, g_printerr ("%s\n", "XL 2000 file"););
7382 case BIFF_RECALCID
: excel_read_RECALCID (q
, importer
); break;
7383 case BIFF_UNCALCED
: excel_read_UNCALCED (q
, importer
); break;
7384 case BIFF_REFRESHALL
: break;
7385 case BIFF_CODENAME
: excel_read_CODENAME (q
, importer
, NULL
); break;
7386 case BIFF_PROT4REVPASS
: break;
7388 case BIFF_USESELFS
: break;
7389 case BIFF_TABID
: break;
7394 case BIFF_SUPBOOK
: excel_read_SUPBOOK (q
, importer
); break;
7396 case BIFF_SXStreamID
: xls_read_SXStreamID (importer
, q
, gsf_input_container (input
)); break;
7399 excel_unexpected_biff (q
, "Workbook", ms_excel_read_debug
);
7402 /* check here in case any of the handlers read additional records */
7403 prev_was_eof
= (q
->opcode
== BIFF_EOF
);
7406 ms_biff_query_destroy (q
);
7408 ms_biff_bof_data_destroy (ver
);
7409 go_io_progress_unset (context
);
7411 d (1, g_printerr ("finished read\n"););
7413 gnm_xl_importer_free (importer
);
7415 /* If we were forced to stop then the load failed */
7416 if (problem_loading
!= NULL
)
7417 go_cmd_context_error_import (GO_CMD_CONTEXT (context
), problem_loading
);
7421 static GSList
*formats
;
7424 * These are special in that they appear to be saved as macros.
7425 * Excel will only recognize them when saved as macros: neither
7426 * externname as "IFERROR" nor "_xlfn.IFERROR" will work.
7428 static const ExcelFuncDesc excel97_func_desc
[] = {
7429 { 0xff, "_xlfn.AVERAGEIF", -1, -1, XL_XLM
},
7430 { 0xff, "_xlfn.AVERAGEIFS", -1, -1, XL_XLM
},
7431 { 0xff, "_xlfn.CUBEKPIMEMBER", -1, -1, XL_XLM
},
7432 { 0xff, "_xlfn.CUBEMEMBER", -1, -1, XL_XLM
},
7433 { 0xff, "_xlfn.CUBEMEMBERPROPERTY", -1, -1, XL_XLM
},
7434 { 0xff, "_xlfn.CUBERANKEDMEMBER", -1, -1, XL_XLM
},
7435 { 0xff, "_xlfn.CUBESET", -1, -1, XL_XLM
},
7436 { 0xff, "_xlfn.CUBESETCOUNT", -1, -1, XL_XLM
},
7437 { 0xff, "_xlfn.CUBEVALUE", -1, -1, XL_XLM
},
7438 { 0xff, "_xlfn.COUNTIFS", -1, -1, XL_XLM
},
7439 { 0xff, "_xlfn.IFERROR", 2, 2, XL_XLM
, 2, 'V', "VV" },
7440 { 0xff, "_xlfn.SUMIFS", -1, -1, XL_XLM
}
7444 excel_read_init (void)
7447 int mbd
= go_locale_month_before_day ();
7450 fmt
= go_format_new_magic (GO_FORMAT_MAGIC_SHORT_DATE
);
7451 formats
= g_slist_prepend (formats
, fmt
);
7452 excel_builtin_formats
[0x0e] = go_format_as_XL (fmt
);
7454 fmt
= go_format_new_magic (GO_FORMAT_MAGIC_MEDIUM_DATE
);
7455 formats
= g_slist_prepend (formats
, fmt
);
7456 excel_builtin_formats
[0x0f] = go_format_as_XL (fmt
);
7458 /* Doesn't seem to have a name. */
7459 excel_builtin_formats
[0x10] = mbd
? "d-mmm" : "mmm-d";
7461 fmt
= go_format_new_magic (GO_FORMAT_MAGIC_SHORT_DATETIME
);
7462 formats
= g_slist_prepend (formats
, fmt
);
7463 excel_builtin_formats
[0x16] = go_format_as_XL (fmt
);
7465 excel_func_by_name
= g_hash_table_new (g_str_hash
, g_str_equal
);
7466 for (i
= 0; i
< excel_func_desc_size
; i
++) {
7467 const ExcelFuncDesc
*efd
= excel_func_desc
+ i
;
7468 const char *name
= efd
->name
;
7469 GnmFunc
*func
= gnm_func_lookup (name
, NULL
);
7473 name
= gnm_func_get_name (func
, FALSE
);
7475 g_assert (g_hash_table_lookup (excel_func_by_name
, name
) ==
7477 g_hash_table_insert (excel_func_by_name
,
7482 for (i
= 0; i
< (int)G_N_ELEMENTS(excel97_func_desc
); i
++) {
7483 const ExcelFuncDesc
*efd
= excel97_func_desc
+ i
;
7484 const char *excel_name
= efd
->name
;
7485 const char *gnm_name
= strchr (excel_name
, '.') + 1;
7486 GnmFunc
*func
= gnm_func_lookup (gnm_name
, NULL
);
7490 gnm_name
= gnm_func_get_name (func
, FALSE
);
7492 g_assert (g_hash_table_lookup (excel_func_by_name
, gnm_name
) ==
7494 g_hash_table_insert (excel_func_by_name
,
7499 empty_attr_list
= pango_attr_list_new ();
7503 excel_read_cleanup (void)
7505 g_hash_table_destroy (excel_func_by_name
);
7506 excel_func_by_name
= NULL
;
7508 g_slist_free_full (formats
, (GDestroyNotify
)go_format_unref
);
7511 pango_attr_list_unref (empty_attr_list
);
7512 empty_attr_list
= NULL
;