PageRenderTime 35ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/branches/v1.6.5/Classes/PHPExcel/Writer/Excel5/BIFFwriter.php

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