writeexcel 0.6.4 → 0.6.5
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/.gitignore +3 -0
- data/README.rdoc +2 -0
- data/VERSION +1 -1
- data/lib/writeexcel/chart.rb +3 -13
- data/lib/writeexcel/format.rb +4 -12
- data/lib/writeexcel/formula.rb +7 -24
- data/lib/writeexcel/helper.rb +7 -0
- data/lib/writeexcel/workbook.rb +266 -271
- data/lib/writeexcel/worksheet.rb +320 -428
- data/test/test_workbook.rb +20 -15
- data/writeexcel.gemspec +2 -2
- metadata +4 -4
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -80,6 +80,8 @@ when use urf8 string data.
|
|
80
80
|
* ruby 1.8, ruby 1.9.1, ruby 1.9.2
|
81
81
|
|
82
82
|
== Recent Changes
|
83
|
+
v0.6.5
|
84
|
+
* Bug fix. if workbook already has worksheet of utf8 name, Workbook#add_worksheet, Workbook#add_chart, Workbook#add_chart_ext raise exception when add new worksheet of utf8 name.
|
83
85
|
|
84
86
|
v0.6.4
|
85
87
|
* Bug fix. endless loop when inserted image size > 8224bytes.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.5
|
data/lib/writeexcel/chart.rb
CHANGED
@@ -54,8 +54,6 @@ module Writeexcel
|
|
54
54
|
class Chart < Worksheet
|
55
55
|
require 'writeexcel/helper'
|
56
56
|
|
57
|
-
NonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]\{\}^` ~\0\n]/
|
58
|
-
|
59
57
|
###############################################################################
|
60
58
|
#
|
61
59
|
# factory()
|
@@ -691,17 +689,9 @@ def encode_utf16(str, encoding = 0) # :nodoc:
|
|
691
689
|
ruby_19 { string = convert_to_ascii_if_ascii(string) }
|
692
690
|
|
693
691
|
# Handle utf8 strings.
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
encoding = 1
|
698
|
-
end
|
699
|
-
end
|
700
|
-
ruby_19 do
|
701
|
-
if string.encoding == Encoding::UTF_8
|
702
|
-
string = utf8_to_16be(string)
|
703
|
-
encoding = 1
|
704
|
-
end
|
692
|
+
if is_utf8?(string)
|
693
|
+
string = utf8_to_16be(string)
|
694
|
+
encoding = 1
|
705
695
|
end
|
706
696
|
|
707
697
|
# Chart strings are limited to 255 characters.
|
data/lib/writeexcel/format.rb
CHANGED
@@ -23,7 +23,7 @@
|
|
23
23
|
module Writeexcel
|
24
24
|
|
25
25
|
class Format < Colors
|
26
|
-
|
26
|
+
require 'writeexcel/helper'
|
27
27
|
|
28
28
|
###############################################################################
|
29
29
|
#
|
@@ -373,17 +373,9 @@ def get_font # :nodoc:
|
|
373
373
|
ruby_19 { rgch = convert_to_ascii_if_ascii(rgch) }
|
374
374
|
|
375
375
|
# Handle utf8 strings
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
encoding = 1
|
380
|
-
end
|
381
|
-
end
|
382
|
-
ruby_19 do
|
383
|
-
if rgch.encoding == Encoding::UTF_8
|
384
|
-
rgch = utf8_to_16be(rgch)
|
385
|
-
encoding = 1
|
386
|
-
end
|
376
|
+
if is_utf8?(rgch)
|
377
|
+
rgch = utf8_to_16be(rgch)
|
378
|
+
encoding = 1
|
387
379
|
end
|
388
380
|
|
389
381
|
cch = rgch.bytesize
|
data/lib/writeexcel/formula.rb
CHANGED
@@ -19,8 +19,6 @@ module Writeexcel
|
|
19
19
|
class Formula < ExcelFormulaParser #:nodoc:
|
20
20
|
require 'writeexcel/helper'
|
21
21
|
|
22
|
-
NonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]\{\}^` ~\0\n]/
|
23
|
-
|
24
22
|
attr_accessor :byte_order, :workbook, :ext_sheets, :ext_refs, :ext_ref_count
|
25
23
|
|
26
24
|
def initialize(byte_order)
|
@@ -313,19 +311,10 @@ def convert_string(str)
|
|
313
311
|
ruby_19 { str.length }
|
314
312
|
|
315
313
|
# Handle utf8 strings
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
encoding = 1
|
321
|
-
end
|
322
|
-
end
|
323
|
-
ruby_19 do
|
324
|
-
if str.encoding == Encoding::UTF_8
|
325
|
-
str = utf8_to_16le(str)
|
326
|
-
ruby_19 { str.force_encoding('BINARY') }
|
327
|
-
encoding = 1
|
328
|
-
end
|
314
|
+
if is_utf8?(str)
|
315
|
+
str = utf8_to_16le(str)
|
316
|
+
ruby_19 { str.force_encoding('BINARY') }
|
317
|
+
encoding = 1
|
329
318
|
end
|
330
319
|
|
331
320
|
exit "String in formula has more than 255 chars\n" if length > 255
|
@@ -513,15 +502,9 @@ def get_sheet_index(sheet_name)
|
|
513
502
|
ruby_19 { sheet_name = convert_to_ascii_if_ascii(sheet_name) }
|
514
503
|
|
515
504
|
# Handle utf8 sheetnames
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
end
|
520
|
-
end
|
521
|
-
ruby_19 do
|
522
|
-
if sheet_name.encoding == Encoding::UTF_8
|
523
|
-
sheet_name = sheet_name.encode('UTF-16BE')
|
524
|
-
end
|
505
|
+
if is_utf8?(sheet_name)
|
506
|
+
ruby_18 { sheet_name = utf8_to_16be(sheet_name) } ||
|
507
|
+
ruby_19 { sheet_name = sheet_name.encode('UTF-16BE') }
|
525
508
|
end
|
526
509
|
|
527
510
|
if @ext_sheets[sheet_name].nil?
|
data/lib/writeexcel/helper.rb
CHANGED
@@ -66,3 +66,10 @@ def chars_to_col(chars)
|
|
66
66
|
col
|
67
67
|
end
|
68
68
|
private :chars_to_col
|
69
|
+
|
70
|
+
NonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]\{\}^` ~\0\n]/
|
71
|
+
|
72
|
+
def is_utf8?(str)
|
73
|
+
ruby_18 { str =~ NonAscii } ||
|
74
|
+
ruby_19 { str.encoding == Encoding::UTF_8 }
|
75
|
+
end
|
data/lib/writeexcel/workbook.rb
CHANGED
@@ -26,18 +26,23 @@ class Workbook < BIFFWriter
|
|
26
26
|
require 'writeexcel/properties'
|
27
27
|
require 'writeexcel/helper'
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
BOF = 11 # :nodoc:
|
29
|
+
BOF = 12 # :nodoc:
|
32
30
|
EOF = 4 # :nodoc:
|
33
31
|
SheetName = "Sheet" # :nodoc:
|
34
32
|
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_accessor :add_doc_properties #:nodoc:
|
36
|
+
attr_reader :formats, :defined_names #:nodoc:
|
37
|
+
|
38
|
+
public
|
39
|
+
|
35
40
|
#
|
36
|
-
#
|
37
|
-
# you can set default format of workbook using
|
41
|
+
# _file_ is a filename (as string) or io object where to out spreadsheet data.
|
42
|
+
# you can set default format of workbook using _default_formats_.
|
38
43
|
#
|
39
44
|
# A new Excel workbook is created using the new() constructor which accepts
|
40
|
-
# either a filename or
|
45
|
+
# either a filename or an IO object as a parameter. The following example
|
41
46
|
# creates a new Excel file based on a filename:
|
42
47
|
#
|
43
48
|
# workbook = WriteExcel.new('filename.xls')
|
@@ -74,8 +79,6 @@ def initialize(file, default_formats = {})
|
|
74
79
|
@parser = Writeexcel::Formula.new(@byte_order)
|
75
80
|
@tempdir = nil
|
76
81
|
@date_1904 = false
|
77
|
-
@sheet =
|
78
|
-
|
79
82
|
@selected = 0
|
80
83
|
@xf_index = 0
|
81
84
|
@fileclosed = false
|
@@ -88,7 +91,6 @@ def initialize(file, default_formats = {})
|
|
88
91
|
@codepage = 0x04E4
|
89
92
|
@country = 1
|
90
93
|
@worksheets = []
|
91
|
-
@sheetnames = []
|
92
94
|
@formats = []
|
93
95
|
@palette = []
|
94
96
|
@biff_only = 0
|
@@ -117,7 +119,6 @@ def initialize(file, default_formats = {})
|
|
117
119
|
@hideobj = 0
|
118
120
|
@compatibility = 0
|
119
121
|
|
120
|
-
@add_doc_properties = 0
|
121
122
|
@summary = ''
|
122
123
|
@doc_summary = ''
|
123
124
|
@localtime = Time.now
|
@@ -165,7 +166,7 @@ def initialize(file, default_formats = {})
|
|
165
166
|
|
166
167
|
###############################################################################
|
167
168
|
#
|
168
|
-
#
|
169
|
+
# get_checksum_method.
|
169
170
|
#
|
170
171
|
# Check for modules available to calculate image checksum. Excel uses MD4 but
|
171
172
|
# MD5 will also work.
|
@@ -182,12 +183,6 @@ def get_checksum_method #:nodoc:
|
|
182
183
|
# Calls finalization methods and explicitly close the OLEwriter files
|
183
184
|
# handle.
|
184
185
|
#
|
185
|
-
# In general your Excel file will be closed automatically when your program
|
186
|
-
# ends or when the Workbook object goes out of scope, however the close method
|
187
|
-
# can be used to explicitly close an Excel file.
|
188
|
-
#
|
189
|
-
# workbook.close
|
190
|
-
#
|
191
186
|
# An explicit close() is required if the file must be closed prior to performing
|
192
187
|
# some external action on it such as copying it, reading its size or attaching
|
193
188
|
# it to an email.
|
@@ -195,12 +190,6 @@ def get_checksum_method #:nodoc:
|
|
195
190
|
# In general, if you create a file with a size of 0 bytes or you fail to create
|
196
191
|
# a file you need to call close().
|
197
192
|
#
|
198
|
-
# The return value of close() is the same as that returned by perl when it
|
199
|
-
# closes the file created by new(). This allows you to handle error conditions
|
200
|
-
# in the usual way:
|
201
|
-
#
|
202
|
-
# $workbook.close() or die "Error closing file: $!";
|
203
|
-
#
|
204
193
|
def close
|
205
194
|
return if @fileclosed # Prevent close() from being called twice.
|
206
195
|
|
@@ -245,11 +234,7 @@ def sheets(*args)
|
|
245
234
|
if args.empty?
|
246
235
|
@worksheets
|
247
236
|
else
|
248
|
-
|
249
|
-
args.each do |i|
|
250
|
-
ary << @worksheets[i]
|
251
|
-
end
|
252
|
-
ary
|
237
|
+
args.collect{|i| @worksheets[i] }
|
253
238
|
end
|
254
239
|
end
|
255
240
|
|
@@ -266,7 +251,7 @@ def sheets(*args)
|
|
266
251
|
# worksheet3 = workbook.add_worksheet('Data') # Data
|
267
252
|
# worksheet4 = workbook.add_worksheet # Sheet4
|
268
253
|
#
|
269
|
-
# If
|
254
|
+
# If _sheetname_ is not specified the default Excel convention will be followed,
|
270
255
|
# i.e. Sheet1, Sheet2, etc. The utf_16_be parameter is optional, see below.
|
271
256
|
#
|
272
257
|
# The worksheet name must be a valid Excel worksheet name, i.e. it cannot
|
@@ -308,14 +293,10 @@ def add_worksheet(sheetname = '', encoding = 0)
|
|
308
293
|
]
|
309
294
|
worksheet = Writeexcel::Worksheet.new(*init_data)
|
310
295
|
@worksheets[index] = worksheet # Store ref for iterator
|
311
|
-
@sheetnames[index] = name # Store EXTERNSHEET names
|
312
296
|
@parser.set_ext_sheets(name, index) # Store names in Formula.rb
|
313
297
|
worksheet
|
314
298
|
end
|
315
299
|
|
316
|
-
###############################################################################
|
317
|
-
#
|
318
|
-
# add_chart(params)
|
319
300
|
#
|
320
301
|
# Create a chart for embedding or as as new sheet.
|
321
302
|
#
|
@@ -327,72 +308,78 @@ def add_worksheet(sheetname = '', encoding = 0)
|
|
327
308
|
#
|
328
309
|
# The properties that can be set are:
|
329
310
|
#
|
330
|
-
#
|
331
|
-
#
|
332
|
-
#
|
311
|
+
# :type (required)
|
312
|
+
# :name (optional)
|
313
|
+
# :encoding (optional)
|
314
|
+
# :embedded (optional)
|
315
|
+
#
|
316
|
+
# * type
|
333
317
|
#
|
334
|
-
#
|
318
|
+
# This is a required parameter. It defines the type of chart that will be created.
|
335
319
|
#
|
336
|
-
#
|
320
|
+
# chart = workbook.add_chart(:type => 'Chart::Line')
|
337
321
|
#
|
338
|
-
#
|
322
|
+
# The available types are:
|
339
323
|
#
|
340
|
-
#
|
324
|
+
# 'Chart::Column'
|
325
|
+
# 'Chart::Bar'
|
326
|
+
# 'Chart::Line'
|
327
|
+
# 'Chart::Area'
|
328
|
+
# 'Chart::Pie'
|
329
|
+
# 'Chart::Scatter'
|
330
|
+
# 'Chart::Stock'
|
341
331
|
#
|
342
|
-
#
|
343
|
-
# 'Chart::Bar'
|
344
|
-
# 'Chart::Line'
|
345
|
-
# 'Chart::Area'
|
346
|
-
# 'Chart::Pie'
|
347
|
-
# 'Chart::Scatter'
|
348
|
-
# 'Chart::Stock'
|
332
|
+
# * :name
|
349
333
|
#
|
350
|
-
#
|
334
|
+
# Set the name for the chart sheet. The name property is optional and
|
335
|
+
# if it isn't supplied will default to Chart1 .. n. The name must be
|
336
|
+
# a valid Excel worksheet name. See add_worksheet() for more details
|
337
|
+
# on valid sheet names. The name property can be omitted for embedded
|
338
|
+
# charts.
|
351
339
|
#
|
352
|
-
#
|
353
|
-
#
|
354
|
-
#
|
355
|
-
#
|
356
|
-
# charts.
|
340
|
+
# chart = workbook.add_chart(
|
341
|
+
# :type => 'Chart::Line',
|
342
|
+
# :name => 'Results Chart'
|
343
|
+
# )
|
357
344
|
#
|
358
|
-
#
|
359
|
-
# :type => 'Chart::Line',
|
360
|
-
# :name => 'Results Chart'
|
361
|
-
# )
|
345
|
+
# * :encoding
|
362
346
|
#
|
363
|
-
#
|
347
|
+
# if :name is UTF-16BE format, pass 1 as :encoding.
|
364
348
|
#
|
365
|
-
#
|
366
|
-
# the insert_chart() Worksheet method. It is an error to try insert a
|
367
|
-
# Chart that doesn't have this flag set.
|
349
|
+
# * :embedded
|
368
350
|
#
|
369
|
-
#
|
351
|
+
# Specifies that the Chart object will be inserted in a worksheet via
|
352
|
+
# the insert_chart() Worksheet method. It is an error to try insert a
|
353
|
+
# Chart that doesn't have this flag set.
|
370
354
|
#
|
371
|
-
#
|
372
|
-
# ...
|
355
|
+
# chart = workbook.add_chart(:type => 'Chart::Line', :embedded => 1)
|
373
356
|
#
|
374
|
-
#
|
375
|
-
#
|
357
|
+
# # Configure the chart.
|
358
|
+
# ...
|
359
|
+
#
|
360
|
+
# # Insert the chart into the a worksheet.
|
361
|
+
# worksheet.insert_chart('E2', chart)
|
376
362
|
#
|
377
363
|
# See WriteExcel::Chart for details on how to configure the
|
378
|
-
# chart object once it is created. See also the chart_*.
|
364
|
+
# chart object once it is created. See also the chart_*.rb programs in the
|
379
365
|
# examples directory of the distro.
|
380
366
|
#
|
381
|
-
def add_chart(
|
367
|
+
def add_chart(properties)
|
382
368
|
name = ''
|
383
369
|
encoding = 0
|
384
370
|
index = @worksheets.size
|
385
371
|
|
386
372
|
# Type must be specified so we can create the required chart instance.
|
387
|
-
type =
|
388
|
-
|
373
|
+
type = properties[:type]
|
374
|
+
raise "Must define chart type in add_chart()" if type.nil?
|
389
375
|
|
390
376
|
# Ensure that the chart defaults to non embedded.
|
391
|
-
embedded =
|
377
|
+
embedded = properties[:embedded]
|
392
378
|
|
393
379
|
# Check the worksheet name for non-embedded charts.
|
394
380
|
unless embedded
|
395
|
-
name, encoding =
|
381
|
+
name, encoding =
|
382
|
+
check_sheetname(properties[:name], properties[:encoding], true)
|
396
383
|
end
|
397
384
|
|
398
385
|
init_data = [
|
@@ -412,7 +399,6 @@ def add_chart(params)
|
|
412
399
|
# If the chart isn't embedded let the workbook control it.
|
413
400
|
if !embedded
|
414
401
|
@worksheets[index] = chart # Store ref for iterator
|
415
|
-
@sheetnames[index] = name # Store EXTERNSHEET names
|
416
402
|
else
|
417
403
|
# Set index to 0 so that the activate() and set_first_sheet() methods
|
418
404
|
# point back to the first worksheet if used for embedded charts.
|
@@ -423,9 +409,6 @@ def add_chart(params)
|
|
423
409
|
chart
|
424
410
|
end
|
425
411
|
|
426
|
-
###############################################################################
|
427
|
-
#
|
428
|
-
# add_chart_ext($filename, $name)
|
429
412
|
#
|
430
413
|
# Add an externally created chart.
|
431
414
|
#
|
@@ -454,24 +437,21 @@ def add_chart_ext(filename, name, encoding = 0)
|
|
454
437
|
|
455
438
|
chart = Writeexcel::Chart.factory(self, type, init_data)
|
456
439
|
@worksheets[index] = chart # Store ref for iterator
|
457
|
-
@sheetnames[index] = name # Store EXTERNSHEET names
|
458
440
|
chart
|
459
441
|
end
|
460
442
|
|
461
443
|
###############################################################################
|
462
444
|
#
|
463
|
-
#
|
445
|
+
# check_sheetname(name, encoding)
|
464
446
|
#
|
465
447
|
# Check for valid worksheet names. We check the length, if it contains any
|
466
448
|
# invalid characters and if the name is unique in the workbook.
|
467
449
|
#
|
468
|
-
def check_sheetname(name, encoding = 0, chart =
|
450
|
+
def check_sheetname(name, encoding = 0, chart = nil) #:nodoc:
|
469
451
|
encoding ||= 0
|
470
|
-
limit = encoding != 0 ? 62 : 31
|
471
|
-
invalid_char = %r![\[\]:*?/\\]!
|
472
452
|
|
473
453
|
# Increment the Sheet/Chart number used for default sheet names below.
|
474
|
-
if chart
|
454
|
+
if chart
|
475
455
|
@chart_count += 1
|
476
456
|
else
|
477
457
|
@sheet_count += 1
|
@@ -480,7 +460,7 @@ def check_sheetname(name, encoding = 0, chart = 0) #:nodoc:
|
|
480
460
|
# Supply default Sheet/Chart name if none has been defined.
|
481
461
|
if name.nil? || name == ""
|
482
462
|
encoding = 0
|
483
|
-
if chart
|
463
|
+
if chart
|
484
464
|
name = @chart_name + @chart_count.to_s
|
485
465
|
else
|
486
466
|
name = @sheet_name + @sheet_count.to_s
|
@@ -488,16 +468,39 @@ def check_sheetname(name, encoding = 0, chart = 0) #:nodoc:
|
|
488
468
|
end
|
489
469
|
|
490
470
|
ruby_19 { name = convert_to_ascii_if_ascii(name) }
|
471
|
+
check_sheetname_length(name, encoding)
|
472
|
+
check_sheetname_even(name) if encoding == 1
|
473
|
+
check_sheetname_valid_chars(name, encoding)
|
474
|
+
|
475
|
+
# Handle utf8 strings
|
476
|
+
if is_utf8?(name)
|
477
|
+
name = utf8_to_16be(name)
|
478
|
+
encoding = 1
|
479
|
+
end
|
491
480
|
|
481
|
+
check_sheetname_uniq(name, encoding)
|
482
|
+
[name, encoding]
|
483
|
+
end
|
484
|
+
private :check_sheetname
|
485
|
+
|
486
|
+
def check_sheetname_length(name, encoding) #:nodoc:
|
492
487
|
# Check that sheetname is <= 31 (1 or 2 byte chars). Excel limit.
|
488
|
+
limit = encoding != 0 ? 62 : 31
|
493
489
|
raise "Sheetname $name must be <= 31 chars" if name.bytesize > limit
|
490
|
+
end
|
491
|
+
private :check_sheetname_length
|
494
492
|
|
493
|
+
def check_sheetname_even(name) #:nodoc:
|
495
494
|
# Check that Unicode sheetname has an even number of bytes
|
496
|
-
if
|
495
|
+
if (name.bytesize % 2 != 0)
|
497
496
|
raise "Odd number of bytes in Unicode worksheet name: #{name}"
|
498
497
|
end
|
498
|
+
end
|
499
|
+
private :check_sheetname_even
|
499
500
|
|
501
|
+
def check_sheetname_valid_chars(name, encoding) #:nodoc:
|
500
502
|
# Check that sheetname doesn't contain any invalid characters
|
503
|
+
invalid_char = %r![\[\]:*?/\\]!
|
501
504
|
if encoding != 1 && name =~ invalid_char
|
502
505
|
# Check ASCII names
|
503
506
|
raise "Invalid character []:*?/\\ in worksheet name: #{name}"
|
@@ -512,32 +515,21 @@ def check_sheetname(name, encoding = 0, chart = 0) #:nodoc:
|
|
512
515
|
str = $~.post_match
|
513
516
|
end
|
514
517
|
end
|
518
|
+
end
|
519
|
+
private :check_sheetname_valid_chars
|
515
520
|
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
end
|
523
|
-
ruby_19 do
|
524
|
-
if name.encoding == Encoding::UTF_8
|
525
|
-
name = utf8_to_16be(name)
|
526
|
-
encoding = 1
|
527
|
-
end
|
528
|
-
end
|
529
|
-
|
530
|
-
# Check that the worksheet name doesn't already exist since this is a fatal
|
531
|
-
# error in Excel 97. The check must also exclude case insensitive matches
|
532
|
-
# since the names 'Sheet1' and 'sheet1' are equivalent. The tests also have
|
533
|
-
# to take the encoding into account.
|
534
|
-
#
|
521
|
+
# Check that the worksheet name doesn't already exist since this is a fatal
|
522
|
+
# error in Excel 97. The check must also exclude case insensitive matches
|
523
|
+
# since the names 'Sheet1' and 'sheet1' are equivalent. The tests also have
|
524
|
+
# to take the encoding into account.
|
525
|
+
#
|
526
|
+
def check_sheetname_uniq(name, encoding) #:nodoc:
|
535
527
|
@worksheets.each do |worksheet|
|
536
528
|
name_a = name
|
537
529
|
encd_a = encoding
|
538
530
|
name_b = worksheet.name
|
539
531
|
encd_b = worksheet.encoding
|
540
|
-
error =
|
532
|
+
error = false
|
541
533
|
|
542
534
|
if encd_a == 0 and encd_b == 0
|
543
535
|
error = (name_a.downcase == name_b.downcase)
|
@@ -569,9 +561,8 @@ def check_sheetname(name, encoding = 0, chart = 0) #:nodoc:
|
|
569
561
|
raise "Worksheet name '#{name}', with case ignored, is already in use"
|
570
562
|
end
|
571
563
|
end
|
572
|
-
[name, encoding]
|
573
564
|
end
|
574
|
-
private :
|
565
|
+
private :check_sheetname_uniq
|
575
566
|
|
576
567
|
#
|
577
568
|
# The add_format method can be used to create new Format objects which are
|
@@ -584,11 +575,11 @@ def check_sheetname(name, encoding = 0, chart = 0) #:nodoc:
|
|
584
575
|
# See the "CELL FORMATTING" section for more details about Format properties and how to set them.
|
585
576
|
#
|
586
577
|
def add_format(*args)
|
587
|
-
|
588
|
-
args.each { |arg|
|
589
|
-
format = Writeexcel::Format.new(@xf_index, @default_formats.merge(
|
578
|
+
fmts = {}
|
579
|
+
args.each { |arg| fmts = fmts.merge(arg) }
|
580
|
+
format = Writeexcel::Format.new(@xf_index, @default_formats.merge(fmts))
|
590
581
|
@xf_index += 1
|
591
|
-
|
582
|
+
formats.push format # Store format reference
|
592
583
|
format
|
593
584
|
end
|
594
585
|
|
@@ -819,7 +810,6 @@ def set_palette_xl97 #:nodoc:
|
|
819
810
|
[0x33, 0x33, 0x99, 0x00], # 62
|
820
811
|
[0x33, 0x33, 0x33, 0x00] # 63
|
821
812
|
]
|
822
|
-
0
|
823
813
|
end
|
824
814
|
private :set_palette_xl97
|
825
815
|
|
@@ -948,7 +938,7 @@ def define_name(name, formula, encoding = 0)
|
|
948
938
|
# Parse the tokens into a formula string.
|
949
939
|
formula = parser.parse_tokens(tokens)
|
950
940
|
|
951
|
-
|
941
|
+
defined_names.push(
|
952
942
|
{
|
953
943
|
:name => name,
|
954
944
|
:encoding => encoding,
|
@@ -957,7 +947,7 @@ def define_name(name, formula, encoding = 0)
|
|
957
947
|
}
|
958
948
|
)
|
959
949
|
|
960
|
-
index =
|
950
|
+
index = defined_names.size
|
961
951
|
|
962
952
|
parser.set_ext_name(name, index)
|
963
953
|
end
|
@@ -1020,107 +1010,111 @@ def set_properties(params)
|
|
1020
1010
|
params.each do |k, v|
|
1021
1011
|
params[k] = convert_to_ascii_if_ascii(v) if v.respond_to?(:to_str)
|
1022
1012
|
end
|
1023
|
-
# List of valid input parameters.
|
1024
|
-
properties = {
|
1025
|
-
:codepage => [0x0001, 'VT_I2' ],
|
1026
|
-
:title => [0x0002, 'VT_LPSTR' ],
|
1027
|
-
:subject => [0x0003, 'VT_LPSTR' ],
|
1028
|
-
:author => [0x0004, 'VT_LPSTR' ],
|
1029
|
-
:keywords => [0x0005, 'VT_LPSTR' ],
|
1030
|
-
:comments => [0x0006, 'VT_LPSTR' ],
|
1031
|
-
:last_author => [0x0008, 'VT_LPSTR' ],
|
1032
|
-
:created => [0x000C, 'VT_FILETIME'],
|
1033
|
-
:category => [0x0002, 'VT_LPSTR' ],
|
1034
|
-
:manager => [0x000E, 'VT_LPSTR' ],
|
1035
|
-
:company => [0x000F, 'VT_LPSTR' ],
|
1036
|
-
:utf8 => 1
|
1037
|
-
}
|
1038
1013
|
|
1039
1014
|
# Check for valid input parameters.
|
1040
|
-
params
|
1041
|
-
unless properties.has_key?(k)
|
1042
|
-
raise "Unknown parameter '#{k}' in set_properties()";
|
1043
|
-
end
|
1044
|
-
end
|
1015
|
+
check_valid_params_for_properties(params)
|
1045
1016
|
|
1046
1017
|
# Set the creation time unless specified by the user.
|
1047
|
-
unless params.has_key?(:created)
|
1048
|
-
params[:created] = @localtime
|
1049
|
-
end
|
1018
|
+
params[:created] = @localtime unless params.has_key?(:created)
|
1050
1019
|
|
1051
1020
|
#
|
1052
1021
|
# Create the SummaryInformation property set.
|
1053
1022
|
#
|
1054
1023
|
|
1055
1024
|
# Get the codepage of the strings in the property set.
|
1056
|
-
|
1057
|
-
params[:codepage] = get_property_set_codepage(params,
|
1025
|
+
properties = [:title, :subject, :author, :keywords, :comments, :last_author]
|
1026
|
+
params[:codepage] = get_property_set_codepage(params, properties)
|
1058
1027
|
|
1059
1028
|
# Create an array of property set values.
|
1060
|
-
|
1061
|
-
|
1062
|
-
strings.push("created")
|
1063
|
-
strings.each do |string|
|
1064
|
-
property = string.to_sym
|
1065
|
-
property_sets.push(property_set(properties, property, params)) if params[property]
|
1066
|
-
end
|
1029
|
+
properties.unshift(:codepage)
|
1030
|
+
properties.push(:created)
|
1067
1031
|
|
1068
1032
|
# Pack the property sets.
|
1069
|
-
@summary =
|
1033
|
+
@summary =
|
1034
|
+
create_summary_property_set(property_sets(properties, params))
|
1070
1035
|
|
1071
1036
|
#
|
1072
1037
|
# Create the DocSummaryInformation property set.
|
1073
1038
|
#
|
1074
1039
|
|
1075
1040
|
# Get the codepage of the strings in the property set.
|
1076
|
-
|
1077
|
-
params[:codepage] = get_property_set_codepage(params,
|
1041
|
+
properties = [:category, :manager, :company]
|
1042
|
+
params[:codepage] = get_property_set_codepage(params, properties)
|
1078
1043
|
|
1079
1044
|
# Create an array of property set values.
|
1080
|
-
|
1081
|
-
|
1082
|
-
[:codepage, :category, :manager, :company].each do |property|
|
1083
|
-
property_sets.push(property_set(properties, property, params)) if params[property]
|
1084
|
-
end
|
1045
|
+
properties.unshift(:codepage)
|
1085
1046
|
|
1086
1047
|
# Pack the property sets.
|
1087
|
-
@doc_summary =
|
1048
|
+
@doc_summary =
|
1049
|
+
create_doc_summary_property_set(property_sets(properties, params))
|
1088
1050
|
|
1089
1051
|
# Set a flag for when the files is written.
|
1090
|
-
|
1052
|
+
add_doc_properties = true
|
1091
1053
|
end
|
1092
1054
|
|
1093
|
-
def property_set(
|
1094
|
-
[
|
1055
|
+
def property_set(property, params) #:nodoc:
|
1056
|
+
valid_properties[property][0..1] + [params[property]]
|
1095
1057
|
end
|
1096
1058
|
private :property_set
|
1097
1059
|
|
1060
|
+
def property_sets(properties, params) #:nodoc:
|
1061
|
+
properties.select { |property| params[property.to_sym] }.
|
1062
|
+
collect do |property|
|
1063
|
+
property_set(property.to_sym, params)
|
1064
|
+
end
|
1065
|
+
end
|
1066
|
+
private :property_sets
|
1067
|
+
|
1068
|
+
# List of valid input parameters.
|
1069
|
+
def valid_properties #:nodoc:
|
1070
|
+
{
|
1071
|
+
:codepage => [0x0001, 'VT_I2' ],
|
1072
|
+
:title => [0x0002, 'VT_LPSTR' ],
|
1073
|
+
:subject => [0x0003, 'VT_LPSTR' ],
|
1074
|
+
:author => [0x0004, 'VT_LPSTR' ],
|
1075
|
+
:keywords => [0x0005, 'VT_LPSTR' ],
|
1076
|
+
:comments => [0x0006, 'VT_LPSTR' ],
|
1077
|
+
:last_author => [0x0008, 'VT_LPSTR' ],
|
1078
|
+
:created => [0x000C, 'VT_FILETIME'],
|
1079
|
+
:category => [0x0002, 'VT_LPSTR' ],
|
1080
|
+
:manager => [0x000E, 'VT_LPSTR' ],
|
1081
|
+
:company => [0x000F, 'VT_LPSTR' ],
|
1082
|
+
:utf8 => 1
|
1083
|
+
}
|
1084
|
+
end
|
1085
|
+
private :valid_properties
|
1086
|
+
|
1087
|
+
def check_valid_params_for_properties(params) #:nodoc:
|
1088
|
+
params.each_key do |k|
|
1089
|
+
unless valid_properties.has_key?(k)
|
1090
|
+
raise "Unknown parameter '#{k}' in set_properties()";
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
private :check_valid_params_for_properties
|
1095
|
+
|
1098
1096
|
###############################################################################
|
1099
1097
|
#
|
1100
|
-
#
|
1098
|
+
# get_property_set_codepage()
|
1101
1099
|
#
|
1102
1100
|
# Get the character codepage used by the strings in a property set. If one of
|
1103
1101
|
# the strings used is utf8 then the codepage is marked as utf8. Otherwise
|
1104
1102
|
# Latin 1 is used (although in our case this is limited to 7bit ASCII).
|
1105
1103
|
#
|
1106
|
-
def get_property_set_codepage(params,
|
1104
|
+
def get_property_set_codepage(params, properties) #:nodoc:
|
1107
1105
|
# Allow for manually marked utf8 strings.
|
1108
|
-
unless params[:utf8].nil?
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
next unless params.has_key?(string.to_sym)
|
1113
|
-
ruby_18 { return 0xFDE9 if params[string.to_sym] =~ NonAscii }
|
1114
|
-
ruby_19 { return 0xFDE9 if params[string.to_sym].encoding == Encoding::UTF_8 }
|
1115
|
-
end
|
1116
|
-
return 0x04E4; # Default codepage, Latin 1.
|
1106
|
+
return 0xFDE9 unless params[:utf8].nil?
|
1107
|
+
properties.each do |property|
|
1108
|
+
next unless params.has_key?(property.to_sym)
|
1109
|
+
return 0xFDE9 if is_utf8?(params[property.to_sym])
|
1117
1110
|
end
|
1111
|
+
return 0x04E4; # Default codepage, Latin 1.
|
1118
1112
|
end
|
1119
1113
|
private :get_property_set_codepage
|
1120
1114
|
|
1121
1115
|
###############################################################################
|
1122
1116
|
#
|
1123
|
-
#
|
1117
|
+
# store_workbook()
|
1124
1118
|
#
|
1125
1119
|
# Assemble worksheets into a workbook and send the BIFF data to an OLE
|
1126
1120
|
# storage.
|
@@ -1168,7 +1162,7 @@ def store_workbook #:nodoc:
|
|
1168
1162
|
end
|
1169
1163
|
|
1170
1164
|
# NOTE: If any records are added between here and EOF the
|
1171
|
-
#
|
1165
|
+
# calc_sheet_offsets() should be updated to include the new length.
|
1172
1166
|
store_country
|
1173
1167
|
if @ext_refs.keys.size != 0
|
1174
1168
|
store_supbook
|
@@ -1213,7 +1207,7 @@ def localtime=(val) # :nodoc:
|
|
1213
1207
|
|
1214
1208
|
###############################################################################
|
1215
1209
|
#
|
1216
|
-
#
|
1210
|
+
# store_ole_filie()
|
1217
1211
|
#
|
1218
1212
|
# Store the workbook in an OLE container using the default handler or using
|
1219
1213
|
# OLE::Storage_Lite if the workbook data is > ~ 7MB.
|
@@ -1222,7 +1216,7 @@ def store_ole_filie #:nodoc:
|
|
1222
1216
|
maxsize = 7_087_104
|
1223
1217
|
# maxsize = 1
|
1224
1218
|
|
1225
|
-
if
|
1219
|
+
if !add_doc_properties && @biffsize <= maxsize
|
1226
1220
|
# Write the OLE file using OLEwriter if data <= 7MB
|
1227
1221
|
ole = OLEWriter.new(@fh_out)
|
1228
1222
|
|
@@ -1266,7 +1260,7 @@ def store_ole_filie #:nodoc:
|
|
1266
1260
|
streams << workbook
|
1267
1261
|
|
1268
1262
|
# Create the properties streams, if any.
|
1269
|
-
if
|
1263
|
+
if add_doc_properties
|
1270
1264
|
stream = "\5SummaryInformation".unpack('C*').pack('v*')
|
1271
1265
|
summary = OLEStorageLitePPSFile.new(stream, @summary)
|
1272
1266
|
streams << summary
|
@@ -1293,14 +1287,11 @@ def store_ole_filie #:nodoc:
|
|
1293
1287
|
|
1294
1288
|
###############################################################################
|
1295
1289
|
#
|
1296
|
-
#
|
1290
|
+
# calc_sheet_offsets()
|
1297
1291
|
#
|
1298
1292
|
# Calculate Worksheet BOF offsets records for use in the BOUNDSHEET records.
|
1299
1293
|
#
|
1300
1294
|
def calc_sheet_offsets #:nodoc:
|
1301
|
-
_bof = 12
|
1302
|
-
_eof = 4
|
1303
|
-
|
1304
1295
|
offset = @datasize
|
1305
1296
|
|
1306
1297
|
# Add the length of the COUNTRY record
|
@@ -1316,16 +1307,16 @@ def calc_sheet_offsets #:nodoc:
|
|
1316
1307
|
offset += calculate_extern_sizes
|
1317
1308
|
|
1318
1309
|
# Add the length of the MSODRAWINGGROUP records including an extra 4 bytes
|
1319
|
-
# for any CONTINUE headers. See
|
1310
|
+
# for any CONTINUE headers. See add_mso_drawing_group_continue().
|
1320
1311
|
mso_size = @mso_size
|
1321
1312
|
mso_size += 4 * Integer((mso_size -1) / Float(@limit))
|
1322
1313
|
offset += mso_size
|
1323
1314
|
|
1324
1315
|
@worksheets.each do |sheet|
|
1325
|
-
offset +=
|
1316
|
+
offset += BOF + sheet.name.bytesize
|
1326
1317
|
end
|
1327
1318
|
|
1328
|
-
offset +=
|
1319
|
+
offset += EOF
|
1329
1320
|
@worksheets.each do |sheet|
|
1330
1321
|
sheet.offset = offset
|
1331
1322
|
sheet.close
|
@@ -1338,7 +1329,7 @@ def calc_sheet_offsets #:nodoc:
|
|
1338
1329
|
|
1339
1330
|
###############################################################################
|
1340
1331
|
#
|
1341
|
-
#
|
1332
|
+
# calc_mso_sizes()
|
1342
1333
|
#
|
1343
1334
|
# Calculate the MSODRAWINGGROUP sizes and the indexes of the Worksheet
|
1344
1335
|
# MSODRAWING records.
|
@@ -1419,7 +1410,7 @@ def calc_mso_sizes #:nodoc:
|
|
1419
1410
|
|
1420
1411
|
###############################################################################
|
1421
1412
|
#
|
1422
|
-
#
|
1413
|
+
# process_images()
|
1423
1414
|
#
|
1424
1415
|
# We need to process each image in each worksheet and extract information.
|
1425
1416
|
# Some of this information is stored and used in the Workbook and some is
|
@@ -1554,10 +1545,10 @@ def process_images #:nodoc:
|
|
1554
1545
|
|
1555
1546
|
###############################################################################
|
1556
1547
|
#
|
1557
|
-
#
|
1548
|
+
# image_checksum()
|
1558
1549
|
#
|
1559
1550
|
# Generate a checksum for the image using whichever module is available..The
|
1560
|
-
# available modules are checked in
|
1551
|
+
# available modules are checked in get_checksum_method(). Excel uses an MD4
|
1561
1552
|
# checksum but any other will do. In the event of no checksum module being
|
1562
1553
|
# available we simulate a checksum using the image index.
|
1563
1554
|
#
|
@@ -1580,7 +1571,7 @@ def image_checksum(data, index1, index2 = 0) #:nodoc:
|
|
1580
1571
|
|
1581
1572
|
###############################################################################
|
1582
1573
|
#
|
1583
|
-
#
|
1574
|
+
# process_png()
|
1584
1575
|
#
|
1585
1576
|
# Extract width and height information from a PNG file.
|
1586
1577
|
#
|
@@ -1595,7 +1586,7 @@ def process_png(data) #:nodoc:
|
|
1595
1586
|
|
1596
1587
|
###############################################################################
|
1597
1588
|
#
|
1598
|
-
#
|
1589
|
+
# process_bmp()
|
1599
1590
|
#
|
1600
1591
|
# Extract width and height information from a BMP file.
|
1601
1592
|
#
|
@@ -1644,7 +1635,7 @@ def process_bmp(data, filename) #:nodoc:
|
|
1644
1635
|
|
1645
1636
|
###############################################################################
|
1646
1637
|
#
|
1647
|
-
#
|
1638
|
+
# process_jpg()
|
1648
1639
|
#
|
1649
1640
|
# Extract width and height information from a JPEG file.
|
1650
1641
|
#
|
@@ -1683,12 +1674,12 @@ def process_jpg(data, filename) # :nodoc:
|
|
1683
1674
|
|
1684
1675
|
###############################################################################
|
1685
1676
|
#
|
1686
|
-
#
|
1677
|
+
# store_all_fonts()
|
1687
1678
|
#
|
1688
1679
|
# Store the Excel FONT records.
|
1689
1680
|
#
|
1690
1681
|
def store_all_fonts #:nodoc:
|
1691
|
-
format =
|
1682
|
+
format = formats[15] # The default cell format.
|
1692
1683
|
font = format.get_font
|
1693
1684
|
|
1694
1685
|
# Fonts are 0-indexed. According to the SDK there is no index 4,
|
@@ -1751,7 +1742,7 @@ def store_all_fonts #:nodoc:
|
|
1751
1742
|
# Fonts that are marked as '_font_only' are always stored. These are used
|
1752
1743
|
# mainly for charts and may not have an associated XF record.
|
1753
1744
|
|
1754
|
-
|
1745
|
+
formats.each do |fmt|
|
1755
1746
|
key = fmt.get_font_key
|
1756
1747
|
if fmt.font_only == 0 and !fonts[key].nil?
|
1757
1748
|
# FONT has already been used
|
@@ -1774,7 +1765,7 @@ def store_all_fonts #:nodoc:
|
|
1774
1765
|
|
1775
1766
|
###############################################################################
|
1776
1767
|
#
|
1777
|
-
#
|
1768
|
+
# store_all_num_formats()
|
1778
1769
|
#
|
1779
1770
|
# Store user defined numerical formats i.e. FORMAT records
|
1780
1771
|
#
|
@@ -1785,7 +1776,7 @@ def store_all_num_formats #:nodoc:
|
|
1785
1776
|
# Iterate through the XF objects and write a FORMAT record if it isn't a
|
1786
1777
|
# built-in format type and if the FORMAT string hasn't already been used.
|
1787
1778
|
#
|
1788
|
-
|
1779
|
+
formats.each do |format|
|
1789
1780
|
num_format = format.num_format
|
1790
1781
|
encoding = format.num_format_enc
|
1791
1782
|
|
@@ -1813,12 +1804,12 @@ def store_all_num_formats #:nodoc:
|
|
1813
1804
|
|
1814
1805
|
###############################################################################
|
1815
1806
|
#
|
1816
|
-
#
|
1807
|
+
# store_all_xfs()
|
1817
1808
|
#
|
1818
1809
|
# Write all XF records.
|
1819
1810
|
#
|
1820
1811
|
def store_all_xfs #:nodoc:
|
1821
|
-
|
1812
|
+
formats.each do |format|
|
1822
1813
|
xf = format.get_xf
|
1823
1814
|
append(xf)
|
1824
1815
|
end
|
@@ -1827,7 +1818,7 @@ def store_all_xfs #:nodoc:
|
|
1827
1818
|
|
1828
1819
|
###############################################################################
|
1829
1820
|
#
|
1830
|
-
#
|
1821
|
+
# store_all_styles()
|
1831
1822
|
#
|
1832
1823
|
# Write all STYLE records.
|
1833
1824
|
#
|
@@ -1858,13 +1849,13 @@ def store_all_styles #:nodoc:
|
|
1858
1849
|
|
1859
1850
|
###############################################################################
|
1860
1851
|
#
|
1861
|
-
#
|
1852
|
+
# store_names()
|
1862
1853
|
#
|
1863
1854
|
# Write the NAME record to define the print area and the repeat rows and cols.
|
1864
1855
|
#
|
1865
1856
|
def store_names # :nodoc:
|
1866
1857
|
# Create the user defined names.
|
1867
|
-
|
1858
|
+
defined_names.each do |defined_name|
|
1868
1859
|
store_name(
|
1869
1860
|
defined_name[:name],
|
1870
1861
|
defined_name[:encoding],
|
@@ -1875,20 +1866,28 @@ def store_names # :nodoc:
|
|
1875
1866
|
|
1876
1867
|
# Sort the worksheets into alphabetical order by name. This is a
|
1877
1868
|
# requirement for some non-English language Excel patch levels.
|
1878
|
-
|
1869
|
+
sorted_worksheets = @worksheets.sort_by{ |x| x.name }
|
1879
1870
|
|
1880
1871
|
# Create the autofilter NAME records
|
1881
|
-
|
1872
|
+
create_autofilter_name_records(sorted_worksheets)
|
1873
|
+
|
1874
|
+
# Create the print area NAME records
|
1875
|
+
create_print_area_name_records(sorted_worksheets)
|
1876
|
+
|
1877
|
+
# Create the print title NAME records
|
1878
|
+
create_print_title_name_records(sorted_worksheets)
|
1879
|
+
end
|
1880
|
+
|
1881
|
+
def create_autofilter_name_records(sorted_worksheets) #:nodoc:
|
1882
|
+
sorted_worksheets.each do |worksheet|
|
1882
1883
|
index = worksheet.index
|
1883
|
-
key = "#{index}:#{index}"
|
1884
|
-
ref = @ext_refs[key]
|
1885
1884
|
|
1886
1885
|
# Write a Name record if Autofilter has been defined
|
1887
1886
|
if worksheet.filter_count != 0
|
1888
1887
|
store_name_short(
|
1889
1888
|
worksheet.index,
|
1890
1889
|
0x0D, # NAME type = Filter Database
|
1891
|
-
|
1890
|
+
@ext_refs["#{index}:#{index}"],
|
1892
1891
|
worksheet.filter_area[0],
|
1893
1892
|
worksheet.filter_area[1],
|
1894
1893
|
worksheet.filter_area[2],
|
@@ -1897,19 +1896,19 @@ def store_names # :nodoc:
|
|
1897
1896
|
)
|
1898
1897
|
end
|
1899
1898
|
end
|
1899
|
+
end
|
1900
|
+
private :create_autofilter_name_records
|
1900
1901
|
|
1901
|
-
|
1902
|
-
|
1902
|
+
def create_print_area_name_records(sorted_worksheets) #:nodoc:
|
1903
|
+
sorted_worksheets.each do |worksheet|
|
1903
1904
|
index = worksheet.index
|
1904
|
-
key = "#{index}:#{index}"
|
1905
|
-
ref = @ext_refs[key]
|
1906
1905
|
|
1907
1906
|
# Write a Name record if the print area has been defined
|
1908
1907
|
if !worksheet.print_rowmin.nil?
|
1909
1908
|
store_name_short(
|
1910
1909
|
worksheet.index,
|
1911
1910
|
0x06, # NAME type = Print_Area
|
1912
|
-
|
1911
|
+
@ext_refs["#{index}:#{index}"],
|
1913
1912
|
worksheet.print_rowmin,
|
1914
1913
|
worksheet.print_rowmax,
|
1915
1914
|
worksheet.print_colmin,
|
@@ -1917,9 +1916,11 @@ def store_names # :nodoc:
|
|
1917
1916
|
)
|
1918
1917
|
end
|
1919
1918
|
end
|
1919
|
+
end
|
1920
|
+
private :create_print_area_name_records
|
1920
1921
|
|
1921
|
-
|
1922
|
-
|
1922
|
+
def create_print_title_name_records(sorted_worksheets) #:nodoc:
|
1923
|
+
sorted_worksheets.each do |worksheet|
|
1923
1924
|
index = worksheet.index
|
1924
1925
|
rowmin = worksheet.title_rowmin
|
1925
1926
|
rowmax = worksheet.title_rowmax
|
@@ -1970,6 +1971,7 @@ def store_names # :nodoc:
|
|
1970
1971
|
end
|
1971
1972
|
end
|
1972
1973
|
end
|
1974
|
+
private :create_print_title_name_records
|
1973
1975
|
|
1974
1976
|
###############################################################################
|
1975
1977
|
###############################################################################
|
@@ -1980,7 +1982,7 @@ def store_names # :nodoc:
|
|
1980
1982
|
|
1981
1983
|
###############################################################################
|
1982
1984
|
#
|
1983
|
-
#
|
1985
|
+
# store_window1()
|
1984
1986
|
#
|
1985
1987
|
# Write Excel BIFF WINDOW1 record.
|
1986
1988
|
#
|
@@ -2014,7 +2016,7 @@ def store_window1 #:nodoc:
|
|
2014
2016
|
|
2015
2017
|
###############################################################################
|
2016
2018
|
#
|
2017
|
-
#
|
2019
|
+
# store_boundsheet()
|
2018
2020
|
# my $sheetname = $_[0]; # Worksheet name
|
2019
2021
|
# my $offset = $_[1]; # Location of worksheet BOF
|
2020
2022
|
# my $type = $_[2]; # Worksheet type
|
@@ -2046,7 +2048,7 @@ def store_boundsheet(sheetname, offset, type, hidden, encoding) #:nodoc:
|
|
2046
2048
|
|
2047
2049
|
###############################################################################
|
2048
2050
|
#
|
2049
|
-
#
|
2051
|
+
# store_style()
|
2050
2052
|
# type = $_[0] # Built-in style
|
2051
2053
|
# xf_index = $_[1] # Index to style XF
|
2052
2054
|
#
|
@@ -2069,7 +2071,7 @@ def store_style(type, xf_index) #:nodoc:
|
|
2069
2071
|
|
2070
2072
|
###############################################################################
|
2071
2073
|
#
|
2072
|
-
#
|
2074
|
+
# store_num_format()
|
2073
2075
|
# my $format = $_[0]; # Custom format string
|
2074
2076
|
# my $ifmt = $_[1]; # Format index code
|
2075
2077
|
# my $encoding = $_[2]; # Char encoding for format string
|
@@ -2086,17 +2088,9 @@ def store_num_format(format, ifmt, encoding) #:nodoc:
|
|
2086
2088
|
ruby_19 { format = convert_to_ascii_if_ascii(format) }
|
2087
2089
|
|
2088
2090
|
# Handle utf8 strings
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
encoding = 1
|
2093
|
-
end
|
2094
|
-
end
|
2095
|
-
ruby_19 do
|
2096
|
-
if format.encoding == Encoding::UTF_8
|
2097
|
-
format = utf8_to_16be(format)
|
2098
|
-
encoding = 1
|
2099
|
-
end
|
2091
|
+
if is_utf8?(format)
|
2092
|
+
format = utf8_to_16be(format)
|
2093
|
+
encoding = 1
|
2100
2094
|
end
|
2101
2095
|
|
2102
2096
|
# Handle Unicode format strings.
|
@@ -2125,7 +2119,7 @@ def store_num_format(format, ifmt, encoding) #:nodoc:
|
|
2125
2119
|
|
2126
2120
|
###############################################################################
|
2127
2121
|
#
|
2128
|
-
#
|
2122
|
+
# store_1904()
|
2129
2123
|
#
|
2130
2124
|
# Write Excel 1904 record to indicate the date system in use.
|
2131
2125
|
#
|
@@ -2144,7 +2138,7 @@ def store_1904 #:nodoc:
|
|
2144
2138
|
|
2145
2139
|
###############################################################################
|
2146
2140
|
#
|
2147
|
-
#
|
2141
|
+
# store_supbook()
|
2148
2142
|
#
|
2149
2143
|
# Write BIFF record SUPBOOK to indicate that the workbook contains external
|
2150
2144
|
# references, in our case, formula, print area and print title refs.
|
@@ -2165,7 +2159,7 @@ def store_supbook #:nodoc:
|
|
2165
2159
|
|
2166
2160
|
###############################################################################
|
2167
2161
|
#
|
2168
|
-
#
|
2162
|
+
# store_externsheet()
|
2169
2163
|
#
|
2170
2164
|
# Writes the Excel BIFF EXTERNSHEET record. These references are used by
|
2171
2165
|
# formulas. TODO NAME record is required to define the print area and the
|
@@ -2198,8 +2192,8 @@ def store_externsheet # :nodoc:
|
|
2198
2192
|
# Store the NAME record used for storing the print area, repeat rows, repeat
|
2199
2193
|
# columns, autofilters and defined names.
|
2200
2194
|
#
|
2201
|
-
# TODO. This is a more generic version that will replace
|
2202
|
-
# and
|
2195
|
+
# TODO. This is a more generic version that will replace store_name_short()
|
2196
|
+
# and store_name_long().
|
2203
2197
|
#
|
2204
2198
|
def store_name(name, encoding, sheet_index, formula) # :nodoc:
|
2205
2199
|
ruby_19 { formula = convert_to_ascii_if_ascii(formula) }
|
@@ -2248,7 +2242,7 @@ def store_name(name, encoding, sheet_index, formula) # :nodoc:
|
|
2248
2242
|
|
2249
2243
|
###############################################################################
|
2250
2244
|
#
|
2251
|
-
#
|
2245
|
+
# store_name_short()
|
2252
2246
|
# index = shift # Sheet index
|
2253
2247
|
# type = shift
|
2254
2248
|
# ext_ref = shift # TODO
|
@@ -2309,7 +2303,7 @@ def store_name_short(index, type, ext_ref, rowmin, rowmax, colmin, colmax, hidde
|
|
2309
2303
|
|
2310
2304
|
###############################################################################
|
2311
2305
|
#
|
2312
|
-
#
|
2306
|
+
# store_name_long()
|
2313
2307
|
# my $index = shift; # Sheet index
|
2314
2308
|
# my $type = shift;
|
2315
2309
|
# my $ext_ref = shift; # TODO
|
@@ -2321,7 +2315,7 @@ def store_name_short(index, type, ext_ref, rowmin, rowmax, colmin, colmax, hidde
|
|
2321
2315
|
#
|
2322
2316
|
# Store the NAME record in the long format that is used for storing the repeat
|
2323
2317
|
# rows and columns when both are specified. This share a lot of code with
|
2324
|
-
#
|
2318
|
+
# store_name_short() but we use a separate method to keep the code clean.
|
2325
2319
|
# Code abstraction for reuse can be carried too far, and I should know. ;-)
|
2326
2320
|
#
|
2327
2321
|
def store_name_long(index, type, ext_ref, rowmin, rowmax, colmin, colmax) #:nodoc:
|
@@ -2385,7 +2379,7 @@ def store_name_long(index, type, ext_ref, rowmin, rowmax, colmin, colmax)
|
|
2385
2379
|
|
2386
2380
|
###############################################################################
|
2387
2381
|
#
|
2388
|
-
#
|
2382
|
+
# store_palette()
|
2389
2383
|
#
|
2390
2384
|
# Stores the PALETTE biff record.
|
2391
2385
|
#
|
@@ -2408,7 +2402,7 @@ def store_palette #:nodoc:
|
|
2408
2402
|
|
2409
2403
|
###############################################################################
|
2410
2404
|
#
|
2411
|
-
#
|
2405
|
+
# store_codepage()
|
2412
2406
|
#
|
2413
2407
|
# Stores the CODEPAGE biff record.
|
2414
2408
|
#
|
@@ -2423,7 +2417,7 @@ def store_codepage #:nodoc:
|
|
2423
2417
|
|
2424
2418
|
###############################################################################
|
2425
2419
|
#
|
2426
|
-
#
|
2420
|
+
# store_country()
|
2427
2421
|
#
|
2428
2422
|
# Stores the COUNTRY biff record.
|
2429
2423
|
#
|
@@ -2439,7 +2433,7 @@ def store_country #:nodoc:
|
|
2439
2433
|
|
2440
2434
|
###############################################################################
|
2441
2435
|
#
|
2442
|
-
#
|
2436
|
+
# store_hideobj()
|
2443
2437
|
#
|
2444
2438
|
# Stores the HIDEOBJ biff record.
|
2445
2439
|
#
|
@@ -2452,7 +2446,7 @@ def store_hideobj #:nodoc:
|
|
2452
2446
|
end
|
2453
2447
|
private :store_hideobj
|
2454
2448
|
|
2455
|
-
def store_common(record, length, *data)
|
2449
|
+
def store_common(record, length, *data) #:nodoc:
|
2456
2450
|
header = [record, length].pack("vv")
|
2457
2451
|
add_data = [*data].pack("v*")
|
2458
2452
|
|
@@ -2462,7 +2456,7 @@ def store_common(record, length, *data)
|
|
2462
2456
|
|
2463
2457
|
###############################################################################
|
2464
2458
|
#
|
2465
|
-
#
|
2459
|
+
# calculate_extern_sizes()
|
2466
2460
|
#
|
2467
2461
|
# We need to calculate the space required by the SUPBOOK, EXTERNSHEET and NAME
|
2468
2462
|
# records so that it can be added to the BOUNDSHEET offsets.
|
@@ -2472,14 +2466,14 @@ def calculate_extern_sizes # :nodoc:
|
|
2472
2466
|
length = 0
|
2473
2467
|
index = 0
|
2474
2468
|
|
2475
|
-
unless
|
2469
|
+
unless defined_names.empty?
|
2476
2470
|
index = 0
|
2477
2471
|
key = "#{index}:#{index}"
|
2478
2472
|
|
2479
2473
|
add_ext_refs(ext_refs, key) unless ext_refs.has_key?(key)
|
2480
2474
|
end
|
2481
2475
|
|
2482
|
-
|
2476
|
+
defined_names.each do |defined_name|
|
2483
2477
|
length += 19 + defined_name[:name].bytesize + defined_name[:formula].bytesize
|
2484
2478
|
end
|
2485
2479
|
|
@@ -2535,26 +2529,26 @@ def calculate_extern_sizes # :nodoc:
|
|
2535
2529
|
length
|
2536
2530
|
end
|
2537
2531
|
|
2538
|
-
def add_ext_refs(ext_refs, key)
|
2532
|
+
def add_ext_refs(ext_refs, key) #:nodoc:
|
2539
2533
|
ext_refs[key] = ext_refs.keys.size
|
2540
2534
|
end
|
2541
2535
|
private :add_ext_refs
|
2542
2536
|
|
2543
2537
|
###############################################################################
|
2544
2538
|
#
|
2545
|
-
#
|
2539
|
+
# calculate_shared_string_sizes()
|
2546
2540
|
#
|
2547
2541
|
# Handling of the SST continue blocks is complicated by the need to include an
|
2548
2542
|
# additional continuation byte depending on whether the string is split between
|
2549
2543
|
# blocks or whether it starts at the beginning of the block. (There are also
|
2550
2544
|
# additional complications that will arise later when/if Rich Strings are
|
2551
2545
|
# supported). As such we cannot use the simple CONTINUE mechanism provided by
|
2552
|
-
# the
|
2546
|
+
# the add_continue() method in BIFFwriter.pm. Thus we have to make two passes
|
2553
2547
|
# through the strings data. The first is to calculate the required block sizes
|
2554
|
-
# and the second, in
|
2548
|
+
# and the second, in store_shared_strings(), is to write the actual strings.
|
2555
2549
|
# The first pass through the data is also used to calculate the size of the SST
|
2556
2550
|
# and CONTINUE records for use in setting the BOUNDSHEET record offsets. The
|
2557
|
-
# downside of this is that the same algorithm repeated in
|
2551
|
+
# downside of this is that the same algorithm repeated in store_shared_strings.
|
2558
2552
|
#
|
2559
2553
|
def calculate_shared_string_sizes #:nodoc:
|
2560
2554
|
strings = Array.new(@sinfo[:str_unique])
|
@@ -2570,12 +2564,12 @@ def calculate_shared_string_sizes #:nodoc:
|
|
2570
2564
|
#
|
2571
2565
|
# The SST blocks requires a specialised CONTINUE block, so we have to
|
2572
2566
|
# ensure that the maximum data block size is less than the limit used by
|
2573
|
-
#
|
2567
|
+
# add_continue() in BIFFwriter.pm. For simplicity we use the same size
|
2574
2568
|
# for the SST and CONTINUE records:
|
2575
2569
|
# 8228 : Maximum Excel97 block size
|
2576
2570
|
# -4 : Length of block header
|
2577
2571
|
# -8 : Length of additional SST header information
|
2578
|
-
# -8 : Arbitrary number to keep within
|
2572
|
+
# -8 : Arbitrary number to keep within add_continue() limit
|
2579
2573
|
# = 8208
|
2580
2574
|
#
|
2581
2575
|
continue_limit = 8208
|
@@ -2605,7 +2599,7 @@ def calculate_shared_string_sizes #:nodoc:
|
|
2605
2599
|
split_string = 0
|
2606
2600
|
while block_length >= continue_limit
|
2607
2601
|
header_length, space_remaining, align, split_string =
|
2608
|
-
|
2602
|
+
split_string_setup(encoding, split_string, continue_limit, written, continue)
|
2609
2603
|
|
2610
2604
|
if space_remaining > header_length
|
2611
2605
|
# Write as much as possible of the string in the current block
|
@@ -2667,7 +2661,7 @@ def calculate_shared_string_sizes #:nodoc:
|
|
2667
2661
|
end
|
2668
2662
|
private :calculate_shared_string_sizes
|
2669
2663
|
|
2670
|
-
def
|
2664
|
+
def split_string_setup(encoding, split_string, continue_limit, written, continue) #:nodoc:
|
2671
2665
|
# We need to avoid the case where a string is continued in the first
|
2672
2666
|
# n bytes that contain the string header information.
|
2673
2667
|
header_length = 3 # Min string + header size -1
|
@@ -2697,15 +2691,15 @@ def _split_string_setup(encoding, split_string, continue_limit, written, continu
|
|
2697
2691
|
end
|
2698
2692
|
[header_length, space_remaining, align, split_string]
|
2699
2693
|
end
|
2700
|
-
private :
|
2694
|
+
private :split_string_setup
|
2701
2695
|
|
2702
2696
|
###############################################################################
|
2703
2697
|
#
|
2704
|
-
#
|
2698
|
+
# store_shared_strings()
|
2705
2699
|
#
|
2706
2700
|
# Write all of the workbooks strings into an indexed array.
|
2707
2701
|
#
|
2708
|
-
# See the comments in
|
2702
|
+
# See the comments in calculate_shared_string_sizes() for more information.
|
2709
2703
|
#
|
2710
2704
|
# We also use this routine to record the offsets required by the EXTSST table.
|
2711
2705
|
# In order to do this we first identify the first string in an EXTSST bucket
|
@@ -2726,7 +2720,7 @@ def store_shared_strings #:nodoc:
|
|
2726
2720
|
continue = 0
|
2727
2721
|
|
2728
2722
|
# The SST and CONTINUE block sizes have been pre-calculated by
|
2729
|
-
#
|
2723
|
+
# calculate_shared_string_sizes()
|
2730
2724
|
block_sizes = @str_block_sizes
|
2731
2725
|
|
2732
2726
|
# The SST record is required even if it contains no strings. Thus we will
|
@@ -2785,7 +2779,7 @@ def store_shared_strings #:nodoc:
|
|
2785
2779
|
split_string = 0
|
2786
2780
|
while block_length >= continue_limit
|
2787
2781
|
header_length, space_remaining, align, split_string =
|
2788
|
-
|
2782
|
+
split_string_setup(encoding, split_string, continue_limit, written, continue)
|
2789
2783
|
|
2790
2784
|
if space_remaining > header_length
|
2791
2785
|
# Write as much as possible of the string in the current block
|
@@ -2857,7 +2851,7 @@ def store_shared_strings #:nodoc:
|
|
2857
2851
|
|
2858
2852
|
###############################################################################
|
2859
2853
|
#
|
2860
|
-
#
|
2854
|
+
# calculate_extsst_size
|
2861
2855
|
#
|
2862
2856
|
# The number of buckets used in the EXTSST is between 0 and 128. The number of
|
2863
2857
|
# strings per bucket (bucket size) has a minimum value of 8 and a theoretical
|
@@ -2884,9 +2878,9 @@ def calculate_extsst_size #:nodoc:
|
|
2884
2878
|
|
2885
2879
|
###############################################################################
|
2886
2880
|
#
|
2887
|
-
#
|
2881
|
+
# store_extsst
|
2888
2882
|
#
|
2889
|
-
# Write EXTSST table using the offsets calculated in
|
2883
|
+
# Write EXTSST table using the offsets calculated in store_shared_strings().
|
2890
2884
|
#
|
2891
2885
|
def store_extsst #:nodoc:
|
2892
2886
|
offsets = @extsst_offsets
|
@@ -2912,7 +2906,7 @@ def store_extsst #:nodoc:
|
|
2912
2906
|
|
2913
2907
|
###############################################################################
|
2914
2908
|
#
|
2915
|
-
#
|
2909
|
+
# add_mso_drawing_group()
|
2916
2910
|
#
|
2917
2911
|
# Write the MSODRAWINGGROUP record that keeps track of the Escher drawing
|
2918
2912
|
# objects in the file such as images, comments and filters.
|
@@ -2943,7 +2937,7 @@ def add_mso_drawing_group #:nodoc:
|
|
2943
2937
|
|
2944
2938
|
###############################################################################
|
2945
2939
|
#
|
2946
|
-
#
|
2940
|
+
# add_mso_drawing_group_continue()
|
2947
2941
|
#
|
2948
2942
|
# See first the WriteExcel::BIFFwriter::_add_continue() method.
|
2949
2943
|
#
|
@@ -2962,7 +2956,7 @@ def add_mso_drawing_group_continue(data) #:nodoc:
|
|
2962
2956
|
continue = 0x003C # Record identifier
|
2963
2957
|
block_count = 1
|
2964
2958
|
|
2965
|
-
# Ignore the base class
|
2959
|
+
# Ignore the base class add_continue() method.
|
2966
2960
|
@ignore_continue = 1
|
2967
2961
|
|
2968
2962
|
# Case 1 above. Just return the data as it is.
|
@@ -2995,12 +2989,12 @@ def add_mso_drawing_group_continue(data) #:nodoc:
|
|
2995
2989
|
header = [continue, data.bytesize].pack("vv")
|
2996
2990
|
append(header, data)
|
2997
2991
|
|
2998
|
-
# Turn the base class
|
2992
|
+
# Turn the base class add_continue() method back on.
|
2999
2993
|
@ignore_continue = 0
|
3000
2994
|
end
|
3001
2995
|
private :add_mso_drawing_group_continue
|
3002
2996
|
|
3003
|
-
def devide_string(string, nth)
|
2997
|
+
def devide_string(string, nth) #:nodoc:
|
3004
2998
|
first_string = string[0, nth]
|
3005
2999
|
latter_string = string[nth, string.size - nth]
|
3006
3000
|
[first_string, latter_string]
|
@@ -3009,7 +3003,7 @@ def devide_string(string, nth)
|
|
3009
3003
|
|
3010
3004
|
###############################################################################
|
3011
3005
|
#
|
3012
|
-
#
|
3006
|
+
# store_mso_dgg_container()
|
3013
3007
|
#
|
3014
3008
|
# Write the Escher DggContainer record that is part of MSODRAWINGGROUP.
|
3015
3009
|
#
|
@@ -3026,7 +3020,7 @@ def store_mso_dgg_container #:nodoc:
|
|
3026
3020
|
|
3027
3021
|
###############################################################################
|
3028
3022
|
#
|
3029
|
-
#
|
3023
|
+
# store_mso_dgg()
|
3030
3024
|
# my $max_spid = $_[0];
|
3031
3025
|
# my $num_clusters = $_[1];
|
3032
3026
|
# my $shapes_saved = $_[2];
|
@@ -3058,7 +3052,7 @@ def store_mso_dgg(max_spid, num_clusters, shapes_saved, drawings_saved, clusters
|
|
3058
3052
|
|
3059
3053
|
###############################################################################
|
3060
3054
|
#
|
3061
|
-
#
|
3055
|
+
# store_mso_bstore_container()
|
3062
3056
|
#
|
3063
3057
|
# Write the Escher BstoreContainer record that is part of MSODRAWINGGROUP.
|
3064
3058
|
#
|
@@ -3077,7 +3071,7 @@ def store_mso_bstore_container #:nodoc:
|
|
3077
3071
|
|
3078
3072
|
###############################################################################
|
3079
3073
|
#
|
3080
|
-
#
|
3074
|
+
# store_mso_images()
|
3081
3075
|
# ref_count = $_[0]
|
3082
3076
|
# image_type = $_[1]
|
3083
3077
|
# image = $_[2]
|
@@ -3109,7 +3103,7 @@ def store_mso_images(ref_count, image_type, image, size, checksum1, checksum2)
|
|
3109
3103
|
|
3110
3104
|
###############################################################################
|
3111
3105
|
#
|
3112
|
-
#
|
3106
|
+
# store_mso_blip_store_entry()
|
3113
3107
|
# ref_count = $_[0]
|
3114
3108
|
# image_type = $_[1]
|
3115
3109
|
# size = $_[2]
|
@@ -3140,7 +3134,7 @@ def store_mso_blip_store_entry(ref_count, image_type, size, checksum1) #:n
|
|
3140
3134
|
|
3141
3135
|
###############################################################################
|
3142
3136
|
#
|
3143
|
-
#
|
3137
|
+
# store_mso_blip()
|
3144
3138
|
# image_type = $_[0]
|
3145
3139
|
# image_data = $_[1]
|
3146
3140
|
# size = $_[2]
|
@@ -3172,7 +3166,7 @@ def store_mso_blip(image_type, image_data, size, checksum1, checksum2) #:n
|
|
3172
3166
|
|
3173
3167
|
###############################################################################
|
3174
3168
|
#
|
3175
|
-
#
|
3169
|
+
# store_mso_opt()
|
3176
3170
|
#
|
3177
3171
|
# Write the Escher Opt record that is part of MSODRAWINGGROUP.
|
3178
3172
|
#
|
@@ -3191,7 +3185,7 @@ def store_mso_opt #:nodoc:
|
|
3191
3185
|
|
3192
3186
|
###############################################################################
|
3193
3187
|
#
|
3194
|
-
#
|
3188
|
+
# store_mso_split_menu_colors()
|
3195
3189
|
#
|
3196
3190
|
# Write the Escher SplitMenuColors record that is part of MSODRAWINGGROUP.
|
3197
3191
|
#
|
@@ -3208,8 +3202,9 @@ def store_mso_split_menu_colors #:nodoc:
|
|
3208
3202
|
end
|
3209
3203
|
private :store_mso_split_menu_colors
|
3210
3204
|
|
3211
|
-
def cleanup
|
3205
|
+
def cleanup #:nodoc:
|
3212
3206
|
super
|
3213
3207
|
sheets.each { |sheet| sheet.cleanup }
|
3214
3208
|
end
|
3209
|
+
private :cleanup
|
3215
3210
|
end
|