lib/writeexcel/workbook.rb in writeexcel-0.4.0 vs lib/writeexcel/workbook.rb in writeexcel-0.4.1
- old
+ new
@@ -12,23 +12,15 @@
# converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
#
require 'digest/md5'
require 'nkf'
require 'writeexcel/biffwriter'
-require 'writeexcel/olewriter'
-require 'writeexcel/formula'
-require 'writeexcel/format'
require 'writeexcel/worksheet'
require 'writeexcel/chart'
-require 'writeexcel/charts/area'
-require 'writeexcel/charts/bar'
-require 'writeexcel/charts/column'
-require 'writeexcel/charts/external'
-require 'writeexcel/charts/line'
-require 'writeexcel/charts/pie'
-require 'writeexcel/charts/scatter'
-require 'writeexcel/charts/stock'
+require 'writeexcel/format'
+require 'writeexcel/formula'
+require 'writeexcel/olewriter'
require 'writeexcel/storage_lite'
require 'writeexcel/compatibility'
class Workbook < BIFFWriter
require 'writeexcel/properties'
@@ -110,15 +102,14 @@
:str_unique => 0,
:str_table => {}
}
@str_array = []
@str_block_sizes = []
- @extsst_offsets = []
+ @extsst_offsets = [] # array of [global_offset, local_offset]
@extsst_buckets = 0
@extsst_bucket_size = 0
- @ext_ref_count = 0
@ext_refs = {}
@mso_clusters = []
@mso_size = 0
@@ -156,11 +147,11 @@
add_format(:type => 1, :num_format => 0x09) # 20 Percent
# Add the default format for hyperlinks
@url_format = add_format(:color => 'blue', :underline => 1)
- if file.kind_of?(String) && file != ''
+ if file.respond_to?(:to_str) && file != ''
@fh_out = open(file, "wb")
@internal_fh = 1
else
@fh_out = file
end
@@ -521,12 +512,11 @@
end
end
# Handle utf8 strings
if name.encoding == Encoding::UTF_8
- name = NKF.nkf('-w16B0 -m0 -W', name)
- name.force_encoding('UTF-16BE')
+ name = utf8_to_16be(name)
encoding = 1
end
# Check that the worksheet name doesn't already exist since this is a fatal
# error in Excel 97. The check must also exclude case insensitive matches
@@ -539,46 +529,37 @@
name_b = worksheet.name
encd_b = worksheet.encoding
error = 0;
if encd_a == 0 and encd_b == 0
- error = 1 if name_a.downcase == name_b.downcase
+ error = (name_a.downcase == name_b.downcase)
elsif encd_a == 0 and encd_b == 1
- name_a = name_a.unpack("C*").pack("n*")
- error = 1 if name_a.downcase == name_b.downcase
+ name_a = ascii_to_16be(name_a)
+ error = (name_a.downcase == name_b.downcase)
elsif encd_a == 1 and encd_b == 0
- name_b = name_b.unpack("C*").pack("n*")
- error = 1 if name_a.downcase == name_b.downcase
+ name_b = ascii_to_16be(name_b)
+ error = (name_a.downcase == name_b.downcase)
elsif encd_a == 1 and encd_b == 1
- # # We can do a true case insensitive test with Perl 5.8 and utf8.
- # if ($] >= 5.008) {
- # $name_a = Encode::decode("UTF-16BE", $name_a);
- # $name_b = Encode::decode("UTF-16BE", $name_b);
- # $error = 1 if lc($name_a) eq lc($name_b);
- # }
- # else {
- # # We can't easily do a case insensitive test of the UTF16 names.
- # # As a special case we check if all of the high bytes are nulls and
- # # then do an ASCII style case insensitive test.
+ # TODO : not converted yet.
+
+ # We can't easily do a case insensitive test of the UTF16 names.
+ # As a special case we check if all of the high bytes are nulls and
+ # then do an ASCII style case insensitive test.
#
- # # Strip out the high bytes (funkily).
- # my $hi_a = grep {ord} $name_a =~ /(.)./sg;
- # my $hi_b = grep {ord} $name_b =~ /(.)./sg;
+ # Strip out the high bytes (funkily).
+ # my $hi_a = grep {ord} $name_a =~ /(.)./sg;
+ # my $hi_b = grep {ord} $name_b =~ /(.)./sg;
#
- # if ($hi_a or $hi_b) {
- # $error = 1 if $name_a eq $name_b;
- # }
- # else {
- # $error = 1 if lc($name_a) eq lc($name_b);
- # }
- # }
- # }
- # # If any of the cases failed we throw the error here.
+ # if ($hi_a or $hi_b) {
+ # $error = 1 if $name_a eq $name_b;
+ # }
+ # else {
+ # $error = 1 if lc($name_a) eq lc($name_b);
+ # }
end
- if error != 0
- raise "Worksheet name '#{name}', with case ignored, " +
- "is already in use"
+ if error
+ raise "Worksheet name '#{name}', with case ignored, is already in use"
end
end
[name, encoding]
end
private :check_sheetname
@@ -591,11 +572,13 @@
# format1 = workbook.add_format(props) # Set properties at creation
# format2 = workbook.add_format # Set properties later
#
# See the "CELL FORMATTING" section for more details about Format properties and how to set them.
#
- def add_format(formats = {})
+ def add_format(*args)
+ formats = {}
+ args.each { |arg| formats = formats.merge(arg) }
format = Format.new(@xf_index, @default_formats.merge(formats))
@xf_index += 1
@formats.push format # Store format reference
format
end
@@ -1021,14 +1004,14 @@
#
# See also the properties.rb program in the examples directory of the distro.
#
def set_properties(params)
# Ignore if no args were passed.
- return -1 if !params.kind_of?(Hash) || params.empty?
+ return -1 if !params.respond_to?(:to_hash) || params.empty?
params.each do |k, v|
- params[k] = convert_to_ascii_if_ascii(v) if v.kind_of?(String)
+ params[k] = convert_to_ascii_if_ascii(v) if v.respond_to?(:to_str)
end
# List of valid input parameters.
properties = {
:codepage => [0x0001, 'VT_I2' ],
:title => [0x0002, 'VT_LPSTR' ],
@@ -1066,18 +1049,13 @@
# Create an array of property set values.
property_sets = []
strings.unshift("codepage")
strings.push("created")
- strings.each do |property|
- if params.has_key?(property.to_sym) && !params[property.to_sym].nil?
- property_sets.push(
- [ properties[property.to_sym][0],
- properties[property.to_sym][1],
- params[property.to_sym] ]
- )
- end
+ strings.each do |string|
+ property = string.to_sym
+ property_sets.push(property_set(properties, property, params)) if params[property]
end
# Pack the property sets.
@summary = create_summary_property_set(property_sets)
@@ -1090,27 +1068,26 @@
params[:codepage] = get_property_set_codepage(params, strings)
# Create an array of property set values.
property_sets = []
- ["codepage", "category", "manager", "company"].each do |property|
- if params.has_key?(property.to_sym) && !params[property.to_sym].nil?
- property_sets.push(
- [ properties[property.to_sym][0],
- properties[property.to_sym][1],
- params[property.to_sym] ]
- )
- end
+ [:codepage, :category, :manager, :company].each do |property|
+ property_sets.push(property_set(properties, property, params)) if params[property]
end
# Pack the property sets.
@doc_summary = create_doc_summary_property_set(property_sets)
# Set a flag for when the files is written.
@add_doc_properties = 1
end
+ def property_set(properties, property, params)
+ [ properties[property][0], properties[property][1], params[property] ]
+ end
+ private :property_set
+
###############################################################################
#
# _get_property_set_codepage()
#
# Get the character codepage used by the strings in a property set. If one of
@@ -1181,11 +1158,11 @@
end
# NOTE: If any records are added between here and EOF the
# _calc_sheet_offsets() should be updated to include the new length.
store_country
- if @ext_ref_count != 0
+ if @ext_refs.keys.size != 0
store_supbook
store_externsheet
store_names
end
add_mso_drawing_group
@@ -1194,11 +1171,11 @@
# End Workbook globals
store_eof
# Store the workbook in an OLE container
- store_OLE_file
+ store_ole_filie
end
private :store_workbook
def str_unique=(val) # :nodoc:
@sinfo[:str_unique] = val
@@ -1224,16 +1201,16 @@
@localtime = val
end
###############################################################################
#
- # _store_OLE_file()
+ # _store_ole_filie()
#
# Store the workbook in an OLE container using the default handler or using
# OLE::Storage_Lite if the workbook data is > ~ 7MB.
#
- def store_OLE_file #:nodoc:
+ def store_ole_filie #:nodoc:
maxsize = 7_087_104
# maxsize = 1
if @add_doc_properties == 0 && @biffsize <= maxsize
# Write the OLE file using OLEwriter if data <= 7MB
@@ -1264,17 +1241,15 @@
stream = 'Workbook'.unpack('C*').pack('v*')
workbook = OLEStorageLitePPSFile.new(stream)
workbook.set_file # use tempfile
while tmp = get_data
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
workbook.append(tmp)
end
@worksheets.each do |worksheet|
while tmp = worksheet.get_data
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
workbook.append(tmp)
end
end
streams = []
@@ -1302,11 +1277,11 @@
# Close the filehandle if it was created internally.
return @fh_out.close if @internal_fh != 0
end
end
- private :store_OLE_file
+ private :store_ole_filie
###############################################################################
#
# _calc_sheet_offsets()
#
@@ -1706,11 +1681,10 @@
format = @formats[15] # The default cell format.
font = format.get_font
# Fonts are 0-indexed. According to the SDK there is no index 4,
(0..3).each do
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(font)
end
# Add the default fonts for charts and comments. This aren't connected
# to XF formats. Note, the font size, and some other properties of
@@ -1719,47 +1693,42 @@
# Index 5. Axis numbers.
tmp_format = Format.new(
nil,
:font_only => 1
)
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(tmp_format.get_font)
# Index 6. Series names.
tmp_format = Format.new(
nil,
:font_only => 1
)
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(tmp_format.get_font)
# Index 7. Title.
tmp_format = Format.new(
nil,
:font_only => 1,
:bold => 1
)
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(tmp_format.get_font)
# Index 8. Axes.
tmp_format = Format.new(
nil,
:font_only => 1,
:bold => 1
)
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(tmp_format.get_font)
# Index 9. Comments.
tmp_format = Format.new(
nil,
:font_only => 1,
:font => 'Tahoma',
:size => 8
)
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(tmp_format.get_font)
# Iterate through the XF objects and write a FONT record if it isn't the
# same as the default FONT and if it hasn't already been used.
#
@@ -1785,11 +1754,10 @@
end
fmt.font_index = index
index += 1
font = fmt.get_font
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(font)
end
end
end
private :store_all_fonts
@@ -1840,11 +1808,10 @@
# Write all XF records.
#
def store_all_xfs #:nodoc:
@formats.each do |format|
xf = format.get_xf
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(xf)
end
end
private :store_all_xfs
@@ -2009,31 +1976,30 @@
#
def store_window1 #:nodoc:
record = 0x003D # Record identifier
length = 0x0012 # Number of bytes to follow
- xWn = 0x0000 # Horizontal position of window
- yWn = 0x0000 # Vertical position of window
- dxWn = 0x355C # Width of window
- dyWn = 0x30ED # Height of window
+ x_pos = 0x0000 # Horizontal position of window
+ y_pos = 0x0000 # Vertical position of window
+ dx_win = 0x355C # Width of window
+ dy_win = 0x30ED # Height of window
grbit = 0x0038 # Option flags
ctabsel = @selected # Number of workbook tabs selected
- wTabRatio = 0x0258 # Tab to scrollbar ratio
+ tab_ratio = 0x0258 # Tab to scrollbar ratio
- itabFirst = @sinfo[:firstsheet] # 1st displayed worksheet
- itabCur = @sinfo[:activesheet] # Active worksheet
+ tab_cur = @sinfo[:activesheet] # Active worksheet
+ tab_first = @sinfo[:firstsheet] # 1st displayed worksheet
header = [record, length].pack("vv")
data = [
- xWn, yWn, dxWn, dyWn,
+ x_pos, y_pos, dx_win, dy_win,
grbit,
- itabCur, itabFirst,
- ctabsel, wTabRatio
+ tab_cur, tab_first,
+ ctabsel, tab_ratio
].pack("vvvvvvvvv")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
private :store_window1
###############################################################################
@@ -2062,11 +2028,10 @@
sheetname = sheetname.unpack('v*').pack('n*') if encoding != 0
header = [record, length].pack("vv")
data = [offset, grbit, cch, encoding].pack("VvCC")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data, sheetname)
end
private :store_boundsheet
###############################################################################
@@ -2086,11 +2051,10 @@
xf_index |= 0x8000 # Add flag to indicate built-in style.
header = [record, length].pack("vv")
data = [xf_index, type, level].pack("vCC")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
private :store_style
###############################################################################
@@ -2101,22 +2065,21 @@
# my $encoding = $_[2]; # Char encoding for format string
#
# Writes Excel FORMAT record for non "built-in" numerical formats.
#
def store_num_format(format, ifmt, encoding) #:nodoc:
- format = format.to_s unless format.kind_of?(String)
+ format = format.to_s unless format.respond_to?(:to_str)
record = 0x041E # Record identifier
# length # Number of bytes to follow
# Char length of format string
cch = format.bytesize
format = convert_to_ascii_if_ascii(format)
# Handle utf8 strings
if format.encoding == Encoding::UTF_8
- format = NKF.nkf('-w16B0 -m0 -W', format)
- format.force_encoding('UTF-16BE')
+ format = utf8_to_16be(format)
encoding = 1
end
# Handle Unicode format strings.
if encoding == 1
@@ -2136,11 +2099,10 @@
length = 0x05 + format.bytesize
header = [record, length].pack("vv")
data = [ifmt, cch, encoding].pack("vvC")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data, format)
end
private :store_num_format
###############################################################################
@@ -2156,11 +2118,10 @@
f1904 = @date_1904 ? 1 : 0 # Flag for 1904 date system
header = [record, length].pack("vv")
data = [f1904].pack("v")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
private :store_1904
###############################################################################
@@ -2172,17 +2133,16 @@
#
def store_supbook #:nodoc:
record = 0x01AE # Record identifier
length = 0x0004 # Number of bytes to follow
- ctabs = @worksheets.size # Number of worksheets
- stVirtPath = 0x0401 # Encoded workbook filename
+ tabs = @worksheets.size # Number of worksheets
+ virt_path = 0x0401 # Encoded workbook filename
header = [record, length].pack("vv")
- data = [ctabs, stVirtPath].pack("vv")
+ data = [tabs, virt_path].pack("vv")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
private :store_supbook
###############################################################################
@@ -2195,12 +2155,11 @@
#
def store_externsheet # :nodoc:
record = 0x0017 # Record identifier
# Get the external refs
- ext_refs = @ext_refs
- ext = ext_refs.keys.sort
+ ext = @ext_refs.keys.sort
# Change the external refs from stringified "1:1" to [1, 1]
ext.map! {|e| e.split(/:/).map! {|v| v.to_i} }
cxti = ext.size # Number of Excel XTI structures
@@ -2212,11 +2171,10 @@
end
data = [cxti].pack("v") + rgxti
header = [record, data.bytesize].pack("vv")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
#
# Store the NAME record used for storing the print area, repeat rows, repeat
@@ -2265,11 +2223,10 @@
data += name
data += formula
header = [record, data.bytesize].pack("vv")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
###############################################################################
#
@@ -2290,47 +2247,46 @@
def store_name_short(index, type, ext_ref, rowmin, rowmax, colmin, colmax, hidden = nil) #:nodoc:
record = 0x0018 # Record identifier
length = 0x001b # Number of bytes to follow
grbit = 0x0020 # Option flags
- chKey = 0x00 # Keyboard shortcut
+ chkey = 0x00 # Keyboard shortcut
cch = 0x01 # Length of text name
cce = 0x000b # Length of text definition
unknown01 = 0x0000 #
ixals = index + 1 # Sheet index
unknown02 = 0x00 #
- cchCustMenu = 0x00 # Length of cust menu text
- cchDescription = 0x00 # Length of description text
- cchHelptopic = 0x00 # Length of help topic text
- cchStatustext = 0x00 # Length of status bar text
+ cch_cust_menu = 0x00 # Length of cust menu text
+ cch_description = 0x00 # Length of description text
+ cch_helptopic = 0x00 # Length of help topic text
+ cch_statustext = 0x00 # Length of status bar text
rgch = type # Built-in name type
unknown03 = 0x3b #
grbit = 0x0021 if hidden
header = [record, length].pack("vv")
data = [grbit].pack("v")
- data += [chKey].pack("C")
+ data += [chkey].pack("C")
data += [cch].pack("C")
data += [cce].pack("v")
data += [unknown01].pack("v")
data += [ixals].pack("v")
data += [unknown02].pack("C")
- data += [cchCustMenu].pack("C")
- data += [cchDescription].pack("C")
- data += [cchHelptopic].pack("C")
- data += [cchStatustext].pack("C")
+ data += [cch_cust_menu].pack("C")
+ data += [cch_description].pack("C")
+ data += [cch_helptopic].pack("C")
+ data += [cch_statustext].pack("C")
data += [rgch].pack("C")
data += [unknown03].pack("C")
data += [ext_ref].pack("v")
data += [rowmin].pack("v")
data += [rowmax].pack("v")
data += [colmin].pack("v")
data += [colmax].pack("v")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
private :store_name_short
###############################################################################
@@ -2353,38 +2309,38 @@
def store_name_long(index, type, ext_ref, rowmin, rowmax, colmin, colmax) #:nodoc:
record = 0x0018 # Record identifier
length = 0x002a # Number of bytes to follow
grbit = 0x0020 # Option flags
- chKey = 0x00 # Keyboard shortcut
+ chkey = 0x00 # Keyboard shortcut
cch = 0x01 # Length of text name
cce = 0x001a # Length of text definition
unknown01 = 0x0000 #
ixals = index + 1 # Sheet index
unknown02 = 0x00 #
- cchCustMenu = 0x00 # Length of cust menu text
- cchDescription = 0x00 # Length of description text
- cchHelptopic = 0x00 # Length of help topic text
- cchStatustext = 0x00 # Length of status bar text
+ cch_cust_menu = 0x00 # Length of cust menu text
+ cch_description = 0x00 # Length of description text
+ cch_helptopic = 0x00 # Length of help topic text
+ cch_statustext = 0x00 # Length of status bar text
rgch = type # Built-in name type
unknown03 = 0x29
unknown04 = 0x0017
unknown05 = 0x3b
header = [record, length].pack("vv")
data = [grbit].pack("v")
- data += [chKey].pack("C")
+ data += [chkey].pack("C")
data += [cch].pack("C")
data += [cce].pack("v")
data += [unknown01].pack("v")
data += [ixals].pack("v")
data += [unknown02].pack("C")
- data += [cchCustMenu].pack("C")
- data += [cchDescription].pack("C")
- data += [cchHelptopic].pack("C")
- data += [cchStatustext].pack("C")
+ data += [cch_cust_menu].pack("C")
+ data += [cch_description].pack("C")
+ data += [cch_helptopic].pack("C")
+ data += [cch_statustext].pack("C")
data += [rgch].pack("C")
# Column definition
data += [unknown03].pack("C")
data += [unknown04].pack("v")
@@ -2403,11 +2359,10 @@
data += [0x00].pack("v")
data += [0xff].pack("v")
# End of data
data += [0x10].pack("C")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
private :store_name_long
###############################################################################
@@ -2427,11 +2382,10 @@
data += p.pack('CCCC')
end
header = [record, length, ccv].pack("vvv")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
private :store_palette
###############################################################################
@@ -2443,15 +2397,11 @@
def store_codepage #:nodoc:
record = 0x0042 # Record identifier
length = 0x0002 # Number of bytes to follow
cv = @codepage # The code page
- header = [record, length].pack("vv")
- data = [cv].pack("v")
-
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
- append(header, data)
+ store_common(record, length, cv)
end
private :store_codepage
###############################################################################
#
@@ -2463,14 +2413,11 @@
record = 0x008C # Record identifier
length = 0x0004 # Number of bytes to follow
country_default = @country
country_win_ini = @country
- header = [record, length].pack("vv")
- data = [country_default, country_win_ini].pack("vv")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
- append(header, data)
+ store_common(record, length, country_default, country_win_ini)
end
private :store_country
###############################################################################
#
@@ -2481,101 +2428,81 @@
def store_hideobj #:nodoc:
record = 0x008D # Record identifier
length = 0x0002 # Number of bytes to follow
hide = @hideobj # Option to hide objects
- header = [record, length].pack("vv")
- data = [hide].pack("v")
-
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
- append(header, data)
+ store_common(record, length, hide)
end
private :store_hideobj
- ###############################################################################
- ###############################################################################
- ###############################################################################
+ def store_common(record, length, *data)
+ header = [record, length].pack("vv")
+ add_data = [*data].pack("v*")
+ append(header, add_data)
+ end
+ private :store_common
-
###############################################################################
#
# _calculate_extern_sizes()
#
# We need to calculate the space required by the SUPBOOK, EXTERNSHEET and NAME
# records so that it can be added to the BOUNDSHEET offsets.
#
def calculate_extern_sizes # :nodoc:
ext_refs = @parser.get_ext_sheets
- ext_ref_count = ext_refs.keys.size
length = 0
index = 0
unless @defined_names.empty?
index = 0
key = "#{index}:#{index}"
- unless ext_refs.has_key?(key)
- ext_refs[key] = ext_ref_count
- ext_ref_count += 1
- end
+ add_ext_refs(ext_refs, key) unless ext_refs.has_key?(key)
end
@defined_names.each do |defined_name|
length += 19 + defined_name[:name].bytesize + defined_name[:formula].bytesize
end
@worksheets.each do |worksheet|
rowmin = worksheet.title_rowmin
colmin = worksheet.title_colmin
- filter = worksheet.filter_count
key = "#{index}:#{index}"
index += 1
# Add area NAME records
#
- if !worksheet.print_rowmin.nil?
- if ext_refs[key].nil?
- ext_refs[key] = ext_ref_count
- ext_ref_count += 1
- end
+ if worksheet.print_rowmin
+ add_ext_refs(ext_refs, key) unless ext_refs[key]
length += 31
end
# Add title NAME records
#
if rowmin and colmin
- if ext_refs[key].nil?
- ext_refs[key] = ext_ref_count
- ext_ref_count += 1
- end
-
+ add_ext_refs(ext_refs, key) unless ext_refs[key]
length += 46
elsif rowmin or colmin
- if ext_refs[key].nil?
- ext_refs[key] = ext_ref_count
- ext_ref_count += 1
- end
+ add_ext_refs(ext_refs, key) unless ext_refs[key]
length += 31
else
# TODO, may need this later.
end
# Add Autofilter NAME records
#
- if filter != 0
- if ext_refs[key].nil?
- ext_refs[key] = ext_ref_count
- ext_ref_count += 1
- end
+ unless worksheet.filter_count == 0
+ add_ext_refs(ext_refs, key) unless ext_refs[key]
length += 31
end
end
# Update the ref counts.
- @ext_ref_count = ext_ref_count
+ ext_ref_count = ext_refs.keys.size
@ext_refs = ext_refs
# If there are no external refs then we don't write, SUPBOOK, EXTERNSHEET
# and NAME. Therefore the length is 0.
@@ -2588,10 +2515,15 @@
length += 6 * (1 + ext_ref_count)
length
end
+ def add_ext_refs(ext_refs, key)
+ ext_refs[key] = ext_refs.keys.size
+ end
+ private :add_ext_refs
+
###############################################################################
#
# _calculate_shared_string_sizes()
#
# Handling of the SST continue blocks is complicated by the need to include an
@@ -2633,14 +2565,11 @@
written = 0
block_sizes = []
continue = 0
strings.each do |string|
-
string_length = string.bytesize
- encoding = string.unpack("xx C")[0]
- split_string = 0
# Block length is the total length of the strings that will be
# written out in a single SST or CONTINUE block.
#
block_length += string_length
@@ -2649,49 +2578,19 @@
if block_length < continue_limit
written += string_length
next
end
-
# Deal with the cases where the next string to be written will exceed
# the CONTINUE boundary. If the string is very long it may need to be
# written in more than one CONTINUE record.
- #
+ encoding = string.unpack("xx C")[0]
+ split_string = 0
while block_length >= continue_limit
+ header_length, space_remaining, align, split_string =
+ _split_string_setup(encoding, split_string, continue_limit, written, continue)
- # We need to avoid the case where a string is continued in the first
- # n bytes that contain the string header information.
- #
- header_length = 3 # Min string + header size -1
- space_remaining = continue_limit -written -continue
-
-
- # Unicode data should only be split on char (2 byte) boundaries.
- # Therefore, in some cases we need to reduce the amount of available
- # space by 1 byte to ensure the correct alignment.
- align = 0
-
- # Only applies to Unicode strings
- if encoding == 1
- # Min string + header size -1
- header_length = 4
-
- if space_remaining > header_length
- # String contains 3 byte header => split on odd boundary
- if split_string == 0 and space_remaining % 2 != 1
- space_remaining -= 1
- align = 1
- # Split section without header => split on even boundary
- elsif split_string != 0 and space_remaining % 2 == 1
- space_remaining -= 1
- align = 1
- end
-
- split_string = 1
- end
- end
-
if space_remaining > header_length
# Write as much as possible of the string in the current block
written += space_remaining
# Reduce the current block length by the amount written
@@ -2748,10 +2647,42 @@
length
end
private :calculate_shared_string_sizes
+ def _split_string_setup(encoding, split_string, continue_limit, written, continue)
+ # We need to avoid the case where a string is continued in the first
+ # n bytes that contain the string header information.
+ header_length = 3 # Min string + header size -1
+ space_remaining = continue_limit - written - continue
+
+ # Unicode data should only be split on char (2 byte) boundaries.
+ # Therefore, in some cases we need to reduce the amount of available
+ # space by 1 byte to ensure the correct alignment.
+ align = 0
+
+ # Only applies to Unicode strings
+ if encoding == 1
+ # Min string + header size -1
+ header_length = 4
+ if space_remaining > header_length
+ # String contains 3 byte header => split on odd boundary
+ if split_string == 0 and space_remaining % 2 != 1
+ space_remaining -= 1
+ align = 1
+ # Split section without header => split on even boundary
+ elsif split_string != 0 and space_remaining % 2 == 1
+ space_remaining -= 1
+ align = 1
+ end
+ split_string = 1
+ end
+ end
+ [header_length, space_remaining, align, split_string]
+ end
+ private :_split_string_setup
+
###############################################################################
#
# _store_shared_strings()
#
# Write all of the workbooks strings into an indexed array.
@@ -2795,106 +2726,63 @@
sst_block_start = @datasize
# Write the SST block header information
header = [record, length].pack("vv")
data = [@sinfo[:str_total], @sinfo[:str_unique]].pack("VV")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
# Iterate through the strings and write them out
return if strings.empty?
strings.each do |string|
string_length = string.bytesize
- encoding = string.unpack("xx C")[0]
- split_string = 0
- bucket_string = 0 # Used to track EXTSST bucket offsets.
# Check if the string is at the start of a EXTSST bucket.
extsst_str_num += 1
- if extsst_str_num % @extsst_bucket_size == 0
- bucket_string = 1
- end
+ # Used to track EXTSST bucket offsets.
+ bucket_string = (extsst_str_num % @extsst_bucket_size == 0)
# Block length is the total length of the strings that will be
# written out in a single SST or CONTINUE block.
#
block_length += string_length
# We can write the string if it doesn't cross a CONTINUE boundary
if block_length < continue_limit
# Store location of EXTSST bucket string.
- if bucket_string != 0
- global_offset = @datasize
- local_offset = @datasize - sst_block_start
-
- @extsst_offsets.push([global_offset, local_offset])
- bucket_string = 0
+ if bucket_string
+ @extsst_offsets.push([@datasize, @datasize - sst_block_start])
+ bucket_string = false
end
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(string)
written += string_length
next
end
# Deal with the cases where the next string to be written will exceed
# the CONTINUE boundary. If the string is very long it may need to be
# written in more than one CONTINUE record.
- #
+ encoding = string.unpack("xx C")[0]
+ split_string = 0
while block_length >= continue_limit
+ header_length, space_remaining, align, split_string =
+ _split_string_setup(encoding, split_string, continue_limit, written, continue)
- # We need to avoid the case where a string is continued in the first
- # n bytes that contain the string header information.
- #
- header_length = 3 # Min string + header size -1
- space_remaining = continue_limit -written -continue
-
-
- # Unicode data should only be split on char (2 byte) boundaries.
- # Therefore, in some cases we need to reduce the amount of available
- # space by 1 byte to ensure the correct alignment.
- align = 0
-
- # Only applies to Unicode strings
- if encoding == 1
- # Min string + header size -1
- header_length = 4
-
- if space_remaining > header_length
- # String contains 3 byte header => split on odd boundary
- if split_string == 0 and space_remaining % 2 != 1
- space_remaining -= 1
- align = 1
- # Split section without header => split on even boundary
- elsif split_string != 0 and space_remaining % 2 == 1
- space_remaining -= 1
- align = 1
- end
-
- split_string = 1
- end
- end
-
if space_remaining > header_length
# Write as much as possible of the string in the current block
tmp = string[0, space_remaining]
# Store location of EXTSST bucket string.
- if bucket_string != 0
- global_offset = @datasize
- local_offset = @datasize - sst_block_start
-
- @extsst_offsets.push([global_offset, local_offset])
- bucket_string = 0
+ if bucket_string
+ @extsst_offsets.push([@datasize, @datasize - sst_block_start])
+ bucket_string = false
end
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(tmp)
-
# The remainder will be written in the next block(s)
string = string[space_remaining .. string.length-1]
# Reduce the current block length by the amount written
block_length -= continue_limit -continue -align
@@ -2922,30 +2810,24 @@
length = block_sizes.shift
header = [record, length].pack("vv")
header += [encoding].pack("C") if continue != 0
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header)
end
# If the string (or substr) is small enough we can write it in the
# new CONTINUE block. Else, go through the loop again to write it in
# one or more CONTINUE blocks
#
if block_length < continue_limit
# Store location of EXTSST bucket string.
- if bucket_string != 0
- global_offset = @datasize
- local_offset = @datasize - sst_block_start
-
- @extsst_offsets.push([global_offset, local_offset])
-
- bucket_string = 0
+ if bucket_string
+ @extsst_offsets.push([@datasize, @datasize - sst_block_start])
+ bucket_string = false
end
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(string)
written = block_length
else
written = 0
@@ -3000,11 +2882,10 @@
offsets.each do |offset|
data += [offset[0], offset[1], 0].pack('Vvv')
end
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
end
private :store_extsst
#
@@ -3066,20 +2947,18 @@
# Ignore the base class _add_continue() method.
@ignore_continue = 1
# Case 1 above. Just return the data as it is.
if data.bytesize <= limit
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(data)
return
end
# Change length field of the first MSODRAWINGGROUP block. Case 2 and 3.
tmp = data.dup
tmp[0, limit + 4] = ""
tmp[2, 2] = [limit].pack('v')
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(tmp)
# Add MSODRAWINGGROUP and CONTINUE blocks for Case 3 above.
while data.bytesize > limit
if block_count == 1
@@ -3091,16 +2970,14 @@
header = [continue, limit].pack("vv")
end
tmp = data.dup
tmp[0, limit] = ''
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, tmp)
end
# Last CONTINUE block for remaining data. Case 2 and 3 above.
header = [continue, data.bytesize].pack("vv")
- print "#{__FILE__}(#{__LINE__}) \n" if defined?($debug)
append(header, data)
# Turn the base class _add_continue() method back on.
@ignore_continue = 0
end