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.



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

def initialize
  super
  set_byte_order
  @ignore_continue = false
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



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

def data
  @data
end

#datasizeObject (readonly)

Returns the value of attribute datasize.



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

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.



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

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.



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

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)

  [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:



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

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

#clear_data_for_testObject

:nodoc:



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

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.



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

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



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

def inspect          # :nodoc:
  to_s
end

#not_using_tmpfileObject



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

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().



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

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.



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

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.



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

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