Code

Updated opacity
[gosa.git] / include / php_writeexcel / class.writeexcel_olewriter.inc.php
1 <?php
3 /*
4  * Copyleft 2002 Johann Hanne
5  *
6  * This is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this software; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place,
19  * Suite 330, Boston, MA  02111-1307 USA
20  */
22 /*
23  * This is the Spreadsheet::WriteExcel Perl package ported to PHP
24  * Spreadsheet::WriteExcel was written by John McNamara, jmcnamara@cpan.org
25  */
27 class writeexcel_olewriter {
28     var $_OLEfilename;
29     var $_OLEtmpfilename; /* ABR */
30     var $_filehandle;
31     var $_fileclosed;
32     var $_internal_fh;
33     var $_biff_only;
34     var $_size_allowed;
35     var $_biffsize;
36     var $_booksize;
37     var $_big_blocks;
38     var $_list_blocks;
39     var $_root_start;
40     var $_block_count;
42     /*
43      * Constructor
44      */
45     function writeexcel_olewriter($filename) {
47         $this->_OLEfilename  = $filename;
48         $this->_filehandle   = false;
49         $this->_fileclosed   = 0;
50         $this->_internal_fh  = 0;
51         $this->_biff_only    = 0;
52         $this->_size_allowed = 0;
53         $this->_biffsize     = 0;
54         $this->_booksize     = 0;
55         $this->_big_blocks   = 0;
56         $this->_list_blocks  = 0;
57         $this->_root_start   = 0;
58         $this->_block_count  = 4;
60         $this->_initialize();
61     }
63     /*
64      * Check for a valid filename and store the filehandle.
65      */
66     function _initialize() {
67         $OLEfile = $this->_OLEfilename;
69         /* Check for a filename. Workbook.pm will catch this first. */
70         if ($OLEfile == '') {
71             trigger_error("Filename required", E_USER_ERROR);
72         }
74         /*
75          * If the filename is a resource it is assumed that it is a valid
76          * filehandle, if not we create a filehandle.
77          */
78         if (is_resource($OLEfile)) {
79             $fh = $OLEfile;
80         } else {
81             // Create a new file, open for writing
82             $fh = fopen($OLEfile, "wb");
83             // The workbook class also checks this but something may have
84             // happened since then.
85             if (!$fh) {
86                 trigger_error("Can't open $OLEfile. It may be in use or ".
87                               "protected", E_USER_ERROR);
88             }
90             $this->_internal_fh = 1;
91         }
93         // Store filehandle
94         $this->_filehandle = $fh;
95     }
97     /*
98      * Set the size of the data to be written to the OLE stream
99      *
100      * $big_blocks = (109 depot block x (128 -1 marker word)
101      *               - (1 x end words)) = 13842
102      * $maxsize    = $big_blocks * 512 bytes = 7087104
103      */
104     function set_size($size) {
105         $maxsize = 7087104;
107         if ($size > $maxsize) {
108             trigger_error("Maximum file size, $maxsize, exceeded. To create ".
109                           "files bigger than this limit please use the ".
110                           "workbookbig class.", E_USER_ERROR);
111             return ($this->_size_allowed = 0);
112         }
114         $this->_biffsize = $size;
116         // Set the min file size to 4k to avoid having to use small blocks
117         if ($size > 4096) {
118             $this->_booksize = $size;
119         } else {
120             $this->_booksize = 4096;
121         }
123         return ($this->_size_allowed = 1);
124     }
126     /*
127      * Calculate various sizes needed for the OLE stream
128      */
129     function _calculate_sizes() {
130         $datasize = $this->_booksize;
132         if ($datasize % 512 == 0) {
133             $this->_big_blocks = $datasize/512;
134         } else {
135             $this->_big_blocks = floor($datasize/512)+1;
136         }
137         // There are 127 list blocks and 1 marker blocks for each big block
138         // depot + 1 end of chain block
139         $this->_list_blocks = floor(($this->_big_blocks)/127)+1;
140         $this->_root_start  = $this->_big_blocks;
142         //print $this->_biffsize.    "\n";
143         //print $this->_big_blocks.  "\n";
144         //print $this->_list_blocks. "\n";
145     }
147     /*
148      * Write root entry, big block list and close the filehandle.
149      * This method must be called so that the file contents are
150      * actually written.
151      */
152     function close() {
154         if (!$this->_size_allowed) {
155             return;
156         }
158         if (!$this->_biff_only) {
159             $this->_write_padding();
160             $this->_write_property_storage();
161             $this->_write_big_block_depot();
162         }
164         // Close the filehandle if it was created internally.
165         if ($this->_internal_fh) {
166             fclose($this->_filehandle);
167         }
168 /* ABR */
169         if ($this->_OLEtmpfilename != '') {
170             $fh = fopen($this->_OLEtmpfilename, "rb");
171             if ($fh == false) {
172                 trigger_error("Can't read temporary file.", E_USER_ERROR);
173             }
174             fpassthru($fh);
175             fclose($fh);
176             unlink($this->_OLEtmpfilename);
177         };
179         $this->_fileclosed = 1;
180     }
182     /*
183      * Write BIFF data to OLE file.
184      */
185     function write($data) {
186         fputs($this->_filehandle, $data);
187     }
189     /*
190      * Write OLE header block.
191      */
192     function write_header() {
193         if ($this->_biff_only) {
194             return;
195         }
197         $this->_calculate_sizes();
199         $root_start      = $this->_root_start;
200         $num_lists       = $this->_list_blocks;
202         $id              = pack("C8", 0xD0, 0xCF, 0x11, 0xE0,
203                                       0xA1, 0xB1, 0x1A, 0xE1);
204         $unknown1        = pack("VVVV", 0x00, 0x00, 0x00, 0x00);
205         $unknown2        = pack("vv",   0x3E, 0x03);
206         $unknown3        = pack("v",    -2);
207         $unknown4        = pack("v",    0x09);
208         $unknown5        = pack("VVV",  0x06, 0x00, 0x00);
209         $num_bbd_blocks  = pack("V",    $num_lists);
210         $root_startblock = pack("V",    $root_start);
211         $unknown6        = pack("VV",   0x00, 0x1000);
212         $sbd_startblock  = pack("V",    -2);
213         $unknown7        = pack("VVV",  0x00, -2 ,0x00);
214         $unused          = pack("V",    -1);
216         fputs($this->_filehandle, $id);
217         fputs($this->_filehandle, $unknown1);
218         fputs($this->_filehandle, $unknown2);
219         fputs($this->_filehandle, $unknown3);
220         fputs($this->_filehandle, $unknown4);
221         fputs($this->_filehandle, $unknown5);
222         fputs($this->_filehandle, $num_bbd_blocks);
223         fputs($this->_filehandle, $root_startblock);
224         fputs($this->_filehandle, $unknown6);
225         fputs($this->_filehandle, $sbd_startblock);
226         fputs($this->_filehandle, $unknown7);
228         for ($c=1;$c<=$num_lists;$c++) {
229             $root_start++;
230             fputs($this->_filehandle, pack("V", $root_start));
231         }
233         for ($c=$num_lists;$c<=108;$c++) {
234             fputs($this->_filehandle, $unused);
235         }
236     }
238     /*
239      * Write big block depot.
240      */
241     function _write_big_block_depot() {
242         $num_blocks   = $this->_big_blocks;
243         $num_lists    = $this->_list_blocks;
244         $total_blocks = $num_lists * 128;
245         $used_blocks  = $num_blocks + $num_lists + 2;
247         $marker       = pack("V", -3);
248         $end_of_chain = pack("V", -2);
249         $unused       = pack("V", -1);
251         for ($i=1;$i<=($num_blocks-1);$i++) {
252             fputs($this->_filehandle, pack("V", $i));
253         }
255         fputs($this->_filehandle, $end_of_chain);
256         fputs($this->_filehandle, $end_of_chain);
258         for ($c=1;$c<=$num_lists;$c++) {
259             fputs($this->_filehandle, $marker);
260         }
262         for ($c=$used_blocks;$c<=$total_blocks;$c++) {
263             fputs($this->_filehandle, $unused);
264         }
265     }
267     /*
268      * Write property storage. TODO: add summary sheets
269      */
270     function _write_property_storage() {
271         $rootsize = -2;
272         $booksize = $this->_booksize;
274         //                name          type  dir start  size
275         $this->_write_pps('Root Entry', 0x05,   1,   -2, 0x00);
276         $this->_write_pps('Book',       0x02,  -1, 0x00, $booksize);
277         $this->_write_pps('',           0x00,  -1, 0x00, 0x0000);
278         $this->_write_pps('',           0x00,  -1, 0x00, 0x0000);
279     }
281     /*
282      * Write property sheet in property storage
283      */
284     function _write_pps($name, $type, $dir, $start, $size) {
285         $names           = array();
286         $length          = 0;
288         if ($name != '') {
289             $name   = $name . "\0";
290             // Simulate a Unicode string
291             $chars=preg_split("''", $name, -1, PREG_SPLIT_NO_EMPTY);
292             foreach ($chars as $char) {
293                 array_push($names, ord($char));
294             }
295             $length = strlen($name) * 2;
296         }
298         $rawname         = call_user_func_array('pack', array_merge(array("v*"), $names));
299         $zero            = pack("C",  0);
301         $pps_sizeofname  = pack("v",  $length);   //0x40
302         $pps_type        = pack("v",  $type);     //0x42
303         $pps_prev        = pack("V",  -1);        //0x44
304         $pps_next        = pack("V",  -1);        //0x48
305         $pps_dir         = pack("V",  $dir);      //0x4c
307         $unknown1        = pack("V",  0);
309         $pps_ts1s        = pack("V",  0);         //0x64
310         $pps_ts1d        = pack("V",  0);         //0x68
311         $pps_ts2s        = pack("V",  0);         //0x6c
312         $pps_ts2d        = pack("V",  0);         //0x70
313         $pps_sb          = pack("V",  $start);    //0x74
314         $pps_size        = pack("V",  $size);     //0x78
316         fputs($this->_filehandle, $rawname);
317         fputs($this->_filehandle, str_repeat($zero, (64-$length)));
318         fputs($this->_filehandle, $pps_sizeofname);
319         fputs($this->_filehandle, $pps_type);
320         fputs($this->_filehandle, $pps_prev);
321         fputs($this->_filehandle, $pps_next);
322         fputs($this->_filehandle, $pps_dir);
323         fputs($this->_filehandle, str_repeat($unknown1, 5));
324         fputs($this->_filehandle, $pps_ts1s);
325         fputs($this->_filehandle, $pps_ts1d);
326         fputs($this->_filehandle, $pps_ts2d);
327         fputs($this->_filehandle, $pps_ts2d);
328         fputs($this->_filehandle, $pps_sb);
329         fputs($this->_filehandle, $pps_size);
330         fputs($this->_filehandle, $unknown1);
331     }
333     /*
334      * Pad the end of the file
335      */
336     function _write_padding() {
337         $biffsize = $this->_biffsize;
339         if ($biffsize < 4096) {
340             $min_size = 4096;
341         } else {
342             $min_size = 512;
343         }
345         if ($biffsize % $min_size != 0) {
346             $padding  = $min_size - ($biffsize % $min_size);
347             fputs($this->_filehandle, str_repeat("\0", $padding));
348         }
349     }
353 ?>