BIFFwriter.pm 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. # DISCLAIMER OF WARRANTY
  2. # Because this software is licensed free of charge, there is no warranty for the software,
  3. # to the extent permitted by applicable law. Except when otherwise stated in writing
  4. # the copyright holders and/or other parties provide the software "as is" without
  5. # warranty of any kind, either expressed or implied, including, but not limited to,
  6. # the implied warranties of merchantability and fitness for a particular purpose.
  7. # The entire risk as to the quality and performance of the software is with you.
  8. # Should the software prove defective, you assume the cost of all necessary
  9. # servicing, repair, or correction.
  10. # In no event unless required by applicable law or agreed to in writing will any
  11. # copyright holder, or any other party who may modify and/or redistribute the software
  12. # as permitted by the above licence, be liable to you for damages, including any general,
  13. # special, incidental, or consequential damages arising out of the use or inability
  14. # to use the software (including but not limited to loss of data or data being rendered
  15. # inaccurate or losses sustained by you or third parties or a failure of the software
  16. # to operate with any other software), even if such holder or other party
  17. # has been advised of the possibility of such damages.
  18. # AUTHOR
  19. # John McNamara jmcnamara@cpan.org
  20. # COPYRIGHT
  21. # Copyright MM-MMX, John McNamara.
  22. # All Rights Reserved. This module is free software. It may be used,
  23. # redistributed and/or modified under the terms of
  24. # the Artistic License(full text of the Artistic License http://dev.perl.org/licenses/artistic.html).
  25. package Spreadsheet::WriteExcel::BIFFwriter;
  26. ###############################################################################
  27. #
  28. # BIFFwriter - An abstract base class for Excel workbooks and worksheets.
  29. #
  30. #
  31. # Used in conjunction with Spreadsheet::WriteExcel
  32. #
  33. # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
  34. #
  35. # Documentation after __END__
  36. #
  37. use Exporter;
  38. use strict;
  39. use vars qw($VERSION @ISA);
  40. @ISA = qw(Exporter);
  41. $VERSION = '2.37';
  42. ###############################################################################
  43. #
  44. # Class data.
  45. #
  46. my $byte_order = '';
  47. my $BIFF_version = 0x0600;
  48. ###############################################################################
  49. #
  50. # new()
  51. #
  52. # Constructor
  53. #
  54. sub new {
  55. my $class = $_[0];
  56. my $self = {
  57. _byte_order => '',
  58. _data => '',
  59. _datasize => 0,
  60. _limit => 8224,
  61. _ignore_continue => 0,
  62. };
  63. bless $self, $class;
  64. $self->_set_byte_order();
  65. return $self;
  66. }
  67. ###############################################################################
  68. #
  69. # _set_byte_order()
  70. #
  71. # Determine the byte order and store it as class data to avoid
  72. # recalculating it for each call to new().
  73. #
  74. sub _set_byte_order {
  75. my $self = shift;
  76. if ($byte_order eq ''){
  77. # Check if "pack" gives the required IEEE 64bit float
  78. my $teststr = pack "d", 1.2345;
  79. my @hexdata =(0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
  80. my $number = pack "C8", @hexdata;
  81. if ($number eq $teststr) {
  82. $byte_order = 0; # Little Endian
  83. }
  84. elsif ($number eq reverse($teststr)){
  85. $byte_order = 1; # Big Endian
  86. }
  87. else {
  88. # Give up. I'll fix this in a later version.
  89. croak ( "Required floating point format not supported " .
  90. "on this platform. See the portability section " .
  91. "of the documentation."
  92. );
  93. }
  94. }
  95. $self->{_byte_order} = $byte_order;
  96. }
  97. ###############################################################################
  98. #
  99. # _prepend($data)
  100. #
  101. # General storage function
  102. #
  103. sub _prepend {
  104. my $self = shift;
  105. my $data = join('', @_);
  106. $data = $self->_add_continue($data) if length($data) > $self->{_limit};
  107. $self->{_data} = $data . $self->{_data};
  108. $self->{_datasize} += length($data);
  109. return $data;
  110. }
  111. ###############################################################################
  112. #
  113. # _append($data)
  114. #
  115. # General storage function
  116. #
  117. sub _append {
  118. my $self = shift;
  119. my $data = join('', @_);
  120. $data = $self->_add_continue($data) if length($data) > $self->{_limit};
  121. $self->{_data} = $self->{_data} . $data;
  122. $self->{_datasize} += length($data);
  123. return $data;
  124. }
  125. ###############################################################################
  126. #
  127. # _store_bof($type)
  128. #
  129. # $type = 0x0005, Workbook
  130. # $type = 0x0010, Worksheet
  131. # $type = 0x0020, Chart
  132. #
  133. # Writes Excel BOF record to indicate the beginning of a stream or
  134. # sub-stream in the BIFF file.
  135. #
  136. sub _store_bof {
  137. my $self = shift;
  138. my $record = 0x0809; # Record identifier
  139. my $length = 0x0010; # Number of bytes to follow
  140. my $version = $BIFF_version;
  141. my $type = $_[0];
  142. # According to the SDK $build and $year should be set to zero.
  143. # However, this throws a warning in Excel 5. So, use these
  144. # magic numbers.
  145. my $build = 0x0DBB;
  146. my $year = 0x07CC;
  147. my $bfh = 0x00000041;
  148. my $sfo = 0x00000006;
  149. my $header = pack("vv", $record, $length);
  150. my $data = pack("vvvvVV", $version, $type, $build, $year, $bfh, $sfo);
  151. $self->_prepend($header, $data);
  152. }
  153. ###############################################################################
  154. #
  155. # _store_eof()
  156. #
  157. # Writes Excel EOF record to indicate the end of a BIFF stream.
  158. #
  159. sub _store_eof {
  160. my $self = shift;
  161. my $record = 0x000A; # Record identifier
  162. my $length = 0x0000; # Number of bytes to follow
  163. my $header = pack("vv", $record, $length);
  164. $self->_append($header);
  165. }
  166. ###############################################################################
  167. #
  168. # _add_continue()
  169. #
  170. # Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
  171. # Excel 97 the limit is 8228 bytes. Records that are longer than these limits
  172. # must be split up into CONTINUE blocks.
  173. #
  174. # This function take a long BIFF record and inserts CONTINUE records as
  175. # necessary.
  176. #
  177. # Some records have their own specialised Continue blocks so there is also an
  178. # option to bypass this function.
  179. #
  180. sub _add_continue {
  181. my $self = shift;
  182. my $data = $_[0];
  183. my $limit = $self->{_limit};
  184. my $record = 0x003C; # Record identifier
  185. my $header;
  186. my $tmp;
  187. # Skip this if another method handles the continue blocks.
  188. return $data if $self->{_ignore_continue};
  189. # The first 2080/8224 bytes remain intact. However, we have to change
  190. # the length field of the record.
  191. #
  192. $tmp = substr($data, 0, $limit, "");
  193. substr($tmp, 2, 2, pack("v", $limit-4));
  194. # Strip out chunks of 2080/8224 bytes +4 for the header.
  195. while (length($data) > $limit) {
  196. $header = pack("vv", $record, $limit);
  197. $tmp .= $header;
  198. $tmp .= substr($data, 0, $limit, "");
  199. }
  200. # Mop up the last of the data
  201. $header = pack("vv", $record, length($data));
  202. $tmp .= $header;
  203. $tmp .= $data;
  204. return $tmp ;
  205. }
  206. ###############################################################################
  207. #
  208. # _add_mso_generic()
  209. #
  210. # Create a mso structure that is part of an Escher drawing object. These are
  211. # are used for images, comments and filters. This generic method is used by
  212. # other methods to create specific mso records.
  213. #
  214. # Returns the packed record.
  215. #
  216. sub _add_mso_generic {
  217. my $self = shift;
  218. my $type = $_[0];
  219. my $version = $_[1];
  220. my $instance = $_[2];
  221. my $data = $_[3];
  222. my $length = defined $_[4] ? $_[4] : length($data);
  223. # The header contains version and instance info packed into 2 bytes.
  224. my $header = $version | ($instance << 4);
  225. my $record = pack "vvV", $header, $type, $length;
  226. $record .= $data;
  227. return $record;
  228. }
  229. ###############################################################################
  230. #
  231. # For debugging
  232. #
  233. sub _hexout {
  234. my $self = shift;
  235. print +(caller(1))[3], "\n";
  236. my $data = join '', @_;
  237. my @bytes = unpack("H*", $data) =~ /../g;
  238. while (@bytes > 16) {
  239. print join " ", splice @bytes, 0, 16;
  240. print "\n";
  241. }
  242. print join " ", @bytes, "\n\n";
  243. }
  244. 1;
  245. __END__
  246. =head1 NAME
  247. BIFFwriter - An abstract base class for Excel workbooks and worksheets.
  248. =head1 SYNOPSIS
  249. See the documentation for Spreadsheet::WriteExcel
  250. =head1 DESCRIPTION
  251. This module is used in conjunction with Spreadsheet::WriteExcel.
  252. =head1 AUTHOR
  253. John McNamara jmcnamara@cpan.org
  254. =head1 COPYRIGHT
  255. © MM-MMX, John McNamara.
  256. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.