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
@@ -0,0 +1,968 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
class OLEStorageLite #:nodoc:
|
5
|
+
PPS_TYPE_ROOT = 5
|
6
|
+
PPS_TYPE_DIR = 1
|
7
|
+
PPS_TYPE_FILE = 2
|
8
|
+
DATA_SIZE_SMALL = 0x1000
|
9
|
+
LONG_INT_SIZE = 4
|
10
|
+
PPS_SIZE = 0x80
|
11
|
+
|
12
|
+
attr_reader :file
|
13
|
+
|
14
|
+
def initialize(file = nil)
|
15
|
+
@file = file
|
16
|
+
end
|
17
|
+
|
18
|
+
def getPpsTree(data)
|
19
|
+
info = _initParse(file)
|
20
|
+
info ? _getPpsTree(0, info, data) : nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def getPpsSearch(name, data, icase)
|
24
|
+
info = _initParse(file)
|
25
|
+
info ? _getPpsSearch(0, info, name, data, icase) : nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def getNthPps(no, data)
|
29
|
+
info = _initParse(file)
|
30
|
+
info ? _getNthPps(no, info, data) : nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def _initParse(file)
|
34
|
+
io = file.kind_of?(String) ? open(file, 'rb') : file
|
35
|
+
_getHeaderInfo(io)
|
36
|
+
end
|
37
|
+
private :_initParse
|
38
|
+
|
39
|
+
def _getPpsTree(no, info, data, done)
|
40
|
+
if done
|
41
|
+
return [] if done.include?(no)
|
42
|
+
else
|
43
|
+
done = []
|
44
|
+
end
|
45
|
+
done << no
|
46
|
+
|
47
|
+
rootblock = info[:root_start]
|
48
|
+
|
49
|
+
#1. Get Information about itself
|
50
|
+
pps = _getNthPps(no, info, data)
|
51
|
+
|
52
|
+
#2. Child
|
53
|
+
if pps.dir_pps != 0xFFFFFFFF
|
54
|
+
pps.child = _getPpsTree(pps.dir_pps, info, data, done)
|
55
|
+
else
|
56
|
+
pps.child = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
#3. Previous,Next PPSs
|
60
|
+
list = []
|
61
|
+
list << _getPpsTree(pps.prev_pps, info, data, done) if pps.prev_pps != 0xFFFFFFFF
|
62
|
+
list << pps
|
63
|
+
list << _getPpsTree(pps.next_pps, info, data, done) if pps.next_pps != 0xFFFFFFFF
|
64
|
+
end
|
65
|
+
private :_getPpsTree
|
66
|
+
|
67
|
+
def _getPpsSearch(no, info, name, data, icase, done = nil)
|
68
|
+
rootblock = info[:root_start]
|
69
|
+
#1. Check it self
|
70
|
+
if done
|
71
|
+
return [] if done.include?(no)
|
72
|
+
else
|
73
|
+
done = []
|
74
|
+
end
|
75
|
+
done << no
|
76
|
+
pps = _getNthPps(no, info, nil)
|
77
|
+
|
78
|
+
re = Regexp.new("^\Q#{pps.name}\E$", Regexp::IGNORECASE)
|
79
|
+
if (icase && !name.select { |v| v =~ re }.empty?) || name.include?(pps.name)
|
80
|
+
pps = _getNthPps(no, info, data) if data
|
81
|
+
res = [pps]
|
82
|
+
else
|
83
|
+
res = []
|
84
|
+
end
|
85
|
+
|
86
|
+
#2. Check Child, Previous, Next PPSs
|
87
|
+
res +=
|
88
|
+
_getPpsSearch(pps.dir_pps, info, name, data, icase, done) if pps.dir_pps != 0xFFFFFFFF
|
89
|
+
res +=
|
90
|
+
_getPpsSearch(pps.prev_pps, info, name, data, icase, done) if pps.prev_pps != 0xFFFFFFFF
|
91
|
+
res +=
|
92
|
+
_getPpsSearch(pps.next_pps, info, name, data, icase, done) if pps.next_pps != 0xFFFFFFFF
|
93
|
+
res
|
94
|
+
end
|
95
|
+
private :_getPpsSearch
|
96
|
+
|
97
|
+
def _getHeaderInfo(io)
|
98
|
+
info = { :fileh => io }
|
99
|
+
|
100
|
+
#0. Check ID
|
101
|
+
info[:fileh].seek(0, 0)
|
102
|
+
return nil unless info[:fileh].read(8) == "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
|
103
|
+
|
104
|
+
# BIG BLOCK SIZE
|
105
|
+
val = _getInfoFromFile(info[:fileh], 0x1E, 2, "v")
|
106
|
+
return nil if val.nil?
|
107
|
+
info[:big_block_size] = 2 ** val
|
108
|
+
|
109
|
+
# SMALL BLOCK SIZE
|
110
|
+
val = _getInfoFromFile(info[:fileh], 0x20, 2, "v")
|
111
|
+
return nil if val.nil?
|
112
|
+
info[:small_block_size] = 2 ** val
|
113
|
+
|
114
|
+
# BDB Count
|
115
|
+
val = _getInfoFromFile(info[:fileh], 0x2C, 4, "V")
|
116
|
+
return nil if val.nil?
|
117
|
+
info[:bdb_count] = val
|
118
|
+
|
119
|
+
# START BLOCK
|
120
|
+
val = _getInfoFromFile(info[:fileh], 0x30, 4, "V")
|
121
|
+
return nil if val.nil?
|
122
|
+
info[:root_start] = val
|
123
|
+
|
124
|
+
# SMALL BD START
|
125
|
+
val = _getInfoFromFile(info[:fileh], 0x3C, 4, "V")
|
126
|
+
return nil if val.nil?
|
127
|
+
info[:sbd_start] = val
|
128
|
+
|
129
|
+
# SMALL BD COUNT
|
130
|
+
val = _getInfoFromFile(info[:fileh], 0x40, 4, "V")
|
131
|
+
return nil if val.nil?
|
132
|
+
info[:sbd_count] = val
|
133
|
+
|
134
|
+
# EXTRA BBD START
|
135
|
+
val = _getInfoFromFile(info[:fileh], 0x44, 4, "V")
|
136
|
+
return nil if val.nil?
|
137
|
+
info[:extra_bbd_start] = val
|
138
|
+
|
139
|
+
# EXTRA BBD COUNT
|
140
|
+
val = _getInfoFromFile(info[:fileh], 0x48, 4, "V")
|
141
|
+
return nil if val.nil?
|
142
|
+
info[:extra_bbd_count] = val
|
143
|
+
|
144
|
+
#GET BBD INFO
|
145
|
+
info[:bbd_info] = _getBbdInfo(info)
|
146
|
+
|
147
|
+
# GET ROOT PPS
|
148
|
+
root = _getNthPps(0, info, nil)
|
149
|
+
info[:sb_start] = root.start_block
|
150
|
+
info[:sb_size] = root.size
|
151
|
+
info
|
152
|
+
end
|
153
|
+
private :_getHeaderInfo
|
154
|
+
|
155
|
+
def _getInfoFromFile(io, pos, len, fmt)
|
156
|
+
io.seek(pos, 0)
|
157
|
+
str = io.read(len)
|
158
|
+
if str.length != len
|
159
|
+
nil
|
160
|
+
else
|
161
|
+
str.unpack(fmt)[0]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
private :_getInfoFromFile
|
165
|
+
|
166
|
+
def _getBbdInfo(info)
|
167
|
+
bdlist = []
|
168
|
+
iBdbCnt = info[:bdb_count]
|
169
|
+
i1stCnt = (info[:big_block_size] - 0x4C) / LONG_INT_SIZE
|
170
|
+
iBdlCnt = info[:big_block_size] / LONG_INT_SIZE - 1
|
171
|
+
|
172
|
+
#1. 1st BDlist
|
173
|
+
info[:fileh].seek(0x4C, 0)
|
174
|
+
iGetCnt = iBdbCnt < i1stCnt ? iBdbCnt : i1stCnt
|
175
|
+
str = info[:fileh].read(LONG_INT_SIZE * iGetCnt)
|
176
|
+
bdlist += str.unpack("V#{iGetCnt}")
|
177
|
+
iBdbCnt -= iGetCnt
|
178
|
+
|
179
|
+
#2. Extra BDList
|
180
|
+
iBlock = info[:extra_bbd_start]
|
181
|
+
while iBdbCnt> 0 && _isNormalBlock(iBlock)
|
182
|
+
_setFilePos(iBlock, 0, info)
|
183
|
+
iGetCnt = iBdbCnt < iBdlCnt ? iBdbCnt : iBdlCnt
|
184
|
+
str = info[:fileh].read(LONG_INT_SIZE * iGetCnt)
|
185
|
+
bdlist += str.unpack("V#{iGetCnt}")
|
186
|
+
iBdbCnt -= iGetCnt
|
187
|
+
str = info[:fileh].read(LONG_INT_SIZE)
|
188
|
+
iBlock = str.unpack("V")
|
189
|
+
end
|
190
|
+
|
191
|
+
#3.Get BDs
|
192
|
+
hBd = Hash.new
|
193
|
+
iBlkNo = 0
|
194
|
+
iBdCnt = info[:big_block_size] / LONG_INT_SIZE
|
195
|
+
bdlist.each do |iBdL|
|
196
|
+
_setFilePos(iBdL, 0, info)
|
197
|
+
str = info[:fileh].read(info[:big_block_size])
|
198
|
+
arr = str.unpack("V#{iBdCnt}")
|
199
|
+
(0...iBdCnt).each do |i|
|
200
|
+
hBd[iBlkNo] = arr[i] if arr[i] != iBlkNo + 1
|
201
|
+
iBlkNo += 1
|
202
|
+
end
|
203
|
+
end
|
204
|
+
hBd
|
205
|
+
end
|
206
|
+
private :_getBbdInfo
|
207
|
+
|
208
|
+
def _getNthPps(pos, info, data)
|
209
|
+
ppsstart = info[:root_start]
|
210
|
+
|
211
|
+
basecnt = info[:big_block_size] / PPS_SIZE
|
212
|
+
ppsblock = pos / basecnt
|
213
|
+
ppspos = pos % basecnt
|
214
|
+
|
215
|
+
block = _getNthBlockNo(ppsstart, ppsblock, info)
|
216
|
+
return nil if block.nil?
|
217
|
+
|
218
|
+
_setFilePos(block, PPS_SIZE * ppspos, info)
|
219
|
+
str = info[:fileh].read(PPS_SIZE)
|
220
|
+
return nil if str.nil? || str == ''
|
221
|
+
nmsize = str[0x40, 2].unpack('v')[0]
|
222
|
+
nmsize -= 2 if nmsize > 2
|
223
|
+
nm = str[0, nmsize]
|
224
|
+
type = str[0x42, 2].unpack('C')[0]
|
225
|
+
ppsprev = str[0x44, LONG_INT_SIZE].unpack('V')[0]
|
226
|
+
ppsnext = str[0x48, LONG_INT_SIZE].unpack('V')[0]
|
227
|
+
dirpps = str[0x4C, LONG_INT_SIZE].unpack('V')[0]
|
228
|
+
time1st =
|
229
|
+
(type == PPS_TYPE_ROOT || type == PPS_TYPE_DIR) ? oleData2Local(str[0x64, 8]) : nil
|
230
|
+
time2nd =
|
231
|
+
(type == PPS_TYPE_ROOT || type == PPS_TYPE_DIR) ? oleData2Local(str[0x6C, 8]) : nil
|
232
|
+
start, size = str[0x74, 8].unpack('VV')
|
233
|
+
if data
|
234
|
+
sdata = _getData(type, start, size, info)
|
235
|
+
OLEStorageLitePPS.new(pos, nm, type, ppsprev, ppsnext, dirpps,
|
236
|
+
time1st, time2nd, start, size, sdata, nil)
|
237
|
+
else
|
238
|
+
OLEStorageLitePPS.new(pos, nm, type, ppsprev, ppsnext, dirpps,
|
239
|
+
time1st, time2nd, start, size, nil, nil)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
private :_getNthPps
|
243
|
+
|
244
|
+
def _setFilePos(iBlock, iPos, info)
|
245
|
+
info[:fileh].seek((iBlock + 1) * info[:big_block_size] + iPos, 0)
|
246
|
+
end
|
247
|
+
private :_setFilePos
|
248
|
+
|
249
|
+
def _getNthBlockNo(stblock, nth, info)
|
250
|
+
inext = stblock
|
251
|
+
(0...nth).each do |i|
|
252
|
+
sv = inext
|
253
|
+
inext = _getNextBlockNo(sv, info)
|
254
|
+
return nil unless _isNormalBlock(inext)
|
255
|
+
end
|
256
|
+
inext
|
257
|
+
end
|
258
|
+
private :_getNthBlockNo
|
259
|
+
|
260
|
+
def _getData(iType, iBlock, iSize, info)
|
261
|
+
if iType == PPS_TYPE_FILE
|
262
|
+
if iSize < DATA_SIZE_SMALL
|
263
|
+
return _getSmallData(iBlock, iSize, info)
|
264
|
+
else
|
265
|
+
return _getBigData(iBlock, iSize, info)
|
266
|
+
end
|
267
|
+
elsif iType == PPS_TYPE_ROOT # Root
|
268
|
+
return _getBigData(iBlock, iSize, info)
|
269
|
+
elsif iType == PPS_TYPE_DIR # Directory
|
270
|
+
return nil
|
271
|
+
end
|
272
|
+
end
|
273
|
+
private :_getData
|
274
|
+
|
275
|
+
def _getBigData(iBlock, iSize, info)
|
276
|
+
return '' unless _isNormalBlock(iBlock)
|
277
|
+
iRest = iSize
|
278
|
+
sRes = ''
|
279
|
+
aKeys = info[:bbd_info].keys.sort
|
280
|
+
|
281
|
+
while iRest > 0
|
282
|
+
aRes = aKeys.select { |key| key >= iBlock }
|
283
|
+
iNKey = aRes[0]
|
284
|
+
i = iNKey - iBlock
|
285
|
+
iNext = info[:bbd_info][iNKey]
|
286
|
+
_setFilePos(iBlock, 0, info)
|
287
|
+
iGetSize = info[:big_block_size] * (i + 1)
|
288
|
+
iGetSize = iRest if iRest < iGetSize
|
289
|
+
sRes += info[:fileh].read(iGetSize)
|
290
|
+
iRest -= iGetSize
|
291
|
+
iBlock = iNext
|
292
|
+
end
|
293
|
+
return sRes
|
294
|
+
end
|
295
|
+
private :_getBigData
|
296
|
+
|
297
|
+
def _getNextBlockNo(iBlockNo, info)
|
298
|
+
iRes = info[:bbd_info][iBlockNo]
|
299
|
+
iRes ? iRes : iBlockNo + 1
|
300
|
+
end
|
301
|
+
private :_getNextBlockNo
|
302
|
+
|
303
|
+
def _isNormalBlock(iBlock)
|
304
|
+
iBlock < 0xFFFFFFFC ? 1 : nil
|
305
|
+
end
|
306
|
+
private :_isNormalBlock
|
307
|
+
|
308
|
+
def _getSmallData(iSmBlock, iSize, info)
|
309
|
+
iRest = iSize
|
310
|
+
sRes = ''
|
311
|
+
while iRest > 0
|
312
|
+
_setFilePosSmall(iSmBlock, info)
|
313
|
+
sRes += info[:fileh].read(
|
314
|
+
iRest >= info[:small_block_size] ? info[:small_block_size] : iRest)
|
315
|
+
iRest -= info[:small_block_size]
|
316
|
+
iSmBlock = _getNextSmallBlockNo(iSmBlock, info)
|
317
|
+
end
|
318
|
+
sRes
|
319
|
+
end
|
320
|
+
private :_getSmallData
|
321
|
+
|
322
|
+
def _setFilePosSmall(iSmBlock, info)
|
323
|
+
iSmStart = info[:sb_start]
|
324
|
+
iBaseCnt = info[:big_block_size] / info[:small_block_size]
|
325
|
+
iNth = iSmBlock / iBaseCnt
|
326
|
+
iPos = iSmBlock % iBaseCnt
|
327
|
+
|
328
|
+
iBlk = _getNthBlockNo(iSmStart, iNth, info)
|
329
|
+
_setFilePos(iBlk, iPos * info[:small_block_size], info)
|
330
|
+
end
|
331
|
+
private :_setFilePosSmall
|
332
|
+
|
333
|
+
def _getNextSmallBlockNo(iSmBlock, info)
|
334
|
+
iBaseCnt = info[:big_block_size] / LONG_INT_SIZE
|
335
|
+
iNth = iSmBlock / iBaseCnt
|
336
|
+
iPos = iSmBlock % iBaseCnt
|
337
|
+
iBlk = _getNthBlockNo(info[:sbd_start], iNth, info)
|
338
|
+
_setFilePos(iBlk, iPos * LONG_INT_SIZE, info)
|
339
|
+
info[:fileh].read(LONG_INT_SIZE).unpack('V')
|
340
|
+
end
|
341
|
+
private :_getNextSmallBlockNo
|
342
|
+
|
343
|
+
def asc2ucs(str)
|
344
|
+
str.split(//).join("\0") + "\0"
|
345
|
+
end
|
346
|
+
|
347
|
+
def ucs2asc(str)
|
348
|
+
ary = str.unpack('v*').map { |s| [s].pack('c')}
|
349
|
+
ary.join('')
|
350
|
+
end
|
351
|
+
|
352
|
+
#------------------------------------------------------------------------------
|
353
|
+
# OLEDate2Local()
|
354
|
+
#
|
355
|
+
# Convert from a Window FILETIME structure to a localtime array. FILETIME is
|
356
|
+
# a 64-bit value representing the number of 100-nanosecond intervals since
|
357
|
+
# January 1 1601.
|
358
|
+
#
|
359
|
+
# We first convert the FILETIME to seconds and then subtract the difference
|
360
|
+
# between the 1601 epoch and the 1970 Unix epoch.
|
361
|
+
#
|
362
|
+
def oleData2Local(oletime)
|
363
|
+
# Unpack the FILETIME into high and low longs.
|
364
|
+
lo, hi = oletime.unpack('V2')
|
365
|
+
|
366
|
+
# Convert the longs to a double.
|
367
|
+
nanoseconds = hi * 2 ** 32 + lo
|
368
|
+
|
369
|
+
# Convert the 100 nanosecond units into seconds.
|
370
|
+
time = nanoseconds / 1e7
|
371
|
+
|
372
|
+
# Subtract the number of seconds between the 1601 and 1970 epochs.
|
373
|
+
time -= 11644473600
|
374
|
+
|
375
|
+
# Convert to a localtime (actually gmtime) structure.
|
376
|
+
if time >= 1
|
377
|
+
ltime = Time.at(time).getgm.to_a[0, 9]
|
378
|
+
ltime[4] -= 1 # month
|
379
|
+
ltime[5] -= 1900 # year
|
380
|
+
ltime[7] -= 1 # past from 1, Jan
|
381
|
+
ltime[8] = ltime[8] ? 1 : 0
|
382
|
+
ltime
|
383
|
+
else
|
384
|
+
[]
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
#------------------------------------------------------------------------------
|
389
|
+
# LocalDate2OLE()
|
390
|
+
#
|
391
|
+
# Convert from a a localtime array to a Window FILETIME structure. FILETIME is
|
392
|
+
# a 64-bit value representing the number of 100-nanosecond intervals since
|
393
|
+
# January 1 1601.
|
394
|
+
#
|
395
|
+
# We first convert the localtime (actually gmtime) to seconds and then add the
|
396
|
+
# difference between the 1601 epoch and the 1970 Unix epoch. We convert that to
|
397
|
+
# 100 nanosecond units, divide it into high and low longs and return it as a
|
398
|
+
# packed 64bit structure.
|
399
|
+
#
|
400
|
+
def localDate2OLE(localtime)
|
401
|
+
return "\x00" * 8 unless localtime
|
402
|
+
|
403
|
+
# Convert from localtime (actually gmtime) to seconds.
|
404
|
+
args = localtime.reverse
|
405
|
+
args[0] += 1900 # year
|
406
|
+
args[1] += 1 # month
|
407
|
+
time = Time.gm(*args)
|
408
|
+
|
409
|
+
# Add the number of seconds between the 1601 and 1970 epochs.
|
410
|
+
time = time.to_i + 11644473600
|
411
|
+
|
412
|
+
# The FILETIME seconds are in units of 100 nanoseconds.
|
413
|
+
nanoseconds = time * 10000000
|
414
|
+
|
415
|
+
# Pack the total nanoseconds into 64 bits...
|
416
|
+
hi, lo = nanoseconds.divmod 1 << 32
|
417
|
+
|
418
|
+
[lo, hi].pack("VV") # oletime
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
class OLEStorageLitePPS < OLEStorageLite #:nodoc:
|
423
|
+
attr_accessor :no, :name, :type, :prev_pps, :next_pps, :dir_pps
|
424
|
+
attr_accessor :time_1st, :time_2nd, :start_block, :size, :data, :child
|
425
|
+
attr_reader :pps_file
|
426
|
+
|
427
|
+
def initialize(iNo, sNm, iType, iPrev, iNext, iDir,
|
428
|
+
raTime1st, raTime2nd, iStart, iSize, sData, raChild)
|
429
|
+
@no = iNo
|
430
|
+
@name = sNm
|
431
|
+
@type = iType
|
432
|
+
@prev_pps = iPrev
|
433
|
+
@next_pps = iNext
|
434
|
+
@dir_pps = iDir
|
435
|
+
@time_1st = raTime1st
|
436
|
+
@time_2nd = raTime2nd
|
437
|
+
@start_block = iStart
|
438
|
+
@size = iSize
|
439
|
+
@data = sData
|
440
|
+
@child = raChild
|
441
|
+
@pps_file = nil
|
442
|
+
end
|
443
|
+
|
444
|
+
def _datalen
|
445
|
+
return 0 if @data.nil?
|
446
|
+
if @pps_file
|
447
|
+
return @pps_file.lstat.size
|
448
|
+
else
|
449
|
+
return @data.size
|
450
|
+
end
|
451
|
+
end
|
452
|
+
protected :_datalen
|
453
|
+
|
454
|
+
def _makeSmallData(aList, rh_info)
|
455
|
+
file = rh_info[:fileh]
|
456
|
+
iSmBlk = 0
|
457
|
+
sRes = ''
|
458
|
+
|
459
|
+
aList.each do |pps|
|
460
|
+
#1. Make SBD, small data string
|
461
|
+
if pps.type == PPS_TYPE_FILE
|
462
|
+
next if pps.size <= 0
|
463
|
+
if pps.size < rh_info[:small_size]
|
464
|
+
iSmbCnt = pps.size / rh_info[:small_block_size]
|
465
|
+
iSmbCnt += 1 if pps.size % rh_info[:small_block_size] > 0
|
466
|
+
#1.1 Add to SBD
|
467
|
+
0.upto(iSmbCnt-1-1) do |i|
|
468
|
+
file.write([i + iSmBlk+1].pack("V"))
|
469
|
+
end
|
470
|
+
file.write([-2].pack("V"))
|
471
|
+
|
472
|
+
#1.2 Add to Data String(this will be written for RootEntry)
|
473
|
+
#Check for update
|
474
|
+
if pps.pps_file
|
475
|
+
pps.pps_file.seek(0) #To The Top
|
476
|
+
while sBuff = pps.pps_file.read(4096)
|
477
|
+
sRes << sBuff
|
478
|
+
end
|
479
|
+
else
|
480
|
+
sRes << pps.data
|
481
|
+
end
|
482
|
+
if pps.size % rh_info[:small_block_size] > 0
|
483
|
+
cnt = rh_info[:small_block_size] - (pps.size % rh_info[:small_block_size])
|
484
|
+
sRes << "\0" * cnt
|
485
|
+
end
|
486
|
+
#1.3 Set for PPS
|
487
|
+
pps.start_block = iSmBlk
|
488
|
+
iSmBlk += iSmbCnt
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
iSbCnt = rh_info[:big_block_size] / LONG_INT_SIZE
|
493
|
+
file.write([-1].pack("V") * (iSbCnt - (iSmBlk % iSbCnt))) if iSmBlk % iSbCnt > 0
|
494
|
+
#2. Write SBD with adjusting length for block
|
495
|
+
return sRes
|
496
|
+
end
|
497
|
+
private :_makeSmallData
|
498
|
+
|
499
|
+
def _savePpsWk(rh_info)
|
500
|
+
#1. Write PPS
|
501
|
+
file = rh_info[:fileh]
|
502
|
+
file.write(
|
503
|
+
@name +
|
504
|
+
("\x00" * (64 - @name.length)) + #64
|
505
|
+
[@name.length + 2].pack("v") + #66
|
506
|
+
[@type].pack("c") + #67
|
507
|
+
[0x00].pack("c") + #UK #68
|
508
|
+
[@prev_pps].pack("V") + #Prev #72
|
509
|
+
[@next_pps].pack("V") + #Next #76
|
510
|
+
[@dir_pps].pack("V") + #Dir #80
|
511
|
+
"\x00\x09\x02\x00" + #84
|
512
|
+
"\x00\x00\x00\x00" + #88
|
513
|
+
"\xc0\x00\x00\x00" + #92
|
514
|
+
"\x00\x00\x00\x46" + #96
|
515
|
+
"\x00\x00\x00\x00" + #100
|
516
|
+
localDate2OLE(@time_1st) + #108
|
517
|
+
localDate2OLE(@time_2nd) #116
|
518
|
+
)
|
519
|
+
if @start_block != 0
|
520
|
+
file.write([@start_block].pack('V'))
|
521
|
+
else
|
522
|
+
file.write([0].pack('V'))
|
523
|
+
end
|
524
|
+
if @size != 0 #124
|
525
|
+
file.write([@size].pack('V'))
|
526
|
+
else
|
527
|
+
file.write([0].pack('V'))
|
528
|
+
end
|
529
|
+
file.write([0].pack('V')) #128
|
530
|
+
end
|
531
|
+
protected :_savePpsWk
|
532
|
+
end
|
533
|
+
|
534
|
+
class OLEStorageLitePPSRoot < OLEStorageLitePPS #:nodoc:
|
535
|
+
def initialize(raTime1st, raTime2nd, raChild)
|
536
|
+
super(
|
537
|
+
nil,
|
538
|
+
asc2ucs('Root Entry'),
|
539
|
+
PPS_TYPE_ROOT,
|
540
|
+
nil,
|
541
|
+
nil,
|
542
|
+
nil,
|
543
|
+
raTime1st,
|
544
|
+
raTime2nd,
|
545
|
+
nil,
|
546
|
+
nil,
|
547
|
+
nil,
|
548
|
+
raChild)
|
549
|
+
end
|
550
|
+
|
551
|
+
def save(sFile, bNoAs = nil, rh_info = nil)
|
552
|
+
#0.Initial Setting for saving
|
553
|
+
rh_info = Hash.new unless rh_info
|
554
|
+
if rh_info[:big_block_size]
|
555
|
+
rh_info[:big_block_size] = 2 ** adjust2(rh_info[:big_block_size])
|
556
|
+
else
|
557
|
+
rh_info[:big_block_size] = 2 ** 9
|
558
|
+
end
|
559
|
+
if rh_info[:small_block_size]
|
560
|
+
rh_info[:small_block_size] = 2 ** adjust2(rh_info[:small_block_size])
|
561
|
+
else
|
562
|
+
rh_info[:small_block_size] = 2 ** 6
|
563
|
+
end
|
564
|
+
rh_info[:small_size] = 0x1000
|
565
|
+
rh_info[:pps_size] = 0x80
|
566
|
+
|
567
|
+
close_file = true
|
568
|
+
|
569
|
+
#1.Open File
|
570
|
+
#1.1 sFile is Ref of scalar
|
571
|
+
if sFile.kind_of?(String)
|
572
|
+
rh_info[:fileh] = open(sFile, "wb")
|
573
|
+
else
|
574
|
+
rh_info[:fileh] = sFile.binmode
|
575
|
+
end
|
576
|
+
|
577
|
+
iBlk = 0
|
578
|
+
#1. Make an array of PPS (for Save)
|
579
|
+
aList=[]
|
580
|
+
if bNoAs
|
581
|
+
_savePpsSetPnt2([self], aList, rh_info)
|
582
|
+
else
|
583
|
+
_savePpsSetPnt([self], aList, rh_info)
|
584
|
+
end
|
585
|
+
iSBDcnt, iBBcnt, iPPScnt = _calcSize(aList, rh_info)
|
586
|
+
|
587
|
+
#2.Save Header
|
588
|
+
_saveHeader(rh_info, iSBDcnt, iBBcnt, iPPScnt)
|
589
|
+
|
590
|
+
#3.Make Small Data string (write SBD)
|
591
|
+
# Small Datas become RootEntry Data
|
592
|
+
@data = _makeSmallData(aList, rh_info)
|
593
|
+
|
594
|
+
#4. Write BB
|
595
|
+
iBBlk = iSBDcnt
|
596
|
+
_saveBigData(iBBlk, aList, rh_info)
|
597
|
+
|
598
|
+
#5. Write PPS
|
599
|
+
_savePps(aList, rh_info)
|
600
|
+
|
601
|
+
#6. Write BD and BDList and Adding Header informations
|
602
|
+
_saveBbd(iSBDcnt, iBBcnt, iPPScnt, rh_info)
|
603
|
+
|
604
|
+
#7.Close File
|
605
|
+
rh_info[:fileh].close if close_file
|
606
|
+
end
|
607
|
+
|
608
|
+
def _calcSize(aList, rh_info)
|
609
|
+
#0. Calculate Basic Setting
|
610
|
+
iSBDcnt, iBBcnt, iPPScnt = [0,0,0]
|
611
|
+
iSmallLen = 0
|
612
|
+
iSBcnt = 0
|
613
|
+
aList.each do |pps|
|
614
|
+
if pps.type == PPS_TYPE_FILE
|
615
|
+
pps.size = pps._datalen #Mod
|
616
|
+
if pps.size < rh_info[:small_size]
|
617
|
+
iSBcnt += pps.size / rh_info[:small_block_size]
|
618
|
+
iSBcnt += 1 if pps.size % rh_info[:small_block_size] > 0
|
619
|
+
else
|
620
|
+
iBBcnt += pps.size / rh_info[:big_block_size]
|
621
|
+
iBBcnt += 1 if pps.size % rh_info[:big_block_size] > 0
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
iSmallLen = iSBcnt * rh_info[:small_block_size]
|
626
|
+
iSlCnt = rh_info[:big_block_size] / LONG_INT_SIZE
|
627
|
+
iSBDcnt = iSBcnt / iSlCnt
|
628
|
+
iSBDcnt += 1 if iSBcnt % iSlCnt > 0
|
629
|
+
iBBcnt += iSmallLen / rh_info[:big_block_size]
|
630
|
+
iBBcnt += 1 if iSmallLen % rh_info[:big_block_size] > 0
|
631
|
+
iCnt = aList.size
|
632
|
+
iBdCnt = rh_info[:big_block_size] / PPS_SIZE
|
633
|
+
iPPScnt = iCnt / iBdCnt
|
634
|
+
iPPScnt += 1 if iCnt % iBdCnt > 0
|
635
|
+
return [iSBDcnt, iBBcnt, iPPScnt]
|
636
|
+
end
|
637
|
+
private :_calcSize
|
638
|
+
|
639
|
+
def _adjust2(i2)
|
640
|
+
iWk = Math.log(i2)/Math.log(2)
|
641
|
+
return iWk > Integer(iWk) ? Integer(iWk) + 1 : iWk
|
642
|
+
end
|
643
|
+
private :_adjust2
|
644
|
+
|
645
|
+
def _saveHeader(rh_info, iSBDcnt, iBBcnt, iPPScnt)
|
646
|
+
file = rh_info[:fileh]
|
647
|
+
|
648
|
+
#0. Calculate Basic Setting
|
649
|
+
iBlCnt = rh_info[:big_block_size] / LONG_INT_SIZE
|
650
|
+
i1stBdL = (rh_info[:big_block_size] - 0x4C) / LONG_INT_SIZE
|
651
|
+
i1stBdMax = i1stBdL * iBlCnt - i1stBdL
|
652
|
+
iBdExL = 0
|
653
|
+
iAll = iBBcnt + iPPScnt + iSBDcnt
|
654
|
+
iAllW = iAll
|
655
|
+
iBdCntW = iAllW / iBlCnt
|
656
|
+
iBdCntW += 1 if iAllW % iBlCnt > 0
|
657
|
+
iBdCnt = 0
|
658
|
+
#0.1 Calculate BD count
|
659
|
+
iBlCnt -= 1 #the BlCnt is reduced in the count of the last sect is used for a pointer the next Bl
|
660
|
+
iBBleftover = iAll - i1stBdMax
|
661
|
+
if iAll >i1stBdMax
|
662
|
+
while true
|
663
|
+
iBdCnt = iBBleftover / iBlCnt
|
664
|
+
iBdCnt += 1 if iBBleftover % iBlCnt > 0
|
665
|
+
iBdExL = iBdCnt / iBlCnt
|
666
|
+
iBdExL += 1 if iBdCnt % iBlCnt > 0
|
667
|
+
iBBleftover += iBdExL
|
668
|
+
break if iBdCnt == iBBleftover / iBlCnt + (iBBleftover % iBlCnt > 0 ? 1 : 0)
|
669
|
+
end
|
670
|
+
end
|
671
|
+
iBdCnt += i1stBdL
|
672
|
+
#print "iBdCnt = iBdCnt \n"
|
673
|
+
|
674
|
+
#1.Save Header
|
675
|
+
file.write(
|
676
|
+
"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" +
|
677
|
+
"\x00\x00\x00\x00" * 4 +
|
678
|
+
[0x3b].pack("v") +
|
679
|
+
[0x03].pack("v") +
|
680
|
+
[-2].pack("v") +
|
681
|
+
[9].pack("v") +
|
682
|
+
[6].pack("v") +
|
683
|
+
[0].pack("v") +
|
684
|
+
"\x00\x00\x00\x00" * 2 +
|
685
|
+
[iBdCnt].pack("V") +
|
686
|
+
[iBBcnt+iSBDcnt].pack("V") + #ROOT START
|
687
|
+
[0].pack("V") +
|
688
|
+
[0x1000].pack("V") +
|
689
|
+
[0].pack("V") + #Small Block Depot
|
690
|
+
[1].pack("V")
|
691
|
+
)
|
692
|
+
#2. Extra BDList Start, Count
|
693
|
+
if iAll <= i1stBdMax
|
694
|
+
file.write(
|
695
|
+
[-2].pack("V") + #Extra BDList Start
|
696
|
+
[0].pack("V") #Extra BDList Count
|
697
|
+
)
|
698
|
+
else
|
699
|
+
file.write(
|
700
|
+
[iAll + iBdCnt].pack("V") +
|
701
|
+
[iBdExL].pack("V")
|
702
|
+
)
|
703
|
+
end
|
704
|
+
|
705
|
+
#3. BDList
|
706
|
+
cnt = i1stBdL
|
707
|
+
cnt = iBdCnt if iBdCnt < i1stBdL
|
708
|
+
0.upto(cnt-1) do |i|
|
709
|
+
file.write([iAll + i].pack("V"))
|
710
|
+
end
|
711
|
+
file.write([-1].pack("V") * (i1stBdL - cnt)) if cnt < i1stBdL
|
712
|
+
end
|
713
|
+
private :_saveHeader
|
714
|
+
|
715
|
+
def _saveBigData(iStBlk, aList, rh_info)
|
716
|
+
iRes = 0
|
717
|
+
file = rh_info[:fileh]
|
718
|
+
|
719
|
+
#1.Write Big (ge 0x1000) Data into Block
|
720
|
+
aList.each do |pps|
|
721
|
+
if pps.type != PPS_TYPE_DIR
|
722
|
+
#print "PPS: pps DEF:", defined(pps->{Data}), "\n"
|
723
|
+
pps.size = pps._datalen #Mod
|
724
|
+
if (pps.size >= rh_info[:small_size]) ||
|
725
|
+
((pps.type == PPS_TYPE_ROOT) && !pps.data.nil?)
|
726
|
+
#1.1 Write Data
|
727
|
+
#Check for update
|
728
|
+
if pps.pps_file
|
729
|
+
iLen = 0
|
730
|
+
pps.pps_file.seek(0, 0) #To The Top
|
731
|
+
while sBuff = pps.pps_file.read(4096)
|
732
|
+
iLen += sBuff.length
|
733
|
+
file.write(sBuff) #Check for update
|
734
|
+
end
|
735
|
+
else
|
736
|
+
file.write(pps.data)
|
737
|
+
end
|
738
|
+
if pps.size % rh_info[:big_block_size] > 0
|
739
|
+
file.write(
|
740
|
+
"\x00" *
|
741
|
+
(rh_info[:big_block_size] -
|
742
|
+
(pps.size % rh_info[:big_block_size]))
|
743
|
+
)
|
744
|
+
end
|
745
|
+
#1.2 Set For PPS
|
746
|
+
pps.start_block = iStBlk
|
747
|
+
iStBlk += pps.size / rh_info[:big_block_size]
|
748
|
+
iStBlk += 1 if pps.size % rh_info[:big_block_size] > 0
|
749
|
+
end
|
750
|
+
end
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
754
|
+
def _savePps(aList, rh_info)
|
755
|
+
#0. Initial
|
756
|
+
file = rh_info[:fileh]
|
757
|
+
#2. Save PPS
|
758
|
+
aList.each do |oItem|
|
759
|
+
oItem._savePpsWk(rh_info)
|
760
|
+
end
|
761
|
+
#3. Adjust for Block
|
762
|
+
iCnt = aList.size
|
763
|
+
iBCnt = rh_info[:big_block_size] / rh_info[:pps_size]
|
764
|
+
if iCnt % iBCnt > 0
|
765
|
+
file.write("\x00" * ((iBCnt - (iCnt % iBCnt)) * rh_info[:pps_size]))
|
766
|
+
end
|
767
|
+
return (iCnt / iBCnt) + ((iCnt % iBCnt) > 0 ? 1: 0)
|
768
|
+
end
|
769
|
+
private :_savePps
|
770
|
+
|
771
|
+
def _savePpsSetPnt(pps_array, aList, rh_info)
|
772
|
+
#1. make Array as Children-Relations
|
773
|
+
#1.1 if No Children
|
774
|
+
bpp=1
|
775
|
+
if pps_array.nil? || pps_array.size == 0
|
776
|
+
return 0xFFFFFFFF
|
777
|
+
#1.2 Just Only one
|
778
|
+
elsif pps_array.size == 1
|
779
|
+
aList << pps_array[0]
|
780
|
+
pps_array[0].no = aList.size - 1
|
781
|
+
pps_array[0].prev_pps = 0xFFFFFFFF
|
782
|
+
pps_array[0].next_pps = 0xFFFFFFFF
|
783
|
+
pps_array[0].dir_pps = _savePpsSetPnt(pps_array[0].child, aList, rh_info)
|
784
|
+
return pps_array[0].no
|
785
|
+
#1.3 Array
|
786
|
+
else
|
787
|
+
iCnt = pps_array.size
|
788
|
+
#1.3.1 Define Center
|
789
|
+
iPos = Integer(iCnt / 2.0) #$iCnt
|
790
|
+
|
791
|
+
aList.push(pps_array[iPos])
|
792
|
+
pps_array[iPos].no = aList.size - 1
|
793
|
+
|
794
|
+
aWk = pps_array.dup
|
795
|
+
#1.3.2 Devide a array into Previous,Next
|
796
|
+
aPrev = aWk[0, iPos]
|
797
|
+
aWk[0..iPos-1] = nil
|
798
|
+
aNext = aWk[1, iCnt - iPos - 1]
|
799
|
+
aWk[1..(1 + iCnt - iPos -1 -1)] = nil
|
800
|
+
pps_array[iPos].prev_pps = _savePpsSetPnt(aPrev, aList, rh_info)
|
801
|
+
pps_array[iPos].next_pps = _savePpsSetPnt(aNext, aList, rh_info)
|
802
|
+
pps_array[iPos].dir_pps = _savePpsSetPnt(pps_array[iPos].child, aList, rh_info)
|
803
|
+
return pps_array[iPos].no
|
804
|
+
end
|
805
|
+
end
|
806
|
+
private :_savePpsSetPnt
|
807
|
+
|
808
|
+
def _savePpsSetPnt2(pps_array, aList, rh_info)
|
809
|
+
#1. make Array as Children-Relations
|
810
|
+
#1.1 if No Children
|
811
|
+
if pps_array.nil? || pps_array.size == 0
|
812
|
+
return 0xFFFFFFFF
|
813
|
+
#1.2 Just Only one
|
814
|
+
elsif pps_array.size == 1
|
815
|
+
aList << pps_array[0]
|
816
|
+
pps_array[0].no = aList.size - 1
|
817
|
+
pps_array[0].prev_pps = 0xFFFFFFFF
|
818
|
+
pps_array[0].next_pps = 0xFFFFFFFF
|
819
|
+
pps_array[0].dir_pps = _savePpsSetPnt2(pps_array[0].child, aList, rh_info)
|
820
|
+
return pps_array[0].no
|
821
|
+
#1.3 Array
|
822
|
+
else
|
823
|
+
iCnt = pps_array.size
|
824
|
+
#1.3.1 Define Center
|
825
|
+
iPos = 0 #int($iCnt/ 2); #$iCnt
|
826
|
+
|
827
|
+
aWk = pps_array.dup
|
828
|
+
aPrev = aWk[1, 1]
|
829
|
+
aWk[1..1] = nil
|
830
|
+
aNext = aWk[1..aWk.size] #, $iCnt - $iPos -1);
|
831
|
+
pps_array[iPos].prev_pps = _savePpsSetPnt2(pps_array, aList, rh_info)
|
832
|
+
aList.push(pps_array[iPos])
|
833
|
+
pps_array[iPos].no = aList.size
|
834
|
+
|
835
|
+
#1.3.2 Devide a array into Previous,Next
|
836
|
+
pps_array[iPos].next_pps = _savePpsSetPnt2(aNext, aList, rh_info)
|
837
|
+
pps_array[iPos].dir_pps = _savePpsSetPnt2(pps_array[iPos].child, aList, rh_info)
|
838
|
+
return pps_array[iPos].no
|
839
|
+
end
|
840
|
+
end
|
841
|
+
private :_savePpsSetPnt2
|
842
|
+
|
843
|
+
def _saveBbd(iSbdSize, iBsize, iPpsCnt, rh_info)
|
844
|
+
file = rh_info[:fileh]
|
845
|
+
#0. Calculate Basic Setting
|
846
|
+
iBbCnt = rh_info[:big_block_size] / LONG_INT_SIZE
|
847
|
+
iBlCnt = iBbCnt - 1
|
848
|
+
i1stBdL = (rh_info[:big_block_size] - 0x4C) / LONG_INT_SIZE
|
849
|
+
i1stBdMax = i1stBdL * iBbCnt - i1stBdL
|
850
|
+
iBdExL = 0
|
851
|
+
iAll = iBsize + iPpsCnt + iSbdSize
|
852
|
+
iAllW = iAll
|
853
|
+
iBdCntW = iAllW / iBbCnt
|
854
|
+
iBdCntW += 1 if iAllW % iBbCnt > 0
|
855
|
+
iBdCnt = 0
|
856
|
+
#0.1 Calculate BD count
|
857
|
+
iBBleftover = iAll - i1stBdMax
|
858
|
+
if iAll >i1stBdMax
|
859
|
+
while true
|
860
|
+
iBdCnt = iBBleftover / iBlCnt
|
861
|
+
iBdCnt += 1 if iBBleftover % iBlCnt > 0
|
862
|
+
|
863
|
+
iBdExL = iBdCnt / iBlCnt
|
864
|
+
iBdExL += 1 if iBdCnt % iBlCnt > 0
|
865
|
+
iBBleftover = iBBleftover + iBdExL
|
866
|
+
break if iBdCnt == (iBBleftover / iBlCnt + ((iBBleftover % iBlCnt) > 0 ? 1: 0))
|
867
|
+
end
|
868
|
+
end
|
869
|
+
iAllW += iBdExL
|
870
|
+
iBdCnt += i1stBdL
|
871
|
+
#print "iBdCnt = iBdCnt \n"
|
872
|
+
|
873
|
+
#1. Making BD
|
874
|
+
#1.1 Set for SBD
|
875
|
+
if iSbdSize > 0
|
876
|
+
0.upto(iSbdSize-1-1) do |i|
|
877
|
+
file.write([i + 1].pack('V'))
|
878
|
+
end
|
879
|
+
file.write([-2].pack('V'))
|
880
|
+
end
|
881
|
+
#1.2 Set for B
|
882
|
+
0.upto(iBsize-1-1) do |i|
|
883
|
+
file.write([i + iSbdSize + 1].pack('V'))
|
884
|
+
end
|
885
|
+
file.write([-2].pack('V'))
|
886
|
+
|
887
|
+
#1.3 Set for PPS
|
888
|
+
0.upto(iPpsCnt-1-1) do |i|
|
889
|
+
file.write([i+iSbdSize+iBsize+1].pack("V"))
|
890
|
+
end
|
891
|
+
file.write([-2].pack('V'))
|
892
|
+
#1.4 Set for BBD itself ( 0xFFFFFFFD : BBD)
|
893
|
+
0.upto(iBdCnt-1) do |i|
|
894
|
+
file.write([0xFFFFFFFD].pack("V"))
|
895
|
+
end
|
896
|
+
#1.5 Set for ExtraBDList
|
897
|
+
0.upto(iBdExL-1) do |i|
|
898
|
+
file.write([0xFFFFFFFC].pack("V"))
|
899
|
+
end
|
900
|
+
#1.6 Adjust for Block
|
901
|
+
if (iAllW + iBdCnt) % iBbCnt > 0
|
902
|
+
file.write([-1].pack('V') * (iBbCnt - ((iAllW + iBdCnt) % iBbCnt)))
|
903
|
+
end
|
904
|
+
#2.Extra BDList
|
905
|
+
if iBdCnt > i1stBdL
|
906
|
+
iN = 0
|
907
|
+
iNb = 0
|
908
|
+
i1stBdL.upto(iBdCnt-1) do |i|
|
909
|
+
if iN >= iBbCnt-1
|
910
|
+
iN = 0
|
911
|
+
iNb += 1
|
912
|
+
file.write([iAll+iBdCnt+iNb].pack("V"))
|
913
|
+
end
|
914
|
+
file.write([iBsize+iSbdSize+iPpsCnt+i].pack("V"))
|
915
|
+
iN += 1
|
916
|
+
end
|
917
|
+
if (iBdCnt-i1stBdL) % (iBbCnt-1) > 0
|
918
|
+
file.write([-1].pack("V") * ((iBbCnt-1) - ((iBdCnt-i1stBdL) % (iBbCnt-1))))
|
919
|
+
end
|
920
|
+
file.write([-2].pack('V'))
|
921
|
+
end
|
922
|
+
end
|
923
|
+
end
|
924
|
+
|
925
|
+
class OLEStorageLitePPSFile < OLEStorageLitePPS #:nodoc:
|
926
|
+
def initialize(sNm, data = '')
|
927
|
+
super(
|
928
|
+
nil,
|
929
|
+
sNm || '',
|
930
|
+
PPS_TYPE_FILE,
|
931
|
+
nil,
|
932
|
+
nil,
|
933
|
+
nil,
|
934
|
+
nil,
|
935
|
+
nil,
|
936
|
+
nil,
|
937
|
+
nil,
|
938
|
+
data || '',
|
939
|
+
nil
|
940
|
+
)
|
941
|
+
end
|
942
|
+
|
943
|
+
def set_file(sFile = '')
|
944
|
+
if sFile.nil? or sFile == ''
|
945
|
+
@pps_file = Tempfile.new('OLEStorageLitePPSFile')
|
946
|
+
elsif sFile.kind_of?(IO) || sFile.kind_of?(StringIO)
|
947
|
+
@pps_file = sFile
|
948
|
+
elsif sFile.kind_of?(String)
|
949
|
+
#File Name
|
950
|
+
@pps_file = open(sFile, "r+")
|
951
|
+
return nil unless @pps_file
|
952
|
+
else
|
953
|
+
return nil
|
954
|
+
end
|
955
|
+
@pps_file.seek(0, IO::SEEK_END)
|
956
|
+
@pps_file.binmode
|
957
|
+
end
|
958
|
+
|
959
|
+
def append (data)
|
960
|
+
return if data.nil?
|
961
|
+
if @pps_file
|
962
|
+
@pps_file << data
|
963
|
+
@pps_file.flush
|
964
|
+
else
|
965
|
+
@data << data
|
966
|
+
end
|
967
|
+
end
|
968
|
+
end
|