| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693 |
- # COPYRIGHT
- # The OLE::Storage_Lite module is Copyright (c) 2000,2001 Kawai Takanori. Japan. All rights reserved.
- # You may distribute under the terms of the Artistic License
- # (full text of the Artistic License http://dev.perl.org/licenses/artistic.html).
- # AUTHOR
- # Kawai Takanori kwitknr@cpan.org
- # This module is currently maintained by John McNamara jmcnamara@cpan.org
- # OLE::Storage_Lite
- # by Kawai, Takanori (Hippo2000) 2000.11.4, 8, 14
- # This Program is Still ALPHA version.
- #//////////////////////////////////////////////////////////////////////////////
- # OLE::Storage_Lite::PPS Object
- #//////////////////////////////////////////////////////////////////////////////
- #==============================================================================
- # OLE::Storage_Lite::PPS
- #==============================================================================
- package OLE::Storage_Lite::PPS;
- require Exporter;
- use strict;
- use vars qw($VERSION @ISA);
- @ISA = qw(Exporter);
- $VERSION = '0.18';
- #------------------------------------------------------------------------------
- # new (OLE::Storage_Lite::PPS)
- #------------------------------------------------------------------------------
- sub new ($$$$$$$$$$;$$) {
- #1. Constructor for General Usage
- my($sClass, $iNo, $sNm, $iType, $iPrev, $iNext, $iDir,
- $raTime1st, $raTime2nd, $iStart, $iSize, $sData, $raChild) = @_;
- if($iType == OLE::Storage_Lite::PpsType_File()) { #FILE
- return OLE::Storage_Lite::PPS::File->_new
- ($iNo, $sNm, $iType, $iPrev, $iNext, $iDir, $raTime1st, $raTime2nd,
- $iStart, $iSize, $sData, $raChild);
- }
- elsif($iType == OLE::Storage_Lite::PpsType_Dir()) { #DIRECTRY
- return OLE::Storage_Lite::PPS::Dir->_new
- ($iNo, $sNm, $iType, $iPrev, $iNext, $iDir, $raTime1st, $raTime2nd,
- $iStart, $iSize, $sData, $raChild);
- }
- elsif($iType == OLE::Storage_Lite::PpsType_Root()) { #ROOT
- return OLE::Storage_Lite::PPS::Root->_new
- ($iNo, $sNm, $iType, $iPrev, $iNext, $iDir, $raTime1st, $raTime2nd,
- $iStart, $iSize, $sData, $raChild);
- }
- else {
- die "Error PPS:$iType $sNm\n";
- }
- }
- #------------------------------------------------------------------------------
- # _new (OLE::Storage_Lite::PPS)
- # for OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub _new ($$$$$$$$$$$;$$) {
- my($sClass, $iNo, $sNm, $iType, $iPrev, $iNext, $iDir,
- $raTime1st, $raTime2nd, $iStart, $iSize, $sData, $raChild) = @_;
- #1. Constructor for OLE::Storage_Lite
- my $oThis = {
- No => $iNo,
- Name => $sNm,
- Type => $iType,
- PrevPps => $iPrev,
- NextPps => $iNext,
- DirPps => $iDir,
- Time1st => $raTime1st,
- Time2nd => $raTime2nd,
- StartBlock => $iStart,
- Size => $iSize,
- Data => $sData,
- Child => $raChild,
- };
- bless $oThis, $sClass;
- return $oThis;
- }
- #------------------------------------------------------------------------------
- # _DataLen (OLE::Storage_Lite::PPS)
- # Check for update
- #------------------------------------------------------------------------------
- sub _DataLen($) {
- my($oSelf) =@_;
- return 0 unless(defined($oSelf->{Data}));
- return ($oSelf->{_PPS_FILE})?
- ($oSelf->{_PPS_FILE}->stat())[7] : length($oSelf->{Data});
- }
- #------------------------------------------------------------------------------
- # _makeSmallData (OLE::Storage_Lite::PPS)
- #------------------------------------------------------------------------------
- sub _makeSmallData($$$) {
- my($oThis, $aList, $rhInfo) = @_;
- my ($sRes);
- my $FILE = $rhInfo->{_FILEH_};
- my $iSmBlk = 0;
- foreach my $oPps (@$aList) {
- #1. Make SBD, small data string
- if($oPps->{Type}==OLE::Storage_Lite::PpsType_File()) {
- next if($oPps->{Size}<=0);
- if($oPps->{Size} < $rhInfo->{_SMALL_SIZE}) {
- my $iSmbCnt = int($oPps->{Size} / $rhInfo->{_SMALL_BLOCK_SIZE})
- + (($oPps->{Size} % $rhInfo->{_SMALL_BLOCK_SIZE})? 1: 0);
- #1.1 Add to SBD
- for (my $i = 0; $i<($iSmbCnt-1); $i++) {
- print {$FILE} (pack("V", $i+$iSmBlk+1));
- }
- print {$FILE} (pack("V", -2));
- #1.2 Add to Data String(this will be written for RootEntry)
- #Check for update
- if($oPps->{_PPS_FILE}) {
- my $sBuff;
- $oPps->{_PPS_FILE}->seek(0, 0); #To The Top
- while($oPps->{_PPS_FILE}->read($sBuff, 4096)) {
- $sRes .= $sBuff;
- }
- }
- else {
- $sRes .= $oPps->{Data};
- }
- $sRes .= ("\x00" x
- ($rhInfo->{_SMALL_BLOCK_SIZE} - ($oPps->{Size}% $rhInfo->{_SMALL_BLOCK_SIZE})))
- if($oPps->{Size}% $rhInfo->{_SMALL_BLOCK_SIZE});
- #1.3 Set for PPS
- $oPps->{StartBlock} = $iSmBlk;
- $iSmBlk += $iSmbCnt;
- }
- }
- }
- my $iSbCnt = int($rhInfo->{_BIG_BLOCK_SIZE}/ OLE::Storage_Lite::LongIntSize());
- print {$FILE} (pack("V", -1) x ($iSbCnt - ($iSmBlk % $iSbCnt)))
- if($iSmBlk % $iSbCnt);
- #2. Write SBD with adjusting length for block
- return $sRes;
- }
- #------------------------------------------------------------------------------
- # _savePpsWk (OLE::Storage_Lite::PPS)
- #------------------------------------------------------------------------------
- sub _savePpsWk($$)
- {
- my($oThis, $rhInfo) = @_;
- #1. Write PPS
- my $FILE = $rhInfo->{_FILEH_};
- print {$FILE} (
- $oThis->{Name}
- . ("\x00" x (64 - length($oThis->{Name}))) #64
- , pack("v", length($oThis->{Name}) + 2) #66
- , pack("c", $oThis->{Type}) #67
- , pack("c", 0x00) #UK #68
- , pack("V", $oThis->{PrevPps}) #Prev #72
- , pack("V", $oThis->{NextPps}) #Next #76
- , pack("V", $oThis->{DirPps}) #Dir #80
- , "\x00\x09\x02\x00" #84
- , "\x00\x00\x00\x00" #88
- , "\xc0\x00\x00\x00" #92
- , "\x00\x00\x00\x46" #96
- , "\x00\x00\x00\x00" #100
- , OLE::Storage_Lite::LocalDate2OLE($oThis->{Time1st}) #108
- , OLE::Storage_Lite::LocalDate2OLE($oThis->{Time2nd}) #116
- , pack("V", defined($oThis->{StartBlock})?
- $oThis->{StartBlock}:0) #116
- , pack("V", defined($oThis->{Size})?
- $oThis->{Size} : 0) #124
- , pack("V", 0), #128
- );
- }
- #//////////////////////////////////////////////////////////////////////////////
- # OLE::Storage_Lite::PPS::Root Object
- #//////////////////////////////////////////////////////////////////////////////
- #==============================================================================
- # OLE::Storage_Lite::PPS::Root
- #==============================================================================
- package OLE::Storage_Lite::PPS::Root;
- require Exporter;
- use strict;
- use IO::File;
- use IO::Handle;
- use Fcntl;
- use vars qw($VERSION @ISA);
- @ISA = qw(OLE::Storage_Lite::PPS Exporter);
- $VERSION = '0.18';
- sub _savePpsSetPnt($$$);
- sub _savePpsSetPnt2($$$);
- #------------------------------------------------------------------------------
- # new (OLE::Storage_Lite::PPS::Root)
- #------------------------------------------------------------------------------
- sub new ($;$$$) {
- my($sClass, $raTime1st, $raTime2nd, $raChild) = @_;
- OLE::Storage_Lite::PPS::_new(
- $sClass,
- undef,
- OLE::Storage_Lite::Asc2Ucs('Root Entry'),
- 5,
- undef,
- undef,
- undef,
- $raTime1st,
- $raTime2nd,
- undef,
- undef,
- undef,
- $raChild);
- }
- #------------------------------------------------------------------------------
- # save (OLE::Storage_Lite::PPS::Root)
- #------------------------------------------------------------------------------
- sub save($$;$$) {
- my($oThis, $sFile, $bNoAs, $rhInfo) = @_;
- #0.Initial Setting for saving
- $rhInfo = {} unless($rhInfo);
- $rhInfo->{_BIG_BLOCK_SIZE} = 2**
- (($rhInfo->{_BIG_BLOCK_SIZE})?
- _adjust2($rhInfo->{_BIG_BLOCK_SIZE}) : 9);
- $rhInfo->{_SMALL_BLOCK_SIZE}= 2 **
- (($rhInfo->{_SMALL_BLOCK_SIZE})?
- _adjust2($rhInfo->{_SMALL_BLOCK_SIZE}): 6);
- $rhInfo->{_SMALL_SIZE} = 0x1000;
- $rhInfo->{_PPS_SIZE} = 0x80;
- my $closeFile = 1;
- #1.Open File
- #1.1 $sFile is Ref of scalar
- if(ref($sFile) eq 'SCALAR') {
- require IO::Scalar;
- my $oIo = new IO::Scalar $sFile, O_WRONLY;
- $rhInfo->{_FILEH_} = $oIo;
- }
- #1.1.1 $sFile is a IO::Scalar object
- # Now handled as a filehandle ref below.
- #1.2 $sFile is a IO::Handle object
- elsif(UNIVERSAL::isa($sFile, 'IO::Handle')) {
- # Not all filehandles support binmode() so try it in an eval.
- eval{ binmode $sFile };
- $rhInfo->{_FILEH_} = $sFile;
- }
- #1.3 $sFile is a simple filename string
- elsif(!ref($sFile)) {
- if($sFile ne '-') {
- my $oIo = new IO::File;
- $oIo->open(">$sFile") || return undef;
- binmode($oIo);
- $rhInfo->{_FILEH_} = $oIo;
- }
- else {
- my $oIo = new IO::Handle;
- $oIo->fdopen(fileno(STDOUT),"w") || return undef;
- binmode($oIo);
- $rhInfo->{_FILEH_} = $oIo;
- }
- }
- #1.4 Assume that if $sFile is a ref then it is a valid filehandle
- else {
- # Not all filehandles support binmode() so try it in an eval.
- eval{ binmode $sFile };
- $rhInfo->{_FILEH_} = $sFile;
- # Caller controls filehandle closing
- $closeFile = 0;
- }
- my $iBlk = 0;
- #1. Make an array of PPS (for Save)
- my @aList=();
- if($bNoAs) {
- _savePpsSetPnt2([$oThis], \@aList, $rhInfo);
- }
- else {
- _savePpsSetPnt([$oThis], \@aList, $rhInfo);
- }
- my ($iSBDcnt, $iBBcnt, $iPPScnt) = $oThis->_calcSize(\@aList, $rhInfo);
- #2.Save Header
- $oThis->_saveHeader($rhInfo, $iSBDcnt, $iBBcnt, $iPPScnt);
- #3.Make Small Data string (write SBD)
- my $sSmWk = $oThis->_makeSmallData(\@aList, $rhInfo);
- $oThis->{Data} = $sSmWk; #Small Datas become RootEntry Data
- #4. Write BB
- my $iBBlk = $iSBDcnt;
- $oThis->_saveBigData(\$iBBlk, \@aList, $rhInfo);
- #5. Write PPS
- $oThis->_savePps(\@aList, $rhInfo);
- #6. Write BD and BDList and Adding Header informations
- $oThis->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt, $rhInfo);
- #7.Close File
- return $rhInfo->{_FILEH_}->close if $closeFile;
- }
- #------------------------------------------------------------------------------
- # _calcSize (OLE::Storage_Lite::PPS)
- #------------------------------------------------------------------------------
- sub _calcSize($$)
- {
- my($oThis, $raList, $rhInfo) = @_;
- #0. Calculate Basic Setting
- my ($iSBDcnt, $iBBcnt, $iPPScnt) = (0,0,0);
- my $iSmallLen = 0;
- my $iSBcnt = 0;
- foreach my $oPps (@$raList) {
- if($oPps->{Type}==OLE::Storage_Lite::PpsType_File()) {
- $oPps->{Size} = $oPps->_DataLen(); #Mod
- if($oPps->{Size} < $rhInfo->{_SMALL_SIZE}) {
- $iSBcnt += int($oPps->{Size} / $rhInfo->{_SMALL_BLOCK_SIZE})
- + (($oPps->{Size} % $rhInfo->{_SMALL_BLOCK_SIZE})? 1: 0);
- }
- else {
- $iBBcnt +=
- (int($oPps->{Size}/ $rhInfo->{_BIG_BLOCK_SIZE}) +
- (($oPps->{Size}% $rhInfo->{_BIG_BLOCK_SIZE})? 1: 0));
- }
- }
- }
- $iSmallLen = $iSBcnt * $rhInfo->{_SMALL_BLOCK_SIZE};
- my $iSlCnt = int($rhInfo->{_BIG_BLOCK_SIZE}/ OLE::Storage_Lite::LongIntSize());
- $iSBDcnt = int($iSBcnt / $iSlCnt)+ (($iSBcnt % $iSlCnt)? 1:0);
- $iBBcnt += (int($iSmallLen/ $rhInfo->{_BIG_BLOCK_SIZE}) +
- (( $iSmallLen% $rhInfo->{_BIG_BLOCK_SIZE})? 1: 0));
- my $iCnt = scalar(@$raList);
- my $iBdCnt = $rhInfo->{_BIG_BLOCK_SIZE}/OLE::Storage_Lite::PpsSize();
- $iPPScnt = (int($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0));
- return ($iSBDcnt, $iBBcnt, $iPPScnt);
- }
- #------------------------------------------------------------------------------
- # _adjust2 (OLE::Storage_Lite::PPS::Root)
- #------------------------------------------------------------------------------
- sub _adjust2($) {
- my($i2) = @_;
- my $iWk;
- $iWk = log($i2)/log(2);
- return ($iWk > int($iWk))? int($iWk)+1:$iWk;
- }
- #------------------------------------------------------------------------------
- # _saveHeader (OLE::Storage_Lite::PPS::Root)
- #------------------------------------------------------------------------------
- sub _saveHeader($$$$$) {
- my($oThis, $rhInfo, $iSBDcnt, $iBBcnt, $iPPScnt) = @_;
- my $FILE = $rhInfo->{_FILEH_};
- #0. Calculate Basic Setting
- my $iBlCnt = $rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize();
- my $i1stBdL = int(($rhInfo->{_BIG_BLOCK_SIZE} - 0x4C) / OLE::Storage_Lite::LongIntSize());
- my $i1stBdMax = $i1stBdL * $iBlCnt - $i1stBdL;
- my $iBdExL = 0;
- my $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
- my $iAllW = $iAll;
- my $iBdCntW = int($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
- my $iBdCnt = 0;
- my $i;
- #0.1 Calculate BD count
- $iBlCnt--; #the BlCnt is reduced in the count of the last sect is used for a pointer the next Bl
- my $iBBleftover = $iAll - $i1stBdMax;
- if ($iAll >$i1stBdMax) {
- while(1) {
- $iBdCnt = int(($iBBleftover) / $iBlCnt) + ((($iBBleftover) % $iBlCnt)? 1: 0);
- $iBdExL = int(($iBdCnt) / $iBlCnt) + ((($iBdCnt) % $iBlCnt)? 1: 0);
- $iBBleftover = $iBBleftover + $iBdExL;
- last if($iBdCnt == (int(($iBBleftover) / $iBlCnt) + ((($iBBleftover) % $iBlCnt)? 1: 0)));
- }
- }
- $iBdCnt += $i1stBdL;
- #print "iBdCnt = $iBdCnt \n";
- #1.Save Header
- print {$FILE} (
- "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
- , "\x00\x00\x00\x00" x 4
- , pack("v", 0x3b)
- , pack("v", 0x03)
- , pack("v", -2)
- , pack("v", 9)
- , pack("v", 6)
- , pack("v", 0)
- , "\x00\x00\x00\x00" x 2
- , pack("V", $iBdCnt),
- , pack("V", $iBBcnt+$iSBDcnt), #ROOT START
- , pack("V", 0)
- , pack("V", 0x1000)
- , pack("V", 0) #Small Block Depot
- , pack("V", 1)
- );
- #2. Extra BDList Start, Count
- if($iAll <= $i1stBdMax) {
- print {$FILE} (
- pack("V", -2), #Extra BDList Start
- pack("V", 0), #Extra BDList Count
- );
- }
- else {
- print {$FILE} (
- pack("V", $iAll+$iBdCnt),
- pack("V", $iBdExL),
- );
- }
- #3. BDList
- for($i=0; $i<$i1stBdL and $i < $iBdCnt; $i++) {
- print {$FILE} (pack("V", $iAll+$i));
- }
- print {$FILE} ((pack("V", -1)) x($i1stBdL-$i)) if($i<$i1stBdL);
- }
- #------------------------------------------------------------------------------
- # _saveBigData (OLE::Storage_Lite::PPS)
- #------------------------------------------------------------------------------
- sub _saveBigData($$$$) {
- my($oThis, $iStBlk, $raList, $rhInfo) = @_;
- my $iRes = 0;
- my $FILE = $rhInfo->{_FILEH_};
- #1.Write Big (ge 0x1000) Data into Block
- foreach my $oPps (@$raList) {
- if($oPps->{Type}!=OLE::Storage_Lite::PpsType_Dir()) {
- #print "PPS: $oPps DEF:", defined($oPps->{Data}), "\n";
- $oPps->{Size} = $oPps->_DataLen(); #Mod
- if(($oPps->{Size} >= $rhInfo->{_SMALL_SIZE}) ||
- (($oPps->{Type} == OLE::Storage_Lite::PpsType_Root()) && defined($oPps->{Data}))) {
- #1.1 Write Data
- #Check for update
- if($oPps->{_PPS_FILE}) {
- my $sBuff;
- my $iLen = 0;
- $oPps->{_PPS_FILE}->seek(0, 0); #To The Top
- while($oPps->{_PPS_FILE}->read($sBuff, 4096)) {
- $iLen += length($sBuff);
- print {$FILE} ($sBuff); #Check for update
- }
- }
- else {
- print {$FILE} ($oPps->{Data});
- }
- print {$FILE} (
- "\x00" x
- ($rhInfo->{_BIG_BLOCK_SIZE} -
- ($oPps->{Size} % $rhInfo->{_BIG_BLOCK_SIZE}))
- ) if ($oPps->{Size} % $rhInfo->{_BIG_BLOCK_SIZE});
- #1.2 Set For PPS
- $oPps->{StartBlock} = $$iStBlk;
- $$iStBlk +=
- (int($oPps->{Size}/ $rhInfo->{_BIG_BLOCK_SIZE}) +
- (($oPps->{Size}% $rhInfo->{_BIG_BLOCK_SIZE})? 1: 0));
- }
- }
- }
- }
- #------------------------------------------------------------------------------
- # _savePps (OLE::Storage_Lite::PPS::Root)
- #------------------------------------------------------------------------------
- sub _savePps($$$)
- {
- my($oThis, $raList, $rhInfo) = @_;
- #0. Initial
- my $FILE = $rhInfo->{_FILEH_};
- #2. Save PPS
- foreach my $oItem (@$raList) {
- $oItem->_savePpsWk($rhInfo);
- }
- #3. Adjust for Block
- my $iCnt = scalar(@$raList);
- my $iBCnt = $rhInfo->{_BIG_BLOCK_SIZE} / $rhInfo->{_PPS_SIZE};
- print {$FILE} ("\x00" x (($iBCnt - ($iCnt % $iBCnt)) * $rhInfo->{_PPS_SIZE}))
- if($iCnt % $iBCnt);
- return int($iCnt / $iBCnt) + (($iCnt % $iBCnt)? 1: 0);
- }
- #------------------------------------------------------------------------------
- # _savePpsSetPnt2 (OLE::Storage_Lite::PPS::Root)
- # For Test
- #------------------------------------------------------------------------------
- sub _savePpsSetPnt2($$$)
- {
- my($aThis, $raList, $rhInfo) = @_;
- #1. make Array as Children-Relations
- #1.1 if No Children
- if($#$aThis < 0) {
- return 0xFFFFFFFF;
- }
- elsif($#$aThis == 0) {
- #1.2 Just Only one
- push @$raList, $aThis->[0];
- $aThis->[0]->{No} = $#$raList;
- $aThis->[0]->{PrevPps} = 0xFFFFFFFF;
- $aThis->[0]->{NextPps} = 0xFFFFFFFF;
- $aThis->[0]->{DirPps} = _savePpsSetPnt2($aThis->[0]->{Child}, $raList, $rhInfo);
- return $aThis->[0]->{No};
- }
- else {
- #1.3 Array
- my $iCnt = $#$aThis + 1;
- #1.3.1 Define Center
- my $iPos = 0; #int($iCnt/ 2); #$iCnt
- my @aWk = @$aThis;
- my @aPrev = ($#$aThis > 1)? splice(@aWk, 1, 1) : (); #$iPos);
- my @aNext = splice(@aWk, 1); #, $iCnt - $iPos -1);
- $aThis->[$iPos]->{PrevPps} = _savePpsSetPnt2(
- \@aPrev, $raList, $rhInfo);
- push @$raList, $aThis->[$iPos];
- $aThis->[$iPos]->{No} = $#$raList;
- #1.3.2 Devide a array into Previous,Next
- $aThis->[$iPos]->{NextPps} = _savePpsSetPnt2(
- \@aNext, $raList, $rhInfo);
- $aThis->[$iPos]->{DirPps} = _savePpsSetPnt2($aThis->[$iPos]->{Child}, $raList, $rhInfo);
- return $aThis->[$iPos]->{No};
- }
- }
- #------------------------------------------------------------------------------
- # _savePpsSetPnt2 (OLE::Storage_Lite::PPS::Root)
- # For Test
- #------------------------------------------------------------------------------
- sub _savePpsSetPnt2s($$$)
- {
- my($aThis, $raList, $rhInfo) = @_;
- #1. make Array as Children-Relations
- #1.1 if No Children
- if($#$aThis < 0) {
- return 0xFFFFFFFF;
- }
- elsif($#$aThis == 0) {
- #1.2 Just Only one
- push @$raList, $aThis->[0];
- $aThis->[0]->{No} = $#$raList;
- $aThis->[0]->{PrevPps} = 0xFFFFFFFF;
- $aThis->[0]->{NextPps} = 0xFFFFFFFF;
- $aThis->[0]->{DirPps} = _savePpsSetPnt2($aThis->[0]->{Child}, $raList, $rhInfo);
- return $aThis->[0]->{No};
- }
- else {
- #1.3 Array
- my $iCnt = $#$aThis + 1;
- #1.3.1 Define Center
- my $iPos = 0; #int($iCnt/ 2); #$iCnt
- push @$raList, $aThis->[$iPos];
- $aThis->[$iPos]->{No} = $#$raList;
- my @aWk = @$aThis;
- #1.3.2 Devide a array into Previous,Next
- my @aPrev = splice(@aWk, 0, $iPos);
- my @aNext = splice(@aWk, 1, $iCnt - $iPos -1);
- $aThis->[$iPos]->{PrevPps} = _savePpsSetPnt2(
- \@aPrev, $raList, $rhInfo);
- $aThis->[$iPos]->{NextPps} = _savePpsSetPnt2(
- \@aNext, $raList, $rhInfo);
- $aThis->[$iPos]->{DirPps} = _savePpsSetPnt2($aThis->[$iPos]->{Child}, $raList, $rhInfo);
- return $aThis->[$iPos]->{No};
- }
- }
- #------------------------------------------------------------------------------
- # _savePpsSetPnt (OLE::Storage_Lite::PPS::Root)
- #------------------------------------------------------------------------------
- sub _savePpsSetPnt($$$)
- {
- my($aThis, $raList, $rhInfo) = @_;
- #1. make Array as Children-Relations
- #1.1 if No Children
- if($#$aThis < 0) {
- return 0xFFFFFFFF;
- }
- elsif($#$aThis == 0) {
- #1.2 Just Only one
- push @$raList, $aThis->[0];
- $aThis->[0]->{No} = $#$raList;
- $aThis->[0]->{PrevPps} = 0xFFFFFFFF;
- $aThis->[0]->{NextPps} = 0xFFFFFFFF;
- $aThis->[0]->{DirPps} = _savePpsSetPnt($aThis->[0]->{Child}, $raList, $rhInfo);
- return $aThis->[0]->{No};
- }
- else {
- #1.3 Array
- my $iCnt = $#$aThis + 1;
- #1.3.1 Define Center
- my $iPos = int($iCnt/ 2); #$iCnt
- push @$raList, $aThis->[$iPos];
- $aThis->[$iPos]->{No} = $#$raList;
- my @aWk = @$aThis;
- #1.3.2 Devide a array into Previous,Next
- my @aPrev = splice(@aWk, 0, $iPos);
- my @aNext = splice(@aWk, 1, $iCnt - $iPos -1);
- $aThis->[$iPos]->{PrevPps} = _savePpsSetPnt(
- \@aPrev, $raList, $rhInfo);
- $aThis->[$iPos]->{NextPps} = _savePpsSetPnt(
- \@aNext, $raList, $rhInfo);
- $aThis->[$iPos]->{DirPps} = _savePpsSetPnt($aThis->[$iPos]->{Child}, $raList, $rhInfo);
- return $aThis->[$iPos]->{No};
- }
- }
- #------------------------------------------------------------------------------
- # _savePpsSetPnt (OLE::Storage_Lite::PPS::Root)
- #------------------------------------------------------------------------------
- sub _savePpsSetPnt1($$$)
- {
- my($aThis, $raList, $rhInfo) = @_;
- #1. make Array as Children-Relations
- #1.1 if No Children
- if($#$aThis < 0) {
- return 0xFFFFFFFF;
- }
- elsif($#$aThis == 0) {
- #1.2 Just Only one
- push @$raList, $aThis->[0];
- $aThis->[0]->{No} = $#$raList;
- $aThis->[0]->{PrevPps} = 0xFFFFFFFF;
- $aThis->[0]->{NextPps} = 0xFFFFFFFF;
- $aThis->[0]->{DirPps} = _savePpsSetPnt($aThis->[0]->{Child}, $raList, $rhInfo);
- return $aThis->[0]->{No};
- }
- else {
- #1.3 Array
- my $iCnt = $#$aThis + 1;
- #1.3.1 Define Center
- my $iPos = int($iCnt/ 2); #$iCnt
- push @$raList, $aThis->[$iPos];
- $aThis->[$iPos]->{No} = $#$raList;
- my @aWk = @$aThis;
- #1.3.2 Devide a array into Previous,Next
- my @aPrev = splice(@aWk, 0, $iPos);
- my @aNext = splice(@aWk, 1, $iCnt - $iPos -1);
- $aThis->[$iPos]->{PrevPps} = _savePpsSetPnt(
- \@aPrev, $raList, $rhInfo);
- $aThis->[$iPos]->{NextPps} = _savePpsSetPnt(
- \@aNext, $raList, $rhInfo);
- $aThis->[$iPos]->{DirPps} = _savePpsSetPnt($aThis->[$iPos]->{Child}, $raList, $rhInfo);
- return $aThis->[$iPos]->{No};
- }
- }
- #------------------------------------------------------------------------------
- # _saveBbd (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _saveBbd($$$$)
- {
- my($oThis, $iSbdSize, $iBsize, $iPpsCnt, $rhInfo) = @_;
- my $FILE = $rhInfo->{_FILEH_};
- #0. Calculate Basic Setting
- my $iBbCnt = $rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize();
- my $iBlCnt = $iBbCnt - 1;
- my $i1stBdL = int(($rhInfo->{_BIG_BLOCK_SIZE} - 0x4C) / OLE::Storage_Lite::LongIntSize());
- my $i1stBdMax = $i1stBdL * $iBbCnt - $i1stBdL;
- my $iBdExL = 0;
- my $iAll = $iBsize + $iPpsCnt + $iSbdSize;
- my $iAllW = $iAll;
- my $iBdCntW = int($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
- my $iBdCnt = 0;
- my $i;
- #0.1 Calculate BD count
- my $iBBleftover = $iAll - $i1stBdMax;
- if ($iAll >$i1stBdMax) {
- while(1) {
- $iBdCnt = int(($iBBleftover) / $iBlCnt) + ((($iBBleftover) % $iBlCnt)? 1: 0);
- $iBdExL = int(($iBdCnt) / $iBlCnt) + ((($iBdCnt) % $iBlCnt)? 1: 0);
- $iBBleftover = $iBBleftover + $iBdExL;
- last if($iBdCnt == (int(($iBBleftover) / $iBlCnt) + ((($iBBleftover) % $iBlCnt)? 1: 0)));
- }
- }
- $iAllW += $iBdExL;
- $iBdCnt += $i1stBdL;
- #print "iBdCnt = $iBdCnt \n";
- #1. Making BD
- #1.1 Set for SBD
- if($iSbdSize > 0) {
- for ($i = 0; $i<($iSbdSize-1); $i++) {
- print {$FILE} (pack("V", $i+1));
- }
- print {$FILE} (pack("V", -2));
- }
- #1.2 Set for B
- for ($i = 0; $i<($iBsize-1); $i++) {
- print {$FILE} (pack("V", $i+$iSbdSize+1));
- }
- print {$FILE} (pack("V", -2));
- #1.3 Set for PPS
- for ($i = 0; $i<($iPpsCnt-1); $i++) {
- print {$FILE} (pack("V", $i+$iSbdSize+$iBsize+1));
- }
- print {$FILE} (pack("V", -2));
- #1.4 Set for BBD itself ( 0xFFFFFFFD : BBD)
- for($i=0; $i<$iBdCnt;$i++) {
- print {$FILE} (pack("V", 0xFFFFFFFD));
- }
- #1.5 Set for ExtraBDList
- for($i=0; $i<$iBdExL;$i++) {
- print {$FILE} (pack("V", 0xFFFFFFFC));
- }
- #1.6 Adjust for Block
- print {$FILE} (pack("V", -1) x ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)))
- if(($iAllW + $iBdCnt) % $iBbCnt);
- #2.Extra BDList
- if($iBdCnt > $i1stBdL) {
- my $iN=0;
- my $iNb=0;
- for($i=$i1stBdL;$i<$iBdCnt; $i++, $iN++) {
- if($iN>=($iBbCnt-1)) {
- $iN = 0;
- $iNb++;
- print {$FILE} (pack("V", $iAll+$iBdCnt+$iNb));
- }
- print {$FILE} (pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i));
- }
- print {$FILE} (pack("V", -1) x (($iBbCnt-1) - (($iBdCnt-$i1stBdL) % ($iBbCnt-1))))
- if(($iBdCnt-$i1stBdL) % ($iBbCnt-1));
- print {$FILE} (pack("V", -2));
- }
- }
- #//////////////////////////////////////////////////////////////////////////////
- # OLE::Storage_Lite::PPS::File Object
- #//////////////////////////////////////////////////////////////////////////////
- #==============================================================================
- # OLE::Storage_Lite::PPS::File
- #==============================================================================
- package OLE::Storage_Lite::PPS::File;
- require Exporter;
- use strict;
- use vars qw($VERSION @ISA);
- @ISA = qw(OLE::Storage_Lite::PPS Exporter);
- $VERSION = '0.18';
- #------------------------------------------------------------------------------
- # new (OLE::Storage_Lite::PPS::File)
- #------------------------------------------------------------------------------
- sub new ($$$) {
- my($sClass, $sNm, $sData) = @_;
- OLE::Storage_Lite::PPS::_new(
- $sClass,
- undef,
- $sNm,
- 2,
- undef,
- undef,
- undef,
- undef,
- undef,
- undef,
- undef,
- $sData,
- undef);
- }
- #------------------------------------------------------------------------------
- # newFile (OLE::Storage_Lite::PPS::File)
- #------------------------------------------------------------------------------
- sub newFile ($$;$) {
- my($sClass, $sNm, $sFile) = @_;
- my $oSelf =
- OLE::Storage_Lite::PPS::_new(
- $sClass,
- undef,
- $sNm,
- 2,
- undef,
- undef,
- undef,
- undef,
- undef,
- undef,
- undef,
- '',
- undef);
- #
- if((!defined($sFile)) or ($sFile eq '')) {
- $oSelf->{_PPS_FILE} = IO::File->new_tmpfile();
- }
- elsif(UNIVERSAL::isa($sFile, 'IO::Handle')) {
- $oSelf->{_PPS_FILE} = $sFile;
- }
- elsif(!ref($sFile)) {
- #File Name
- $oSelf->{_PPS_FILE} = new IO::File;
- return undef unless($oSelf->{_PPS_FILE});
- $oSelf->{_PPS_FILE}->open("$sFile", "r+") || return undef;
- }
- else {
- return undef;
- }
- if($oSelf->{_PPS_FILE}) {
- $oSelf->{_PPS_FILE}->seek(0, 2);
- binmode($oSelf->{_PPS_FILE});
- $oSelf->{_PPS_FILE}->autoflush(1);
- }
- return $oSelf;
- }
- #------------------------------------------------------------------------------
- # append (OLE::Storage_Lite::PPS::File)
- #------------------------------------------------------------------------------
- sub append ($$) {
- my($oSelf, $sData) = @_;
- if($oSelf->{_PPS_FILE}) {
- print {$oSelf->{_PPS_FILE}} $sData;
- }
- else {
- $oSelf->{Data} .= $sData;
- }
- }
- #//////////////////////////////////////////////////////////////////////////////
- # OLE::Storage_Lite::PPS::Dir Object
- #//////////////////////////////////////////////////////////////////////////////
- #------------------------------------------------------------------------------
- # new (OLE::Storage_Lite::PPS::Dir)
- #------------------------------------------------------------------------------
- package OLE::Storage_Lite::PPS::Dir;
- require Exporter;
- use strict;
- use vars qw($VERSION @ISA);
- @ISA = qw(OLE::Storage_Lite::PPS Exporter);
- $VERSION = '0.18';
- sub new ($$;$$$) {
- my($sClass, $sName, $raTime1st, $raTime2nd, $raChild) = @_;
- OLE::Storage_Lite::PPS::_new(
- $sClass,
- undef,
- $sName,
- 1,
- undef,
- undef,
- undef,
- $raTime1st,
- $raTime2nd,
- undef,
- undef,
- undef,
- $raChild);
- }
- #==============================================================================
- # OLE::Storage_Lite
- #==============================================================================
- package OLE::Storage_Lite;
- require Exporter;
- use strict;
- use IO::File;
- use Time::Local 'timegm';
- use vars qw($VERSION @ISA @EXPORT);
- @ISA = qw(Exporter);
- $VERSION = '0.18';
- sub _getPpsSearch($$$$$;$);
- sub _getPpsTree($$$;$);
- #------------------------------------------------------------------------------
- # Const for OLE::Storage_Lite
- #------------------------------------------------------------------------------
- #0. Constants
- sub PpsType_Root {5};
- sub PpsType_Dir {1};
- sub PpsType_File {2};
- sub DataSizeSmall{0x1000};
- sub LongIntSize {4};
- sub PpsSize {0x80};
- #------------------------------------------------------------------------------
- # new OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub new($$) {
- my($sClass, $sFile) = @_;
- my $oThis = {
- _FILE => $sFile,
- };
- bless $oThis;
- return $oThis;
- }
- #------------------------------------------------------------------------------
- # getPpsTree: OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub getPpsTree($;$)
- {
- my($oThis, $bData) = @_;
- #0.Init
- my $rhInfo = _initParse($oThis->{_FILE});
- return undef unless($rhInfo);
- #1. Get Data
- my ($oPps) = _getPpsTree(0, $rhInfo, $bData);
- close(IN);
- return $oPps;
- }
- #------------------------------------------------------------------------------
- # getSearch: OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub getPpsSearch($$;$$)
- {
- my($oThis, $raName, $bData, $iCase) = @_;
- #0.Init
- my $rhInfo = _initParse($oThis->{_FILE});
- return undef unless($rhInfo);
- #1. Get Data
- my @aList = _getPpsSearch(0, $rhInfo, $raName, $bData, $iCase);
- close(IN);
- return @aList;
- }
- #------------------------------------------------------------------------------
- # getNthPps: OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub getNthPps($$;$)
- {
- my($oThis, $iNo, $bData) = @_;
- #0.Init
- my $rhInfo = _initParse($oThis->{_FILE});
- return undef unless($rhInfo);
- #1. Get Data
- my $oPps = _getNthPps($iNo, $rhInfo, $bData);
- close IN;
- return $oPps;
- }
- #------------------------------------------------------------------------------
- # _initParse: OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub _initParse($) {
- my($sFile)=@_;
- my $oIo;
- #1. $sFile is Ref of scalar
- if(ref($sFile) eq 'SCALAR') {
- require IO::Scalar;
- $oIo = new IO::Scalar;
- $oIo->open($sFile);
- }
- #2. $sFile is a IO::Handle object
- elsif(UNIVERSAL::isa($sFile, 'IO::Handle')) {
- $oIo = $sFile;
- binmode($oIo);
- }
- #3. $sFile is a simple filename string
- elsif(!ref($sFile)) {
- $oIo = new IO::File;
- $oIo->open("<$sFile") || return undef;
- binmode($oIo);
- }
- #4 Assume that if $sFile is a ref then it is a valid filehandle
- else {
- $oIo = $sFile;
- # Not all filehandles support binmode() so try it in an eval.
- eval{ binmode $oIo };
- }
- return _getHeaderInfo($oIo);
- }
- #------------------------------------------------------------------------------
- # _getPpsTree: OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub _getPpsTree($$$;$) {
- my($iNo, $rhInfo, $bData, $raDone) = @_;
- if(defined($raDone)) {
- return () if(grep {$_ ==$iNo} @$raDone);
- }
- else {
- $raDone=[];
- }
- push @$raDone, $iNo;
- my $iRootBlock = $rhInfo->{_ROOT_START} ;
- #1. Get Information about itself
- my $oPps = _getNthPps($iNo, $rhInfo, $bData);
- #2. Child
- if($oPps->{DirPps} != 0xFFFFFFFF) {
- my @aChildL = _getPpsTree($oPps->{DirPps}, $rhInfo, $bData, $raDone);
- $oPps->{Child} = \@aChildL;
- }
- else {
- $oPps->{Child} = undef;
- }
- #3. Previous,Next PPSs
- my @aList = ();
- push @aList, _getPpsTree($oPps->{PrevPps}, $rhInfo, $bData, $raDone)
- if($oPps->{PrevPps} != 0xFFFFFFFF);
- push @aList, $oPps;
- push @aList, _getPpsTree($oPps->{NextPps}, $rhInfo, $bData, $raDone)
- if($oPps->{NextPps} != 0xFFFFFFFF);
- return @aList;
- }
- #------------------------------------------------------------------------------
- # _getPpsSearch: OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub _getPpsSearch($$$$$;$) {
- my($iNo, $rhInfo, $raName, $bData, $iCase, $raDone) = @_;
- my $iRootBlock = $rhInfo->{_ROOT_START} ;
- my @aRes;
- #1. Check it self
- if(defined($raDone)) {
- return () if(grep {$_==$iNo} @$raDone);
- }
- else {
- $raDone=[];
- }
- push @$raDone, $iNo;
- my $oPps = _getNthPps($iNo, $rhInfo, undef);
- # if(grep($_ eq $oPps->{Name}, @$raName)) {
- if(($iCase && (grep(/^\Q$oPps->{Name}\E$/i, @$raName))) ||
- (grep($_ eq $oPps->{Name}, @$raName))) {
- $oPps = _getNthPps($iNo, $rhInfo, $bData) if ($bData);
- @aRes = ($oPps);
- }
- else {
- @aRes = ();
- }
- #2. Check Child, Previous, Next PPSs
- push @aRes, _getPpsSearch($oPps->{DirPps}, $rhInfo, $raName, $bData, $iCase, $raDone)
- if($oPps->{DirPps} != 0xFFFFFFFF) ;
- push @aRes, _getPpsSearch($oPps->{PrevPps}, $rhInfo, $raName, $bData, $iCase, $raDone)
- if($oPps->{PrevPps} != 0xFFFFFFFF );
- push @aRes, _getPpsSearch($oPps->{NextPps}, $rhInfo, $raName, $bData, $iCase, $raDone)
- if($oPps->{NextPps} != 0xFFFFFFFF);
- return @aRes;
- }
- #===================================================================
- # Get Header Info (BASE Informain about that file)
- #===================================================================
- sub _getHeaderInfo($){
- my($FILE) = @_;
- my($iWk);
- my $rhInfo = {};
- $rhInfo->{_FILEH_} = $FILE;
- my $sWk;
- #0. Check ID
- $rhInfo->{_FILEH_}->seek(0, 0);
- $rhInfo->{_FILEH_}->read($sWk, 8);
- return undef unless($sWk eq "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1");
- #BIG BLOCK SIZE
- $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x1E, 2, "v");
- return undef unless(defined($iWk));
- $rhInfo->{_BIG_BLOCK_SIZE} = 2 ** $iWk;
- #SMALL BLOCK SIZE
- $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x20, 2, "v");
- return undef unless(defined($iWk));
- $rhInfo->{_SMALL_BLOCK_SIZE} = 2 ** $iWk;
- #BDB Count
- $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x2C, 4, "V");
- return undef unless(defined($iWk));
- $rhInfo->{_BDB_COUNT} = $iWk;
- #START BLOCK
- $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x30, 4, "V");
- return undef unless(defined($iWk));
- $rhInfo->{_ROOT_START} = $iWk;
- #MIN SIZE OF BB
- # $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x38, 4, "V");
- # return undef unless(defined($iWk));
- # $rhInfo->{_MIN_SIZE_BB} = $iWk;
- #SMALL BD START
- $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x3C, 4, "V");
- return undef unless(defined($iWk));
- $rhInfo->{_SBD_START} = $iWk;
- #SMALL BD COUNT
- $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x40, 4, "V");
- return undef unless(defined($iWk));
- $rhInfo->{_SBD_COUNT} = $iWk;
- #EXTRA BBD START
- $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x44, 4, "V");
- return undef unless(defined($iWk));
- $rhInfo->{_EXTRA_BBD_START} = $iWk;
- #EXTRA BD COUNT
- $iWk = _getInfoFromFile($rhInfo->{_FILEH_}, 0x48, 4, "V");
- return undef unless(defined($iWk));
- $rhInfo->{_EXTRA_BBD_COUNT} = $iWk;
- #GET BBD INFO
- $rhInfo->{_BBD_INFO}= _getBbdInfo($rhInfo);
- #GET ROOT PPS
- my $oRoot = _getNthPps(0, $rhInfo, undef);
- $rhInfo->{_SB_START} = $oRoot->{StartBlock};
- $rhInfo->{_SB_SIZE} = $oRoot->{Size};
- return $rhInfo;
- }
- #------------------------------------------------------------------------------
- # _getInfoFromFile
- #------------------------------------------------------------------------------
- sub _getInfoFromFile($$$$) {
- my($FILE, $iPos, $iLen, $sFmt) =@_;
- my($sWk);
- return undef unless($FILE);
- return undef if($FILE->seek($iPos, 0)==0);
- return undef if($FILE->read($sWk, $iLen)!=$iLen);
- return unpack($sFmt, $sWk);
- }
- #------------------------------------------------------------------------------
- # _getBbdInfo
- #------------------------------------------------------------------------------
- sub _getBbdInfo($) {
- my($rhInfo) =@_;
- my @aBdList = ();
- my $iBdbCnt = $rhInfo->{_BDB_COUNT};
- my $iGetCnt;
- my $sWk;
- my $i1stCnt = int(($rhInfo->{_BIG_BLOCK_SIZE} - 0x4C) / OLE::Storage_Lite::LongIntSize());
- my $iBdlCnt = int($rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize()) - 1;
- #1. 1st BDlist
- $rhInfo->{_FILEH_}->seek(0x4C, 0);
- $iGetCnt = ($iBdbCnt < $i1stCnt)? $iBdbCnt: $i1stCnt;
- $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::LongIntSize()*$iGetCnt);
- push @aBdList, unpack("V$iGetCnt", $sWk);
- $iBdbCnt -= $iGetCnt;
- #2. Extra BDList
- my $iBlock = $rhInfo->{_EXTRA_BBD_START};
- while(($iBdbCnt> 0) && _isNormalBlock($iBlock)){
- _setFilePos($iBlock, 0, $rhInfo);
- $iGetCnt= ($iBdbCnt < $iBdlCnt)? $iBdbCnt: $iBdlCnt;
- $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::LongIntSize()*$iGetCnt);
- push @aBdList, unpack("V$iGetCnt", $sWk);
- $iBdbCnt -= $iGetCnt;
- $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::LongIntSize());
- $iBlock = unpack("V", $sWk);
- }
- #3.Get BDs
- my @aWk;
- my %hBd;
- my $iBlkNo = 0;
- my $iBdL;
- my $i;
- my $iBdCnt = int($rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize());
- foreach $iBdL (@aBdList) {
- _setFilePos($iBdL, 0, $rhInfo);
- $rhInfo->{_FILEH_}->read($sWk, $rhInfo->{_BIG_BLOCK_SIZE});
- @aWk = unpack("V$iBdCnt", $sWk);
- for($i=0;$i<$iBdCnt;$i++, $iBlkNo++) {
- if($aWk[$i] != ($iBlkNo+1)){
- $hBd{$iBlkNo} = $aWk[$i];
- }
- }
- }
- return \%hBd;
- }
- #------------------------------------------------------------------------------
- # getNthPps (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _getNthPps($$$){
- my($iPos, $rhInfo, $bData) = @_;
- my($iPpsStart) = ($rhInfo->{_ROOT_START});
- my($iPpsBlock, $iPpsPos);
- my $sWk;
- my $iBlock;
- my $iBaseCnt = $rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::PpsSize();
- $iPpsBlock = int($iPos / $iBaseCnt);
- $iPpsPos = $iPos % $iBaseCnt;
- $iBlock = _getNthBlockNo($iPpsStart, $iPpsBlock, $rhInfo);
- return undef unless(defined($iBlock));
- _setFilePos($iBlock, OLE::Storage_Lite::PpsSize()*$iPpsPos, $rhInfo);
- $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::PpsSize());
- return undef unless($sWk);
- my $iNmSize = unpack("v", substr($sWk, 0x40, 2));
- $iNmSize = ($iNmSize > 2)? $iNmSize - 2 : $iNmSize;
- my $sNm= substr($sWk, 0, $iNmSize);
- my $iType = unpack("C", substr($sWk, 0x42, 2));
- my $lPpsPrev = unpack("V", substr($sWk, 0x44, OLE::Storage_Lite::LongIntSize()));
- my $lPpsNext = unpack("V", substr($sWk, 0x48, OLE::Storage_Lite::LongIntSize()));
- my $lDirPps = unpack("V", substr($sWk, 0x4C, OLE::Storage_Lite::LongIntSize()));
- my @raTime1st =
- (($iType == OLE::Storage_Lite::PpsType_Root()) or ($iType == OLE::Storage_Lite::PpsType_Dir()))?
- OLEDate2Local(substr($sWk, 0x64, 8)) : undef ,
- my @raTime2nd =
- (($iType == OLE::Storage_Lite::PpsType_Root()) or ($iType == OLE::Storage_Lite::PpsType_Dir()))?
- OLEDate2Local(substr($sWk, 0x6C, 8)) : undef,
- my($iStart, $iSize) = unpack("VV", substr($sWk, 0x74, 8));
- if($bData) {
- my $sData = _getData($iType, $iStart, $iSize, $rhInfo);
- return OLE::Storage_Lite::PPS->new(
- $iPos, $sNm, $iType, $lPpsPrev, $lPpsNext, $lDirPps,
- \@raTime1st, \@raTime2nd, $iStart, $iSize, $sData, undef);
- }
- else {
- return OLE::Storage_Lite::PPS->new(
- $iPos, $sNm, $iType, $lPpsPrev, $lPpsNext, $lDirPps,
- \@raTime1st, \@raTime2nd, $iStart, $iSize, undef, undef);
- }
- }
- #------------------------------------------------------------------------------
- # _setFilePos (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _setFilePos($$$){
- my($iBlock, $iPos, $rhInfo) = @_;
- $rhInfo->{_FILEH_}->seek(($iBlock+1)*$rhInfo->{_BIG_BLOCK_SIZE}+$iPos, 0);
- }
- #------------------------------------------------------------------------------
- # _getNthBlockNo (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _getNthBlockNo($$$){
- my($iStBlock, $iNth, $rhInfo) = @_;
- my $iSv;
- my $iNext = $iStBlock;
- for(my $i =0; $i<$iNth; $i++) {
- $iSv = $iNext;
- $iNext = _getNextBlockNo($iSv, $rhInfo);
- return undef unless _isNormalBlock($iNext);
- }
- return $iNext;
- }
- #------------------------------------------------------------------------------
- # _getData (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _getData($$$$)
- {
- my($iType, $iBlock, $iSize, $rhInfo) = @_;
- if ($iType == OLE::Storage_Lite::PpsType_File()) {
- if($iSize < OLE::Storage_Lite::DataSizeSmall()) {
- return _getSmallData($iBlock, $iSize, $rhInfo);
- }
- else {
- return _getBigData($iBlock, $iSize, $rhInfo);
- }
- }
- elsif($iType == OLE::Storage_Lite::PpsType_Root()) { #Root
- return _getBigData($iBlock, $iSize, $rhInfo);
- }
- elsif($iType == OLE::Storage_Lite::PpsType_Dir()) { # Directory
- return undef;
- }
- }
- #------------------------------------------------------------------------------
- # _getBigData (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _getBigData($$$)
- {
- my($iBlock, $iSize, $rhInfo) = @_;
- my($iRest, $sWk, $sRes);
- return '' unless(_isNormalBlock($iBlock));
- $iRest = $iSize;
- my($i, $iGetSize, $iNext);
- $sRes = '';
- my @aKeys= sort({$a<=>$b} keys(%{$rhInfo->{_BBD_INFO}}));
- while ($iRest > 0) {
- my @aRes = grep($_ >= $iBlock, @aKeys);
- my $iNKey = $aRes[0];
- $i = $iNKey - $iBlock;
- $iNext = $rhInfo->{_BBD_INFO}{$iNKey};
- _setFilePos($iBlock, 0, $rhInfo);
- my $iGetSize = ($rhInfo->{_BIG_BLOCK_SIZE} * ($i+1));
- $iGetSize = $iRest if($iRest < $iGetSize);
- $rhInfo->{_FILEH_}->read( $sWk, $iGetSize);
- $sRes .= $sWk;
- $iRest -= $iGetSize;
- $iBlock= $iNext;
- }
- return $sRes;
- }
- #------------------------------------------------------------------------------
- # _getNextBlockNo (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _getNextBlockNo($$){
- my($iBlockNo, $rhInfo) = @_;
- my $iRes = $rhInfo->{_BBD_INFO}->{$iBlockNo};
- return defined($iRes)? $iRes: $iBlockNo+1;
- }
- #------------------------------------------------------------------------------
- # _isNormalBlock (OLE::Storage_Lite)
- # 0xFFFFFFFC : BDList, 0xFFFFFFFD : BBD,
- # 0xFFFFFFFE: End of Chain 0xFFFFFFFF : unused
- #------------------------------------------------------------------------------
- sub _isNormalBlock($){
- my($iBlock) = @_;
- return ($iBlock < 0xFFFFFFFC)? 1: undef;
- }
- #------------------------------------------------------------------------------
- # _getSmallData (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _getSmallData($$$)
- {
- my($iSmBlock, $iSize, $rhInfo) = @_;
- my($sRes, $sWk);
- my $iRest = $iSize;
- $sRes = '';
- while ($iRest > 0) {
- _setFilePosSmall($iSmBlock, $rhInfo);
- $rhInfo->{_FILEH_}->read($sWk,
- ($iRest >= $rhInfo->{_SMALL_BLOCK_SIZE})?
- $rhInfo->{_SMALL_BLOCK_SIZE}: $iRest);
- $sRes .= $sWk;
- $iRest -= $rhInfo->{_SMALL_BLOCK_SIZE};
- $iSmBlock= _getNextSmallBlockNo($iSmBlock, $rhInfo);
- }
- return $sRes;
- }
- #------------------------------------------------------------------------------
- # _setFilePosSmall(OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _setFilePosSmall($$)
- {
- my($iSmBlock, $rhInfo) = @_;
- my $iSmStart = $rhInfo->{_SB_START};
- my $iBaseCnt = $rhInfo->{_BIG_BLOCK_SIZE} / $rhInfo->{_SMALL_BLOCK_SIZE};
- my $iNth = int($iSmBlock/$iBaseCnt);
- my $iPos = $iSmBlock % $iBaseCnt;
- my $iBlk = _getNthBlockNo($iSmStart, $iNth, $rhInfo);
- _setFilePos($iBlk, $iPos * $rhInfo->{_SMALL_BLOCK_SIZE}, $rhInfo);
- }
- #------------------------------------------------------------------------------
- # _getNextSmallBlockNo (OLE::Storage_Lite)
- #------------------------------------------------------------------------------
- sub _getNextSmallBlockNo($$)
- {
- my($iSmBlock, $rhInfo) = @_;
- my($sWk);
- my $iBaseCnt = $rhInfo->{_BIG_BLOCK_SIZE} / OLE::Storage_Lite::LongIntSize();
- my $iNth = int($iSmBlock/$iBaseCnt);
- my $iPos = $iSmBlock % $iBaseCnt;
- my $iBlk = _getNthBlockNo($rhInfo->{_SBD_START}, $iNth, $rhInfo);
- _setFilePos($iBlk, $iPos * OLE::Storage_Lite::LongIntSize(), $rhInfo);
- $rhInfo->{_FILEH_}->read($sWk, OLE::Storage_Lite::LongIntSize());
- return unpack("V", $sWk);
- }
- #------------------------------------------------------------------------------
- # Asc2Ucs: OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub Asc2Ucs($)
- {
- my($sAsc) = @_;
- return join("\x00", split //, $sAsc) . "\x00";
- }
- #------------------------------------------------------------------------------
- # Ucs2Asc: OLE::Storage_Lite
- #------------------------------------------------------------------------------
- sub Ucs2Asc($)
- {
- my($sUcs) = @_;
- return join('', map(pack('c', $_), unpack('v*', $sUcs)));
- }
- #------------------------------------------------------------------------------
- # OLEDate2Local()
- #
- # Convert from a Window FILETIME structure to a localtime array. FILETIME is
- # a 64-bit value representing the number of 100-nanosecond intervals since
- # January 1 1601.
- #
- # We first convert the FILETIME to seconds and then subtract the difference
- # between the 1601 epoch and the 1970 Unix epoch.
- #
- sub OLEDate2Local {
- my $oletime = shift;
- # Unpack the FILETIME into high and low longs.
- my ( $lo, $hi ) = unpack 'V2', $oletime;
- # Convert the longs to a double.
- my $nanoseconds = $hi * 2**32 + $lo;
- # Convert the 100 nanosecond units into seconds.
- my $time = $nanoseconds / 1e7;
- # Subtract the number of seconds between the 1601 and 1970 epochs.
- $time -= 11644473600;
- # Convert to a localtime (actually gmtime) structure.
- my @localtime = gmtime($time);
- return @localtime;
- }
- #------------------------------------------------------------------------------
- # LocalDate2OLE()
- #
- # Convert from a a localtime array to a Window FILETIME structure. FILETIME is
- # a 64-bit value representing the number of 100-nanosecond intervals since
- # January 1 1601.
- #
- # We first convert the localtime (actually gmtime) to seconds and then add the
- # difference between the 1601 epoch and the 1970 Unix epoch. We convert that to
- # 100 nanosecond units, divide it into high and low longs and return it as a
- # packed 64bit structure.
- #
- sub LocalDate2OLE {
- my $localtime = shift;
- return "\x00" x 8 unless $localtime;
- # Convert from localtime (actually gmtime) to seconds.
- my $time = timegm( @{$localtime} );
- # Add the number of seconds between the 1601 and 1970 epochs.
- $time += 11644473600;
- # The FILETIME seconds are in units of 100 nanoseconds.
- my $nanoseconds = $time * 1E7;
- use POSIX 'fmod';
- # Pack the total nanoseconds into 64 bits...
- my $hi = int( $nanoseconds / 2**32 );
- my $lo = fmod($nanoseconds, 2**32);
- my $oletime = pack "VV", $lo, $hi;
- return $oletime;
- }
- 1;
- __END__
- =head1 NAME
- OLE::Storage_Lite - Simple Class for OLE document interface.
- =head1 SYNOPSIS
- use OLE::Storage_Lite;
- # Initialize.
- # From a file
- my $oOl = OLE::Storage_Lite->new("some.xls");
- # From a filehandle object
- use IO::File;
- my $oIo = new IO::File;
- $oIo->open("<iofile.xls");
- binmode($oIo);
- my $oOl = OLE::Storage_Lite->new($oFile);
- # Read data
- my $oPps = $oOl->getPpsTree(1);
- # Save Data
- # To a File
- $oPps->save("kaba.xls"); #kaba.xls
- $oPps->save('-'); #STDOUT
- # To a filehandle object
- my $oIo = new IO::File;
- $oIo->open(">iofile.xls");
- bimode($oIo);
- $oPps->save($oIo);
- =head1 DESCRIPTION
- OLE::Storage_Lite allows you to read and write an OLE structured file.
- OLE::Storage_Lite::PPS is a class representing PPS. OLE::Storage_Lite::PPS::Root, OLE::Storage_Lite::PPS::File and OLE::Storage_Lite::PPS::Dir
- are subclasses of OLE::Storage_Lite::PPS.
- =head2 new()
- Constructor.
- $oOle = OLE::Storage_Lite->new($sFile);
- Creates a OLE::Storage_Lite object for C<$sFile>. C<$sFile> must be a correct file name.
- The C<new()> constructor also accepts a valid filehandle. Remember to C<binmode()> the filehandle first.
- =head2 getPpsTree()
- $oPpsRoot = $oOle->getPpsTree([$bData]);
- Returns PPS as an OLE::Storage_Lite::PPS::Root object.
- Other PPS objects will be included as its children.
- If C<$bData> is true, the objects will have data in the file.
- =head2 getPpsSearch()
- $oPpsRoot = $oOle->getPpsTree($raName [, $bData][, $iCase] );
- Returns PPSs as OLE::Storage_Lite::PPS objects that has the name specified in C<$raName> array.
- If C<$bData> is true, the objects will have data in the file.
- If C<$iCase> is true, search is case insensitive.
- =head2 getNthPps()
- $oPpsRoot = $oOle->getNthPps($iNth [, $bData]);
- Returns PPS as C<OLE::Storage_Lite::PPS> object specified number C<$iNth>.
- If C<$bData> is true, the objects will have data in the file.
- =head2 Asc2Ucs()
- $sUcs2 = OLE::Storage_Lite::Asc2Ucs($sAsc>);
- Utility function. Just adds 0x00 after every characters in C<$sAsc>.
- =head2 Ucs2Asc()
- $sAsc = OLE::Storage_Lite::Ucs2Asc($sUcs2);
- Utility function. Just deletes 0x00 after words in C<$sUcs>.
- =head1 OLE::Storage_Lite::PPS
- OLE::Storage_Lite::PPS has these properties:
- =over 4
- =item No
- Order number in saving.
- =item Name
- Its name in UCS2 (a.k.a Unicode).
- =item Type
- Its type (1:Dir, 2:File (Data), 5: Root)
- =item PrevPps
- Previous pps (as No)
- =item NextPps
- Next pps (as No)
- =item DirPps
- Dir pps (as No).
- =item Time1st
- Timestamp 1st in array ref as similar fomat of localtime.
- =item Time2nd
- Timestamp 2nd in array ref as similar fomat of localtime.
- =item StartBlock
- Start block number
- =item Size
- Size of the pps
- =item Data
- Its data
- =item Child
- Its child PPSs in array ref
- =back
- =head1 OLE::Storage_Lite::PPS::Root
- OLE::Storage_Lite::PPS::Root has 2 methods.
- =head2 new()
- $oRoot = OLE::Storage_Lite::PPS::Root->new(
- $raTime1st,
- $raTime2nd,
- $raChild);
- Constructor.
- C<$raTime1st>, C<$raTime2nd> are array refs with ($iSec, $iMin, $iHour, $iDay, $iMon, $iYear).
- $iSec means seconds, $iMin means minutes. $iHour means hours.
- $iDay means day. $iMon is month -1. $iYear is year - 1900.
- C<$raChild> is a array ref of children PPSs.
- =head2 save()
- $oRoot = $oRoot>->save(
- $sFile,
- $bNoAs);
- Saves information into C<$sFile>. If C<$sFile> is '-', this will use STDOUT.
- The C<new()> constructor also accepts a valid filehandle. Remember to C<binmode()> the filehandle first.
- If C<$bNoAs> is defined, this function will use the No of PPSs for saving order.
- If C<$bNoAs> is undefined, this will calculate PPS saving order.
- =head1 OLE::Storage_Lite::PPS::Dir
- OLE::Storage_Lite::PPS::Dir has 1 method.
- =head2 new()
- $oRoot = OLE::Storage_Lite::PPS::Dir->new(
- $sName,
- [, $raTime1st]
- [, $raTime2nd]
- [, $raChild>]);
- Constructor.
- C<$sName> is a name of the PPS.
- C<$raTime1st>, C<$raTime2nd> is a array ref as
- ($iSec, $iMin, $iHour, $iDay, $iMon, $iYear).
- $iSec means seconds, $iMin means minutes. $iHour means hours.
- $iDay means day. $iMon is month -1. $iYear is year - 1900.
- C<$raChild> is a array ref of children PPSs.
- =head1 OLE::Storage_Lite::PPS::File
- OLE::Storage_Lite::PPS::File has 3 method.
- =head2 new
- $oRoot = OLE::Storage_Lite::PPS::File->new($sName, $sData);
- C<$sName> is name of the PPS.
- C<$sData> is data of the PPS.
- =head2 newFile()
- $oRoot = OLE::Storage_Lite::PPS::File->newFile($sName, $sFile);
- This function makes to use file handle for geting and storing data.
- C<$sName> is name of the PPS.
- If C<$sFile> is scalar, it assumes that is a filename.
- If C<$sFile> is an IO::Handle object, it uses that specified handle.
- If C<$sFile> is undef or '', it uses temporary file.
- CAUTION: Take care C<$sFile> will be updated by C<append> method.
- So if you want to use IO::Handle and append a data to it,
- you should open the handle with "r+".
- =head2 append()
- $oRoot = $oPps->append($sData);
- appends specified data to that PPS.
- C<$sData> is appending data for that PPS.
- =head1 CAUTION
- A saved file with VBA (a.k.a Macros) by this module will not work correctly.
- However modules can get the same information from the file,
- the file occurs a error in application(Word, Excel ...).
- =head1 DEPRECATED FEATURES
- Older version of C<OLE::Storage_Lite> autovivified a scalar ref in the C<new()> constructors into a scalar filehandle. This functionality is still there for backwards compatibility but it is highly recommended that you do not use it. Instead create a filehandle (scalar or otherwise) and pass that in.
- =head1 COPYRIGHT
- The OLE::Storage_Lite module is Copyright (c) 2000,2001 Kawai Takanori. Japan.
- All rights reserved.
- You may distribute under the terms of either the GNU General Public
- License or the Artistic License, as specified in the Perl README file.
- =head1 ACKNOWLEDGEMENTS
- First of all, I would like to acknowledge to Martin Schwartz and his module OLE::Storage.
- =head1 AUTHOR
- Kawai Takanori kwitknr@cpan.org
- This module is currently maintained by John McNamara jmcnamara@cpan.org
- =head1 SEE ALSO
- OLE::Storage
- Documentation for the OLE Compound document has been released by Microsoft under the I<Open Specification Promise>. See http://www.microsoft.com/interop/docs/supportingtechnologies.mspx
- The Digital Imaging Group have also detailed the OLE format in the JPEG2000 specification: see Appendix A of http://www.i3a.org/pdf/wg1n1017.pdf
- =cut
|