class Cell attr_reader :index def set_style(style) style = StyleFormat.new(style) if style.is_a?(Hash) @format_index = @parent.parent_wb.styles.add(style) end def row @parent end def col @index end end class StringCell < Cell def initialize(parent, index, format_index, sst_index) @parent = parent @index = index @format_index = format_index @sst_index = sst_index end def to_biff LabelSSTRecord.new(@parent.index, @index, @format_index, @sst_index).to_biff end end class BlankCell < Cell def initialize(parent, index, format_index) @parent = parent @index = index @format_index = format_index end def to_biff BlankRecord.new(@parent.index, @index, @format_index).to_biff end end class NumberCell < Cell def initialize(parent, index, format_index, number) @parent = parent @index = index @format_index = format_index @number = number end def rk_record(rk_encoded) RKRecord.new(@parent.index, @index, @format_index, rk_encoded).to_biff end # TODO test this section to be sure numbers are categorized and packed correctly. def to_biff # 30 bit signed int in_range = (-0x20000000 <= @number) && (@number < 0x20000000) is_int = (@number.to_i == @number) if in_range && is_int rk_encoded = 2 | (@number.to_i << 2) return rk_record(rk_encoded) end # try scaling by 100 then using a 30 bit signed int in_range = (-0x20000000 <= @number * 100) && (@number * 100 < 0x20000000) round_trip = (@number.to_i*100) == @number*100 if in_range && round_trip rk_encoded = (3 | (@number.to_i*100 << 2)) return rk_record(rk_encoded) end w0, w1, w2, w3 = [@number].pack('E').unpack('v4') is_float_rk = (w0 == 0) && (w1 == 0) && (w2 & 0xFFFC) == w2 if is_float_rk rk_encoded = (w3 << 16) | w2 return rk_record(rk_encoded) end w0, w1, w2, w3 = [@number * 100].pack('E').unpack('v4') is_float_rk_100 = w0 == 0 && w1 == 0 && w2 & 0xFFFC == w2 if is_float_rk_100 rk_encoded = 1 | (w3 << 16) | w2 return rk_record(rk_encoded) end # If not an RK value, use a NumberRecord instead. NumberRecord.new(@parent.index, @index, @format_index, @number).to_biff end end class MulNumberCell < Cell def initialize(parent, index, format_index, sst_index) @parent = parent @index = index @format_index = format_index @sst_index = sst_index end def to_biff raise "not implemented" end end class MulBlankCell < Cell def initialize(parent, col1, col2, xf_idx) raise unless col1 < col2 @parent = parent @col1 = col1 @col2 = col2 @xf_idx = xf_idx end def to_biff MulBlankRecord.new(@parent.index, @col1, @col2, @xf_idx).to_biff end end class FormulaCell < Cell def initialize(parent, index, format_index, formula, calc_flags = 0) @parent = parent @index = index @format_index = format_index @formula = formula @calc_flags = calc_flags end def to_biff args = [@parent.index, @index, @format_index, @formula.to_biff, @calc_flags] FormulaRecord.new(*args).to_biff end end class BooleanCell < Cell def initialize(parent, index, format_index, number) @parent = parent @index = index @format_index = format_index @number = number @is_error = 0 end def to_biff number = @number ? 1 : 0 BoolErrRecord.new(@parent.index, @index, @format_index, number, @is_error).to_biff end end class ErrorCell < Cell ERROR_CODES = { 0x00 => 0, # Intersection of two cell ranges is empty 0x07 => 7, # Division by zero 0x0F => 15, # Wrong type of operand 0x17 => 23, # Illegal or deleted cell reference 0x1D => 29, # Wrong function or range name 0x24 => 36, # Value range overflow 0x2A => 42, # Argument or function not available '#NULL!' => 0, # Intersection of two cell ranges is empty '#DIV/0!' => 7, # Division by zero '#VALUE!' => 36, # Wrong type of operand '#REF!' => 23, # Illegal or deleted cell reference '#NAME?' => 29, # Wrong function or range name '#NUM!' => 36, # Value range overflow '#N/A!' => 42 # Argument or function not available } def initialize(parent, index, format_index, error_string_or_code) @parent = parent @index = index @format_index = format_index @number = ERROR_CODES[error_string_or_code] @is_error = 1 raise "invalid error code #{error_string_or_code}" if @number.nil? end def to_biff BoolErrRecord.new(@parent.index, @index, @format_index, @number, @is_error) end end