source: sourcecode/application/libraries/PHPExcel/Shared/OLE/PPS/Root.php @ 1

Last change on this file since 1 was 1, checked in by dungnv, 11 years ago
File size: 13.9 KB
Line 
1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4: */
3// +----------------------------------------------------------------------+
4// | PHP Version 4                                                        |
5// +----------------------------------------------------------------------+
6// | Copyright (c) 1997-2002 The PHP Group                                |
7// +----------------------------------------------------------------------+
8// | This source file is subject to version 2.02 of the PHP license,      |
9// | that is bundled with this package in the file LICENSE, and is        |
10// | available at through the world-wide-web at                           |
11// | http://www.php.net/license/2_02.txt.                                 |
12// | If you did not receive a copy of the PHP license and are unable to   |
13// | obtain it through the world-wide-web, please send a note to          |
14// | license@php.net so we can mail you a copy immediately.               |
15// +----------------------------------------------------------------------+
16// | Author: Xavier Noguer <xnoguer@php.net>                              |
17// | Based on OLE::Storage_Lite by Kawai, Takanori                        |
18// +----------------------------------------------------------------------+
19//
20// $Id: Root.php,v 1.9 2005/04/23 21:53:49 dufuz Exp $
21
22
23/**
24* Class for creating Root PPS's for OLE containers
25*
26* @author   Xavier Noguer <xnoguer@php.net>
27* @category PHPExcel
28* @package  PHPExcel_Shared_OLE
29*/
30class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS
31        {
32
33        /**
34         * Directory for temporary files
35         * @var string
36         */
37        protected $_tmp_dir             = NULL;
38
39        /**
40         * @param integer $time_1st A timestamp
41         * @param integer $time_2nd A timestamp
42         */
43        public function __construct($time_1st, $time_2nd, $raChild)
44        {
45                $this->_tempDir = PHPExcel_Shared_File::sys_get_temp_dir();
46
47                parent::__construct(
48                   null,
49                   PHPExcel_Shared_OLE::Asc2Ucs('Root Entry'),
50                   PHPExcel_Shared_OLE::OLE_PPS_TYPE_ROOT,
51                   null,
52                   null,
53                   null,
54                   $time_1st,
55                   $time_2nd,
56                   null,
57                   $raChild);
58        }
59
60        /**
61        * Method for saving the whole OLE container (including files).
62        * In fact, if called with an empty argument (or '-'), it saves to a
63        * temporary file and then outputs it's contents to stdout.
64        * If a resource pointer to a stream created by fopen() is passed
65        * it will be used, but you have to close such stream by yourself.
66        *
67        * @param string|resource $filename The name of the file or stream where to save the OLE container.
68        * @access public
69        * @return mixed true on success
70        */
71        public function save($filename)
72        {
73                // Initial Setting for saving
74                $this->_BIG_BLOCK_SIZE  = pow(2,
75                                          ((isset($this->_BIG_BLOCK_SIZE))? self::_adjust2($this->_BIG_BLOCK_SIZE)  : 9));
76                $this->_SMALL_BLOCK_SIZE= pow(2,
77                                          ((isset($this->_SMALL_BLOCK_SIZE))?  self::_adjust2($this->_SMALL_BLOCK_SIZE): 6));
78
79                if (is_resource($filename)) {
80                    $this->_FILEH_ = $filename;
81                } else if ($filename == '-' || $filename == '') {
82                        if ($this->_tmp_dir === NULL)
83                                $this->_tmp_dir = PHPExcel_Shared_File::sys_get_temp_dir();
84                        $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_Root");
85                        $this->_FILEH_ = fopen($this->_tmp_filename,"w+b");
86                        if ($this->_FILEH_ == false) {
87                                throw new PHPExcel_Writer_Exception("Can't create temporary file.");
88                        }
89                } else {
90                        $this->_FILEH_ = fopen($filename, "wb");
91                }
92                if ($this->_FILEH_ == false) {
93                        throw new PHPExcel_Writer_Exception("Can't open $filename. It may be in use or protected.");
94                }
95                // Make an array of PPS's (for Save)
96                $aList = array();
97                PHPExcel_Shared_OLE_PPS::_savePpsSetPnt($aList, array($this));
98                // calculate values for header
99                list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
100                // Save Header
101                $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
102
103                // Make Small Data string (write SBD)
104                $this->_data = $this->_makeSmallData($aList);
105
106                // Write BB
107                $this->_saveBigData($iSBDcnt, $aList);
108                // Write PPS
109                $this->_savePps($aList);
110                // Write Big Block Depot and BDList and Adding Header informations
111                $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
112
113                if (!is_resource($filename)) {
114                        fclose($this->_FILEH_);
115                }
116
117                return true;
118        }
119
120        /**
121        * Calculate some numbers
122        *
123        * @access public
124        * @param array $raList Reference to an array of PPS's
125        * @return array The array of numbers
126        */
127        public function _calcSize(&$raList)
128        {
129                // Calculate Basic Setting
130                list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0);
131                $iSmallLen = 0;
132                $iSBcnt = 0;
133                $iCount = count($raList);
134                for ($i = 0; $i < $iCount; ++$i) {
135                        if ($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_FILE) {
136                                $raList[$i]->Size = $raList[$i]->_DataLen();
137                                if ($raList[$i]->Size < PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) {
138                                        $iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
139                                                                  + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
140                                } else {
141                                        $iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
142                                                (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
143                                }
144                        }
145                }
146                $iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE;
147                $iSlCnt = floor($this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE);
148                $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1:0);
149                $iBBcnt +=  (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) +
150                                          (( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0));
151                $iCnt = count($raList);
152                $iBdCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_PPS_SIZE;
153                $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0));
154
155                return array($iSBDcnt, $iBBcnt, $iPPScnt);
156        }
157
158        /**
159        * Helper function for caculating a magic value for block sizes
160        *
161        * @access public
162        * @param integer $i2 The argument
163        * @see save()
164        * @return integer
165        */
166        private static function _adjust2($i2)
167        {
168                $iWk = log($i2)/log(2);
169                return ($iWk > floor($iWk))? floor($iWk)+1:$iWk;
170        }
171
172        /**
173        * Save OLE header
174        *
175        * @access public
176        * @param integer $iSBDcnt
177        * @param integer $iBBcnt
178        * @param integer $iPPScnt
179        */
180        public function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt)
181        {
182                $FILE = $this->_FILEH_;
183
184                // Calculate Basic Setting
185                $iBlCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
186                $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
187
188                $iBdExL = 0;
189                $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
190                $iAllW = $iAll;
191                $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
192                $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
193
194                // Calculate BD count
195                if ($iBdCnt > $i1stBdL) {
196                        while (1) {
197                                ++$iBdExL;
198                                ++$iAllW;
199                                $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
200                                $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
201                                if ($iBdCnt <= ($iBdExL*$iBlCnt+ $i1stBdL)) {
202                                        break;
203                                }
204                        }
205                }
206
207                // Save Header
208                fwrite($FILE,
209                                "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
210                                . "\x00\x00\x00\x00"
211                                . "\x00\x00\x00\x00"
212                                . "\x00\x00\x00\x00"
213                                . "\x00\x00\x00\x00"
214                                . pack("v", 0x3b)
215                                . pack("v", 0x03)
216                                . pack("v", -2)
217                                . pack("v", 9)
218                                . pack("v", 6)
219                                . pack("v", 0)
220                                . "\x00\x00\x00\x00"
221                                . "\x00\x00\x00\x00"
222                                . pack("V", $iBdCnt)
223                                . pack("V", $iBBcnt+$iSBDcnt) //ROOT START
224                                . pack("V", 0)
225                                . pack("V", 0x1000)
226                                . pack("V", $iSBDcnt ? 0 : -2)                  //Small Block Depot
227                                . pack("V", $iSBDcnt)
228                  );
229                // Extra BDList Start, Count
230                if ($iBdCnt < $i1stBdL) {
231                        fwrite($FILE,
232                                        pack("V", -2)      // Extra BDList Start
233                                        . pack("V", 0)        // Extra BDList Count
234                                  );
235                } else {
236                        fwrite($FILE, pack("V", $iAll+$iBdCnt) . pack("V", $iBdExL));
237                }
238
239                // BDList
240                for ($i = 0; $i < $i1stBdL && $i < $iBdCnt; ++$i) {
241                        fwrite($FILE, pack("V", $iAll+$i));
242                }
243                if ($i < $i1stBdL) {
244                        $jB = $i1stBdL - $i;
245                        for ($j = 0; $j < $jB; ++$j) {
246                                fwrite($FILE, (pack("V", -1)));
247                        }
248                }
249        }
250
251        /**
252        * Saving big data (PPS's with data bigger than PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL)
253        *
254        * @access public
255        * @param integer $iStBlk
256        * @param array &$raList Reference to array of PPS's
257        */
258        public function _saveBigData($iStBlk, &$raList)
259        {
260                $FILE = $this->_FILEH_;
261
262                // cycle through PPS's
263                $iCount = count($raList);
264                for ($i = 0; $i < $iCount; ++$i) {
265                        if ($raList[$i]->Type != PHPExcel_Shared_OLE::OLE_PPS_TYPE_DIR) {
266                                $raList[$i]->Size = $raList[$i]->_DataLen();
267                                if (($raList[$i]->Size >= PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) ||
268                                        (($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_ROOT) && isset($raList[$i]->_data)))
269                                {
270                                        // Write Data
271                                        //if (isset($raList[$i]->_PPS_FILE)) {
272                                        //      $iLen = 0;
273                                        //      fseek($raList[$i]->_PPS_FILE, 0); // To The Top
274                                        //      while($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
275                                        //              $iLen += strlen($sBuff);
276                                        //              fwrite($FILE, $sBuff);
277                                        //      }
278                                        //} else {
279                                                fwrite($FILE, $raList[$i]->_data);
280                                        //}
281
282                                        if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) {
283                                                fwrite($FILE, str_repeat("\x00", $this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)));
284                                        }
285                                        // Set For PPS
286                                        $raList[$i]->_StartBlock = $iStBlk;
287                                        $iStBlk +=
288                                                        (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
289                                                                (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
290                                }
291                                // Close file for each PPS, and unlink it
292                                //if (isset($raList[$i]->_PPS_FILE)) {
293                                //      fclose($raList[$i]->_PPS_FILE);
294                                //      $raList[$i]->_PPS_FILE = null;
295                                //      unlink($raList[$i]->_tmp_filename);
296                                //}
297                        }
298                }
299        }
300
301        /**
302        * get small data (PPS's with data smaller than PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL)
303        *
304        * @access public
305        * @param array &$raList Reference to array of PPS's
306        */
307        public function _makeSmallData(&$raList)
308        {
309                $sRes = '';
310                $FILE = $this->_FILEH_;
311                $iSmBlk = 0;
312
313                $iCount = count($raList);
314                for ($i = 0; $i < $iCount; ++$i) {
315                        // Make SBD, small data string
316                        if ($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_FILE) {
317                                if ($raList[$i]->Size <= 0) {
318                                        continue;
319                                }
320                                if ($raList[$i]->Size < PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) {
321                                        $iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
322                                                                  + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
323                                        // Add to SBD
324                                        $jB = $iSmbCnt - 1;
325                                        for ($j = 0; $j < $jB; ++$j) {
326                                                fwrite($FILE, pack("V", $j+$iSmBlk+1));
327                                        }
328                                        fwrite($FILE, pack("V", -2));
329
330                                        //// Add to Data String(this will be written for RootEntry)
331                                        //if ($raList[$i]->_PPS_FILE) {
332                                        //      fseek($raList[$i]->_PPS_FILE, 0); // To The Top
333                                        //      while ($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
334                                        //              $sRes .= $sBuff;
335                                        //      }
336                                        //} else {
337                                                $sRes .= $raList[$i]->_data;
338                                        //}
339                                        if ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE) {
340                                                $sRes .= str_repeat("\x00",$this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE));
341                                        }
342                                        // Set for PPS
343                                        $raList[$i]->_StartBlock = $iSmBlk;
344                                        $iSmBlk += $iSmbCnt;
345                                }
346                        }
347                }
348                $iSbCnt = floor($this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE);
349                if ($iSmBlk % $iSbCnt) {
350                        $iB = $iSbCnt - ($iSmBlk % $iSbCnt);
351                        for ($i = 0; $i < $iB; ++$i) {
352                                fwrite($FILE, pack("V", -1));
353                        }
354                }
355                return $sRes;
356        }
357
358        /**
359        * Saves all the PPS's WKs
360        *
361        * @access public
362        * @param array $raList Reference to an array with all PPS's
363        */
364        public function _savePps(&$raList)
365        {
366                // Save each PPS WK
367                $iC = count($raList);
368                for ($i = 0; $i < $iC; ++$i) {
369                        fwrite($this->_FILEH_, $raList[$i]->_getPpsWk());
370                }
371                // Adjust for Block
372                $iCnt = count($raList);
373                $iBCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_PPS_SIZE;
374                if ($iCnt % $iBCnt) {
375                        fwrite($this->_FILEH_, str_repeat("\x00",($iBCnt - ($iCnt % $iBCnt)) * PHPExcel_Shared_OLE::OLE_PPS_SIZE));
376                }
377        }
378
379        /**
380        * Saving Big Block Depot
381        *
382        * @access public
383        * @param integer $iSbdSize
384        * @param integer $iBsize
385        * @param integer $iPpsCnt
386        */
387        public function _saveBbd($iSbdSize, $iBsize, $iPpsCnt)
388        {
389                $FILE = $this->_FILEH_;
390                // Calculate Basic Setting
391                $iBbCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
392                $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE;
393
394                $iBdExL = 0;
395                $iAll = $iBsize + $iPpsCnt + $iSbdSize;
396                $iAllW = $iAll;
397                $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
398                $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
399                // Calculate BD count
400                if ($iBdCnt >$i1stBdL) {
401                        while (1) {
402                                ++$iBdExL;
403                                ++$iAllW;
404                                $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
405                                $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
406                                if ($iBdCnt <= ($iBdExL*$iBbCnt+ $i1stBdL)) {
407                                        break;
408                                }
409                        }
410                }
411
412                // Making BD
413                // Set for SBD
414                if ($iSbdSize > 0) {
415                        for ($i = 0; $i < ($iSbdSize - 1); ++$i) {
416                                fwrite($FILE, pack("V", $i+1));
417                        }
418                        fwrite($FILE, pack("V", -2));
419                }
420                // Set for B
421                for ($i = 0; $i < ($iBsize - 1); ++$i) {
422                        fwrite($FILE, pack("V", $i+$iSbdSize+1));
423                }
424                fwrite($FILE, pack("V", -2));
425
426                // Set for PPS
427                for ($i = 0; $i < ($iPpsCnt - 1); ++$i) {
428                        fwrite($FILE, pack("V", $i+$iSbdSize+$iBsize+1));
429                }
430                fwrite($FILE, pack("V", -2));
431                // Set for BBD itself ( 0xFFFFFFFD : BBD)
432                for ($i = 0; $i < $iBdCnt; ++$i) {
433                        fwrite($FILE, pack("V", 0xFFFFFFFD));
434                }
435                // Set for ExtraBDList
436                for ($i = 0; $i < $iBdExL; ++$i) {
437                        fwrite($FILE, pack("V", 0xFFFFFFFC));
438                }
439                // Adjust for Block
440                if (($iAllW + $iBdCnt) % $iBbCnt) {
441                        $iBlock = ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt));
442                        for ($i = 0; $i < $iBlock; ++$i) {
443                                fwrite($FILE, pack("V", -1));
444                        }
445                }
446                // Extra BDList
447                if ($iBdCnt > $i1stBdL) {
448                        $iN=0;
449                        $iNb=0;
450                        for ($i = $i1stBdL;$i < $iBdCnt; $i++, ++$iN) {
451                                if ($iN >= ($iBbCnt - 1)) {
452                                        $iN = 0;
453                                        ++$iNb;
454                                        fwrite($FILE, pack("V", $iAll+$iBdCnt+$iNb));
455                                }
456                                fwrite($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i));
457                        }
458                        if (($iBdCnt-$i1stBdL) % ($iBbCnt-1)) {
459                                $iB = ($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1));
460                                for ($i = 0; $i < $iB; ++$i) {
461                                        fwrite($FILE, pack("V", -1));
462                                }
463                        }
464                        fwrite($FILE, pack("V", -2));
465                }
466        }
467}
Note: See TracBrowser for help on using the repository browser.