* * The majority of this is _NOT_ my code. I simply ported it from the * PERL Spreadsheet::WriteExcel module. * * The author of the Spreadsheet::WriteExcel module is John McNamara * * * I _DO_ maintain this code, and John McNamara has nothing to do with the * porting of this code to PHP. Any questions directly related to this * class library should be directed to me. * * License Information: * * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ require_once('PEAR.php'); /** * Class for creating OLE streams for Excel Spreadsheets * * @author Xavier Noguer * @category FileFormats * @package Spreadsheet_Excel_Writer */ class Spreadsheet_Excel_Writer_OLEwriter extends PEAR { /** * Filename for the OLE stream * @var string * @see _initialize() */ var $_OLEfilename; /** * Filehandle for the OLE stream * @var resource */ var $_filehandle; /** * Name of the temporal file in case OLE stream goes to stdout * @var string */ var $_tmp_filename; /** * Variable for preventing closing two times * @var integer */ var $_fileclosed; /** * Size of the data to be written to the OLE stream * @var integer */ var $_biffsize; /** * Real data size to be written to the OLE stream * @var integer */ var $_booksize; /** * Number of big blocks in the OLE stream * @var integer */ var $_big_blocks; /** * Number of list blocks in the OLE stream * @var integer */ var $_list_blocks; /** * Number of big blocks in the OLE stream * @var integer */ var $_root_start; /** * Constructor for the OLEwriter class * * @param string $OLEfilename the name of the file for the OLE stream */ function Spreadsheet_Excel_Writer_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(); } /** * Check for a valid filename and store the filehandle. * Filehandle "-" writes to STDOUT * * @access private */ function _initialize() { $OLEfile = $this->_OLEfilename; if(($OLEfile == '-') or ($OLEfile == '')) { $this->_tmp_filename = tempnam("/tmp", "OLEwriter"); $fh = fopen($this->_tmp_filename,"wb"); if ($fh == false) { $this->raiseError("Can't create temporary file."); } } else { // Create a new file, open for writing (in binmode) $fh = fopen($OLEfile,"wb"); if ($fh == false) { $this->raiseError("Can't open $OLEfile. It may be in use or protected."); } } // 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) { $this->raiseError("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); } /** * 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; } /** * 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) { $this->raiseError("Can't read temporary file."); } 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); } } /** * Write property storage. TODO: add summary sheets * * @access private */ function _writePropertyStorage() { //$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); } /** * 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"; for($i=0;$i_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); } /** * 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"); } } } } ?>