fix bug#1572 and bug#2942 - Problems with files with over 200 row / or 30kb of filesize - patch originally by michal dot fapso at goldenboat dot net - tested and reviewed

git-svn-id: https://svn.php.net/repository/pear/packages/Spreadsheet_Excel_Writer/trunk@289242 c90b9560-bf6c-de11-be94-00142212c4b1
This commit is contained in:
Alan Knowles 2009-10-06 05:57:28 +00:00
parent f70336321a
commit 366794efd7
1 changed files with 99 additions and 22 deletions

View File

@ -1279,7 +1279,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
$header = pack("vvv", $record, $length, $ccv); $header = pack("vvv", $record, $length, $ccv);
$this->_append($header . $data); $this->_append($header . $data);
} }
/** /**
* Calculate * Calculate
* Handling of the SST continue blocks is complicated by the need to include an * Handling of the SST continue blocks is complicated by the need to include an
@ -1297,9 +1297,9 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
8228 : Maximum Excel97 block size 8228 : Maximum Excel97 block size
-4 : Length of block header -4 : Length of block header
-8 : Length of additional SST header information -8 : Length of additional SST header information
= 8216 -8 : Arbitrary number to keep within _add_continue() limit = 8208
*/ */
$continue_limit = 8216; $continue_limit = 8208;
$block_length = 0; $block_length = 0;
$written = 0; $written = 0;
$this->_block_sizes = array(); $this->_block_sizes = array();
@ -1307,6 +1307,9 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
foreach (array_keys($this->_str_table) as $string) { foreach (array_keys($this->_str_table) as $string) {
$string_length = strlen($string); $string_length = strlen($string);
$headerinfo = unpack("vlength/Cencoding", $string);
$encoding = $headerinfo["encoding"];
$split_string = 0;
// Block length is the total length of the strings that will be // Block length is the total length of the strings that will be
// written out in a single SST or CONTINUE block. // written out in a single SST or CONTINUE block.
@ -1333,16 +1336,39 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
boundaries. Therefore, in some cases we need to reduce the boundaries. Therefore, in some cases we need to reduce the
amount of available amount of available
*/ */
$align = 0;
// Only applies to Unicode strings
if ($encoding == 1) {
// Min string + header size -1
$header_length = 4;
if ($space_remaining > $header_length) {
// String contains 3 byte header => split on odd boundary
if (!$split_string && $space_remaining % 2 != 1) {
$space_remaining--;
$align = 1;
}
// Split section without header => split on even boundary
else if ($split_string && $space_remaining % 2 == 1) {
$space_remaining--;
$align = 1;
}
$split_string = 1;
}
}
if ($space_remaining > $header_length) { if ($space_remaining > $header_length) {
// Write as much as possible of the string in the current block // Write as much as possible of the string in the current block
$written += $space_remaining; $written += $space_remaining;
// Reduce the current block length by the amount written // Reduce the current block length by the amount written
$block_length -= $continue_limit - $continue; $block_length -= $continue_limit - $continue - $align;
// Store the max size for this block // Store the max size for this block
$this->_block_sizes[] = $continue_limit; $this->_block_sizes[] = $continue_limit - $align;
// If the current string was split then the next CONTINUE block // If the current string was split then the next CONTINUE block
// should have the string continue flag (grbit) set unless the // should have the string continue flag (grbit) set unless the
@ -1384,13 +1410,19 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
This length is required to set the offsets in the BOUNDSHEET records since This length is required to set the offsets in the BOUNDSHEET records since
they must be written before the SST records they must be written before the SST records
*/ */
$total_offset = array_sum($this->_block_sizes);
// SST information $tmp_block_sizes = array();
$total_offset += 8; $tmp_block_sizes = $this->_block_sizes;
if (!empty($this->_block_sizes)) {
$total_offset += (count($this->_block_sizes)) * 4; // add CONTINUE headers $length = 12;
if (!empty($tmp_block_sizes)) {
$length += array_shift($tmp_block_sizes); // SST
} }
return $total_offset; while (!empty($tmp_block_sizes)) {
$length += 4 + array_shift($tmp_block_sizes); // CONTINUEs
}
return $length;
} }
/** /**
@ -1407,9 +1439,31 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
function _storeSharedStringsTable() function _storeSharedStringsTable()
{ {
$record = 0x00fc; // Record identifier $record = 0x00fc; // Record identifier
$length = 0x0008; // Number of bytes to follow
$total = 0x0000;
// Iterate through the strings to calculate the CONTINUE block sizes
$continue_limit = 8208;
$block_length = 0;
$written = 0;
$continue = 0;
// sizes are upside down // sizes are upside down
$this->_block_sizes = array_reverse($this->_block_sizes); $tmp_block_sizes = $this->_block_sizes;
$length = array_pop($this->_block_sizes) + 8; // First block size plus SST information // $tmp_block_sizes = array_reverse($this->_block_sizes);
// The SST record is required even if it contains no strings. Thus we will
// always have a length
//
if (!empty($tmp_block_sizes)) {
$length = 8 + array_shift($tmp_block_sizes);
}
else {
// No strings
$length = 8;
}
// Write the SST block header information // Write the SST block header information
$header = pack("vv", $record, $length); $header = pack("vv", $record, $length);
@ -1417,18 +1471,14 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
$this->_append($header . $data); $this->_append($header . $data);
// Iterate through the strings to calculate the CONTINUE block sizes
$continue_limit = 8216;
$block_length = 0;
$written = 0;
$continue = 0;
/* TODO: not good for performance */ /* TODO: not good for performance */
foreach (array_keys($this->_str_table) as $string) { foreach (array_keys($this->_str_table) as $string) {
$string_length = strlen($string); $string_length = strlen($string);
$encoding = 0; // assume there are no Unicode strings $headerinfo = unpack("vlength/Cencoding", $string);
$encoding = $headerinfo["encoding"];
$split_string = 0; $split_string = 0;
// Block length is the total length of the strings that will be // Block length is the total length of the strings that will be
@ -1459,6 +1509,30 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
// Unicode data should only be split on char (2 byte) boundaries. // Unicode data should only be split on char (2 byte) boundaries.
// Therefore, in some cases we need to reduce the amount of available // Therefore, in some cases we need to reduce the amount of available
// space by 1 byte to ensure the correct alignment.
$align = 0;
// Only applies to Unicode strings
if ($encoding == 1) {
// Min string + header size -1
$header_length = 4;
if ($space_remaining > $header_length) {
// String contains 3 byte header => split on odd boundary
if (!$split_string && $space_remaining % 2 != 1) {
$space_remaining--;
$align = 1;
}
// Split section without header => split on even boundary
else if ($split_string && $space_remaining % 2 == 1) {
$space_remaining--;
$align = 1;
}
$split_string = 1;
}
}
if ($space_remaining > $header_length) { if ($space_remaining > $header_length) {
// Write as much as possible of the string in the current block // Write as much as possible of the string in the current block
@ -1469,7 +1543,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
$string = substr($string, $space_remaining); $string = substr($string, $space_remaining);
// Reduce the current block length by the amount written // Reduce the current block length by the amount written
$block_length -= $continue_limit - $continue; $block_length -= $continue_limit - $continue - $align;
// If the current string was split then the next CONTINUE block // If the current string was split then the next CONTINUE block
// should have the string continue flag (grbit) set unless the // should have the string continue flag (grbit) set unless the
@ -1489,7 +1563,8 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
// Write the CONTINUE block header // Write the CONTINUE block header
if (!empty($this->_block_sizes)) { if (!empty($this->_block_sizes)) {
$record = 0x003C; $record = 0x003C;
$length = array_pop($this->_block_sizes); $length = array_shift($tmp_block_sizes);
$header = pack('vv', $record, $length); $header = pack('vv', $record, $length);
if ($continue) { if ($continue) {
$header .= pack('C', $encoding); $header .= pack('C', $encoding);
@ -1510,5 +1585,7 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
} }
} }
} }
} }
?>