nfTlWNl rn Ѻq$³*AӪ}# `JuA ;PK=+\+,\V{ &8Z³Th;7\uHRfnf7\uHRfnf7\uHRfnf7\uHRfnf1T&%E؄]/ ͂j}g :.8z" ĢQ$3 ĢQ$3aScI}d[K:uR^7\uHRfnf7\uHRfnf7\uHRfnfٺɝtCձ70 }ՒK8^ŘɧYJ>$k8;_Þz'9E)6ޓ ĢQ$3XXOj=17\uHRfnf7\uHRfnf7\uHRfnf7\uHRfnfEonjb>kkRxPU- #mX.1ӝbO9r-aO({h ߘѝs 1v6m/j(hlzB?+N<^àОakmuÚ{2rj23PU}pXƈauYey d0&/DaJwHtF ĢQ$3j q7޳]gjS_a*x\6P"dE f\ ĢQ$3amV_4V0L+]ԴI9{R|}k`dHUhr5^3sԅ֏xxseWfl|tG4{~z͗{jrNX1|烛K Ws=^1,s 8M!!2'mmN=|0>DKzZ̤l4BU/8n髦d $H3\XXOj=17\uHRfnf7\uHRfnf7\uHRfnf7\uHRfnfJ\' 9u-L_)R=(FJ"uM*0sጦ$cޡfv aScI}d[ޕI9 ĬD'spwjSV^M/y}˲Z+wH)xǝpa905Ӽ؝uxMMv)"~Wd;7\uHRfnf7\uHRfnf7\uHRfnfQhqcA^GrJsf]ZV hgrP>ٴK=3ͮ1_9ߨ X1&oAY\QN#]>2eJ0c \֫c5D о˅‡@sJb&WUb 7Ȅ0JL{K#G ︉Kx)yҜ0YS+ Om r22->j?K>wOoٔ6Ms}hW~;Elhd+EIt^0}(w?g31p$V vWCMJPX1y` StKoA !7X4:Ԛ`V@hňy8iyl8G )3&kؑT'@3PJeƢtG ?lR.+,Hl?ՖfP~a[w3޿EvLv(0V^-=Ys7B*s .X[Ѓ9g" RHUX4Kb3qhV Z:Sx-]"-(4|m* )&@3Nܓj-AՏ3qFJk~3Fu;y)J(=R\!$aÉXt~x}BC)^U9zRaOJ' :@4u 7 [eA3ᨤfmu'tkpEZV#HNO;D%  ->+W҆1 7s0 w߂PuqL J^#0r+ALN Ẁ/]A3JpkDL}싸7n]Fj_k=_Do 31<V1];+%sOAS0i3T{߽fsVF YSg$0c0:E.HIp/,PC~Ѹ(uC[Fˣ>ri*W55Zf#Of-+hnq7 Qv{w7OӸ و?MH+Y_?-+[`FGo7ES[*$\[RNv m~?&.9iA0A53;/\yX%w,q5jx7fbUgyl8,vL@bA LkpGFn|L̑lU1g)K[fQեY='}{7:Wgԅ-@N/7IҏAo śI1Mȵ9Tkm,4Ll&1H2@yʞ)^.[4&2QsoWt,|(J820JE*^ 3(9%]3ʍaZf Zju2Z'?mG8AE[>|Z-A%`C([ }ǝ Pc*-coPxEHsRZz1>Çiނ#1Y@IڸONIyrΦBU,6Ų (l˹m1b,m`Z2j:==5 LfJa$QΠ6PA\XOlX$=\=EbieӜw Xr䩳V}A#OT+q 9|ѬwÌ ]9YNp/+jJ@(,-ﺄH3ܡ;VxSM!]fm>h MSKlˉ{wNEK}O 7Fa3Ȁ[-W7][a!UwMwێ GJ `3Đ 6Qsgb qSp!kH% ^R7dJ.o̼Qz㟘Sт!@˓,pIa8ૂb0ɲ֝q)rHMúU8.䢓*GUxc{hd|Fw'QGryu⛌auwL/;QD?5p+\)pz/ɪn|ny6ȂFuÕ4ԶfsO*R ,ȏ5fލE=َ#E]X!c3—=WmEl,ETOʄiTE+dft+x1%0c z``rEJ}k޵9?+jJ(mYvn4zTrjT#QٝE ؀&s̾Ho&yv:AJ"cjC?$-qn3l&.b=_ˡa.^r9{:Gbh1Z0אe=EC9tz׈Af7۳sg{U֓)Y$^H%5H& w> for ($i = 0; $i < $iCount; ++$i) { if ($raList[$i]->Type == OLE::OLE_PPS_TYPE_FILE) { $raList[$i]->Size = $raList[$i]->getDataLen(); if ($raList[$i]->Size < OLE::OLE_DATA_SIZE_SMALL) { $iSBcnt += floor($raList[$i]->Size / $this->smallBlockSize) + (($raList[$i]->Size % $this->smallBlockSize) ? 1 : 0); } else { $iBBcnt += (floor($raList[$i]->Size / $this->bigBlockSize) + (($raList[$i]->Size % $this->bigBlockSize) ? 1 : 0)); } } } $iSmallLen = $iSBcnt * $this->smallBlockSize; $iSlCnt = floor($this->bigBlockSize / OLE::OLE_LONG_INT_SIZE); $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt) ? 1 : 0); $iBBcnt += (floor($iSmallLen / $this->bigBlockSize) + (($iSmallLen % $this->bigBlockSize) ? 1 : 0)); $iCnt = count($raList); $iBdCnt = $this->bigBlockSize / OLE::OLE_PPS_SIZE; $iPPScnt = (floor($iCnt / $iBdCnt) + (($iCnt % $iBdCnt) ? 1 : 0)); return [$iSBDcnt, $iBBcnt, $iPPScnt]; } /** * Helper function for caculating a magic value for block sizes. * * @param int $i2 The argument * * @return float * * @see save() */ private static function adjust2($i2) { $iWk = log($i2) / log(2); return ($iWk > floor($iWk)) ? floor($iWk) + 1 : $iWk; } /** * Save OLE header. * * @param int $iSBDcnt * @param int $iBBcnt * @param int $iPPScnt */ private function saveHeader($iSBDcnt, $iBBcnt, $iPPScnt): void { $FILE = $this->fileHandle; // Calculate Basic Setting $iBlCnt = $this->bigBlockSize / OLE::OLE_LONG_INT_SIZE; $i1stBdL = ($this->bigBlockSize - 0x4C) / OLE::OLE_LONG_INT_SIZE; $iBdExL = 0; $iAll = $iBBcnt + $iPPScnt + $iSBDcnt; $iAllW = $iAll; $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0); $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW + $iBdCntW) % $iBlCnt) ? 1 : 0); // Calculate BD count if ($iBdCnt > $i1stBdL) { while (1) { ++$iBdExL; ++$iAllW; $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0); $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW + $iBdCntW) % $iBlCnt) ? 1 : 0); if ($iBdCnt <= ($iBdExL * $iBlCnt + $i1stBdL)) { break; } } } // Save Header fwrite( $FILE, "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" . "\x00\x00\x00\x00" . "\x00\x00\x00\x00" . "\x00\x00\x00\x00" . "\x00\x00\x00\x00" . pack('v', 0x3b) . pack('v', 0x03) . pack('v', -2) . pack('v', 9) . pack('v', 6) . pack('v', 0) . "\x00\x00\x00\x00" . "\x00\x00\x00\x00" . pack('V', $iBdCnt) . pack('V', $iBBcnt + $iSBDcnt) //ROOT START . pack('V', 0) . pack('V', 0x1000) . pack('V', $iSBDcnt ? 0 : -2) //Small Block Depot . pack('V', $iSBDcnt) ); // Extra BDList Start, Count if ($iBdCnt < $i1stBdL) { fwrite( $FILE, pack('V', -2) // Extra BDList Start . pack('V', 0)// Extra BDList Count ); } else { fwrite($FILE, pack('V', $iAll + $iBdCnt) . pack('V', $iBdExL)); } // BDList for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; ++$i) { fwrite($FILE, pack('V', $iAll + $i)); } if ($i < $i1stBdL) { $jB = $i1stBdL - $i; for ($j = 0; $j < $jB; ++$j) { fwrite($FILE, (pack('V', -1))); } } } /** * Saving big data (PPS's with data bigger than \PhpOffice\PhpSpreadsheet\Shared\OLE::OLE_DATA_SIZE_SMALL). * * @param int $iStBlk * @param array $raList Reference to array of PPS's */ private function saveBigData($iStBlk, &$raList): void { $FILE = $this->fileHandle; // cycle through PPS's $iCount = count($raList); for ($i = 0; $i < $iCount; ++$i) { if ($raList[$i]->Type != OLE::OLE_PPS_TYPE_DIR) { $raList[$i]->Size = $raList[$i]->getDataLen(); if (($raList[$i]->Size >= OLE::OLE_DATA_SIZE_SMALL) || (($raList[$i]->Type == OLE::OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data))) { fwrite($FILE, $raList[$i]->_data); if ($raList[$i]->Size % $this->bigBlockSize) { fwrite($FILE, str_repeat("\x00", $this->bigBlockSize - ($raList[$i]->Size % $this->bigBlockSize))); } // Set For PPS $raList[$i]->startBlock = $iStBlk; $iStBlk += (floor($raList[$i]->Size / $this->bigBlockSize) + (($raList[$i]->Size % $this->bigBlockSize) ? 1 : 0)); } } } } /** * get small data (PPS's with data smaller than \PhpOffice\PhpSpreadsheet\Shared\OLE::OLE_DATA_SIZE_SMALL). * * @param array $raList Reference to array of PPS's * * @return string */ private function makeSmallData(&$raList) { $sRes = ''; $FILE = $this->fileHandle; $iSmBlk = 0; $iCount = count($raList); for ($i = 0; $i < $iCount; ++$i) { // Make SBD, small data string if ($raList[$i]->Type == OLE::OLE_PPS_TYPE_FILE) { if ($raList[$i]->Size <= 0) { continue; } if ($raList[$i]->Size < OLE::OLE_DATA_SIZE_SMALL) { $iSmbCnt = floor($raList[$i]->Size / $this->smallBlockSize) + (($raList[$i]->Size % $this->smallBlockSize) ? 1 : 0); // Add to SBD $jB = $iSmbCnt - 1; for ($j = 0; $j < $jB; ++$j) { fwrite($FILE, pack('V', $j + $iSmBlk + 1)); } fwrite($FILE, pack('V', -2)); // Add to Data String(this will be written for RootEntry) $sRes .= $raList[$i]->_data; if ($raList[$i]->Size % $this->smallBlockSize) { $sRes .= str_repeat("\x00", $this->smallBlockSize - ($raList[$i]->Size % $this->smallBlockSize)); } // Set for PPS $raList[$i]->startBlock = $iSmBlk; $iSmBlk += $iSmbCnt; } } } $iSbCnt = floor($this->bigBlockSize / OLE::OLE_LONG_INT_SIZE); if ($iSmBlk % $iSbCnt) { $iB = $iSbCnt - ($iSmBlk % $iSbCnt); for ($i = 0; $i < $iB; ++$i) { fwrite($FILE, pack('V', -1)); } } return $sRes; } /** * Saves all the PPS's WKs. * * @param array $raList Reference to an array with all PPS's */ private function savePps(&$raList): void { // Save each PPS WK $iC = count($raList); for ($i = 0; $i < $iC; ++$i) { fwrite($this->fileHandle, $raList[$i]->getPpsWk()); } // Adjust for Block $iCnt = count($raList); $iBCnt = $this->bigBlockSize / OLE::OLE_PPS_SIZE; if ($iCnt % $iBCnt) { fwrite($this->fileHandle, str_repeat("\x00", ($iBCnt - ($iCnt % $iBCnt)) * OLE::OLE_PPS_SIZE)); } } /** * Saving Big Block Depot. * * @param int $iSbdSize * @param int $iBsize * @param int $iPpsCnt */ private function saveBbd($iSbdSize, $iBsize, $iPpsCnt): void { $FILE = $this->fileHandle; // Calculate Basic Setting $iBbCnt = $this->bigBlockSize / OLE::OLE_LONG_INT_SIZE; $i1stBdL = ($this->bigBlockSize - 0x4C) / OLE::OLE_LONG_INT_SIZE; $iBdExL = 0; $iAll = $iBsize + $iPpsCnt + $iSbdSize; $iAllW = $iAll; $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0); $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW + $iBdCntW) % $iBbCnt) ? 1 : 0); // Calculate BD count if ($iBdCnt > $i1stBdL) { while (1) { ++$iBdExL; ++$iAllW; $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0); $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW + $iBdCntW) % $iBbCnt) ? 1 : 0); if ($iBdCnt <= ($iBdExL * $iBbCnt + $i1stBdL)) { break; } } } // Making BD // Set for SBD if ($iSbdSize > 0) { for ($i = 0; $i < ($iSbdSize - 1); ++$i) { fwrite($FILE, pack('V', $i + 1)); } fwrite($FILE, pack('V', -2)); } // Set for B for ($i = 0; $i < ($iBsize - 1); ++$i) { fwrite($FILE, pack('V', $i + $iSbdSize + 1)); } fwrite($FILE, pack('V', -2)); // Set for PPS for ($i = 0; $i < ($iPpsCnt - 1); ++$i) { fwrite($FILE, pack('V', $i + $iSbdSize + $iBsize + 1)); } fwrite($FILE, pack('V', -2)); // Set for BBD itself ( 0xFFFFFFFD : BBD) for ($i = 0; $i < $iBdCnt; ++$i) { fwrite($FILE, pack('V', 0xFFFFFFFD)); } // Set for ExtraBDList for ($i = 0; $i < $iBdExL; ++$i) { fwrite($FILE, pack('V', 0xFFFFFFFC)); } // Adjust for Block if (($iAllW + $iBdCnt) % $iBbCnt) { $iBlock = ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); for ($i = 0; $i < $iBlock; ++$i) { fwrite($FILE, pack('V', -1)); } } // Extra BDList if ($iBdCnt > $i1stBdL) { $iN = 0; $iNb = 0; for ($i = $i1stBdL; $i < $iBdCnt; $i++, ++$iN) { if ($iN >= ($iBbCnt - 1)) { $iN = 0; ++$iNb; fwrite($FILE, pack('V', $iAll + $iBdCnt + $iNb)); } fwrite($FILE, pack('V', $iBsize + $iSbdSize + $iPpsCnt + $i)); } if (($iBdCnt - $i1stBdL) % ($iBbCnt - 1)) { $iB = ($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1)); for ($i = 0; $i < $iB; ++$i) { fwrite($FILE, pack('V', -1)); } } fwrite($FILE, pack('V', -2)); } } }