Storage_Lite.pm 53 KB

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