1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * boot.c: the external interface to the MS Excel import/export
6 * Copyright (C) 2000-2007 Jody Goldberg (jody@gnome.org)
7 * Copyright (C) 1998-2001 Michael Meeks (miguel@kernel.org)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) version 3.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
24 #include <gnumeric-config.h>
27 #include "libgnumeric.h"
28 #include "command-context.h"
29 #include "workbook-view.h"
31 #include "gnm-plugin.h"
34 #include "ms-excel-write.h"
36 #include "ms-excel-util.h"
37 #include "ms-excel-read.h"
39 #include <goffice/goffice.h>
40 #include <gsf/gsf-input.h>
41 #include <gsf/gsf-infile.h>
42 #include <gsf/gsf-infile-msole.h>
43 #include <gsf/gsf-infile-msvba.h>
44 #include <gsf/gsf-msole-utils.h>
45 #include <gsf/gsf-output-stdio.h>
46 #include <gsf/gsf-outfile.h>
47 #include <gsf/gsf-outfile-msole.h>
48 #include <gsf/gsf-structured-blob.h>
49 #include <glib/gi18n-lib.h>
52 GNM_PLUGIN_MODULE_HEADER
;
54 /* Used to toggle debug messages on & off */
57 * 0 = quiet, no experimental features.
58 * 1 = enable experimental features
59 * >1 increasing levels of detail.
61 gint ms_excel_read_debug
= 0;
62 gint ms_excel_pivot_debug
= 0;
63 gint ms_excel_escher_debug
= 0;
64 gint ms_excel_formula_debug
= 0;
65 gint ms_excel_chart_debug
= 0;
66 gint ms_excel_write_debug
= 0;
67 gint ms_excel_object_debug
= 0;
69 gboolean
excel_file_probe (GOFileOpener
const *fo
, GsfInput
*input
, GOFileProbeLevel pl
);
70 void excel_file_open (GOFileOpener
const *fo
, GOIOContext
*context
, WorkbookView
*wbv
, GsfInput
*input
);
71 void excel_enc_file_open (GOFileOpener
const *fo
, char const *enc
, GOIOContext
*context
, WorkbookView
*wbv
, GsfInput
*input
);
72 void excel_biff7_file_save (GOFileSaver
const *fs
, GOIOContext
*context
, WorkbookView
const *wbv
, GsfOutput
*output
);
73 void excel_biff8_file_save (GOFileSaver
const *fs
, GOIOContext
*context
, WorkbookView
const *wbv
, GsfOutput
*output
);
74 void excel_dsf_file_save (GOFileSaver
const *fs
, GOIOContext
*context
, WorkbookView
const *wbv
, GsfOutput
*output
);
77 find_content_stream (GsfInfile
*ole
, gboolean
*is_97
)
79 static char const * const stream_names
[] = {
80 "Workbook", "WORKBOOK", "workbook",
81 "Book", "BOOK", "book"
86 for (i
= 0 ; i
< G_N_ELEMENTS (stream_names
) ; i
++) {
87 stream
= gsf_infile_child_by_name (ole
, stream_names
[i
]);
99 excel_file_probe (GOFileOpener
const *fo
, GsfInput
*input
, GOFileProbeLevel pl
)
103 gboolean res
= FALSE
;
107 ole
= gsf_infile_msole_new (input
, NULL
);
108 if (ole
== NULL
) { /* Test for non-OLE BIFF file */
110 gsf_input_seek (input
, 0, G_SEEK_SET
);
111 data
= gsf_input_read (input
, 2, NULL
);
112 return data
&& data
[0] == 0x09 && (data
[1] & 0xf1) == 0;
115 stream
= find_content_stream (ole
, NULL
);
116 if (stream
!= NULL
) {
117 g_object_unref (stream
);
120 g_object_unref (ole
);
126 excel_read_metadata (GsfDocMetaData
*meta_data
, GsfInfile
*ole
, char const *name
,
127 GOIOContext
*context
)
129 GsfInput
*stream
= gsf_infile_child_by_name (ole
, name
);
131 if (stream
!= NULL
) {
132 GError
*err
= gsf_doc_meta_data_read_from_msole (meta_data
, stream
);
134 go_io_warning (context
, "%s", err
->message
);
138 g_object_unref (stream
);
144 cb_dump_vba (char const *name
, guint8
const *src_code
)
146 g_printerr ("<module name=\"%s\">\n<![CDATA[%s]]>\n</module>\n", name
, src_code
);
150 /* Service entry point */
152 excel_enc_file_open (GOFileOpener
const *fo
, char const *enc
, GOIOContext
*context
,
153 WorkbookView
*wbv
, GsfInput
*input
)
155 GsfInput
*stream
= NULL
;
157 GsfInfile
*ole
= gsf_infile_msole_new (input
, &err
);
158 Workbook
*wb
= wb_view_get_workbook (wbv
);
159 gboolean is_double_stream_file
, is_97
;
160 GsfDocMetaData
*meta_data
;
165 /* Test for non-OLE BIFF file */
166 gsf_input_seek (input
, 0, G_SEEK_SET
);
167 data
= gsf_input_read (input
, 2, NULL
);
168 if (data
&& data
[0] == 0x09 && (data
[1] & 0xf1) == 0) {
169 gsf_input_seek (input
, -2, G_SEEK_CUR
);
170 excel_read_workbook (context
, wbv
, input
,
171 &is_double_stream_file
, enc
);
172 /* NOTE : we lack a saver for the early formats */
173 g_clear_error (&err
);
177 /* OK, it really isn't an Excel file */
178 g_return_if_fail (err
!= NULL
);
179 go_cmd_context_error_import (GO_CMD_CONTEXT (context
),
185 stream
= find_content_stream (ole
, &is_97
);
186 if (stream
== NULL
) {
187 go_cmd_context_error_import (GO_CMD_CONTEXT (context
),
188 _("No Workbook or Book streams found."));
189 g_object_unref (ole
);
193 excel_read_workbook (context
, wbv
, stream
, &is_double_stream_file
, enc
);
194 g_object_unref (stream
);
196 meta_data
= gsf_doc_meta_data_new ();
197 excel_read_metadata (meta_data
, ole
, "\05SummaryInformation", context
);
198 excel_read_metadata (meta_data
, ole
, "\05DocumentSummaryInformation", context
);
199 go_doc_set_meta_data (GO_DOC (wb
), meta_data
);
200 g_object_unref (meta_data
);
202 /* See if there are any macros to keep around */
203 stream
= gsf_infile_child_by_name (ole
, "\01CompObj");
204 if (stream
!= NULL
) {
205 GsfInput
*macros
= gsf_infile_child_by_name (ole
, "_VBA_PROJECT_CUR");
206 if (macros
!= NULL
) {
207 GsfInput
*vba_child
= gsf_infile_child_by_name (GSF_INFILE (macros
), "VBA");
208 GsfInfile
*vba
= vba_child
209 ? gsf_infile_msvba_new (GSF_INFILE (vba_child
), NULL
)
211 GsfStructuredBlob
*blob
;
214 GHashTable
*modules
=
215 gsf_infile_msvba_steal_modules (GSF_INFILE_MSVBA (vba
));
216 if (NULL
!= modules
) {
218 g_hash_table_foreach (modules
,
219 (GHFunc
) cb_dump_vba
, NULL
);
221 g_object_set_data_full (G_OBJECT (wb
), "VBA",
222 modules
, (GDestroyNotify
) g_hash_table_destroy
);
224 g_object_unref (vba
);
227 g_object_unref (vba_child
);
229 blob
= gsf_structured_blob_read (stream
);
231 g_object_set_data_full (G_OBJECT (wb
),
232 "MS_EXCEL_COMPOBJ_STREAM",
233 blob
, g_object_unref
);
235 blob
= gsf_structured_blob_read (macros
);
237 g_object_set_data_full (G_OBJECT (wb
),
239 blob
, g_object_unref
);
241 g_object_unref (macros
);
243 g_object_unref (stream
);
246 stream
= gsf_infile_child_by_name (ole
, "\01Ole");
248 GsfStructuredBlob
*blob
= gsf_structured_blob_read (stream
);
250 g_object_set_data_full (G_OBJECT (wb
), "MS_EXCEL_OLE_STREAM",
251 blob
, g_object_unref
);
252 g_object_unref (stream
);
255 g_object_unref (ole
);
257 /* simple guess of format based on stream names */
258 if (is_double_stream_file
)
259 workbook_set_saveinfo (wb
, GO_FILE_FL_AUTO
,
260 go_file_saver_for_id ("Gnumeric_Excel:excel_dsf"));
262 workbook_set_saveinfo (wb
, GO_FILE_FL_AUTO
,
263 go_file_saver_for_id ("Gnumeric_Excel:excel_biff8"));
265 workbook_set_saveinfo (wb
, GO_FILE_FL_AUTO
,
266 go_file_saver_for_id ("Gnumeric_Excel:excel_biff7"));
270 excel_file_open (GOFileOpener
const *fo
, GOIOContext
*context
,
271 WorkbookView
*wbv
, GsfInput
*input
)
273 excel_enc_file_open (fo
, NULL
, context
, wbv
, input
);
277 excel_save (GOIOContext
*context
, WorkbookView
const *wbv
, GsfOutput
*output
,
278 gboolean biff7
, gboolean biff8
)
283 ExcelWriteState
*ewb
= NULL
;
284 GsfStructuredBlob
*blob
;
285 GsfDocMetaData
*meta_data
;
287 go_io_progress_message (context
, _("Preparing to save..."));
288 go_io_progress_range_push (context
, 0.0, 0.1);
289 ewb
= excel_write_state_new (context
, wbv
, biff7
, biff8
);
290 go_io_progress_range_pop (context
);
294 wb
= wb_view_get_workbook (wbv
);
295 outfile
= gsf_outfile_msole_new (output
);
296 ewb
->export_macros
= (biff8
&&
297 NULL
!= g_object_get_data (G_OBJECT (wb
), "MS_EXCEL_MACROS"));
299 go_io_progress_message (context
, _("Saving file..."));
300 go_io_progress_range_push (context
, 0.1, 1.0);
302 excel_write_v7 (ewb
, outfile
);
304 excel_write_v8 (ewb
, outfile
);
305 excel_write_state_free (ewb
);
306 go_io_progress_range_pop (context
);
308 meta_data
= go_doc_get_meta_data (GO_DOC (wb
));
309 if (meta_data
!= NULL
) {
310 content
= gsf_outfile_new_child (outfile
,
311 "\05DocumentSummaryInformation", FALSE
);
312 gsf_doc_meta_data_write_to_msole (meta_data
, content
, TRUE
);
313 gsf_output_close (content
);
314 g_object_unref (content
);
316 content
= gsf_outfile_new_child (outfile
,
317 "\05SummaryInformation", FALSE
);
318 gsf_doc_meta_data_write_to_msole (meta_data
, content
, FALSE
);
319 gsf_output_close (content
);
320 g_object_unref (content
);
323 /* restore the macros we loaded */
324 blob
= g_object_get_data (G_OBJECT (wb
), "MS_EXCEL_COMPOBJ_STREAM");
326 gsf_structured_blob_write (blob
, outfile
);
328 blob
= g_object_get_data (G_OBJECT (wb
), "MS_EXCEL_OLE_STREAM");
330 gsf_structured_blob_write (blob
, outfile
);
332 blob
= g_object_get_data (G_OBJECT (wb
), "MS_EXCEL_MACROS");
334 gsf_structured_blob_write (blob
, outfile
);
336 gsf_output_close (GSF_OUTPUT (outfile
));
337 g_object_unref (outfile
);
341 excel_dsf_file_save (GOFileSaver
const *fs
, GOIOContext
*context
,
342 WorkbookView
const *wbv
, GsfOutput
*output
)
344 excel_save (context
, wbv
, output
, TRUE
, TRUE
);
347 excel_biff8_file_save (GOFileSaver
const *fs
, GOIOContext
*context
,
348 WorkbookView
const *wbv
, GsfOutput
*output
)
350 excel_save (context
, wbv
, output
, FALSE
, TRUE
);
354 excel_biff7_file_save (GOFileSaver
const *fs
, GOIOContext
*context
,
355 WorkbookView
const *wbv
, GsfOutput
*output
)
357 excel_save (context
, wbv
, output
, TRUE
, FALSE
);
361 #include <formula-types.h>
363 go_plugin_init (GOPlugin
*plugin
, GOCmdContext
*cc
)
372 for (i
= 0 ; i
< excel_func_desc_size
; i
++) {
373 ExcelFuncDesc
const *fd
= excel_func_desc
+ i
;
375 if (fd
->flags
& (XL_UNKNOWN
| XL_MAGIC
))
377 if (fd
->flags
& XL_XLM
) {
378 if (fd
->flags
!= XL_XLM
)
379 g_printerr ("%s : flags in addition to XLM\n", name
);
380 if (fd
->min_args
!= fd
->max_args
)
381 g_printerr ("%s : min != max\n", name
);
384 if (fd
->min_args
< 0)
385 g_printerr ("%s : min_args < 0\n", name
);
386 if (fd
->max_args
< 0)
387 g_printerr ("%s : min_args < 0\n", name
);
388 if (fd
->known_args
!= NULL
&&
389 fd
->num_known_args
!= strlen (fd
->known_args
))
390 g_printerr ("%s : num_expected_args inconsistent\n", name
);
397 * Cleanup allocations made by this plugin.
398 * (Called right before we are unloaded.)
401 go_plugin_shutdown (GOPlugin
*plugin
, GOCmdContext
*cc
)
403 destroy_xl_font_widths ();
404 excel_read_cleanup ();