From 53b52b713490e0e9c45b79433f10393a9349e68f Mon Sep 17 00:00:00 2001 From: smiley Date: Sat, 16 Nov 2024 21:34:24 +0100 Subject: [PATCH] :octocat: allow for ECI encoded numeric and alphanum segments (???), see https://github.com/chillerlan/php-qrcode/discussions/289 --- examples/reader.php | 2 +- src/Data/ECI.php | 25 +++++++++++++++++-------- tests/Data/ECITest.php | 4 ++-- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/examples/reader.php b/examples/reader.php index 6a2f1073a..367a6e66f 100644 --- a/examples/reader.php +++ b/examples/reader.php @@ -24,7 +24,7 @@ var_dump($result); } catch(Throwable $e){ - echo $e->getMessage(); + printf("%s(%s): %s\n%s", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getTraceAsString()); } exit; diff --git a/src/Data/ECI.php b/src/Data/ECI.php index 624fa10f3..1aacd0b71 100644 --- a/src/Data/ECI.php +++ b/src/Data/ECI.php @@ -129,17 +129,12 @@ public static function validateString(string $string):bool{ public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{ $eciCharset = self::parseValue($bitBuffer); $nextMode = $bitBuffer->read(4); - - if($nextMode !== Mode::BYTE){ - throw new QRCodeDataException(sprintf('ECI designator followed by invalid mode: "%04b"', $nextMode)); - } - - $data = Byte::decodeSegment($bitBuffer, $versionNumber); - $encoding = $eciCharset->getName(); + $data = self::decodeModeSegment($nextMode, $bitBuffer, $versionNumber); + $encoding = $eciCharset->getName(); if($encoding === null){ // The spec isn't clear on this mode; see - // section 6.4.5: t does not say which encoding to assuming + // section 6.4.5: it does not say which encoding to assuming // upon decoding. I have seen ISO-8859-1 used as well as // Shift_JIS -- without anything like an ECI designator to // give a hint. @@ -153,4 +148,18 @@ public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):s return mb_convert_encoding($data, mb_internal_encoding(), $encoding); } + /** + * @throws \chillerlan\QRCode\Data\QRCodeDataException + */ + private static function decodeModeSegment(int $mode, BitBuffer $bitBuffer, int $versionNumber):string{ + + switch(true){ + case $mode === Mode::NUMBER: return Number::decodeSegment($bitBuffer, $versionNumber); + case $mode === Mode::ALPHANUM: return AlphaNum::decodeSegment($bitBuffer, $versionNumber); + case $mode === Mode::BYTE: return Byte::decodeSegment($bitBuffer, $versionNumber); + } + + throw new QRCodeDataException(sprintf('ECI designator followed by invalid mode: "%04b"', $mode)); + } + } diff --git a/tests/Data/ECITest.php b/tests/Data/ECITest.php index 5505d084e..d6855e406 100644 --- a/tests/Data/ECITest.php +++ b/tests/Data/ECITest.php @@ -12,7 +12,7 @@ use chillerlan\QRCode\QROptions; use chillerlan\QRCode\Common\{BitBuffer, ECICharset, Mode}; -use chillerlan\QRCode\Data\{Byte, ECI, Number, QRCodeDataException, QRData, QRDataModeInterface}; +use chillerlan\QRCode\Data\{Byte, ECI, Hanzi, QRCodeDataException, QRData, QRDataModeInterface}; use PHPUnit\Framework\TestCase; /** @@ -125,7 +125,7 @@ public function testDecodeECISegmentFollowedByInvalidModeException():void{ /** @var \chillerlan\QRCode\Data\QRDataModeInterface[] $segments */ $segments = $this->getDataSegments(); // follow the ECI segment by a non-8bit-byte segment - $segments[1] = new Number('1'); + $segments[1] = new Hanzi(self::testData); $bitBuffer = (new QRData($options, $segments))->getBitBuffer(); // verify the ECI mode indicator $this::assertSame(Mode::ECI, $bitBuffer->read(4));