writeexcel 0.6.4 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|