3 * Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
5 * The majority of this is _NOT_ my code. I simply ported it from the
6 * PERL Spreadsheet::WriteExcel module.
8 * The author of the Spreadsheet::WriteExcel module is John McNamara
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.
15 * License Information:
17 * Spreadsheet::WriteExcel: A library for generating Excel Spreadsheets
18 * Copyright (C) 2002 Xavier Noguer xnoguer@rezebra.com
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.
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.
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
36 * Class for creating OLE streams for Excel Spreadsheets
38 * @author Xavier Noguer <xnoguer@rezebra.com>
39 * @package Spreadsheet_WriteExcel
44 * Filename for the OLE stream
51 * Filehandle for the OLE stream
57 * Name of the temporal file in case OLE stream goes to stdout
63 * Variable for preventing closing two times
69 * Size of the data to be written to the OLE stream
75 * Real data size to be written to the OLE stream
81 * Number of big blocks in the OLE stream
87 * Number of list blocks in the OLE stream
93 * Number of big blocks in the OLE stream
99 * Class for creating an OLEwriter
101 * @param string $OLEfilename the name of the file for the OLE stream
103 function OLEwriter($OLEfilename)
105 $this->_OLEfilename
= $OLEfilename;
106 $this->_filehandle
= "";
107 $this->_tmp_filename
= "";
108 $this->_fileclosed
= 0;
109 //$this->_size_allowed = 0;
110 $this->_biffsize
= 0;
111 $this->_booksize
= 0;
112 $this->_big_blocks
= 0;
113 $this->_list_blocks
= 0;
114 $this->_root_start
= 0;
115 //$this->_block_count = 4;
116 $this->_initialize();
120 * Check for a valid filename and store the filehandle.
121 * Filehandle "-" writes to STDOUT
123 function _initialize()
125 $OLEfile = $this->_OLEfilename
;
127 if(($OLEfile == '-') or ($OLEfile == ''))
129 $this->_tmp_filename
= tempnam("/tmp", "OLEwriter");
130 $fh = fopen($this->_tmp_filename
,"wb");
132 die("Can't create temporary file.");
137 // Create a new file, open for writing (in binmode)
138 $fh = fopen($OLEfile,"wb");
140 die("Can't open $OLEfile. It may be in use or protected.");
145 $this->_filehandle
= $fh;
150 * Set the size of the data to be written to the OLE stream.
151 * The maximun size comes from this:
152 * $big_blocks = (109 depot block x (128 -1 marker word)
153 * - (1 x end words)) = 13842
154 * $maxsize = $big_blocks * 512 bytes = 7087104
157 * @see Workbook::store_OLE_file()
158 * @param integer $biffsize The size of the data to be written to the OLE stream
159 * @return integer 1 for success
161 function set_size($biffsize)
163 $maxsize = 7087104; // TODO: extend max size
165 if ($biffsize > $maxsize) {
166 die("Maximum file size, $maxsize, exceeded.");
169 $this->_biffsize
= $biffsize;
170 // Set the min file size to 4k to avoid having to use small blocks
171 if ($biffsize > 4096) {
172 $this->_booksize
= $biffsize;
175 $this->_booksize
= 4096;
177 //$this->_size_allowed = 1;
183 * Calculate various sizes needed for the OLE stream
185 function _calculate_sizes()
187 $datasize = $this->_booksize
;
188 if ($datasize %
512 == 0) {
189 $this->_big_blocks
= $datasize/512;
192 $this->_big_blocks
= floor($datasize/512) +
1;
194 // There are 127 list blocks and 1 marker blocks for each big block
195 // depot + 1 end of chain block
196 $this->_list_blocks
= floor(($this->_big_blocks
)/127) +
1;
197 $this->_root_start
= $this->_big_blocks
;
201 * Write root entry, big block list and close the filehandle.
202 * This routine is used to explicitly close the open filehandle without
203 * having to wait for DESTROY.
206 * @see Workbook::store_OLE_file()
210 //return if not $this->{_size_allowed};
211 $this->_write_padding();
212 $this->_write_property_storage();
213 $this->_write_big_block_depot();
214 // Close the filehandle
215 fclose($this->_filehandle
);
216 if(($this->_OLEfilename
== '-') or ($this->_OLEfilename
== ''))
218 $fh = fopen($this->_tmp_filename
, "rb");
220 die("Can't read temporary file.");
223 // Delete the temporary file.
224 @unlink
($this->_tmp_filename
);
226 $this->_fileclosed
= 1;
231 * Write BIFF data to OLE file.
233 * @param string $data string of bytes to be written
235 function write($data) //por ahora sólo a STDOUT
237 fwrite($this->_filehandle
,$data,strlen($data));
242 * Write OLE header block.
244 function write_header()
246 $this->_calculate_sizes();
247 $root_start = $this->_root_start
;
248 $num_lists = $this->_list_blocks
;
249 $id = pack("nnnn", 0xD0CF, 0x11E0, 0xA1B1, 0x1AE1);
250 $unknown1 = pack("VVVV", 0x00, 0x00, 0x00, 0x00);
251 $unknown2 = pack("vv", 0x3E, 0x03);
252 $unknown3 = pack("v", -2);
253 $unknown4 = pack("v", 0x09);
254 $unknown5 = pack("VVV", 0x06, 0x00, 0x00);
255 $num_bbd_blocks = pack("V", $num_lists);
256 $root_startblock = pack("V", $root_start);
257 $unknown6 = pack("VV", 0x00, 0x1000);
258 $sbd_startblock = pack("V", -2);
259 $unknown7 = pack("VVV", 0x00, -2 ,0x00);
260 $unused = pack("V", -1);
262 fwrite($this->_filehandle
,$id);
263 fwrite($this->_filehandle
,$unknown1);
264 fwrite($this->_filehandle
,$unknown2);
265 fwrite($this->_filehandle
,$unknown3);
266 fwrite($this->_filehandle
,$unknown4);
267 fwrite($this->_filehandle
,$unknown5);
268 fwrite($this->_filehandle
,$num_bbd_blocks);
269 fwrite($this->_filehandle
,$root_startblock);
270 fwrite($this->_filehandle
,$unknown6);
271 fwrite($this->_filehandle
,$sbd_startblock);
272 fwrite($this->_filehandle
,$unknown7);
274 for($i=1; $i <= $num_lists; $i++
)
277 fwrite($this->_filehandle
,pack("V",$root_start));
279 for($i = $num_lists; $i <=108; $i++
)
281 fwrite($this->_filehandle
,$unused);
287 * Write big block depot.
289 function _write_big_block_depot()
291 $num_blocks = $this->_big_blocks
;
292 $num_lists = $this->_list_blocks
;
293 $total_blocks = $num_lists *128;
294 $used_blocks = $num_blocks +
$num_lists +
2;
296 $marker = pack("V", -3);
297 $end_of_chain = pack("V", -2);
298 $unused = pack("V", -1);
300 for($i=1; $i < $num_blocks; $i++
)
302 fwrite($this->_filehandle
,pack("V",$i));
304 fwrite($this->_filehandle
,$end_of_chain);
305 fwrite($this->_filehandle
,$end_of_chain);
306 for($i=0; $i < $num_lists; $i++
)
308 fwrite($this->_filehandle
,$marker);
310 for($i=$used_blocks; $i <= $total_blocks; $i++
)
312 fwrite($this->_filehandle
,$unused);
317 * Write property storage. TODO: add summary sheets
319 function _write_property_storage()
322 /*************** name type dir start size */
323 $this->_write_pps("Root Entry", 0x05, 1, -2, 0x00);
324 $this->_write_pps("Book", 0x02, -1, 0x00, $this->_booksize
);
325 $this->_write_pps('', 0x00, -1, 0x00, 0x0000);
326 $this->_write_pps('', 0x00, -1, 0x00, 0x0000);
330 * Write property sheet in property storage
332 * @param string $name name of the property storage.
333 * @param integer $type type of the property storage.
334 * @param integer $dir dir of the property storage.
335 * @param integer $start start of the property storage.
336 * @param integer $size size of the property storage.
339 function _write_pps($name,$type,$dir,$start,$size)
346 $name = $name . "\0";
347 for($i=0;$i<strlen($name);$i++
)
349 // Simulate a Unicode string
350 $rawname .= pack("H*",dechex(ord($name{$i}))).pack("C",0);
352 $length = strlen($name) * 2;
355 $zero = pack("C", 0);
356 $pps_sizeofname = pack("v", $length); // 0x40
357 $pps_type = pack("v", $type); // 0x42
358 $pps_prev = pack("V", -1); // 0x44
359 $pps_next = pack("V", -1); // 0x48
360 $pps_dir = pack("V", $dir); // 0x4c
362 $unknown1 = pack("V", 0);
364 $pps_ts1s = pack("V", 0); // 0x64
365 $pps_ts1d = pack("V", 0); // 0x68
366 $pps_ts2s = pack("V", 0); // 0x6c
367 $pps_ts2d = pack("V", 0); // 0x70
368 $pps_sb = pack("V", $start); // 0x74
369 $pps_size = pack("V", $size); // 0x78
372 fwrite($this->_filehandle
,$rawname);
373 for($i=0; $i < (64 -$length); $i++
) {
374 fwrite($this->_filehandle
,$zero);
376 fwrite($this->_filehandle
,$pps_sizeofname);
377 fwrite($this->_filehandle
,$pps_type);
378 fwrite($this->_filehandle
,$pps_prev);
379 fwrite($this->_filehandle
,$pps_next);
380 fwrite($this->_filehandle
,$pps_dir);
381 for($i=0; $i < 5; $i++
) {
382 fwrite($this->_filehandle
,$unknown1);
384 fwrite($this->_filehandle
,$pps_ts1s);
385 fwrite($this->_filehandle
,$pps_ts1d);
386 fwrite($this->_filehandle
,$pps_ts2d);
387 fwrite($this->_filehandle
,$pps_ts2d);
388 fwrite($this->_filehandle
,$pps_sb);
389 fwrite($this->_filehandle
,$pps_size);
390 fwrite($this->_filehandle
,$unknown1);
394 * Pad the end of the file
396 function _write_padding()
398 $biffsize = $this->_biffsize
;
399 if ($biffsize < 4096) {
405 if ($biffsize %
$min_size != 0)
407 $padding = $min_size - ($biffsize %
$min_size);
408 for($i=0; $i < $padding; $i++
) {
409 fwrite($this->_filehandle
,"\0");