Class: BIFFWriter

Inherits:
WriteFile show all
Includes:
CallerInfo
Defined in:
lib/writeexcel/biffwriter.rb,
lib/writeexcel/debug_info.rb

Overview

:nodoc:

Direct Known Subclasses

Workbook, Writeexcel::Worksheet

Constant Summary collapse

BIFF_Version =
0x0600
BigEndian =
[1].pack("I") == [1].pack("N")

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from CallerInfo

#caller_info

Constructor Details

#initializeBIFFWriter

The args here aren't used by BIFFWriter, but they are needed by its subclasses. I don't feel like creating multiple constructors.


30
31
32
33
34
# File 'lib/writeexcel/biffwriter.rb', line 30

def initialize
  super
  set_byte_order
  @ignore_continue = false
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data


23
24
25
# File 'lib/writeexcel/biffwriter.rb', line 23

def data
  @data
end

#datasizeObject (readonly)

Returns the value of attribute datasize


23
24
25
# File 'lib/writeexcel/biffwriter.rb', line 23

def datasize
  @datasize
end

Instance Method Details

#add_continue(data) ⇒ Object

_add_continue()

Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In Excel 97 the limit is 8228 bytes. Records that are longer than these limits must be split up into CONTINUE blocks.

This function take a long BIFF record and inserts CONTINUE records as necessary.

Some records have their own specialised Continue blocks so there is also an option to bypass this function.


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/writeexcel/biffwriter.rb', line 150

def add_continue(data)
  # Skip this if another method handles the continue blocks.
  return data if @ignore_continue

  record  = 0x003C # Record identifier
  header  = [record, @limit].pack("vv")

  # The first 2080/8224 bytes remain intact. However, we have to change
  # the length field of the record.
  #
  data_array = split_by_length(data, @limit)
  first_data = data_array.shift
  last_data  = data_array.pop || ''
  first_data[2, 2] = [@limit-4].pack('v')
  first_data <<
    data_array.join(header) <<
    [record, last_data.bytesize].pack('vv') <<
    last_data
end

#add_mso_generic(type, version, instance, data, length = nil) ⇒ Object

_add_mso_generic()

my $type        = $_[0];
my $version     = $_[1];
my $instance    = $_[2];
my $data        = $_[3];

Create a mso structure that is part of an Escher drawing object. These are are used for images, comments and filters. This generic method is used by other methods to create specific mso records.

Returns the packed record.


184
185
186
187
188
189
190
191
# File 'lib/writeexcel/biffwriter.rb', line 184

def add_mso_generic(type, version, instance, data, length = nil)
  length  ||= data.bytesize

  # The header contains version and instance info packed into 2 bytes.
  header  = version | (instance << 4)

  record  = [header, type, length].pack('vvV') + data
end

#append(*args) ⇒ Object


9
10
11
12
13
14
15
# File 'lib/writeexcel/debug_info.rb', line 9

def append(*args)
  data =
    ruby_18 { args.join } ||
    ruby_19 { args.collect{ |arg| arg.dup.force_encoding('ASCII-8BIT') }.join }
  print_caller_info(data, :method => 'append')
  super
end

#cleanupObject

:nodoc:


203
204
205
# File 'lib/writeexcel/biffwriter.rb', line 203

def cleanup # :nodoc:
  @filehandle.close(true) if @filehandle
end

#clear_data_for_testObject

:nodoc:


199
200
201
# File 'lib/writeexcel/biffwriter.rb', line 199

def clear_data_for_test # :nodoc:
  @data = ''
end

#get_dataObject

get_data().

Retrieves data from memory in one chunk, or from disk in $buffer sized chunks.


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/writeexcel/biffwriter.rb', line 69

def get_data
  buflen = 4096

  # Return data stored in memory
  unless @data.nil?
    tmp   = @data
    @data = nil
    if @using_tmpfile
      @filehandle.open
      @filehandle.binmode
    end
    return tmp
  end

  # Return data stored on disk
  if @using_tmpfile
    return @filehandle.read(buflen)
  end

  # No data to return
  nil
end

#inspectObject

override Object#inspect


208
209
210
# File 'lib/writeexcel/biffwriter.rb', line 208

def inspect          # :nodoc:
  to_s
end

#not_using_tmpfileObject


193
194
195
196
197
# File 'lib/writeexcel/biffwriter.rb', line 193

def not_using_tmpfile
  @filehandle.close(true) if @filehandle
  @filehandle = nil
  @using_tmpfile = nil
end

#prepend(*args) ⇒ Object


17
18
19
20
21
22
23
# File 'lib/writeexcel/debug_info.rb', line 17

def prepend(*args)
  data =
    ruby_18 { args.join } ||
    ruby_19 { args.collect{ |arg| arg.dup.force_encoding('ASCII-8BIT') }.join }
  print_caller_info(data, :method => 'prepend')
  super
end

25
26
27
28
29
30
31
32
33
34
35
# File 'lib/writeexcel/debug_info.rb', line 25

def print_caller_info(data, param = {})
  infos = caller_info

  print "#{param[:method]}\n" if param[:method]
  infos.each do |info|
    print "#{info[:file]}:#{info[:line]}"
    print " in #{info[:method]}" if info[:method]
    print "\n"
  end
  print unpack_record(data) + "\n\n"
end

#set_byte_orderObject

_set_byte_order()

Determine the byte order and store it as class data to avoid recalculating it for each call to new().


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/writeexcel/biffwriter.rb', line 43

def set_byte_order
  # Check if "pack" gives the required IEEE 64bit float
  teststr = [1.2345].pack("d")
  hexdata = [0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F]
  number  = hexdata.pack("C8")

  if number == teststr
    @byte_order = false    # Little Endian
  elsif number == teststr.reverse
    @byte_order = true     # Big Endian
  else
    # Give up. I'll fix this in a later version.
    raise( "Required floating point format not supported "  +
    "on this platform. See the portability section " +
    "of the documentation."
    )
  end
end

#store_bof(type = 0x0005) ⇒ Object

_store_bof($type)

$type = 0x0005, Workbook $type = 0x0010, Worksheet $type = 0x0020, Chart

Writes Excel BOF record to indicate the beginning of a stream or sub-stream in the BIFF file.


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/writeexcel/biffwriter.rb', line 103

def store_bof(type = 0x0005)
  record  = 0x0809      # Record identifier
  length  = 0x0010      # Number of bytes to follow

  # According to the SDK $build and $year should be set to zero.
  # However, this throws a warning in Excel 5. So, use these
  # magic numbers.
  build   = 0x0DBB
  year    = 0x07CC

  bfh     = 0x00000041
  sfo     = 0x00000006

  header  = [record,length].pack("vv")
  data    = [BIFF_Version,type,build,year,bfh,sfo].pack("vvvvVV")

  prepend(header, data)
end

#store_eofObject

_store_eof()

Writes Excel EOF record to indicate the end of a BIFF stream.


128
129
130
131
132
133
134
# File 'lib/writeexcel/biffwriter.rb', line 128

def store_eof
  record = 0x000A
  length = 0x0000
  header = [record,length].pack("vv")

  append(header)
end

#unpack_record(data) ⇒ Object

:nodoc:


37
38
39
# File 'lib/writeexcel/debug_info.rb', line 37

def unpack_record(data)  # :nodoc:
  data.unpack('C*').map! {|c| sprintf("%02X", c) }.join(' ')
end