writeexcel 0.1.0 → 0.3.0
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/README +26 -31
- data/examples/a_simple.rb +42 -42
- data/examples/{autofilters.rb → autofilter.rb} +264 -266
- data/examples/bigfile.rb +29 -0
- data/examples/chart_area.rb +120 -0
- data/examples/chart_bar.rb +119 -0
- data/examples/chart_column.rb +119 -0
- data/examples/chart_line.rb +119 -0
- data/examples/chart_pie.rb +107 -0
- data/examples/chart_scatter.rb +120 -0
- data/examples/chart_stock.rb +147 -0
- data/examples/copyformat.rb +51 -51
- data/examples/data_validate.rb +278 -278
- data/examples/date_time.rb +86 -86
- data/examples/defined_name.rb +31 -0
- data/examples/demo.rb +120 -118
- data/examples/diag_border.rb +35 -35
- data/examples/formats.rb +489 -489
- data/examples/header.rb +136 -136
- data/examples/hidden.rb +28 -28
- data/examples/hyperlink.rb +42 -42
- data/examples/images.rb +52 -52
- data/examples/merge1.rb +39 -39
- data/examples/merge2.rb +44 -44
- data/examples/merge3.rb +65 -65
- data/examples/merge4.rb +82 -82
- data/examples/merge5.rb +79 -79
- data/examples/properties.rb +33 -0
- data/examples/properties_jp.rb +32 -0
- data/examples/protection.rb +46 -46
- data/examples/regions.rb +52 -52
- data/examples/repeat.rb +42 -42
- data/examples/stats.rb +75 -75
- data/examples/stocks.rb +80 -80
- data/examples/tab_colors.rb +30 -30
- data/examples/write_arrays.rb +82 -0
- data/lib/writeexcel.rb +1134 -18
- data/lib/writeexcel/biffwriter.rb +273 -260
- data/lib/writeexcel/chart.rb +2306 -217
- data/lib/writeexcel/charts/area.rb +152 -0
- data/lib/writeexcel/charts/bar.rb +177 -0
- data/lib/writeexcel/charts/column.rb +156 -0
- data/lib/writeexcel/charts/external.rb +61 -0
- data/lib/writeexcel/charts/line.rb +152 -0
- data/lib/writeexcel/charts/pie.rb +169 -0
- data/lib/writeexcel/charts/scatter.rb +192 -0
- data/lib/writeexcel/charts/stock.rb +211 -0
- data/lib/writeexcel/excelformulaparser.rb +208 -195
- data/lib/writeexcel/format.rb +1697 -1108
- data/lib/writeexcel/formula.rb +1050 -986
- data/lib/writeexcel/olewriter.rb +322 -322
- data/lib/writeexcel/properties.rb +251 -250
- data/lib/writeexcel/storage_lite.rb +968 -0
- data/lib/writeexcel/workbook.rb +3294 -2630
- data/lib/writeexcel/worksheet.rb +9012 -6377
- 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/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/a_simple.xls +0 -0
- data/test/perl_output/autofilter.xls +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/data_validate.xls +0 -0
- data/test/perl_output/date_time.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/headers.xls +0 -0
- data/test/perl_output/hyperlink.xls +0 -0
- data/test/perl_output/images.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/protection.xls +0 -0
- data/test/perl_output/regions.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/workbook1.xls +0 -0
- data/test/perl_output/workbook2.xls +0 -0
- data/test/tc_all.rb +32 -31
- data/test/tc_biff.rb +104 -104
- data/test/tc_chart.rb +22 -22
- data/test/tc_example_match.rb +1944 -1280
- data/test/tc_format.rb +1254 -1267
- data/test/tc_formula.rb +63 -63
- data/test/tc_ole.rb +110 -110
- data/test/tc_storage_lite.rb +149 -0
- data/test/tc_workbook.rb +140 -115
- data/test/tc_worksheet.rb +115 -115
- data/test/test_00_IEEE_double.rb +14 -14
- data/test/test_01_add_worksheet.rb +12 -12
- data/test/test_02_merge_formats.rb +58 -58
- data/test/test_04_dimensions.rb +397 -397
- data/test/test_05_rows.rb +182 -182
- data/test/test_06_extsst.rb +80 -80
- data/test/test_11_date_time.rb +484 -484
- data/test/test_12_date_only.rb +506 -506
- data/test/test_13_date_seconds.rb +486 -486
- data/test/test_21_escher.rb +642 -629
- data/test/test_22_mso_drawing_group.rb +750 -739
- data/test/test_23_note.rb +78 -78
- data/test/test_24_txo.rb +80 -80
- data/test/test_25_position_object.rb +82 -0
- data/test/test_26_autofilter.rb +327 -327
- data/test/test_27_autofilter.rb +144 -144
- data/test/test_28_autofilter.rb +174 -174
- data/test/test_29_process_jpg.rb +681 -131
- data/test/test_30_validation_dval.rb +82 -82
- data/test/test_31_validation_dv_strings.rb +131 -131
- data/test/test_32_validation_dv_formula.rb +211 -211
- data/test/test_40_property_types.rb +191 -191
- data/test/test_41_properties.rb +238 -238
- data/test/test_42_set_properties.rb +442 -419
- data/test/test_50_name_stored.rb +305 -0
- data/test/test_51_name_print_area.rb +363 -0
- data/test/test_52_name_print_titles.rb +460 -0
- data/test/test_53_autofilter.rb +209 -0
- data/test/test_60_chart_generic.rb +576 -0
- data/test/test_61_chart_subclasses.rb +97 -0
- data/test/test_62_chart_formats.rb +270 -0
- data/test/test_63_chart_area_formats.rb +647 -0
- data/test/test_chartex.rb +35 -0
- data/test/ts_all.rb +46 -34
- data/writeexcel.gemspec +18 -0
- data/writeexcel.rdoc +583 -0
- metadata +162 -108
data/lib/writeexcel/olewriter.rb
CHANGED
@@ -1,322 +1,322 @@
|
|
1
|
-
###############################################################################
|
2
|
-
#
|
3
|
-
# BIFFwriter - An abstract base class for Excel workbooks and worksheets.
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# Used in conjunction with
|
7
|
-
#
|
8
|
-
# Copyright 2000-
|
9
|
-
#
|
10
|
-
# original written in Perl by John McNamara
|
11
|
-
# converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
|
12
|
-
#
|
13
|
-
class MaxSizeError < StandardError; end
|
14
|
-
|
15
|
-
class OLEWriter
|
16
|
-
|
17
|
-
# Not meant for public consumption
|
18
|
-
MaxSize = 7087104 # Use
|
19
|
-
BlockSize = 4096
|
20
|
-
BlockDiv = 512
|
21
|
-
ListBlocks = 127
|
22
|
-
|
23
|
-
attr_reader :biff_size, :book_size, :big_blocks, :list_blocks
|
24
|
-
attr_reader :root_start, :size_allowed
|
25
|
-
attr_accessor :biff_only, :internal_fh
|
26
|
-
|
27
|
-
# Accept an IO or IO-like object or a filename (as a String)
|
28
|
-
def initialize(arg)
|
29
|
-
if arg.kind_of?(String)
|
30
|
-
@io = File.open(arg, "w")
|
31
|
-
else
|
32
|
-
@io = arg
|
33
|
-
end
|
34
|
-
@io.binmode
|
35
|
-
|
36
|
-
@filehandle = ""
|
37
|
-
@fileclosed = false
|
38
|
-
@internal_fh = 0
|
39
|
-
@biff_only = 0
|
40
|
-
@size_allowed = true
|
41
|
-
@biff_size = 0
|
42
|
-
@book_size = 0
|
43
|
-
@big_blocks = 0
|
44
|
-
@list_blocks = 0
|
45
|
-
@root_start = 0
|
46
|
-
@block_count = 4
|
47
|
-
end
|
48
|
-
|
49
|
-
# Imitate IO.open behavior
|
50
|
-
|
51
|
-
###############################################################################
|
52
|
-
#
|
53
|
-
# _initialize()
|
54
|
-
#
|
55
|
-
# Create a new filehandle or use the provided filehandle.
|
56
|
-
#
|
57
|
-
def _initialize
|
58
|
-
olefile = @olefilename
|
59
|
-
|
60
|
-
# If the filename is a reference it is assumed that it is a valid
|
61
|
-
# filehandle, if not we create a filehandle.
|
62
|
-
#
|
63
|
-
|
64
|
-
# Create a new file, open for writing
|
65
|
-
fh = open(olefile, "wb")
|
66
|
-
|
67
|
-
# Workbook.pm also checks this but something may have happened since
|
68
|
-
# then.
|
69
|
-
raise "Can't open olefile. It may be in use or protected.\n" unless fh
|
70
|
-
|
71
|
-
@internal_fh = 1
|
72
|
-
|
73
|
-
# Store filehandle
|
74
|
-
@filehandle = fh
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.open(arg)
|
78
|
-
if block_given?
|
79
|
-
ole = self.new(arg)
|
80
|
-
result = yield(ole)
|
81
|
-
ole.close
|
82
|
-
result
|
83
|
-
else
|
84
|
-
self.new(arg)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
###############################################################################
|
89
|
-
#
|
90
|
-
# write($data)
|
91
|
-
#
|
92
|
-
# Write BIFF data to OLE file.
|
93
|
-
#
|
94
|
-
def write(data)
|
95
|
-
#print "ole write\n"
|
96
|
-
#print data.unpack('C*').map! {|c| sprintf("%02X", c) }.join(' ') + "\n\n"
|
97
|
-
@io.write(data)
|
98
|
-
end
|
99
|
-
# def print(data)
|
100
|
-
# @io.print(data)
|
101
|
-
# end
|
102
|
-
|
103
|
-
###############################################################################
|
104
|
-
#
|
105
|
-
# set_size($biffsize)
|
106
|
-
#
|
107
|
-
# Set the size of the data to be written to the OLE stream
|
108
|
-
#
|
109
|
-
# $big_blocks = (109 depot block x (128 -1 marker word)
|
110
|
-
# - (1 x end words)) = 13842
|
111
|
-
# $maxsize = $big_blocks * 512 bytes = 7087104
|
112
|
-
#
|
113
|
-
def set_size(size = BlockSize)
|
114
|
-
if size > MaxSize
|
115
|
-
return @size_allowed = false
|
116
|
-
end
|
117
|
-
|
118
|
-
@biff_size = size
|
119
|
-
|
120
|
-
if biff_size > BlockSize
|
121
|
-
@book_size = size
|
122
|
-
else
|
123
|
-
@book_size = BlockSize
|
124
|
-
end
|
125
|
-
|
126
|
-
@size_allowed = true
|
127
|
-
end
|
128
|
-
|
129
|
-
###############################################################################
|
130
|
-
#
|
131
|
-
# _calculate_sizes()
|
132
|
-
#
|
133
|
-
# Calculate various sizes needed for the OLE stream
|
134
|
-
#
|
135
|
-
def calculate_sizes
|
136
|
-
@big_blocks = (@book_size.to_f/BlockDiv.to_f).ceil
|
137
|
-
@list_blocks = (@big_blocks / ListBlocks) + 1
|
138
|
-
@root_start = @big_blocks
|
139
|
-
end
|
140
|
-
|
141
|
-
###############################################################################
|
142
|
-
#
|
143
|
-
# close()
|
144
|
-
#
|
145
|
-
# Write root entry, big block list and close the filehandle.
|
146
|
-
# This routine is used to explicitly close the open filehandle without
|
147
|
-
# having to wait for DESTROY.
|
148
|
-
#
|
149
|
-
def close
|
150
|
-
if @size_allowed == true
|
151
|
-
#print "write_padding"
|
152
|
-
write_padding if @biff_only == 0
|
153
|
-
#print "write_property_storage"
|
154
|
-
write_property_storage if @biff_only == 0
|
155
|
-
#print "write_big_block_depot"
|
156
|
-
write_big_block_depot if @biff_only == 0
|
157
|
-
end
|
158
|
-
@io.close
|
159
|
-
end
|
160
|
-
|
161
|
-
###############################################################################
|
162
|
-
#
|
163
|
-
# write_header()
|
164
|
-
#
|
165
|
-
# Write OLE header block.
|
166
|
-
#
|
167
|
-
def write_header
|
168
|
-
return if @biff_only == 1
|
169
|
-
calculate_sizes
|
170
|
-
root_start = @root_start
|
171
|
-
num_lists = @list_blocks
|
172
|
-
|
173
|
-
id = [0xD0CF11E0, 0xA1B11AE1].pack("NN")
|
174
|
-
unknown1 = [0x00, 0x00, 0x00, 0x00].pack("VVVV")
|
175
|
-
unknown2 = [0x3E, 0x03].pack("vv")
|
176
|
-
unknown3 = [-2].pack("v")
|
177
|
-
unknown4 = [0x09].pack("v")
|
178
|
-
unknown5 = [0x06, 0x00, 0x00].pack("VVV")
|
179
|
-
num_bbd_blocks = [num_lists].pack("V")
|
180
|
-
root_startblock = [root_start].pack("V")
|
181
|
-
unknown6 = [0x00, 0x1000].pack("VV")
|
182
|
-
sbd_startblock = [-2].pack("V")
|
183
|
-
unknown7 = [0x00, -2 ,0x00].pack("VVV")
|
184
|
-
|
185
|
-
write(id)
|
186
|
-
write(unknown1)
|
187
|
-
write(unknown2)
|
188
|
-
write(unknown3)
|
189
|
-
write(unknown4)
|
190
|
-
write(unknown5)
|
191
|
-
write(num_bbd_blocks)
|
192
|
-
write(root_startblock)
|
193
|
-
write(unknown6)
|
194
|
-
write(sbd_startblock)
|
195
|
-
write(unknown7)
|
196
|
-
|
197
|
-
unused = [-1].pack("V")
|
198
|
-
|
199
|
-
1.upto(num_lists){
|
200
|
-
root_start += 1
|
201
|
-
write([root_start].pack("V"))
|
202
|
-
}
|
203
|
-
|
204
|
-
num_lists.upto(108){
|
205
|
-
write(unused)
|
206
|
-
}
|
207
|
-
end
|
208
|
-
|
209
|
-
###############################################################################
|
210
|
-
#
|
211
|
-
# _write_big_block_depot()
|
212
|
-
#
|
213
|
-
# Write big block depot.
|
214
|
-
#
|
215
|
-
def write_big_block_depot
|
216
|
-
num_blocks = @big_blocks
|
217
|
-
num_lists = @list_blocks
|
218
|
-
total_blocks = num_lists * 128
|
219
|
-
used_blocks = num_blocks + num_lists + 2
|
220
|
-
|
221
|
-
marker = [-3].pack("V")
|
222
|
-
end_of_chain = [-2].pack("V")
|
223
|
-
unused = [-1].pack("V")
|
224
|
-
|
225
|
-
1.upto(num_blocks-1){|n|
|
226
|
-
write([n].pack("V"))
|
227
|
-
}
|
228
|
-
|
229
|
-
write end_of_chain
|
230
|
-
write end_of_chain
|
231
|
-
|
232
|
-
1.upto(num_lists){ write(marker) }
|
233
|
-
|
234
|
-
used_blocks.upto(total_blocks){ write(unused) }
|
235
|
-
|
236
|
-
end
|
237
|
-
|
238
|
-
###############################################################################
|
239
|
-
#
|
240
|
-
# _write_property_storage()
|
241
|
-
#
|
242
|
-
# Write property storage. TODO: add summary sheets
|
243
|
-
#
|
244
|
-
def write_property_storage
|
245
|
-
|
246
|
-
######### name type dir start size
|
247
|
-
write_pps('Root Entry', 0x05, 1, -2, 0x00)
|
248
|
-
write_pps('Workbook', 0x02, -1, 0x00, @book_size)
|
249
|
-
write_pps("", 0x00, -1, 0x00, 0x0000)
|
250
|
-
write_pps("", 0x00, -1, 0x00, 0x0000)
|
251
|
-
end
|
252
|
-
|
253
|
-
###############################################################################
|
254
|
-
#
|
255
|
-
# _write_pps()
|
256
|
-
#
|
257
|
-
# Write property sheet in property storage
|
258
|
-
#
|
259
|
-
def write_pps(name, type, dir, start, size)
|
260
|
-
length = 0
|
261
|
-
ord_name = []
|
262
|
-
unless name.empty?
|
263
|
-
name = name + "\0"
|
264
|
-
ord_name = name.unpack("c*")
|
265
|
-
length = name.length * 2
|
266
|
-
end
|
267
|
-
|
268
|
-
rawname = ord_name.pack("v*")
|
269
|
-
zero = [0].pack("C")
|
270
|
-
|
271
|
-
pps_sizeofname = [length].pack("v") #0x40
|
272
|
-
pps_type = [type].pack("v") #0x42
|
273
|
-
pps_prev = [-1].pack("V") #0x44
|
274
|
-
pps_next = [-1].pack("V") #0x48
|
275
|
-
pps_dir = [dir].pack("V") #0x4c
|
276
|
-
|
277
|
-
unknown = [0].pack("V")
|
278
|
-
|
279
|
-
pps_ts1s = [0].pack("V") #0x64
|
280
|
-
pps_ts1d = [0].pack("V") #0x68
|
281
|
-
pps_ts2s = [0].pack("V") #0x6c
|
282
|
-
pps_ts2d = [0].pack("V") #0x70
|
283
|
-
pps_sb = [start].pack("V") #0x74
|
284
|
-
pps_size = [size].pack("V") #0x78
|
285
|
-
|
286
|
-
write(rawname)
|
287
|
-
for n in 1..64-length
|
288
|
-
write(zero)
|
289
|
-
end
|
290
|
-
write(pps_sizeofname)
|
291
|
-
write(pps_type)
|
292
|
-
write(pps_prev)
|
293
|
-
write(pps_next)
|
294
|
-
write(pps_dir)
|
295
|
-
for n in 1..5
|
296
|
-
write(unknown)
|
297
|
-
end
|
298
|
-
write(pps_ts1s)
|
299
|
-
write(pps_ts1d)
|
300
|
-
write(pps_ts2s)
|
301
|
-
write(pps_ts2d)
|
302
|
-
write(pps_sb)
|
303
|
-
write(pps_size)
|
304
|
-
write(unknown)
|
305
|
-
end
|
306
|
-
|
307
|
-
###############################################################################
|
308
|
-
#
|
309
|
-
# _write_padding()
|
310
|
-
#
|
311
|
-
# Pad the end of the file
|
312
|
-
#
|
313
|
-
def write_padding
|
314
|
-
min_size = 512
|
315
|
-
min_size = BlockSize if @biff_size < BlockSize
|
316
|
-
|
317
|
-
if @biff_size % min_size != 0
|
318
|
-
padding = min_size - (@biff_size % min_size)
|
319
|
-
write("\0" * padding)
|
320
|
-
end
|
321
|
-
end
|
322
|
-
end
|
1
|
+
###############################################################################
|
2
|
+
#
|
3
|
+
# BIFFwriter - An abstract base class for Excel workbooks and worksheets.
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# Used in conjunction with WriteExcel
|
7
|
+
#
|
8
|
+
# Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
|
9
|
+
#
|
10
|
+
# original written in Perl by John McNamara
|
11
|
+
# converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
|
12
|
+
#
|
13
|
+
class MaxSizeError < StandardError; end #:nodoc:
|
14
|
+
|
15
|
+
class OLEWriter #:nodoc:
|
16
|
+
|
17
|
+
# Not meant for public consumption
|
18
|
+
MaxSize = 7087104 # Use WriteExcel::Big to exceed this
|
19
|
+
BlockSize = 4096
|
20
|
+
BlockDiv = 512
|
21
|
+
ListBlocks = 127
|
22
|
+
|
23
|
+
attr_reader :biff_size, :book_size, :big_blocks, :list_blocks
|
24
|
+
attr_reader :root_start, :size_allowed
|
25
|
+
attr_accessor :biff_only, :internal_fh
|
26
|
+
|
27
|
+
# Accept an IO or IO-like object or a filename (as a String)
|
28
|
+
def initialize(arg)
|
29
|
+
if arg.kind_of?(String)
|
30
|
+
@io = File.open(arg, "w")
|
31
|
+
else
|
32
|
+
@io = arg
|
33
|
+
end
|
34
|
+
@io.binmode
|
35
|
+
|
36
|
+
@filehandle = ""
|
37
|
+
@fileclosed = false
|
38
|
+
@internal_fh = 0
|
39
|
+
@biff_only = 0
|
40
|
+
@size_allowed = true
|
41
|
+
@biff_size = 0
|
42
|
+
@book_size = 0
|
43
|
+
@big_blocks = 0
|
44
|
+
@list_blocks = 0
|
45
|
+
@root_start = 0
|
46
|
+
@block_count = 4
|
47
|
+
end
|
48
|
+
|
49
|
+
# Imitate IO.open behavior
|
50
|
+
|
51
|
+
###############################################################################
|
52
|
+
#
|
53
|
+
# _initialize()
|
54
|
+
#
|
55
|
+
# Create a new filehandle or use the provided filehandle.
|
56
|
+
#
|
57
|
+
def _initialize
|
58
|
+
olefile = @olefilename
|
59
|
+
|
60
|
+
# If the filename is a reference it is assumed that it is a valid
|
61
|
+
# filehandle, if not we create a filehandle.
|
62
|
+
#
|
63
|
+
|
64
|
+
# Create a new file, open for writing
|
65
|
+
fh = open(olefile, "wb")
|
66
|
+
|
67
|
+
# Workbook.pm also checks this but something may have happened since
|
68
|
+
# then.
|
69
|
+
raise "Can't open olefile. It may be in use or protected.\n" unless fh
|
70
|
+
|
71
|
+
@internal_fh = 1
|
72
|
+
|
73
|
+
# Store filehandle
|
74
|
+
@filehandle = fh
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.open(arg)
|
78
|
+
if block_given?
|
79
|
+
ole = self.new(arg)
|
80
|
+
result = yield(ole)
|
81
|
+
ole.close
|
82
|
+
result
|
83
|
+
else
|
84
|
+
self.new(arg)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
###############################################################################
|
89
|
+
#
|
90
|
+
# write($data)
|
91
|
+
#
|
92
|
+
# Write BIFF data to OLE file.
|
93
|
+
#
|
94
|
+
def write(data)
|
95
|
+
#print "ole write\n"
|
96
|
+
#print data.unpack('C*').map! {|c| sprintf("%02X", c) }.join(' ') + "\n\n"
|
97
|
+
@io.write(data)
|
98
|
+
end
|
99
|
+
# def print(data)
|
100
|
+
# @io.print(data)
|
101
|
+
# end
|
102
|
+
|
103
|
+
###############################################################################
|
104
|
+
#
|
105
|
+
# set_size($biffsize)
|
106
|
+
#
|
107
|
+
# Set the size of the data to be written to the OLE stream
|
108
|
+
#
|
109
|
+
# $big_blocks = (109 depot block x (128 -1 marker word)
|
110
|
+
# - (1 x end words)) = 13842
|
111
|
+
# $maxsize = $big_blocks * 512 bytes = 7087104
|
112
|
+
#
|
113
|
+
def set_size(size = BlockSize)
|
114
|
+
if size > MaxSize
|
115
|
+
return @size_allowed = false
|
116
|
+
end
|
117
|
+
|
118
|
+
@biff_size = size
|
119
|
+
|
120
|
+
if biff_size > BlockSize
|
121
|
+
@book_size = size
|
122
|
+
else
|
123
|
+
@book_size = BlockSize
|
124
|
+
end
|
125
|
+
|
126
|
+
@size_allowed = true
|
127
|
+
end
|
128
|
+
|
129
|
+
###############################################################################
|
130
|
+
#
|
131
|
+
# _calculate_sizes()
|
132
|
+
#
|
133
|
+
# Calculate various sizes needed for the OLE stream
|
134
|
+
#
|
135
|
+
def calculate_sizes
|
136
|
+
@big_blocks = (@book_size.to_f/BlockDiv.to_f).ceil
|
137
|
+
@list_blocks = (@big_blocks / ListBlocks) + 1
|
138
|
+
@root_start = @big_blocks
|
139
|
+
end
|
140
|
+
|
141
|
+
###############################################################################
|
142
|
+
#
|
143
|
+
# close()
|
144
|
+
#
|
145
|
+
# Write root entry, big block list and close the filehandle.
|
146
|
+
# This routine is used to explicitly close the open filehandle without
|
147
|
+
# having to wait for DESTROY.
|
148
|
+
#
|
149
|
+
def close
|
150
|
+
if @size_allowed == true
|
151
|
+
#print "write_padding"
|
152
|
+
write_padding if @biff_only == 0
|
153
|
+
#print "write_property_storage"
|
154
|
+
write_property_storage if @biff_only == 0
|
155
|
+
#print "write_big_block_depot"
|
156
|
+
write_big_block_depot if @biff_only == 0
|
157
|
+
end
|
158
|
+
@io.close
|
159
|
+
end
|
160
|
+
|
161
|
+
###############################################################################
|
162
|
+
#
|
163
|
+
# write_header()
|
164
|
+
#
|
165
|
+
# Write OLE header block.
|
166
|
+
#
|
167
|
+
def write_header
|
168
|
+
return if @biff_only == 1
|
169
|
+
calculate_sizes
|
170
|
+
root_start = @root_start
|
171
|
+
num_lists = @list_blocks
|
172
|
+
|
173
|
+
id = [0xD0CF11E0, 0xA1B11AE1].pack("NN")
|
174
|
+
unknown1 = [0x00, 0x00, 0x00, 0x00].pack("VVVV")
|
175
|
+
unknown2 = [0x3E, 0x03].pack("vv")
|
176
|
+
unknown3 = [-2].pack("v")
|
177
|
+
unknown4 = [0x09].pack("v")
|
178
|
+
unknown5 = [0x06, 0x00, 0x00].pack("VVV")
|
179
|
+
num_bbd_blocks = [num_lists].pack("V")
|
180
|
+
root_startblock = [root_start].pack("V")
|
181
|
+
unknown6 = [0x00, 0x1000].pack("VV")
|
182
|
+
sbd_startblock = [-2].pack("V")
|
183
|
+
unknown7 = [0x00, -2 ,0x00].pack("VVV")
|
184
|
+
|
185
|
+
write(id)
|
186
|
+
write(unknown1)
|
187
|
+
write(unknown2)
|
188
|
+
write(unknown3)
|
189
|
+
write(unknown4)
|
190
|
+
write(unknown5)
|
191
|
+
write(num_bbd_blocks)
|
192
|
+
write(root_startblock)
|
193
|
+
write(unknown6)
|
194
|
+
write(sbd_startblock)
|
195
|
+
write(unknown7)
|
196
|
+
|
197
|
+
unused = [-1].pack("V")
|
198
|
+
|
199
|
+
1.upto(num_lists){
|
200
|
+
root_start += 1
|
201
|
+
write([root_start].pack("V"))
|
202
|
+
}
|
203
|
+
|
204
|
+
num_lists.upto(108){
|
205
|
+
write(unused)
|
206
|
+
}
|
207
|
+
end
|
208
|
+
|
209
|
+
###############################################################################
|
210
|
+
#
|
211
|
+
# _write_big_block_depot()
|
212
|
+
#
|
213
|
+
# Write big block depot.
|
214
|
+
#
|
215
|
+
def write_big_block_depot
|
216
|
+
num_blocks = @big_blocks
|
217
|
+
num_lists = @list_blocks
|
218
|
+
total_blocks = num_lists * 128
|
219
|
+
used_blocks = num_blocks + num_lists + 2
|
220
|
+
|
221
|
+
marker = [-3].pack("V")
|
222
|
+
end_of_chain = [-2].pack("V")
|
223
|
+
unused = [-1].pack("V")
|
224
|
+
|
225
|
+
1.upto(num_blocks-1){|n|
|
226
|
+
write([n].pack("V"))
|
227
|
+
}
|
228
|
+
|
229
|
+
write end_of_chain
|
230
|
+
write end_of_chain
|
231
|
+
|
232
|
+
1.upto(num_lists){ write(marker) }
|
233
|
+
|
234
|
+
used_blocks.upto(total_blocks){ write(unused) }
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
###############################################################################
|
239
|
+
#
|
240
|
+
# _write_property_storage()
|
241
|
+
#
|
242
|
+
# Write property storage. TODO: add summary sheets
|
243
|
+
#
|
244
|
+
def write_property_storage
|
245
|
+
|
246
|
+
######### name type dir start size
|
247
|
+
write_pps('Root Entry', 0x05, 1, -2, 0x00)
|
248
|
+
write_pps('Workbook', 0x02, -1, 0x00, @book_size)
|
249
|
+
write_pps("", 0x00, -1, 0x00, 0x0000)
|
250
|
+
write_pps("", 0x00, -1, 0x00, 0x0000)
|
251
|
+
end
|
252
|
+
|
253
|
+
###############################################################################
|
254
|
+
#
|
255
|
+
# _write_pps()
|
256
|
+
#
|
257
|
+
# Write property sheet in property storage
|
258
|
+
#
|
259
|
+
def write_pps(name, type, dir, start, size)
|
260
|
+
length = 0
|
261
|
+
ord_name = []
|
262
|
+
unless name.empty?
|
263
|
+
name = name + "\0"
|
264
|
+
ord_name = name.unpack("c*")
|
265
|
+
length = name.length * 2
|
266
|
+
end
|
267
|
+
|
268
|
+
rawname = ord_name.pack("v*")
|
269
|
+
zero = [0].pack("C")
|
270
|
+
|
271
|
+
pps_sizeofname = [length].pack("v") #0x40
|
272
|
+
pps_type = [type].pack("v") #0x42
|
273
|
+
pps_prev = [-1].pack("V") #0x44
|
274
|
+
pps_next = [-1].pack("V") #0x48
|
275
|
+
pps_dir = [dir].pack("V") #0x4c
|
276
|
+
|
277
|
+
unknown = [0].pack("V")
|
278
|
+
|
279
|
+
pps_ts1s = [0].pack("V") #0x64
|
280
|
+
pps_ts1d = [0].pack("V") #0x68
|
281
|
+
pps_ts2s = [0].pack("V") #0x6c
|
282
|
+
pps_ts2d = [0].pack("V") #0x70
|
283
|
+
pps_sb = [start].pack("V") #0x74
|
284
|
+
pps_size = [size].pack("V") #0x78
|
285
|
+
|
286
|
+
write(rawname)
|
287
|
+
for n in 1..64-length
|
288
|
+
write(zero)
|
289
|
+
end
|
290
|
+
write(pps_sizeofname)
|
291
|
+
write(pps_type)
|
292
|
+
write(pps_prev)
|
293
|
+
write(pps_next)
|
294
|
+
write(pps_dir)
|
295
|
+
for n in 1..5
|
296
|
+
write(unknown)
|
297
|
+
end
|
298
|
+
write(pps_ts1s)
|
299
|
+
write(pps_ts1d)
|
300
|
+
write(pps_ts2s)
|
301
|
+
write(pps_ts2d)
|
302
|
+
write(pps_sb)
|
303
|
+
write(pps_size)
|
304
|
+
write(unknown)
|
305
|
+
end
|
306
|
+
|
307
|
+
###############################################################################
|
308
|
+
#
|
309
|
+
# _write_padding()
|
310
|
+
#
|
311
|
+
# Pad the end of the file
|
312
|
+
#
|
313
|
+
def write_padding
|
314
|
+
min_size = 512
|
315
|
+
min_size = BlockSize if @biff_size < BlockSize
|
316
|
+
|
317
|
+
if @biff_size % min_size != 0
|
318
|
+
padding = min_size - (@biff_size % min_size)
|
319
|
+
write("\0" * padding)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|