$this->_append($header . $data);
}
- /**
+/**
* Calculate
* Handling of the SST continue blocks is complicated by the need to include an
* additional continuation byte depending on whether the string is split between
* additional complications that will arise later when/if Rich Strings are
* supported).
*
+ * MOODLE NOTE!!
+ *
+ * The functions below
+ * _calculateSharedStringsSizes()
+ * _storeSharedStringsTable()
+ * have been inserted, replacing the original functions in order to make the function
+ * work with 2-byte data. The patch is discussed at this URL:
+ * http://pear.php.net/bugs/bug.php?id=1572
+ * and documented for Moodle at:
+ * http://tracker.moodle.org/browse/MDL-9911
+ * --Tom Robb, trobb@cc.kyoto-su.ac.jp July 23, 2007
+ *
* @access private
*/
function _calculateSharedStringsSizes()
8228 : Maximum Excel97 block size
-4 : Length of block header
-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;
$written = 0;
$this->_block_sizes = array();
foreach (array_keys($this->_str_table) as $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
// written out in a single SST or CONTINUE block.
boundaries. Therefore, in some cases we need to reduce the
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) {
// Write as much as possible of the string in the current block
$written += $space_remaining;
// 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
- $this->_block_sizes[] = $continue_limit;
+ $this->_block_sizes[] = $continue_limit - $align;
// If the current string was split then the next CONTINUE block
// should have the string continue flag (grbit) set unless the
This length is required to set the offsets in the BOUNDSHEET records since
they must be written before the SST records
*/
- $total_offset = array_sum($this->_block_sizes);
- // SST information
- $total_offset += 8;
- if (!empty($this->_block_sizes)) {
- $total_offset += (count($this->_block_sizes)) * 4; // add CONTINUE headers
+
+ $tmp_block_sizes = array();
+ $tmp_block_sizes = $this->_block_sizes;
+
+ $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;
}
/**
function _storeSharedStringsTable()
{
$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
- $this->_block_sizes = array_reverse($this->_block_sizes);
- $length = array_pop($this->_block_sizes) + 8; // First block size plus SST information
+ $tmp_block_sizes = $this->_block_sizes;
+// $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
$header = pack("vv", $record, $length);
$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 */
foreach (array_keys($this->_str_table) as $string) {
$string_length = strlen($string);
- $encoding = 0; // assume there are no Unicode strings
+ $headerinfo = unpack("vlength/Cencoding", $string);
+ $encoding = $headerinfo["encoding"];
$split_string = 0;
// Block length is the total length of the strings that will be
// Unicode data should only be split on char (2 byte) boundaries.
// 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) {
// Write as much as possible of the string in the current block
$string = substr($string, $space_remaining);
// 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
// should have the string continue flag (grbit) set unless the
// Write the CONTINUE block header
if (!empty($this->_block_sizes)) {
$record = 0x003C;
- $length = array_pop($this->_block_sizes);
+ $length = array_shift($tmp_block_sizes);
+
$header = pack('vv', $record, $length);
if ($continue) {
$header .= pack('C', $encoding);