writeexcel 0.6.6 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +0 -0
- data/.gitattributes +0 -0
- data/README.rdoc +9 -35
- data/Rakefile +0 -0
- data/VERSION +1 -1
- data/charts/chartex.rb +0 -0
- data/charts/demo1.rb +0 -0
- data/charts/demo101.bin +0 -0
- data/charts/demo2.rb +0 -0
- data/charts/demo201.bin +0 -0
- data/charts/demo3.rb +0 -0
- data/charts/demo301.bin +0 -0
- data/charts/demo4.rb +0 -0
- data/charts/demo401.bin +0 -0
- data/charts/demo5.rb +0 -0
- data/charts/demo501.bin +0 -0
- data/examples/a_simple.rb +0 -0
- data/examples/autofilter.rb +0 -0
- data/examples/bigfile.rb +0 -0
- data/examples/chart_area.rb +0 -0
- data/examples/chart_bar.rb +0 -0
- data/examples/chart_column.rb +0 -0
- data/examples/chart_line.rb +0 -0
- data/examples/chart_pie.rb +0 -0
- data/examples/chart_scatter.rb +0 -0
- data/examples/chart_stock.rb +0 -0
- data/examples/chess.rb +0 -0
- data/examples/colors.rb +0 -0
- data/examples/comments1.rb +0 -0
- data/examples/comments2.rb +0 -0
- data/examples/copyformat.rb +0 -0
- data/examples/data_validate.rb +0 -0
- data/examples/date_time.rb +0 -0
- data/examples/defined_name.rb +0 -0
- data/examples/demo.rb +0 -0
- data/examples/diag_border.rb +0 -0
- data/examples/formats.rb +0 -0
- data/examples/formula_result.rb +0 -0
- data/examples/header.rb +0 -0
- data/examples/hide_sheet.rb +0 -0
- data/examples/hyperlink.rb +0 -0
- data/examples/images.rb +0 -0
- data/examples/indent.rb +0 -0
- data/examples/merge1.rb +0 -0
- data/examples/merge2.rb +0 -0
- data/examples/merge3.rb +0 -0
- data/examples/merge4.rb +0 -0
- data/examples/merge5.rb +0 -0
- data/examples/merge6.rb +0 -0
- data/examples/outline.rb +0 -0
- data/examples/outline_collapsed.rb +0 -0
- data/examples/panes.rb +0 -0
- data/examples/properties.rb +0 -0
- data/examples/properties_jp.rb +0 -0
- data/examples/protection.rb +0 -0
- data/examples/regions.rb +0 -0
- data/examples/repeat.rb +0 -0
- data/examples/republic.png +0 -0
- data/examples/right_to_left.rb +0 -0
- data/examples/row_wrap.rb +0 -0
- data/examples/set_first_sheet.rb +14 -0
- data/examples/stats.rb +0 -0
- data/examples/stocks.rb +0 -0
- data/examples/tab_colors.rb +0 -0
- data/examples/utf8.rb +0 -0
- data/examples/write_arrays.rb +0 -0
- data/html/en/doc_en.html +5941 -0
- data/html/images/a_simple.jpg +0 -0
- data/html/images/area1.jpg +0 -0
- data/html/images/bar1.jpg +0 -0
- data/html/images/chart_area.xls +0 -0
- data/html/images/column1.jpg +0 -0
- data/html/images/data_validation.jpg +0 -0
- data/html/images/line1.jpg +0 -0
- data/html/images/pie1.jpg +0 -0
- data/html/images/regions.jpg +0 -0
- data/html/images/scatter1.jpg +0 -0
- data/html/images/stats.jpg +0 -0
- data/html/images/stock1.jpg +0 -0
- data/html/images/stocks.jpg +0 -0
- data/html/index.html +16 -0
- data/html/style.css +433 -0
- data/lib/writeexcel/biffwriter.rb +5 -0
- data/lib/writeexcel/caller_info.rb +0 -0
- data/lib/writeexcel/chart.rb +8 -219
- data/lib/writeexcel/charts/area.rb +0 -0
- data/lib/writeexcel/charts/bar.rb +0 -0
- data/lib/writeexcel/charts/column.rb +0 -0
- data/lib/writeexcel/charts/external.rb +0 -0
- data/lib/writeexcel/charts/line.rb +0 -0
- data/lib/writeexcel/charts/pie.rb +0 -0
- data/lib/writeexcel/charts/scatter.rb +0 -0
- data/lib/writeexcel/charts/stock.rb +0 -0
- data/lib/writeexcel/colors.rb +4 -0
- data/lib/writeexcel/compatibility.rb +0 -0
- data/lib/writeexcel/debug_info.rb +0 -0
- data/lib/writeexcel/excelformula.y +0 -0
- data/lib/writeexcel/excelformulaparser.rb +0 -0
- data/lib/writeexcel/format.rb +2 -28
- data/lib/writeexcel/formula.rb +4 -70
- data/lib/writeexcel/helper.rb +0 -0
- data/lib/writeexcel/image.rb +158 -0
- data/lib/writeexcel/olewriter.rb +0 -0
- data/lib/writeexcel/properties.rb +0 -0
- data/lib/writeexcel/storage_lite.rb +0 -0
- data/lib/writeexcel/workbook.rb +434 -824
- data/lib/writeexcel/worksheet.rb +4194 -4718
- data/lib/writeexcel/write_file.rb +0 -0
- data/lib/writeexcel.rb +0 -0
- data/test/excelfile/Chart1.xls +0 -0
- data/test/excelfile/Chart2.xls +0 -0
- data/test/excelfile/Chart3.xls +0 -0
- data/test/excelfile/Chart4.xls +0 -0
- data/test/excelfile/Chart5.xls +0 -0
- data/test/helper.rb +0 -0
- data/test/perl_output/Chart1.xls.data +0 -0
- data/test/perl_output/Chart2.xls.data +0 -0
- data/test/perl_output/Chart3.xls.data +0 -0
- data/test/perl_output/Chart4.xls.data +0 -0
- data/test/perl_output/Chart5.xls.data +0 -0
- data/test/perl_output/README +0 -0
- data/test/perl_output/a_simple.xls +0 -0
- data/test/perl_output/autofilter.xls +0 -0
- data/test/perl_output/biff_add_continue_testdata +0 -0
- data/test/perl_output/chart_area.xls +0 -0
- data/test/perl_output/chart_bar.xls +0 -0
- data/test/perl_output/chart_column.xls +0 -0
- data/test/perl_output/chart_line.xls +0 -0
- data/test/perl_output/chess.xls +0 -0
- data/test/perl_output/colors.xls +0 -0
- data/test/perl_output/comments1.xls +0 -0
- data/test/perl_output/comments2.xls +0 -0
- data/test/perl_output/data_validate.xls +0 -0
- data/test/perl_output/date_time.xls +0 -0
- data/test/perl_output/defined_name.xls +0 -0
- data/test/perl_output/demo.xls +0 -0
- data/test/perl_output/demo101.bin +0 -0
- data/test/perl_output/demo201.bin +0 -0
- data/test/perl_output/demo301.bin +0 -0
- data/test/perl_output/demo401.bin +0 -0
- data/test/perl_output/demo501.bin +0 -0
- data/test/perl_output/diag_border.xls +0 -0
- data/test/perl_output/f_font_biff +0 -0
- data/test/perl_output/f_font_key +0 -0
- data/test/perl_output/f_xf_biff +0 -0
- data/test/perl_output/file_font_biff +0 -0
- data/test/perl_output/file_font_key +0 -0
- data/test/perl_output/file_xf_biff +0 -0
- data/test/perl_output/formula_result.xls +0 -0
- data/test/perl_output/headers.xls +0 -0
- data/test/perl_output/hidden.xls +0 -0
- data/test/perl_output/hide_zero.xls +0 -0
- data/test/perl_output/hyperlink.xls +0 -0
- data/test/perl_output/images.xls +0 -0
- data/test/perl_output/indent.xls +0 -0
- data/test/perl_output/merge1.xls +0 -0
- data/test/perl_output/merge2.xls +0 -0
- data/test/perl_output/merge3.xls +0 -0
- data/test/perl_output/merge4.xls +0 -0
- data/test/perl_output/merge5.xls +0 -0
- data/test/perl_output/merge6.xls +0 -0
- data/test/perl_output/ole_write_header +0 -0
- data/test/perl_output/outline.xls +0 -0
- data/test/perl_output/outline_collapsed.xls +0 -0
- data/test/perl_output/panes.xls +0 -0
- data/test/perl_output/protection.xls +0 -0
- data/test/perl_output/regions.xls +0 -0
- data/test/perl_output/right_to_left.xls +0 -0
- data/test/perl_output/set_first_sheet.xls +0 -0
- data/test/perl_output/stats.xls +0 -0
- data/test/perl_output/stocks.xls +0 -0
- data/test/perl_output/tab_colors.xls +0 -0
- data/test/perl_output/unicode_cyrillic.xls +0 -0
- data/test/perl_output/utf8.xls +0 -0
- data/test/perl_output/workbook1.xls +0 -0
- data/test/perl_output/workbook2.xls +0 -0
- data/test/perl_output/ws_colinfo +0 -0
- data/test/perl_output/ws_store_colinfo +0 -0
- data/test/perl_output/ws_store_dimensions +0 -0
- data/test/perl_output/ws_store_filtermode +0 -0
- data/test/perl_output/ws_store_filtermode_off +0 -0
- data/test/perl_output/ws_store_filtermode_on +0 -0
- data/test/perl_output/ws_store_selection +0 -0
- data/test/perl_output/ws_store_window2 +0 -0
- data/test/republic.png +0 -0
- data/test/test_00_IEEE_double.rb +0 -0
- data/test/test_01_add_worksheet.rb +0 -0
- data/test/test_02_merge_formats.rb +0 -0
- data/test/test_04_dimensions.rb +27 -27
- data/test/test_05_rows.rb +0 -0
- data/test/test_06_extsst.rb +1 -1
- data/test/test_11_date_time.rb +3 -3
- data/test/test_12_date_only.rb +7 -14
- data/test/test_13_date_seconds.rb +5 -5
- data/test/test_21_escher.rb +138 -138
- data/test/test_22_mso_drawing_group.rb +0 -0
- data/test/test_23_note.rb +4 -4
- data/test/test_24_txo.rb +3 -3
- data/test/test_25_position_object.rb +1 -1
- data/test/test_26_autofilter.rb +3 -3
- data/test/test_27_autofilter.rb +1 -1
- data/test/test_28_autofilter.rb +2 -2
- data/test/test_29_process_jpg.rb +16 -29
- data/test/test_30_validation_dval.rb +3 -3
- data/test/test_31_validation_dv_strings.rb +6 -6
- data/test/test_32_validation_dv_formula.rb +12 -12
- data/test/test_40_property_types.rb +0 -0
- data/test/test_41_properties.rb +0 -0
- data/test/test_42_set_properties.rb +0 -0
- data/test/test_50_name_stored.rb +8 -8
- data/test/test_51_name_print_area.rb +18 -18
- data/test/test_52_name_print_titles.rb +27 -27
- data/test/test_53_autofilter.rb +6 -6
- data/test/test_60_chart_generic.rb +1 -1
- data/test/test_61_chart_subclasses.rb +7 -14
- data/test/test_62_chart_formats.rb +0 -0
- data/test/test_63_chart_area_formats.rb +0 -0
- data/test/test_biff.rb +0 -0
- data/test/test_compatibility.rb +0 -0
- data/test/test_example_match.rb +31 -0
- data/test/test_format.rb +0 -0
- data/test/test_formula.rb +0 -0
- data/test/test_ole.rb +0 -0
- data/test/test_storage_lite.rb +0 -0
- data/test/test_workbook.rb +6 -0
- data/test/test_worksheet.rb +5 -5
- data/utils/add_magic_comment.rb +0 -0
- data/writeexcel.gemspec +263 -243
- data/writeexcel.rdoc +3 -3
- metadata +42 -39
data/lib/writeexcel/workbook.rb
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
# original written in Perl by John McNamara
|
|
12
12
|
# converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
|
|
13
13
|
#
|
|
14
|
-
require 'digest/md5'
|
|
15
14
|
require 'nkf'
|
|
16
15
|
require 'writeexcel/biffwriter'
|
|
17
16
|
require 'writeexcel/worksheet'
|
|
@@ -26,9 +25,11 @@ class Workbook < BIFFWriter
|
|
|
26
25
|
require 'writeexcel/properties'
|
|
27
26
|
require 'writeexcel/helper'
|
|
28
27
|
|
|
28
|
+
attr_reader :url_format, :parser, :tempdir, :date_1904
|
|
29
|
+
attr_reader :compatibility, :palette, :sinfo
|
|
30
|
+
|
|
29
31
|
BOF = 12 # :nodoc:
|
|
30
32
|
EOF = 4 # :nodoc:
|
|
31
|
-
SheetName = "Sheet" # :nodoc:
|
|
32
33
|
|
|
33
34
|
#
|
|
34
35
|
# _file_ is a filename (as string) or io object where to out spreadsheet data.
|
|
@@ -42,7 +43,7 @@ class Workbook < BIFFWriter
|
|
|
42
43
|
# worksheet = workbook.add_worksheet
|
|
43
44
|
# worksheet.write(0, 0, 'Hi Excel!')
|
|
44
45
|
#
|
|
45
|
-
# Here are some other examples of using new()
|
|
46
|
+
# Here are some other examples of using new():
|
|
46
47
|
#
|
|
47
48
|
# workbook1 = WriteExcel.new(filename)
|
|
48
49
|
# workbook2 = WriteExcel.new('/tmp/filename.xls')
|
|
@@ -57,13 +58,17 @@ class Workbook < BIFFWriter
|
|
|
57
58
|
# worksheets and store data.
|
|
58
59
|
#
|
|
59
60
|
# If the file cannot be created, due to file permissions or some other reason,
|
|
60
|
-
# new will
|
|
61
|
-
#
|
|
61
|
+
# new will raise Exception Errno::EXXX.
|
|
62
|
+
#
|
|
63
|
+
# You can also pass a valid IO object to the new() constructor.:
|
|
64
|
+
# require 'stringio'
|
|
65
|
+
#
|
|
66
|
+
# io = StringIO.new
|
|
67
|
+
# workbook = WriteExcel.new(io) # After workbook.close, you can get excel data as io.string
|
|
62
68
|
#
|
|
63
|
-
#
|
|
64
|
-
# die "Problems creating new Excel file:" if workbook.nil?
|
|
69
|
+
# And, you can also pass default format properties.
|
|
65
70
|
#
|
|
66
|
-
#
|
|
71
|
+
# workbook = WriteExcel.new(filename, :font => 'Courier New', :size => 11)
|
|
67
72
|
#
|
|
68
73
|
def initialize(file, default_formats = {})
|
|
69
74
|
super()
|
|
@@ -74,13 +79,9 @@ class Workbook < BIFFWriter
|
|
|
74
79
|
@date_1904 = false
|
|
75
80
|
@selected = 0
|
|
76
81
|
@xf_index = 0
|
|
77
|
-
@fileclosed = false
|
|
78
82
|
@biffsize = 0
|
|
79
|
-
@sheet_name = "Sheet"
|
|
80
|
-
@chart_name = "Chart"
|
|
81
83
|
@sheet_count = 0
|
|
82
84
|
@chart_count = 0
|
|
83
|
-
@url_format = ''
|
|
84
85
|
@codepage = 0x04E4
|
|
85
86
|
@country = 1
|
|
86
87
|
@worksheets = []
|
|
@@ -109,8 +110,7 @@ class Workbook < BIFFWriter
|
|
|
109
110
|
@mso_clusters = []
|
|
110
111
|
@mso_size = 0
|
|
111
112
|
|
|
112
|
-
@hideobj =
|
|
113
|
-
@compatibility = 0
|
|
113
|
+
@hideobj = false
|
|
114
114
|
|
|
115
115
|
@summary = ''
|
|
116
116
|
@doc_summary = ''
|
|
@@ -118,28 +118,7 @@ class Workbook < BIFFWriter
|
|
|
118
118
|
|
|
119
119
|
@defined_names = []
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
add_format(:type => 1) # 0 Normal
|
|
123
|
-
add_format(:type => 1) # 1 RowLevel 1
|
|
124
|
-
add_format(:type => 1) # 2 RowLevel 2
|
|
125
|
-
add_format(:type => 1) # 3 RowLevel 3
|
|
126
|
-
add_format(:type => 1) # 4 RowLevel 4
|
|
127
|
-
add_format(:type => 1) # 5 RowLevel 5
|
|
128
|
-
add_format(:type => 1) # 6 RowLevel 6
|
|
129
|
-
add_format(:type => 1) # 7 RowLevel 7
|
|
130
|
-
add_format(:type => 1) # 8 ColLevel 1
|
|
131
|
-
add_format(:type => 1) # 9 ColLevel 2
|
|
132
|
-
add_format(:type => 1) # 10 ColLevel 3
|
|
133
|
-
add_format(:type => 1) # 11 ColLevel 4
|
|
134
|
-
add_format(:type => 1) # 12 ColLevel 5
|
|
135
|
-
add_format(:type => 1) # 13 ColLevel 6
|
|
136
|
-
add_format(:type => 1) # 14 ColLevel 7
|
|
137
|
-
add_format(default_formats) # 15 Cell XF
|
|
138
|
-
add_format(:type => 1, :num_format => 0x2B) # 16 Comma
|
|
139
|
-
add_format(:type => 1, :num_format => 0x29) # 17 Comma[0]
|
|
140
|
-
add_format(:type => 1, :num_format => 0x2C) # 18 Currency
|
|
141
|
-
add_format(:type => 1, :num_format => 0x2A) # 19 Currency[0]
|
|
142
|
-
add_format(:type => 1, :num_format => 0x09) # 20 Percent
|
|
121
|
+
setup_built_in_formats(default_formats)
|
|
143
122
|
|
|
144
123
|
# Add the default format for hyperlinks
|
|
145
124
|
@url_format = add_format(:color => 'blue', :underline => 1)
|
|
@@ -153,25 +132,8 @@ class Workbook < BIFFWriter
|
|
|
153
132
|
|
|
154
133
|
# Set colour palette.
|
|
155
134
|
set_palette_xl97
|
|
156
|
-
|
|
157
|
-
get_checksum_method
|
|
158
135
|
end
|
|
159
136
|
|
|
160
|
-
###############################################################################
|
|
161
|
-
#
|
|
162
|
-
# get_checksum_method.
|
|
163
|
-
#
|
|
164
|
-
# Check for modules available to calculate image checksum. Excel uses MD4 but
|
|
165
|
-
# MD5 will also work.
|
|
166
|
-
#
|
|
167
|
-
# ------- cxn03651 add -------
|
|
168
|
-
# md5 can use in ruby. so, @checksum_method is always 3.
|
|
169
|
-
|
|
170
|
-
def get_checksum_method #:nodoc:
|
|
171
|
-
@checksum_method = 3
|
|
172
|
-
end
|
|
173
|
-
private :get_checksum_method
|
|
174
|
-
|
|
175
137
|
#
|
|
176
138
|
# Calls finalization methods and explicitly close the OLEwriter files
|
|
177
139
|
# handle.
|
|
@@ -184,7 +146,7 @@ class Workbook < BIFFWriter
|
|
|
184
146
|
# a file you need to call close().
|
|
185
147
|
#
|
|
186
148
|
def close
|
|
187
|
-
return if
|
|
149
|
+
return if fileclosed? # Prevent close() from being called twice.
|
|
188
150
|
|
|
189
151
|
@fileclosed = true
|
|
190
152
|
store_workbook
|
|
@@ -234,7 +196,7 @@ class Workbook < BIFFWriter
|
|
|
234
196
|
#
|
|
235
197
|
# Add a new worksheet to the Excel workbook.
|
|
236
198
|
#
|
|
237
|
-
# if _sheetname_ is UTF-16BE format, pass
|
|
199
|
+
# if _sheetname_ is UTF-16BE format, pass true as _name_utf16be_.
|
|
238
200
|
#
|
|
239
201
|
# At least one worksheet should be added to a new workbook. A worksheet is
|
|
240
202
|
# used to write data into cells:
|
|
@@ -259,30 +221,18 @@ class Workbook < BIFFWriter
|
|
|
259
221
|
# UTF-16BE worksheet names using an additional optional parameter:
|
|
260
222
|
#
|
|
261
223
|
# name = [0x263a].pack('n')
|
|
262
|
-
# worksheet = workbook.add_worksheet(name,
|
|
224
|
+
# worksheet = workbook.add_worksheet(name, true) # Smiley
|
|
263
225
|
#
|
|
264
|
-
def add_worksheet(sheetname = '',
|
|
226
|
+
def add_worksheet(sheetname = '', name_utf16be = false)
|
|
265
227
|
index = @worksheets.size
|
|
266
228
|
|
|
267
|
-
name,
|
|
229
|
+
name, name_utf16be = check_sheetname(sheetname, name_utf16be)
|
|
268
230
|
|
|
269
|
-
# Porters take note, the following scheme of passing references to Workbook
|
|
270
|
-
# data (in the \$self->{_foo} cases) instead of a reference to the Workbook
|
|
271
|
-
# itself is a workaround to avoid circular references between Workbook and
|
|
272
|
-
# Worksheet objects. Feel free to implement this in any way the suits your
|
|
273
|
-
# language.
|
|
274
|
-
#
|
|
275
231
|
init_data = [
|
|
232
|
+
self,
|
|
276
233
|
name,
|
|
277
234
|
index,
|
|
278
|
-
|
|
279
|
-
@url_format,
|
|
280
|
-
@parser,
|
|
281
|
-
@tempdir,
|
|
282
|
-
@date_1904,
|
|
283
|
-
@compatibility,
|
|
284
|
-
nil, # Palette. Not used yet. See add_chart().
|
|
285
|
-
@sinfo,
|
|
235
|
+
name_utf16be
|
|
286
236
|
]
|
|
287
237
|
worksheet = Writeexcel::Worksheet.new(*init_data)
|
|
288
238
|
@worksheets[index] = worksheet # Store ref for iterator
|
|
@@ -303,10 +253,10 @@ class Workbook < BIFFWriter
|
|
|
303
253
|
#
|
|
304
254
|
# :type (required)
|
|
305
255
|
# :name (optional)
|
|
306
|
-
# :
|
|
256
|
+
# :name_utf16be (optional)
|
|
307
257
|
# :embedded (optional)
|
|
308
258
|
#
|
|
309
|
-
# * type
|
|
259
|
+
# * :type
|
|
310
260
|
#
|
|
311
261
|
# This is a required parameter. It defines the type of chart that will be created.
|
|
312
262
|
#
|
|
@@ -327,7 +277,7 @@ class Workbook < BIFFWriter
|
|
|
327
277
|
# Set the name for the chart sheet. The name property is optional and
|
|
328
278
|
# if it isn't supplied will default to Chart1 .. n. The name must be
|
|
329
279
|
# a valid Excel worksheet name. See add_worksheet() for more details
|
|
330
|
-
# on valid sheet names. The name property can be omitted for embedded
|
|
280
|
+
# on valid sheet names. The :name property can be omitted for embedded
|
|
331
281
|
# charts.
|
|
332
282
|
#
|
|
333
283
|
# chart = workbook.add_chart(
|
|
@@ -335,17 +285,22 @@ class Workbook < BIFFWriter
|
|
|
335
285
|
# :name => 'Results Chart'
|
|
336
286
|
# )
|
|
337
287
|
#
|
|
288
|
+
# * :name_utf16be
|
|
289
|
+
#
|
|
290
|
+
# if :name is UTF-16BE format, pass true as :name_utf16be
|
|
291
|
+
#
|
|
338
292
|
# * :encoding
|
|
339
293
|
#
|
|
340
294
|
# if :name is UTF-16BE format, pass 1 as :encoding.
|
|
295
|
+
# This key is obsolete in v0.7 or later. Use :name_utf16be instead.
|
|
341
296
|
#
|
|
342
297
|
# * :embedded
|
|
343
298
|
#
|
|
344
|
-
# Specifies that the Chart object will be inserted in a worksheet via
|
|
299
|
+
# Specifies true that the Chart object will be inserted in a worksheet via
|
|
345
300
|
# the insert_chart() Worksheet method. It is an error to try insert a
|
|
346
301
|
# Chart that doesn't have this flag set.
|
|
347
302
|
#
|
|
348
|
-
# chart = workbook.add_chart(:type => 'Chart::Line', :embedded =>
|
|
303
|
+
# chart = workbook.add_chart(:type => 'Chart::Line', :embedded => true)
|
|
349
304
|
#
|
|
350
305
|
# # Configure the chart.
|
|
351
306
|
# ...
|
|
@@ -359,7 +314,7 @@ class Workbook < BIFFWriter
|
|
|
359
314
|
#
|
|
360
315
|
def add_chart(properties)
|
|
361
316
|
name = ''
|
|
362
|
-
|
|
317
|
+
name_utf16be = false
|
|
363
318
|
index = @worksheets.size
|
|
364
319
|
|
|
365
320
|
# Type must be specified so we can create the required chart instance.
|
|
@@ -371,21 +326,16 @@ class Workbook < BIFFWriter
|
|
|
371
326
|
|
|
372
327
|
# Check the worksheet name for non-embedded charts.
|
|
373
328
|
unless embedded
|
|
374
|
-
|
|
375
|
-
|
|
329
|
+
properties[:name_utf16be] = true if properties[:encoding] == 1
|
|
330
|
+
name, name_utf16be =
|
|
331
|
+
check_sheetname(properties[:name], properties[:name_utf16be], true)
|
|
376
332
|
end
|
|
377
333
|
|
|
378
334
|
init_data = [
|
|
335
|
+
self,
|
|
379
336
|
name,
|
|
380
337
|
index,
|
|
381
|
-
|
|
382
|
-
@url_format,
|
|
383
|
-
@parser,
|
|
384
|
-
@tempdir,
|
|
385
|
-
@date_1904 ? 1 : 0,
|
|
386
|
-
@compatibility,
|
|
387
|
-
@palette,
|
|
388
|
-
@sinfo
|
|
338
|
+
name_utf16be
|
|
389
339
|
]
|
|
390
340
|
|
|
391
341
|
chart = Writeexcel::Chart.factory(type, *init_data)
|
|
@@ -414,17 +364,17 @@ class Workbook < BIFFWriter
|
|
|
414
364
|
# using add_chart(). Read external_charts.txt in the external_charts
|
|
415
365
|
# directory of the distro for a full explanation.
|
|
416
366
|
#
|
|
417
|
-
def add_chart_ext(filename,
|
|
367
|
+
def add_chart_ext(filename, chartname, name_utf16be = false)
|
|
418
368
|
index = @worksheets.size
|
|
419
369
|
type = 'extarnal'
|
|
420
370
|
|
|
421
|
-
name,
|
|
371
|
+
name, name_utf16be = check_sheetname(chartname, name_utf16be)
|
|
422
372
|
|
|
423
373
|
init_data = [
|
|
424
374
|
filename,
|
|
425
375
|
name,
|
|
426
376
|
index,
|
|
427
|
-
|
|
377
|
+
name_utf16be,
|
|
428
378
|
@sinfo
|
|
429
379
|
]
|
|
430
380
|
|
|
@@ -433,130 +383,6 @@ class Workbook < BIFFWriter
|
|
|
433
383
|
chart
|
|
434
384
|
end
|
|
435
385
|
|
|
436
|
-
###############################################################################
|
|
437
|
-
#
|
|
438
|
-
# check_sheetname(name, encoding)
|
|
439
|
-
#
|
|
440
|
-
# Check for valid worksheet names. We check the length, if it contains any
|
|
441
|
-
# invalid characters and if the name is unique in the workbook.
|
|
442
|
-
#
|
|
443
|
-
def check_sheetname(name, encoding = 0, chart = nil) #:nodoc:
|
|
444
|
-
encoding ||= 0
|
|
445
|
-
|
|
446
|
-
# Increment the Sheet/Chart number used for default sheet names below.
|
|
447
|
-
if chart
|
|
448
|
-
@chart_count += 1
|
|
449
|
-
else
|
|
450
|
-
@sheet_count += 1
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
# Supply default Sheet/Chart name if none has been defined.
|
|
454
|
-
if name.nil? || name == ""
|
|
455
|
-
encoding = 0
|
|
456
|
-
if chart
|
|
457
|
-
name = @chart_name + @chart_count.to_s
|
|
458
|
-
else
|
|
459
|
-
name = @sheet_name + @sheet_count.to_s
|
|
460
|
-
end
|
|
461
|
-
end
|
|
462
|
-
|
|
463
|
-
ruby_19 { name = convert_to_ascii_if_ascii(name) }
|
|
464
|
-
check_sheetname_length(name, encoding)
|
|
465
|
-
check_sheetname_even(name) if encoding == 1
|
|
466
|
-
check_sheetname_valid_chars(name, encoding)
|
|
467
|
-
|
|
468
|
-
# Handle utf8 strings
|
|
469
|
-
if is_utf8?(name)
|
|
470
|
-
name = utf8_to_16be(name)
|
|
471
|
-
encoding = 1
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
check_sheetname_uniq(name, encoding)
|
|
475
|
-
[name, encoding]
|
|
476
|
-
end
|
|
477
|
-
private :check_sheetname
|
|
478
|
-
|
|
479
|
-
def check_sheetname_length(name, encoding) #:nodoc:
|
|
480
|
-
# Check that sheetname is <= 31 (1 or 2 byte chars). Excel limit.
|
|
481
|
-
limit = encoding != 0 ? 62 : 31
|
|
482
|
-
raise "Sheetname $name must be <= 31 chars" if name.bytesize > limit
|
|
483
|
-
end
|
|
484
|
-
private :check_sheetname_length
|
|
485
|
-
|
|
486
|
-
def check_sheetname_even(name) #:nodoc:
|
|
487
|
-
# Check that Unicode sheetname has an even number of bytes
|
|
488
|
-
if (name.bytesize % 2 != 0)
|
|
489
|
-
raise "Odd number of bytes in Unicode worksheet name: #{name}"
|
|
490
|
-
end
|
|
491
|
-
end
|
|
492
|
-
private :check_sheetname_even
|
|
493
|
-
|
|
494
|
-
def check_sheetname_valid_chars(name, encoding) #:nodoc:
|
|
495
|
-
# Check that sheetname doesn't contain any invalid characters
|
|
496
|
-
invalid_char = %r![\[\]:*?/\\]!
|
|
497
|
-
if encoding != 1 && name =~ invalid_char
|
|
498
|
-
# Check ASCII names
|
|
499
|
-
raise "Invalid character []:*?/\\ in worksheet name: #{name}"
|
|
500
|
-
else
|
|
501
|
-
# Extract any 8bit clean chars from the UTF16 name and validate them.
|
|
502
|
-
str = name.dup
|
|
503
|
-
while str =~ /../m
|
|
504
|
-
hi, lo = $~[0].unpack('aa')
|
|
505
|
-
if hi == "\0" and lo =~ invalid_char
|
|
506
|
-
raise 'Invalid character []:*?/\\ in worksheet name: ' + name
|
|
507
|
-
end
|
|
508
|
-
str = $~.post_match
|
|
509
|
-
end
|
|
510
|
-
end
|
|
511
|
-
end
|
|
512
|
-
private :check_sheetname_valid_chars
|
|
513
|
-
|
|
514
|
-
# Check that the worksheet name doesn't already exist since this is a fatal
|
|
515
|
-
# error in Excel 97. The check must also exclude case insensitive matches
|
|
516
|
-
# since the names 'Sheet1' and 'sheet1' are equivalent. The tests also have
|
|
517
|
-
# to take the encoding into account.
|
|
518
|
-
#
|
|
519
|
-
def check_sheetname_uniq(name, encoding) #:nodoc:
|
|
520
|
-
@worksheets.each do |worksheet|
|
|
521
|
-
name_a = name
|
|
522
|
-
encd_a = encoding
|
|
523
|
-
name_b = worksheet.name
|
|
524
|
-
encd_b = worksheet.encoding
|
|
525
|
-
error = false
|
|
526
|
-
|
|
527
|
-
if encd_a == 0 and encd_b == 0
|
|
528
|
-
error = (name_a.downcase == name_b.downcase)
|
|
529
|
-
elsif encd_a == 0 and encd_b == 1
|
|
530
|
-
name_a = ascii_to_16be(name_a)
|
|
531
|
-
error = (name_a.downcase == name_b.downcase)
|
|
532
|
-
elsif encd_a == 1 and encd_b == 0
|
|
533
|
-
name_b = ascii_to_16be(name_b)
|
|
534
|
-
error = (name_a.downcase == name_b.downcase)
|
|
535
|
-
elsif encd_a == 1 and encd_b == 1
|
|
536
|
-
# TODO : not converted yet.
|
|
537
|
-
|
|
538
|
-
# We can't easily do a case insensitive test of the UTF16 names.
|
|
539
|
-
# As a special case we check if all of the high bytes are nulls and
|
|
540
|
-
# then do an ASCII style case insensitive test.
|
|
541
|
-
#
|
|
542
|
-
# Strip out the high bytes (funkily).
|
|
543
|
-
# my $hi_a = grep {ord} $name_a =~ /(.)./sg;
|
|
544
|
-
# my $hi_b = grep {ord} $name_b =~ /(.)./sg;
|
|
545
|
-
#
|
|
546
|
-
# if ($hi_a or $hi_b) {
|
|
547
|
-
# $error = 1 if $name_a eq $name_b;
|
|
548
|
-
# }
|
|
549
|
-
# else {
|
|
550
|
-
# $error = 1 if lc($name_a) eq lc($name_b);
|
|
551
|
-
# }
|
|
552
|
-
end
|
|
553
|
-
if error
|
|
554
|
-
raise "Worksheet name '#{name}', with case ignored, is already in use"
|
|
555
|
-
end
|
|
556
|
-
end
|
|
557
|
-
end
|
|
558
|
-
private :check_sheetname_uniq
|
|
559
|
-
|
|
560
386
|
#
|
|
561
387
|
# The add_format method can be used to create new Format objects which are
|
|
562
388
|
# used to apply formatting to a cell. You can either define the properties
|
|
@@ -625,7 +451,7 @@ class Workbook < BIFFWriter
|
|
|
625
451
|
# about to be written. This incurs a memory and speed penalty and may not be
|
|
626
452
|
# suitable for very large files.
|
|
627
453
|
#
|
|
628
|
-
def compatibility_mode(mode =
|
|
454
|
+
def compatibility_mode(mode = true)
|
|
629
455
|
unless sheets.empty?
|
|
630
456
|
raise "compatibility_mode() must be called before add_worksheet()"
|
|
631
457
|
end
|
|
@@ -645,7 +471,7 @@ class Workbook < BIFFWriter
|
|
|
645
471
|
# WriteExcel stores dates in the 1900 format by default. If you wish to
|
|
646
472
|
# change this you can call the set_1904() workbook method. You can query
|
|
647
473
|
# the current value by calling the get_1904() workbook method. This returns
|
|
648
|
-
#
|
|
474
|
+
# false for 1900 and true for 1904.
|
|
649
475
|
#
|
|
650
476
|
# See also "DATES AND TIME IN EXCEL" for more information about working
|
|
651
477
|
# with Excel's date system.
|
|
@@ -656,7 +482,11 @@ class Workbook < BIFFWriter
|
|
|
656
482
|
unless sheets.empty?
|
|
657
483
|
raise "set_1904() must be called before add_worksheet()"
|
|
658
484
|
end
|
|
659
|
-
@date_1904 = mode
|
|
485
|
+
@date_1904 = (!mode || mode == 0) ? false : true
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def get_1904
|
|
489
|
+
@date_1904
|
|
660
490
|
end
|
|
661
491
|
|
|
662
492
|
#
|
|
@@ -710,7 +540,7 @@ class Workbook < BIFFWriter
|
|
|
710
540
|
# :border => 1
|
|
711
541
|
# )
|
|
712
542
|
#
|
|
713
|
-
def set_custom_color(index
|
|
543
|
+
def set_custom_color(index, red = nil, green = nil, blue = nil)
|
|
714
544
|
# Match a HTML #xxyyzz style parameter
|
|
715
545
|
if !red.nil? && red =~ /^#(\w\w)(\w\w)(\w\w)/
|
|
716
546
|
red = $1.hex
|
|
@@ -738,78 +568,9 @@ class Workbook < BIFFWriter
|
|
|
738
568
|
index + 8
|
|
739
569
|
end
|
|
740
570
|
|
|
741
|
-
###############################################################################
|
|
742
|
-
#
|
|
743
|
-
# set_palette_xl97()
|
|
744
|
-
#
|
|
745
|
-
# Sets the colour palette to the Excel 97+ default.
|
|
746
|
-
#
|
|
747
|
-
def set_palette_xl97 #:nodoc:
|
|
748
|
-
@palette = [
|
|
749
|
-
[0x00, 0x00, 0x00, 0x00], # 8
|
|
750
|
-
[0xff, 0xff, 0xff, 0x00], # 9
|
|
751
|
-
[0xff, 0x00, 0x00, 0x00], # 10
|
|
752
|
-
[0x00, 0xff, 0x00, 0x00], # 11
|
|
753
|
-
[0x00, 0x00, 0xff, 0x00], # 12
|
|
754
|
-
[0xff, 0xff, 0x00, 0x00], # 13
|
|
755
|
-
[0xff, 0x00, 0xff, 0x00], # 14
|
|
756
|
-
[0x00, 0xff, 0xff, 0x00], # 15
|
|
757
|
-
[0x80, 0x00, 0x00, 0x00], # 16
|
|
758
|
-
[0x00, 0x80, 0x00, 0x00], # 17
|
|
759
|
-
[0x00, 0x00, 0x80, 0x00], # 18
|
|
760
|
-
[0x80, 0x80, 0x00, 0x00], # 19
|
|
761
|
-
[0x80, 0x00, 0x80, 0x00], # 20
|
|
762
|
-
[0x00, 0x80, 0x80, 0x00], # 21
|
|
763
|
-
[0xc0, 0xc0, 0xc0, 0x00], # 22
|
|
764
|
-
[0x80, 0x80, 0x80, 0x00], # 23
|
|
765
|
-
[0x99, 0x99, 0xff, 0x00], # 24
|
|
766
|
-
[0x99, 0x33, 0x66, 0x00], # 25
|
|
767
|
-
[0xff, 0xff, 0xcc, 0x00], # 26
|
|
768
|
-
[0xcc, 0xff, 0xff, 0x00], # 27
|
|
769
|
-
[0x66, 0x00, 0x66, 0x00], # 28
|
|
770
|
-
[0xff, 0x80, 0x80, 0x00], # 29
|
|
771
|
-
[0x00, 0x66, 0xcc, 0x00], # 30
|
|
772
|
-
[0xcc, 0xcc, 0xff, 0x00], # 31
|
|
773
|
-
[0x00, 0x00, 0x80, 0x00], # 32
|
|
774
|
-
[0xff, 0x00, 0xff, 0x00], # 33
|
|
775
|
-
[0xff, 0xff, 0x00, 0x00], # 34
|
|
776
|
-
[0x00, 0xff, 0xff, 0x00], # 35
|
|
777
|
-
[0x80, 0x00, 0x80, 0x00], # 36
|
|
778
|
-
[0x80, 0x00, 0x00, 0x00], # 37
|
|
779
|
-
[0x00, 0x80, 0x80, 0x00], # 38
|
|
780
|
-
[0x00, 0x00, 0xff, 0x00], # 39
|
|
781
|
-
[0x00, 0xcc, 0xff, 0x00], # 40
|
|
782
|
-
[0xcc, 0xff, 0xff, 0x00], # 41
|
|
783
|
-
[0xcc, 0xff, 0xcc, 0x00], # 42
|
|
784
|
-
[0xff, 0xff, 0x99, 0x00], # 43
|
|
785
|
-
[0x99, 0xcc, 0xff, 0x00], # 44
|
|
786
|
-
[0xff, 0x99, 0xcc, 0x00], # 45
|
|
787
|
-
[0xcc, 0x99, 0xff, 0x00], # 46
|
|
788
|
-
[0xff, 0xcc, 0x99, 0x00], # 47
|
|
789
|
-
[0x33, 0x66, 0xff, 0x00], # 48
|
|
790
|
-
[0x33, 0xcc, 0xcc, 0x00], # 49
|
|
791
|
-
[0x99, 0xcc, 0x00, 0x00], # 50
|
|
792
|
-
[0xff, 0xcc, 0x00, 0x00], # 51
|
|
793
|
-
[0xff, 0x99, 0x00, 0x00], # 52
|
|
794
|
-
[0xff, 0x66, 0x00, 0x00], # 53
|
|
795
|
-
[0x66, 0x66, 0x99, 0x00], # 54
|
|
796
|
-
[0x96, 0x96, 0x96, 0x00], # 55
|
|
797
|
-
[0x00, 0x33, 0x66, 0x00], # 56
|
|
798
|
-
[0x33, 0x99, 0x66, 0x00], # 57
|
|
799
|
-
[0x00, 0x33, 0x00, 0x00], # 58
|
|
800
|
-
[0x33, 0x33, 0x00, 0x00], # 59
|
|
801
|
-
[0x99, 0x33, 0x00, 0x00], # 60
|
|
802
|
-
[0x99, 0x33, 0x66, 0x00], # 61
|
|
803
|
-
[0x33, 0x33, 0x99, 0x00], # 62
|
|
804
|
-
[0x33, 0x33, 0x33, 0x00] # 63
|
|
805
|
-
]
|
|
806
|
-
end
|
|
807
|
-
private :set_palette_xl97
|
|
808
|
-
|
|
809
571
|
#
|
|
810
572
|
# Change the default temp directory
|
|
811
573
|
#
|
|
812
|
-
#
|
|
813
574
|
# For speed and efficiency WriteExcel stores worksheet data in temporary
|
|
814
575
|
# files prior to assembling the final workbook.
|
|
815
576
|
#
|
|
@@ -964,14 +725,14 @@ class Workbook < BIFFWriter
|
|
|
964
725
|
#
|
|
965
726
|
# The properties that can be set are:
|
|
966
727
|
#
|
|
967
|
-
# * title
|
|
968
|
-
# * subject
|
|
969
|
-
# * author
|
|
970
|
-
# * manager
|
|
971
|
-
# * company
|
|
972
|
-
# * category
|
|
973
|
-
# * keywords
|
|
974
|
-
# * comments
|
|
728
|
+
# * :title
|
|
729
|
+
# * :subject
|
|
730
|
+
# * :author
|
|
731
|
+
# * :manager
|
|
732
|
+
# * :company
|
|
733
|
+
# * :category
|
|
734
|
+
# * :keywords
|
|
735
|
+
# * :comments
|
|
975
736
|
#
|
|
976
737
|
# User defined properties are not supported due to effort required.
|
|
977
738
|
#
|
|
@@ -990,7 +751,7 @@ class Workbook < BIFFWriter
|
|
|
990
751
|
#
|
|
991
752
|
# workbook.set_properties(
|
|
992
753
|
# ...,
|
|
993
|
-
# :comments => 'Created with Ruby and
|
|
754
|
+
# :comments => 'Created with Ruby and writeexcel',
|
|
994
755
|
# ...,
|
|
995
756
|
# )
|
|
996
757
|
#
|
|
@@ -1042,13 +803,261 @@ class Workbook < BIFFWriter
|
|
|
1042
803
|
create_doc_summary_property_set(property_sets(properties, params))
|
|
1043
804
|
|
|
1044
805
|
# Set a flag for when the files is written.
|
|
1045
|
-
add_doc_properties = true
|
|
806
|
+
@add_doc_properties = true
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
def str_unique=(val) # :nodoc:
|
|
810
|
+
@sinfo[:str_unique] = val
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
def extsst_buckets # :nodoc:
|
|
814
|
+
@extsst_buckets
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
def extsst_bucket_size # :nodoc:
|
|
818
|
+
@extsst_bucket_size
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
def biff_only=(val) # :nodoc:
|
|
822
|
+
@biff_only = val
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
def summary # :nodoc:
|
|
826
|
+
@summary
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
def localtime=(val) # :nodoc:
|
|
830
|
+
@localtime = val
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
#==========================================
|
|
834
|
+
# Internal method
|
|
835
|
+
#==========================================
|
|
836
|
+
|
|
837
|
+
private
|
|
838
|
+
|
|
839
|
+
# Add the in-built style formats and the default cell format.
|
|
840
|
+
def setup_built_in_formats(default_formats) # :nodoc:
|
|
841
|
+
add_format(:type => 1) # 0 Normal
|
|
842
|
+
add_format(:type => 1) # 1 RowLevel 1
|
|
843
|
+
add_format(:type => 1) # 2 RowLevel 2
|
|
844
|
+
add_format(:type => 1) # 3 RowLevel 3
|
|
845
|
+
add_format(:type => 1) # 4 RowLevel 4
|
|
846
|
+
add_format(:type => 1) # 5 RowLevel 5
|
|
847
|
+
add_format(:type => 1) # 6 RowLevel 6
|
|
848
|
+
add_format(:type => 1) # 7 RowLevel 7
|
|
849
|
+
add_format(:type => 1) # 8 ColLevel 1
|
|
850
|
+
add_format(:type => 1) # 9 ColLevel 2
|
|
851
|
+
add_format(:type => 1) # 10 ColLevel 3
|
|
852
|
+
add_format(:type => 1) # 11 ColLevel 4
|
|
853
|
+
add_format(:type => 1) # 12 ColLevel 5
|
|
854
|
+
add_format(:type => 1) # 13 ColLevel 6
|
|
855
|
+
add_format(:type => 1) # 14 ColLevel 7
|
|
856
|
+
add_format(default_formats) # 15 Cell XF
|
|
857
|
+
add_format(:type => 1, :num_format => 0x2B) # 16 Comma
|
|
858
|
+
add_format(:type => 1, :num_format => 0x29) # 17 Comma[0]
|
|
859
|
+
add_format(:type => 1, :num_format => 0x2C) # 18 Currency
|
|
860
|
+
add_format(:type => 1, :num_format => 0x2A) # 19 Currency[0]
|
|
861
|
+
add_format(:type => 1, :num_format => 0x09) # 20 Percent
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
def fileclosed?
|
|
865
|
+
@fileclosed || false
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
#
|
|
869
|
+
# Check for valid worksheet names. We check the length, if it contains any
|
|
870
|
+
# invalid characters and if the name is unique in the workbook.
|
|
871
|
+
#
|
|
872
|
+
def check_sheetname(name, name_utf16be = false, chart = nil) #:nodoc:
|
|
873
|
+
# name_utf16be parameter may set 0/1 in v0.6.6 or earlier
|
|
874
|
+
name_utf16be = false if name_utf16be == 0
|
|
875
|
+
name_utf16be = true if name_utf16be == 1
|
|
876
|
+
|
|
877
|
+
increment_sheet_chart_count(chart)
|
|
878
|
+
if name.nil? || name == ""
|
|
879
|
+
name_utf16be = false
|
|
880
|
+
name = default_sheet_chart_name(chart)
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
ruby_19 { name = convert_to_ascii_if_ascii(name) }
|
|
884
|
+
check_sheetname_length(name, name_utf16be)
|
|
885
|
+
check_sheetname_even(name) if name_utf16be
|
|
886
|
+
check_sheetname_valid_chars(name, name_utf16be)
|
|
887
|
+
|
|
888
|
+
# Handle utf8 strings
|
|
889
|
+
if is_utf8?(name)
|
|
890
|
+
name = utf8_to_16be(name)
|
|
891
|
+
name_utf16be = true
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
check_sheetname_uniq(name, name_utf16be)
|
|
895
|
+
[name, name_utf16be]
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
# Increment the Sheet/Chart number used for default sheet names below.
|
|
899
|
+
def increment_sheet_chart_count(chart)
|
|
900
|
+
if chart
|
|
901
|
+
@chart_count += 1
|
|
902
|
+
else
|
|
903
|
+
@sheet_count += 1
|
|
904
|
+
end
|
|
905
|
+
end
|
|
906
|
+
|
|
907
|
+
# Supply default Sheet/Chart name if none has been defined.
|
|
908
|
+
def default_sheet_chart_name(chart)
|
|
909
|
+
if chart
|
|
910
|
+
"Chart#{@chart_count}"
|
|
911
|
+
else
|
|
912
|
+
"Sheet#{@sheet_count}"
|
|
913
|
+
end
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
def check_sheetname_length(name, name_utf16be) #:nodoc:
|
|
917
|
+
# Check that sheetname is <= 31 (1 or 2 byte chars). Excel limit.
|
|
918
|
+
limit = name_utf16be ? 62 : 31
|
|
919
|
+
raise "Sheetname $name must be <= 31 chars" if name.bytesize > limit
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
def check_sheetname_even(name) #:nodoc:
|
|
923
|
+
# Check that Unicode sheetname has an even number of bytes
|
|
924
|
+
if (name.bytesize % 2 != 0)
|
|
925
|
+
raise "Odd number of bytes in Unicode worksheet name: #{name}"
|
|
926
|
+
end
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
def check_sheetname_valid_chars(name, name_utf16be) #:nodoc:
|
|
930
|
+
# Check that sheetname doesn't contain any invalid characters
|
|
931
|
+
invalid_char = %r![\[\]:*?/\\]!
|
|
932
|
+
if !name_utf16be && name =~ invalid_char
|
|
933
|
+
# Check ASCII names
|
|
934
|
+
raise "Invalid character []:*?/\\ in worksheet name: #{name}"
|
|
935
|
+
else
|
|
936
|
+
# Extract any 8bit clean chars from the UTF16 name and validate them.
|
|
937
|
+
str = name.dup
|
|
938
|
+
while str =~ /../m
|
|
939
|
+
hi, lo = $~[0].unpack('aa')
|
|
940
|
+
if hi == "\0" and lo =~ invalid_char
|
|
941
|
+
raise 'Invalid character []:*?/\\ in worksheet name: ' + name
|
|
942
|
+
end
|
|
943
|
+
str = $~.post_match
|
|
944
|
+
end
|
|
945
|
+
end
|
|
946
|
+
end
|
|
947
|
+
|
|
948
|
+
# Check that the worksheet name doesn't already exist since this is a fatal
|
|
949
|
+
# error in Excel 97. The check must also exclude case insensitive matches
|
|
950
|
+
# since the names 'Sheet1' and 'sheet1' are equivalent. The tests also have
|
|
951
|
+
# to take the name_utf16be into account.
|
|
952
|
+
#
|
|
953
|
+
def check_sheetname_uniq(name, name_utf16be) #:nodoc:
|
|
954
|
+
@worksheets.each do |worksheet|
|
|
955
|
+
name_a = name
|
|
956
|
+
encd_a = name_utf16be
|
|
957
|
+
name_b = worksheet.name
|
|
958
|
+
encd_b = worksheet.is_name_utf16be?
|
|
959
|
+
error = false
|
|
960
|
+
|
|
961
|
+
if !encd_a and !encd_b
|
|
962
|
+
error = (name_a.downcase == name_b.downcase)
|
|
963
|
+
elsif !encd_a and encd_b
|
|
964
|
+
name_a = ascii_to_16be(name_a)
|
|
965
|
+
error = (name_a.downcase == name_b.downcase)
|
|
966
|
+
elsif encd_a and !encd_b
|
|
967
|
+
name_b = ascii_to_16be(name_b)
|
|
968
|
+
error = (name_a.downcase == name_b.downcase)
|
|
969
|
+
elsif encd_a and encd_b
|
|
970
|
+
error = (name_a.downcase == name_b.downcase)
|
|
971
|
+
# TODO : not converted yet.
|
|
972
|
+
|
|
973
|
+
# We can't easily do a case insensitive test of the UTF16 names.
|
|
974
|
+
# As a special case we check if all of the high bytes are nulls and
|
|
975
|
+
# then do an ASCII style case insensitive test.
|
|
976
|
+
#
|
|
977
|
+
# Strip out the high bytes (funkily).
|
|
978
|
+
# my $hi_a = grep {ord} $name_a =~ /(.)./sg;
|
|
979
|
+
# my $hi_b = grep {ord} $name_b =~ /(.)./sg;
|
|
980
|
+
#
|
|
981
|
+
# if ($hi_a or $hi_b) {
|
|
982
|
+
# $error = 1 if $name_a eq $name_b;
|
|
983
|
+
# }
|
|
984
|
+
# else {
|
|
985
|
+
# $error = 1 if lc($name_a) eq lc($name_b);
|
|
986
|
+
# }
|
|
987
|
+
end
|
|
988
|
+
if error
|
|
989
|
+
raise "Worksheet name '#{name}', with case ignored, is already in use"
|
|
990
|
+
end
|
|
991
|
+
end
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
#
|
|
995
|
+
# Sets the colour palette to the Excel 97+ default.
|
|
996
|
+
#
|
|
997
|
+
def set_palette_xl97 #:nodoc:
|
|
998
|
+
@palette = [
|
|
999
|
+
[0x00, 0x00, 0x00, 0x00], # 8
|
|
1000
|
+
[0xff, 0xff, 0xff, 0x00], # 9
|
|
1001
|
+
[0xff, 0x00, 0x00, 0x00], # 10
|
|
1002
|
+
[0x00, 0xff, 0x00, 0x00], # 11
|
|
1003
|
+
[0x00, 0x00, 0xff, 0x00], # 12
|
|
1004
|
+
[0xff, 0xff, 0x00, 0x00], # 13
|
|
1005
|
+
[0xff, 0x00, 0xff, 0x00], # 14
|
|
1006
|
+
[0x00, 0xff, 0xff, 0x00], # 15
|
|
1007
|
+
[0x80, 0x00, 0x00, 0x00], # 16
|
|
1008
|
+
[0x00, 0x80, 0x00, 0x00], # 17
|
|
1009
|
+
[0x00, 0x00, 0x80, 0x00], # 18
|
|
1010
|
+
[0x80, 0x80, 0x00, 0x00], # 19
|
|
1011
|
+
[0x80, 0x00, 0x80, 0x00], # 20
|
|
1012
|
+
[0x00, 0x80, 0x80, 0x00], # 21
|
|
1013
|
+
[0xc0, 0xc0, 0xc0, 0x00], # 22
|
|
1014
|
+
[0x80, 0x80, 0x80, 0x00], # 23
|
|
1015
|
+
[0x99, 0x99, 0xff, 0x00], # 24
|
|
1016
|
+
[0x99, 0x33, 0x66, 0x00], # 25
|
|
1017
|
+
[0xff, 0xff, 0xcc, 0x00], # 26
|
|
1018
|
+
[0xcc, 0xff, 0xff, 0x00], # 27
|
|
1019
|
+
[0x66, 0x00, 0x66, 0x00], # 28
|
|
1020
|
+
[0xff, 0x80, 0x80, 0x00], # 29
|
|
1021
|
+
[0x00, 0x66, 0xcc, 0x00], # 30
|
|
1022
|
+
[0xcc, 0xcc, 0xff, 0x00], # 31
|
|
1023
|
+
[0x00, 0x00, 0x80, 0x00], # 32
|
|
1024
|
+
[0xff, 0x00, 0xff, 0x00], # 33
|
|
1025
|
+
[0xff, 0xff, 0x00, 0x00], # 34
|
|
1026
|
+
[0x00, 0xff, 0xff, 0x00], # 35
|
|
1027
|
+
[0x80, 0x00, 0x80, 0x00], # 36
|
|
1028
|
+
[0x80, 0x00, 0x00, 0x00], # 37
|
|
1029
|
+
[0x00, 0x80, 0x80, 0x00], # 38
|
|
1030
|
+
[0x00, 0x00, 0xff, 0x00], # 39
|
|
1031
|
+
[0x00, 0xcc, 0xff, 0x00], # 40
|
|
1032
|
+
[0xcc, 0xff, 0xff, 0x00], # 41
|
|
1033
|
+
[0xcc, 0xff, 0xcc, 0x00], # 42
|
|
1034
|
+
[0xff, 0xff, 0x99, 0x00], # 43
|
|
1035
|
+
[0x99, 0xcc, 0xff, 0x00], # 44
|
|
1036
|
+
[0xff, 0x99, 0xcc, 0x00], # 45
|
|
1037
|
+
[0xcc, 0x99, 0xff, 0x00], # 46
|
|
1038
|
+
[0xff, 0xcc, 0x99, 0x00], # 47
|
|
1039
|
+
[0x33, 0x66, 0xff, 0x00], # 48
|
|
1040
|
+
[0x33, 0xcc, 0xcc, 0x00], # 49
|
|
1041
|
+
[0x99, 0xcc, 0x00, 0x00], # 50
|
|
1042
|
+
[0xff, 0xcc, 0x00, 0x00], # 51
|
|
1043
|
+
[0xff, 0x99, 0x00, 0x00], # 52
|
|
1044
|
+
[0xff, 0x66, 0x00, 0x00], # 53
|
|
1045
|
+
[0x66, 0x66, 0x99, 0x00], # 54
|
|
1046
|
+
[0x96, 0x96, 0x96, 0x00], # 55
|
|
1047
|
+
[0x00, 0x33, 0x66, 0x00], # 56
|
|
1048
|
+
[0x33, 0x99, 0x66, 0x00], # 57
|
|
1049
|
+
[0x00, 0x33, 0x00, 0x00], # 58
|
|
1050
|
+
[0x33, 0x33, 0x00, 0x00], # 59
|
|
1051
|
+
[0x99, 0x33, 0x00, 0x00], # 60
|
|
1052
|
+
[0x99, 0x33, 0x66, 0x00], # 61
|
|
1053
|
+
[0x33, 0x33, 0x99, 0x00], # 62
|
|
1054
|
+
[0x33, 0x33, 0x33, 0x00] # 63
|
|
1055
|
+
]
|
|
1046
1056
|
end
|
|
1047
1057
|
|
|
1048
1058
|
def property_set(property, params) #:nodoc:
|
|
1049
1059
|
valid_properties[property][0..1] + [params[property]]
|
|
1050
1060
|
end
|
|
1051
|
-
private :property_set
|
|
1052
1061
|
|
|
1053
1062
|
def property_sets(properties, params) #:nodoc:
|
|
1054
1063
|
properties.select { |property| params[property.to_sym] }.
|
|
@@ -1056,7 +1065,6 @@ class Workbook < BIFFWriter
|
|
|
1056
1065
|
property_set(property.to_sym, params)
|
|
1057
1066
|
end
|
|
1058
1067
|
end
|
|
1059
|
-
private :property_sets
|
|
1060
1068
|
|
|
1061
1069
|
# List of valid input parameters.
|
|
1062
1070
|
def valid_properties #:nodoc:
|
|
@@ -1075,7 +1083,6 @@ class Workbook < BIFFWriter
|
|
|
1075
1083
|
:utf8 => 1
|
|
1076
1084
|
}
|
|
1077
1085
|
end
|
|
1078
|
-
private :valid_properties
|
|
1079
1086
|
|
|
1080
1087
|
def check_valid_params_for_properties(params) #:nodoc:
|
|
1081
1088
|
params.each_key do |k|
|
|
@@ -1084,11 +1091,7 @@ class Workbook < BIFFWriter
|
|
|
1084
1091
|
end
|
|
1085
1092
|
end
|
|
1086
1093
|
end
|
|
1087
|
-
private :check_valid_params_for_properties
|
|
1088
1094
|
|
|
1089
|
-
###############################################################################
|
|
1090
|
-
#
|
|
1091
|
-
# get_property_set_codepage()
|
|
1092
1095
|
#
|
|
1093
1096
|
# Get the character codepage used by the strings in a property set. If one of
|
|
1094
1097
|
# the strings used is utf8 then the codepage is marked as utf8. Otherwise
|
|
@@ -1103,11 +1106,7 @@ class Workbook < BIFFWriter
|
|
|
1103
1106
|
end
|
|
1104
1107
|
return 0x04E4 # Default codepage, Latin 1.
|
|
1105
1108
|
end
|
|
1106
|
-
private :get_property_set_codepage
|
|
1107
1109
|
|
|
1108
|
-
###############################################################################
|
|
1109
|
-
#
|
|
1110
|
-
# store_workbook()
|
|
1111
1110
|
#
|
|
1112
1111
|
# Assemble worksheets into a workbook and send the BIFF data to an OLE
|
|
1113
1112
|
# storage.
|
|
@@ -1124,7 +1123,7 @@ class Workbook < BIFFWriter
|
|
|
1124
1123
|
|
|
1125
1124
|
# Calculate the number of selected sheet tabs and set the active sheet.
|
|
1126
1125
|
@worksheets.each do |sheet|
|
|
1127
|
-
@selected += 1 if sheet.selected
|
|
1126
|
+
@selected += 1 if sheet.selected?
|
|
1128
1127
|
sheet.active = 1 if sheet.index == @sinfo[:activesheet]
|
|
1129
1128
|
end
|
|
1130
1129
|
|
|
@@ -1145,13 +1144,7 @@ class Workbook < BIFFWriter
|
|
|
1145
1144
|
|
|
1146
1145
|
# Add BOUNDSHEET records.
|
|
1147
1146
|
@worksheets.each do |sheet|
|
|
1148
|
-
store_boundsheet(
|
|
1149
|
-
sheet.name,
|
|
1150
|
-
sheet.offset,
|
|
1151
|
-
sheet.sheet_type,
|
|
1152
|
-
sheet.hidden,
|
|
1153
|
-
sheet.encoding
|
|
1154
|
-
)
|
|
1147
|
+
store_boundsheet(sheet)
|
|
1155
1148
|
end
|
|
1156
1149
|
|
|
1157
1150
|
# NOTE: If any records are added between here and EOF the
|
|
@@ -1170,117 +1163,93 @@ class Workbook < BIFFWriter
|
|
|
1170
1163
|
store_eof
|
|
1171
1164
|
|
|
1172
1165
|
# Store the workbook in an OLE container
|
|
1173
|
-
|
|
1174
|
-
end
|
|
1175
|
-
private :store_workbook
|
|
1176
|
-
|
|
1177
|
-
def str_unique=(val) # :nodoc:
|
|
1178
|
-
@sinfo[:str_unique] = val
|
|
1179
|
-
end
|
|
1180
|
-
|
|
1181
|
-
def extsst_buckets # :nodoc:
|
|
1182
|
-
@extsst_buckets
|
|
1183
|
-
end
|
|
1184
|
-
|
|
1185
|
-
def extsst_bucket_size # :nodoc:
|
|
1186
|
-
@extsst_bucket_size
|
|
1187
|
-
end
|
|
1188
|
-
|
|
1189
|
-
def biff_only=(val) # :nodoc:
|
|
1190
|
-
@biff_only = val
|
|
1191
|
-
end
|
|
1192
|
-
|
|
1193
|
-
def summary # :nodoc:
|
|
1194
|
-
@summary
|
|
1195
|
-
end
|
|
1196
|
-
|
|
1197
|
-
def localtime=(val) # :nodoc:
|
|
1198
|
-
@localtime = val
|
|
1166
|
+
store_ole_file
|
|
1199
1167
|
end
|
|
1200
1168
|
|
|
1201
|
-
###############################################################################
|
|
1202
|
-
#
|
|
1203
|
-
# store_ole_filie()
|
|
1204
1169
|
#
|
|
1205
1170
|
# Store the workbook in an OLE container using the default handler or using
|
|
1206
1171
|
# OLE::Storage_Lite if the workbook data is > ~ 7MB.
|
|
1207
1172
|
#
|
|
1208
|
-
def
|
|
1173
|
+
def store_ole_file #:nodoc:
|
|
1209
1174
|
maxsize = 7_087_104
|
|
1210
1175
|
# maxsize = 1
|
|
1211
1176
|
|
|
1212
1177
|
if !add_doc_properties && @biffsize <= maxsize
|
|
1213
|
-
|
|
1214
|
-
|
|
1178
|
+
store_through_ole_writer
|
|
1179
|
+
else
|
|
1180
|
+
store_through_ole_storage_lite
|
|
1181
|
+
end
|
|
1182
|
+
end
|
|
1215
1183
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1184
|
+
def store_through_ole_writer
|
|
1185
|
+
# Write the OLE file using OLEwriter if data <= 7MB
|
|
1186
|
+
ole = OLEWriter.new(@fh_out)
|
|
1218
1187
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1188
|
+
# Write the BIFF data without the OLE container for testing.
|
|
1189
|
+
ole.biff_only = @biff_only
|
|
1221
1190
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1191
|
+
# Indicate that we created the filehandle and want to close it.
|
|
1192
|
+
ole.internal_fh = @internal_fh
|
|
1224
1193
|
|
|
1225
|
-
|
|
1194
|
+
ole.set_size(@biffsize)
|
|
1195
|
+
ole.write_header
|
|
1196
|
+
|
|
1197
|
+
while tmp = get_data
|
|
1198
|
+
ole.write(tmp)
|
|
1199
|
+
end
|
|
1200
|
+
|
|
1201
|
+
@worksheets.each do |worksheet|
|
|
1202
|
+
while tmp = worksheet.get_data
|
|
1226
1203
|
ole.write(tmp)
|
|
1227
1204
|
end
|
|
1205
|
+
end
|
|
1228
1206
|
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
ole.write(tmp)
|
|
1232
|
-
end
|
|
1233
|
-
end
|
|
1207
|
+
return ole.close
|
|
1208
|
+
end
|
|
1234
1209
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
workbook.set_file # use tempfile
|
|
1210
|
+
def store_through_ole_storage_lite
|
|
1211
|
+
# Create the Workbook stream.
|
|
1212
|
+
stream = 'Workbook'.unpack('C*').pack('v*')
|
|
1213
|
+
workbook = OLEStorageLitePPSFile.new(stream)
|
|
1214
|
+
workbook.set_file # use tempfile
|
|
1241
1215
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1216
|
+
while tmp = get_data
|
|
1217
|
+
workbook.append(tmp)
|
|
1218
|
+
end
|
|
1245
1219
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
end
|
|
1220
|
+
@worksheets.each do |worksheet|
|
|
1221
|
+
while tmp = worksheet.get_data
|
|
1222
|
+
workbook.append(tmp)
|
|
1250
1223
|
end
|
|
1224
|
+
end
|
|
1251
1225
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
# Create the properties streams, if any.
|
|
1256
|
-
if add_doc_properties
|
|
1257
|
-
stream = "\5SummaryInformation".unpack('C*').pack('v*')
|
|
1258
|
-
summary = OLEStorageLitePPSFile.new(stream, @summary)
|
|
1259
|
-
streams << summary
|
|
1260
|
-
stream = "\5DocumentSummaryInformation".unpack('C*').pack('v*')
|
|
1261
|
-
summary = OLEStorageLitePPSFile.new(stream, @doc_summary)
|
|
1262
|
-
streams << summary
|
|
1263
|
-
end
|
|
1264
|
-
# Create the OLE root document and add the substreams.
|
|
1265
|
-
localtime = @localtime.to_a[0..5]
|
|
1266
|
-
localtime[4] -= 1 # month
|
|
1267
|
-
localtime[5] -= 1900
|
|
1268
|
-
ole_root = OLEStorageLitePPSRoot.new(
|
|
1269
|
-
localtime,
|
|
1270
|
-
localtime,
|
|
1271
|
-
streams
|
|
1272
|
-
)
|
|
1273
|
-
ole_root.save(@file)
|
|
1226
|
+
streams = []
|
|
1227
|
+
streams << workbook
|
|
1274
1228
|
|
|
1275
|
-
|
|
1276
|
-
|
|
1229
|
+
# Create the properties streams, if any.
|
|
1230
|
+
if add_doc_properties
|
|
1231
|
+
stream = "\5SummaryInformation".unpack('C*').pack('v*')
|
|
1232
|
+
summary = OLEStorageLitePPSFile.new(stream, @summary)
|
|
1233
|
+
streams << summary
|
|
1234
|
+
stream = "\5DocumentSummaryInformation".unpack('C*').pack('v*')
|
|
1235
|
+
summary = OLEStorageLitePPSFile.new(stream, @doc_summary)
|
|
1236
|
+
streams << summary
|
|
1277
1237
|
end
|
|
1238
|
+
# Create the OLE root document and add the substreams.
|
|
1239
|
+
localtime = @localtime.to_a[0..5]
|
|
1240
|
+
localtime[4] -= 1 # month
|
|
1241
|
+
localtime[5] -= 1900
|
|
1242
|
+
ole_root = OLEStorageLitePPSRoot.new(
|
|
1243
|
+
localtime,
|
|
1244
|
+
localtime,
|
|
1245
|
+
streams
|
|
1246
|
+
)
|
|
1247
|
+
ole_root.save(@file)
|
|
1248
|
+
|
|
1249
|
+
# Close the filehandle if it was created internally.
|
|
1250
|
+
return @fh_out.close if @internal_fh != 0
|
|
1278
1251
|
end
|
|
1279
|
-
private :store_ole_filie
|
|
1280
1252
|
|
|
1281
|
-
###############################################################################
|
|
1282
|
-
#
|
|
1283
|
-
# calc_sheet_offsets()
|
|
1284
1253
|
#
|
|
1285
1254
|
# Calculate Worksheet BOF offsets records for use in the BOUNDSHEET records.
|
|
1286
1255
|
#
|
|
@@ -1318,11 +1287,7 @@ class Workbook < BIFFWriter
|
|
|
1318
1287
|
|
|
1319
1288
|
@biffsize = offset
|
|
1320
1289
|
end
|
|
1321
|
-
private :calc_sheet_offsets
|
|
1322
1290
|
|
|
1323
|
-
###############################################################################
|
|
1324
|
-
#
|
|
1325
|
-
# calc_mso_sizes()
|
|
1326
1291
|
#
|
|
1327
1292
|
# Calculate the MSODRAWINGGROUP sizes and the indexes of the Worksheet
|
|
1328
1293
|
# MSODRAWING records.
|
|
@@ -1348,10 +1313,9 @@ class Workbook < BIFFWriter
|
|
|
1348
1313
|
# required by each worksheet.
|
|
1349
1314
|
#
|
|
1350
1315
|
@worksheets.each do |sheet|
|
|
1351
|
-
next unless sheet.
|
|
1316
|
+
next unless sheet.type == 0x0000
|
|
1352
1317
|
|
|
1353
1318
|
num_images = sheet.num_images
|
|
1354
|
-
image_mso_size = sheet.image_mso_size
|
|
1355
1319
|
num_comments = sheet.prepare_comments
|
|
1356
1320
|
num_charts = sheet.prepare_charts
|
|
1357
1321
|
num_filters = sheet.filter_count
|
|
@@ -1362,7 +1326,7 @@ class Workbook < BIFFWriter
|
|
|
1362
1326
|
num_shapes = 1 + num_images + num_comments +
|
|
1363
1327
|
num_charts + num_filters
|
|
1364
1328
|
shapes_saved += num_shapes
|
|
1365
|
-
mso_size += image_mso_size
|
|
1329
|
+
mso_size += sheet.image_mso_size
|
|
1366
1330
|
|
|
1367
1331
|
# Add a drawing object for each sheet with comments.
|
|
1368
1332
|
drawings_saved += 1
|
|
@@ -1399,11 +1363,7 @@ class Workbook < BIFFWriter
|
|
|
1399
1363
|
drawings_saved, clusters
|
|
1400
1364
|
]
|
|
1401
1365
|
end
|
|
1402
|
-
private :calc_mso_sizes
|
|
1403
1366
|
|
|
1404
|
-
###############################################################################
|
|
1405
|
-
#
|
|
1406
|
-
# process_images()
|
|
1407
1367
|
#
|
|
1408
1368
|
# We need to process each image in each worksheet and extract information.
|
|
1409
1369
|
# Some of this information is stored and used in the Workbook and some is
|
|
@@ -1423,251 +1383,58 @@ class Workbook < BIFFWriter
|
|
|
1423
1383
|
images_size = 0
|
|
1424
1384
|
|
|
1425
1385
|
@worksheets.each do |sheet|
|
|
1426
|
-
next unless sheet.
|
|
1386
|
+
next unless sheet.type == 0x0000
|
|
1427
1387
|
next if sheet.prepare_images == 0
|
|
1428
1388
|
|
|
1429
1389
|
num_images = 0
|
|
1430
1390
|
image_mso_size = 0
|
|
1431
1391
|
|
|
1432
1392
|
sheet.images_array.each do |image|
|
|
1433
|
-
filename = image[2]
|
|
1434
1393
|
num_images += 1
|
|
1435
|
-
|
|
1436
|
-
#
|
|
1437
|
-
# For each Worksheet image we get a structure like this
|
|
1438
|
-
# [
|
|
1439
|
-
# $row,
|
|
1440
|
-
# $col,
|
|
1441
|
-
# $name,
|
|
1442
|
-
# $x_offset,
|
|
1443
|
-
# $y_offset,
|
|
1444
|
-
# $scale_x,
|
|
1445
|
-
# $scale_y,
|
|
1446
|
-
# ]
|
|
1447
|
-
#
|
|
1448
|
-
# And we add additional information:
|
|
1449
|
-
#
|
|
1450
|
-
# $image_id,
|
|
1451
|
-
# $type,
|
|
1452
|
-
# $width,
|
|
1453
|
-
# $height;
|
|
1454
|
-
|
|
1455
|
-
if images_seen[filename].nil?
|
|
1394
|
+
unless images_seen[image.filename]
|
|
1456
1395
|
# TODO should also match seen images based on checksum.
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
raise "Couldn't import #{filename}: #{$!}" unless fh
|
|
1461
|
-
|
|
1462
|
-
# Slurp the file into a string and do some size calcs.
|
|
1463
|
-
# my $data = do {local $/; <$fh>};
|
|
1464
|
-
data = fh.read
|
|
1465
|
-
size = data.bytesize
|
|
1466
|
-
checksum1 = image_checksum(data, image_id)
|
|
1467
|
-
checksum2 = checksum1
|
|
1468
|
-
ref_count = 1
|
|
1469
|
-
|
|
1470
|
-
# Process the image and extract dimensions.
|
|
1471
|
-
# Test for PNGs...
|
|
1472
|
-
if data.unpack('x A3')[0] == 'PNG'
|
|
1473
|
-
type, width, height = process_png(data)
|
|
1474
|
-
# Test for JFIF and Exif JPEGs...
|
|
1475
|
-
elsif ( data.unpack('n')[0] == 0xFFD8 &&
|
|
1476
|
-
(data.unpack('x6 A4')[0] == 'JFIF' ||
|
|
1477
|
-
data.unpack('x6 A4')[0] == 'Exif')
|
|
1478
|
-
)
|
|
1479
|
-
type, width, height = process_jpg(data, filename)
|
|
1480
|
-
# Test for BMPs...
|
|
1481
|
-
elsif data.unpack('A2')[0] == 'BM'
|
|
1482
|
-
type, width, height = process_bmp(data, filename)
|
|
1483
|
-
# The 14 byte header of the BMP is stripped off.
|
|
1484
|
-
data[0, 13] = ''
|
|
1485
|
-
|
|
1486
|
-
# A checksum of the new image data is also required.
|
|
1487
|
-
checksum2 = image_checksum(data, image_id, image_id)
|
|
1488
|
-
|
|
1489
|
-
# Adjust size -14 (header) + 16 (extra checksum).
|
|
1490
|
-
size += 2
|
|
1491
|
-
else
|
|
1492
|
-
raise "Unsupported image format for file: #{filename}\n"
|
|
1493
|
-
end
|
|
1494
|
-
|
|
1495
|
-
# Push the new data back into the Worksheet array;
|
|
1496
|
-
image.push(image_id, type, width, height)
|
|
1396
|
+
image.id = image_id
|
|
1397
|
+
image.ref_count = 1
|
|
1398
|
+
image.import
|
|
1497
1399
|
|
|
1498
1400
|
# Also store new data for use in duplicate images.
|
|
1499
|
-
previous_images.push(
|
|
1401
|
+
previous_images.push(image)
|
|
1500
1402
|
|
|
1501
1403
|
# Store information required by the Workbook.
|
|
1502
|
-
image_data.push(
|
|
1503
|
-
checksum1, checksum2])
|
|
1404
|
+
image_data.push(image)
|
|
1504
1405
|
|
|
1505
1406
|
# Keep track of overall data size.
|
|
1506
|
-
images_size += size +61 # Size for bstore container.
|
|
1507
|
-
image_mso_size += size +69 # Size for dgg container.
|
|
1407
|
+
images_size += image.size + 61 # Size for bstore container.
|
|
1408
|
+
image_mso_size += image.size + 69 # Size for dgg container.
|
|
1508
1409
|
|
|
1509
|
-
images_seen[filename] = image_id
|
|
1410
|
+
images_seen[image.filename] = image_id
|
|
1510
1411
|
image_id += 1
|
|
1511
|
-
fh.close
|
|
1512
1412
|
else
|
|
1513
1413
|
# We've processed this file already.
|
|
1514
|
-
index = images_seen[filename] -1
|
|
1414
|
+
index = images_seen[image.filename] -1
|
|
1515
1415
|
|
|
1516
1416
|
# Increase image reference count.
|
|
1517
|
-
image_data[index]
|
|
1417
|
+
image_data[index].ref_count += 1
|
|
1518
1418
|
|
|
1519
1419
|
# Add previously calculated data back onto the Worksheet array.
|
|
1520
|
-
#
|
|
1521
|
-
|
|
1522
|
-
image.
|
|
1420
|
+
# image_id, type, width, height
|
|
1421
|
+
image.id = previous_images[index].id
|
|
1422
|
+
image.type = previous_images[index].type
|
|
1423
|
+
image.width = previous_images[index].width
|
|
1424
|
+
image.height = previous_images[index].height
|
|
1523
1425
|
end
|
|
1524
1426
|
end
|
|
1525
1427
|
|
|
1526
1428
|
# Store information required by the Worksheet.
|
|
1527
1429
|
sheet.num_images = num_images
|
|
1528
1430
|
sheet.image_mso_size = image_mso_size
|
|
1529
|
-
|
|
1530
1431
|
end
|
|
1531
1432
|
|
|
1532
|
-
|
|
1533
1433
|
# Store information required by the Workbook.
|
|
1534
1434
|
@images_size = images_size
|
|
1535
1435
|
@images_data = image_data # Store the data for MSODRAWINGGROUP.
|
|
1536
1436
|
end
|
|
1537
|
-
private :process_images
|
|
1538
|
-
|
|
1539
|
-
###############################################################################
|
|
1540
|
-
#
|
|
1541
|
-
# image_checksum()
|
|
1542
|
-
#
|
|
1543
|
-
# Generate a checksum for the image using whichever module is available..The
|
|
1544
|
-
# available modules are checked in get_checksum_method(). Excel uses an MD4
|
|
1545
|
-
# checksum but any other will do. In the event of no checksum module being
|
|
1546
|
-
# available we simulate a checksum using the image index.
|
|
1547
|
-
#
|
|
1548
|
-
def image_checksum(data, index1, index2 = 0) #:nodoc:
|
|
1549
|
-
if @checksum_method == 1
|
|
1550
|
-
# Digest::MD4
|
|
1551
|
-
# return Digest::MD4::md4_hex($data);
|
|
1552
|
-
elsif @checksum_method == 2
|
|
1553
|
-
# Digest::Perl::MD4
|
|
1554
|
-
# return Digest::Perl::MD4::md4_hex($data);
|
|
1555
|
-
elsif @checksum_method == 3
|
|
1556
|
-
# Digest::MD5
|
|
1557
|
-
return Digest::MD5.hexdigest(data)
|
|
1558
|
-
else
|
|
1559
|
-
# Default
|
|
1560
|
-
return sprintf('%016X%016X', index2, index1)
|
|
1561
|
-
end
|
|
1562
|
-
end
|
|
1563
|
-
private :image_checksum
|
|
1564
|
-
|
|
1565
|
-
###############################################################################
|
|
1566
|
-
#
|
|
1567
|
-
# process_png()
|
|
1568
|
-
#
|
|
1569
|
-
# Extract width and height information from a PNG file.
|
|
1570
|
-
#
|
|
1571
|
-
def process_png(data) #:nodoc:
|
|
1572
|
-
type = 6 # Excel Blip type (MSOBLIPTYPE).
|
|
1573
|
-
width = data[16, 4].unpack("N")[0]
|
|
1574
|
-
height = data[20, 4].unpack("N")[0]
|
|
1575
|
-
|
|
1576
|
-
[type, width, height]
|
|
1577
|
-
end
|
|
1578
|
-
private :process_png
|
|
1579
|
-
|
|
1580
|
-
###############################################################################
|
|
1581
|
-
#
|
|
1582
|
-
# process_bmp()
|
|
1583
|
-
#
|
|
1584
|
-
# Extract width and height information from a BMP file.
|
|
1585
|
-
#
|
|
1586
|
-
# Most of these checks came from the old Worksheet::_process_bitmap() method.
|
|
1587
|
-
#
|
|
1588
|
-
def process_bmp(data, filename) #:nodoc:
|
|
1589
|
-
type = 7 # Excel Blip type (MSOBLIPTYPE).
|
|
1590
|
-
|
|
1591
|
-
# Check that the file is big enough to be a bitmap.
|
|
1592
|
-
if data.bytesize <= 0x36
|
|
1593
|
-
raise "#{filename} doesn't contain enough data."
|
|
1594
|
-
end
|
|
1595
|
-
|
|
1596
|
-
# Read the bitmap width and height. Verify the sizes.
|
|
1597
|
-
width, height = data.unpack("x18 V2")
|
|
1598
|
-
|
|
1599
|
-
if width > 0xFFFF
|
|
1600
|
-
raise "#{filename}: largest image width #{width} supported is 65k."
|
|
1601
|
-
end
|
|
1602
|
-
|
|
1603
|
-
if height > 0xFFFF
|
|
1604
|
-
raise "#{filename}: largest image height supported is 65k."
|
|
1605
|
-
end
|
|
1606
|
-
|
|
1607
|
-
# Read the bitmap planes and bpp data. Verify them.
|
|
1608
|
-
planes, bitcount = data.unpack("x26 v2")
|
|
1609
|
-
|
|
1610
|
-
if bitcount != 24
|
|
1611
|
-
raise "#{filename} isn't a 24bit true color bitmap."
|
|
1612
|
-
end
|
|
1613
|
-
|
|
1614
|
-
if planes != 1
|
|
1615
|
-
raise "#{filename}: only 1 plane supported in bitmap image."
|
|
1616
|
-
end
|
|
1617
|
-
|
|
1618
|
-
# Read the bitmap compression. Verify compression.
|
|
1619
|
-
compression = data.unpack("x30 V")
|
|
1620
|
-
|
|
1621
|
-
if compression != 0
|
|
1622
|
-
raise "#{filename}: compression not supported in bitmap image."
|
|
1623
|
-
end
|
|
1624
|
-
|
|
1625
|
-
[type, width, height]
|
|
1626
|
-
end
|
|
1627
|
-
private :process_bmp
|
|
1628
|
-
|
|
1629
|
-
###############################################################################
|
|
1630
|
-
#
|
|
1631
|
-
# process_jpg()
|
|
1632
|
-
#
|
|
1633
|
-
# Extract width and height information from a JPEG file.
|
|
1634
|
-
#
|
|
1635
|
-
def process_jpg(data, filename) # :nodoc:
|
|
1636
|
-
type = 5 # Excel Blip type (MSOBLIPTYPE).
|
|
1637
|
-
|
|
1638
|
-
offset = 2
|
|
1639
|
-
data_length = data.bytesize
|
|
1640
|
-
|
|
1641
|
-
# Search through the image data to find the 0xFFC0 marker. The height and
|
|
1642
|
-
# width are contained in the data for that sub element.
|
|
1643
|
-
while offset < data_length
|
|
1644
|
-
marker = data[offset, 2].unpack("n")
|
|
1645
|
-
marker = marker[0]
|
|
1646
|
-
length = data[offset+2, 2].unpack("n")
|
|
1647
|
-
length = length[0]
|
|
1648
|
-
|
|
1649
|
-
if marker == 0xFFC0 || marker == 0xFFC2
|
|
1650
|
-
height = data[offset+5, 2].unpack("n")
|
|
1651
|
-
height = height[0]
|
|
1652
|
-
width = data[offset+7, 2].unpack("n")
|
|
1653
|
-
width = width[0]
|
|
1654
|
-
break
|
|
1655
|
-
end
|
|
1656
|
-
|
|
1657
|
-
offset += length + 2
|
|
1658
|
-
break if marker == 0xFFDA
|
|
1659
|
-
end
|
|
1660
|
-
|
|
1661
|
-
if height.nil?
|
|
1662
|
-
raise "#{filename}: no size data found in jpeg image.\n"
|
|
1663
|
-
end
|
|
1664
|
-
|
|
1665
|
-
[type, width, height]
|
|
1666
|
-
end
|
|
1667
1437
|
|
|
1668
|
-
###############################################################################
|
|
1669
|
-
#
|
|
1670
|
-
# store_all_fonts()
|
|
1671
1438
|
#
|
|
1672
1439
|
# Store the Excel FONT records.
|
|
1673
1440
|
#
|
|
@@ -1754,11 +1521,7 @@ class Workbook < BIFFWriter
|
|
|
1754
1521
|
end
|
|
1755
1522
|
end
|
|
1756
1523
|
end
|
|
1757
|
-
private :store_all_fonts
|
|
1758
1524
|
|
|
1759
|
-
###############################################################################
|
|
1760
|
-
#
|
|
1761
|
-
# store_all_num_formats()
|
|
1762
1525
|
#
|
|
1763
1526
|
# Store user defined numerical formats i.e. FORMAT records
|
|
1764
1527
|
#
|
|
@@ -1793,11 +1556,7 @@ class Workbook < BIFFWriter
|
|
|
1793
1556
|
end
|
|
1794
1557
|
end
|
|
1795
1558
|
end
|
|
1796
|
-
private :store_all_num_formats
|
|
1797
1559
|
|
|
1798
|
-
###############################################################################
|
|
1799
|
-
#
|
|
1800
|
-
# store_all_xfs()
|
|
1801
1560
|
#
|
|
1802
1561
|
# Write all XF records.
|
|
1803
1562
|
#
|
|
@@ -1807,11 +1566,7 @@ class Workbook < BIFFWriter
|
|
|
1807
1566
|
append(xf)
|
|
1808
1567
|
end
|
|
1809
1568
|
end
|
|
1810
|
-
private :store_all_xfs
|
|
1811
1569
|
|
|
1812
|
-
###############################################################################
|
|
1813
|
-
#
|
|
1814
|
-
# store_all_styles()
|
|
1815
1570
|
#
|
|
1816
1571
|
# Write all STYLE records.
|
|
1817
1572
|
#
|
|
@@ -1838,11 +1593,7 @@ class Workbook < BIFFWriter
|
|
|
1838
1593
|
store_style(type, xf_index)
|
|
1839
1594
|
end
|
|
1840
1595
|
end
|
|
1841
|
-
private :store_all_styles
|
|
1842
1596
|
|
|
1843
|
-
###############################################################################
|
|
1844
|
-
#
|
|
1845
|
-
# store_names()
|
|
1846
1597
|
#
|
|
1847
1598
|
# Write the NAME record to define the print area and the repeat rows and cols.
|
|
1848
1599
|
#
|
|
@@ -1890,7 +1641,6 @@ class Workbook < BIFFWriter
|
|
|
1890
1641
|
end
|
|
1891
1642
|
end
|
|
1892
1643
|
end
|
|
1893
|
-
private :create_autofilter_name_records
|
|
1894
1644
|
|
|
1895
1645
|
def create_print_area_name_records(sorted_worksheets) #:nodoc:
|
|
1896
1646
|
sorted_worksheets.each do |worksheet|
|
|
@@ -1910,7 +1660,6 @@ class Workbook < BIFFWriter
|
|
|
1910
1660
|
end
|
|
1911
1661
|
end
|
|
1912
1662
|
end
|
|
1913
|
-
private :create_print_area_name_records
|
|
1914
1663
|
|
|
1915
1664
|
def create_print_title_name_records(sorted_worksheets) #:nodoc:
|
|
1916
1665
|
sorted_worksheets.each do |worksheet|
|
|
@@ -1964,7 +1713,6 @@ class Workbook < BIFFWriter
|
|
|
1964
1713
|
end
|
|
1965
1714
|
end
|
|
1966
1715
|
end
|
|
1967
|
-
private :create_print_title_name_records
|
|
1968
1716
|
|
|
1969
1717
|
###############################################################################
|
|
1970
1718
|
###############################################################################
|
|
@@ -1973,9 +1721,6 @@ class Workbook < BIFFWriter
|
|
|
1973
1721
|
#
|
|
1974
1722
|
|
|
1975
1723
|
|
|
1976
|
-
###############################################################################
|
|
1977
|
-
#
|
|
1978
|
-
# store_window1()
|
|
1979
1724
|
#
|
|
1980
1725
|
# Write Excel BIFF WINDOW1 record.
|
|
1981
1726
|
#
|
|
@@ -2005,20 +1750,23 @@ class Workbook < BIFFWriter
|
|
|
2005
1750
|
|
|
2006
1751
|
append(header, data)
|
|
2007
1752
|
end
|
|
2008
|
-
private :store_window1
|
|
2009
1753
|
|
|
2010
|
-
###############################################################################
|
|
2011
|
-
#
|
|
2012
|
-
# store_boundsheet()
|
|
2013
|
-
# my $sheetname = $_[0]; # Worksheet name
|
|
2014
|
-
# my $offset = $_[1]; # Location of worksheet BOF
|
|
2015
|
-
# my $type = $_[2]; # Worksheet type
|
|
2016
|
-
# my $hidden = $_[3]; # Worksheet hidden flag
|
|
2017
|
-
# my $encoding = $_[4]; # Sheet name encoding
|
|
2018
1754
|
#
|
|
2019
1755
|
# Writes Excel BIFF BOUNDSHEET record.
|
|
2020
1756
|
#
|
|
2021
|
-
|
|
1757
|
+
# sheetname # Worksheet name
|
|
1758
|
+
# offset # Location of worksheet BOF
|
|
1759
|
+
# type # Worksheet type
|
|
1760
|
+
# hidden # Worksheet hidden flag
|
|
1761
|
+
# encoding # Sheet name encoding
|
|
1762
|
+
#
|
|
1763
|
+
def store_boundsheet(sheet) #:nodoc:
|
|
1764
|
+
sheetname = sheet.name
|
|
1765
|
+
offset = sheet.offset
|
|
1766
|
+
type = sheet.type
|
|
1767
|
+
hidden = sheet.hidden? ? 1 : 0
|
|
1768
|
+
encoding = sheet.is_name_utf16be? ? 1 : 0
|
|
1769
|
+
|
|
2022
1770
|
record = 0x0085 # Record identifier
|
|
2023
1771
|
length = 0x08 + sheetname.bytesize # Number of bytes to follow
|
|
2024
1772
|
|
|
@@ -2037,16 +1785,13 @@ class Workbook < BIFFWriter
|
|
|
2037
1785
|
|
|
2038
1786
|
append(header, data, sheetname)
|
|
2039
1787
|
end
|
|
2040
|
-
private :store_boundsheet
|
|
2041
1788
|
|
|
2042
|
-
###############################################################################
|
|
2043
|
-
#
|
|
2044
|
-
# store_style()
|
|
2045
|
-
# type = $_[0] # Built-in style
|
|
2046
|
-
# xf_index = $_[1] # Index to style XF
|
|
2047
1789
|
#
|
|
2048
1790
|
# Write Excel BIFF STYLE records.
|
|
2049
1791
|
#
|
|
1792
|
+
# type # Built-in style
|
|
1793
|
+
# xf_index # Index to style XF
|
|
1794
|
+
#
|
|
2050
1795
|
def store_style(type, xf_index) #:nodoc:
|
|
2051
1796
|
record = 0x0293 # Record identifier
|
|
2052
1797
|
length = 0x0004 # Bytes to follow
|
|
@@ -2060,17 +1805,14 @@ class Workbook < BIFFWriter
|
|
|
2060
1805
|
|
|
2061
1806
|
append(header, data)
|
|
2062
1807
|
end
|
|
2063
|
-
private :store_style
|
|
2064
1808
|
|
|
2065
|
-
###############################################################################
|
|
2066
|
-
#
|
|
2067
|
-
# store_num_format()
|
|
2068
|
-
# my $format = $_[0]; # Custom format string
|
|
2069
|
-
# my $ifmt = $_[1]; # Format index code
|
|
2070
|
-
# my $encoding = $_[2]; # Char encoding for format string
|
|
2071
1809
|
#
|
|
2072
1810
|
# Writes Excel FORMAT record for non "built-in" numerical formats.
|
|
2073
1811
|
#
|
|
1812
|
+
# format # Custom format string
|
|
1813
|
+
# ifmt # Format index code
|
|
1814
|
+
# encoding # Char encoding for format string
|
|
1815
|
+
#
|
|
2074
1816
|
def store_num_format(format, ifmt, encoding) #:nodoc:
|
|
2075
1817
|
format = format.to_s unless format.respond_to?(:to_str)
|
|
2076
1818
|
record = 0x041E # Record identifier
|
|
@@ -2108,11 +1850,7 @@ class Workbook < BIFFWriter
|
|
|
2108
1850
|
|
|
2109
1851
|
append(header, data, format)
|
|
2110
1852
|
end
|
|
2111
|
-
private :store_num_format
|
|
2112
1853
|
|
|
2113
|
-
###############################################################################
|
|
2114
|
-
#
|
|
2115
|
-
# store_1904()
|
|
2116
1854
|
#
|
|
2117
1855
|
# Write Excel 1904 record to indicate the date system in use.
|
|
2118
1856
|
#
|
|
@@ -2127,11 +1865,7 @@ class Workbook < BIFFWriter
|
|
|
2127
1865
|
|
|
2128
1866
|
append(header, data)
|
|
2129
1867
|
end
|
|
2130
|
-
private :store_1904
|
|
2131
1868
|
|
|
2132
|
-
###############################################################################
|
|
2133
|
-
#
|
|
2134
|
-
# store_supbook()
|
|
2135
1869
|
#
|
|
2136
1870
|
# Write BIFF record SUPBOOK to indicate that the workbook contains external
|
|
2137
1871
|
# references, in our case, formula, print area and print title refs.
|
|
@@ -2148,11 +1882,7 @@ class Workbook < BIFFWriter
|
|
|
2148
1882
|
|
|
2149
1883
|
append(header, data)
|
|
2150
1884
|
end
|
|
2151
|
-
private :store_supbook
|
|
2152
1885
|
|
|
2153
|
-
###############################################################################
|
|
2154
|
-
#
|
|
2155
|
-
# store_externsheet()
|
|
2156
1886
|
#
|
|
2157
1887
|
# Writes the Excel BIFF EXTERNSHEET record. These references are used by
|
|
2158
1888
|
# formulas. TODO NAME record is required to define the print area and the
|
|
@@ -2233,22 +1963,19 @@ class Workbook < BIFFWriter
|
|
|
2233
1963
|
append(header, data)
|
|
2234
1964
|
end
|
|
2235
1965
|
|
|
2236
|
-
###############################################################################
|
|
2237
|
-
#
|
|
2238
|
-
# store_name_short()
|
|
2239
|
-
# index = shift # Sheet index
|
|
2240
|
-
# type = shift
|
|
2241
|
-
# ext_ref = shift # TODO
|
|
2242
|
-
# rowmin = $_[0] # Start row
|
|
2243
|
-
# rowmax = $_[1] # End row
|
|
2244
|
-
# colmin = $_[2] # Start column
|
|
2245
|
-
# colmax = $_[3] # end column
|
|
2246
|
-
# hidden = $_[4] # Name is hidden
|
|
2247
|
-
#
|
|
2248
1966
|
#
|
|
2249
1967
|
# Store the NAME record in the short format that is used for storing the print
|
|
2250
1968
|
# area, repeat rows only and repeat columns only.
|
|
2251
1969
|
#
|
|
1970
|
+
# index # Sheet index
|
|
1971
|
+
# type
|
|
1972
|
+
# ext_ref # TODO
|
|
1973
|
+
# rowmin # Start row
|
|
1974
|
+
# rowmax # End row
|
|
1975
|
+
# colmin # Start column
|
|
1976
|
+
# colmax # end column
|
|
1977
|
+
# hidden # Name is hidden
|
|
1978
|
+
#
|
|
2252
1979
|
def store_name_short(index, type, ext_ref, rowmin, rowmax, colmin, colmax, hidden = nil) #:nodoc:
|
|
2253
1980
|
record = 0x0018 # Record identifier
|
|
2254
1981
|
length = 0x001b # Number of bytes to follow
|
|
@@ -2292,25 +2019,21 @@ class Workbook < BIFFWriter
|
|
|
2292
2019
|
|
|
2293
2020
|
append(header, data)
|
|
2294
2021
|
end
|
|
2295
|
-
private :store_name_short
|
|
2296
2022
|
|
|
2297
|
-
###############################################################################
|
|
2298
|
-
#
|
|
2299
|
-
# store_name_long()
|
|
2300
|
-
# my $index = shift; # Sheet index
|
|
2301
|
-
# my $type = shift;
|
|
2302
|
-
# my $ext_ref = shift; # TODO
|
|
2303
|
-
# my $rowmin = $_[0]; # Start row
|
|
2304
|
-
# my $rowmax = $_[1]; # End row
|
|
2305
|
-
# my $colmin = $_[2]; # Start column
|
|
2306
|
-
# my $colmax = $_[3]; # end column
|
|
2307
|
-
#
|
|
2308
2023
|
#
|
|
2309
2024
|
# Store the NAME record in the long format that is used for storing the repeat
|
|
2310
2025
|
# rows and columns when both are specified. This share a lot of code with
|
|
2311
2026
|
# store_name_short() but we use a separate method to keep the code clean.
|
|
2312
2027
|
# Code abstraction for reuse can be carried too far, and I should know. ;-)
|
|
2313
2028
|
#
|
|
2029
|
+
# index # Sheet index
|
|
2030
|
+
# type
|
|
2031
|
+
# ext_ref # TODO
|
|
2032
|
+
# rowmin # Start row
|
|
2033
|
+
# rowmax # End row
|
|
2034
|
+
# colmin # Start column
|
|
2035
|
+
# colmax # end column
|
|
2036
|
+
#
|
|
2314
2037
|
def store_name_long(index, type, ext_ref, rowmin, rowmax, colmin, colmax) #:nodoc:
|
|
2315
2038
|
record = 0x0018 # Record identifier
|
|
2316
2039
|
length = 0x002a # Number of bytes to follow
|
|
@@ -2368,11 +2091,7 @@ class Workbook < BIFFWriter
|
|
|
2368
2091
|
|
|
2369
2092
|
append(header, data)
|
|
2370
2093
|
end
|
|
2371
|
-
private :store_name_long
|
|
2372
2094
|
|
|
2373
|
-
###############################################################################
|
|
2374
|
-
#
|
|
2375
|
-
# store_palette()
|
|
2376
2095
|
#
|
|
2377
2096
|
# Stores the PALETTE biff record.
|
|
2378
2097
|
#
|
|
@@ -2391,11 +2110,7 @@ class Workbook < BIFFWriter
|
|
|
2391
2110
|
|
|
2392
2111
|
append(header, data)
|
|
2393
2112
|
end
|
|
2394
|
-
private :store_palette
|
|
2395
2113
|
|
|
2396
|
-
###############################################################################
|
|
2397
|
-
#
|
|
2398
|
-
# store_codepage()
|
|
2399
2114
|
#
|
|
2400
2115
|
# Stores the CODEPAGE biff record.
|
|
2401
2116
|
#
|
|
@@ -2406,11 +2121,7 @@ class Workbook < BIFFWriter
|
|
|
2406
2121
|
|
|
2407
2122
|
store_common(record, length, cv)
|
|
2408
2123
|
end
|
|
2409
|
-
private :store_codepage
|
|
2410
2124
|
|
|
2411
|
-
###############################################################################
|
|
2412
|
-
#
|
|
2413
|
-
# store_country()
|
|
2414
2125
|
#
|
|
2415
2126
|
# Stores the COUNTRY biff record.
|
|
2416
2127
|
#
|
|
@@ -2422,22 +2133,17 @@ class Workbook < BIFFWriter
|
|
|
2422
2133
|
|
|
2423
2134
|
store_common(record, length, country_default, country_win_ini)
|
|
2424
2135
|
end
|
|
2425
|
-
private :store_country
|
|
2426
2136
|
|
|
2427
|
-
###############################################################################
|
|
2428
|
-
#
|
|
2429
|
-
# store_hideobj()
|
|
2430
2137
|
#
|
|
2431
2138
|
# Stores the HIDEOBJ biff record.
|
|
2432
2139
|
#
|
|
2433
2140
|
def store_hideobj #:nodoc:
|
|
2434
2141
|
record = 0x008D # Record identifier
|
|
2435
2142
|
length = 0x0002 # Number of bytes to follow
|
|
2436
|
-
hide = @hideobj
|
|
2143
|
+
hide = @hideobj ? 1 : 0 # Option to hide objects
|
|
2437
2144
|
|
|
2438
2145
|
store_common(record, length, hide)
|
|
2439
2146
|
end
|
|
2440
|
-
private :store_hideobj
|
|
2441
2147
|
|
|
2442
2148
|
def store_common(record, length, *data) #:nodoc:
|
|
2443
2149
|
header = [record, length].pack("vv")
|
|
@@ -2445,11 +2151,7 @@ class Workbook < BIFFWriter
|
|
|
2445
2151
|
|
|
2446
2152
|
append(header, add_data)
|
|
2447
2153
|
end
|
|
2448
|
-
private :store_common
|
|
2449
2154
|
|
|
2450
|
-
###############################################################################
|
|
2451
|
-
#
|
|
2452
|
-
# calculate_extern_sizes()
|
|
2453
2155
|
#
|
|
2454
2156
|
# We need to calculate the space required by the SUPBOOK, EXTERNSHEET and NAME
|
|
2455
2157
|
# records so that it can be added to the BOUNDSHEET offsets.
|
|
@@ -2525,11 +2227,7 @@ class Workbook < BIFFWriter
|
|
|
2525
2227
|
def add_ext_refs(ext_refs, key) #:nodoc:
|
|
2526
2228
|
ext_refs[key] = ext_refs.keys.size
|
|
2527
2229
|
end
|
|
2528
|
-
private :add_ext_refs
|
|
2529
2230
|
|
|
2530
|
-
###############################################################################
|
|
2531
|
-
#
|
|
2532
|
-
# calculate_shared_string_sizes()
|
|
2533
2231
|
#
|
|
2534
2232
|
# Handling of the SST continue blocks is complicated by the need to include an
|
|
2535
2233
|
# additional continuation byte depending on whether the string is split between
|
|
@@ -2652,7 +2350,6 @@ class Workbook < BIFFWriter
|
|
|
2652
2350
|
|
|
2653
2351
|
length
|
|
2654
2352
|
end
|
|
2655
|
-
private :calculate_shared_string_sizes
|
|
2656
2353
|
|
|
2657
2354
|
def split_string_setup(encoding, split_string, continue_limit, written, continue) #:nodoc:
|
|
2658
2355
|
# We need to avoid the case where a string is continued in the first
|
|
@@ -2684,11 +2381,7 @@ class Workbook < BIFFWriter
|
|
|
2684
2381
|
end
|
|
2685
2382
|
[header_length, space_remaining, align, split_string]
|
|
2686
2383
|
end
|
|
2687
|
-
private :split_string_setup
|
|
2688
2384
|
|
|
2689
|
-
###############################################################################
|
|
2690
|
-
#
|
|
2691
|
-
# store_shared_strings()
|
|
2692
2385
|
#
|
|
2693
2386
|
# Write all of the workbooks strings into an indexed array.
|
|
2694
2387
|
#
|
|
@@ -2840,11 +2533,7 @@ class Workbook < BIFFWriter
|
|
|
2840
2533
|
end
|
|
2841
2534
|
end
|
|
2842
2535
|
end
|
|
2843
|
-
private :store_shared_strings
|
|
2844
2536
|
|
|
2845
|
-
###############################################################################
|
|
2846
|
-
#
|
|
2847
|
-
# calculate_extsst_size
|
|
2848
2537
|
#
|
|
2849
2538
|
# The number of buckets used in the EXTSST is between 0 and 128. The number of
|
|
2850
2539
|
# strings per bucket (bucket size) has a minimum value of 8 and a theoretical
|
|
@@ -2869,9 +2558,6 @@ class Workbook < BIFFWriter
|
|
|
2869
2558
|
6 + 8 * buckets
|
|
2870
2559
|
end
|
|
2871
2560
|
|
|
2872
|
-
###############################################################################
|
|
2873
|
-
#
|
|
2874
|
-
# store_extsst
|
|
2875
2561
|
#
|
|
2876
2562
|
# Write EXTSST table using the offsets calculated in store_shared_strings().
|
|
2877
2563
|
#
|
|
@@ -2891,15 +2577,11 @@ class Workbook < BIFFWriter
|
|
|
2891
2577
|
|
|
2892
2578
|
append(header, data)
|
|
2893
2579
|
end
|
|
2894
|
-
private :store_extsst
|
|
2895
2580
|
|
|
2896
2581
|
#
|
|
2897
2582
|
# Methods related to comments and MSO objects.
|
|
2898
2583
|
#
|
|
2899
2584
|
|
|
2900
|
-
###############################################################################
|
|
2901
|
-
#
|
|
2902
|
-
# add_mso_drawing_group()
|
|
2903
2585
|
#
|
|
2904
2586
|
# Write the MSODRAWINGGROUP record that keeps track of the Escher drawing
|
|
2905
2587
|
# objects in the file such as images, comments and filters.
|
|
@@ -2914,7 +2596,7 @@ class Workbook < BIFFWriter
|
|
|
2914
2596
|
data += store_mso_dgg(*@mso_clusters)
|
|
2915
2597
|
data += store_mso_bstore_container
|
|
2916
2598
|
@images_data.each do |image|
|
|
2917
|
-
data += store_mso_images(
|
|
2599
|
+
data += store_mso_images(image)
|
|
2918
2600
|
end
|
|
2919
2601
|
data += store_mso_opt
|
|
2920
2602
|
data += store_mso_split_menu_colors
|
|
@@ -2926,13 +2608,9 @@ class Workbook < BIFFWriter
|
|
|
2926
2608
|
|
|
2927
2609
|
header + data # For testing only.
|
|
2928
2610
|
end
|
|
2929
|
-
private :add_mso_drawing_group
|
|
2930
2611
|
|
|
2931
|
-
###############################################################################
|
|
2932
|
-
#
|
|
2933
|
-
# add_mso_drawing_group_continue()
|
|
2934
2612
|
#
|
|
2935
|
-
# See first
|
|
2613
|
+
# See first BIFFwriter#add_continue() method.
|
|
2936
2614
|
#
|
|
2937
2615
|
# Add specialised CONTINUE headers to large MSODRAWINGGROUP data block.
|
|
2938
2616
|
# We use the Excel 97 max block size of 8228 - 4 bytes for the header = 8224.
|
|
@@ -2985,18 +2663,13 @@ class Workbook < BIFFWriter
|
|
|
2985
2663
|
# Turn the base class add_continue() method back on.
|
|
2986
2664
|
@ignore_continue = 0
|
|
2987
2665
|
end
|
|
2988
|
-
private :add_mso_drawing_group_continue
|
|
2989
2666
|
|
|
2990
2667
|
def devide_string(string, nth) #:nodoc:
|
|
2991
2668
|
first_string = string[0, nth]
|
|
2992
2669
|
latter_string = string[nth, string.size - nth]
|
|
2993
2670
|
[first_string, latter_string]
|
|
2994
2671
|
end
|
|
2995
|
-
private :devide_string
|
|
2996
2672
|
|
|
2997
|
-
###############################################################################
|
|
2998
|
-
#
|
|
2999
|
-
# store_mso_dgg_container()
|
|
3000
2673
|
#
|
|
3001
2674
|
# Write the Escher DggContainer record that is part of MSODRAWINGGROUP.
|
|
3002
2675
|
#
|
|
@@ -3009,16 +2682,7 @@ class Workbook < BIFFWriter
|
|
|
3009
2682
|
|
|
3010
2683
|
add_mso_generic(type, version, instance, data, length)
|
|
3011
2684
|
end
|
|
3012
|
-
private :store_mso_dgg_container
|
|
3013
2685
|
|
|
3014
|
-
###############################################################################
|
|
3015
|
-
#
|
|
3016
|
-
# store_mso_dgg()
|
|
3017
|
-
# my $max_spid = $_[0];
|
|
3018
|
-
# my $num_clusters = $_[1];
|
|
3019
|
-
# my $shapes_saved = $_[2];
|
|
3020
|
-
# my $drawings_saved = $_[3];
|
|
3021
|
-
# my $clusters = $_[4];
|
|
3022
2686
|
#
|
|
3023
2687
|
# Write the Escher Dgg record that is part of MSODRAWINGGROUP.
|
|
3024
2688
|
#
|
|
@@ -3041,11 +2705,7 @@ class Workbook < BIFFWriter
|
|
|
3041
2705
|
|
|
3042
2706
|
add_mso_generic(type, version, instance, data, length)
|
|
3043
2707
|
end
|
|
3044
|
-
private :store_mso_dgg
|
|
3045
2708
|
|
|
3046
|
-
###############################################################################
|
|
3047
|
-
#
|
|
3048
|
-
# store_mso_bstore_container()
|
|
3049
2709
|
#
|
|
3050
2710
|
# Write the Escher BstoreContainer record that is part of MSODRAWINGGROUP.
|
|
3051
2711
|
#
|
|
@@ -3060,47 +2720,22 @@ class Workbook < BIFFWriter
|
|
|
3060
2720
|
|
|
3061
2721
|
add_mso_generic(type, version, instance, data, length)
|
|
3062
2722
|
end
|
|
3063
|
-
private :store_mso_bstore_container
|
|
3064
2723
|
|
|
3065
|
-
###############################################################################
|
|
3066
|
-
#
|
|
3067
|
-
# store_mso_images()
|
|
3068
|
-
# ref_count = $_[0]
|
|
3069
|
-
# image_type = $_[1]
|
|
3070
|
-
# image = $_[2]
|
|
3071
|
-
# size = $_[3]
|
|
3072
|
-
# checksum1 = $_[4]
|
|
3073
|
-
# checksum2 = $_[5]
|
|
3074
2724
|
#
|
|
3075
2725
|
# Write the Escher BstoreContainer record that is part of MSODRAWINGGROUP.
|
|
3076
2726
|
#
|
|
3077
|
-
def store_mso_images(
|
|
2727
|
+
def store_mso_images(image)
|
|
3078
2728
|
blip_store_entry = store_mso_blip_store_entry(
|
|
3079
|
-
ref_count,
|
|
3080
|
-
image_type,
|
|
3081
|
-
size,
|
|
3082
|
-
checksum1
|
|
2729
|
+
image.ref_count, image.type, image.size, image.checksum1
|
|
3083
2730
|
)
|
|
3084
2731
|
|
|
3085
2732
|
blip = store_mso_blip(
|
|
3086
|
-
|
|
3087
|
-
image,
|
|
3088
|
-
size,
|
|
3089
|
-
checksum1,
|
|
3090
|
-
checksum2
|
|
2733
|
+
image.type, image.data, image.size, image.checksum1, image.checksum2
|
|
3091
2734
|
)
|
|
3092
2735
|
|
|
3093
2736
|
blip_store_entry + blip
|
|
3094
2737
|
end
|
|
3095
|
-
private :store_mso_images
|
|
3096
2738
|
|
|
3097
|
-
###############################################################################
|
|
3098
|
-
#
|
|
3099
|
-
# store_mso_blip_store_entry()
|
|
3100
|
-
# ref_count = $_[0]
|
|
3101
|
-
# image_type = $_[1]
|
|
3102
|
-
# size = $_[2]
|
|
3103
|
-
# checksum1 = $_[3]
|
|
3104
2739
|
#
|
|
3105
2740
|
# Write the Escher BlipStoreEntry record that is part of MSODRAWINGGROUP.
|
|
3106
2741
|
#
|
|
@@ -3123,16 +2758,7 @@ class Workbook < BIFFWriter
|
|
|
3123
2758
|
|
|
3124
2759
|
add_mso_generic(type, version, instance, data, length)
|
|
3125
2760
|
end
|
|
3126
|
-
private :store_mso_blip_store_entry
|
|
3127
2761
|
|
|
3128
|
-
###############################################################################
|
|
3129
|
-
#
|
|
3130
|
-
# store_mso_blip()
|
|
3131
|
-
# image_type = $_[0]
|
|
3132
|
-
# image_data = $_[1]
|
|
3133
|
-
# size = $_[2]
|
|
3134
|
-
# checksum1 = $_[3]
|
|
3135
|
-
# checksum2 = $_[4]
|
|
3136
2762
|
#
|
|
3137
2763
|
# Write the Escher Blip record that is part of MSODRAWINGGROUP.
|
|
3138
2764
|
#
|
|
@@ -3155,11 +2781,7 @@ class Workbook < BIFFWriter
|
|
|
3155
2781
|
|
|
3156
2782
|
add_mso_generic(type, version, instance, data, length)
|
|
3157
2783
|
end
|
|
3158
|
-
private :store_mso_blip
|
|
3159
2784
|
|
|
3160
|
-
###############################################################################
|
|
3161
|
-
#
|
|
3162
|
-
# store_mso_opt()
|
|
3163
2785
|
#
|
|
3164
2786
|
# Write the Escher Opt record that is part of MSODRAWINGGROUP.
|
|
3165
2787
|
#
|
|
@@ -3174,11 +2796,7 @@ class Workbook < BIFFWriter
|
|
|
3174
2796
|
|
|
3175
2797
|
add_mso_generic(type, version, instance, data, length)
|
|
3176
2798
|
end
|
|
3177
|
-
private :store_mso_opt
|
|
3178
2799
|
|
|
3179
|
-
###############################################################################
|
|
3180
|
-
#
|
|
3181
|
-
# store_mso_split_menu_colors()
|
|
3182
2800
|
#
|
|
3183
2801
|
# Write the Escher SplitMenuColors record that is part of MSODRAWINGGROUP.
|
|
3184
2802
|
#
|
|
@@ -3193,22 +2811,14 @@ class Workbook < BIFFWriter
|
|
|
3193
2811
|
|
|
3194
2812
|
add_mso_generic(type, version, instance, data, length)
|
|
3195
2813
|
end
|
|
3196
|
-
private :store_mso_split_menu_colors
|
|
3197
2814
|
|
|
3198
2815
|
def cleanup #:nodoc:
|
|
3199
2816
|
super
|
|
3200
2817
|
sheets.each { |sheet| sheet.cleanup }
|
|
3201
2818
|
end
|
|
3202
|
-
private :cleanup
|
|
3203
|
-
|
|
3204
|
-
private
|
|
3205
2819
|
|
|
3206
2820
|
def add_doc_properties
|
|
3207
|
-
@add_doc_properties
|
|
3208
|
-
end
|
|
3209
|
-
|
|
3210
|
-
def add_doc_properties=(val)
|
|
3211
|
-
@add_doc_properties = val
|
|
2821
|
+
@add_doc_properties ||= false
|
|
3212
2822
|
end
|
|
3213
2823
|
|
|
3214
2824
|
def formats
|