File Coverage

blib/lib/OLE/Storage_Lite.pm
Criterion Covered Total %
statement 67 654 10.2
branch 3 260 1.1
condition 0 27 0.0
subroutine 18 67 26.8
pod 6 14 42.8
total 94 1022 9.2


line stmt bran cond sub pod time code
1             # OLE::Storage_Lite
2             # by Kawai, Takanori (Hippo2000) 2000.11.4, 8, 14
3             # This Program is Still ALPHA version.
4             #//////////////////////////////////////////////////////////////////////////////
5             # OLE::Storage_Lite::PPS Object
6             #//////////////////////////////////////////////////////////////////////////////
7             #==============================================================================
8             # OLE::Storage_Lite::PPS
9             #==============================================================================
10             package OLE::Storage_Lite::PPS;
11             require Exporter;
12 2     2   1303 use strict;
  2         10  
  2         79  
13 2     2   12 use vars qw($VERSION @ISA);
  2         4  
  2         2133  
14             @ISA = qw(Exporter);
15             $VERSION = '0.20';
16            
17             #------------------------------------------------------------------------------
18             # new (OLE::Storage_Lite::PPS)
19             #------------------------------------------------------------------------------
20             sub new ($$$$$$$$$$;$$) {
21             #1. Constructor for General Usage
22 0     0   0 my($sClass, $iNo, $sNm, $iType, $iPrev, $iNext, $iDir,
23             $raTime1st, $raTime2nd, $iStart, $iSize, $sData, $raChild) = @_;
24            
25 0 0       0 if($iType == OLE::Storage_Lite::PpsType_File()) { #FILE
    0          
    0          
26 0         0 return OLE::Storage_Lite::PPS::File->_new
27             ($iNo, $sNm, $iType, $iPrev, $iNext, $iDir, $raTime1st, $raTime2nd,
28             $iStart, $iSize, $sData, $raChild);
29             }
30             elsif($iType == OLE::Storage_Lite::PpsType_Dir()) { #DIRECTRY
31 0         0 return OLE::Storage_Lite::PPS::Dir->_new
32             ($iNo, $sNm, $iType, $iPrev, $iNext, $iDir, $raTime1st, $raTime2nd,
33             $iStart, $iSize, $sData, $raChild);
34             }
35             elsif($iType == OLE::Storage_Lite::PpsType_Root()) { #ROOT
36 0         0 return OLE::Storage_Lite::PPS::Root->_new
37             ($iNo, $sNm, $iType, $iPrev, $iNext, $iDir, $raTime1st, $raTime2nd,
38             $iStart, $iSize, $sData, $raChild);
39             }
40             else {
41 0         0 die "Error PPS:$iType $sNm\n";
42             }
43             }
44             #------------------------------------------------------------------------------
45             # _new (OLE::Storage_Lite::PPS)
46             # for OLE::Storage_Lite
47             #------------------------------------------------------------------------------
48             sub _new ($$$$$$$$$$$;$$) {
49 0     0   0 my($sClass, $iNo, $sNm, $iType, $iPrev, $iNext, $iDir,
50             $raTime1st, $raTime2nd, $iStart, $iSize, $sData, $raChild) = @_;
51             #1. Constructor for OLE::Storage_Lite
52 0         0 my $oThis = {
53             No => $iNo,
54             Name => $sNm,
55             Type => $iType,
56             PrevPps => $iPrev,
57             NextPps => $iNext,
58             DirPps => $iDir,
59             Time1st => $raTime1st,
60             Time2nd => $raTime2nd,
61             StartBlock => $iStart,
62             Size => $iSize,
63             Data => $sData,
64             Child => $raChild,
65             };
66 0         0 bless $oThis, $sClass;
67 0         0 return $oThis;
68             }
69             #------------------------------------------------------------------------------
70             # _DataLen (OLE::Storage_Lite::PPS)
71             # Check for update
72             #------------------------------------------------------------------------------
73             sub _DataLen($) {
74 0     0   0 my($oSelf) =@_;
75 0 0       0 return 0 unless(defined($oSelf->{Data}));
76             return ($oSelf->{_PPS_FILE})?
77 0 0       0 ($oSelf->{_PPS_FILE}->stat())[7] : length($oSelf->{Data});
78             }
79             #------------------------------------------------------------------------------
80             # _makeSmallData (OLE::Storage_Lite::PPS)
81             #------------------------------------------------------------------------------
82             sub _makeSmallData($$$) {
83 0     0   0 my($oThis, $aList, $rhInfo) = @_;
84 0         0 my ($sRes);
85 0         0 my $FILE = $rhInfo->{_FILEH_};
86 0         0 my $iSmBlk = 0;
87            
88 0         0 foreach my $oPps (@$aList) {
89             #1. Make SBD, small data string
90 0 0       0 if($oPps->{Type}==OLE::Storage_Lite::PpsType_File()) {
91 0 0       0 next if($oPps->{Size}<=0);
92 0 0       0 if($oPps->{Size} < $rhInfo->{_SMALL_SIZE}) {
93             my $iSmbCnt = int($oPps->{Size} / $rhInfo->{_SMALL_BLOCK_SIZE})
94 0 0       0 + (($oPps->{Size} % $rhInfo->{_SMALL_BLOCK_SIZE})? 1: 0);
95             #1.1 Add to SBD
96 0         0 for (my $i = 0; $i<($iSmbCnt-1); $i++) {
97 0         0 print {$FILE} (pack("V", $i+$iSmBlk+1));
  0         0  
98             }
99 0         0 print {$FILE} (pack("V", -2));
  0         0  
100            
101             #1.2 Add to Data String(this will be written for RootEntry)
102             #Check for update
103 0 0       0 if($oPps->{_PPS_FILE}) {
104 0         0 my $sBuff;
105 0         0 $oPps->{_PPS_FILE}->seek(0, 0); #To The Top
106 0         0 while($oPps->{_PPS_FILE}->read($sBuff, 4096)) {
107 0         0 $sRes .= $sBuff;
108             }
109             }
110             else {
111 0         0 $sRes .= $oPps->{Data};
112             }
113             $sRes .= ("\x00" x
114             ($rhInfo->{_SMALL_BLOCK_SIZE} - ($oPps->{Size}% $rhInfo->{_SMALL_BLOCK_SIZE})))
115 0 0       0 if($oPps->{Size}% $rhInfo->{_SMALL_BLOCK_SIZE});
116             #1.3 Set for PPS
117 0         0 $oPps->{StartBlock} = $iSmBlk;
118 0         0 $iSmBlk += $iSmbCnt;
119             }
120             }
121             }
122 0         0 my $iSbCnt = int($rhInfo->{_BIG_BLOCK_SIZE}/ OLE::Storage_Lite::LongIntSize());
123 0 0       0 print {$FILE} (pack("V", -1) x ($iSbCnt - ($iSmBlk % $iSbCnt)))
  0         0  
124             if($iSmBlk % $iSbCnt);
125             #2. Write SBD with adjusting length for block
126 0         0 return $sRes;
127             }
128             #------------------------------------------------------------------------------
129             # _savePpsWk (OLE::Storage_Lite::PPS)
130             #------------------------------------------------------------------------------
131             sub _savePpsWk($$)
132             {
133 0     0   0 my($oThis, $rhInfo) = @_;
134             #1. Write PPS
135 0         0 my $FILE = $rhInfo->{_FILEH_};
136 0         0 print {$FILE} (
137             $oThis->{Name}
138             . ("\x00" x (64 - length($oThis->{Name}))) #64
139             , pack("v", length($oThis->{Name}) + 2) #66
140             , pack("c", $oThis->{Type}) #67
141             , pack("c", 0x00) #UK #68
142             , pack("V", $oThis->{PrevPps}) #Prev #72
143             , pack("V", $oThis->{NextPps}) #Next #76
144             , pack("V", $oThis->{DirPps}) #Dir #80
145             , "\x00\x09\x02\x00" #84
146             , "\x00\x00\x00\x00" #88
147             , "\xc0\x00\x00\x00" #92
148             , "\x00\x00\x00\x46" #96
149             , "\x00\x00\x00\x00" #100
150             , OLE::Storage_Lite::LocalDate2OLE($oThis->{Time1st}) #108
151             , OLE::Storage_Lite::LocalDate2OLE($oThis->{Time2nd}) #116
152             , pack("V", defined($oThis->{StartBlock})?
153             $oThis->{StartBlock}:0) #116
154             , pack("V", defined($oThis->{Size})?
155 0 0       0 $oThis->{Size} : 0) #124
    0          
156             , pack("V", 0), #128
157             );
158             }
159            
160             #//////////////////////////////////////////////////////////////////////////////
161             # OLE::Storage_Lite::PPS::Root Object
162             #//////////////////////////////////////////////////////////////////////////////
163             #==============================================================================
164             # OLE::Storage_Lite::PPS::Root
165             #==============================================================================
166             package OLE::Storage_Lite::PPS::Root;
167             require Exporter;
168 2     2   21 use strict;
  2         4  
  2         50  
