home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / OLEwriter.php < prev    next >
Encoding:
PHP Script  |  2003-03-17  |  12.9 KB  |  429 lines

  1. <?php
  2. /*
  3. *  Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
  4. *
  5. *  The majority of this is _NOT_ my code.  I simply ported it from the
  6. *  PERL Spreadsheet::WriteExcel module.
  7. *
  8. *  The author of the Spreadsheet::WriteExcel module is John McNamara 
  9. *  <jmcnamara@cpan.org>
  10. *
  11. *  I _DO_ maintain this code, and John McNamara has nothing to do with the
  12. *  porting of this code to PHP.  Any questions directly related to this
  13. *  class library should be directed to me.
  14. *
  15. *  License Information:
  16. *
  17. *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
  18. *    Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
  19. *
  20. *    This library is free software; you can redistribute it and/or
  21. *    modify it under the terms of the GNU Lesser General Public
  22. *    License as published by the Free Software Foundation; either
  23. *    version 2.1 of the License, or (at your option) any later version.
  24. *
  25. *    This library is distributed in the hope that it will be useful,
  26. *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  28. *    Lesser General Public License for more details.
  29. *
  30. *    You should have received a copy of the GNU Lesser General Public
  31. *    License along with this library; if not, write to the Free Software
  32. *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  33. */
  34.  
  35. require_once('PEAR.php');
  36.  
  37. /**
  38. * Class for creating OLE streams for Excel Spreadsheets
  39. *
  40. * @author   Xavier Noguer <xnoguer@rezebra.com>
  41. * @category FileFormats
  42. * @package  Spreadsheet_Excel_Writer
  43. */
  44.  
  45. class Spreadsheet_Excel_Writer_OLEwriter extends PEAR
  46. {
  47.     /**
  48.     * Filename for the OLE stream
  49.     * @var string
  50.     * @see _initialize()
  51.     */
  52.     var $_OLEfilename;
  53.  
  54.     /**
  55.     * Filehandle for the OLE stream
  56.     * @var resource
  57.     */
  58.     var $_filehandle;
  59.  
  60.     /**
  61.     * Name of the temporal file in case OLE stream goes to stdout
  62.     * @var string
  63.     */
  64.     var $_tmp_filename;
  65.  
  66.     /**
  67.     * Variable for preventing closing two times
  68.     * @var integer
  69.     */
  70.     var $_fileclosed;
  71.  
  72.     /**
  73.     * Size of the data to be written to the OLE stream
  74.     * @var integer
  75.     */
  76.     var $_biffsize;
  77.  
  78.     /**
  79.     * Real data size to be written to the OLE stream
  80.     * @var integer
  81.     */
  82.     var $_booksize;
  83.  
  84.     /**
  85.     * Number of big blocks in the OLE stream
  86.     * @var integer
  87.     */
  88.     var $_big_blocks;
  89.  
  90.     /**
  91.     * Number of list blocks in the OLE stream
  92.     * @var integer
  93.     */
  94.     var $_list_blocks;
  95.  
  96.     /**
  97.     * Number of big blocks in the OLE stream
  98.     * @var integer
  99.     */
  100.     var $_root_start;
  101.  
  102.     /**
  103.     * Constructor for the OLEwriter class
  104.     *
  105.     * @param string $OLEfilename the name of the file for the OLE stream
  106.     */
  107.     function Spreadsheet_Excel_Writer_OLEwriter($OLEfilename)
  108.     {
  109.         $this->_OLEfilename  = $OLEfilename;
  110.         $this->_filehandle   = "";
  111.         $this->_tmp_filename = "";
  112.         $this->_fileclosed   = 0;
  113.         $this->_biff_only    = 0;
  114.         //$this->_size_allowed = 0;
  115.         $this->_biffsize     = 0;
  116.         $this->_booksize     = 0;
  117.         $this->_big_blocks   = 0;
  118.         $this->_list_blocks  = 0;
  119.         $this->_root_start   = 0;
  120.         //$this->_block_count  = 4;
  121.         $this->_initialize();
  122.     }
  123.  
  124.     /**
  125.     * Check for a valid filename and store the filehandle.
  126.     * Filehandle "-" writes to STDOUT
  127.     *
  128.     * @access private
  129.     */
  130.     function _initialize()
  131.     {
  132.         $OLEfile = $this->_OLEfilename;
  133.  
  134.         if(($OLEfile == '-') or ($OLEfile == ''))
  135.         {
  136.             $this->_tmp_filename = tempnam("/tmp", "OLEwriter");
  137.             $fh = fopen($this->_tmp_filename,"wb");
  138.             if ($fh == false) {
  139.                 $this->raiseError("Can't create temporary file.");
  140.             }
  141.         }
  142.         else
  143.         {
  144.             // Create a new file, open for writing (in binmode)
  145.             $fh = fopen($OLEfile,"wb");
  146.             if ($fh == false) {
  147.                 $this->raiseError("Can't open $OLEfile. It may be in use or protected.");
  148.             }
  149.         }
  150.  
  151.         // Store filehandle
  152.         $this->_filehandle = $fh;
  153.     }
  154.  
  155.  
  156.     /**
  157.     * Set the size of the data to be written to the OLE stream.
  158.     * The maximun size comes from this:
  159.     *   $big_blocks = (109 depot block x (128 -1 marker word)
  160.     *                 - (1 x end words)) = 13842
  161.     *   $maxsize    = $big_blocks * 512 bytes = 7087104
  162.     *
  163.     * @access public
  164.     * @see Spreadsheet_Excel_Writer_Workbook::store_OLE_file()
  165.     * @param integer $biffsize The size of the data to be written to the OLE stream
  166.     * @return integer 1 for success
  167.     */
  168.     function setSize($biffsize)
  169.     {
  170.         $maxsize = 7087104; // TODO: extend max size
  171.  
  172.         if ($biffsize > $maxsize) {
  173.             $this->raiseError("Maximum file size, $maxsize, exceeded.");
  174.         }
  175.  
  176.         $this->_biffsize = $biffsize;
  177.         // Set the min file size to 4k to avoid having to use small blocks
  178.         if ($biffsize > 4096) {
  179.             $this->_booksize = $biffsize;
  180.         }
  181.         else {
  182.             $this->_booksize = 4096;
  183.         }
  184.         //$this->_size_allowed = 1;
  185.         return(1);
  186.     }
  187.  
  188.  
  189.     /**
  190.     * Calculate various sizes needed for the OLE stream
  191.     *
  192.     * @access private
  193.     */
  194.     function _calculateSizes()
  195.     {
  196.         $datasize = $this->_booksize;
  197.         if ($datasize % 512 == 0) {
  198.             $this->_big_blocks = $datasize/512;
  199.         }
  200.         else {
  201.             $this->_big_blocks = floor($datasize/512) + 1;
  202.         }
  203.         // There are 127 list blocks and 1 marker blocks for each big block
  204.         // depot + 1 end of chain block
  205.         $this->_list_blocks = floor(($this->_big_blocks)/127) + 1;
  206.         $this->_root_start  = $this->_big_blocks;
  207.     }
  208.  
  209.     /**
  210.     * Write root entry, big block list and close the filehandle.
  211.     * This routine is used to explicitly close the open filehandle without
  212.     * having to wait for DESTROY.
  213.     *
  214.     * @access public
  215.     * @see Spreadsheet_Excel_Writer_Workbook::store_OLE_file()
  216.     */
  217.     function close() 
  218.     {
  219.         //return if not $this->{_size_allowed};
  220.         $this->_writePadding();
  221.         $this->_writePropertyStorage();
  222.         $this->_writeBigBlockDepot();
  223.         // Close the filehandle 
  224.         fclose($this->_filehandle);
  225.         if(($this->_OLEfilename == '-') or ($this->_OLEfilename == ''))
  226.         {
  227.             $fh = fopen($this->_tmp_filename, "rb");
  228.             if ($fh == false) {
  229.                 $this->raiseError("Can't read temporary file.");
  230.             }
  231.             fpassthru($fh);
  232.             @unlink($this->_tmp_filename);
  233.         }
  234.         $this->_fileclosed = 1;
  235.     }
  236.  
  237.  
  238.     /**
  239.     * Write BIFF data to OLE file.
  240.     *
  241.     * @param string $data string of bytes to be written
  242.     */
  243.     function write($data) //por ahora s≤lo a STDOUT
  244.     {
  245.         fwrite($this->_filehandle,$data,strlen($data));
  246.     }
  247.  
  248.  
  249.     /**
  250.     * Write OLE header block.
  251.     */
  252.     function writeHeader()
  253.     {
  254.         $this->_calculateSizes();
  255.         $root_start      = $this->_root_start;
  256.         $num_lists       = $this->_list_blocks;
  257.         $id              = pack("nnnn", 0xD0CF, 0x11E0, 0xA1B1, 0x1AE1);
  258.         $unknown1        = pack("VVVV", 0x00, 0x00, 0x00, 0x00);
  259.         $unknown2        = pack("vv",   0x3E, 0x03);
  260.         $unknown3        = pack("v",    -2);
  261.         $unknown4        = pack("v",    0x09);
  262.         $unknown5        = pack("VVV",  0x06, 0x00, 0x00);
  263.         $num_bbd_blocks  = pack("V",    $num_lists);
  264.         $root_startblock = pack("V",    $root_start);
  265.         $unknown6        = pack("VV",   0x00, 0x1000);
  266.         $sbd_startblock  = pack("V",    -2);
  267.         $unknown7        = pack("VVV",  0x00, -2 ,0x00);
  268.         $unused          = pack("V",    -1);
  269.  
  270.         fwrite($this->_filehandle,$id);
  271.         fwrite($this->_filehandle,$unknown1);
  272.         fwrite($this->_filehandle,$unknown2);
  273.         fwrite($this->_filehandle,$unknown3);
  274.         fwrite($this->_filehandle,$unknown4);
  275.         fwrite($this->_filehandle,$unknown5);
  276.         fwrite($this->_filehandle,$num_bbd_blocks);
  277.         fwrite($this->_filehandle,$root_startblock);
  278.         fwrite($this->_filehandle,$unknown6);
  279.         fwrite($this->_filehandle,$sbd_startblock);
  280.         fwrite($this->_filehandle,$unknown7);
  281.  
  282.         for($i=1; $i <= $num_lists; $i++)
  283.         {
  284.             $root_start++;
  285.             fwrite($this->_filehandle,pack("V",$root_start));
  286.         }
  287.         for($i = $num_lists; $i <=108; $i++)
  288.         {
  289.             fwrite($this->_filehandle,$unused);
  290.         }
  291.     }
  292.  
  293.  
  294.     /**
  295.     * Write big block depot.
  296.     *
  297.     * @access private
  298.     */
  299.     function _writeBigBlockDepot()
  300.     {
  301.         $num_blocks   = $this->_big_blocks;
  302.         $num_lists    = $this->_list_blocks;
  303.         $total_blocks = $num_lists *128;
  304.         $used_blocks  = $num_blocks + $num_lists +2;
  305.  
  306.         $marker       = pack("V", -3);
  307.         $end_of_chain = pack("V", -2);
  308.         $unused       = pack("V", -1);
  309.  
  310.         for($i=1; $i < $num_blocks; $i++)
  311.         {
  312.             fwrite($this->_filehandle,pack("V",$i));
  313.         }
  314.         fwrite($this->_filehandle,$end_of_chain);
  315.         fwrite($this->_filehandle,$end_of_chain);
  316.         for($i=0; $i < $num_lists; $i++)
  317.         {
  318.             fwrite($this->_filehandle,$marker);
  319.         }
  320.         for($i=$used_blocks; $i <= $total_blocks; $i++)
  321.         {
  322.             fwrite($this->_filehandle,$unused);
  323.         }
  324.     }
  325.  
  326.     /**
  327.     * Write property storage. TODO: add summary sheets
  328.     *
  329.     * @access private
  330.     */
  331.     function _writePropertyStorage()
  332.     {
  333.         //$rootsize = -2;
  334.         /***************  name         type   dir start size */
  335.         $this->_writePps("Root Entry", 0x05,   1,   -2, 0x00);
  336.         $this->_writePps("Book",       0x02,  -1, 0x00, $this->_booksize);
  337.         $this->_writePps('',           0x00,  -1, 0x00, 0x0000);
  338.         $this->_writePps('',           0x00,  -1, 0x00, 0x0000);
  339.     }
  340.  
  341. /**
  342. * Write property sheet in property storage
  343. *
  344. * @param string  $name  name of the property storage.
  345. * @param integer $type  type of the property storage.
  346. * @param integer $dir   dir of the property storage.
  347. * @param integer $start start of the property storage.
  348. * @param integer $size  size of the property storage.
  349. * @access private
  350. */
  351.     function _writePps($name,$type,$dir,$start,$size)
  352.     {
  353.         $length  = 0;
  354.         $rawname = '';
  355.  
  356.         if ($name != '')
  357.         {
  358.             $name = $name . "\0";
  359.             for($i=0;$i<strlen($name);$i++)
  360.             {
  361.                 // Simulate a Unicode string
  362.                 $rawname .= pack("H*",dechex(ord($name{$i}))).pack("C",0);
  363.             }
  364.             $length = strlen($name) * 2;
  365.         }
  366.        
  367.         $zero            = pack("C",  0);
  368.         $pps_sizeofname  = pack("v",  $length);    // 0x40
  369.         $pps_type        = pack("v",  $type);      // 0x42
  370.         $pps_prev        = pack("V",  -1);         // 0x44
  371.         $pps_next        = pack("V",  -1);         // 0x48
  372.         $pps_dir         = pack("V",  $dir);       // 0x4c
  373.        
  374.         $unknown1        = pack("V",  0);
  375.        
  376.         $pps_ts1s        = pack("V",  0);          // 0x64
  377.         $pps_ts1d        = pack("V",  0);          // 0x68
  378.         $pps_ts2s        = pack("V",  0);          // 0x6c
  379.         $pps_ts2d        = pack("V",  0);          // 0x70
  380.         $pps_sb          = pack("V",  $start);     // 0x74
  381.         $pps_size        = pack("V",  $size);      // 0x78
  382.        
  383.        
  384.         fwrite($this->_filehandle,$rawname);
  385.         for($i=0; $i < (64 -$length); $i++) {
  386.             fwrite($this->_filehandle,$zero);
  387.         }
  388.         fwrite($this->_filehandle,$pps_sizeofname);
  389.         fwrite($this->_filehandle,$pps_type);
  390.         fwrite($this->_filehandle,$pps_prev);
  391.         fwrite($this->_filehandle,$pps_next);
  392.         fwrite($this->_filehandle,$pps_dir);
  393.         for($i=0; $i < 5; $i++) {
  394.             fwrite($this->_filehandle,$unknown1);
  395.         }
  396.         fwrite($this->_filehandle,$pps_ts1s);
  397.         fwrite($this->_filehandle,$pps_ts1d);
  398.         fwrite($this->_filehandle,$pps_ts2d);
  399.         fwrite($this->_filehandle,$pps_ts2d);
  400.         fwrite($this->_filehandle,$pps_sb);
  401.         fwrite($this->_filehandle,$pps_size);
  402.         fwrite($this->_filehandle,$unknown1);
  403.     }
  404.  
  405.     /**
  406.     * Pad the end of the file
  407.     *
  408.     * @access private
  409.     */
  410.     function _writePadding()
  411.     {
  412.         $biffsize = $this->_biffsize;
  413.         if ($biffsize < 4096) {
  414.         $min_size = 4096;
  415.         }
  416.     else {    
  417.             $min_size = 512;
  418.         }
  419.     if ($biffsize % $min_size != 0)
  420.         {
  421.             $padding  = $min_size - ($biffsize % $min_size);
  422.             for($i=0; $i < $padding; $i++) {
  423.                 fwrite($this->_filehandle,"\0");
  424.             }
  425.         }
  426.     }
  427. }
  428. ?>
  429.