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.
- data/README +26 -31
- data/examples/a_simple.rb +42 -42
- data/examples/{autofilters.rb → autofilter.rb} +264 -266
- data/examples/bigfile.rb +29 -0
- data/examples/chart_area.rb +120 -0
- data/examples/chart_bar.rb +119 -0
- data/examples/chart_column.rb +119 -0
- data/examples/chart_line.rb +119 -0
- data/examples/chart_pie.rb +107 -0
- data/examples/chart_scatter.rb +120 -0
- data/examples/chart_stock.rb +147 -0
- data/examples/copyformat.rb +51 -51
- data/examples/data_validate.rb +278 -278
- data/examples/date_time.rb +86 -86
- data/examples/defined_name.rb +31 -0
- data/examples/demo.rb +120 -118
- data/examples/diag_border.rb +35 -35
- data/examples/formats.rb +489 -489
- data/examples/header.rb +136 -136
- data/examples/hidden.rb +28 -28
- data/examples/hyperlink.rb +42 -42
- data/examples/images.rb +52 -52
- data/examples/merge1.rb +39 -39
- data/examples/merge2.rb +44 -44
- data/examples/merge3.rb +65 -65
- data/examples/merge4.rb +82 -82
- data/examples/merge5.rb +79 -79
- data/examples/properties.rb +33 -0
- data/examples/properties_jp.rb +32 -0
- data/examples/protection.rb +46 -46
- data/examples/regions.rb +52 -52
- data/examples/repeat.rb +42 -42
- data/examples/stats.rb +75 -75
- data/examples/stocks.rb +80 -80
- data/examples/tab_colors.rb +30 -30
- data/examples/write_arrays.rb +82 -0
- data/lib/writeexcel.rb +1134 -18
- data/lib/writeexcel/biffwriter.rb +273 -260
- data/lib/writeexcel/chart.rb +2306 -217
- data/lib/writeexcel/charts/area.rb +152 -0
- data/lib/writeexcel/charts/bar.rb +177 -0
- data/lib/writeexcel/charts/column.rb +156 -0
- data/lib/writeexcel/charts/external.rb +61 -0
- data/lib/writeexcel/charts/line.rb +152 -0
- data/lib/writeexcel/charts/pie.rb +169 -0
- data/lib/writeexcel/charts/scatter.rb +192 -0
- data/lib/writeexcel/charts/stock.rb +211 -0
- data/lib/writeexcel/excelformulaparser.rb +208 -195
- data/lib/writeexcel/format.rb +1697 -1108
- data/lib/writeexcel/formula.rb +1050 -986
- data/lib/writeexcel/olewriter.rb +322 -322
- data/lib/writeexcel/properties.rb +251 -250
- data/lib/writeexcel/storage_lite.rb +968 -0
- data/lib/writeexcel/workbook.rb +3294 -2630
- data/lib/writeexcel/worksheet.rb +9012 -6377
- data/test/excelfile/Chart1.xls +0 -0
- data/test/excelfile/Chart2.xls +0 -0
- data/test/excelfile/Chart3.xls +0 -0
- data/test/excelfile/Chart4.xls +0 -0
- data/test/excelfile/Chart5.xls +0 -0
- data/test/perl_output/Chart1.xls.data +0 -0
- data/test/perl_output/Chart2.xls.data +0 -0
- data/test/perl_output/Chart3.xls.data +0 -0
- data/test/perl_output/Chart4.xls.data +0 -0
- data/test/perl_output/Chart5.xls.data +0 -0
- data/test/perl_output/a_simple.xls +0 -0
- data/test/perl_output/autofilter.xls +0 -0
- data/test/perl_output/chart_area.xls +0 -0
- data/test/perl_output/chart_bar.xls +0 -0
- data/test/perl_output/chart_column.xls +0 -0
- data/test/perl_output/chart_line.xls +0 -0
- data/test/perl_output/data_validate.xls +0 -0
- data/test/perl_output/date_time.xls +0 -0
- data/test/perl_output/demo.xls +0 -0
- data/test/perl_output/demo101.bin +0 -0
- data/test/perl_output/demo201.bin +0 -0
- data/test/perl_output/demo301.bin +0 -0
- data/test/perl_output/demo401.bin +0 -0
- data/test/perl_output/demo501.bin +0 -0
- data/test/perl_output/diag_border.xls +0 -0
- data/test/perl_output/headers.xls +0 -0
- data/test/perl_output/hyperlink.xls +0 -0
- data/test/perl_output/images.xls +0 -0
- data/test/perl_output/merge1.xls +0 -0
- data/test/perl_output/merge2.xls +0 -0
- data/test/perl_output/merge3.xls +0 -0
- data/test/perl_output/merge4.xls +0 -0
- data/test/perl_output/merge5.xls +0 -0
- data/test/perl_output/protection.xls +0 -0
- data/test/perl_output/regions.xls +0 -0
- data/test/perl_output/stats.xls +0 -0
- data/test/perl_output/stocks.xls +0 -0
- data/test/perl_output/tab_colors.xls +0 -0
- data/test/perl_output/unicode_cyrillic.xls +0 -0
- data/test/perl_output/workbook1.xls +0 -0
- data/test/perl_output/workbook2.xls +0 -0
- data/test/tc_all.rb +32 -31
- data/test/tc_biff.rb +104 -104
- data/test/tc_chart.rb +22 -22
- data/test/tc_example_match.rb +1944 -1280
- data/test/tc_format.rb +1254 -1267
- data/test/tc_formula.rb +63 -63
- data/test/tc_ole.rb +110 -110
- data/test/tc_storage_lite.rb +149 -0
- data/test/tc_workbook.rb +140 -115
- data/test/tc_worksheet.rb +115 -115
- data/test/test_00_IEEE_double.rb +14 -14
- data/test/test_01_add_worksheet.rb +12 -12
- data/test/test_02_merge_formats.rb +58 -58
- data/test/test_04_dimensions.rb +397 -397
- data/test/test_05_rows.rb +182 -182
- data/test/test_06_extsst.rb +80 -80
- data/test/test_11_date_time.rb +484 -484
- data/test/test_12_date_only.rb +506 -506
- data/test/test_13_date_seconds.rb +486 -486
- data/test/test_21_escher.rb +642 -629
- data/test/test_22_mso_drawing_group.rb +750 -739
- data/test/test_23_note.rb +78 -78
- data/test/test_24_txo.rb +80 -80
- data/test/test_25_position_object.rb +82 -0
- data/test/test_26_autofilter.rb +327 -327
- data/test/test_27_autofilter.rb +144 -144
- data/test/test_28_autofilter.rb +174 -174
- data/test/test_29_process_jpg.rb +681 -131
- data/test/test_30_validation_dval.rb +82 -82
- data/test/test_31_validation_dv_strings.rb +131 -131
- data/test/test_32_validation_dv_formula.rb +211 -211
- data/test/test_40_property_types.rb +191 -191
- data/test/test_41_properties.rb +238 -238
- data/test/test_42_set_properties.rb +442 -419
- data/test/test_50_name_stored.rb +305 -0
- data/test/test_51_name_print_area.rb +363 -0
- data/test/test_52_name_print_titles.rb +460 -0
- data/test/test_53_autofilter.rb +209 -0
- data/test/test_60_chart_generic.rb +576 -0
- data/test/test_61_chart_subclasses.rb +97 -0
- data/test/test_62_chart_formats.rb +270 -0
- data/test/test_63_chart_area_formats.rb +647 -0
- data/test/test_chartex.rb +35 -0
- data/test/ts_all.rb +46 -34
- data/writeexcel.gemspec +18 -0
- data/writeexcel.rdoc +583 -0
- 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
|
7
|
-
#
|
8
|
-
# Copyright 2000-
|
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
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
data =
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
localtime.
|
240
|
-
localtime.
|
241
|
-
localtime.
|
242
|
-
localtime.
|
243
|
-
localtime.
|
244
|
-
localtime.
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|