WriteExcel 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +17 -0
  5. data/Rakefile +47 -0
  6. data/VERSION +1 -0
  7. data/examples/a_simple.rb +42 -0
  8. data/examples/autofilters.rb +266 -0
  9. data/examples/bigfile.rb +30 -0
  10. data/examples/copyformat.rb +51 -0
  11. data/examples/data_validate.rb +278 -0
  12. data/examples/date_time.rb +86 -0
  13. data/examples/demo.rb +118 -0
  14. data/examples/diag_border.rb +35 -0
  15. data/examples/formats.rb +489 -0
  16. data/examples/header.rb +136 -0
  17. data/examples/hidden.rb +28 -0
  18. data/examples/hyperlink.rb +42 -0
  19. data/examples/images.rb +52 -0
  20. data/examples/merge1.rb +39 -0
  21. data/examples/merge2.rb +44 -0
  22. data/examples/merge3.rb +65 -0
  23. data/examples/merge4.rb +82 -0
  24. data/examples/merge5.rb +79 -0
  25. data/examples/protection.rb +46 -0
  26. data/examples/regions.rb +52 -0
  27. data/examples/repeat.rb +42 -0
  28. data/examples/stats.rb +75 -0
  29. data/examples/stocks.rb +80 -0
  30. data/examples/tab_colors.rb +30 -0
  31. data/lib/WriteExcel.rb +30 -0
  32. data/lib/WriteExcel/biffwriter.rb +259 -0
  33. data/lib/WriteExcel/chart.rb +217 -0
  34. data/lib/WriteExcel/excelformula.y +138 -0
  35. data/lib/WriteExcel/excelformulaparser.rb +573 -0
  36. data/lib/WriteExcel/format.rb +1108 -0
  37. data/lib/WriteExcel/formula.rb +986 -0
  38. data/lib/WriteExcel/olewriter.rb +322 -0
  39. data/lib/WriteExcel/properties.rb +250 -0
  40. data/lib/WriteExcel/storage_lite.rb +590 -0
  41. data/lib/WriteExcel/workbook.rb +2602 -0
  42. data/lib/WriteExcel/worksheet.rb +6378 -0
  43. data/spec/WriteExcel_spec.rb +7 -0
  44. data/spec/spec.opts +1 -0
  45. data/spec/spec_helper.rb +9 -0
  46. data/test/tc_all.rb +31 -0
  47. data/test/tc_biff.rb +104 -0
  48. data/test/tc_chart.rb +22 -0
  49. data/test/tc_example_match.rb +1280 -0
  50. data/test/tc_format.rb +1264 -0
  51. data/test/tc_formula.rb +63 -0
  52. data/test/tc_ole.rb +110 -0
  53. data/test/tc_storage_lite.rb +102 -0
  54. data/test/tc_workbook.rb +115 -0
  55. data/test/tc_worksheet.rb +115 -0
  56. data/test/test_00_IEEE_double.rb +14 -0
  57. data/test/test_01_add_worksheet.rb +12 -0
  58. data/test/test_02_merge_formats.rb +58 -0
  59. data/test/test_04_dimensions.rb +397 -0
  60. data/test/test_05_rows.rb +182 -0
  61. data/test/test_06_extsst.rb +80 -0
  62. data/test/test_11_date_time.rb +484 -0
  63. data/test/test_12_date_only.rb +506 -0
  64. data/test/test_13_date_seconds.rb +486 -0
  65. data/test/test_21_escher.rb +629 -0
  66. data/test/test_22_mso_drawing_group.rb +739 -0
  67. data/test/test_23_note.rb +78 -0
  68. data/test/test_24_txo.rb +80 -0
  69. data/test/test_26_autofilter.rb +327 -0
  70. data/test/test_27_autofilter.rb +144 -0
  71. data/test/test_28_autofilter.rb +174 -0
  72. data/test/test_29_process_jpg.rb +131 -0
  73. data/test/test_30_validation_dval.rb +82 -0
  74. data/test/test_31_validation_dv_strings.rb +131 -0
  75. data/test/test_32_validation_dv_formula.rb +211 -0
  76. data/test/test_40_property_types.rb +191 -0
  77. data/test/test_41_properties.rb +238 -0
  78. data/test/test_42_set_properties.rb +430 -0
  79. data/test/ts_all.rb +34 -0
  80. metadata +154 -0
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ ###############################################################################
4
+ #
5
+ # Example of how to use the Spreadsheet::WriteExcel merge_cells() workbook
6
+ # method with complex formatting and rotation.
7
+ #
8
+ #
9
+ # reverse('©'), September 2002, John McNamara, jmcnamara@cpan.org
10
+ #
11
+ # original written in Perl by John McNamara
12
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
13
+ #
14
+
15
+ require 'rubygems'
16
+ require 'WriteExcel'
17
+
18
+ # Create a new workbook and add a worksheet
19
+ workbook = Spreadsheet::WriteExcel.new('merge5.xls')
20
+ worksheet = workbook.add_worksheet
21
+
22
+
23
+ # Increase the cell size of the merged cells to highlight the formatting.
24
+ (3..8).each { |col| worksheet.set_row(col, 36) }
25
+ [1, 3, 5].each { |n| worksheet.set_column(n, n, 15) }
26
+
27
+
28
+ ###############################################################################
29
+ #
30
+ # Rotation 1, letters run from top to bottom
31
+ #
32
+ format1 = workbook.add_format(
33
+ :border => 6,
34
+ :bold => 1,
35
+ :color => 'red',
36
+ :valign => 'vcentre',
37
+ :align => 'centre',
38
+ :rotation => 270
39
+ )
40
+
41
+
42
+ worksheet.merge_range('B4:B9', 'Rotation 270', format1)
43
+
44
+
45
+ ###############################################################################
46
+ #
47
+ # Rotation 2, 90° anticlockwise
48
+ #
49
+ format2 = workbook.add_format(
50
+ :border => 6,
51
+ :bold => 1,
52
+ :color => 'red',
53
+ :valign => 'vcentre',
54
+ :align => 'centre',
55
+ :rotation => 90
56
+ )
57
+
58
+
59
+ worksheet.merge_range('D4:D9', 'Rotation 90°', format2)
60
+
61
+
62
+
63
+ ###############################################################################
64
+ #
65
+ # Rotation 3, 90° clockwise
66
+ #
67
+ format3 = workbook.add_format(
68
+ :border => 6,
69
+ :bold => 1,
70
+ :color => 'red',
71
+ :valign => 'vcentre',
72
+ :align => 'centre',
73
+ :rotation => -90
74
+ )
75
+
76
+
77
+ worksheet.merge_range('F4:F9', 'Rotation -90°', format3)
78
+
79
+ workbook.close
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ ########################################################################
4
+ #
5
+ # Example of cell locking and formula hiding in an Excel worksheet via
6
+ # the Spreadsheet::WriteExcel module.
7
+ #
8
+ # reverse('©'), August 2001, John McNamara, jmcnamara@cpan.org
9
+ #
10
+ # original written in Perl by John McNamara
11
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
12
+ #
13
+
14
+ require 'rubygems'
15
+ require 'WriteExcel'
16
+
17
+ workbook = Spreadsheet::WriteExcel.new("protection.xls")
18
+ worksheet = workbook.add_worksheet
19
+
20
+ # Create some format objects
21
+ locked = workbook.add_format(:locked => 1)
22
+ unlocked = workbook.add_format(:locked => 0)
23
+ hidden = workbook.add_format(:hidden => 1)
24
+
25
+ # Format the columns
26
+ worksheet.set_column('A:A', 42)
27
+ worksheet.set_selection('B3:B3')
28
+
29
+ # Protect the worksheet
30
+ worksheet.protect
31
+
32
+ # Examples of cell locking and hiding
33
+ worksheet.write('A1', 'Cell B1 is locked. It cannot be edited.')
34
+ worksheet.write('B1', '=1+2', locked)
35
+
36
+ worksheet.write('A2', 'Cell B2 is unlocked. It can be edited.')
37
+ worksheet.write('B2', '=1+2', unlocked)
38
+
39
+ worksheet.write('A3', "Cell B3 is hidden. The formula isn't visible.")
40
+ worksheet.write('B3', '=1+2', hidden)
41
+
42
+ worksheet.write('A5', 'Use Menu->Tools->Protection->Unprotect Sheet')
43
+ worksheet.write('A6', 'to remove the worksheet protection. ')
44
+
45
+ workbook.close
46
+
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ ###############################################################################
4
+ #
5
+ # Example of how to use the WriteExcel module to write a basic multiple
6
+ # worksheet Excel file.
7
+ #
8
+ # reverse('©'), March 2001, John McNamara, jmcnamara@cpan.org
9
+ #
10
+ # original written in Perl by John McNamara
11
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
12
+ #
13
+
14
+ require 'rubygems'
15
+ require 'WriteExcel'
16
+
17
+ workbook = Spreadsheet::WriteExcel.new("regions.xls")
18
+
19
+ # Add some worksheets
20
+ north = workbook.add_worksheet("North")
21
+ south = workbook.add_worksheet("South")
22
+ east = workbook.add_worksheet("East")
23
+ west = workbook.add_worksheet("West")
24
+
25
+ # Add a Format
26
+ format = workbook.add_format()
27
+ format.set_bold()
28
+ format.set_color('blue')
29
+
30
+ # Add a caption to each worksheet
31
+ workbook.sheets.each do |worksheet|
32
+ worksheet.write(0, 0, "Sales", format)
33
+ end
34
+
35
+ # Write some data
36
+ north.write(0, 1, 200000)
37
+ south.write(0, 1, 100000)
38
+ east.write(0, 1, 150000)
39
+ west.write(0, 1, 100000)
40
+
41
+ # Set the active worksheet
42
+ bp=1
43
+ south.activate()
44
+
45
+ # Set the width of the first column
46
+ south.set_column(0, 0, 20)
47
+
48
+ # Set the active cell
49
+ south.set_selection(0, 1)
50
+
51
+ workbook.close
52
+
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ ######################################################################
4
+ #
5
+ # Example of writing repeated formulas.
6
+ #
7
+ # reverse('©'), August 2002, John McNamara, jmcnamara@cpan.org
8
+ #
9
+ # original written in Perl by John McNamara
10
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
11
+ #
12
+
13
+ require 'rubygems'
14
+ require 'WriteExcel'
15
+
16
+ workbook = Spreadsheet::WriteExcel.new("repeat.xls")
17
+ worksheet = workbook.add_worksheet
18
+
19
+ limit = 1000
20
+
21
+ # Write a column of numbers
22
+ 0.upto(limit) do |row|
23
+ worksheet.write(row, 0, row)
24
+ end
25
+
26
+ # Store a formula
27
+ formula = worksheet.store_formula('=A1*5+4')
28
+
29
+ # Write a column of formulas based on the stored formula
30
+ 0.upto(limit) do |row|
31
+ worksheet.repeat_formula(row, 1, formula, nil,
32
+ /A1/, 'A'+(row+1).to_s)
33
+ end
34
+
35
+ # Direct formula writing. As a speed comparison uncomment the
36
+ # following and run the program again
37
+
38
+ #for row (0..limit) {
39
+ # worksheet.write_formula(row, 2, '=A'.(row+1).'*5+4')
40
+ #}
41
+
42
+ workbook.close
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ ###############################################################################
4
+ #
5
+ # This is a simple example of how to use functions with the
6
+ # Spreadsheet::WriteExcel module.
7
+ #
8
+ # reverse('©'), March 2001, John McNamara, jmcnamara@cpan.org
9
+ #
10
+ # original written in Perl by John McNamara
11
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
12
+ #
13
+
14
+ require 'rubygems'
15
+ require 'WriteExcel'
16
+ include Spreadsheet
17
+ xlsfile = 'stats.xls'
18
+
19
+ workbook = Spreadsheet::WriteExcel.new(xlsfile)
20
+ worksheet = workbook.add_worksheet('Test data')
21
+
22
+ # Set the column width for columns 1
23
+ worksheet.set_column(0, 0, 20)
24
+
25
+
26
+ # Create a format for the headings
27
+ format = workbook.add_format
28
+ format.set_bold
29
+
30
+
31
+ # Write the sample data
32
+ worksheet.write(0, 0, 'Sample', format)
33
+ worksheet.write(0, 1, 1)
34
+ worksheet.write(0, 2, 2)
35
+ worksheet.write(0, 3, 3)
36
+ worksheet.write(0, 4, 4)
37
+ worksheet.write(0, 5, 5)
38
+ worksheet.write(0, 6, 6)
39
+ worksheet.write(0, 7, 7)
40
+ worksheet.write(0, 8, 8)
41
+
42
+ worksheet.write(1, 0, 'Length', format)
43
+ worksheet.write(1, 1, 25.4)
44
+ worksheet.write(1, 2, 25.4)
45
+ worksheet.write(1, 3, 24.8)
46
+ worksheet.write(1, 4, 25.0)
47
+ worksheet.write(1, 5, 25.3)
48
+ worksheet.write(1, 6, 24.9)
49
+ worksheet.write(1, 7, 25.2)
50
+ worksheet.write(1, 8, 24.8)
51
+
52
+ # Write some statistical functions
53
+ worksheet.write(4, 0, 'Count', format)
54
+ worksheet.write(4, 1, '=COUNT(B1:I1)')
55
+
56
+ worksheet.write(5, 0, 'Sum', format)
57
+ worksheet.write(5, 1, '=SUM(B2:I2)')
58
+
59
+ worksheet.write(6, 0, 'Average', format)
60
+ worksheet.write(6, 1, '=AVERAGE(B2:I2)')
61
+
62
+ worksheet.write(7, 0, 'Min', format)
63
+ worksheet.write(7, 1, '=MIN(B2:I2)')
64
+
65
+ worksheet.write(8, 0, 'Max', format)
66
+ worksheet.write(8, 1, '=MAX(B2:I2)')
67
+
68
+ worksheet.write(9, 0, 'Standard Deviation', format)
69
+ worksheet.write(9, 1, '=STDEV(B2:I2)')
70
+
71
+ worksheet.write(10, 0, 'Kurtosis', format)
72
+ worksheet.write(10, 1, '=KURT(B2:I2)')
73
+
74
+ workbook.close
75
+
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ ###############################################################################
4
+ #
5
+ # Example of formatting using the Spreadsheet::WriteExcel module
6
+ #
7
+ # This example shows how to use a conditional numerical format
8
+ # with colours to indicate if a share price has gone up or down.
9
+ #
10
+ # reverse('©'), March 2001, John McNamara, jmcnamara@cpan.org
11
+ #
12
+ # original written in Perl by John McNamara
13
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
14
+ #
15
+
16
+ require 'rubygems'
17
+ require 'WriteExcel'
18
+
19
+ # Create a new workbook and add a worksheet
20
+ workbook = Spreadsheet::WriteExcel.new("stocks.xls")
21
+ worksheet = workbook.add_worksheet
22
+
23
+ # Set the column width for columns 1, 2, 3 and 4
24
+ worksheet.set_column(0, 3, 15)
25
+
26
+
27
+ # Create a format for the column headings
28
+ header = workbook.add_format
29
+ header.set_bold
30
+ header.set_size(12)
31
+ header.set_color('blue')
32
+
33
+
34
+ # Create a format for the stock price
35
+ f_price = workbook.add_format
36
+ f_price.set_align('left')
37
+ f_price.set_num_format('$0.00')
38
+
39
+
40
+ # Create a format for the stock volume
41
+ f_volume = workbook.add_format
42
+ f_volume.set_align('left')
43
+ f_volume.set_num_format('#,##0')
44
+
45
+
46
+ # Create a format for the price change. This is an example of a conditional
47
+ # format. The number is formatted as a percentage. If it is positive it is
48
+ # formatted in green, if it is negative it is formatted in red and if it is
49
+ # zero it is formatted as the default font colour (in this case black).
50
+ # Note: the [Green] format produces an unappealing lime green. Try
51
+ # [Color 10] instead for a dark green.
52
+ #
53
+ f_change = workbook.add_format
54
+ f_change.set_align('left')
55
+ f_change.set_num_format('[Green]0.0%;[Red]-0.0%;0.0%')
56
+
57
+
58
+ # Write out the data
59
+ worksheet.write(0, 0, 'Company', header)
60
+ worksheet.write(0, 1, 'Price', header)
61
+ worksheet.write(0, 2, 'Volume', header)
62
+ worksheet.write(0, 3, 'Change', header)
63
+
64
+ worksheet.write(1, 0, 'Damage Inc.' )
65
+ worksheet.write(1, 1, 30.25, f_price) # $30.25
66
+ worksheet.write(1, 2, 1234567, f_volume) # 1,234,567
67
+ worksheet.write(1, 3, 0.085, f_change) # 8.5% in green
68
+
69
+ worksheet.write(2, 0, 'Dump Corp.' )
70
+ worksheet.write(2, 1, 1.56, f_price) # $1.56
71
+ worksheet.write(2, 2, 7564, f_volume) # 7,564
72
+ worksheet.write(2, 3, -0.015, f_change) # -1.5% in red
73
+
74
+ worksheet.write(3, 0, 'Rev Ltd.' )
75
+ worksheet.write(3, 1, 0.13, f_price) # $0.13
76
+ worksheet.write(3, 2, 321, f_volume) # 321
77
+ worksheet.write(3, 3, 0, f_change) # 0 in the font color (black)
78
+
79
+
80
+ workbook.close
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ #######################################################################
4
+ #
5
+ # Example of how to set Excel worksheet tab colours.
6
+ #
7
+ # reverse('©'), May 2006, John McNamara, jmcnamara@cpan.org
8
+ #
9
+ # original written in Perl by John McNamara
10
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
11
+ #
12
+
13
+ require 'rubygems'
14
+ require 'WriteExcel'
15
+
16
+ workbook = Spreadsheet::WriteExcel.new('tab_colors.xls')
17
+
18
+ worksheet1 = workbook.add_worksheet
19
+ worksheet2 = workbook.add_worksheet
20
+ worksheet3 = workbook.add_worksheet
21
+ worksheet4 = workbook.add_worksheet
22
+
23
+ # Worsheet1 will have the default tab colour.
24
+ worksheet2.set_tab_color('red')
25
+ worksheet3.set_tab_color('green')
26
+ worksheet4.set_tab_color(0x35) # Orange
27
+
28
+ workbook.close
29
+
30
+ workbook.close
@@ -0,0 +1,30 @@
1
+
2
+
3
+ require "rubygems"
4
+ require "date"
5
+ require "digest/md5"
6
+ require "nkf"
7
+ require "strscan"
8
+ require "racc/parser.rb"
9
+ require 'tempfile'
10
+ require 'stringio'
11
+ require "iconv"
12
+ bdir = "#{File.join(File.dirname(__FILE__), "WriteExcel")}"
13
+
14
+ autoload :Workbook, File.join(bdir.to_s, "workbook.rb")
15
+ autoload :BIFFWriter, File.join(bdir.to_s, "biffwriter.rb")
16
+ autoload :OLEWriter, File.join(bdir.to_s, "olewriter.rb")
17
+ autoload :ExcelFormulaParser, File.join(bdir.to_s, "excelformulaparser.rb")
18
+ autoload :Formula, File.join(bdir.to_s, "formula.rb")
19
+ autoload :Format , File.join(bdir.to_s, "format.rb")
20
+ autoload :Worksheet, File.join(bdir.to_s, "worksheet.rb")
21
+ require File.join(bdir.to_s, "properties.rb")
22
+ autoload :OLEStorageLite, File.join(bdir.to_s, "storage_lite.rb")
23
+
24
+ bdir = nil
25
+
26
+ class Spreadsheet
27
+ class WriteExcel < Workbook
28
+ VERSION = "0.2.0"
29
+ end
30
+ end
@@ -0,0 +1,259 @@
1
+ #
2
+ # BIFFwriter - An abstract base class for Excel workbooks and worksheets.
3
+ #
4
+ #
5
+ # Used in conjunction with Spreadsheet::WriteExcel
6
+ #
7
+ # Copyright 2000-2008, John McNamara, jmcnamara@cpan.org
8
+ #
9
+ # original written in Perl by John McNamara
10
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
11
+ #
12
+
13
+
14
+ #require 'tempfile'
15
+
16
+ class BIFFWriter
17
+ BIFF_Version = 0x0600
18
+ BigEndian = [1].pack("I") == [1].pack("N")
19
+
20
+ attr_reader :byte_order, :data, :datasize
21
+
22
+ ######################################################################
23
+ # The args here aren't used by BIFFWriter, but they are needed by its
24
+ # subclasses. I don't feel like creating multiple constructors.
25
+ ######################################################################
26
+
27
+ def initialize
28
+ set_byte_order
29
+ @data = ''
30
+ @datasize = 0
31
+ @limit = 8224
32
+ @ignore_continue = 0
33
+
34
+ # Open a tmp file to store the majority of the Worksheet data. If this fails,
35
+ # for example due to write permissions, store the data in memory. This can be
36
+ # slow for large files.
37
+ @filehandle = Tempfile.new('spreadsheetWriteExcel')
38
+ @filehandle.binmode
39
+
40
+ # failed. store temporary data in memory.
41
+ @using_tmpfile = @filehandle ? true : false
42
+
43
+ end
44
+
45
+ ###############################################################################
46
+ #
47
+ # _set_byte_order()
48
+ #
49
+ # Determine the byte order and store it as class data to avoid
50
+ # recalculating it for each call to new().
51
+ #
52
+ def set_byte_order
53
+ # Check if "pack" gives the required IEEE 64bit float
54
+ teststr = [1.2345].pack("d")
55
+ hexdata = [0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F]
56
+ number = hexdata.pack("C8")
57
+
58
+ if number == teststr
59
+ @byte_order = 0 # Little Endian
60
+ elsif number == teststr.reverse
61
+ @byte_order = 1 # Big Endian
62
+ else
63
+ # Give up. I'll fix this in a later version.
64
+ raise( "Required floating point format not supported " +
65
+ "on this platform. See the portability section " +
66
+ "of the documentation."
67
+ )
68
+ end
69
+ end
70
+
71
+ ###############################################################################
72
+ #
73
+ # _prepend($data)
74
+ #
75
+ # General storage function
76
+ #
77
+ def prepend(*args)
78
+ d = args.join
79
+ d = add_continue(d) if d.length > @limit
80
+
81
+ @datasize += d.length
82
+ @data = d + @data
83
+
84
+ #print "prepend\n"
85
+ #print d.unpack('C*').map! {|c| sprintf("%02X", c) }.join(' ') + "\n\n"
86
+ return d
87
+ end
88
+
89
+ ###############################################################################
90
+ #
91
+ # _append($data)
92
+ #
93
+ # General storage function
94
+ #
95
+ def append(*args)
96
+ d = args.join
97
+ # Add CONTINUE records if necessary
98
+ d = add_continue(d) if d.length > @limit
99
+ if @using_tmpfile
100
+ @filehandle.write d
101
+ @datasize += d.length
102
+ else
103
+ @datasize += d.length
104
+ @data = @data + d
105
+ end
106
+ #print "apend\n"
107
+ #print d.unpack('C*').map! {|c| sprintf("%02X", c) }.join(' ') + "\n\n"
108
+ return d
109
+ end
110
+
111
+ ###############################################################################
112
+ #
113
+ # get_data().
114
+ #
115
+ # Retrieves data from memory in one chunk, or from disk in $buffer
116
+ # sized chunks.
117
+ #
118
+ def get_data
119
+ buflen = 4096
120
+
121
+ # Return data stored in memory
122
+ unless @data.nil?
123
+ tmp = @data
124
+ @data = nil
125
+ if @using_tmpfile
126
+ @filehandle.open
127
+ @filehandle.binmode
128
+ end
129
+ return tmp
130
+ end
131
+
132
+ # Return data stored on disk
133
+ if @using_tmpfile
134
+ return @filehandle.read(buflen)
135
+ end
136
+
137
+ # No data to return
138
+ return nil
139
+ end
140
+
141
+ ###############################################################################
142
+ #
143
+ # _store_bof($type)
144
+ #
145
+ # $type = 0x0005, Workbook
146
+ # $type = 0x0010, Worksheet
147
+ #
148
+ # Writes Excel BOF record to indicate the beginning of a stream or
149
+ # sub-stream in the BIFF file.
150
+ #
151
+ def store_bof(type = 0x0005)
152
+ record = 0x0809 # Record identifier
153
+ length = 0x0010 # Number of bytes to follow
154
+
155
+ # According to the SDK $build and $year should be set to zero.
156
+ # However, this throws a warning in Excel 5. So, use these
157
+ # magic numbers.
158
+ build = 0x0DBB
159
+ year = 0x07CC
160
+
161
+ bfh = 0x00000041
162
+ sfo = 0x00000006
163
+
164
+ header = [record,length].pack("vv")
165
+ data = [BIFF_Version,type,build,year,bfh,sfo].pack("vvvvVV")
166
+
167
+ prepend(header, data)
168
+ end
169
+
170
+ ###############################################################################
171
+ #
172
+ # _store_eof()
173
+ #
174
+ # Writes Excel EOF record to indicate the end of a BIFF stream.
175
+ #
176
+ def store_eof
177
+ record = 0x000A
178
+ length = 0x0000
179
+ header = [record,length].pack("vv")
180
+
181
+ append(header)
182
+ end
183
+
184
+ ###############################################################################
185
+ #
186
+ # _add_continue()
187
+ #
188
+ # Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
189
+ # Excel 97 the limit is 8228 bytes. Records that are longer than these limits
190
+ # must be split up into CONTINUE blocks.
191
+ #
192
+ # This function take a long BIFF record and inserts CONTINUE records as
193
+ # necessary.
194
+ #
195
+ # Some records have their own specialised Continue blocks so there is also an
196
+ # option to bypass this function.
197
+ #
198
+ def add_continue(data)
199
+ record = 0x003C # Record identifier
200
+
201
+ # Skip this if another method handles the continue blocks.
202
+ return data if @ignore_continue != 0
203
+
204
+ # The first 2080/8224 bytes remain intact. However, we have to change
205
+ # the length field of the record.
206
+ #
207
+
208
+ # in perl
209
+ # $tmp = substr($data, 0, $limit, "");
210
+ if data.length > @limit
211
+ tmp = data[0, @limit]
212
+ data[0, @limit] = ''
213
+ else
214
+ tmp = data.dup
215
+ data = ''
216
+ end
217
+
218
+ tmp[2, 2] = [@limit-4].pack('v')
219
+
220
+ # Strip out chunks of 2080/8224 bytes +4 for the header.
221
+ while (data.length > @limit)
222
+ header = [record, @limit].pack("vv")
223
+ tmp = tmp + header + data[0, @limit]
224
+ data[0, @limit] = ''
225
+ end
226
+
227
+ # Mop up the last of the data
228
+ header = [record, data.length].pack("vv")
229
+ tmp = tmp + header + data
230
+
231
+ return tmp
232
+ end
233
+
234
+ ###############################################################################
235
+ #
236
+ # _add_mso_generic()
237
+ # my $type = $_[0];
238
+ # my $version = $_[1];
239
+ # my $instance = $_[2];
240
+ # my $data = $_[3];
241
+ #
242
+ # Create a mso structure that is part of an Escher drawing object. These are
243
+ # are used for images, comments and filters. This generic method is used by
244
+ # other methods to create specific mso records.
245
+ #
246
+ # Returns the packed record.
247
+ #
248
+ def add_mso_generic(type, version, instance, data, length = nil)
249
+ length = length.nil? ? data.length : length
250
+
251
+ # The header contains version and instance info packed into 2 bytes.
252
+ header = version | (instance << 4)
253
+
254
+ record = [header, type, length].pack('vvV') + data
255
+
256
+ return record
257
+ end
258
+
259
+ end