Subversion Repositories Applications.bazar

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
468 mathias 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)
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
?>