~desarrollokumbia/kumbia/0.5

« back to all changes in this revision

Viewing changes to library/excel/writer/BIFFwriter.php

  • Committer: Joan Miquel
  • Date: 2008-11-07 01:12:54 UTC
  • Revision ID: joan@ubuntu-black-20081107011254-lc0jk82y3yg7jvpl
commit inicial para kumbia 0.5 RC1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/*
 
3
*  Module written/ported by Xavier Noguer <xnoguer@php.net>
 
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@php.net
 
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
/**
 
36
* Class for writing Excel BIFF records.
 
37
*
 
38
* From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation):
 
39
*
 
40
* BIFF (BInary File Format) is the file format in which Excel documents are
 
41
* saved on disk.  A BIFF file is a complete description of an Excel document.
 
42
* BIFF files consist of sequences of variable-length records. There are many
 
43
* different types of BIFF records.  For example, one record type describes a
 
44
* formula entered into a cell; one describes the size and location of a
 
45
* window into a document; another describes a picture format.
 
46
*
 
47
* @author   Xavier Noguer <xnoguer@php.net>
 
48
* @category FileFormats
 
49
* @package  Spreadsheet_Excel_Writer
 
50
*/
 
51
 
 
52
class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR
 
53
{
 
54
    /**
 
55
    * The BIFF/Excel version (5).
 
56
    * @var integer
 
57
    */
 
58
    var $_BIFF_version = 0x0500;
 
59
 
 
60
    /**
 
61
    * The byte order of this architecture. 0 => little endian, 1 => big endian
 
62
    * @var integer
 
63
    */
 
64
    var $_byte_order;
 
65
 
 
66
    /**
 
67
    * The string containing the data of the BIFF stream
 
68
    * @var string
 
69
    */
 
70
    var $_data;
 
71
 
 
72
    /**
 
73
    * The size of the data in bytes. Should be the same as strlen($this->_data)
 
74
    * @var integer
 
75
    */
 
76
    var $_datasize;
 
77
 
 
78
    /**
 
79
    * The maximun length for a BIFF record. See _addContinue()
 
80
    * @var integer
 
81
    * @see _addContinue()
 
82
    */
 
83
    var $_limit;
 
84
 
 
85
    /**
 
86
    * Constructor
 
87
    *
 
88
    * @access public
 
89
    */
 
90
    function Spreadsheet_Excel_Writer_BIFFwriter()
 
91
    {
 
92
        $this->_byte_order = '';
 
93
        $this->_data       = '';
 
94
        $this->_datasize   = 0;
 
95
        $this->_limit      = 2080;
 
96
        // Set the byte order
 
97
        $this->_setByteOrder();
 
98
    }
 
99
 
 
100
    /**
 
101
    * Determine the byte order and store it as class data to avoid
 
102
    * recalculating it for each call to new().
 
103
    *
 
104
    * @access private
 
105
    */
 
106
    function _setByteOrder()
 
107
    {
 
108
        // Check if "pack" gives the required IEEE 64bit float
 
109
        $teststr = pack("d", 1.2345);
 
110
        $number  = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
 
111
        if ($number == $teststr) {
 
112
            $byte_order = 0;    // Little Endian
 
113
        } elseif ($number == strrev($teststr)){
 
114
            $byte_order = 1;    // Big Endian
 
115
        } else {
 
116
            // Give up. I'll fix this in a later version.
 
117
            return $this->raiseError("Required floating point format ".
 
118
                                     "not supported on this platform.");
 
119
        }
 
120
        $this->_byte_order = $byte_order;
 
121
    }
 
122
 
 
123
    /**
 
124
    * General storage function
 
125
    *
 
126
    * @param string $data binary data to prepend
 
127
    * @access private
 
128
    */
 
129
    function _prepend($data)
 
130
    {
 
131
        if (strlen($data) > $this->_limit) {
 
132
            $data = $this->_addContinue($data);
 
133
        }
 
134
        $this->_data      = $data.$this->_data;
 
135
        $this->_datasize += strlen($data);
 
136
    }
 
137
 
 
138
    /**
 
139
    * General storage function
 
140
    *
 
141
    * @param string $data binary data to append
 
142
    * @access private
 
143
    */
 
144
    function _append($data)
 
145
    {
 
146
        if (strlen($data) > $this->_limit) {
 
147
            $data = $this->_addContinue($data);
 
148
        }
 
149
        $this->_data      = $this->_data.$data;
 
150
        $this->_datasize += strlen($data);
 
151
    }
 
152
 
 
153
    /**
 
154
    * Writes Excel BOF record to indicate the beginning of a stream or
 
155
    * sub-stream in the BIFF file.
 
156
    *
 
157
    * @param  integer $type Type of BIFF file to write: 0x0005 Workbook,
 
158
    *                       0x0010 Worksheet.
 
159
    * @access private
 
160
    */
 
161
    function _storeBof($type)
 
162
    {
 
163
        $record  = 0x0809;        // Record identifier
 
164
 
 
165
        // According to the SDK $build and $year should be set to zero.
 
166
        // However, this throws a warning in Excel 5. So, use magic numbers.
 
167
        if ($this->_BIFF_version == 0x0500) {
 
168
            $length  = 0x0008;
 
169
            $unknown = '';
 
170
            $build   = 0x096C;
 
171
            $year    = 0x07C9;
 
172
        } elseif ($this->_BIFF_version == 0x0600) {
 
173
            $length  = 0x0010;
 
174
            $unknown = pack("VV", 0x00000041, 0x00000006); //unknown last 8 bytes for BIFF8
 
175
            $build   = 0x0DBB;
 
176
            $year    = 0x07CC;
 
177
        }
 
178
        $version = $this->_BIFF_version;
 
179
 
 
180
        $header  = pack("vv",   $record, $length);
 
181
        $data    = pack("vvvv", $version, $type, $build, $year);
 
182
        $this->_prepend($header . $data . $unknown);
 
183
    }
 
184
 
 
185
    /**
 
186
    * Writes Excel EOF record to indicate the end of a BIFF stream.
 
187
    *
 
188
    * @access private
 
189
    */
 
190
    function _storeEof()
 
191
    {
 
192
        $record    = 0x000A;   // Record identifier
 
193
        $length    = 0x0000;   // Number of bytes to follow
 
194
        $header    = pack("vv", $record, $length);
 
195
        $this->_append($header);
 
196
    }
 
197
 
 
198
    /**
 
199
    * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
 
200
    * Excel 97 the limit is 8228 bytes. Records that are longer than these limits
 
201
    * must be split up into CONTINUE blocks.
 
202
    *
 
203
    * This function takes a long BIFF record and inserts CONTINUE records as
 
204
    * necessary.
 
205
    *
 
206
    * @param  string  $data The original binary data to be written
 
207
    * @return string        A very convenient string of continue blocks
 
208
    * @access private
 
209
    */
 
210
    function _addContinue($data)
 
211
    {
 
212
        $limit  = $this->_limit;
 
213
        $record = 0x003C;         // Record identifier
 
214
 
 
215
        // The first 2080/8224 bytes remain intact. However, we have to change
 
216
        // the length field of the record.
 
217
        $tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4);
 
218
 
 
219
        $header = pack("vv", $record, $limit);  // Headers for continue records
 
220
 
 
221
        // Retrieve chunks of 2080/8224 bytes +4 for the header.
 
222
        $data_length = strlen($data);
 
223
        for ($i = $limit; $i <  ($data_length - $limit); $i += $limit) {
 
224
            $tmp .= $header;
 
225
            $tmp .= substr($data, $i, $limit);
 
226
        }
 
227
 
 
228
        // Retrieve the last chunk of data
 
229
        $header  = pack("vv", $record, strlen($data) - $i);
 
230
        $tmp    .= $header;
 
231
        $tmp    .= substr($data, $i, strlen($data) - $i);
 
232
 
 
233
        return $tmp;
 
234
    }
 
235
}
 
236
?>