writeexcel 0.1.0 → 0.3.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 (143) hide show
  1. data/README +26 -31
  2. data/examples/a_simple.rb +42 -42
  3. data/examples/{autofilters.rb → autofilter.rb} +264 -266
  4. data/examples/bigfile.rb +29 -0
  5. data/examples/chart_area.rb +120 -0
  6. data/examples/chart_bar.rb +119 -0
  7. data/examples/chart_column.rb +119 -0
  8. data/examples/chart_line.rb +119 -0
  9. data/examples/chart_pie.rb +107 -0
  10. data/examples/chart_scatter.rb +120 -0
  11. data/examples/chart_stock.rb +147 -0
  12. data/examples/copyformat.rb +51 -51
  13. data/examples/data_validate.rb +278 -278
  14. data/examples/date_time.rb +86 -86
  15. data/examples/defined_name.rb +31 -0
  16. data/examples/demo.rb +120 -118
  17. data/examples/diag_border.rb +35 -35
  18. data/examples/formats.rb +489 -489
  19. data/examples/header.rb +136 -136
  20. data/examples/hidden.rb +28 -28
  21. data/examples/hyperlink.rb +42 -42
  22. data/examples/images.rb +52 -52
  23. data/examples/merge1.rb +39 -39
  24. data/examples/merge2.rb +44 -44
  25. data/examples/merge3.rb +65 -65
  26. data/examples/merge4.rb +82 -82
  27. data/examples/merge5.rb +79 -79
  28. data/examples/properties.rb +33 -0
  29. data/examples/properties_jp.rb +32 -0
  30. data/examples/protection.rb +46 -46
  31. data/examples/regions.rb +52 -52
  32. data/examples/repeat.rb +42 -42
  33. data/examples/stats.rb +75 -75
  34. data/examples/stocks.rb +80 -80
  35. data/examples/tab_colors.rb +30 -30
  36. data/examples/write_arrays.rb +82 -0
  37. data/lib/writeexcel.rb +1134 -18
  38. data/lib/writeexcel/biffwriter.rb +273 -260
  39. data/lib/writeexcel/chart.rb +2306 -217
  40. data/lib/writeexcel/charts/area.rb +152 -0
  41. data/lib/writeexcel/charts/bar.rb +177 -0
  42. data/lib/writeexcel/charts/column.rb +156 -0
  43. data/lib/writeexcel/charts/external.rb +61 -0
  44. data/lib/writeexcel/charts/line.rb +152 -0
  45. data/lib/writeexcel/charts/pie.rb +169 -0
  46. data/lib/writeexcel/charts/scatter.rb +192 -0
  47. data/lib/writeexcel/charts/stock.rb +211 -0
  48. data/lib/writeexcel/excelformulaparser.rb +208 -195
  49. data/lib/writeexcel/format.rb +1697 -1108
  50. data/lib/writeexcel/formula.rb +1050 -986
  51. data/lib/writeexcel/olewriter.rb +322 -322
  52. data/lib/writeexcel/properties.rb +251 -250
  53. data/lib/writeexcel/storage_lite.rb +968 -0
  54. data/lib/writeexcel/workbook.rb +3294 -2630
  55. data/lib/writeexcel/worksheet.rb +9012 -6377
  56. data/test/excelfile/Chart1.xls +0 -0
  57. data/test/excelfile/Chart2.xls +0 -0
  58. data/test/excelfile/Chart3.xls +0 -0
  59. data/test/excelfile/Chart4.xls +0 -0
  60. data/test/excelfile/Chart5.xls +0 -0
  61. data/test/perl_output/Chart1.xls.data +0 -0
  62. data/test/perl_output/Chart2.xls.data +0 -0
  63. data/test/perl_output/Chart3.xls.data +0 -0
  64. data/test/perl_output/Chart4.xls.data +0 -0
  65. data/test/perl_output/Chart5.xls.data +0 -0
  66. data/test/perl_output/a_simple.xls +0 -0
  67. data/test/perl_output/autofilter.xls +0 -0
  68. data/test/perl_output/chart_area.xls +0 -0
  69. data/test/perl_output/chart_bar.xls +0 -0
  70. data/test/perl_output/chart_column.xls +0 -0
  71. data/test/perl_output/chart_line.xls +0 -0
  72. data/test/perl_output/data_validate.xls +0 -0
  73. data/test/perl_output/date_time.xls +0 -0
  74. data/test/perl_output/demo.xls +0 -0
  75. data/test/perl_output/demo101.bin +0 -0
  76. data/test/perl_output/demo201.bin +0 -0
  77. data/test/perl_output/demo301.bin +0 -0
  78. data/test/perl_output/demo401.bin +0 -0
  79. data/test/perl_output/demo501.bin +0 -0
  80. data/test/perl_output/diag_border.xls +0 -0
  81. data/test/perl_output/headers.xls +0 -0
  82. data/test/perl_output/hyperlink.xls +0 -0
  83. data/test/perl_output/images.xls +0 -0
  84. data/test/perl_output/merge1.xls +0 -0
  85. data/test/perl_output/merge2.xls +0 -0
  86. data/test/perl_output/merge3.xls +0 -0
  87. data/test/perl_output/merge4.xls +0 -0
  88. data/test/perl_output/merge5.xls +0 -0
  89. data/test/perl_output/protection.xls +0 -0
  90. data/test/perl_output/regions.xls +0 -0
  91. data/test/perl_output/stats.xls +0 -0
  92. data/test/perl_output/stocks.xls +0 -0
  93. data/test/perl_output/tab_colors.xls +0 -0
  94. data/test/perl_output/unicode_cyrillic.xls +0 -0
  95. data/test/perl_output/workbook1.xls +0 -0
  96. data/test/perl_output/workbook2.xls +0 -0
  97. data/test/tc_all.rb +32 -31
  98. data/test/tc_biff.rb +104 -104
  99. data/test/tc_chart.rb +22 -22
  100. data/test/tc_example_match.rb +1944 -1280
  101. data/test/tc_format.rb +1254 -1267
  102. data/test/tc_formula.rb +63 -63
  103. data/test/tc_ole.rb +110 -110
  104. data/test/tc_storage_lite.rb +149 -0
  105. data/test/tc_workbook.rb +140 -115
  106. data/test/tc_worksheet.rb +115 -115
  107. data/test/test_00_IEEE_double.rb +14 -14
  108. data/test/test_01_add_worksheet.rb +12 -12
  109. data/test/test_02_merge_formats.rb +58 -58
  110. data/test/test_04_dimensions.rb +397 -397
  111. data/test/test_05_rows.rb +182 -182
  112. data/test/test_06_extsst.rb +80 -80
  113. data/test/test_11_date_time.rb +484 -484
  114. data/test/test_12_date_only.rb +506 -506
  115. data/test/test_13_date_seconds.rb +486 -486
  116. data/test/test_21_escher.rb +642 -629
  117. data/test/test_22_mso_drawing_group.rb +750 -739
  118. data/test/test_23_note.rb +78 -78
  119. data/test/test_24_txo.rb +80 -80
  120. data/test/test_25_position_object.rb +82 -0
  121. data/test/test_26_autofilter.rb +327 -327
  122. data/test/test_27_autofilter.rb +144 -144
  123. data/test/test_28_autofilter.rb +174 -174
  124. data/test/test_29_process_jpg.rb +681 -131
  125. data/test/test_30_validation_dval.rb +82 -82
  126. data/test/test_31_validation_dv_strings.rb +131 -131
  127. data/test/test_32_validation_dv_formula.rb +211 -211
  128. data/test/test_40_property_types.rb +191 -191
  129. data/test/test_41_properties.rb +238 -238
  130. data/test/test_42_set_properties.rb +442 -419
  131. data/test/test_50_name_stored.rb +305 -0
  132. data/test/test_51_name_print_area.rb +363 -0
  133. data/test/test_52_name_print_titles.rb +460 -0
  134. data/test/test_53_autofilter.rb +209 -0
  135. data/test/test_60_chart_generic.rb +576 -0
  136. data/test/test_61_chart_subclasses.rb +97 -0
  137. data/test/test_62_chart_formats.rb +270 -0
  138. data/test/test_63_chart_area_formats.rb +647 -0
  139. data/test/test_chartex.rb +35 -0
  140. data/test/ts_all.rb +46 -34
  141. data/writeexcel.gemspec +18 -0
  142. data/writeexcel.rdoc +583 -0
  143. metadata +162 -108
@@ -1,250 +1,251 @@
1
- ###############################################################################
2
- #
3
- # Properties - A module for creating Excel property sets.
4
- #
5
- #
6
- # Used in conjunction with Spreadsheet::WriteExcel
7
- #
8
- # Copyright 2000-2008, John McNamara.
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 'date'
15
-
16
- ###############################################################################
17
- #
18
- # create_summary_property_set().
19
- #
20
- # Create the SummaryInformation property set. This is mainly used for the
21
- # Title, Subject, Author, Keywords, Comments, Last author keywords and the
22
- # creation date.
23
- #
24
- def create_summary_property_set(properties)
25
- byte_order = [0xFFFE].pack('v')
26
- version = [0x0000].pack('v')
27
- system_id = [0x00020105].pack('V')
28
- class_id = ['00000000000000000000000000000000'].pack('H*')
29
- num_property_sets = [0x0001].pack('V')
30
- format_id = ['E0859FF2F94F6810AB9108002B27B3D9'].pack('H*')
31
- offset = [0x0030].pack('V')
32
- num_property = [properties.size].pack('V')
33
- property_offsets = ''
34
-
35
- # Create the property set data block and calculate the offsets into it.
36
- property_data, offsets = pack_property_data(properties)
37
-
38
- # Create the property type and offsets based on the previous calculation.
39
- 0.upto(properties.size-1) do |i|
40
- property_offsets = property_offsets + [properties[i][0], offsets[i]].pack('VV')
41
- end
42
-
43
- # Size of size (4 bytes) + num_property (4 bytes) + the data structures.
44
- size = 8 + (property_offsets).length + property_data.length
45
- size = [size].pack('V')
46
-
47
- return byte_order +
48
- version +
49
- system_id +
50
- class_id +
51
- num_property_sets +
52
- format_id +
53
- offset +
54
- size +
55
- num_property +
56
- property_offsets +
57
- property_data
58
- end
59
-
60
-
61
- ###############################################################################
62
- #
63
- # Create the DocSummaryInformation property set. This is mainly used for the
64
- # Manager, Company and Category keywords.
65
- #
66
- # The DocSummary also contains a stream for user defined properties. However
67
- # this is a little arcane and probably not worth the implementation effort.
68
- #
69
- def create_doc_summary_property_set(properties)
70
- byte_order = [0xFFFE].pack('v')
71
- version = [0x0000].pack('v')
72
- system_id = [0x00020105].pack('V')
73
- class_id = ['00000000000000000000000000000000'].pack('H*')
74
- num_property_sets = [0x0002].pack('V')
75
-
76
- format_id_0 = ['02D5CDD59C2E1B10939708002B2CF9AE'].pack('H*')
77
- format_id_1 = ['05D5CDD59C2E1B10939708002B2CF9AE'].pack('H*')
78
- offset_0 = [0x0044].pack('V')
79
- num_property_0 = [properties.size].pack('V')
80
- property_offsets_0 = ''
81
-
82
- # Create the property set data block and calculate the offsets into it.
83
- property_data_0, offsets = pack_property_data(properties)
84
-
85
- # Create the property type and offsets based on the previous calculation.
86
- 0.upto(properties.size-1) do |i|
87
- property_offsets_0 = property_offsets_0 + [properties[i][0], offsets[i]].pack('VV')
88
- end
89
-
90
- # Size of size (4 bytes) + num_property (4 bytes) + the data structures.
91
- data_len = 8 + (property_offsets_0).length + property_data_0.length
92
- size_0 = [data_len].pack('V')
93
-
94
- # The second property set offset is at the end of the first property set.
95
- offset_1 = [0x0044 + data_len].pack('V')
96
-
97
- # We will use a static property set stream rather than try to generate it.
98
- property_data_1 = [%w(
99
- 98 00 00 00 03 00 00 00 00 00 00 00 20 00 00 00
100
- 01 00 00 00 36 00 00 00 02 00 00 00 3E 00 00 00
101
- 01 00 00 00 02 00 00 00 0A 00 00 00 5F 50 49 44
102
- 5F 47 55 49 44 00 02 00 00 00 E4 04 00 00 41 00
103
- 00 00 4E 00 00 00 7B 00 31 00 36 00 43 00 34 00
104
- 42 00 38 00 33 00 42 00 2D 00 39 00 36 00 35 00
105
- 46 00 2D 00 34 00 42 00 32 00 31 00 2D 00 39 00
106
- 30 00 33 00 44 00 2D 00 39 00 31 00 30 00 46 00
107
- 41 00 44 00 46 00 41 00 37 00 30 00 31 00 42 00
108
- 7D 00 00 00 00 00 00 00 2D 00 39 00 30 00 33 00
109
- ).join('')].pack('H*')
110
-
111
- return byte_order +
112
- version +
113
- system_id +
114
- class_id +
115
- num_property_sets +
116
- format_id_0 +
117
- offset_0 +
118
- format_id_1 +
119
- offset_1 +
120
-
121
- size_0 +
122
- num_property_0 +
123
- property_offsets_0 +
124
- property_data_0 +
125
-
126
- property_data_1
127
- end
128
-
129
-
130
- ###############################################################################
131
- #
132
- # _pack_property_data().
133
- #
134
- # Create a packed property set structure. Strings are null terminated and
135
- # padded to a 4 byte boundary. We also use this function to keep track of the
136
- # property offsets within the data structure. These offsets are used by the
137
- # calling functions. Currently we only need to handle 4 property types:
138
- # VT_I2, VT_LPSTR, VT_FILETIME.
139
- #
140
- def pack_property_data(properties, offset = 0)
141
- packed_property = ''
142
- data = ''
143
- offsets = []
144
-
145
- # Get the strings codepage from the first property.
146
- codepage = properties[0][2]
147
-
148
- # The properties start after 8 bytes for size + num_properties + 8 bytes
149
- # for each propety type/offset pair.
150
- offset += 8 * (properties.size + 1)
151
-
152
- properties.each do |property|
153
- offsets.push(offset)
154
-
155
- property_type = property[1]
156
-
157
- if property_type == 'VT_I2'
158
- packed_property = pack_VT_I2(property[2])
159
- elsif property_type == 'VT_LPSTR'
160
- packed_property = pack_VT_LPSTR(property[2], codepage)
161
- elsif property_type == 'VT_FILETIME'
162
- packed_property = pack_VT_FILETIME(property[2])
163
- else
164
- raise "Unknown property type: '#{property_type}'\n"
165
- end
166
-
167
- offset += packed_property.length
168
- data = data + packed_property
169
- end
170
-
171
- return [data, offsets]
172
- end
173
-
174
- ###############################################################################
175
- #
176
- # _pack_VT_I2().
177
- #
178
- # Pack an OLE property type: VT_I2, 16-bit signed integer.
179
- #
180
- def pack_VT_I2(value)
181
- type = 0x0002
182
- data = [type, value].pack('VV')
183
- end
184
-
185
- ###############################################################################
186
- #
187
- # _pack_VT_LPSTR().
188
- #
189
- # Pack an OLE property type: VT_LPSTR, String in the Codepage encoding.
190
- # The strings are null terminated and padded to a 4 byte boundary.
191
- #
192
- def pack_VT_LPSTR(str, codepage)
193
- type = 0x001E
194
- string = str + "\0"
195
-
196
- if codepage == 0x04E4
197
- # Latin1
198
- byte_string = string
199
- length = byte_string.length
200
- elsif codepage == 0xFDE9
201
- # UTF-8
202
- nonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]^` ~\0\n]/
203
- if string =~ nonAscii
204
- require 'jcode'
205
- byte_string = string
206
- length = byte_string.jlength
207
- else
208
- byte_string = string
209
- length = byte_string.length
210
- end
211
- else
212
- raise "Unknown codepage: codepage\n"
213
- end
214
-
215
- # Pack the data.
216
- data = [type, length].pack('VV')
217
- data = data + byte_string
218
-
219
- # The packed data has to null padded to a 4 byte boundary.
220
- if (extra = length % 4) != 0
221
- data = data + "\0" * (4 - extra)
222
- end
223
- return data
224
- end
225
-
226
- ###############################################################################
227
- #
228
- # _pack_VT_FILETIME().
229
- #
230
- # Pack an OLE property type: VT_FILETIME.
231
- #
232
- def pack_VT_FILETIME(localtime)
233
- type = 0x0040
234
-
235
- epoch = DateTime.new(1601, 1, 1)
236
-
237
- datetime = DateTime.new(
238
- localtime.year,
239
- localtime.mon,
240
- localtime.mday,
241
- localtime.hour,
242
- localtime.min,
243
- localtime.sec,
244
- localtime.usec
245
- )
246
- bignum = (datetime - epoch) * 86400 * 1e7.to_i
247
- high, low = bignum.divmod 1 << 32
248
-
249
- [type].pack('V') + [low, high].pack('V2')
250
- end
1
+ ###############################################################################
2
+ #
3
+ # Properties - A module for creating Excel property sets.
4
+ #
5
+ #
6
+ # Used in conjunction with WriteExcel
7
+ #
8
+ # Copyright 2000-2010, John McNamara.
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 'date'
15
+
16
+ ###############################################################################
17
+ #
18
+ # create_summary_property_set().
19
+ #
20
+ # Create the SummaryInformation property set. This is mainly used for the
21
+ # Title, Subject, Author, Keywords, Comments, Last author keywords and the
22
+ # creation date.
23
+ #
24
+ def create_summary_property_set(properties) #:nodoc:
25
+ byte_order = [0xFFFE].pack('v')
26
+ version = [0x0000].pack('v')
27
+ system_id = [0x00020105].pack('V')
28
+ class_id = ['00000000000000000000000000000000'].pack('H*')
29
+ num_property_sets = [0x0001].pack('V')
30
+ format_id = ['E0859FF2F94F6810AB9108002B27B3D9'].pack('H*')
31
+ offset = [0x0030].pack('V')
32
+ num_property = [properties.size].pack('V')
33
+ property_offsets = ''
34
+
35
+ # Create the property set data block and calculate the offsets into it.
36
+ property_data, offsets = pack_property_data(properties)
37
+
38
+ # Create the property type and offsets based on the previous calculation.
39
+ 0.upto(properties.size-1) do |i|
40
+ property_offsets = property_offsets + [properties[i][0], offsets[i]].pack('VV')
41
+ end
42
+
43
+ # Size of size (4 bytes) + num_property (4 bytes) + the data structures.
44
+ size = 8 + (property_offsets).length + property_data.length
45
+ size = [size].pack('V')
46
+
47
+ return byte_order +
48
+ version +
49
+ system_id +
50
+ class_id +
51
+ num_property_sets +
52
+ format_id +
53
+ offset +
54
+ size +
55
+ num_property +
56
+ property_offsets +
57
+ property_data
58
+ end
59
+
60
+
61
+ ###############################################################################
62
+ #
63
+ # Create the DocSummaryInformation property set. This is mainly used for the
64
+ # Manager, Company and Category keywords.
65
+ #
66
+ # The DocSummary also contains a stream for user defined properties. However
67
+ # this is a little arcane and probably not worth the implementation effort.
68
+ #
69
+ def create_doc_summary_property_set(properties) #:nodoc:
70
+ byte_order = [0xFFFE].pack('v')
71
+ version = [0x0000].pack('v')
72
+ system_id = [0x00020105].pack('V')
73
+ class_id = ['00000000000000000000000000000000'].pack('H*')
74
+ num_property_sets = [0x0002].pack('V')
75
+
76
+ format_id_0 = ['02D5CDD59C2E1B10939708002B2CF9AE'].pack('H*')
77
+ format_id_1 = ['05D5CDD59C2E1B10939708002B2CF9AE'].pack('H*')
78
+ offset_0 = [0x0044].pack('V')
79
+ num_property_0 = [properties.size].pack('V')
80
+ property_offsets_0 = ''
81
+
82
+ # Create the property set data block and calculate the offsets into it.
83
+ property_data_0, offsets = pack_property_data(properties)
84
+
85
+ # Create the property type and offsets based on the previous calculation.
86
+ 0.upto(properties.size-1) do |i|
87
+ property_offsets_0 = property_offsets_0 + [properties[i][0], offsets[i]].pack('VV')
88
+ end
89
+
90
+ # Size of size (4 bytes) + num_property (4 bytes) + the data structures.
91
+ data_len = 8 + (property_offsets_0).length + property_data_0.length
92
+ size_0 = [data_len].pack('V')
93
+
94
+ # The second property set offset is at the end of the first property set.
95
+ offset_1 = [0x0044 + data_len].pack('V')
96
+
97
+ # We will use a static property set stream rather than try to generate it.
98
+ property_data_1 = [%w(
99
+ 98 00 00 00 03 00 00 00 00 00 00 00 20 00 00 00
100
+ 01 00 00 00 36 00 00 00 02 00 00 00 3E 00 00 00
101
+ 01 00 00 00 02 00 00 00 0A 00 00 00 5F 50 49 44
102
+ 5F 47 55 49 44 00 02 00 00 00 E4 04 00 00 41 00
103
+ 00 00 4E 00 00 00 7B 00 31 00 36 00 43 00 34 00
104
+ 42 00 38 00 33 00 42 00 2D 00 39 00 36 00 35 00
105
+ 46 00 2D 00 34 00 42 00 32 00 31 00 2D 00 39 00
106
+ 30 00 33 00 44 00 2D 00 39 00 31 00 30 00 46 00
107
+ 41 00 44 00 46 00 41 00 37 00 30 00 31 00 42 00
108
+ 7D 00 00 00 00 00 00 00 2D 00 39 00 30 00 33 00
109
+ ).join('')].pack('H*')
110
+
111
+ return byte_order +
112
+ version +
113
+ system_id +
114
+ class_id +
115
+ num_property_sets +
116
+ format_id_0 +
117
+ offset_0 +
118
+ format_id_1 +
119
+ offset_1 +
120
+
121
+ size_0 +
122
+ num_property_0 +
123
+ property_offsets_0 +
124
+ property_data_0 +
125
+
126
+ property_data_1
127
+ end
128
+
129
+
130
+ ###############################################################################
131
+ #
132
+ # _pack_property_data().
133
+ #
134
+ # Create a packed property set structure. Strings are null terminated and
135
+ # padded to a 4 byte boundary. We also use this function to keep track of the
136
+ # property offsets within the data structure. These offsets are used by the
137
+ # calling functions. Currently we only need to handle 4 property types:
138
+ # VT_I2, VT_LPSTR, VT_FILETIME.
139
+ #
140
+ def pack_property_data(properties, offset = 0) #:nodoc:
141
+ packed_property = ''
142
+ data = ''
143
+ offsets = []
144
+
145
+ # Get the strings codepage from the first property.
146
+ codepage = properties[0][2]
147
+
148
+ # The properties start after 8 bytes for size + num_properties + 8 bytes
149
+ # for each propety type/offset pair.
150
+ offset += 8 * (properties.size + 1)
151
+
152
+ properties.each do |property|
153
+ offsets.push(offset)
154
+
155
+ property_type = property[1]
156
+
157
+ if property_type == 'VT_I2'
158
+ packed_property = pack_VT_I2(property[2])
159
+ elsif property_type == 'VT_LPSTR'
160
+ packed_property = pack_VT_LPSTR(property[2], codepage)
161
+ elsif property_type == 'VT_FILETIME'
162
+ packed_property = pack_VT_FILETIME(property[2])
163
+ else
164
+ raise "Unknown property type: '#{property_type}'\n"
165
+ end
166
+
167
+ offset += packed_property.length
168
+ data = data + packed_property
169
+ end
170
+
171
+ return [data, offsets]
172
+ end
173
+
174
+ ###############################################################################
175
+ #
176
+ # _pack_VT_I2().
177
+ #
178
+ # Pack an OLE property type: VT_I2, 16-bit signed integer.
179
+ #
180
+ def pack_VT_I2(value) #:nodoc:
181
+ type = 0x0002
182
+ data = [type, value].pack('VV')
183
+ end
184
+
185
+ ###############################################################################
186
+ #
187
+ # _pack_VT_LPSTR().
188
+ #
189
+ # Pack an OLE property type: VT_LPSTR, String in the Codepage encoding.
190
+ # The strings are null terminated and padded to a 4 byte boundary.
191
+ #
192
+ def pack_VT_LPSTR(str, codepage) #:nodoc:
193
+ type = 0x001E
194
+ string = str + "\0"
195
+
196
+ if codepage == 0x04E4
197
+ # Latin1
198
+ byte_string = string
199
+ length = byte_string.length
200
+ elsif codepage == 0xFDE9
201
+ # UTF-8
202
+ nonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]^` ~\0\n]/
203
+ if string =~ nonAscii
204
+ # $KCODE = 'u'
205
+ require 'jcode'
206
+ byte_string = string
207
+ length = byte_string.jlength
208
+ else
209
+ byte_string = string
210
+ length = byte_string.length
211
+ end
212
+ else
213
+ raise "Unknown codepage: codepage\n"
214
+ end
215
+
216
+ # Pack the data.
217
+ data = [type, length].pack('VV')
218
+ data = data + byte_string
219
+
220
+ # The packed data has to null padded to a 4 byte boundary.
221
+ if (extra = length % 4) != 0
222
+ data = data + "\0" * (4 - extra)
223
+ end
224
+ return data
225
+ end
226
+
227
+ ###############################################################################
228
+ #
229
+ # _pack_VT_FILETIME().
230
+ #
231
+ # Pack an OLE property type: VT_FILETIME.
232
+ #
233
+ def pack_VT_FILETIME(localtime) #:nodoc:
234
+ type = 0x0040
235
+
236
+ epoch = DateTime.new(1601, 1, 1)
237
+
238
+ datetime = DateTime.new(
239
+ localtime.year,
240
+ localtime.mon,
241
+ localtime.mday,
242
+ localtime.hour,
243
+ localtime.min,
244
+ localtime.sec,
245
+ localtime.usec
246
+ )
247
+ bignum = (datetime - epoch) * 86400 * 1e7.to_i
248
+ high, low = bignum.divmod 1 << 32
249
+
250
+ [type].pack('V') + [low, high].pack('V2')
251
+ end