Curly braces {} in arrays replaced, by @kvvaradha.
[fa-stable.git] / reporting / includes / Workbook.php
index 1f53c2aad6973ca143a7a5dbec8bfb817e6925cd..89573820d7d1d293988b0e4a4536bd21ddc3aaeb 100644 (file)
@@ -102,383 +102,795 @@ define('SPREADSHEET_EXCEL_WRITER_EQ', "=");
 */
 define('SPREADSHEET_EXCEL_WRITER_NE', "<>");
 
-$encoding_string='';
-/**
-* Class for creating OLE streams for Excel Spreadsheets
-*
-* @author Xavier Noguer <xnoguer@rezebra.com>
-* @package Spreadsheet_WriteExcel
-*/
-class OLEwriter
+define('PpsType_Root', 5);
+define('PpsType_Dir', 1);
+define('PpsType_File', 2);
+define('DataSizeSmall', 0x1000);
+define('LongIntSize', 4);
+define('PpsSize', 0x80);
+
+function Asc2Ucs($sAsc) 
 {
-    /**
-    * Filename for the OLE stream
-    * @var string
-    * @see _initialize()
-    */
-    var $_OLEfilename;
+    return implode("\x00", (preg_split('//', $sAsc, -1, PREG_SPLIT_NO_EMPTY)))."\x00";
+}
 
-    /**
-    * Filehandle for the OLE stream
-    * @var resource
-    */
-    var $_filehandle;
+function Ucs2Asc($sUcs) 
+{
+    $chars=explode("\x00", $sUcs);
+    array_pop($chars);
+    return implode("", $chars);
+}
 
-    /**
-    * Name of the temporal file in case OLE stream goes to stdout
-    * @var string
-    */
-    var $_tmp_filename;
+function OLEDate2Local($sDateTime) 
+{
+}
 
-    /**
-    * Variable for preventing closing two times
-    * @var integer
-    */
-    var $_fileclosed;
+#------------------------------------------------------------------------------
+# Localtime->OLE Date
+#------------------------------------------------------------------------------
+function LocalDate2OLE($raDate) 
+{
+}
 
-    /**
-    * Size of the data to be written to the OLE stream
-    * @var integer
-    */
-    var $_biffsize;
+function _leapYear($iYear) 
+{
+    return ((($iYear % 4)==0) && (($iYear % 100) || ($iYear % 400)==0)) ? 1 : 0;
+}
 
-    /**
-    * Real data size to be written to the OLE stream
-    * @var integer
-    */
-    var $_booksize;
+function _yearDays($iYear) 
+{
+    return _leapYear($iYear) ? 366 : 365;
+}
 
-    /**
-    * Number of big blocks in the OLE stream
-    * @var integer
-    */
-    var $_big_blocks;
+function _monthDays($iMon, $iYear) 
+{
+    if ($iMon == 1 || $iMon ==  3 || $iMon ==  5 || $iMon == 7 ||
+        $iMon == 8 || $iMon == 10 || $iMon == 12) 
+        return 31;
+    elseif ($iMon == 4 || $iMon == 6 || $iMon == 9 || $iMon == 11) 
+        return 30;
+    elseif ($iMon == 2) 
+        return _leapYear($iYear) ? 29 : 28;
+}
 
-    /**
-    * Number of list blocks in the OLE stream
-    * @var integer
-    */
-    var $_list_blocks;
+/*
+ * This is the OLE::Storage_Lite Perl package ported to PHP
+ * OLE::Storage_Lite was written by Kawai Takanori, kwitknr@cpan.org
+ */
 
