diff --git a/src/Buffer.php b/src/Buffer.php index 120cbc1..642a5a1 100644 --- a/src/Buffer.php +++ b/src/Buffer.php @@ -214,7 +214,24 @@ public function read($length = null) } /** - * @param $data + * @param string $data + * @param int $maxLength + * + * @return int + */ + public function lengthBytes($data, $maxLength = null) + { + if (strtolower($this->streamCharset) != strtolower($this->systemCharset)) { + $data = mb_convert_encoding($data, $this->streamCharset, $this->systemCharset); + } + if (isset($maxLength)) { + $data = mb_strcut($data, 0, $maxLength, $this->streamCharset); + } + return \strlen($data); + } + + /** + * @param string $data * @param int|string $length * * @return false|int @@ -224,7 +241,9 @@ public function writeString($data, $length = '*') if (strtolower($this->streamCharset) != strtolower($this->systemCharset)) { $data = mb_convert_encoding($data, $this->streamCharset, $this->systemCharset); } - + if (isset($length) && ($length != '*')) { + $data = mb_strcut($data, 0, $length, $this->streamCharset); + } return $this->write(pack('A' . $length, $data)); } diff --git a/src/Sav/Record/Info/LongStringValueLabels.php b/src/Sav/Record/Info/LongStringValueLabels.php index e804588..5fcb696 100644 --- a/src/Sav/Record/Info/LongStringValueLabels.php +++ b/src/Sav/Record/Info/LongStringValueLabels.php @@ -45,15 +45,17 @@ public function write(Buffer $buffer) throw new \InvalidArgumentException('values required'); } $width = (int) $data['width']; - $localBuffer->writeInt(mb_strlen($varName)); - $localBuffer->writeString($varName, mb_strlen($varName)); + $varLengthBytes = $buffer->lengthBytes($varName); + $localBuffer->writeInt($varLengthBytes); + $localBuffer->writeString($varName, $varLengthBytes); $localBuffer->writeInt($width); $localBuffer->writeInt(Utils::is_countable($data['values']) ? \count($data['values']) : 0); foreach ($data['values'] as $value => $label) { $localBuffer->writeInt($width); $localBuffer->writeString($value, $width); - $localBuffer->writeInt(mb_strlen($label)); - $localBuffer->writeString($label, mb_strlen($label)); + $labelLengthBytes = $buffer->lengthBytes($label); + $localBuffer->writeInt($labelLengthBytes); + $localBuffer->writeString($label, $labelLengthBytes); } } diff --git a/src/Sav/Record/Info/VariableAttributes.php b/src/Sav/Record/Info/VariableAttributes.php index 46a90b2..5a1e088 100644 --- a/src/Sav/Record/Info/VariableAttributes.php +++ b/src/Sav/Record/Info/VariableAttributes.php @@ -44,7 +44,7 @@ public function write(Buffer $buffer) if ($lines !== []) { $data = implode('/', $lines); - $this->dataCount = mb_strlen($data); + $this->dataCount = \strlen($data); parent::write($buffer); $buffer->writeString($data); } diff --git a/src/Sav/Record/ValueLabel.php b/src/Sav/Record/ValueLabel.php index d2dad5d..88deb16 100644 --- a/src/Sav/Record/ValueLabel.php +++ b/src/Sav/Record/ValueLabel.php @@ -96,22 +96,16 @@ public function write(Buffer $buffer) $buffer->writeInt(self::TYPE); $buffer->writeInt(\count($this->labels)); foreach ($this->labels as $item) { - $labelLength = min(mb_strlen($item['label']), self::LABEL_MAX_LENGTH); - $label = mb_substr($item['label'], 0, $labelLength); - $labelLengthBytes = mb_strlen($label, '8bit'); - while ($labelLengthBytes > 255) { - // Strip one char, can be multiple bytes - $label = mb_substr($label, 0, -1); - $labelLengthBytes = mb_strlen($label, '8bit'); - } - + $labelLengthBytes = $buffer->lengthBytes($item['label'], self::LABEL_MAX_LENGTH); + $labelLengthBytesRound = Utils::roundUp($labelLengthBytes + 1, 8) - 1; + if ($convertToDouble) { $item['value'] = Utils::stringToDouble($item['value']); } $buffer->writeDouble($item['value']); $buffer->write(\chr($labelLengthBytes)); - $buffer->writeString($label, Utils::roundUp($labelLengthBytes + 1, 8) - 1); + $buffer->writeString($item['label'], $labelLengthBytesRound); } // Value label variable record. diff --git a/src/Sav/Record/Variable.php b/src/Sav/Record/Variable.php index bab4cc6..2a1373e 100644 --- a/src/Sav/Record/Variable.php +++ b/src/Sav/Record/Variable.php @@ -141,17 +141,10 @@ public function write(Buffer $buffer) $buffer->writeString($this->name, 8); if ($hasLabel) { - // Maxlength is 255 bytes, since we write utf8 a char can be multiple bytes - $labelLength = min(mb_strlen($this->label), 255); - $label = mb_substr($this->label, 0, $labelLength); - $labelLengthBytes = mb_strlen($label, '8bit'); - while ($labelLengthBytes > 255) { - // Strip one char, can be multiple bytes - $label = mb_substr($label, 0, -1); - $labelLengthBytes = mb_strlen($label, '8bit'); - } + $labelLengthBytes = $buffer->lengthBytes($this->label, self::REAL_VLS_CHUNK); + $labelLengthBytesRound = Utils::roundUp($labelLengthBytes, 4); $buffer->writeInt($labelLengthBytes); - $buffer->writeString($label, Utils::roundUp($labelLengthBytes, 4)); + $buffer->writeString($this->label, $labelLengthBytesRound); } // TODO: test @@ -180,10 +173,10 @@ public function write(Buffer $buffer) $buffer->writeInt(0); // No missing values $buffer->writeInt($format); // Print format $buffer->writeInt($format); // Write format - $buffer->writeString($this->getSegmentName($i - 1), 8); + $buffer->writeString($this->getSegmentName($buffer, $i - 1), 8); if ($hasLabel) { $buffer->writeInt($labelLengthBytes); - $buffer->writeString($label, Utils::roundUp($labelLengthBytes, 4)); + $buffer->writeString($this->label, Utils::roundUp($labelLengthBytes, 4)); } $this->writeBlank($buffer, $segmentWidth); @@ -215,13 +208,13 @@ public function writeBlank(Buffer $buffer, $width) * * @return string */ - public function getSegmentName($seg = 0) + public function getSegmentName($buffer, $seg = 0) { // TODO: refactory $name = $this->name; - $name = mb_substr($name, 0, 6); + $name = mb_strcut($name, 0, 6, $buffer->systemCharset); $name .= $seg; - return mb_strtoupper($name); + return mb_strtoupper($name, $buffer->systemCharset); } }