WriteExcel 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/examples/a_simple.rb +42 -0
- data/examples/autofilters.rb +266 -0
- data/examples/bigfile.rb +30 -0
- data/examples/copyformat.rb +51 -0
- data/examples/data_validate.rb +278 -0
- data/examples/date_time.rb +86 -0
- data/examples/demo.rb +118 -0
- data/examples/diag_border.rb +35 -0
- data/examples/formats.rb +489 -0
- data/examples/header.rb +136 -0
- data/examples/hidden.rb +28 -0
- data/examples/hyperlink.rb +42 -0
- data/examples/images.rb +52 -0
- data/examples/merge1.rb +39 -0
- data/examples/merge2.rb +44 -0
- data/examples/merge3.rb +65 -0
- data/examples/merge4.rb +82 -0
- data/examples/merge5.rb +79 -0
- data/examples/protection.rb +46 -0
- data/examples/regions.rb +52 -0
- data/examples/repeat.rb +42 -0
- data/examples/stats.rb +75 -0
- data/examples/stocks.rb +80 -0
- data/examples/tab_colors.rb +30 -0
- data/lib/WriteExcel.rb +30 -0
- data/lib/WriteExcel/biffwriter.rb +259 -0
- data/lib/WriteExcel/chart.rb +217 -0
- data/lib/WriteExcel/excelformula.y +138 -0
- data/lib/WriteExcel/excelformulaparser.rb +573 -0
- data/lib/WriteExcel/format.rb +1108 -0
- data/lib/WriteExcel/formula.rb +986 -0
- data/lib/WriteExcel/olewriter.rb +322 -0
- data/lib/WriteExcel/properties.rb +250 -0
- data/lib/WriteExcel/storage_lite.rb +590 -0
- data/lib/WriteExcel/workbook.rb +2602 -0
- data/lib/WriteExcel/worksheet.rb +6378 -0
- data/spec/WriteExcel_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- data/test/tc_all.rb +31 -0
- data/test/tc_biff.rb +104 -0
- data/test/tc_chart.rb +22 -0
- data/test/tc_example_match.rb +1280 -0
- data/test/tc_format.rb +1264 -0
- data/test/tc_formula.rb +63 -0
- data/test/tc_ole.rb +110 -0
- data/test/tc_storage_lite.rb +102 -0
- data/test/tc_workbook.rb +115 -0
- data/test/tc_worksheet.rb +115 -0
- data/test/test_00_IEEE_double.rb +14 -0
- data/test/test_01_add_worksheet.rb +12 -0
- data/test/test_02_merge_formats.rb +58 -0
- data/test/test_04_dimensions.rb +397 -0
- data/test/test_05_rows.rb +182 -0
- data/test/test_06_extsst.rb +80 -0
- data/test/test_11_date_time.rb +484 -0
- data/test/test_12_date_only.rb +506 -0
- data/test/test_13_date_seconds.rb +486 -0
- data/test/test_21_escher.rb +629 -0
- data/test/test_22_mso_drawing_group.rb +739 -0
- data/test/test_23_note.rb +78 -0
- data/test/test_24_txo.rb +80 -0
- data/test/test_26_autofilter.rb +327 -0
- data/test/test_27_autofilter.rb +144 -0
- data/test/test_28_autofilter.rb +174 -0
- data/test/test_29_process_jpg.rb +131 -0
- data/test/test_30_validation_dval.rb +82 -0
- data/test/test_31_validation_dv_strings.rb +131 -0
- data/test/test_32_validation_dv_formula.rb +211 -0
- data/test/test_40_property_types.rb +191 -0
- data/test/test_41_properties.rb +238 -0
- data/test/test_42_set_properties.rb +430 -0
- data/test/ts_all.rb +34 -0
- metadata +154 -0
@@ -0,0 +1,590 @@
|
|
1
|
+
#require 'tempfile'
|
2
|
+
#require 'stringio'
|
3
|
+
|
4
|
+
class OLEStorageLite
|
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
|
+
def asc2ucs(str)
|
13
|
+
str.split(//).join("\0") + "\0"
|
14
|
+
end
|
15
|
+
|
16
|
+
def ucs2asc(str)
|
17
|
+
ary = str.unpack('v*').map { |s| [s].pack('c')}
|
18
|
+
ary.join('')
|
19
|
+
end
|
20
|
+
|
21
|
+
def localDate2OLE(localtime)
|
22
|
+
return "\x00" * 8 unless localtime
|
23
|
+
|
24
|
+
# Convert from localtime (actually gmtime) to seconds.
|
25
|
+
args = localtime.reverse
|
26
|
+
args[0] += 1900 # year
|
27
|
+
args[1] += 1 # month
|
28
|
+
time = Time.gm(*args)
|
29
|
+
|
30
|
+
# Add the number of seconds between the 1601 and 1970 epochs.
|
31
|
+
time = time.to_i + 11644473600
|
32
|
+
|
33
|
+
# The FILETIME seconds are in units of 100 nanoseconds.
|
34
|
+
nanoseconds = time * 1E7
|
35
|
+
|
36
|
+
# Pack the total nanoseconds into 64 bits...
|
37
|
+
hi, lo = nanoseconds.divmod 1 << 32
|
38
|
+
|
39
|
+
oletime = [lo, hi].pack("VV")
|
40
|
+
return oletime
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class OLEStorageLitePPS < OLEStorageLite
|
45
|
+
attr_accessor :no, :name, :type, :prev_pps, :next_pps, :dir_pps
|
46
|
+
attr_accessor :time_1st, :time_2nd, :start_block, :size, :data, :child
|
47
|
+
attr_reader :pps_file
|
48
|
+
|
49
|
+
def initialize(iNo, sNm, iType, iPrev, iNext, iDir,
|
50
|
+
raTime1st, raTime2nd, iStart, iSize, sData, raChild)
|
51
|
+
@no = iNo
|
52
|
+
@name = sNm
|
53
|
+
@type = iType
|
54
|
+
@prev_pps = iPrev
|
55
|
+
@next_pps = iNext
|
56
|
+
@dir_pps = iDir
|
57
|
+
@time_1st = raTime1st
|
58
|
+
@time_2nd = raTime2nd
|
59
|
+
@start_block = iStart
|
60
|
+
@size = iSize
|
61
|
+
@data = sData
|
62
|
+
@child = raChild
|
63
|
+
@pps_file = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def _datalen
|
67
|
+
return 0 if @data.nil?
|
68
|
+
if @pps_file
|
69
|
+
return @pps_file.lstat.size
|
70
|
+
else
|
71
|
+
return @data.size
|
72
|
+
end
|
73
|
+
end
|
74
|
+
protected :_datalen
|
75
|
+
|
76
|
+
def _makeSmallData(aList, rh_info)
|
77
|
+
file = rh_info[:fileh]
|
78
|
+
iSmBlk = 0
|
79
|
+
sRes = ''
|
80
|
+
|
81
|
+
aList.each do |pps|
|
82
|
+
#1. Make SBD, small data string
|
83
|
+
if pps.type == PPS_TYPE_FILE
|
84
|
+
next if pps.size <= 0
|
85
|
+
if pps.size < rh_info[:small_size]
|
86
|
+
iSmbCnt = pps.size / rh_info[:small_block_size]
|
87
|
+
iSmbCnt += 1 if pps.size % rh_info[:small_block_size] > 0
|
88
|
+
#1.1 Add to SBD
|
89
|
+
0.upto(iSmbCnt-1-1) do |i|
|
90
|
+
file.write([i + iSmBlk+1].pack("V"))
|
91
|
+
end
|
92
|
+
file.write([-2].pack("V"))
|
93
|
+
|
94
|
+
#1.2 Add to Data String(this will be written for RootEntry)
|
95
|
+
#Check for update
|
96
|
+
if pps.pps_file
|
97
|
+
pps.pps_file.seek(0) #To The Top
|
98
|
+
while sBuff = pps.pps_file.read(4096)
|
99
|
+
sRes << sBuff
|
100
|
+
end
|
101
|
+
else
|
102
|
+
sRes << pps.data
|
103
|
+
end
|
104
|
+
if pps.size % rh_info[:small_block_size] > 0
|
105
|
+
cnt = rh_info[:small_block_size] - (pps.size % rh_info[:small_block_size])
|
106
|
+
sRes << "\0" * cnt
|
107
|
+
end
|
108
|
+
#1.3 Set for PPS
|
109
|
+
pps.start_block = iSmBlk
|
110
|
+
iSmBlk += iSmbCnt
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
iSbCnt = rh_info[:big_block_size] / LONG_INT_SIZE
|
115
|
+
file.write([-1].pack("V") * (iSbCnt - (iSmBlk % iSbCnt))) if iSmBlk % iSbCnt > 0
|
116
|
+
#2. Write SBD with adjusting length for block
|
117
|
+
return sRes
|
118
|
+
end
|
119
|
+
private :_makeSmallData
|
120
|
+
|
121
|
+
def _savePpsWk(rh_info)
|
122
|
+
#1. Write PPS
|
123
|
+
file = rh_info[:fileh]
|
124
|
+
file.write(
|
125
|
+
@name +
|
126
|
+
("\x00" * (64 - @name.length)) + #64
|
127
|
+
[@name.length + 2].pack("v") + #66
|
128
|
+
[@type].pack("c") + #67
|
129
|
+
[0x00].pack("c") + #UK #68
|
130
|
+
[@prev_pps].pack("V") + #Prev #72
|
131
|
+
[@next_pps].pack("V") + #Next #76
|
132
|
+
[@dir_pps].pack("V") + #Dir #80
|
133
|
+
"\x00\x09\x02\x00" + #84
|
134
|
+
"\x00\x00\x00\x00" + #88
|
135
|
+
"\xc0\x00\x00\x00" + #92
|
136
|
+
"\x00\x00\x00\x46" + #96
|
137
|
+
"\x00\x00\x00\x00" + #100
|
138
|
+
localDate2OLE(@time_1st) + #108
|
139
|
+
localDate2OLE(@time_2nd) #116
|
140
|
+
)
|
141
|
+
if @start_block != 0
|
142
|
+
file.write([@start_block].pack('V'))
|
143
|
+
else
|
144
|
+
file.write([0].pack('V'))
|
145
|
+
end
|
146
|
+
if @size != 0 #124
|
147
|
+
file.write([@size].pack('V'))
|
148
|
+
else
|
149
|
+
file.write([0].pack('V'))
|
150
|
+
end
|
151
|
+
file.write([0].pack('V')) #128
|
152
|
+
end
|
153
|
+
protected :_savePpsWk
|
154
|
+
end
|
155
|
+
|
156
|
+
class OLEStorageLitePPSRoot < OLEStorageLitePPS
|
157
|
+
def initialize(raTime1st, raTime2nd, raChild)
|
158
|
+
super(
|
159
|
+
nil,
|
160
|
+
asc2ucs('Root Entry'),
|
161
|
+
PPS_TYPE_ROOT,
|
162
|
+
nil,
|
163
|
+
nil,
|
164
|
+
nil,
|
165
|
+
raTime1st,
|
166
|
+
raTime2nd,
|
167
|
+
nil,
|
168
|
+
nil,
|
169
|
+
nil,
|
170
|
+
raChild)
|
171
|
+
end
|
172
|
+
|
173
|
+
def save(sFile, bNoAs = nil, rh_info = nil)
|
174
|
+
#0.Initial Setting for saving
|
175
|
+
rh_info = Hash.new unless rh_info
|
176
|
+
if rh_info[:big_block_size]
|
177
|
+
rh_info[:big_block_size] = 2 ** adjust2(rh_info[:big_block_size])
|
178
|
+
else
|
179
|
+
rh_info[:big_block_size] = 2 ** 9
|
180
|
+
end
|
181
|
+
if rh_info[:small_block_size]
|
182
|
+
rh_info[:small_block_size] = 2 ** adjust2(rh_info[:small_block_size])
|
183
|
+
else
|
184
|
+
rh_info[:small_block_size] = 2 ** 6
|
185
|
+
end
|
186
|
+
rh_info[:small_size] = 0x1000
|
187
|
+
rh_info[:pps_size] = 0x80
|
188
|
+
|
189
|
+
close_file = true
|
190
|
+
|
191
|
+
#1.Open File
|
192
|
+
#1.1 sFile is Ref of scalar
|
193
|
+
if sFile.kind_of?(String)
|
194
|
+
rh_info[:fileh] = open(sFile, "wb")
|
195
|
+
else
|
196
|
+
rh_info[:fileh] = sFile.binmode
|
197
|
+
end
|
198
|
+
|
199
|
+
iBlk = 0
|
200
|
+
#1. Make an array of PPS (for Save)
|
201
|
+
aList=[]
|
202
|
+
if bNoAs
|
203
|
+
_savePpsSetPnt2([self], aList, rh_info)
|
204
|
+
else
|
205
|
+
_savePpsSetPnt([self], aList, rh_info)
|
206
|
+
end
|
207
|
+
iSBDcnt, iBBcnt, iPPScnt = _calcSize(aList, rh_info)
|
208
|
+
|
209
|
+
#2.Save Header
|
210
|
+
_saveHeader(rh_info, iSBDcnt, iBBcnt, iPPScnt)
|
211
|
+
|
212
|
+
#3.Make Small Data string (write SBD)
|
213
|
+
# Small Datas become RootEntry Data
|
214
|
+
@data = _makeSmallData(aList, rh_info)
|
215
|
+
|
216
|
+
#4. Write BB
|
217
|
+
iBBlk = iSBDcnt
|
218
|
+
_saveBigData(iBBlk, aList, rh_info)
|
219
|
+
|
220
|
+
#5. Write PPS
|
221
|
+
_savePps(aList, rh_info)
|
222
|
+
|
223
|
+
#6. Write BD and BDList and Adding Header informations
|
224
|
+
_saveBbd(iSBDcnt, iBBcnt, iPPScnt, rh_info)
|
225
|
+
|
226
|
+
#7.Close File
|
227
|
+
return rh_info[:fileh].close if close_file != 0
|
228
|
+
end
|
229
|
+
|
230
|
+
def _calcSize(aList, rh_info)
|
231
|
+
#0. Calculate Basic Setting
|
232
|
+
iSBDcnt, iBBcnt, iPPScnt = [0,0,0]
|
233
|
+
iSmallLen = 0
|
234
|
+
iSBcnt = 0
|
235
|
+
aList.each do |pps|
|
236
|
+
if pps.type == PPS_TYPE_FILE
|
237
|
+
pps.size = pps._datalen #Mod
|
238
|
+
if pps.size < rh_info[:small_size]
|
239
|
+
iSBcnt += pps.size / rh_info[:small_block_size]
|
240
|
+
iSBcnt += 1 if pps.size % rh_info[:small_block_size] > 0
|
241
|
+
else
|
242
|
+
iBBcnt += pps.size / rh_info[:big_block_size]
|
243
|
+
iBBcnt += 1 if pps.size % rh_info[:big_block_size] > 0
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
iSmallLen = iSBcnt * rh_info[:small_block_size]
|
248
|
+
iSlCnt = rh_info[:big_block_size] / LONG_INT_SIZE
|
249
|
+
iSBDcnt = iSBcnt / iSlCnt
|
250
|
+
iSBDcnt += 1 if iSBcnt % iSlCnt > 0
|
251
|
+
iBBcnt += iSmallLen / rh_info[:big_block_size]
|
252
|
+
iBBcnt += 1 if iSmallLen % rh_info[:big_block_size] > 0
|
253
|
+
iCnt = aList.size
|
254
|
+
iBdCnt = rh_info[:big_block_size] / PPS_SIZE
|
255
|
+
iPPScnt = iCnt / iBdCnt
|
256
|
+
iPPScnt += 1 if iCnt % iBdCnt > 0
|
257
|
+
return [iSBDcnt, iBBcnt, iPPScnt]
|
258
|
+
end
|
259
|
+
private :_calcSize
|
260
|
+
|
261
|
+
def _adjust2(i2)
|
262
|
+
iWk = Math.log(i2)/Math.log(2)
|
263
|
+
return iWk > Integer(iWk) ? Integer(iWk) + 1 : iWk
|
264
|
+
end
|
265
|
+
private :_adjust2
|
266
|
+
|
267
|
+
def _saveHeader(rh_info, iSBDcnt, iBBcnt, iPPScnt)
|
268
|
+
file = rh_info[:fileh]
|
269
|
+
|
270
|
+
#0. Calculate Basic Setting
|
271
|
+
iBlCnt = rh_info[:big_block_size] / LONG_INT_SIZE
|
272
|
+
i1stBdL = (rh_info[:big_block_size] - 0x4C) / LONG_INT_SIZE
|
273
|
+
i1stBdMax = i1stBdL * iBlCnt - i1stBdL
|
274
|
+
iBdExL = 0
|
275
|
+
iAll = iBBcnt + iPPScnt + iSBDcnt
|
276
|
+
iAllW = iAll
|
277
|
+
iBdCntW = iAllW / iBlCnt
|
278
|
+
iBdCntW += 1 if iAllW % iBlCnt > 0
|
279
|
+
iBdCnt = 0
|
280
|
+
#0.1 Calculate BD count
|
281
|
+
iBlCnt -= 1 #the BlCnt is reduced in the count of the last sect is used for a pointer the next Bl
|
282
|
+
iBBleftover = iAll - i1stBdMax
|
283
|
+
if iAll >i1stBdMax
|
284
|
+
while true
|
285
|
+
iBdCnt = iBBleftover / iBlCnt
|
286
|
+
iBdCnt += 1 if iBBleftover % iBlCnt > 0
|
287
|
+
iBdExL = iBdCnt / iBlCnt
|
288
|
+
iBdExL += 1 if iBdCnt % iBlCnt > 0
|
289
|
+
iBBleftover += iBdExL
|
290
|
+
break if iBdCnt == iBBleftover / iBlCnt + (iBBleftover % iBlCnt > 0 ? 1 : 0)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
iBdCnt += i1stBdL
|
294
|
+
#print "iBdCnt = iBdCnt \n"
|
295
|
+
|
296
|
+
#1.Save Header
|
297
|
+
file.write(
|
298
|
+
"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" +
|
299
|
+
"\x00\x00\x00\x00" * 4 +
|
300
|
+
[0x3b].pack("v") +
|
301
|
+
[0x03].pack("v") +
|
302
|
+
[-2].pack("v") +
|
303
|
+
[9].pack("v") +
|
304
|
+
[6].pack("v") +
|
305
|
+
[0].pack("v") +
|
306
|
+
"\x00\x00\x00\x00" * 2 +
|
307
|
+
[iBdCnt].pack("V") +
|
308
|
+
[iBBcnt+iSBDcnt].pack("V") + #ROOT START
|
309
|
+
[0].pack("V") +
|
310
|
+
[0x1000].pack("V") +
|
311
|
+
[0].pack("V") + #Small Block Depot
|
312
|
+
[1].pack("V")
|
313
|
+
)
|
314
|
+
#2. Extra BDList Start, Count
|
315
|
+
if iAll <= i1stBdMax
|
316
|
+
file.write(
|
317
|
+
[-2].pack("V") + #Extra BDList Start
|
318
|
+
[0].pack("V") #Extra BDList Count
|
319
|
+
)
|
320
|
+
else
|
321
|
+
file.write(
|
322
|
+
[iAll + iBdCnt].pack("V") +
|
323
|
+
[iBdExL].pack("V")
|
324
|
+
)
|
325
|
+
end
|
326
|
+
|
327
|
+
#3. BDList
|
328
|
+
cnt = i1stBdL
|
329
|
+
cnt = iBdCnt if iBdCnt < i1stBdL
|
330
|
+
0.upto(cnt-1) do |i|
|
331
|
+
file.write([iAll + i].pack("V"))
|
332
|
+
end
|
333
|
+
file.write([-1].pack("V") * (i1stBdL - cnt)) if cnt < i1stBdL
|
334
|
+
end
|
335
|
+
private :_saveHeader
|
336
|
+
|
337
|
+
def _saveBigData(iStBlk, aList, rh_info)
|
338
|
+
iRes = 0
|
339
|
+
file = rh_info[:fileh]
|
340
|
+
|
341
|
+
#1.Write Big (ge 0x1000) Data into Block
|
342
|
+
aList.each do |pps|
|
343
|
+
if pps.type != PPS_TYPE_DIR
|
344
|
+
#print "PPS: pps DEF:", defined(pps->{Data}), "\n"
|
345
|
+
pps.size = pps._datalen #Mod
|
346
|
+
if (pps.size >= rh_info[:small_size]) ||
|
347
|
+
((pps.type == PPS_TYPE_ROOT) && !pps.data.nil?)
|
348
|
+
#1.1 Write Data
|
349
|
+
#Check for update
|
350
|
+
if pps.pps_file
|
351
|
+
iLen = 0
|
352
|
+
pps.pps_file.seek(0, 0) #To The Top
|
353
|
+
while sBuff = pps.pps_file.read(4096)
|
354
|
+
iLen += sBuff.length
|
355
|
+
file.write(sBuff) #Check for update
|
356
|
+
end
|
357
|
+
else
|
358
|
+
file.write(pps.data)
|
359
|
+
end
|
360
|
+
if pps.size % rh_info[:big_block_size] > 0
|
361
|
+
file.write(
|
362
|
+
"\x00" *
|
363
|
+
(rh_info[:big_block_size] -
|
364
|
+
(pps.size % rh_info[:big_block_size]))
|
365
|
+
)
|
366
|
+
end
|
367
|
+
#1.2 Set For PPS
|
368
|
+
pps.start_block = iStBlk
|
369
|
+
iStBlk += pps.size / rh_info[:big_block_size]
|
370
|
+
iStBlk += 1 if pps.size % rh_info[:big_block_size] > 0
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def _savePps(aList, rh_info)
|
377
|
+
#0. Initial
|
378
|
+
file = rh_info[:fileh]
|
379
|
+
#2. Save PPS
|
380
|
+
aList.each do |oItem|
|
381
|
+
oItem._savePpsWk(rh_info)
|
382
|
+
end
|
383
|
+
#3. Adjust for Block
|
384
|
+
iCnt = aList.size
|
385
|
+
iBCnt = rh_info[:big_block_size] / rh_info[:pps_size]
|
386
|
+
if iCnt % iBCnt > 0
|
387
|
+
file.write("\x00" * ((iBCnt - (iCnt % iBCnt)) * rh_info[:pps_size]))
|
388
|
+
end
|
389
|
+
return (iCnt / iBCnt) + ((iCnt % iBCnt) > 0 ? 1: 0)
|
390
|
+
end
|
391
|
+
private :_savePps
|
392
|
+
|
393
|
+
def _savePpsSetPnt(pps_array, aList, rh_info)
|
394
|
+
#1. make Array as Children-Relations
|
395
|
+
#1.1 if No Children
|
396
|
+
bpp=1
|
397
|
+
if pps_array.nil? || pps_array.size == 0
|
398
|
+
return 0xFFFFFFFF
|
399
|
+
#1.2 Just Only one
|
400
|
+
elsif pps_array.size == 1
|
401
|
+
aList << pps_array[0]
|
402
|
+
pps_array[0].no = aList.size - 1
|
403
|
+
pps_array[0].prev_pps = 0xFFFFFFFF
|
404
|
+
pps_array[0].next_pps = 0xFFFFFFFF
|
405
|
+
pps_array[0].dir_pps = _savePpsSetPnt(pps_array[0].child, aList, rh_info)
|
406
|
+
return pps_array[0].no
|
407
|
+
#1.3 Array
|
408
|
+
else
|
409
|
+
iCnt = pps_array.size
|
410
|
+
#1.3.1 Define Center
|
411
|
+
iPos = Integer(iCnt / 2.0) #$iCnt
|
412
|
+
|
413
|
+
aList.push(pps_array[iPos])
|
414
|
+
pps_array[iPos].no = aList.size - 1
|
415
|
+
|
416
|
+
aWk = pps_array.dup
|
417
|
+
#1.3.2 Devide a array into Previous,Next
|
418
|
+
aPrev = aWk[0, iPos]
|
419
|
+
aWk[0..iPos-1] = nil
|
420
|
+
aNext = aWk[1, iCnt - iPos - 1]
|
421
|
+
aWk[1..(1 + iCnt - iPos -1 -1)] = nil
|
422
|
+
pps_array[iPos].prev_pps = _savePpsSetPnt(aPrev, aList, rh_info)
|
423
|
+
pps_array[iPos].next_pps = _savePpsSetPnt(aNext, aList, rh_info)
|
424
|
+
pps_array[iPos].dir_pps = _savePpsSetPnt(pps_array[iPos].child, aList, rh_info)
|
425
|
+
return pps_array[iPos].no
|
426
|
+
end
|
427
|
+
end
|
428
|
+
private :_savePpsSetPnt
|
429
|
+
|
430
|
+
def _savePpsSetPnt2(pps_array, aList, rh_info)
|
431
|
+
#1. make Array as Children-Relations
|
432
|
+
#1.1 if No Children
|
433
|
+
if pps_array.nil? || pps_array.size == 0
|
434
|
+
return 0xFFFFFFFF
|
435
|
+
#1.2 Just Only one
|
436
|
+
elsif pps_array.size == 1
|
437
|
+
aList << pps_array[0]
|
438
|
+
pps_array[0].no = aList.size - 1
|
439
|
+
pps_array[0].prev_pps = 0xFFFFFFFF
|
440
|
+
pps_array[0].next_pps = 0xFFFFFFFF
|
441
|
+
pps_array[0].dir_pps = _savePpsSetPnt2(pps_array[0].child, aList, rh_info)
|
442
|
+
return pps_array[0].no
|
443
|
+
#1.3 Array
|
444
|
+
else
|
445
|
+
iCnt = pps_array.size
|
446
|
+
#1.3.1 Define Center
|
447
|
+
iPos = 0 #int($iCnt/ 2); #$iCnt
|
448
|
+
|
449
|
+
aWk = pps_array.dup
|
450
|
+
aPrev = aWk[1, 1]
|
451
|
+
aWk[1..1] = nil
|
452
|
+
aNext = aWk[1..aWk.size] #, $iCnt - $iPos -1);
|
453
|
+
pps_array[iPos].prev_pps = _savePpsSetPnt2(pps_array, aList, rh_info)
|
454
|
+
aList.push(pps_array[iPos])
|
455
|
+
pps_array[iPos].no = aList.size
|
456
|
+
|
457
|
+
#1.3.2 Devide a array into Previous,Next
|
458
|
+
pps_array[iPos].next_pps = _savePpsSetPnt2(aNext, aList, rh_info)
|
459
|
+
pps_array[iPos].dir_pps = _savePpsSetPnt2(pps_array[iPos].child, aList, rh_info)
|
460
|
+
return pps_array[iPos].no
|
461
|
+
end
|
462
|
+
end
|
463
|
+
private :_savePpsSetPnt2
|
464
|
+
|
465
|
+
def _saveBbd(iSbdSize, iBsize, iPpsCnt, rh_info)
|
466
|
+
file = rh_info[:fileh]
|
467
|
+
#0. Calculate Basic Setting
|
468
|
+
iBbCnt = rh_info[:big_block_size] / LONG_INT_SIZE
|
469
|
+
iBlCnt = iBbCnt - 1
|
470
|
+
i1stBdL = (rh_info[:big_block_size] - 0x4C) / LONG_INT_SIZE
|
471
|
+
i1stBdMax = i1stBdL * iBbCnt - i1stBdL
|
472
|
+
iBdExL = 0
|
473
|
+
iAll = iBsize + iPpsCnt + iSbdSize
|
474
|
+
iAllW = iAll
|
475
|
+
iBdCntW = iAllW / iBbCnt
|
476
|
+
iBdCntW += 1 if iAllW % iBbCnt > 0
|
477
|
+
iBdCnt = 0
|
478
|
+
#0.1 Calculate BD count
|
479
|
+
iBBleftover = iAll - i1stBdMax
|
480
|
+
if iAll >i1stBdMax
|
481
|
+
while true
|
482
|
+
iBdCnt = iBBleftover / iBlCnt
|
483
|
+
iBdCnt += 1 if iBBleftover % iBlCnt > 0
|
484
|
+
|
485
|
+
iBdExL = iBdCnt / iBlCnt
|
486
|
+
iBdExL += 1 if iBdCnt % iBlCnt > 0
|
487
|
+
iBBleftover = iBBleftover + iBdExL
|
488
|
+
break if iBdCnt == (iBBleftover / iBlCnt + ((iBBleftover % iBlCnt) > 0 ? 1: 0))
|
489
|
+
end
|
490
|
+
end
|
491
|
+
iAllW += iBdExL
|
492
|
+
iBdCnt += i1stBdL
|
493
|
+
#print "iBdCnt = iBdCnt \n"
|
494
|
+
|
495
|
+
#1. Making BD
|
496
|
+
#1.1 Set for SBD
|
497
|
+
if iSbdSize > 0
|
498
|
+
0.upto(iSbdSize-1-1) do |i|
|
499
|
+
file.write([i + 1].pack('V'))
|
500
|
+
end
|
501
|
+
file.write([-2].pack('V'))
|
502
|
+
end
|
503
|
+
#1.2 Set for B
|
504
|
+
0.upto(iBsize-1-1) do |i|
|
505
|
+
file.write([i + iSbdSize + 1].pack('V'))
|
506
|
+
end
|
507
|
+
file.write([-2].pack('V'))
|
508
|
+
|
509
|
+
#1.3 Set for PPS
|
510
|
+
0.upto(iPpsCnt-1-1) do |i|
|
511
|
+
file.write([i+iSbdSize+iBsize+1].pack("V"))
|
512
|
+
end
|
513
|
+
file.write([-2].pack('V'))
|
514
|
+
#1.4 Set for BBD itself ( 0xFFFFFFFD : BBD)
|
515
|
+
0.upto(iBdCnt-1) do |i|
|
516
|
+
file.write([0xFFFFFFFD].pack("V"))
|
517
|
+
end
|
518
|
+
#1.5 Set for ExtraBDList
|
519
|
+
0.upto(iBdExL-1) do |i|
|
520
|
+
file.write([0xFFFFFFFC].pack("V"))
|
521
|
+
end
|
522
|
+
#1.6 Adjust for Block
|
523
|
+
if (iAllW + iBdCnt) % iBbCnt > 0
|
524
|
+
file.write([-1].pack('V') * (iBbCnt - ((iAllW + iBdCnt) % iBbCnt)))
|
525
|
+
end
|
526
|
+
#2.Extra BDList
|
527
|
+
if iBdCnt > i1stBdL
|
528
|
+
iN = 0
|
529
|
+
iNb = 0
|
530
|
+
i1stBdL.upto(iBdCnt-1) do |i|
|
531
|
+
if iN >= iBbCnt-1
|
532
|
+
iN = 0
|
533
|
+
iNb += 1
|
534
|
+
file.write([iAll+iBdCnt+iNb].pack("V"))
|
535
|
+
end
|
536
|
+
file.write([iBsize+iSbdSize+iPpsCnt+i].pack("V"))
|
537
|
+
iN += 1
|
538
|
+
end
|
539
|
+
if (iBdCnt-i1stBdL) % (iBbCnt-1) > 0
|
540
|
+
file.write([-1].pack("V") * ((iBbCnt-1) - ((iBdCnt-i1stBdL) % (iBbCnt-1))))
|
541
|
+
end
|
542
|
+
file.write([-2].pack('V'))
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
class OLEStorageLitePPSFile < OLEStorageLitePPS
|
548
|
+
def initialize(sNm, data = '')
|
549
|
+
super(
|
550
|
+
nil,
|
551
|
+
sNm || '',
|
552
|
+
PPS_TYPE_FILE,
|
553
|
+
nil,
|
554
|
+
nil,
|
555
|
+
nil,
|
556
|
+
nil,
|
557
|
+
nil,
|
558
|
+
nil,
|
559
|
+
nil,
|
560
|
+
data || '',
|
561
|
+
nil
|
562
|
+
)
|
563
|
+
end
|
564
|
+
|
565
|
+
def set_file(sFile = '')
|
566
|
+
if sFile.nil? or sFile == ''
|
567
|
+
@pps_file = Tempfile.new('OLEStorageLitePPSFile')
|
568
|
+
elsif sFile.kind_of?(IO) || sFile.kind_of?(StringIO)
|
569
|
+
@pps_file = sFile
|
570
|
+
elsif sFile.kind_of?(String)
|
571
|
+
#File Name
|
572
|
+
@pps_file = open(sFile, "r+")
|
573
|
+
return nil unless @pps_file
|
574
|
+
else
|
575
|
+
return nil
|
576
|
+
end
|
577
|
+
@pps_file.seek(0, IO::SEEK_END)
|
578
|
+
@pps_file.binmode
|
579
|
+
end
|
580
|
+
|
581
|
+
def append (data)
|
582
|
+
return if data.nil?
|
583
|
+
if @pps_file
|
584
|
+
@pps_file << data
|
585
|
+
@pps_file.flush
|
586
|
+
else
|
587
|
+
@data << data
|
588
|
+
end
|
589
|
+
end
|
590
|
+
end
|