-    /**
-    * Number of big blocks in the OLE stream
-    * @var integer
-    */
-    var $_root_start;
+class ole_pps 
+{
+    var $No;
+    var $Name;
+    var $Type;
+    var $PrevPps;
+    var $NextPps;
+    var $DirPps;
+    var $Time1st;
+    var $Time2nd;
+    var $StartBlock;
+    var $Size;
+    var $Data;
+    var $Child;
+    var $_PPS_FILE;
+
+    #------------------------------------------------------------------------------
+    # _new (OLE::Storage_Lite::PPS)
+    #   for OLE::Storage_Lite
+    #------------------------------------------------------------------------------
+    function __construct($iNo, $sNm, $iType, $iPrev, $iNext, $iDir,
+                     $raTime1st, $raTime2nd, $iStart, $iSize,
+                     $sData=false, $raChild=false) 
+    {
+        #1. Constructor for OLE::Storage_Lite
+
+        $this->No         = $iNo;
+        $this->Name       = $sNm;
+        $this->Type       = $iType;
+        $this->PrevPps    = $iPrev;
+        $this->NextPps    = $iNext;
+        $this->DirPps     = $iDir;
+        $this->Time1st    = $raTime1st;
+        $this->Time2nd    = $raTime2nd;
+        $this->StartBlock = $iStart;
+        $this->Size       = $iSize;
+        $this->Data       = $sData;
+        $this->Child      = $raChild;
+        $this->_PPS_FILE  = NULL;
+    }
+
+    #------------------------------------------------------------------------------
+    # _DataLen (OLE::Storage_Lite::PPS)
+    # Check for update
+    #------------------------------------------------------------------------------
+    function _DataLen() 
+    {
+        if ($this->Data===false) 
+            return 0;
+
+        if ($this->_PPS_FILE) 
+            return filesize($this->_PPS_FILE);
+
+        return strlen($this->Data);
+    }
+
+    #------------------------------------------------------------------------------
+    # _makeSmallData (OLE::Storage_Lite::PPS)
+    #------------------------------------------------------------------------------
+    function _makeSmallData(&$aList, $rhInfo) 
+    {
+        //my ($sRes);
+        $FILE = $rhInfo->_FILEH_;
+        $iSmBlk = 0;
+        $sRes = '';
+
+        for ($c=0;$c<sizeof($aList);$c++) 
+        {
+            $oPps=&$aList[$c];
 
-    /**
-    * Constructor for the OLEwriter class
-    *
-    * @param string $OLEfilename the name of the file for the OLE stream
-    */
-    function OLEwriter($OLEfilename)
-    {
-        $this->_OLEfilename  = $OLEfilename;
-        $this->_filehandle   = '';
-        $this->_tmp_filename = '';
-        $this->_fileclosed   = 0;
-        $this->_biff_only    = 0;
-        //$this->_size_allowed = 0;
-        $this->_biffsize     = 0;
-        $this->_booksize     = 0;
-        $this->_big_blocks   = 0;
-        $this->_list_blocks  = 0;
-        $this->_root_start   = 0;
-        //$this->_block_count  = 4;
-        $this->_initialize();
-    }
+            #1. Make SBD, small data string
 
-    /**
-    * Check for a valid filename and store the filehandle.
-    * Filehandle "-" writes to STDOUT
-    *
-    * @access private
-    */
-    function _initialize()
-    {
-        $OLEfile = $this->_OLEfilename;
+            if ($oPps->Type==PpsType_File) 
+            {
+                if ($oPps->Size<=0) 
+                    continue;
 
-        if (($OLEfile == '-') or ($OLEfile == '')) {
-            $this->_tmp_filename = tempnam("/tmp", "OLEwriter");
-            $fh = fopen($this->_tmp_filename, "wb");
-            if ($fh == false) {
-                die("Can't create temporary file.");
-            }
-        } else {
-            // Create a new file, open for writing (in binmode)
-            $fh = fopen($OLEfile, "wb");
-            if ($fh == false) {
-                die("Can't open $OLEfile. It may be in use or protected.");
+                if($oPps->Size < $rhInfo->_SMALL_SIZE) 
+                {
+                    $iSmbCnt = floor($oPps->Size / $rhInfo->_SMALL_BLOCK_SIZE) +
+                               (($oPps->Size % $rhInfo->_SMALL_BLOCK_SIZE) ? 1 : 0);
+                    #1.1 Add to SBD
+                    for ($i = 0; $i<($iSmbCnt-1); $i++) 
+                        fputs($FILE, pack("V", $i+$iSmBlk+1));
+                    fputs($FILE, pack("V", -2));
+
+                    #1.2 Add to Data String(this will be written for RootEntry)
+                    #Check for update
+                    if ($oPps->_PPS_FILE) 
+                    {
+                        //my $sBuff;
+                        fseek($oPps->_PPS_FILE, 0, SEEK_SET); #To The Top
+                        while ($sBuff=fread($oPps->_PPS_FILE, 4096)) 
+                            $sRes .= $sBuff;
+                    } 
+                    else 
+                        $sRes .= $oPps->Data;
+                    if($oPps->Size % $rhInfo->_SMALL_BLOCK_SIZE) 
+                    {
+                        $sRes .= (str_repeat("\x00",
+                                  ($rhInfo->_SMALL_BLOCK_SIZE -
+                                  ($oPps->Size % $rhInfo->_SMALL_BLOCK_SIZE))));
+                    }
+                    #1.3 Set for PPS
+                    $oPps->StartBlock = $iSmBlk;
+                    $iSmBlk += $iSmbCnt;
+                }
             }
-        }
-
-        // Store filehandle
-        $this->_filehandle = $fh;
-    }
-
-
-    /**
-    * Set the size of the data to be written to the OLE stream.
-    * The maximun size comes from this:
-    *   $big_blocks = (109 depot block x (128 -1 marker word)
-    *                 - (1 x end words)) = 13842
-    *   $maxsize    = $big_blocks * 512 bytes = 7087104
-    *
-    * @access public
-    * @see Spreadsheet_Excel_Writer_Workbook::store_OLE_file()
-    * @param integer $biffsize The size of the data to be written to the OLE stream
-    * @return integer 1 for success
-    */
-    function setSize($biffsize)
-    {
-        $maxsize = 7087104; // TODO: extend max size
 
-        if ($biffsize > $maxsize) {
-            die("Maximum file size, $maxsize, exceeded.");
         }
-
-        $this->_biffsize = $biffsize;
-        // Set the min file size to 4k to avoid having to use small blocks
-        if ($biffsize > 4096) {
-            $this->_booksize = $biffsize;
-        } else {
-            $this->_booksize = 4096;
-        }
-        //$this->_size_allowed = 1;
-        return(1);
+        $iSbCnt = floor($rhInfo->_BIG_BLOCK_SIZE / LongIntSize);
+        if ($iSmBlk  % $iSbCnt) 
+            fputs($FILE, str_repeat(pack("V", -1), $iSbCnt - ($iSmBlk % $iSbCnt)));
+        #2. Write SBD with adjusting length for block
+        return $sRes;
+    }
+
+    #------------------------------------------------------------------------------
+    # _savePpsWk (OLE::Storage_Lite::PPS)
+    #------------------------------------------------------------------------------
+    function _savePpsWk($rhInfo) 
+    {
+        #1. Write PPS
+        $FILE=$rhInfo->_FILEH_;
+        fputs($FILE,
+              $this->Name.
+              str_repeat("\x00", 64 - strlen($this->Name)).      #  64
+              pack("v", strlen($this->Name) + 2).                #  66
+              pack("c", $this->Type).                            #  67
+              pack("c", 0x00). #UK                               #  68
+              pack("V", $this->PrevPps). #Prev                   #  72
+              pack("V", $this->NextPps). #Next                   #  76
+              pack("V", $this->DirPps).  #Dir                    #  80
+              "\x00\x09\x02\x00".                                #  84
+              "\x00\x00\x00\x00".                                #  88
+              "\xc0\x00\x00\x00".                                #  92
+              "\x00\x00\x00\x46".                                #  96
+              "\x00\x00\x00\x00".                                # 100
+                         "\x00\x00\x00\x00\x00\x00\x00\x00".
+                         "\x00\x00\x00\x00\x00\x00\x00\x00".
+              pack("V", ($this->StartBlock!==false) ?
+                        $this->StartBlock : 0).                  # 120
+              pack("V", ($this->Size!==false) ?
+                        $this->Size : 0).                        # 124
+              pack("V", 0)                                       # 128
+        );
     }
 
+}
 
-    /**
-    * Calculate various sizes needed for the OLE stream
-    *
-    * @access private
-    */
-    function _calculateSizes()
-    {
-        $datasize = $this->_booksize;
-        if ($datasize % 512 == 0) {
-            $this->_big_blocks = $datasize/512;
-        } else {
-            $this->_big_blocks = floor($datasize/512) + 1;
-        }
-        // There are 127 list blocks and 1 marker blocks for each big block
-        // depot + 1 end of chain block
-        $this->_list_blocks = floor(($this->_big_blocks)/127) + 1;
-        $this->_root_start  = $this->_big_blocks;
-    }
+/*
+ * This is the OLE::Storage_Lite Perl package ported to PHP
+ * OLE::Storage_Lite was written by Kawai Takanori, kwitknr@cpan.org
+ */
 
-    /**
-    * Write root entry, big block list and close the filehandle.
-    * This routine is used to explicitly close the open filehandle without
-    * having to wait for DESTROY.
-    *
-    * @access public
-    * @see Spreadsheet_Excel_Writer_Workbook::store_OLE_file()
-    */
-    function close()
-    {
-        //return if not $this->{_size_allowed};
-        $this->_writePadding();
-        $this->_writePropertyStorage();
-        $this->_writeBigBlockDepot();
-        // Close the filehandle
-        fclose($this->_filehandle);
-        if (($this->_OLEfilename == '-') or ($this->_OLEfilename == '')) {
-            $fh = fopen($this->_tmp_filename, "rb");
-            if ($fh == false) {
-                die("Can't read temporary file.");
+class ole_pps_file extends ole_pps 
+{
+    function __construct($sNm, $sData=false, $sFile=false) 
+    {
+        $this->No         = false;
+        $this->Name       = $sNm;
+        $this->Type       = PpsType_File;
+        $this->PrevPps    = false;
+        $this->NextPps    = false;
+        $this->DirPps     = false;
+        $this->Time1st    = false;
+        $this->Time2nd    = false;
+        $this->StartBlock = false;
+        $this->Size       = false;
+        $this->Data       = ($sFile===false) ? $sData : '';
+        $this->Child      = false;
+
+        if ($sFile!==false) 
+        {
+            if (is_ressource($sFile)) 
+                $this->_PPS_FILE=$sFile;
+            elseif ($sFile=="") 
+            {
+                $fname=tempnam("php_ole");
+                $this->_PPS_FILE=fopen($fname, "r+b");
+            } 
+            else 
+            {
+                $fname=$sFile;
+                $this->_PPS_FILE=fopen($fname, "r+b");
             }
-            fpassthru($fh);
-            @unlink($this->_tmp_filename);
-        }
-        $this->_fileclosed = 1;
-    }
-
-
-    /**
-    * Write BIFF data to OLE file.
-    *
-    * @param string $data string of bytes to be written
-    */
-    function write($data)
-    {
-        fwrite($this->_filehandle, $data, strlen($data));
-    }
-
-
-    /**
-    * Write OLE header block.
-    */
-    function writeHeader()
-    {
-        $this->_calculateSizes();
-        $root_start      = $this->_root_start;
-        $num_lists       = $this->_list_blocks;
-        $id              = pack("nnnn", 0xD0CF, 0x11E0, 0xA1B1, 0x1AE1);
-        $unknown1        = pack("VVVV", 0x00, 0x00, 0x00, 0x00);
-        $unknown2        = pack("vv",   0x3E, 0x03);
-        $unknown3        = pack("v",    -2);
-        $unknown4        = pack("v",    0x09);
-        $unknown5        = pack("VVV",  0x06, 0x00, 0x00);
-        $num_bbd_blocks  = pack("V",    $num_lists);
-        $root_startblock = pack("V",    $root_start);
-        $unknown6        = pack("VV",   0x00, 0x1000);
-        $sbd_startblock  = pack("V",    -2);
-        $unknown7        = pack("VVV",  0x00, -2 ,0x00);
-        $unused          = pack("V",    -1);
-
-        fwrite($this->_filehandle, $id);
-        fwrite($this->_filehandle, $unknown1);
-        fwrite($this->_filehandle, $unknown2);
-        fwrite($this->_filehandle, $unknown3);
-        fwrite($this->_filehandle, $unknown4);
-        fwrite($this->_filehandle, $unknown5);
-        fwrite($this->_filehandle, $num_bbd_blocks);
-        fwrite($this->_filehandle, $root_startblock);
-        fwrite($this->_filehandle, $unknown6);
-        fwrite($this->_filehandle, $sbd_startblock);
-        fwrite($this->_filehandle, $unknown7);
-
-        for ($i=1; $i <= $num_lists; $i++) {
-            $root_start++;
-            fwrite($this->_filehandle, pack("V",$root_start));
-        }
-        for ($i = $num_lists; $i <=108; $i++) {
-            fwrite($this->_filehandle, $unused);
-        }
-    }
-
-
-    /**
-    * Write big block depot.
-    *
-    * @access private
-    */
-    function _writeBigBlockDepot()
-    {
-        $num_blocks   = $this->_big_blocks;
-        $num_lists    = $this->_list_blocks;
-        $total_blocks = $num_lists *128;
-        $used_blocks  = $num_blocks + $num_lists +2;
-
-        $marker       = pack("V", -3);
-        $end_of_chain = pack("V", -2);
-        $unused       = pack("V", -1);
 
-        for ($i = 1; $i < $num_blocks; $i++) {
-            fwrite($this->_filehandle, pack("V",$i));
-        }
-
-        fwrite($this->_filehandle, $end_of_chain);
-        fwrite($this->_filehandle, $end_of_chain);
-        for ($i = 0; $i < $num_lists; $i++) {
-            fwrite($this->_filehandle, $marker);
-        }
-
-        for ($i = $used_blocks; $i <= $total_blocks; $i++) {
-            fwrite($this->_filehandle, $unused);
+            if ($sData!==false) 
+                fputs($this->_PPS_FILE, $sData);
         }
     }
 
-    /**
-    * Write property storage. TODO: add summary sheets
-    *
-    * @access private
-    */
-    function _writePropertyStorage()
+    function append ($sData) 
     {
-        //$rootsize = -2;
-        /***************  name         type   dir start size */
-        $this->_writePps("Root Entry", 0x05,   1,   -2, 0x00);
-        $this->_writePps("Book",       0x02,  -1, 0x00, $this->_booksize);
-        $this->_writePps('',           0x00,  -1, 0x00, 0x0000);
-        $this->_writePps('',           0x00,  -1, 0x00, 0x0000);
+        if ($this->_PPS_FILE) 
+            fputs($this->_PPS_FILE, $sData);
+        else 
+            $this->Data.=$sData;
     }
+}
 
-/**
-* Write property sheet in property storage
-*
-* @param string  $name  name of the property storage.
-* @param integer $type  type of the property storage.
-* @param integer $dir   dir of the property storage.
-* @param integer $start start of the property storage.
-* @param integer $size  size of the property storage.
-* @access private
-*/
-    function _writePps($name, $type, $dir, $start, $size)
-    {
-        $length  = 0;
-        $rawname = '';
-
-        if ($name != '') {
-            $name = $name . "\0";
-            $name_length = strlen($name);
-            for ($i = 0; $i < $name_length; $i++) {
-                // Simulate a Unicode string
-                $rawname .= pack("H*",dechex(ord($name{$i}))).pack("C",0);
-            }
-            $length = strlen($name) * 2;
-        }
-
-        $zero            = pack("C",  0);
-        $pps_sizeofname  = pack("v",  $length);    // 0x40
-        $pps_type        = pack("v",  $type);      // 0x42
-        $pps_prev        = pack("V",  -1);         // 0x44
-        $pps_next        = pack("V",  -1);         // 0x48
-        $pps_dir         = pack("V",  $dir);       // 0x4c
-
-        $unknown1        = pack("V",  0);
-
-        $pps_ts1s        = pack("V",  0);          // 0x64
-        $pps_ts1d        = pack("V",  0);          // 0x68
-        $pps_ts2s        = pack("V",  0);          // 0x6c
-        $pps_ts2d        = pack("V",  0);          // 0x70
-        $pps_sb          = pack("V",  $start);     // 0x74
-        $pps_size        = pack("V",  $size);      // 0x78
-
-
-        fwrite($this->_filehandle, $rawname);
-        for ($i = 0; $i < (64 -$length); $i++) {
-            fwrite($this->_filehandle, $zero);
-        }
-        fwrite($this->_filehandle, $pps_sizeofname);
-        fwrite($this->_filehandle, $pps_type);
-        fwrite($this->_filehandle, $pps_prev);
-        fwrite($this->_filehandle, $pps_next);
-        fwrite($this->_filehandle, $pps_dir);
-        for ($i = 0; $i < 5; $i++) {
-            fwrite($this->_filehandle, $unknown1);
-        }
-        fwrite($this->_filehandle, $pps_ts1s);
-        fwrite($this->_filehandle, $pps_ts1d);
-        fwrite($this->_filehandle, $pps_ts2d);
-        fwrite($this->_filehandle, $pps_ts2d);
-        fwrite($this->_filehandle, $pps_sb);
-        fwrite($this->_filehandle, $pps_size);
-        fwrite($this->_filehandle, $unknown1);
-    }
+/*
+ * This is the OLE::Storage_Lite Perl package ported to PHP
+ * OLE::Storage_Lite was written by Kawai Takanori, kwitknr@cpan.org
+ */
 
-    /**
-    * Pad the end of the file
-    *
-    * @access private
-    */
-    function _writePadding()
-    {
-        $biffsize = $this->_biffsize;
-        if ($biffsize < 4096) {
-            $min_size = 4096;
-        } else {
-            $min_size = 512;
-        }
-        if ($biffsize % $min_size != 0) {
-            $padding  = $min_size - ($biffsize % $min_size);
-            for ($i = 0; $i < $padding; $i++) {
-                fwrite($this->_filehandle, "\0");
-            }
-        }
-    }
+class ole_pps_root extends ole_pps 
+{
+    function __construct($raTime1st=false, $raTime2nd=false, $raChild=false) 
+    {
+        $this->No         = false;
+        $this->Name       = Asc2Ucs('Root Entry');
+        $this->Type       = PpsType_Root;
+        $this->PrevPps    = false;
+        $this->NextPps    = false;
+        $this->DirPps     = false;
+        $this->Time1st    = $raTime1st;
+        $this->Time2nd    = $raTime2nd;
+        $this->StartBlock = false;
+        $this->Size       = false;
+        $this->Data       = false;
+        $this->Child      = $raChild;
+    }
+
+       #------------------------------------------------------------------------------
+       # save (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function save($sFile, $bNoAs=false, $rhInfo=false) 
+       {
+               #0.Initial Setting for saving
+
+               if (!$rhInfo) 
+                       $rhInfo=new stdClass();
+
+               $rhInfo->_BIG_BLOCK_SIZE = $rhInfo->_SMALL_BLOCK_SIZE = 0;
+               $rhInfo->_BIG_BLOCK_SIZE=pow(2, (($rhInfo->_BIG_BLOCK_SIZE) ?
+                       _adjust2($rhInfo->_BIG_BLOCK_SIZE) : 9));
+               $rhInfo->_SMALL_BLOCK_SIZE=pow(2, (($rhInfo->_SMALL_BLOCK_SIZE) ?
+                       _adjust2($rhInfo->_SMALL_BLOCK_SIZE) : 6));
+               $rhInfo->_SMALL_SIZE = 0x1000;
+               $rhInfo->_PPS_SIZE = 0x80;
+
+               #1.Open File
+               #1.1 $sFile is Ref of scalar
+               if(is_resource($sFile)) 
+               {
+                       $oIo=$sFile;
+                       $rhInfo->_FILEH_ = $oIo;
+               }
+               #1.2 $sFile is a simple filename string
+               else 
+               {
+                       $oIo=fopen("$sFile", "wb");
+                       $rhInfo->_FILEH_ = $oIo;
+               }
+
+               $iBlk = 0;
+               #1. Make an array of PPS (for Save)
+               $aList=array();
+               $list=array(&$this);
+               if($bNoAs) 
+                       $this->_savePpsSetPnt2($list, $aList, $rhInfo);
+               else 
+                       $this->_savePpsSetPnt($list, $aList, $rhInfo);
+               list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList, $rhInfo);
+               #2.Save Header
+               $this->_saveHeader($rhInfo, $iSBDcnt, $iBBcnt, $iPPScnt);
+
+               #3.Make Small Data string (write SBD)
+               $sSmWk = $this->_makeSmallData($aList, $rhInfo);
+               $this->Data = $sSmWk;  #Small Datas become RootEntry Data
+
+               #4. Write BB
+               $iBBlk = $iSBDcnt;
+               $this->_saveBigData($iBBlk, $aList, $rhInfo);
+               #5. Write PPS
+               $this->_savePps($aList, $rhInfo);
+               #6. Write BD and BDList and Adding Header informations
+               $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt,  $rhInfo); 
+               #7.Close File
+               fclose($rhInfo->_FILEH_);
+       }
+
+       #------------------------------------------------------------------------------
+       # _calcSize (OLE::Storage_Lite::PPS)
+       #------------------------------------------------------------------------------
+       function _calcSize(&$raList, $rhInfo) 
+       {
+               #0. Calculate Basic Setting
+               $iSBDcnt=0;
+               $iBBcnt=0;
+               $iPPScnt = 0;
+               $iSmallLen = 0;
+               $iSBcnt = 0;
+
+               for ($c=0;$c<sizeof($raList);$c++) 
+               {
+               $oPps=&$raList[$c];
+
+               if($oPps->Type==PpsType_File) 
+               {
+                       $oPps->Size = $oPps->_DataLen();  #Mod
+                       if($oPps->Size < $rhInfo->_SMALL_SIZE) 
+                       {
+                               $iSBcnt += floor($oPps->Size / $rhInfo->_SMALL_BLOCK_SIZE) +
+                               (($oPps->Size % $rhInfo->_SMALL_BLOCK_SIZE) ? 1 : 0);
+                       } 
+                       else 
+                       {
+                               $iBBcnt += 
+                               (floor($oPps->Size/ $rhInfo->_BIG_BLOCK_SIZE) +
+                               (($oPps->Size % $rhInfo->_BIG_BLOCK_SIZE)? 1: 0));
+                       }
+               }
+               }       
+               $iSmallLen = $iSBcnt * $rhInfo->_SMALL_BLOCK_SIZE;
+               $iSlCnt = floor($rhInfo->_BIG_BLOCK_SIZE / LongIntSize);
+               $iSBDcnt = floor($iSBcnt / $iSlCnt)+ (($iSBcnt % $iSlCnt) ? 1 : 0);
+               $iBBcnt +=  (floor($iSmallLen/ $rhInfo->_BIG_BLOCK_SIZE) +
+               (( $iSmallLen% $rhInfo->_BIG_BLOCK_SIZE) ? 1 : 0));
+               $iCnt = sizeof($raList);
+               $iBdCnt = $rhInfo->_BIG_BLOCK_SIZE/PpsSize;
+               $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt) ? 1 : 0));
+
+               return array($iSBDcnt, $iBBcnt, $iPPScnt);
+       }
+
+       #------------------------------------------------------------------------------
+       # _adjust2 (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _adjust2($i2) 
+       {
+               $iWk = log($i2)/log(2);
+               return ($iWk > int($iWk)) ? floor($iWk)+1 : $iWk;
+       }
+
+       #------------------------------------------------------------------------------
+       # _saveHeader (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _saveHeader($rhInfo, $iSBDcnt, $iBBcnt, $iPPScnt) 
+       {
+               $FILE = $rhInfo->_FILEH_;
+
+               #0. Calculate Basic Setting
+               $iBlCnt = $rhInfo->_BIG_BLOCK_SIZE / LongIntSize;
+               $i1stBdL = ($rhInfo->_BIG_BLOCK_SIZE - 0x4C) / LongIntSize;
+
+               $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);
+               //my $i;
+
+               #0.1 Calculate BD count
+               if ($iBdCnt > $i1stBdL) 
+               {
+                       // TODO: is do-while correct here?
+                       do 
+                       {
+                       $iBdExL++;
+                       $iAllW++;
+                       $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0);
+                       $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt) ? 1 : 0);
+               } 
+               while($iBdCnt > ($iBdExL*$iBlCnt+ $i1stBdL));
+               }
+
+               #1.Save Header
+               fputs($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", 0).                  #Small Block Depot
+            pack("V", 1)
+       );
+               #2. Extra BDList Start, Count
+               if($iBdCnt < $i1stBdL) 
+               {
+               fputs($FILE, 
+                pack("V", -2).     #Extra BDList Start
+                pack("V", 0)       #Extra BDList Count
+               );
+               } 
+               else 
+               {
+               fputs($FILE,
+               pack("V", $iAll+$iBdCnt).
+               pack("V", $iBdExL)
+           );
+               }
+
+               #3. BDList
+       for ($i=0;($i<$i1stBdL) && ($i < $iBdCnt); $i++) 
+               fputs($FILE, pack("V", $iAll+$i));
+       if ($i<$i1stBdL) 
+       {
+                       // TODO: Check, if str_repeat is binary safe
+               fputs($FILE, str_repeat((pack("V", -1)), ($i1stBdL-$i)));
+       }
+       }
+
+       #------------------------------------------------------------------------------
+       # _saveBigData (OLE::Storage_Lite::PPS)
+       #------------------------------------------------------------------------------
+       function _saveBigData(&$iStBlk, &$raList, $rhInfo) 
+       {
+
+               //return;//!!!
+
+               $iRes = 0;
+               $FILE = $rhInfo->_FILEH_;
+
+               #1.Write Big (ge 0x1000) Data into Block
+               for ($c=0;$c<sizeof($raList);$c++) 
+               {
+               $oPps=&$raList[$c];
+               if($oPps->Type!=PpsType_Dir) 
+               {
+                               #print "PPS: $oPps DEF:", defined($oPps->{Data}), "\n";
+                       $oPps->Size = $oPps->_DataLen();  #Mod
+                       if(($oPps->Size >= $rhInfo->_SMALL_SIZE) ||
+                       (($oPps->Type == PpsType_Root) && $oPps->Data!==false)) 
+               {
+                       #1.1 Write Data
+                       #Check for update
+                       if($oPps->_PPS_FILE) 
+                       {
+                               //my $sBuff;
+                               $iLen = 0;
+                               fseek($oPps->_PPS_FILE, 0, SEEK_SET); #To The Top
+                               while ($sBuff=fread($oPps->_PPS_FILE, 4096)) 
+                               {
+                               $iLen += length($sBuff);
+                               fputs($FILE, $sBuff);           #Check for update
+                               }
+                       } 
+                       else 
+                               fputs($FILE, $oPps->Data);
+                       if ($oPps->Size % $rhInfo->_BIG_BLOCK_SIZE) 
+                       {
+                                               // TODO: Check, if str_repeat() is binary safe
+                               fputs($FILE, str_repeat("\x00", 
+                               ($rhInfo->_BIG_BLOCK_SIZE - 
+                            ($oPps->Size % $rhInfo->_BIG_BLOCK_SIZE)))
+                       );
+                       }
+                       #1.2 Set For PPS
+                       $oPps->StartBlock = $iStBlk;
+                       $iStBlk += 
+                       (floor($oPps->Size/ $rhInfo->_BIG_BLOCK_SIZE) +
+                        (($oPps->Size % $rhInfo->_BIG_BLOCK_SIZE) ? 1 : 0));
+                       }
+               }
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePps (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _savePps(&$raList, $rhInfo) 
+       {
+               #0. Initial
+               $FILE = $rhInfo->_FILEH_;
+               #2. Save PPS
+               for ($c=0;$c<sizeof($raList);$c++) 
+               {
+               $oItem=&$raList[$c];
+               $oItem->_savePpsWk($rhInfo);
+               }
+               #3. Adjust for Block
+               $iCnt = sizeof($raList);
+               $iBCnt = $rhInfo->_BIG_BLOCK_SIZE / $rhInfo->_PPS_SIZE;
+               if($iCnt % $iBCnt) 
+               fputs($FILE, str_repeat("\x00", (($iBCnt - ($iCnt % $iBCnt)) * $rhInfo->_PPS_SIZE)));
+               return (floor($iCnt / $iBCnt) + (($iCnt % $iBCnt) ? 1 : 0));
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePpsSetPnt2 (OLE::Storage_Lite::PPS::Root)
+       #  For Test
+       #------------------------------------------------------------------------------
+       function _savePpsSetPnt2(&$aThis, &$raList, $rhInfo) 
+       {
+               #1. make Array as Children-Relations
+               #1.1 if No Children
+               if (!is_array($aThis) || sizeof($aThis)==0) 
+               return 0xFFFFFFFF;
+               elseif (sizeof($aThis)==1) 
+               {
+                       #1.2 Just Only one
+               array_push($raList, $aThis[0]);
+               $aThis[0]->No = sizeof($raList)-1;
+               $aThis[0]->PrevPps = 0xFFFFFFFF;
+               $aThis[0]->NextPps = 0xFFFFFFFF;
+               $aThis[0]->DirPps = $this->_savePpsSetPnt2($aThis[0]->Child, $raList, $rhInfo);
+               return $aThis[0]->No;
+               } 
+               else 
+               {
+                       #1.3 Array
+               $iCnt = sizeof($aThis);
+                       #1.3.1 Define Center
+               $iPos = 0; #int($iCnt/ 2);     #$iCnt 
+
+               $aWk = $aThis;
+               $aPrev = (sizeof($aThis) > 2) ? array_splice($aWk, 1, 1) : array(); #$iPos);
+               $aNext = array_splice($aWk, 1); #, $iCnt - $iPos -1);
+               $aThis[$iPos]->PrevPps = $this->_savePpsSetPnt2($aPrev, $raList, $rhInfo);
+               array_push($raList, $aThis[$iPos]);
+               $aThis[$iPos]->No = sizeof($raList)-1;
+
+                       #1.3.2 Devide a array into Previous,Next
+               $aThis[$iPos]->NextPps = $this->_savePpsSetPnt2($aNext, $raList, $rhInfo);
+               $aThis[$iPos]->DirPps = $this->_savePpsSetPnt2($aThis[$iPos]->Child, $raList, $rhInfo);
+               return $aThis[$iPos]->No;
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePpsSetPnt2 (OLE::Storage_Lite::PPS::Root)
+       #  For Test
+       #------------------------------------------------------------------------------
+       function _savePpsSetPnt2s(&$aThis, &$raList, $rhInfo) 
+       {
+               #1. make Array as Children-Relations
+               #1.1 if No Children
+               if (!is_array($aThis) || sizeof($aThis)==0) 
+               return 0xFFFFFFFF;
+               elseif (sizeof($aThis)==1) 
+               {
+                       #1.2 Just Only one
+               array_push($raList, $aThis[0]);
+               $aThis[0]->No = sizeof($raList)-1;
+               $aThis[0]->PrevPps = 0xFFFFFFFF;
+               $aThis[0]->NextPps = 0xFFFFFFFF;
+               $aThis[0]->DirPps = $this->_savePpsSetPnt2($aThis[0]->Child, $raList, $rhInfo);
+               return $aThis[0]->No;
+               } 
+               else 
+               {
+                       #1.3 Array
+               $iCnt = sizeof($aThis);
+                       #1.3.1 Define Center
+               $iPos = 0; #int($iCnt/ 2);     #$iCnt 
+               array_push($raList, $aThis[$iPos]);
+               $aThis[$iPos]->No = sizeof($raList)-1;
+               $aWk = $aThis;
+                       #1.3.2 Devide a array into Previous,Next
+               $aPrev = array_splice($aWk, 0, $iPos);
+               $aNext = array_splice($aWk, 1, $iCnt - $iPos - 1);
+               $aThis[$iPos]->PrevPps = $this->_savePpsSetPnt2($aPrev, $raList, $rhInfo);
+               $aThis[$iPos]->NextPps = $this->_savePpsSetPnt2($aNext, $raList, $rhInfo);
+               $aThis[$iPos]->DirPps = $this->_savePpsSetPnt2($aThis[$iPos]->Child, $raList, $rhInfo);
+               return $aThis[$iPos]->No;
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePpsSetPnt (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _savePpsSetPnt(&$aThis, &$raList, $rhInfo) 
+       {
+
+               //print "yyy type: ".gettype($aThis)."<br>\n";
+               //print "yyy name: ".$aThis[0]->Name."<br>\n";
+
+               #1. make Array as Children-Relations
+               #1.1 if No Children
+               if (!is_array($aThis) || sizeof($aThis)==0) 
+               {
+               return 0xFFFFFFFF;
+               } 
+               elseif (sizeof($aThis)==1) 
+               {
+                       #1.2 Just Only one
+               array_push($raList, $aThis[0]);
+               $aThis[0]->No = sizeof($raList)-1;
+               $aThis[0]->PrevPps = 0xFFFFFFFF;
+               $aThis[0]->NextPps = 0xFFFFFFFF;
+               $aThis[0]->DirPps = $this->_savePpsSetPnt($aThis[0]->Child, $raList, $rhInfo);
+               return $aThis[0]->No;
+               } 
+               else 
+               {       
+                       #1.3 Array
+               $iCnt = sizeof($aThis);
+                       #1.3.1 Define Center
+               $iPos = floor($iCnt/2);     #$iCnt 
+               array_push($raList, $aThis[$iPos]);
+               $aThis[$iPos]->No = sizeof($raList)-1;
+               $aWk = $aThis;
+                       #1.3.2 Devide a array into Previous,Next
+               $aPrev = splice($aWk, 0, $iPos);
+               $aNext = splice($aWk, 1, $iCnt - $iPos - 1);
+               $aThis[$iPos]->PrevPps = $this->_savePpsSetPnt($aPrev, $raList, $rhInfo);
+               $aThis[$iPos]->NextPps = $this->_savePpsSetPnt($aNext, $raList, $rhInfo);
+               $aThis[$iPos]->DirPps = $this->_savePpsSetPnt($aThis[$iPos]->Child, $raList, $rhInfo);
+               return $aThis[$iPos]->No;
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePpsSetPnt (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _savePpsSetPnt1(&$aThis, &$raList, $rhInfo) 
+       {
+               #1. make Array as Children-Relations
+               #1.1 if No Children
+               if (!is_array($aThis) || sizeof($aThis)==0) 
+               {
+                       return 0xFFFFFFFF;
+               } 
+               elseif (sizeof($aThis)==1) 
+               {
+                       #1.2 Just Only one
+                       array_push($raList, $aThis[0]);
+                       $aThis[0]->No = sizeof($raList)-1;
+                       $aThis[0]->PrevPps = 0xFFFFFFFF;
+                       $aThis[0]->NextPps = 0xFFFFFFFF;
+                       $aThis[0]->DirPps = $this->_savePpsSetPnt($aThis[0]->Child, $raList, $rhInfo);
+                       return $aThis[0]->No;
+               } 
+               else 
+               {
+                       #1.3 Array
+                       $iCnt = sizeof($aThis);
+                       #1.3.1 Define Center
+                       $iPos = floor($iCnt / 2);     #$iCnt 
+                       array_push($raList, $aThis[$iPos]);
+                       $aThis[$iPos]->No = sizeof($raList)-1;
+                       $aWk = $aThis;
+                       #1.3.2 Devide a array into Previous,Next
+                       $aPrev = splice($aWk, 0, $iPos);
+                       $aNext = splice($aWk, 1, $iCnt - $iPos - 1);
+                       $aThis[$iPos]->PrevPps = $this->_savePpsSetPnt($aPrev, $raList, $rhInfo);
+                       $aThis[$iPos]->NextPps = $this->_savePpsSetPnt($aNext, $raList, $rhInfo);
+                       $aThis[$iPos]->DirPps = $this->_savePpsSetPnt($aThis[$iPos]->Child, $raList, $rhInfo);
+                       return $aThis[$iPos]->No;
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _saveBbd (OLE::Storage_Lite)
+       #------------------------------------------------------------------------------
+       function _saveBbd($iSbdSize, $iBsize, $iPpsCnt, $rhInfo) 
+       {
+               $FILE = $rhInfo->_FILEH_;
+               #0. Calculate Basic Setting
+               $iBbCnt = $rhInfo->_BIG_BLOCK_SIZE / LongIntSize;
+               $i1stBdL = ($rhInfo->_BIG_BLOCK_SIZE - 0x4C) / LongIntSize;
+
+               $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);
+               //my $i;
+               #0.1 Calculate BD count
+               if ($iBdCnt >$i1stBdL) 
+               {
+                       // TODO: do-while correct here?
+               do 
+               {
+                       $iBdExL++;
+                       $iAllW++;
+                       $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0);
+                       $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt) ? 1 : 0);
+               } 
+               while ($iBdCnt > ($iBdExL*$iBbCnt+$i1stBdL));
+               }
+
+               #1. Making BD
+               #1.1 Set for SBD
+               if($iSbdSize > 0) 
+               {
+               for ($i = 0; $i<($iSbdSize-1); $i++) 
+                       fputs($FILE, pack("V", $i+1));
+               fputs($FILE, pack("V", -2));
+               }
+               #1.2 Set for B
+               for ($i = 0; $i<($iBsize-1); $i++) 
+               fputs($FILE, pack("V", $i+$iSbdSize+1));
+               fputs($FILE, pack("V", -2));
+
+               #1.3 Set for PPS
+               for ($i = 0; $i<($iPpsCnt-1); $i++) 
+               fputs($FILE, pack("V", $i+$iSbdSize+$iBsize+1));
+               fputs($FILE, pack("V", -2));
+               #1.4 Set for BBD itself ( 0xFFFFFFFD : BBD)
+               for ($i=0; $i<$iBdCnt;$i++) 
+               fputs($FILE, pack("V", 0xFFFFFFFD));
+               #1.5 Set for ExtraBDList
+               for ($i=0; $i<$iBdExL;$i++) 
+               fputs($FILE, pack("V", 0xFFFFFFFC));
+               #1.6 Adjust for Block
+               if(($iAllW + $iBdCnt) % $iBbCnt) 
+               fputs($FILE, str_repeat(pack("V", -1), ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt))));
+
+               #2.Extra BDList
+               if($iBdCnt > $i1stBdL)  
+               {
+               $iN=0;
+               $iNb=0;
+               for ($i=$i1stBdL;$i<$iBdCnt; $i++, $iN++) 
+               {
+                       if($iN>=($iBbCnt-1)) 
+                       {
+                               $iN = 0;
+                               $iNb++;
+                               fputs($FILE, pack("V", $iAll+$iBdCnt+$iNb));
+                       }
+                       fputs($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i));
+               }
+               if(($iBdCnt-$i1stBdL) % ($iBbCnt-1)) 
+                       fputs($FILE, str_repeat(pack("V", -1), (($iBbCnt-1) - (($iBdCnt-$i1stBdL) % ($iBbCnt-1)))));
+               fputs($FILE, pack("V", -2));
+               }
+       }
 }
 
 /**
@@ -536,7 +948,7 @@ class Spreadsheet_Excel_Writer_BIFFwriter
     *
     * @access public
     */
-    function Spreadsheet_Excel_Writer_BIFFwriter()
+    function __construct()
     {
         $this->_byte_order = '';
         $this->_data       = '';
@@ -724,7 +1136,7 @@ class Spreadsheet_Excel_Writer_Validator
     */
     var $_parser;
 
-    function Spreadsheet_Excel_Writer_Validator(&$parser)
+    function __construct(&$parser)
     {
         $this->_parser       = $parser;
         $this->_type         = 0x01; // FIXME: add method for setting datatype
@@ -1057,7 +1469,7 @@ class Spreadsheet_Excel_Writer_Format
     * @param integer $index the XF index for the format.
     * @param array   $properties array with properties to be set on initialization.
     */
-    function Spreadsheet_Excel_Writer_Format($BIFF_version, $index = 0, $properties =  array())
+    function __construct($BIFF_version, $index = 0, $properties =  array())
     {
         $this->_xf_index       = $index;
         $this->_BIFF_version   = $BIFF_version;
@@ -1975,7 +2387,7 @@ class Spreadsheet_Excel_Writer_Parser
     * @param integer $byte_order The byte order (Little endian or Big endian) of the architecture
                                  (optional). 1 => big endian, 0 (default) little endian.
     */
-    function Spreadsheet_Excel_Writer_Parser($byte_order, $biff_version)
+    function __construct($byte_order, $biff_version)
     {
         $this->_current_char  = 0;
         $this->_BIFF_version  = $biff_version;
@@ -2479,9 +2891,9 @@ class Spreadsheet_Excel_Writer_Parser
 
         // Split the range into 2 cell refs
         if (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\:([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) {
-            list($cell1, $cell2) = split(':', $range);
+            list($cell1, $cell2) = preg_split('/:/', $range);
         } elseif (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\.\.([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) {
-            list($cell1, $cell2) = split('\.\.', $range);
+            list($cell1, $cell2) = preg_split('/\.\./', $range);
 
         } else {
             // TODO: use real error codes
@@ -2521,7 +2933,7 @@ class Spreadsheet_Excel_Writer_Parser
         $class = 2; // as far as I know, this is magick.
 
         // Split the ref at the ! symbol
-        list($ext_ref, $range) = split('!', $token);
+        list($ext_ref, $range) = preg_split('/!/', $token);
 
         // Convert the external reference part (different for BIFF8)
         if ($this->_BIFF_version == 0x0500) {
@@ -2531,7 +2943,7 @@ class Spreadsheet_Excel_Writer_Parser
         }
 
         // Split the range into 2 cell refs
-        list($cell1, $cell2) = split(':', $range);
+        list($cell1, $cell2) = preg_split('/:/', $range);
 
         // Convert the cell references
         if (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/", $cell1)) {
@@ -2600,7 +3012,7 @@ class Spreadsheet_Excel_Writer_Parser
         $class = 2; // as far as I know, this is magick.
 
         // Split the ref at the ! symbol
-        list($ext_ref, $cell) = split('!', $cell);
+        list($ext_ref, $cell) = preg_split('/!/', $cell);
 
         // Convert the external reference part (different for BIFF8)
         if ($this->_BIFF_version == 0x0500) {
@@ -2641,7 +3053,7 @@ class Spreadsheet_Excel_Writer_Parser
 
         // Check if there is a sheet range eg., Sheet1:Sheet2.
         if (preg_match("/:/", $ext_ref)) {
-            list($sheet_name1, $sheet_name2) = split(':', $ext_ref);
+            list($sheet_name1, $sheet_name2) = preg_split('/:/', $ext_ref);
 
             $sheet1 = $this->_getSheetIndex($sheet_name1);
             if ($sheet1 == -1) {
@@ -2687,7 +3099,7 @@ class Spreadsheet_Excel_Writer_Parser
 
         // Check if there is a sheet range eg., Sheet1:Sheet2.
         if (preg_match("/:/", $ext_ref)) {
-            list($sheet_name1, $sheet_name2) = split(':', $ext_ref);
+            list($sheet_name1, $sheet_name2) = preg_split('/:/', $ext_ref);
 
             $sheet1 = $this->_getSheetIndex($sheet_name1);
             if ($sheet1 == -1) {
@@ -2865,7 +3277,7 @@ class Spreadsheet_Excel_Writer_Parser
         $col    = 0;
         $col_ref_length = strlen($col_ref);
         for ($i = 0; $i < $col_ref_length; $i++) {
-            $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn);
+            $col += (ord($col_ref[$i]) - ord('A') + 1) * pow(26, $expn);
             $expn--;
         }
 
@@ -2887,20 +3299,20 @@ class Spreadsheet_Excel_Writer_Parser
         $formula_length = strlen($this->_formula);
         // eat up white spaces
         if ($i < $formula_length) {
-            while ($this->_formula{$i} == " ") {
+            while ($this->_formula[$i] == " ") {
                 $i++;
             }
 
             if ($i < ($formula_length - 1)) {
-                $this->_lookahead = $this->_formula{$i+1};
+                $this->_lookahead = $this->_formula[$i+1];
             }
             $token = '';
         }
 
         while ($i < $formula_length) {
-            $token .= $this->_formula{$i};
+            $token .= $this->_formula[$i];
             if ($i < ($formula_length - 1)) {
-                $this->_lookahead = $this->_formula{$i+1};
+                $this->_lookahead = $this->_formula[$i+1];
             } else {
                 $this->_lookahead = '';
             }
@@ -2915,7 +3327,7 @@ class Spreadsheet_Excel_Writer_Parser
             }
 
             if ($i < ($formula_length - 2)) {
-                $this->_lookahead = $this->_formula{$i+2};
+                $this->_lookahead = $this->_formula[$i+2];
             } else { // if we run out of characters _lookahead becomes empty
                 $this->_lookahead = '';
             }
@@ -2986,7 +3398,7 @@ class Spreadsheet_Excel_Writer_Parser
             default:
                 // if it's a reference
                 if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$token) and
-                   !ereg("[0-9]",$this->_lookahead) and 
+                   !preg_match("/[0-9]/",$this->_lookahead) and 
                    ($this->_lookahead != ':') and ($this->_lookahead != '.') and
                    ($this->_lookahead != '!'))
                 {
@@ -2994,39 +3406,39 @@ class Spreadsheet_Excel_Writer_Parser
                 }
                 // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1)
                 elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and
-                       !ereg("[0-9]",$this->_lookahead) and
+                       !preg_match("/[0-9]/",$this->_lookahead) and
                        ($this->_lookahead != ':') and ($this->_lookahead != '.'))
                 {
                     return $token;
                 }
                 // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1)
                 elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and
-                       !ereg("[0-9]",$this->_lookahead) and
+                       !preg_match("/[0-9]/",$this->_lookahead) and
                        ($this->_lookahead != ':') and ($this->_lookahead != '.'))
                 {
                     return $token;
                 }
                 // if it's a range (A1:A2)
                 elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and 
-                       !ereg("[0-9]",$this->_lookahead))
+                       !preg_match("/[0-9]/",$this->_lookahead))
                 {
                     return $token;
                 }
                 // if it's a range (A1..A2)
                 elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and 
-                       !ereg("[0-9]",$this->_lookahead))
+                       !preg_match("/[0-9]/",$this->_lookahead))
                 {
                     return $token;
                 }
                 // If it's an external range like Sheet1!A1 or Sheet1:Sheet2!A1:B2
                 elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and
-                       !ereg("[0-9]",$this->_lookahead))
+                       !preg_match("/[0-9]/",$this->_lookahead))
                 {
                     return $token;
                 }
                 // If it's an external range like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2
                 elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and
-                       !ereg("[0-9]",$this->_lookahead))
+                       !preg_match("/[0-9]/",$this->_lookahead))
                 {
                     return $token;
                 }
@@ -3038,12 +3450,12 @@ class Spreadsheet_Excel_Writer_Parser
                     return $token;
                 }
                 // If it's a string (of maximum 255 characters)
-                elseif (ereg("^\"[^\"]{0,255}\"$",$token))
+                elseif (preg_match("/^\"[^\"]{0,255}\"$/",$token))
                 {
                     return $token;
                 }
                 // if it's a function call
-                elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$token) and ($this->_lookahead == "("))
+                elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$token) and ($this->_lookahead == "("))
                 {
                     return $token;
                 }
@@ -3063,7 +3475,7 @@ class Spreadsheet_Excel_Writer_Parser
     {
         $this->_current_char = 0;
         $this->_formula      = $formula;
-        $this->_lookahead    = $formula{1};
+        $this->_lookahead    = $formula[1];
         $this->_advance();
         $this->_parse_tree   = $this->_condition();
     }
@@ -3118,7 +3530,7 @@ class Spreadsheet_Excel_Writer_Parser
     function _expression()
     {
         // If it's a string return a string node
-        if (ereg("^\"[^\"]{0,255}\"$", $this->_current_token)) {
+        if (preg_match("/^\"[^\"]{0,255}\"$/", $this->_current_token)) {
             $result = $this->_createTree($this->_current_token, '', '');
             $this->_advance();
             return $result;
@@ -3258,7 +3670,7 @@ class Spreadsheet_Excel_Writer_Parser
             return $result;
         }
         // if it's a function call
-        elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$this->_current_token))
+        elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$this->_current_token))
         {
             $result = $this->_func();
             return $result;
@@ -3731,14 +4143,14 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr
     * @param mixed   &$parser      The formula parser created for the Workbook
     * @access private
     */
-    function Spreadsheet_Excel_Writer_Worksheet($BIFF_version, $name,
+    function                                   __construct($BIFF_version, $name,
                                                 $index, &$activesheet,
                                                 &$firstsheet, &$str_total,
                                                 &$str_unique, &$str_table,
                                                 &$url_format, &$parser)
     {
         // It needs to call its parent's constructor explicitly
-        $this->Spreadsheet_Excel_Writer_BIFFwriter();
+        parent::__construct();
         $this->_BIFF_version   = $BIFF_version;
         $rowmax                = 65536; // 16384 in Excel 5
         $colmax                = 256;
@@ -4683,7 +5095,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr
         $row     = $match[2];
 
         // Convert base26 column string to number
-        $chars = split('', $col);
+        $chars = preg_split('//', $col);
         $expn  = 0;
         $col   = 0;
 
@@ -4878,11 +5290,10 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr
     */
     function setInputEncoding($encoding)
     {
-       global $encoding_string;
          if ($encoding != 'UTF-16LE' && !function_exists('iconv')) {
              die("Using an input encoding other than UTF-16LE requires PHP support for iconv");
          }
-         $this->_input_encoding = $encoding_string = $encoding;
+         $this->_input_encoding = $encoding;
     }
 
     /** added 2009-03-05 by Joe Hunt, FA for arabic languages */
@@ -5401,7 +5812,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr
         // parameters accordingly.
         // Split the dir name and sheet name (if it exists)
         /*if (preg_match("/\#/", $url)) {
-            list($dir_long, $sheet) = split("\#", $url);
+            list($dir_long, $sheet) = preg_split("/\#/", $url);
         } else {
             $dir_long = $url;
         }
@@ -5409,7 +5820,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr
         if (isset($sheet)) {
             $link_type |= 0x08;
             $sheet_len  = pack("V", strlen($sheet) + 0x01);
-            $sheet      = join("\0", split('', $sheet));
+            $sheet      = join("\0", preg_split('//', $sheet));
             $sheet     .= "\0\0\0";
         } else {
             $sheet_len   = '';
@@ -5433,7 +5844,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr
         $dir_short   = preg_replace("/\.\.\\\/", '', $dir_long) . "\0";
     
         // Store the long dir name as a wchar string (non-null terminated)
-        //$dir_long       = join("\0", split('', $dir_long));
+        //$dir_long       = join("\0", preg_split('//', $dir_long));
         $dir_long       = $dir_long . "\0";
     
         // Pack the lengths of the dir strings
@@ -6242,7 +6653,7 @@ class Spreadsheet_Excel_Writer_Worksheet extends Spreadsheet_Excel_Writer_BIFFwr
         $colcount = count($this->_colinfo);
         for ($i = 0; $i < $colcount; $i++) {
            // Skip cols without outline level info.
-           if (count($col_level) >= 6) {
+           if (count_array($col_level) >= 6) {
               $col_level = max($this->_colinfo[$i][5], $col_level);
            }
         }
@@ -7001,13 +7412,13 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
     * @param string filename for storing the workbook. "-" for writing to stdout.
     * @access public
     */
-    function Spreadsheet_Excel_Writer_Workbook($filename)
+    function __construct($filename)
     {
         // It needs to call its parent's constructor explicitly
-        $this->Spreadsheet_Excel_Writer_BIFFwriter();
+        parent::__construct();
 
         $this->_filename         = $filename;
-        $this->_parser           =& new Spreadsheet_Excel_Writer_Parser($this->_byte_order, $this->_BIFF_version);
+        $this->_parser           = new Spreadsheet_Excel_Writer_Parser($this->_byte_order, $this->_BIFF_version);
         $this->_1904             = 0;
         $this->_activesheet      = 0;
         $this->_firstsheet       = 0;
@@ -7016,7 +7427,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
         $this->_fileclosed       = 0;
         $this->_biffsize         = 0;
         $this->_sheetname        = 'Sheet';
-        $this->_tmp_format       =& new Spreadsheet_Excel_Writer_Format($this->_BIFF_version);
+        $this->_tmp_format       = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version);
         $this->_worksheets       = array();
         $this->_sheetnames       = array();
         $this->_formats          = array();
@@ -7401,21 +7812,24 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
     */
     function _storeOLEFile()
     {
-        $OLE  = new OLEwriter($this->_filename);
-        // Write Worksheet data if data <~ 7MB
-        if ($OLE->setSize($this->_biffsize))
-        {
-            $OLE->writeHeader();
-            $OLE->write($this->_data);
-            foreach($this->_worksheets as $sheet) 
-            {
-                while ($tmp = $sheet->getData()) {
-                    $OLE->write($tmp);
-                }
+        if($this->_BIFF_version == 0x0600) {
+            $OLE = new ole_pps_file(Asc2Ucs('Workbook'));
+        } else {
+            $OLE = new ole_pps_file(Asc2Ucs('Book'));
+        }
+
+        $OLE->append($this->_data);
+
+        $total_worksheets = count($this->_worksheets);
+        for ($i = 0; $i < $total_worksheets; $i++) {
+            while ($tmp = $this->_worksheets[$i]->getData()) {
+                $OLE->append($tmp);
             }
         }
-        $OLE->close();
-        return true;
+
+        $root = new ole_pps_root(false, false, array($OLE));
+
+        $root->save($this->_filename);
     }
 
     /**
@@ -7744,7 +8158,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
 /*        
         if ($this->_BIFF_version == 0x0600)    // Tried to fix the correct handling here, with the
         {                                                                              // corrected specification from M$ - Joe Hunt 2009-03-08
-               global $encoding_string;
+               $encoding_string = $this->_input_encoding;
                if ($encoding_string == 'UTF-16LE')
                {
                    $strlen = function_exists('mb_strlen') ? mb_strlen($sheetname, 'UTF-16LE') : (strlen($sheetname) / 2);
@@ -8156,9 +8570,9 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
            8228 : Maximum Excel97 block size
              -4 : Length of block header
              -8 : Length of additional SST header information
-         = 8216
+             -8 : Arbitrary number to keep within _add_continue() limit = 8208
         */
-        $continue_limit     = 8216;
+        $continue_limit     = 8208;
         $block_length       = 0;
         $written            = 0;
         $this->_block_sizes = array();
@@ -8166,6 +8580,9 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
 
         foreach (array_keys($this->_str_table) as $string) {
             $string_length = strlen($string);
+            $headerinfo    = unpack("vlength/Cencoding", $string);
+            $encoding      = $headerinfo["encoding"];
+            $split_string  = 0;
 
             // Block length is the total length of the strings that will be
             // written out in a single SST or CONTINUE block.
@@ -8192,16 +8609,39 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
                 boundaries. Therefore, in some cases we need to reduce the
                 amount of available
                 */
+                $align = 0;
+
+                // Only applies to Unicode strings
+                if ($encoding == 1) {
+                    // Min string + header size -1
+                    $header_length = 4;
+
+                    if ($space_remaining > $header_length) {
+                        // String contains 3 byte header => split on odd boundary
+                        if (!$split_string && $space_remaining % 2 != 1) {
+                            $space_remaining--;
+                            $align = 1;
+                        }
+                        // Split section without header => split on even boundary
+                        else if ($split_string && $space_remaining % 2 == 1) {
+                            $space_remaining--;
+                            $align = 1;
+                        }
+
+                        $split_string = 1;
+                    }
+                }
+
 
                 if ($space_remaining > $header_length) {
                     // Write as much as possible of the string in the current block
                     $written      += $space_remaining;
 
                     // Reduce the current block length by the amount written
-                    $block_length -= $continue_limit - $continue;
+                    $block_length -= $continue_limit - $continue - $align;
 
                     // Store the max size for this block
-                    $this->_block_sizes[] = $continue_limit;
+                    $this->_block_sizes[] = $continue_limit - $align;
 
                     // If the current string was split then the next CONTINUE block
                     // should have the string continue flag (grbit) set unless the
@@ -8243,13 +8683,19 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
          This length is required to set the offsets in the BOUNDSHEET records since
          they must be written before the SST records
         */
-        $total_offset = array_sum($this->_block_sizes);
-        // SST information
-        $total_offset += 8;
-        if (!empty($this->_block_sizes)) {
-            $total_offset += (count($this->_block_sizes)) * 4; // add CONTINUE headers
+
+        $tmp_block_sizes = array();
+        $tmp_block_sizes = $this->_block_sizes;
+
+        $length  = 12;
+        if (!empty($tmp_block_sizes)) {
+            $length += array_shift($tmp_block_sizes); // SST
         }
-        return $total_offset;
+        while (!empty($tmp_block_sizes)) {
+            $length += 4 + array_shift($tmp_block_sizes); // CONTINUEs
+        }
+
+        return $length;
     }
 
     /**
@@ -8266,28 +8712,41 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
     function _storeSharedStringsTable()
     {
         $record  = 0x00fc;  // Record identifier
-        // sizes are upside down
-        $this->_block_sizes = array_reverse($this->_block_sizes);
-        $length = array_pop($this->_block_sizes) + 8; // First block size plus SST information
-
-        // Write the SST block header information
-        $header      = pack("vv", $record, $length);
-        $data        = pack("VV", $this->_str_total, $this->_str_unique);
-        $this->_append($header . $data);
-
+        $length  = 0x0008;  // Number of bytes to follow
+        $total   = 0x0000;
 
         // Iterate through the strings to calculate the CONTINUE block sizes
-        $continue_limit = 8216;
+        $continue_limit = 8208;
         $block_length   = 0;
         $written        = 0;
         $continue       = 0;
 
+        // sizes are upside down
+        $tmp_block_sizes = $this->_block_sizes;
+        // $tmp_block_sizes = array_reverse($this->_block_sizes);
+
+        // The SST record is required even if it contains no strings. Thus we will
+        // always have a length
+        //
+        if (!empty($tmp_block_sizes)) {
+            $length = 8 + array_shift($tmp_block_sizes);
+        }
+        else {
+            // No strings
+            $length = 8;
+        }
+
+        // Write the SST block header information
+        $header      = pack("vv", $record, $length);
+        $data        = pack("VV", $this->_str_total, $this->_str_unique);
+        $this->_append($header . $data);
 
         /* TODO: not good for performance */
         foreach (array_keys($this->_str_table) as $string) {
 
             $string_length = strlen($string);
-            $encoding      = 0; // assume there are no Unicode strings
+            $headerinfo    = unpack("vlength/Cencoding", $string);
+            $encoding      = $headerinfo["encoding"];
             $split_string  = 0;
 
             // Block length is the total length of the strings that will be
@@ -8318,6 +8777,30 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
 
                 // Unicode data should only be split on char (2 byte) boundaries.
                 // Therefore, in some cases we need to reduce the amount of available
+                // space by 1 byte to ensure the correct alignment.
+                $align = 0;
+
+                // Only applies to Unicode strings
+                if ($encoding == 1) {
+                    // Min string + header size -1
+                    $header_length = 4;
+
+                    if ($space_remaining > $header_length) {
+                        // String contains 3 byte header => split on odd boundary
+                        if (!$split_string && $space_remaining % 2 != 1) {
+                            $space_remaining--;
+                            $align = 1;
+                        }
+                        // Split section without header => split on even boundary
+                        else if ($split_string && $space_remaining % 2 == 1) {
+                            $space_remaining--;
+                            $align = 1;
+                        }
+
+                        $split_string = 1;
+                    }
+                }
+
 
                 if ($space_remaining > $header_length) {
                     // Write as much as possible of the string in the current block
@@ -8328,7 +8811,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
                     $string = substr($string, $space_remaining);
 
                     // Reduce the current block length by the amount written
-                    $block_length -= $continue_limit - $continue;
+                    $block_length -= $continue_limit - $continue - $align;
 
                     // If the current string was split then the next CONTINUE block
                     // should have the string continue flag (grbit) set unless the
@@ -8348,7 +8831,8 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
                 // Write the CONTINUE block header
                 if (!empty($this->_block_sizes)) {
                     $record  = 0x003C;
-                    $length  = array_pop($this->_block_sizes);
+                    $length  = array_shift($tmp_block_sizes);
+
                     $header  = pack('vv', $record, $length);
                     if ($continue) {
                         $header .= pack('C', $encoding);
@@ -8370,4 +8854,3 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
         }
     }
 }
-?>