BIFFwriter.php 7.9 KB

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