169 2     2   974 use IO::File;
  2         17511  
  2         239  
170 2     2   17 use IO::Handle;
  2         4  
  2         69  
171 2     2   12 use Fcntl;
  2         4  
  2         614  
172 2     2   22 use vars qw($VERSION @ISA);
  2         5  
  2         6713  
173             @ISA = qw(OLE::Storage_Lite::PPS Exporter);
174             $VERSION = '0.20';
175             sub _savePpsSetPnt($$$);
176             sub _savePpsSetPnt2($$$);
177             #------------------------------------------------------------------------------
178             # new (OLE::Storage_Lite::PPS::Root)
179             #------------------------------------------------------------------------------
180             sub new ($;$$$) {
181 0     0   0 my($sClass, $raTime1st, $raTime2nd, $raChild) = @_;
182 0         0 OLE::Storage_Lite::PPS::_new(
183             $sClass,
184             undef,
185             OLE::Storage_Lite::Asc2Ucs('Root Entry'),
186             5,
187             undef,
188             undef,
189             undef,
190             $raTime1st,
191             $raTime2nd,
192             undef,
193             undef,
194             undef,
195             $raChild);
196             }
197             #------------------------------------------------------------------------------
198             # save (OLE::Storage_Lite::PPS::Root)
199             #------------------------------------------------------------------------------
200             sub save($$;$$) {
201 0     0   0 my($oThis, $sFile, $bNoAs, $rhInfo) = @_;
202             #0.Initial Setting for saving
203 0 0       0 $rhInfo = {} unless($rhInfo);
204             $rhInfo->{_BIG_BLOCK_SIZE} = 2**
205             (($rhInfo->{_BIG_BLOCK_SIZE})?
206 0 0       0 _adjust2($rhInfo->{_BIG_BLOCK_SIZE}) : 9);
207             $rhInfo->{_SMALL_BLOCK_SIZE}= 2 **
208             (($rhInfo->{_SMALL_BLOCK_SIZE})?
209 0 0       0 _adjust2($rhInfo->{_SMALL_BLOCK_SIZE}): 6);
210 0         0 $rhInfo->{_SMALL_SIZE} = 0x1000;
211 0         0 $rhInfo->{_PPS_SIZE} = 0x80;
212            
213 0         0 my $closeFile = 1;
214            
215             #1.Open File
216             #1.1 $sFile is Ref of scalar
217 0 0       0 if(ref($sFile) eq 'SCALAR') {
    0          
    0          
218 0         0 require IO::Scalar;
219 0         0 my $oIo = new IO::Scalar $sFile, O_WRONLY;
220 0         0 $rhInfo->{_FILEH_} = $oIo;
221             }
222             #1.1.1 $sFile is a IO::Scalar object
223             # Now handled as a filehandle ref below.
224            
225             #1.2 $sFile is a IO::Handle object
226             elsif(UNIVERSAL::isa($sFile, 'IO::Handle')) {
227             # Not all filehandles support binmode() so try it in an eval.
228 0         0 eval{ binmode $sFile };
  0         0  
229 0         0 $rhInfo->{_FILEH_} = $sFile;
230             }
231             #1.3 $sFile is a simple filename string
232             elsif(!ref($sFile)) {
233 0 0       0 if($sFile ne '-') {
234 0         0 my $oIo = new IO::File;
235 0 0       0 $oIo->open(">$sFile") || return undef;
236 0         0 binmode($oIo);
237 0         0 $rhInfo->{_FILEH_} = $oIo;
238             }
239             else {
240 0         0 my $oIo = new IO::Handle;
241 0 0       0 $oIo->fdopen(fileno(STDOUT),"w") || return undef;
242 0         0 binmode($oIo);
243 0         0 $rhInfo->{_FILEH_} = $oIo;
244             }
245             }
246             #1.4 Assume that if $sFile is a ref then it is a valid filehandle
247             else {
248             # Not all filehandles support binmode() so try it in an eval.
249 0         0 eval{ binmode $sFile };
  0         0  
250 0         0 $rhInfo->{_FILEH_} = $sFile;
251             # Caller controls filehandle closing
252 0         0 $closeFile = 0;
253             }
254            
255 0         0 my $iBlk = 0;
256             #1. Make an array of PPS (for Save)
257 0         0 my @aList=();
258 0 0       0 if($bNoAs) {
259 0         0 _savePpsSetPnt2([$oThis], \@aList, $rhInfo);
260             }
261             else {
262 0         0 _savePpsSetPnt([$oThis], \@aList, $rhInfo);
263             }
264 0         0 my ($iSBDcnt, $iBBcnt, $iPPScnt) = $oThis->_calcSize(\@aList, $rhInfo);
265            
266             #2.Save Header
267 0         0 $oThis->_saveHeader($rhInfo, $iSBDcnt, $iBBcnt, $iPPScnt);
268            
269             #3.Make Small Data string (write SBD)
270 0         0 my $sSmWk = $oThis->_makeSmallData(\@aList, $rhInfo);
271 0         0 $oThis->{Data} = $sSmWk; #Small Datas become RootEntry Data
272            
273             #4. Write BB
274 0         0 my $iBBlk = $iSBDcnt;
275 0         0 $oThis->_saveBigData(\$iBBlk, \@aList, $rhInfo);
276            
277             #5. Write PPS
278 0         0 $oThis->_savePps(\@aList, $rhInfo);
279            
280             #6. Write BD and BDList and Adding Header informations
281 0         0 $oThis->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt, $rhInfo);
282            
283             #7.Close File
284 0 0       0 return $rhInfo->{_FILEH_}->close if $closeFile;
285             }
286             #------------------------------------------------------------------------------
287             # _calcSize (OLE::Storage_Lite::PPS)
288             #------------------------------------------------------------------------------
289             sub _calcSize($$)
290             {
291 0     0   0 my($oThis, $raList, $rhInfo) = @_;
292            
293             #0. Calculate Basic Setting
294 0         0 my ($iSBDcnt, $iBBcnt, $iPPScnt) = (0,0,0);
295 0         0 my $iSmallLen = 0;
296 0         0 my $iSBcnt = 0;
297 0         0 foreach my $oPps (@$raList) {
298 0 0       0 if($oPps->{Type}==OLE::Storage_Lite::PpsType_File()) {
299 0         0 $oPps->{Size} = $oPps->_DataLen(); #Mod
300 0 0       0 if($oPps->{Size} < $rhInfo->{_SMALL_SIZE}) {
301             $iSBcnt += int($oPps->{Size} / $rhInfo->{_SMALL_BLOCK_SIZE})
302 0 0       0 + (($oPps->{Size} % $rhInfo->{_SMALL_BLOCK_SIZE})? 1: 0);
303             }
304             else {
305             $iBBcnt +=
306             (int($oPps->{Size}/ $rhInfo->{_BIG_BLOCK_SIZE}) +
307 0 0       0 (($oPps->{Size}% $rhInfo->{_BIG_BLOCK_SIZE})? 1: 0));
308             }
309             }
310             }
311 0         0 $iSmallLen = $iSBcnt * $rhInfo->{_SMALL_BLOCK_SIZE};
312 0         0 my $iSlCnt = int($rhInfo->{_BIG_BLOCK_SIZE}/ OLE::Storage_Lite::LongIntSize());
313 0 0       0 $iSBDcnt = int($iSBcnt / $iSlCnt)+ (($iSBcnt % $iSlCnt)? 1:0);
314             $iBBcnt += (int($iSmallLen/ $rhInfo->{_BIG_BLOCK_SIZE}) +
315 0 0       0 (( $iSmallLen% $rhInfo->{_BIG_BLOCK_SIZE})? 1: 0));
316 0         0 my $iCnt = scalar(@$raList);
317 0         0 my $iBdCnt = $rhInfo->{_BIG_BLOCK_SIZE}/OLE::Storage_Lite::PpsSize();
318 0 0       0 $iPPScnt = (int($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0));
319 0         0 return ($iSBDcnt, $iBBcnt, $iPPScnt);
320             }
321             #------------------------------------------------------------------------------
322             # _adjust2 (OLE::Storage_Lite::PPS::Root)
323             #------------------------------------------------------------------------------
324             sub _adjust2($) {
325 0     0   0 my($i2) = @_;
326 0         0 my $iWk;
327 0         0 $iWk = log($i2)/log(2);
328 0 0       0 return ($iWk > int($iWk))? int($iWk)+1:$iWk;
329             }
330             #------------------------------------------------------------------------------
331             # _saveHeader (OLE::Storage_Lite::PPS::Root)
332             #------------------------------------------------------------------------------
333             sub _saveHeader($$$$$) {
334 0     0   0 my($oThis, $rhInfo, $iSBDcnt, $iBBcnt, $iPPScnt) = @_;
335 0         0 my $FILE = $rhInfo->{_FILEH_};
336            
337             #0. Calculate Basic Setting
338 0         0 my $iBlCnt = $rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize();
339 0         0 my $i1stBdL = int(($rhInfo->{_BIG_BLOCK_SIZE} - 0x4C) / OLE::Storage_Lite::LongIntSize());
340 0         0 my $i1stBdMax = $i1stBdL * $iBlCnt - $i1stBdL;
341 0         0 my $iBdExL = 0;
342 0         0 my $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
343 0         0 my $iAllW = $iAll;
344 0 0       0 my $iBdCntW = int($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
345 0 0       0 my $iBdCnt = int(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
346 0         0 my $i;
347            
348 0 0       0 if ($iBdCnt > $i1stBdL) {
349             #0.1 Calculate BD count
350 0         0 $iBlCnt--; #the BlCnt is reduced in the count of the last sect is used for a pointer the next Bl
351 0         0 my $iBBleftover = $iAll - $i1stBdMax;
352            
353 0 0       0 if ($iAll >$i1stBdMax) {
354 0         0 while(1) {
355 0 0       0 $iBdCnt = int(($iBBleftover) / $iBlCnt) + ((($iBBleftover) % $iBlCnt)? 1: 0);
356 0 0       0 $iBdExL = int(($iBdCnt) / $iBlCnt) + ((($iBdCnt) % $iBlCnt)? 1: 0);
357 0         0 $iBBleftover = $iBBleftover + $iBdExL;
358 0 0       0 last if($iBdCnt == (int(($iBBleftover) / $iBlCnt) + ((($iBBleftover) % $iBlCnt)? 1: 0)));
    0          
359             }
360             }
361 0         0 $iBdCnt += $i1stBdL;
362             #print "iBdCnt = $iBdCnt \n";
363             }
364             #1.Save Header
365 0 0       0 print {$FILE} (
  0         0  
366             "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
367             , "\x00\x00\x00\x00" x 4
368             , pack("v", 0x3b)
369             , pack("v", 0x03)
370             , pack("v", -2)
371             , pack("v", 9)
372             , pack("v", 6)
373             , pack("v", 0)
374             , "\x00\x00\x00\x00" x 2
375             , pack("V", $iBdCnt),
376             , pack("V", $iBBcnt+$iSBDcnt), #ROOT START
377             , pack("V", 0)
378             , pack("V", 0x1000)
379             , pack("V", $iSBDcnt ? 0 : -2) #Small Block Depot
380             , pack("V", $iSBDcnt)
381             );
382             #2. Extra BDList Start, Count
383 0 0       0 if($iAll <= $i1stBdMax) {
384 0         0 print {$FILE} (
  0         0  
385             pack("V", -2), #Extra BDList Start
386             pack("V", 0), #Extra BDList Count
387             );
388             }
389             else {
390 0         0 print {$FILE} (
  0         0  
391             pack("V", $iAll+$iBdCnt),
392             pack("V", $iBdExL),
393             );
394             }
395            
396             #3. BDList
397 0   0     0 for($i=0; $i<$i1stBdL and $i < $iBdCnt; $i++) {
398 0         0 print {$FILE} (pack("V", $iAll+$i));
  0         0  
399             }
400 0 0       0 print {$FILE} ((pack("V", -1)) x($i1stBdL-$i)) if($i<$i1stBdL);
  0         0  
401             }
402             #------------------------------------------------------------------------------
403             # _saveBigData (OLE::Storage_Lite::PPS)
404             #------------------------------------------------------------------------------
405             sub _saveBigData($$$$) {
406 0     0   0 my($oThis, $iStBlk, $raList, $rhInfo) = @_;
407 0         0 my $iRes = 0;
408 0         0 my $FILE = $rhInfo->{_FILEH_};
409            
410             #1.Write Big (ge 0x1000) Data into Block
411 0         0 foreach my $oPps (@$raList) {
412 0 0       0 if($oPps->{Type}!=OLE::Storage_Lite::PpsType_Dir()) {
413             #print "PPS: $oPps DEF:", defined($oPps->{Data}), "\n";
414 0         0 $oPps->{Size} = $oPps->_DataLen(); #Mod
415 0 0 0     0 if(($oPps->{Size} >= $rhInfo->{_SMALL_SIZE}) ||
      0        
416             (($oPps->{Type} == OLE::Storage_Lite::PpsType_Root()) && defined($oPps->{Data}))) {
417             #1.1 Write Data
418             #Check for update
419 0 0       0 if($oPps->{_PPS_FILE}) {
420 0         0 my $sBuff;
421 0         0 my $iLen = 0;
422 0         0 $oPps->{_PPS_FILE}->seek(0, 0); #To The Top
423 0         0 while($oPps->{_PPS_FILE}->read($sBuff, 4096)) {
424 0         0 $iLen += length($sBuff);
425 0         0 print {$FILE} ($sBuff); #Check for update
  0         0  
426             }
427             }
428             else {
429 0         0 print {$FILE} ($oPps->{Data});
  0         0  
430             }
431 0         0 print {$FILE} (
432             "\x00" x
433             ($rhInfo->{_BIG_BLOCK_SIZE} -
434             ($oPps->{Size} % $rhInfo->{_BIG_BLOCK_SIZE}))
435 0 0       0 ) if ($oPps->{Size} % $rhInfo->{_BIG_BLOCK_SIZE});
436             #1.2 Set For PPS
437 0         0 $oPps->{StartBlock} = $$iStBlk;
438             $$iStBlk +=
439             (int($oPps->{Size}/ $rhInfo->{_BIG_BLOCK_SIZE}) +
440 0 0       0 (($oPps->{Size}% $rhInfo->{_BIG_BLOCK_SIZE})? 1: 0));
441             }
442             }
443             }
444             }
445             #------------------------------------------------------------------------------
446             # _savePps (OLE::Storage_Lite::PPS::Root)
447             #------------------------------------------------------------------------------
448             sub _savePps($$$)
449             {
450 0     0   0 my($oThis, $raList, $rhInfo) = @_;
451             #0. Initial
452 0         0 my $FILE = $rhInfo->{_FILEH_};
453             #2. Save PPS
454 0         0 foreach my $oItem (@$raList) {
455 0         0 $oItem->_savePpsWk($rhInfo);
456             }
457             #3. Adjust for Block
458 0         0 my $iCnt = scalar(@$raList);
459 0         0 my $iBCnt = $rhInfo->{_BIG_BLOCK_SIZE} / $rhInfo->{_PPS_SIZE};
460 0 0       0 print {$FILE} ("\x00" x (($iBCnt - ($iCnt % $iBCnt)) * $rhInfo->{_PPS_SIZE}))
  0         0  
461             if($iCnt % $iBCnt);
462 0 0       0 return int($iCnt / $iBCnt) + (($iCnt % $iBCnt)? 1: 0);
463             }
464             #------------------------------------------------------------------------------
465             # _savePpsSetPnt2 (OLE::Storage_Lite::PPS::Root)
466             # For Test
467             #------------------------------------------------------------------------------
468             sub _savePpsSetPnt2($$$)
469             {
470 0     0   0 my($aThis, $raList, $rhInfo) = @_;
471             #1. make Array as Children-Relations
472             #1.1 if No Children
473 0 0       0 if($#$aThis < 0) {
    0          
474 0         0 return 0xFFFFFFFF;
475             }
476             elsif($#$aThis == 0) {
477             #1.2 Just Only one
478 0         0 push @$raList, $aThis->[0];
479 0         0 $aThis->[0]->{No} = $#$raList;
480 0         0 $aThis->[0]->{PrevPps} = 0xFFFFFFFF;
481 0         0 $aThis->[0]->{NextPps} = 0xFFFFFFFF;
482 0         0 $aThis->[0]->{DirPps} = _savePpsSetPnt2($aThis->[0]->{Child}, $raList, $rhInfo);
483 0         0 return $aThis->[0]->{No};
484             }
485             else {
486             #1.3 Array
487 0         0 my $iCnt = $#$aThis + 1;
488             #1.3.1 Define Center
489 0         0 my $iPos = 0; #int($iCnt/ 2); #$iCnt
490            
491 0         0 my @aWk = @$aThis;
492 0 0       0 my @aPrev = ($#$aThis > 1)? splice(@aWk, 1, 1) : (); #$iPos);
493 0         0 my @aNext = splice(@aWk, 1); #, $iCnt - $iPos -1);
494 0         0 $aThis->[$iPos]->{PrevPps} = _savePpsSetPnt2(
495             \@aPrev, $raList, $rhInfo);
496 0         0 push @$raList, $aThis->[$iPos];
497 0         0 $aThis->[$iPos]->{No} = $#$raList;
498            
499             #1.3.2 Devide a array into Previous,Next
500 0         0 $aThis->[$iPos]->{NextPps} = _savePpsSetPnt2(
501             \@aNext, $raList, $rhInfo);
502 0         0 $aThis->[$iPos]->{DirPps} = _savePpsSetPnt2($aThis->[$iPos]->{Child}, $raList, $rhInfo);
503 0         0 return $aThis->[$iPos]->{No};
504             }
505             }
506             #------------------------------------------------------------------------------
507             # _savePpsSetPnt2 (OLE::Storage_Lite::PPS::Root)
508             # For Test
509             #------------------------------------------------------------------------------
510             sub _savePpsSetPnt2s($$$)
511             {
512 0     0   0 my($aThis, $raList, $rhInfo) = @_;
513             #1. make Array as Children-Relations
514             #1.1 if No Children
515 0 0       0 if($#$aThis < 0) {
    0          
516 0         0 return 0xFFFFFFFF;
517             }
518             elsif($#$aThis == 0) {
519             #1.2 Just Only one
520 0         0 push @$raList, $aThis->[0];
521 0         0 $aThis->[0]->{No} = $#$raList;
522 0         0 $aThis->[0]->{PrevPps} = 0xFFFFFFFF;
523 0         0 $aThis->[0]->{NextPps} = 0xFFFFFFFF;
524 0         0 $aThis->[0]->{DirPps} = _savePpsSetPnt2($aThis->[0]->{Child}, $raList, $rhInfo);
525 0         0 return $aThis->[0]->{No};
526             }
527             else {
528             #1.3 Array
529 0         0 my $iCnt = $#$aThis + 1;
530             #1.3.1 Define Center
531 0         0 my $iPos = 0; #int($iCnt/ 2); #$iCnt
532 0         0 push @$raList, $aThis->[$iPos];
533 0         0 $aThis->[$iPos]->{No} = $#$raList;
534 0         0 my @aWk = @$aThis;
535             #1.3.2 Devide a array into Previous,Next
536 0         0 my @aPrev = splice(@aWk, 0, $iPos);
537 0         0 my @aNext = splice(@aWk, 1, $iCnt - $iPos -1);
538 0         0 $aThis->[$iPos]->{PrevPps} = _savePpsSetPnt2(
539             \@aPrev, $raList, $rhInfo);
540 0         0 $aThis->[$iPos]->{NextPps} = _savePpsSetPnt2(
541             \@aNext, $raList, $rhInfo);
542 0         0 $aThis->[$iPos]->{DirPps} = _savePpsSetPnt2($aThis->[$iPos]->{Child}, $raList, $rhInfo);
543 0         0 return $aThis->[$iPos]->{No};
544             }
545             }
546             #------------------------------------------------------------------------------
547             # _savePpsSetPnt (OLE::Storage_Lite::PPS::Root)
548             #------------------------------------------------------------------------------
549             sub _savePpsSetPnt($$$)
550             {
551 0     0   0 my($aThis, $raList, $rhInfo) = @_;
552             #1. make Array as Children-Relations
553             #1.1 if No Children
554 0 0       0 if($#$aThis < 0) {
    0          
555 0         0 return 0xFFFFFFFF;
556             }
557             elsif($#$aThis == 0) {
558             #1.2 Just Only one
559 0         0 push @$raList, $aThis->[0];
560 0         0 $aThis->[0]->{No} = $#$raList;
561 0         0 $aThis->[0]->{PrevPps} = 0xFFFFFFFF;
562 0         0 $aThis->[0]->{NextPps} = 0xFFFFFFFF;
563 0         0 $aThis->[0]->{DirPps} = _savePpsSetPnt($aThis->[0]->{Child}, $raList, $rhInfo);
564 0         0 return $aThis->[0]->{No};
565             }
566             else {
567             #1.3 Array
568 0         0 my $iCnt = $#$aThis + 1;
569             #1.3.1 Define Center
570 0         0 my $iPos = int($iCnt/ 2); #$iCnt
571 0         0 push @$raList, $aThis->[$iPos];
572 0         0 $aThis->[$iPos]->{No} = $#$raList;
573 0         0 my @aWk = @$aThis;
574             #1.3.2 Devide a array into Previous,Next
575 0         0 my @aPrev = splice(@aWk, 0, $iPos);
576 0         0 my @aNext = splice(@aWk, 1, $iCnt - $iPos -1);
577 0         0 $aThis->[$iPos]->{PrevPps} = _savePpsSetPnt(
578             \@aPrev, $raList, $rhInfo);
579 0         0 $aThis->[$iPos]->{NextPps} = _savePpsSetPnt(
580             \@aNext, $raList, $rhInfo);
581 0         0 $aThis->[$iPos]->{DirPps} = _savePpsSetPnt($aThis->[$iPos]->{Child}, $raList, $rhInfo);
582 0         0 return $aThis->[$iPos]->{No};
583             }
584             }
585             #------------------------------------------------------------------------------
586             # _savePpsSetPnt (OLE::Storage_Lite::PPS::Root)
587             #------------------------------------------------------------------------------
588             sub _savePpsSetPnt1($$$)
589             {
590 0     0   0 my($aThis, $raList, $rhInfo) = @_;
591             #1. make Array as Children-Relations
592             #1.1 if No Children
593 0 0       0 if($#$aThis < 0) {
    0          
594 0         0 return 0xFFFFFFFF;
595             }
596             elsif($#$aThis == 0) {
597             #1.2 Just Only one
598 0         0 push @$raList, $aThis->[0];
599 0         0 $aThis->[0]->{No} = $#$raList;
600 0         0 $aThis->[0]->{PrevPps} = 0xFFFFFFFF;
601 0         0 $aThis->[0]->{NextPps} = 0xFFFFFFFF;
602 0         0 $aThis->[0]->{DirPps} = _savePpsSetPnt($aThis->[0]->{Child}, $raList, $rhInfo);
603 0         0 return $aThis->[0]->{No};
604             }
605             else {
606             #1.3 Array
607 0         0 my $iCnt = $#$aThis + 1;
608             #1.3.1 Define Center
609 0         0 my $iPos = int($iCnt/ 2); #$iCnt
610 0         0 push @$raList, $aThis->[$iPos];
611 0         0 $aThis->[$iPos]->{No} = $#$raList;
612 0         0 my @aWk = @$aThis;
613             #1.3.2 Devide a array into Previous,Next
614 0         0 my @aPrev = splice(@aWk, 0, $iPos);
615 0         0 my @aNext = splice(@aWk, 1, $iCnt - $iPos -1);
616 0         0 $aThis->[$iPos]->{PrevPps} = _savePpsSetPnt(
617             \@aPrev, $raList, $rhInfo);
618 0         0 $aThis->[$iPos]->{NextPps} = _savePpsSetPnt(
619             \@aNext, $raList, $rhInfo);
620 0         0 $aThis->[$iPos]->{DirPps} = _savePpsSetPnt($aThis->[$iPos]->{Child}, $raList, $rhInfo);
621 0         0 return $aThis->[$iPos]->{No};
622             }
623             }
624             #------------------------------------------------------------------------------
625             # _saveBbd (OLE::Storage_Lite)
626             #------------------------------------------------------------------------------
627             sub _saveBbd($$$$)
628             {
629 0     0   0 my($oThis, $iSbdSize, $iBsize, $iPpsCnt, $rhInfo) = @_;
630 0         0 my $FILE = $rhInfo->{_FILEH_};
631             #0. Calculate Basic Setting
632 0         0 my $iBbCnt = $rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize();
633 0         0 my $iBlCnt = $iBbCnt - 1;
634 0         0 my $i1stBdL = int(($rhInfo->{_BIG_BLOCK_SIZE} - 0x4C) / OLE::Storage_Lite::LongIntSize());
635 0         0 my $i1stBdMax = $i1stBdL * $iBbCnt - $i1stBdL;
636 0         0 my $iBdExL = 0;
637 0         0 my $iAll = $iBsize + $iPpsCnt + $iSbdSize;
638 0         0 my $iAllW = $iAll;
639 0 0       0 my $iBdCntW = int($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
640 0         0 my $iBdCnt = 0;
641 0         0 my $i;
642             #0.1 Calculate BD count
643 0         0 my $iBBleftover = $iAll - $i1stBdMax;
644 0 0       0 if ($iAll >$i1stBdMax) {
645            
646 0         0 while(1) {
647 0 0       0 $iBdCnt = int(($iBBleftover) / $iBlCnt) + ((($iBBleftover) % $iBlCnt)? 1: 0);
648 0 0       0 $iBdExL = int(($iBdCnt) / $iBlCnt) + ((($iBdCnt) % $iBlCnt)? 1: 0);
649 0         0 $iBBleftover = $iBBleftover + $iBdExL;
650 0 0       0 last if($iBdCnt == (int(($iBBleftover) / $iBlCnt) + ((($iBBleftover) % $iBlCnt)? 1: 0)));
    0          
651             }
652             }
653 0         0 $iAllW += $iBdExL;
654 0         0 $iBdCnt += $i1stBdL;
655             #print "iBdCnt = $iBdCnt \n";
656            
657             #1. Making BD
658             #1.1 Set for SBD
659 0 0       0 if($iSbdSize > 0) {
660 0         0 for ($i = 0; $i<($iSbdSize-1); $i++) {
661 0         0 print {$FILE} (pack("V", $i+1));
  0         0  
662             }
663 0         0 print {$FILE} (pack("V", -2));
  0         0  
664             }
665             #1.2 Set for B
666 0         0 for ($i = 0; $i<($iBsize-1); $i++) {
667 0         0 print {$FILE} (pack("V", $i+$iSbdSize+1));
  0         0  
668             }
669 0         0 print {$FILE} (pack("V", -2));
  0         0  
670            
671             #1.3 Set for PPS
672 0         0 for ($i = 0; $i<($iPpsCnt-1); $i++) {
673 0         0 print {$FILE} (pack("V", $i+$iSbdSize+$iBsize+1));
  0         0  
674             }
675 0         0 print {$FILE} (pack("V", -2));
  0         0  
676             #1.4 Set for BBD itself ( 0xFFFFFFFD : BBD)
677 0         0 for($i=0; $i<$iBdCnt;$i++) {
678 0         0 print {$FILE} (pack("V", 0xFFFFFFFD));
  0         0  
679             }
680             #1.5 Set for ExtraBDList
681 0         0 for($i=0; $i<$iBdExL;$i++) {
682 0         0 print {$FILE} (pack("V", 0xFFFFFFFC));
  0         0  
683             }
684             #1.6 Adjust for Block
685 0 0       0 print {$FILE} (pack("V", -1) x ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)))
  0         0  
686             if(($iAllW + $iBdCnt) % $iBbCnt);
687             #2.Extra BDList
688 0 0       0 if($iBdCnt > $i1stBdL) {
689 0         0 my $iN=0;
690 0         0 my $iNb=0;
691 0         0 for($i=$i1stBdL;$i<$iBdCnt; $i++, $iN++) {
692 0 0       0 if($iN>=($iBbCnt-1)) {
693 0         0 $iN = 0;
694 0         0 $iNb++;
695 0         0 print {$FILE} (pack("V", $iAll+$iBdCnt+$iNb));
  0         0  
696             }
697 0         0 print {$FILE} (pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i));
  0         0  
698             }
699 0 0       0 print {$FILE} (pack("V", -1) x (($iBbCnt-1) - (($iBdCnt-$i1stBdL) % ($iBbCnt-1))))
  0         0  
700             if(($iBdCnt-$i1stBdL) % ($iBbCnt-1));
701 0         0 print {$FILE} (pack("V", -2));
  0         0  
702             }
703             }
704            
705             #//////////////////////////////////////////////////////////////////////////////
706             # OLE::Storage_Lite::PPS::File Object
707             #//////////////////////////////////////////////////////////////////////////////
708             #==============================================================================
709             # OLE::Storage_Lite::PPS::File
710             #==============================================================================
711             package OLE::Storage_Lite::PPS::File;
712             require Exporter;
713 2     2   24 use strict;
  2         5  
  2         53  
714 2     2   24 use vars qw($VERSION @ISA);
  2         4  
  2         833  
715             @ISA = qw(OLE::Storage_Lite::PPS Exporter);
716             $VERSION = '0.20';
717             #------------------------------------------------------------------------------
718             # new (OLE::Storage_Lite::PPS::File)
719             #------------------------------------------------------------------------------
720             sub new ($$$) {
721 0     0   0 my($sClass, $sNm, $sData) = @_;
722 0         0 OLE::Storage_Lite::PPS::_new(
723             $sClass,
724             undef,
725             $sNm,
726             2,
727             undef,
728             undef,
729             undef,
730             undef,
731             undef,
732             undef,
733             undef,
734             $sData,
735             undef);
736             }
737             #------------------------------------------------------------------------------
738             # newFile (OLE::Storage_Lite::PPS::File)
739             #------------------------------------------------------------------------------
740             sub newFile ($$;$) {
741 0     0   0 my($sClass, $sNm, $sFile) = @_;
742 0         0 my $oSelf =
743             OLE::Storage_Lite::PPS::_new(
744             $sClass,
745             undef,
746             $sNm,
747             2,
748             undef,
749             undef,
750             undef,
751             undef,
752             undef,
753             undef,
754             undef,
755             '',
756             undef);
757             #
758 0 0 0     0 if((!defined($sFile)) or ($sFile eq '')) {
    0          
    0          
759 0         0 $oSelf->{_PPS_FILE} = IO::File->new_tmpfile();
760             }
761             elsif(UNIVERSAL::isa($sFile, 'IO::Handle')) {
762 0         0 $oSelf->{_PPS_FILE} = $sFile;
763             }
764             elsif(!ref($sFile)) {
765             #File Name
766 0         0 $oSelf->{_PPS_FILE} = new IO::File;
767 0 0       0 return undef unless($oSelf->{_PPS_FILE});
768 0 0       0 $oSelf->{_PPS_FILE}->open("$sFile", "r+") || return undef;
769             }
770             else {
771 0         0 return undef;
772             }
773 0 0       0 if($oSelf->{_PPS_FILE}) {
774 0         0 $oSelf->{_PPS_FILE}->seek(0, 2);
775 0         0 binmode($oSelf->{_PPS_FILE});
776 0         0 $oSelf->{_PPS_FILE}->autoflush(1);
777             }
778 0         0 return $oSelf;
779             }
780             #------------------------------------------------------------------------------
781             # append (OLE::Storage_Lite::PPS::File)
782             #------------------------------------------------------------------------------
783             sub append ($$) {
784 0     0   0 my($oSelf, $sData) = @_;
785 0 0       0 if($oSelf->{_PPS_FILE}) {
786 0         0 print {$oSelf->{_PPS_FILE}} $sData;
  0         0  
787             }
788             else {
789 0         0 $oSelf->{Data} .= $sData;
790             }
791             }
792            
793             #//////////////////////////////////////////////////////////////////////////////
794             # OLE::Storage_Lite::PPS::Dir Object
795             #//////////////////////////////////////////////////////////////////////////////
796             #------------------------------------------------------------------------------
797             # new (OLE::Storage_Lite::PPS::Dir)
798             #------------------------------------------------------------------------------
799             package OLE::Storage_Lite::PPS::Dir;
800             require Exporter;
801 2     2   21 use strict;
  2         3  
  2         59  
802 2     2   11 use vars qw($VERSION @ISA);
  2         4  
  2         280  
803             @ISA = qw(OLE::Storage_Lite::PPS Exporter);
804             $VERSION = '0.20';
805             sub new ($$;$$$) {
806 0     0   0 my($sClass, $sName, $raTime1st, $raTime2nd, $raChild) = @_;
807 0         0 OLE::Storage_Lite::PPS::_new(
808             $sClass,
809             undef,
810             $sName,
811             1,
812             undef,
813             undef,
814             undef,
815             $raTime1st,
816             $raTime2nd,
817             undef,
818             undef,
819             undef,
820             $raChild);
821             }
822             #==============================================================================
823             # OLE::Storage_Lite
824             #==============================================================================
825             package OLE::Storage_Lite;
826             require Exporter;
827            
828 2     2   14 use strict;
  2         4  
  2         51  
829 2     2   9 use IO::File;
  2         4  
  2         252  
830 2     2   1062 use Time::Local 'timegm';
  2         4574  
  2         123  
831            
832 2     2   19 use vars qw($VERSION @ISA @EXPORT);
  2         6  
  2         6538  
833             @ISA = qw(Exporter);
834             $VERSION = '0.20';
835             sub _getPpsSearch($$$$$;$);
836             sub _getPpsTree($$$;$);
837             #------------------------------------------------------------------------------
838             # Const for OLE::Storage_Lite
839             #------------------------------------------------------------------------------
840             #0. Constants
841 0     0 0 0 sub PpsType_Root {5};
842 0     0 0 0 sub PpsType_Dir {1};
843 0     0 0 0 sub PpsType_File {2};
844 0     0 0 0 sub DataSizeSmall{0x1000};
845 0     0 0 0 sub LongIntSize {4};
846 0     0 0 0 sub PpsSize {0x80};
847             #------------------------------------------------------------------------------
848             # new OLE::Storage_Lite
849             #------------------------------------------------------------------------------
850             sub new($$) {
851 0     0 1 0 my($sClass, $sFile) = @_;
852 0         0 my $oThis = {
853             _FILE => $sFile,
854             };
855 0         0 bless $oThis;
856 0         0 return $oThis;
857             }
858             #------------------------------------------------------------------------------
859             # getPpsTree: OLE::Storage_Lite
860             #------------------------------------------------------------------------------
861             sub getPpsTree($;$)
862             {
863 0     0 1 0 my($oThis, $bData) = @_;
864             #0.Init
865 0         0 my $rhInfo = _initParse($oThis->{_FILE});
866 0 0       0 return undef unless($rhInfo);
867             #1. Get Data
868 0         0 my ($oPps) = _getPpsTree(0, $rhInfo, $bData);
869 0         0 close(IN);
870 0         0 return $oPps;
871             }
872             #------------------------------------------------------------------------------
873             # getSearch: OLE::Storage_Lite
874             #------------------------------------------------------------------------------
875             sub getPpsSearch($$;$$)
876             {
877 0     0 1 0 my($oThis, $raName, $bData, $iCase) = @_;
878             #0.Init
879 0         0 my $rhInfo = _initParse($oThis->{_FILE});
880 0 0       0 return undef unless($rhInfo);
881             #1. Get Data
882 0         0 my @aList = _getPpsSearch(0, $rhInfo, $raName, $bData, $iCase);
883 0         0 close(IN);
884 0         0 return @aList;
885             }
886             #------------------------------------------------------------------------------
887             # getNthPps: OLE::Storage_Lite
888             #------------------------------------------------------------------------------
889             sub getNthPps($$;$)
890             {
891 0     0 1 0 my($oThis, $iNo, $bData) = @_;
892             #0.Init
893 0         0 my $rhInfo = _initParse($oThis->{_FILE});
894 0 0       0 return undef unless($rhInfo);
895             #1. Get Data
896 0         0 my $oPps = _getNthPps($iNo, $rhInfo, $bData);
897 0         0 close IN;
898 0         0 return $oPps;
899             }
900             #------------------------------------------------------------------------------
901             # _initParse: OLE::Storage_Lite
902             #------------------------------------------------------------------------------
903             sub _initParse($) {
904 0     0   0 my($sFile)=@_;
905 0         0 my $oIo;
906             #1. $sFile is Ref of scalar
907 0 0       0 if(ref($sFile) eq 'SCALAR') {
    0          
    0          
908 0         0 require IO::Scalar;
909 0         0 $oIo = new IO::Scalar;
910 0         0 $oIo->open($sFile);
911             }
912             #2. $sFile is a IO::Handle object
913             elsif(UNIVERSAL::isa($sFile, 'IO::Handle')) {
914 0         0 $oIo = $sFile;
915 0         0 binmode($oIo);
916             }
917             #3. $sFile is a simple filename string
918             elsif(!ref($sFile)) {
919 0         0 $oIo = new IO::File;
920 0 0       0 $oIo->open("<$sFile") || return undef;
921 0         0 binmode($oIo);
922             }
923             #4 Assume that if $sFile is a ref then it is a valid filehandle
924             else {
925 0         0 $oIo = $sFile;
926             # Not all filehandles support binmode() so try it in an eval.
927 0         0 eval{ binmode $oIo };
  0         0  
928             }
929 0         0 return _getHeaderInfo($oIo);
930             }
931             #------------------------------------------------------------------------------
932             # _getPpsTree: OLE::Storage_Lite
933             #------------------------------------------------------------------------------
934             sub _getPpsTree($$$;$) {
935 0     0   0 my($iNo, $rhInfo, $bData, $raDone) = @_;
936 0 0       0 if(defined($raDone)) {
937 0 0       0 return () if(grep {$_ ==$iNo} @$raDone);
  0         0  
938             }
939             else {
940 0         0 $raDone=[];
941             }
942 0         0 push @$raDone, $iNo;
943            
944 0         0 my $iRootBlock = $rhInfo->{_ROOT_START} ;
945             #1. Get Information about itself
946 0         0 my $oPps = _getNthPps($iNo, $rhInfo, $bData);
947             #2. Child
948 0 0       0 if($oPps->{DirPps} != 0xFFFFFFFF) {
949 0         0 my @aChildL = _getPpsTree($oPps->{DirPps}, $rhInfo, $bData, $raDone);
950 0         0 $oPps->{Child} = \@aChildL;
951             }
952             else {
953 0         0 $oPps->{Child} = undef;
954             }
955             #3. Previous,Next PPSs
956 0         0 my @aList = ();
957             push @aList, _getPpsTree($oPps->{PrevPps}, $rhInfo, $bData, $raDone)
958 0 0       0 if($oPps->{PrevPps} != 0xFFFFFFFF);
959 0         0 push @aList, $oPps;
960             push @aList, _getPpsTree($oPps->{NextPps}, $rhInfo, $bData, $raDone)
961 0 0       0 if($oPps->{NextPps} != 0xFFFFFFFF);
962 0         0 return @aList;
963             }
964             #------------------------------------------------------------------------------
965             # _getPpsSearch: OLE::Storage_Lite
966             #------------------------------------------------------------------------------
967             sub _getPpsSearch($$$$$;$) {
968 0     0   0 my($iNo, $rhInfo, $raName, $bData, $iCase, $raDone) = @_;
969 0         0 my $iRootBlock = $rhInfo->{_ROOT_START} ;
970 0         0 my @aRes;
971             #1. Check it self
972 0 0       0 if(defined($raDone)) {
973 0 0       0 return () if(grep {$_==$iNo} @$raDone);
  0         0  
974             }
975             else {
976 0         0 $raDone=[];
977             }
978 0         0 push @$raDone, $iNo;
979 0         0 my $oPps = _getNthPps($iNo, $rhInfo, undef);
980             # if(grep($_ eq $oPps->{Name}, @$raName)) {
981 0 0 0     0 if(($iCase && (grep(/^\Q$oPps->{Name}\E$/i, @$raName))) ||
      0        
982             (grep($_ eq $oPps->{Name}, @$raName))) {
983 0 0       0 $oPps = _getNthPps($iNo, $rhInfo, $bData) if ($bData);
984 0         0 @aRes = ($oPps);
985             }
986             else {
987 0         0 @aRes = ();
988             }
989             #2. Check Child, Previous, Next PPSs
990             push @aRes, _getPpsSearch($oPps->{DirPps}, $rhInfo, $raName, $bData, $iCase, $raDone)
991 0 0       0 if($oPps->{DirPps} != 0xFFFFFFFF) ;
992             push @aRes, _getPpsSearch($oPps->{PrevPps}, $rhInfo, $raName, $bData, $iCase, $raDone)
993 0 0       0 if($oPps->{PrevPps} != 0xFFFFFFFF );
994             push @aRes, _getPpsSearch($oPps->{NextPps}, $rhInfo, $raName, $bData, $iCase, $raDone)
995 0 0       0 if($oPps->{NextPps} != 0xFFFFFFFF);
996 0         0 return @aRes;
997             }
998             #===================================================================
999             # Get Header Info (BASE Informain about that file)
1000             #===================================================================
1001             sub _getHeaderInfo($){
1002 0     0   0 my($FILE) = @_;
1003 0         0 my($iWk);
1004 0         0 my $rhInfo = {};
1005 0         0 $rhInfo->{_FILEH_} = $FILE;
1006 0         0 my $sWk;
1007             #0. Check ID
1008 0         0 $rhInfo->{_FILEH_}->seek(0, 0);
1009 0         0 $rhInfo->{_FILEH_}->read($sWk, 8);
1010 0 0       0 return undef unless($sWk eq "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1");
1011             #BIG BLOCK SIZE
1012 0         0 $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x1E, 2, "v");
1013 0 0       0 return undef unless(defined($iWk));
1014 0         0 $rhInfo->{_BIG_BLOCK_SIZE} = 2 ** $iWk;
1015             #SMALL BLOCK SIZE
1016 0         0 $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x20, 2, "v");
1017 0 0       0 return undef unless(defined($iWk));
1018 0         0 $rhInfo->{_SMALL_BLOCK_SIZE} = 2 ** $iWk;
1019             #BDB Count
1020 0         0 $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x2C, 4, "V");
1021 0 0       0 return undef unless(defined($iWk));
1022 0         0 $rhInfo->{_BDB_COUNT} = $iWk;
1023             #START BLOCK
1024 0         0 $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x30, 4, "V");
1025 0 0       0 return undef unless(defined($iWk));
1026 0         0 $rhInfo->{_ROOT_START} = $iWk;
1027             #MIN SIZE OF BB
1028             # $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x38, 4, "V");
1029             # return undef unless(defined($iWk));
1030             # $rhInfo->{_MIN_SIZE_BB} = $iWk;
1031             #SMALL BD START
1032 0         0 $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x3C, 4, "V");
1033 0 0       0 return undef unless(defined($iWk));
1034 0         0 $rhInfo->{_SBD_START} = $iWk;
1035             #SMALL BD COUNT
1036 0         0 $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x40, 4, "V");
1037 0 0       0 return undef unless(defined($iWk));
1038 0         0 $rhInfo->{_SBD_COUNT} = $iWk;
1039             #EXTRA BBD START
1040 0         0 $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x44, 4, "V");
1041 0 0       0 return undef unless(defined($iWk));
1042 0         0 $rhInfo->{_EXTRA_BBD_START} = $iWk;
1043             #EXTRA BD COUNT
1044 0         0 $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x48, 4, "V");
1045 0 0       0 return undef unless(defined($iWk));
1046 0         0 $rhInfo->{_EXTRA_BBD_COUNT} = $iWk;
1047             #GET BBD INFO
1048 0         0 $rhInfo->{_BBD_INFO}= _getBbdInfo($rhInfo);
1049             #GET ROOT PPS
1050 0         0 my $oRoot = _getNthPps(0, $rhInfo, undef);
1051 0         0 $rhInfo->{_SB_START} = $oRoot->{StartBlock};
1052 0         0 $rhInfo->{_SB_SIZE} = $oRoot->{Size};
1053 0         0 return $rhInfo;
1054             }
1055             #------------------------------------------------------------------------------
1056             # _getInfoFromFile
1057             #------------------------------------------------------------------------------
1058             sub _getInfoFromFile($$$$) {
1059 0     0   0 my($FILE, $iPos, $iLen, $sFmt) =@_;
1060 0         0 my($sWk);
1061 0 0       0 return undef unless($FILE);
1062 0 0       0 return undef if($FILE->seek($iPos, 0)==0);
1063 0 0       0 return undef if($FILE->read($sWk, $iLen)!=$iLen);
1064 0         0 return unpack($sFmt, $sWk);
1065             }
1066             #------------------------------------------------------------------------------
1067             # _getBbdInfo
1068             #------------------------------------------------------------------------------
1069             sub _getBbdInfo($) {
1070 0     0   0 my($rhInfo) =@_;
1071 0         0 my @aBdList = ();
1072 0         0 my $iBdbCnt = $rhInfo->{_BDB_COUNT};
1073 0         0 my $iGetCnt;
1074             my $sWk;
1075 0         0 my $i1stCnt = int(($rhInfo->{_BIG_BLOCK_SIZE} - 0x4C) / OLE::Storage_Lite::LongIntSize());
1076 0         0 my $iBdlCnt = int($rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize()) - 1;
1077            
1078             #1. 1st BDlist
1079 0         0 $rhInfo->{_FILEH_}->seek(0x4C, 0);
1080 0 0       0 $iGetCnt = ($iBdbCnt < $i1stCnt)? $iBdbCnt: $i1stCnt;
1081 0         0 $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::LongIntSize()*$iGetCnt);
1082 0         0 push @aBdList, unpack("V$iGetCnt", $sWk);
1083 0         0 $iBdbCnt -= $iGetCnt;
1084             #2. Extra BDList
1085 0         0 my $iBlock = $rhInfo->{_EXTRA_BBD_START};
1086 0   0     0 while(($iBdbCnt> 0) && _isNormalBlock($iBlock)){
1087 0         0 _setFilePos($iBlock, 0, $rhInfo);
1088 0 0       0 $iGetCnt= ($iBdbCnt < $iBdlCnt)? $iBdbCnt: $iBdlCnt;
1089 0         0 $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::LongIntSize()*$iGetCnt);
1090 0         0 push @aBdList, unpack("V$iGetCnt", $sWk);
1091 0         0 $iBdbCnt -= $iGetCnt;
1092 0         0 $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::LongIntSize());
1093 0         0 $iBlock = unpack("V", $sWk);
1094             }
1095             #3.Get BDs
1096 0         0 my @aWk;
1097             my %hBd;
1098 0         0 my $iBlkNo = 0;
1099 0         0 my $iBdL;
1100             my $i;
1101 0         0 my $iBdCnt = int($rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize());
1102 0         0 foreach $iBdL (@aBdList) {
1103 0         0 _setFilePos($iBdL, 0, $rhInfo);
1104 0         0 $rhInfo->{_FILEH_}->read($sWk, $rhInfo->{_BIG_BLOCK_SIZE});
1105 0         0 @aWk = unpack("V$iBdCnt", $sWk);
1106 0         0 for($i=0;$i<$iBdCnt;$i++, $iBlkNo++) {
1107 0 0       0 if($aWk[$i] != ($iBlkNo+1)){
1108 0         0 $hBd{$iBlkNo} = $aWk[$i];
1109             }
1110             }
1111             }
1112 0         0 return \%hBd;
1113             }
1114             #------------------------------------------------------------------------------
1115             # getNthPps (OLE::Storage_Lite)
1116             #------------------------------------------------------------------------------
1117             sub _getNthPps($$$){
1118 0     0   0 my($iPos, $rhInfo, $bData) = @_;
1119 0         0 my($iPpsStart) = ($rhInfo->{_ROOT_START});
1120 0         0 my($iPpsBlock, $iPpsPos);
1121 0         0 my $sWk;
1122 0         0 my $iBlock;
1123            
1124 0         0 my $iBaseCnt = $rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::PpsSize();
1125 0         0 $iPpsBlock = int($iPos / $iBaseCnt);
1126 0         0 $iPpsPos = $iPos % $iBaseCnt;
1127            
1128 0         0 $iBlock = _getNthBlockNo($iPpsStart, $iPpsBlock, $rhInfo);
1129 0 0       0 return undef unless(defined($iBlock));
1130            
1131 0         0 _setFilePos($iBlock, OLE::Storage_Lite::PpsSize()*$iPpsPos, $rhInfo);
1132 0         0 $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::PpsSize());
1133 0 0       0 return undef unless($sWk);
1134 0         0 my $iNmSize = unpack("v", substr($sWk, 0x40, 2));
1135 0 0       0 $iNmSize = ($iNmSize > 2)? $iNmSize - 2 : $iNmSize;
1136 0         0 my $sNm= substr($sWk, 0, $iNmSize);
1137 0         0 my $iType = unpack("C", substr($sWk, 0x42, 2));
1138 0         0 my $lPpsPrev = unpack("V", substr($sWk, 0x44, OLE::Storage_Lite::LongIntSize()));
1139 0         0 my $lPpsNext = unpack("V", substr($sWk, 0x48, OLE::Storage_Lite::LongIntSize()));
1140 0         0 my $lDirPps = unpack("V", substr($sWk, 0x4C, OLE::Storage_Lite::LongIntSize()));
1141 0 0 0     0 my @raTime1st =
    0 0        
1142             (($iType == OLE::Storage_Lite::PpsType_Root()) or ($iType == OLE::Storage_Lite::PpsType_Dir()))?
1143             OLEDate2Local(substr($sWk, 0x64, 8)) : undef ,
1144             my @raTime2nd =
1145             (($iType == OLE::Storage_Lite::PpsType_Root()) or ($iType == OLE::Storage_Lite::PpsType_Dir()))?
1146             OLEDate2Local(substr($sWk, 0x6C, 8)) : undef,
1147             my($iStart, $iSize) = unpack("VV", substr($sWk, 0x74, 8));
1148 0 0       0 if($bData) {
1149 0         0 my $sData = _getData($iType, $iStart, $iSize, $rhInfo);
1150 0         0 return OLE::Storage_Lite::PPS->new(
1151             $iPos, $sNm, $iType, $lPpsPrev, $lPpsNext, $lDirPps,
1152             \@raTime1st, \@raTime2nd, $iStart, $iSize, $sData, undef);
1153             }
1154             else {
1155 0         0 return OLE::Storage_Lite::PPS->new(
1156             $iPos, $sNm, $iType, $lPpsPrev, $lPpsNext, $lDirPps,
1157             \@raTime1st, \@raTime2nd, $iStart, $iSize, undef, undef);
1158             }
1159             }
1160             #------------------------------------------------------------------------------
1161             # _setFilePos (OLE::Storage_Lite)
1162             #------------------------------------------------------------------------------
1163             sub _setFilePos($$$){
1164 0     0   0 my($iBlock, $iPos, $rhInfo) = @_;
1165 0         0 $rhInfo->{_FILEH_}->seek(($iBlock+1)*$rhInfo->{_BIG_BLOCK_SIZE}+$iPos, 0);
1166             }
1167             #------------------------------------------------------------------------------
1168             # _getNthBlockNo (OLE::Storage_Lite)
1169             #------------------------------------------------------------------------------
1170             sub _getNthBlockNo($$$){
1171 0     0   0 my($iStBlock, $iNth, $rhInfo) = @_;
1172 0         0 my $iSv;
1173 0         0 my $iNext = $iStBlock;
1174 0         0 for(my $i =0; $i<$iNth; $i++) {
1175 0         0 $iSv = $iNext;
1176 0         0 $iNext = _getNextBlockNo($iSv, $rhInfo);
1177 0 0       0 return undef unless _isNormalBlock($iNext);
1178             }
1179 0         0 return $iNext;
1180             }
1181             #------------------------------------------------------------------------------
1182             # _getData (OLE::Storage_Lite)
1183             #------------------------------------------------------------------------------
1184             sub _getData($$$$)
1185             {
1186 0     0   0 my($iType, $iBlock, $iSize, $rhInfo) = @_;
1187 0 0       0 if ($iType == OLE::Storage_Lite::PpsType_File()) {
    0          
    0          
1188 0 0       0 if($iSize < OLE::Storage_Lite::DataSizeSmall()) {
1189 0         0 return _getSmallData($iBlock, $iSize, $rhInfo);
1190             }
1191             else {
1192 0         0 return _getBigData($iBlock, $iSize, $rhInfo);
1193             }
1194             }
1195             elsif($iType == OLE::Storage_Lite::PpsType_Root()) { #Root
1196 0         0 return _getBigData($iBlock, $iSize, $rhInfo);
1197             }
1198             elsif($iType == OLE::Storage_Lite::PpsType_Dir()) { # Directory
1199 0         0 return undef;
1200             }
1201             }
1202             #------------------------------------------------------------------------------
1203             # _getBigData (OLE::Storage_Lite)
1204             #------------------------------------------------------------------------------
1205             sub _getBigData($$$)
1206             {
1207 0     0   0 my($iBlock, $iSize, $rhInfo) = @_;
1208 0         0 my($iRest, $sWk, $sRes);
1209            
1210 0 0       0 return '' unless(_isNormalBlock($iBlock));
1211 0         0 $iRest = $iSize;
1212 0         0 my($i, $iGetSize, $iNext);
1213 0         0 $sRes = '';
1214 0         0 my @aKeys= sort({$a<=>$b} keys(%{$rhInfo->{_BBD_INFO}}));
  0         0  
  0         0  
1215            
1216 0         0 while ($iRest > 0) {
1217 0         0 my @aRes = grep($_ >= $iBlock, @aKeys);
1218 0         0 my $iNKey = $aRes[0];
1219 0         0 $i = $iNKey - $iBlock;
1220 0         0 $iNext = $rhInfo->{_BBD_INFO}{$iNKey};
1221 0         0 _setFilePos($iBlock, 0, $rhInfo);
1222 0         0 my $iGetSize = ($rhInfo->{_BIG_BLOCK_SIZE} * ($i+1));
1223 0 0       0 $iGetSize = $iRest if($iRest < $iGetSize);
1224 0         0 $rhInfo->{_FILEH_}->read( $sWk, $iGetSize);
1225 0         0 $sRes .= $sWk;
1226 0         0 $iRest -= $iGetSize;
1227 0         0 $iBlock= $iNext;
1228             }
1229 0         0 return $sRes;
1230             }
1231             #------------------------------------------------------------------------------
1232             # _getNextBlockNo (OLE::Storage_Lite)
1233             #------------------------------------------------------------------------------
1234             sub _getNextBlockNo($$){
1235 0     0   0 my($iBlockNo, $rhInfo) = @_;
1236 0         0 my $iRes = $rhInfo->{_BBD_INFO}->{$iBlockNo};
1237 0 0       0 return defined($iRes)? $iRes: $iBlockNo+1;
1238             }
1239             #------------------------------------------------------------------------------
1240             # _isNormalBlock (OLE::Storage_Lite)
1241             # 0xFFFFFFFC : BDList, 0xFFFFFFFD : BBD,
1242             # 0xFFFFFFFE: End of Chain 0xFFFFFFFF : unused
1243             #------------------------------------------------------------------------------
1244             sub _isNormalBlock($){
1245 0     0   0 my($iBlock) = @_;
1246 0 0       0 return ($iBlock < 0xFFFFFFFC)? 1: undef;
1247             }
1248             #------------------------------------------------------------------------------
1249             # _getSmallData (OLE::Storage_Lite)
1250             #------------------------------------------------------------------------------
1251             sub _getSmallData($$$)
1252             {
1253 0     0   0 my($iSmBlock, $iSize, $rhInfo) = @_;
1254 0         0 my($sRes, $sWk);
1255 0         0 my $iRest = $iSize;
1256 0         0 $sRes = '';
1257 0         0 while ($iRest > 0) {
1258 0         0 _setFilePosSmall($iSmBlock, $rhInfo);
1259             $rhInfo->{_FILEH_}->read($sWk,
1260             ($iRest >= $rhInfo->{_SMALL_BLOCK_SIZE})?
1261 0 0       0 $rhInfo->{_SMALL_BLOCK_SIZE}: $iRest);
1262 0         0 $sRes .= $sWk;
1263 0         0 $iRest -= $rhInfo->{_SMALL_BLOCK_SIZE};
1264 0         0 $iSmBlock= _getNextSmallBlockNo($iSmBlock, $rhInfo);
1265             }
1266 0         0 return $sRes;
1267             }
1268             #------------------------------------------------------------------------------
1269             # _setFilePosSmall(OLE::Storage_Lite)
1270             #------------------------------------------------------------------------------
1271             sub _setFilePosSmall($$)
1272             {
1273 0     0   0 my($iSmBlock, $rhInfo) = @_;
1274 0         0 my $iSmStart = $rhInfo->{_SB_START};
1275 0         0 my $iBaseCnt = $rhInfo->{_BIG_BLOCK_SIZE} / $rhInfo->{_SMALL_BLOCK_SIZE};
1276 0         0 my $iNth = int($iSmBlock/$iBaseCnt);
1277 0         0 my $iPos = $iSmBlock % $iBaseCnt;
1278            
1279 0         0 my $iBlk = _getNthBlockNo($iSmStart, $iNth, $rhInfo);
1280 0         0 _setFilePos($iBlk, $iPos * $rhInfo->{_SMALL_BLOCK_SIZE}, $rhInfo);
1281             }
1282             #------------------------------------------------------------------------------
1283             # _getNextSmallBlockNo (OLE::Storage_Lite)
1284             #------------------------------------------------------------------------------
1285             sub _getNextSmallBlockNo($$)
1286             {
1287 0     0   0 my($iSmBlock, $rhInfo) = @_;
1288 0         0 my($sWk);
1289            
1290 0         0 my $iBaseCnt = $rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize();
1291 0         0 my $iNth = int($iSmBlock/$iBaseCnt);
1292 0         0 my $iPos = $iSmBlock % $iBaseCnt;
1293 0         0 my $iBlk = _getNthBlockNo($rhInfo->{_SBD_START}, $iNth, $rhInfo);
1294 0         0 _setFilePos($iBlk, $iPos * OLE::Storage_Lite::LongIntSize(), $rhInfo);
1295 0         0 $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::LongIntSize());
1296 0         0 return unpack("V", $sWk);
1297            
1298             }
1299             #------------------------------------------------------------------------------
1300             # Asc2Ucs: OLE::Storage_Lite
1301             #------------------------------------------------------------------------------
1302             sub Asc2Ucs($)
1303             {
1304 0     0 1 0 my($sAsc) = @_;
1305 0         0 return join("\x00", split //, $sAsc) . "\x00";
1306             }
1307             #------------------------------------------------------------------------------
1308             # Ucs2Asc: OLE::Storage_Lite
1309             #------------------------------------------------------------------------------
1310             sub Ucs2Asc($)
1311             {
1312 0     0 1 0 my($sUcs) = @_;
1313 0         0 return join('', map(pack('c', $_), unpack('v*', $sUcs)));
1314             }
1315            
1316             #------------------------------------------------------------------------------
1317             # OLEDate2Local()
1318             #
1319             # Convert from a Window FILETIME structure to a localtime array. FILETIME is
1320             # a 64-bit value representing the number of 100-nanosecond intervals since
1321             # January 1 1601.
1322             #
1323             # We first convert the FILETIME to seconds and then subtract the difference
1324             # between the 1601 epoch and the 1970 Unix epoch.
1325             #
1326             sub OLEDate2Local {
1327            
1328 99     99 0 52286 my $oletime = shift;
1329            
1330             # Unpack the FILETIME into high and low longs.
1331 99         343 my ( $lo, $hi ) = unpack 'V2', $oletime;
1332            
1333             # Convert the longs to a double.
1334 99         199 my $nanoseconds = $hi * 2**32 + $lo;
1335            
1336             # Convert the 100 nanosecond units into seconds.
1337 99         159 my $time = $nanoseconds / 1e7;
1338            
1339             # Subtract the number of seconds between the 1601 and 1970 epochs.
1340 99         170 $time -= 11644473600;
1341            
1342             # Convert to a localtime (actually gmtime) structure.
1343 99         440 my @localtime = gmtime($time);
1344            
1345 99         326 return @localtime;
1346             }
1347            
1348             #------------------------------------------------------------------------------
1349             # LocalDate2OLE()
1350             #
1351             # Convert from a localtime array to a Window FILETIME structure. FILETIME is
1352             # a 64-bit value representing the number of 100-nanosecond intervals since
1353             # January 1 1601.
1354             #
1355             # We first convert the localtime (actually gmtime) to seconds and then add the
1356             # difference between the 1601 epoch and the 1970 Unix epoch. We convert that to
1357             # 100 nanosecond units, divide it into high and low longs and return it as a
1358             # packed 64bit structure.
1359             #
1360             sub LocalDate2OLE {
1361            
1362 99     99 0 53647 my $localtime = shift;
1363            
1364 99 50       242 return "\x00" x 8 unless $localtime;
1365            
1366             # Convert from localtime (actually gmtime) to seconds.
1367 99         142 my @localtimecopy = @{$localtime};
  99         332  
1368 99 100       321 $localtimecopy[5] += 1900 unless $localtimecopy[5] > 99;
1369 99         280 my $time = timegm( @localtimecopy );
1370            
1371             # Add the number of seconds between the 1601 and 1970 epochs.
1372 99         3358 $time += 11644473600;
1373            
1374             # The FILETIME seconds are in units of 100 nanoseconds.
1375 99         156 my $nanoseconds = $time * 1E7;
1376            
1377 2     2   1038 use POSIX 'fmod';
  2         16226  
  2         11  
1378            
1379             # Pack the total nanoseconds into 64 bits...
1380 99         184 my $hi = int( $nanoseconds / 2**32 );
1381 99         308 my $lo = fmod($nanoseconds, 2**32);
1382            
1383 99         268 my $oletime = pack "VV", $lo, $hi;
1384            
1385 99         289 return $oletime;
1386             }
1387            
1388             1;
1389             __END__