1: <?php
2: /**
3: * PHPExcel
4: *
5: * Copyright (c) 2006 - 2014 PHPExcel
6: *
7: * This library is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU Lesser General Public
9: * License as published by the Free Software Foundation; either
10: * version 2.1 of the License, or (at your option) any later version.
11: *
12: * This library is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * Lesser General Public License for more details.
16: *
17: * You should have received a copy of the GNU Lesser General Public
18: * License along with this library; if not, write to the Free Software
19: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20: *
21: * @category PHPExcel
22: * @package PHPExcel_Writer_Excel5
23: * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24: * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25: * @version 1.8.0, 2014-03-02
26: */
27:
28: // Original file header of PEAR::Spreadsheet_Excel_Writer_BIFFwriter (used as the base for this class):
29: // -----------------------------------------------------------------------------------------
30: // * Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
31: // *
32: // * The majority of this is _NOT_ my code. I simply ported it from the
33: // * PERL Spreadsheet::WriteExcel module.
34: // *
35: // * The author of the Spreadsheet::WriteExcel module is John McNamara
36: // * <jmcnamara@cpan.org>
37: // *
38: // * I _DO_ maintain this code, and John McNamara has nothing to do with the
39: // * porting of this code to PHP. Any questions directly related to this
40: // * class library should be directed to me.
41: // *
42: // * License Information:
43: // *
44: // * Spreadsheet_Excel_Writer: A library for generating Excel Spreadsheets
45: // * Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
46: // *
47: // * This library is free software; you can redistribute it and/or
48: // * modify it under the terms of the GNU Lesser General Public
49: // * License as published by the Free Software Foundation; either
50: // * version 2.1 of the License, or (at your option) any later version.
51: // *
52: // * This library is distributed in the hope that it will be useful,
53: // * but WITHOUT ANY WARRANTY; without even the implied warranty of
54: // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
55: // * Lesser General Public License for more details.
56: // *
57: // * You should have received a copy of the GNU Lesser General Public
58: // * License along with this library; if not, write to the Free Software
59: // * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
60: // */
61:
62:
63: /**
64: * PHPExcel_Writer_Excel5_BIFFwriter
65: *
66: * @category PHPExcel
67: * @package PHPExcel_Writer_Excel5
68: * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
69: */
70: class PHPExcel_Writer_Excel5_BIFFwriter
71: {
72: /**
73: * The byte order of this architecture. 0 => little endian, 1 => big endian
74: * @var integer
75: */
76: private static $_byte_order;
77:
78: /**
79: * The string containing the data of the BIFF stream
80: * @var string
81: */
82: public $_data;
83:
84: /**
85: * The size of the data in bytes. Should be the same as strlen($this->_data)
86: * @var integer
87: */
88: public $_datasize;
89:
90: /**
91: * The maximum length for a BIFF record (excluding record header and length field). See _addContinue()
92: * @var integer
93: * @see _addContinue()
94: */
95: public $_limit = 8224;
96:
97: /**
98: * Constructor
99: */
100: public function __construct()
101: {
102: $this->_data = '';
103: $this->_datasize = 0;
104: // $this->_limit = 8224;
105: }
106:
107: /**
108: * Determine the byte order and store it as class data to avoid
109: * recalculating it for each call to new().
110: *
111: * @return int
112: */
113: public static function getByteOrder()
114: {
115: if (!isset(self::$_byte_order)) {
116: // Check if "pack" gives the required IEEE 64bit float
117: $teststr = pack("d", 1.2345);
118: $number = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
119: if ($number == $teststr) {
120: $byte_order = 0; // Little Endian
121: } elseif ($number == strrev($teststr)){
122: $byte_order = 1; // Big Endian
123: } else {
124: // Give up. I'll fix this in a later version.
125: throw new PHPExcel_Writer_Exception("Required floating point format not supported on this platform.");
126: }
127: self::$_byte_order = $byte_order;
128: }
129:
130: return self::$_byte_order;
131: }
132:
133: /**
134: * General storage function
135: *
136: * @param string $data binary data to append
137: * @access private
138: */
139: function _append($data)
140: {
141: if (strlen($data) - 4 > $this->_limit) {
142: $data = $this->_addContinue($data);
143: }
144: $this->_data .= $data;
145: $this->_datasize += strlen($data);
146: }
147:
148: /**
149: * General storage function like _append, but returns string instead of modifying $this->_data
150: *
151: * @param string $data binary data to write
152: * @return string
153: */
154: public function writeData($data)
155: {
156: if (strlen($data) - 4 > $this->_limit) {
157: $data = $this->_addContinue($data);
158: }
159: $this->_datasize += strlen($data);
160:
161: return $data;
162: }
163:
164: /**
165: * Writes Excel BOF record to indicate the beginning of a stream or
166: * sub-stream in the BIFF file.
167: *
168: * @param integer $type Type of BIFF file to write: 0x0005 Workbook,
169: * 0x0010 Worksheet.
170: * @access private
171: */
172: function _storeBof($type)
173: {
174: $record = 0x0809; // Record identifier (BIFF5-BIFF8)
175: $length = 0x0010;
176:
177: // by inspection of real files, MS Office Excel 2007 writes the following
178: $unknown = pack("VV", 0x000100D1, 0x00000406);
179:
180: $build = 0x0DBB; // Excel 97
181: $year = 0x07CC; // Excel 97
182:
183: $version = 0x0600; // BIFF8
184:
185: $header = pack("vv", $record, $length);
186: $data = pack("vvvv", $version, $type, $build, $year);
187: $this->_append($header . $data . $unknown);
188: }
189:
190: /**
191: * Writes Excel EOF record to indicate the end of a BIFF stream.
192: *
193: * @access private
194: */
195: function _storeEof()
196: {
197: $record = 0x000A; // Record identifier
198: $length = 0x0000; // Number of bytes to follow
199:
200: $header = pack("vv", $record, $length);
201: $this->_append($header);
202: }
203:
204: /**
205: * Writes Excel EOF record to indicate the end of a BIFF stream.
206: *
207: * @access private
208: */
209: public function writeEof()
210: {
211: $record = 0x000A; // Record identifier
212: $length = 0x0000; // Number of bytes to follow
213: $header = pack("vv", $record, $length);
214: return $this->writeData($header);
215: }
216:
217: /**
218: * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
219: * Excel 97 the limit is 8228 bytes. Records that are longer than these limits
220: * must be split up into CONTINUE blocks.
221: *
222: * This function takes a long BIFF record and inserts CONTINUE records as
223: * necessary.
224: *
225: * @param string $data The original binary data to be written
226: * @return string A very convenient string of continue blocks
227: * @access private
228: */
229: function _addContinue($data)
230: {
231: $limit = $this->_limit;
232: $record = 0x003C; // Record identifier
233:
234: // The first 2080/8224 bytes remain intact. However, we have to change
235: // the length field of the record.
236: $tmp = substr($data, 0, 2) . pack("v", $limit) . substr($data, 4, $limit);
237:
238: $header = pack("vv", $record, $limit); // Headers for continue records
239:
240: // Retrieve chunks of 2080/8224 bytes +4 for the header.
241: $data_length = strlen($data);
242: for ($i = $limit + 4; $i < ($data_length - $limit); $i += $limit) {
243: $tmp .= $header;
244: $tmp .= substr($data, $i, $limit);
245: }
246:
247: // Retrieve the last chunk of data
248: $header = pack("vv", $record, strlen($data) - $i);
249: $tmp .= $header;
250: $tmp .= substr($data, $i, strlen($data) - $i);
251:
252: return $tmp;
253: }
254:
255: }
256: