ricardoo27-writeexcel 0.6.12.1

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 (245) hide show
  1. data/.document +5 -0
  2. data/.gitattributes +1 -0
  3. data/README.rdoc +136 -0
  4. data/Rakefile +52 -0
  5. data/VERSION +1 -0
  6. data/charts/chartex.rb +316 -0
  7. data/charts/demo1.rb +46 -0
  8. data/charts/demo101.bin +0 -0
  9. data/charts/demo2.rb +65 -0
  10. data/charts/demo201.bin +0 -0
  11. data/charts/demo3.rb +117 -0
  12. data/charts/demo301.bin +0 -0
  13. data/charts/demo4.rb +119 -0
  14. data/charts/demo401.bin +0 -0
  15. data/charts/demo5.rb +48 -0
  16. data/charts/demo501.bin +0 -0
  17. data/examples/a_simple.rb +43 -0
  18. data/examples/autofilter.rb +265 -0
  19. data/examples/bigfile.rb +30 -0
  20. data/examples/chart_area.rb +121 -0
  21. data/examples/chart_bar.rb +120 -0
  22. data/examples/chart_column.rb +120 -0
  23. data/examples/chart_line.rb +120 -0
  24. data/examples/chart_pie.rb +108 -0
  25. data/examples/chart_scatter.rb +121 -0
  26. data/examples/chart_stock.rb +148 -0
  27. data/examples/chess.rb +142 -0
  28. data/examples/colors.rb +129 -0
  29. data/examples/comments1.rb +27 -0
  30. data/examples/comments2.rb +352 -0
  31. data/examples/copyformat.rb +52 -0
  32. data/examples/data_validate.rb +279 -0
  33. data/examples/date_time.rb +87 -0
  34. data/examples/defined_name.rb +32 -0
  35. data/examples/demo.rb +124 -0
  36. data/examples/diag_border.rb +36 -0
  37. data/examples/formats.rb +490 -0
  38. data/examples/formula_result.rb +30 -0
  39. data/examples/header.rb +137 -0
  40. data/examples/hide_sheet.rb +29 -0
  41. data/examples/hyperlink.rb +43 -0
  42. data/examples/images.rb +63 -0
  43. data/examples/indent.rb +31 -0
  44. data/examples/merge1.rb +40 -0
  45. data/examples/merge2.rb +45 -0
  46. data/examples/merge3.rb +66 -0
  47. data/examples/merge4.rb +83 -0
  48. data/examples/merge5.rb +80 -0
  49. data/examples/merge6.rb +67 -0
  50. data/examples/outline.rb +255 -0
  51. data/examples/outline_collapsed.rb +209 -0
  52. data/examples/panes.rb +113 -0
  53. data/examples/password_protection.rb +33 -0
  54. data/examples/properties.rb +34 -0
  55. data/examples/properties_jp.rb +33 -0
  56. data/examples/protection.rb +47 -0
  57. data/examples/regions.rb +53 -0
  58. data/examples/repeat.rb +43 -0
  59. data/examples/republic.png +0 -0
  60. data/examples/right_to_left.rb +27 -0
  61. data/examples/row_wrap.rb +53 -0
  62. data/examples/set_first_sheet.rb +14 -0
  63. data/examples/stats.rb +74 -0
  64. data/examples/stocks.rb +81 -0
  65. data/examples/store_formula.rb +15 -0
  66. data/examples/tab_colors.rb +31 -0
  67. data/examples/utf8.rb +15 -0
  68. data/examples/write_arrays.rb +83 -0
  69. data/html/en/doc_en.html +5946 -0
  70. data/html/images/a_simple.jpg +0 -0
  71. data/html/images/area1.jpg +0 -0
  72. data/html/images/bar1.jpg +0 -0
  73. data/html/images/chart_area.xls +0 -0
  74. data/html/images/column1.jpg +0 -0
  75. data/html/images/data_validation.jpg +0 -0
  76. data/html/images/line1.jpg +0 -0
  77. data/html/images/pie1.jpg +0 -0
  78. data/html/images/regions.jpg +0 -0
  79. data/html/images/scatter1.jpg +0 -0
  80. data/html/images/stats.jpg +0 -0
  81. data/html/images/stock1.jpg +0 -0
  82. data/html/images/stocks.jpg +0 -0
  83. data/html/index.html +16 -0
  84. data/html/style.css +433 -0
  85. data/lib/writeexcel.rb +1159 -0
  86. data/lib/writeexcel/biffwriter.rb +223 -0
  87. data/lib/writeexcel/caller_info.rb +12 -0
  88. data/lib/writeexcel/cell_range.rb +332 -0
  89. data/lib/writeexcel/chart.rb +1968 -0
  90. data/lib/writeexcel/charts/area.rb +154 -0
  91. data/lib/writeexcel/charts/bar.rb +177 -0
  92. data/lib/writeexcel/charts/column.rb +156 -0
  93. data/lib/writeexcel/charts/external.rb +66 -0
  94. data/lib/writeexcel/charts/line.rb +154 -0
  95. data/lib/writeexcel/charts/pie.rb +169 -0
  96. data/lib/writeexcel/charts/scatter.rb +192 -0
  97. data/lib/writeexcel/charts/stock.rb +213 -0
  98. data/lib/writeexcel/col_info.rb +87 -0
  99. data/lib/writeexcel/colors.rb +68 -0
  100. data/lib/writeexcel/comments.rb +460 -0
  101. data/lib/writeexcel/compatibility.rb +65 -0
  102. data/lib/writeexcel/convert_date_time.rb +117 -0
  103. data/lib/writeexcel/data_validations.rb +370 -0
  104. data/lib/writeexcel/debug_info.rb +41 -0
  105. data/lib/writeexcel/embedded_chart.rb +35 -0
  106. data/lib/writeexcel/excelformula.y +139 -0
  107. data/lib/writeexcel/excelformulaparser.rb +587 -0
  108. data/lib/writeexcel/format.rb +1575 -0
  109. data/lib/writeexcel/formula.rb +987 -0
  110. data/lib/writeexcel/helper.rb +78 -0
  111. data/lib/writeexcel/image.rb +218 -0
  112. data/lib/writeexcel/olewriter.rb +305 -0
  113. data/lib/writeexcel/outline.rb +24 -0
  114. data/lib/writeexcel/properties.rb +242 -0
  115. data/lib/writeexcel/shared_string_table.rb +153 -0
  116. data/lib/writeexcel/storage_lite.rb +984 -0
  117. data/lib/writeexcel/workbook.rb +2478 -0
  118. data/lib/writeexcel/worksheet.rb +6925 -0
  119. data/lib/writeexcel/worksheets.rb +25 -0
  120. data/lib/writeexcel/write_file.rb +63 -0
  121. data/test/excelfile/Chart1.xls +0 -0
  122. data/test/excelfile/Chart2.xls +0 -0
  123. data/test/excelfile/Chart3.xls +0 -0
  124. data/test/excelfile/Chart4.xls +0 -0
  125. data/test/excelfile/Chart5.xls +0 -0
  126. data/test/helper.rb +31 -0
  127. data/test/perl_output/Chart1.xls.data +0 -0
  128. data/test/perl_output/Chart2.xls.data +0 -0
  129. data/test/perl_output/Chart3.xls.data +0 -0
  130. data/test/perl_output/Chart4.xls.data +0 -0
  131. data/test/perl_output/Chart5.xls.data +0 -0
  132. data/test/perl_output/README +31 -0
  133. data/test/perl_output/a_simple.xls +0 -0
  134. data/test/perl_output/autofilter.xls +0 -0
  135. data/test/perl_output/biff_add_continue_testdata +0 -0
  136. data/test/perl_output/chart_area.xls +0 -0
  137. data/test/perl_output/chart_bar.xls +0 -0
  138. data/test/perl_output/chart_column.xls +0 -0
  139. data/test/perl_output/chart_line.xls +0 -0
  140. data/test/perl_output/chess.xls +0 -0
  141. data/test/perl_output/colors.xls +0 -0
  142. data/test/perl_output/comments0.xls +0 -0
  143. data/test/perl_output/comments1.xls +0 -0
  144. data/test/perl_output/comments2.xls +0 -0
  145. data/test/perl_output/data_validate.xls +0 -0
  146. data/test/perl_output/date_time.xls +0 -0
  147. data/test/perl_output/defined_name.xls +0 -0
  148. data/test/perl_output/demo.xls +0 -0
  149. data/test/perl_output/demo101.bin +0 -0
  150. data/test/perl_output/demo201.bin +0 -0
  151. data/test/perl_output/demo301.bin +0 -0
  152. data/test/perl_output/demo401.bin +0 -0
  153. data/test/perl_output/demo501.bin +0 -0
  154. data/test/perl_output/diag_border.xls +0 -0
  155. data/test/perl_output/f_font_biff +0 -0
  156. data/test/perl_output/f_font_key +1 -0
  157. data/test/perl_output/f_xf_biff +0 -0
  158. data/test/perl_output/file_font_biff +0 -0
  159. data/test/perl_output/file_font_key +1 -0
  160. data/test/perl_output/file_xf_biff +0 -0
  161. data/test/perl_output/formula_result.xls +0 -0
  162. data/test/perl_output/headers.xls +0 -0
  163. data/test/perl_output/hidden.xls +0 -0
  164. data/test/perl_output/hide_zero.xls +0 -0
  165. data/test/perl_output/hyperlink.xls +0 -0
  166. data/test/perl_output/images.xls +0 -0
  167. data/test/perl_output/indent.xls +0 -0
  168. data/test/perl_output/merge1.xls +0 -0
  169. data/test/perl_output/merge2.xls +0 -0
  170. data/test/perl_output/merge3.xls +0 -0
  171. data/test/perl_output/merge4.xls +0 -0
  172. data/test/perl_output/merge5.xls +0 -0
  173. data/test/perl_output/merge6.xls +0 -0
  174. data/test/perl_output/ole_write_header +0 -0
  175. data/test/perl_output/outline.xls +0 -0
  176. data/test/perl_output/outline_collapsed.xls +0 -0
  177. data/test/perl_output/panes.xls +0 -0
  178. data/test/perl_output/password_protection.xls +0 -0
  179. data/test/perl_output/protection.xls +0 -0
  180. data/test/perl_output/regions.xls +0 -0
  181. data/test/perl_output/right_to_left.xls +0 -0
  182. data/test/perl_output/set_first_sheet.xls +0 -0
  183. data/test/perl_output/stats.xls +0 -0
  184. data/test/perl_output/stocks.xls +0 -0
  185. data/test/perl_output/store_formula.xls +0 -0
  186. data/test/perl_output/tab_colors.xls +0 -0
  187. data/test/perl_output/unicode_cyrillic.xls +0 -0
  188. data/test/perl_output/utf8.xls +0 -0
  189. data/test/perl_output/workbook1.xls +0 -0
  190. data/test/perl_output/workbook2.xls +0 -0
  191. data/test/perl_output/ws_colinfo +1 -0
  192. data/test/perl_output/ws_store_colinfo +0 -0
  193. data/test/perl_output/ws_store_dimensions +0 -0
  194. data/test/perl_output/ws_store_filtermode +0 -0
  195. data/test/perl_output/ws_store_filtermode_off +0 -0
  196. data/test/perl_output/ws_store_filtermode_on +0 -0
  197. data/test/perl_output/ws_store_selection +0 -0
  198. data/test/perl_output/ws_store_window2 +1 -0
  199. data/test/republic.png +0 -0
  200. data/test/test_00_IEEE_double.rb +13 -0
  201. data/test/test_01_add_worksheet.rb +10 -0
  202. data/test/test_02_merge_formats.rb +49 -0
  203. data/test/test_04_dimensions.rb +388 -0
  204. data/test/test_05_rows.rb +175 -0
  205. data/test/test_06_extsst.rb +74 -0
  206. data/test/test_11_date_time.rb +475 -0
  207. data/test/test_12_date_only.rb +525 -0
  208. data/test/test_13_date_seconds.rb +477 -0
  209. data/test/test_21_escher.rb +624 -0
  210. data/test/test_22_mso_drawing_group.rb +741 -0
  211. data/test/test_23_note.rb +57 -0
  212. data/test/test_24_txo.rb +74 -0
  213. data/test/test_25_position_object.rb +80 -0
  214. data/test/test_26_autofilter.rb +309 -0
  215. data/test/test_27_autofilter.rb +126 -0
  216. data/test/test_28_autofilter.rb +156 -0
  217. data/test/test_29_process_jpg.rb +670 -0
  218. data/test/test_30_validation_dval.rb +74 -0
  219. data/test/test_31_validation_dv_strings.rb +123 -0
  220. data/test/test_32_validation_dv_formula.rb +203 -0
  221. data/test/test_40_property_types.rb +188 -0
  222. data/test/test_41_properties.rb +235 -0
  223. data/test/test_42_set_properties.rb +434 -0
  224. data/test/test_50_name_stored.rb +295 -0
  225. data/test/test_51_name_print_area.rb +353 -0
  226. data/test/test_52_name_print_titles.rb +450 -0
  227. data/test/test_53_autofilter.rb +199 -0
  228. data/test/test_60_chart_generic.rb +574 -0
  229. data/test/test_61_chart_subclasses.rb +84 -0
  230. data/test/test_62_chart_formats.rb +268 -0
  231. data/test/test_63_chart_area_formats.rb +645 -0
  232. data/test/test_biff.rb +71 -0
  233. data/test/test_big_workbook.rb +17 -0
  234. data/test/test_compatibility.rb +12 -0
  235. data/test/test_example_match.rb +3246 -0
  236. data/test/test_format.rb +1189 -0
  237. data/test/test_formula.rb +61 -0
  238. data/test/test_ole.rb +102 -0
  239. data/test/test_storage_lite.rb +116 -0
  240. data/test/test_workbook.rb +146 -0
  241. data/test/test_worksheet.rb +106 -0
  242. data/utils/add_magic_comment.rb +80 -0
  243. data/writeexcel.gemspec +278 -0
  244. data/writeexcel.rdoc +1425 -0
  245. metadata +292 -0
@@ -0,0 +1,78 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # helper.rb
4
+ #
5
+ # Convert to US_ASCII encoding if ascii characters only.
6
+ def convert_to_ascii_if_ascii(str)
7
+ return nil if str.nil?
8
+ ruby_18 do
9
+ unless str =~ /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]\{\}^` ~\0\n]/
10
+ str = String.new(str)
11
+ end
12
+ end ||
13
+ ruby_19 do
14
+ if str.ascii_only?
15
+ str = [str].pack('a*')
16
+ end
17
+ end
18
+ str
19
+ end
20
+ private :convert_to_ascii_if_ascii
21
+
22
+ def utf16be_to_16le(utf16be)
23
+ utf16be.unpack('n*').pack('v*')
24
+ end
25
+
26
+ def utf8_to_16be(utf8)
27
+ ruby_18 { NKF.nkf('-w16B0 -m0 -W', utf8) } ||
28
+ ruby_19 do
29
+ utf16be = NKF.nkf('-w16B0 -m0 -W', utf8)
30
+ utf16be.force_encoding('UTF-16BE')
31
+ end
32
+ end
33
+ private :utf8_to_16be
34
+
35
+ def utf8_to_16le(utf8)
36
+ ruby_18 { NKF.nkf('-w16L0 -m0 -W', utf8) } ||
37
+ ruby_19 do
38
+ utf16le = NKF.nkf('-w16L0 -m0 -W', utf8)
39
+ utf16le.force_encoding('UTF-16LE')
40
+ end
41
+ end
42
+ private :utf8_to_16le
43
+
44
+ def ascii_to_16be(ascii)
45
+ ascii.unpack("C*").pack("n*")
46
+ ruby_19 { ascii.force_encoding('UTF-16BE') }
47
+ ascii
48
+ end
49
+ private :ascii_to_16be
50
+
51
+ def store_simple(record, length, *args)
52
+ header = [record, length].pack('vv')
53
+ data = args.collect { |arg| [arg].pack('v') }.join('')
54
+
55
+ append(header, data)
56
+ end
57
+ private :store_simple
58
+
59
+ # Convert base26 column string to a number.
60
+ # All your Base are belong to us.
61
+ def chars_to_col(chars)
62
+ expn = 0
63
+ col = 0
64
+ while (!chars.empty?)
65
+ char = chars.pop # LS char first
66
+ col += (char.ord - "A".ord + 1) * (26 ** expn)
67
+ expn += 1
68
+ end
69
+ col
70
+ end
71
+ private :chars_to_col
72
+
73
+ NonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]\{\}^` ~\0\n]/
74
+
75
+ def is_utf8?(str)
76
+ ruby_18 { str =~ NonAscii } ||
77
+ ruby_19 { str.encoding == Encoding::UTF_8 }
78
+ end
@@ -0,0 +1,218 @@
1
+ # -*- coding:utf-8 -*-
2
+ require 'digest/md5'
3
+
4
+ module Writeexcel
5
+ class Image
6
+ attr_reader :row, :col, :filename, :x_offset, :y_offset, :scale_x, :scale_y
7
+ attr_reader :data, :size, :checksum1, :checksum2
8
+ attr_accessor :id, :type, :width, :height, :ref_count
9
+
10
+ def initialize(worksheet, row, col, filename, x_offset = 0, y_offset = 0, scale_x = 1, scale_y = 1)
11
+ @worksheet = worksheet
12
+ @row = row
13
+ @col = col
14
+ @filename = filename
15
+ @x_offset = x_offset
16
+ @y_offset = y_offset
17
+ @scale_x = scale_x
18
+ @scale_y = scale_y
19
+ get_checksum_method
20
+ end
21
+
22
+ def import
23
+ File.open(@filename, "rb") do |fh|
24
+ raise "Couldn't import #{@filename}: #{$!}" unless fh
25
+ @data = fh.read
26
+ end
27
+ @size = data.bytesize
28
+ @checksum1 = image_checksum(@data)
29
+ @checksum2 = @checksum1
30
+ process
31
+ end
32
+
33
+ def store_image_record(i, num_images, num_charts, num_filters, num_comments, spid)
34
+ image_width = width
35
+ image_height = height
36
+
37
+ image_width = width * scale_x unless scale_x == 0
38
+ image_height = height * scale_y unless scale_y == 0
39
+
40
+ # Calculate the positions of image object.
41
+ vertices = @worksheet.position_object(col, row, x_offset, y_offset, image_width, image_height)
42
+
43
+ if (i == 0)
44
+ data = images_parent_msodrawing_record(num_images, num_charts, num_filters, num_comments, spid, id, vertices)
45
+ else
46
+ data = images_child_msodrawing_record(spid, id, vertices)
47
+ end
48
+ record = 0x00EC # Record identifier
49
+ length = 0x0000 # Bytes to follow
50
+
51
+ length = data.bytesize
52
+ header = [record, length].pack("vv")
53
+
54
+ append(header, data)
55
+ end
56
+
57
+ private
58
+
59
+ # Process the image and extract dimensions.
60
+ def process
61
+ case filetype
62
+ when 'PNG'
63
+ process_png(@data)
64
+ when 'JPG'
65
+ process_jpg(@data)
66
+ when 'BMP'
67
+ process_bmp(@data)
68
+ # The 14 byte header of the BMP is stripped off.
69
+ @data[0, 13] = ''
70
+ # A checksum of the new image data is also required.
71
+ @checksum2 = image_checksum(@data, @id, @id)
72
+ # Adjust size -14 (header) + 16 (extra checksum).
73
+ @size += 2
74
+ end
75
+ end
76
+
77
+ def filetype
78
+ return 'PNG' if @data.unpack('x A3')[0] == 'PNG'
79
+ return 'BMP' if @data.unpack('A2')[0] == 'BM'
80
+ if data.unpack('n')[0] == 0xFFD8
81
+ return 'JPG' if @data.unpack('x6 A4')[0] == 'JFIF' || @data.unpack('x6 A4')[0] == 'Exif'
82
+ else
83
+ raise "Unsupported image format for file: #{@filename}\n"
84
+ end
85
+ end
86
+
87
+ # Extract width and height information from a PNG file.
88
+ def process_png(data)
89
+ @type = 6 # Excel Blip type (MSOBLIPTYPE).
90
+ @width = data[16, 4].unpack("N")[0]
91
+ @height = data[20, 4].unpack("N")[0]
92
+ end
93
+
94
+ # Extract width and height information from a BMP file.
95
+ def process_bmp(data) #:nodoc:
96
+ @type = 7 # Excel Blip type (MSOBLIPTYPE).
97
+ # Read the bitmap width and height. Verify the sizes.
98
+ @width, @height = data.unpack("x18 V2")
99
+ check_verify(data)
100
+ end
101
+
102
+ def check_verify(data)
103
+ # Check that the file is big enough to be a bitmap.
104
+ raise "#{@filename} doesn't contain enough data." if data.bytesize <= 0x36
105
+ raise "#{@filename}: largest image width #{width} supported is 65k." if @width > 0xFFFF
106
+ raise "#{@filename}: largest image height supported is 65k." if @height > 0xFFFF
107
+
108
+ # Read the bitmap planes and bpp data. Verify them.
109
+ planes, bitcount = data.unpack("x26 v2")
110
+ raise "#{@filename} isn't a 24bit true color bitmap." unless bitcount == 24
111
+ raise "#{@filename}: only 1 plane supported in bitmap image." unless planes == 1
112
+
113
+ # Read the bitmap compression. Verify compression.
114
+ compression = data.unpack("x30 V")
115
+ raise "#{@filename}: compression not supported in bitmap image." unless compression == 0
116
+ end
117
+
118
+ # Extract width and height information from a JPEG file.
119
+ def process_jpg(data)
120
+ @type = 5 # Excel Blip type (MSOBLIPTYPE).
121
+
122
+ offset = 2
123
+ data_length = data.bytesize
124
+
125
+ # Search through the image data to find the 0xFFC0 marker. The height and
126
+ # width are contained in the data for that sub element.
127
+ while offset < data_length
128
+ marker = data[offset, 2].unpack("n")
129
+ marker = marker[0]
130
+ length = data[offset+2, 2].unpack("n")
131
+ length = length[0]
132
+
133
+ if marker == 0xFFC0 || marker == 0xFFC2
134
+ height = data[offset+5, 2].unpack("n")
135
+ @height = height[0]
136
+ width = data[offset+7, 2].unpack("n")
137
+ @width = width[0]
138
+ break
139
+ end
140
+
141
+ offset += length + 2
142
+ break if marker == 0xFFDA
143
+ end
144
+
145
+ raise "#{@filename}: no size data found in jpeg image.\n" unless @height
146
+ end
147
+
148
+ #
149
+ # Generate a checksum for the image using whichever module is available. The
150
+ # available modules are checked in get_checksum_method(). Excel uses an MD4
151
+ # checksum but any other will do. In the event of no checksum module being
152
+ # available we simulate a checksum using the image index.
153
+ #
154
+ # index1 and index2 is not used.
155
+ #
156
+ def image_checksum(data, index1 = 0, index2 = 0) #:nodoc:
157
+ case @checksum_method
158
+ when 3
159
+ Digest::MD5.hexdigest(data)
160
+ when 1
161
+ # Digest::MD4
162
+ # return Digest::MD4::md4_hex($data);
163
+ when 2
164
+ # Digest::Perl::MD4
165
+ # return Digest::Perl::MD4::md4_hex($data);
166
+ else
167
+ # Default
168
+ # return sprintf('%016X%016X', index2, index1)
169
+ end
170
+ end
171
+
172
+ #
173
+ # Check for modules available to calculate image checksum. Excel uses MD4 but
174
+ # MD5 will also work.
175
+ #
176
+ # ------- cxn03651 add -------
177
+ # md5 can use in ruby. so, @checksum_method is always 3.
178
+
179
+ def get_checksum_method #:nodoc:
180
+ @checksum_method = 3
181
+ end
182
+
183
+ def images_parent_msodrawing_record(num_images, charts_size, num_filters, num_comments, spid, image_id, vertices)
184
+ dg_length = 156 + 84*(num_images - 1)
185
+ spgr_length = 132 + 84*(num_images - 1)
186
+
187
+ dg_length += 120 * charts_size
188
+ spgr_length += 120 * charts_size
189
+
190
+ dg_length += 96 * num_filters
191
+ spgr_length += 96 * num_filters
192
+
193
+ dg_length += 128 * num_comments
194
+ spgr_length += 128 * num_comments
195
+
196
+ data = @worksheet.store_parent_mso_record(dg_length, spgr_length, spid)
197
+ spid += 1
198
+ data += @worksheet.store_mso_sp_container(76)
199
+ data += @worksheet.store_mso_sp(75, spid, 0x0A00)
200
+ spid += 1
201
+ data += @worksheet.store_mso_opt_image(image_id)
202
+ data += @worksheet.store_mso_client_anchor(2, *vertices)
203
+ data += @worksheet.store_mso_client_data
204
+ end
205
+
206
+ def images_child_msodrawing_record(spid, image_id, vertices)
207
+ data = @worksheet.store_mso_sp_container(76) + @worksheet.store_mso_sp(75, spid, 0x0A00)
208
+ spid = spid + 1
209
+ data += @worksheet.store_mso_opt_image(image_id) +
210
+ @worksheet.store_mso_client_anchor(2, *vertices) +
211
+ @worksheet.store_mso_client_data
212
+ end
213
+
214
+ def append(*args)
215
+ @worksheet.append(*args)
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,305 @@
1
+ # -*- coding: utf-8 -*-
2
+ ###############################################################################
3
+ #
4
+ # BIFFwriter - An abstract base class for Excel workbooks and worksheets.
5
+ #
6
+ #
7
+ # Used in conjunction with WriteExcel
8
+ #
9
+ # Copyright 2000-2010, 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
+ class MaxSizeError < StandardError; end #:nodoc:
15
+
16
+ class OLEWriter #:nodoc:
17
+
18
+ # Not meant for public consumption
19
+ MaxSize = 7087104 # Use WriteExcel::Big to exceed this
20
+ BlockSize = 4096
21
+ BlockDiv = 512
22
+ ListBlocks = 127
23
+
24
+ attr_reader :biff_size, :book_size, :big_blocks, :list_blocks
25
+ attr_reader :root_start, :size_allowed
26
+ attr_accessor :biff_only, :internal_fh
27
+
28
+ # Accept an IO or IO-like object or a filename (as a String)
29
+ def initialize(arg)
30
+ if arg.respond_to?(:to_str)
31
+ @io = File.open(arg, "w")
32
+ else
33
+ @io = arg
34
+ end
35
+ @io.binmode if @io.respond_to?(:binmode)
36
+
37
+ @filehandle = ""
38
+ @fileclosed = false
39
+ @internal_fh = 0
40
+ @biff_only = 0
41
+ @size_allowed = true
42
+ @biff_size = 0
43
+ @book_size = 0
44
+ @big_blocks = 0
45
+ @list_blocks = 0
46
+ @root_start = 0
47
+ @block_count = 4
48
+ end
49
+
50
+ # Imitate IO.open behavior
51
+
52
+ ###############################################################################
53
+ #
54
+ # _initialize()
55
+ #
56
+ # Create a new filehandle or use the provided filehandle.
57
+ #
58
+ def _initialize
59
+ olefile = @olefilename
60
+
61
+ # If the filename is a reference it is assumed that it is a valid
62
+ # filehandle, if not we create a filehandle.
63
+ #
64
+
65
+ # Create a new file, open for writing
66
+ fh = open(olefile, "wb")
67
+
68
+ # Workbook.pm also checks this but something may have happened since
69
+ # then.
70
+ raise "Can't open olefile. It may be in use or protected.\n" unless fh
71
+
72
+ @internal_fh = 1
73
+
74
+ # Store filehandle
75
+ @filehandle = fh
76
+ end
77
+
78
+ def self.open(arg)
79
+ if block_given?
80
+ ole = self.new(arg)
81
+ result = yield(ole)
82
+ ole.close
83
+ result
84
+ else
85
+ self.new(arg)
86
+ end
87
+ end
88
+
89
+ ###############################################################################
90
+ #
91
+ # write($data)
92
+ #
93
+ # Write BIFF data to OLE file.
94
+ #
95
+ def write(data)
96
+ @io.write(data)
97
+ end
98
+
99
+ ###############################################################################
100
+ #
101
+ # set_size(biffsize)
102
+ #
103
+ # Set the size of the data to be written to the OLE stream
104
+ #
105
+ # $big_blocks = (109 depot block x (128 -1 marker word)
106
+ # - (1 x end words)) = 13842
107
+ # $maxsize = $big_blocks * 512 bytes = 7087104
108
+ #
109
+ def set_size(size = BlockSize)
110
+ if size > MaxSize
111
+ return @size_allowed = false
112
+ end
113
+
114
+ @biff_size = size
115
+ @book_size = [size, BlockSize].max
116
+ @size_allowed = true
117
+ end
118
+
119
+ ###############################################################################
120
+ #
121
+ # _calculate_sizes()
122
+ #
123
+ # Calculate various sizes needed for the OLE stream
124
+ #
125
+ def calculate_sizes
126
+ @big_blocks = (@book_size.to_f/BlockDiv.to_f).ceil
127
+ @list_blocks = (@big_blocks / ListBlocks) + 1
128
+ @root_start = @big_blocks
129
+ end
130
+
131
+ ###############################################################################
132
+ #
133
+ # close()
134
+ #
135
+ # Write root entry, big block list and close the filehandle.
136
+ # This routine is used to explicitly close the open filehandle without
137
+ # having to wait for DESTROY.
138
+ #
139
+ def close
140
+ if @size_allowed == true
141
+ write_padding if @biff_only == 0
142
+ write_property_storage if @biff_only == 0
143
+ write_big_block_depot if @biff_only == 0
144
+ end
145
+ @io.close
146
+ end
147
+
148
+ ###############################################################################
149
+ #
150
+ # write_header()
151
+ #
152
+ # Write OLE header block.
153
+ #
154
+ def write_header
155
+ return if @biff_only == 1
156
+ calculate_sizes
157
+ root_start = @root_start
158
+ num_lists = @list_blocks
159
+
160
+ id = [0xD0CF11E0, 0xA1B11AE1].pack("NN")
161
+ unknown1 = [0x00, 0x00, 0x00, 0x00].pack("VVVV")
162
+ unknown2 = [0x3E, 0x03].pack("vv")
163
+ unknown3 = [-2].pack("v")
164
+ unknown4 = [0x09].pack("v")
165
+ unknown5 = [0x06, 0x00, 0x00].pack("VVV")
166
+ num_bbd_blocks = [num_lists].pack("V")
167
+ root_startblock = [root_start].pack("V")
168
+ unknown6 = [0x00, 0x1000].pack("VV")
169
+ sbd_startblock = [-2].pack("V")
170
+ unknown7 = [0x00, -2 ,0x00].pack("VVV")
171
+
172
+ write(id)
173
+ write(unknown1)
174
+ write(unknown2)
175
+ write(unknown3)
176
+ write(unknown4)
177
+ write(unknown5)
178
+ write(num_bbd_blocks)
179
+ write(root_startblock)
180
+ write(unknown6)
181
+ write(sbd_startblock)
182
+ write(unknown7)
183
+
184
+ unused = [-1].pack("V")
185
+
186
+ 1.upto(num_lists){
187
+ root_start += 1
188
+ write([root_start].pack("V"))
189
+ }
190
+
191
+ num_lists.upto(108){
192
+ write(unused)
193
+ }
194
+ end
195
+
196
+ ###############################################################################
197
+ #
198
+ # _write_big_block_depot()
199
+ #
200
+ # Write big block depot.
201
+ #
202
+ def write_big_block_depot
203
+ num_blocks = @big_blocks
204
+ num_lists = @list_blocks
205
+ total_blocks = num_lists * 128
206
+ used_blocks = num_blocks + num_lists + 2
207
+
208
+ marker = [-3].pack("V")
209
+ end_of_chain = [-2].pack("V")
210
+ unused = [-1].pack("V")
211
+
212
+ 1.upto(num_blocks-1){|n|
213
+ write([n].pack("V"))
214
+ }
215
+
216
+ write end_of_chain
217
+ write end_of_chain
218
+
219
+ 1.upto(num_lists){ write(marker) }
220
+
221
+ used_blocks.upto(total_blocks){ write(unused) }
222
+
223
+ end
224
+
225
+ ###############################################################################
226
+ #
227
+ # _write_property_storage()
228
+ #
229
+ # Write property storage. TODO: add summary sheets
230
+ #
231
+ def write_property_storage
232
+
233
+ ######### name type dir start size
234
+ write_pps('Root Entry', 0x05, 1, -2, 0x00)
235
+ write_pps('Workbook', 0x02, -1, 0x00, @book_size)
236
+ write_pps("", 0x00, -1, 0x00, 0x0000)
237
+ write_pps("", 0x00, -1, 0x00, 0x0000)
238
+ end
239
+
240
+ ###############################################################################
241
+ #
242
+ # _write_pps()
243
+ #
244
+ # Write property sheet in property storage
245
+ #
246
+ def write_pps(name, type, dir, start, size)
247
+ length = 0
248
+ ord_name = []
249
+ unless name.empty?
250
+ name = name + "\0"
251
+ ord_name = name.unpack("c*")
252
+ length = name.bytesize * 2
253
+ end
254
+
255
+ rawname = ord_name.pack("v*")
256
+ zero = [0].pack("C")
257
+
258
+ pps_sizeofname = [length].pack("v") #0x40
259
+ pps_type = [type].pack("v") #0x42
260
+ pps_prev = [-1].pack("V") #0x44
261
+ pps_next = [-1].pack("V") #0x48
262
+ pps_dir = [dir].pack("V") #0x4c
263
+
264
+ unknown = [0].pack("V")
265
+
266
+ pps_ts1s = [0].pack("V") #0x64
267
+ pps_ts1d = [0].pack("V") #0x68
268
+ pps_ts2s = [0].pack("V") #0x6c
269
+ pps_ts2d = [0].pack("V") #0x70
270
+ pps_sb = [start].pack("V") #0x74
271
+ pps_size = [size].pack("V") #0x78
272
+
273
+ write(rawname)
274
+ write(zero * (64 - length)) if 64 - length >= 1
275
+ write(pps_sizeofname)
276
+ write(pps_type)
277
+ write(pps_prev)
278
+ write(pps_next)
279
+ write(pps_dir)
280
+ write(unknown * 5)
281
+ write(pps_ts1s)
282
+ write(pps_ts1d)
283
+ write(pps_ts2s)
284
+ write(pps_ts2d)
285
+ write(pps_sb)
286
+ write(pps_size)
287
+ write(unknown)
288
+ end
289
+
290
+ ###############################################################################
291
+ #
292
+ # _write_padding()
293
+ #
294
+ # Pad the end of the file
295
+ #
296
+ def write_padding
297
+ min_size = 512
298
+ min_size = BlockSize if @biff_size < BlockSize
299
+
300
+ if @biff_size % min_size != 0
301
+ padding = min_size - (@biff_size % min_size)
302
+ write("\0" * padding)
303
+ end
304
+ end
305
+ end