From 21b414cab03fdc42d54485bf1b7f609127bbcdab Mon Sep 17 00:00:00 2001 From: codemasher Date: Thu, 2 Dec 2021 00:18:51 +0100 Subject: [PATCH] :shower: replaced generic exceptions --- src/Decoder/Binarizer.php | 5 ++-- src/Decoder/BitMatrix.php | 29 ++++++++++++------------ src/Decoder/Decoder.php | 22 ++++++++---------- src/Decoder/GDLuminanceSource.php | 5 ++-- src/Decoder/LuminanceSourceAbstract.php | 9 ++++---- src/Decoder/LuminanceSourceInterface.php | 1 + src/Decoder/QRCodeDecoderException.php | 15 ++++++++++++ src/Detector/Detector.php | 11 ++++----- src/Detector/FinderPatternFinder.php | 7 +++--- src/Detector/GridSampler.php | 16 ++++++------- src/Detector/QRCodeDetectorException.php | 15 ++++++++++++ 11 files changed, 79 insertions(+), 56 deletions(-) create mode 100644 src/Decoder/QRCodeDecoderException.php create mode 100644 src/Detector/QRCodeDetectorException.php diff --git a/src/Decoder/Binarizer.php b/src/Decoder/Binarizer.php index bed797d04..94387d88e 100644 --- a/src/Decoder/Binarizer.php +++ b/src/Decoder/Binarizer.php @@ -11,7 +11,6 @@ namespace chillerlan\QRCode\Decoder; -use RuntimeException; use function array_fill, count, max; /** @@ -55,7 +54,7 @@ final class Binarizer{ } /** - * @throws \RuntimeException + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ private function estimateBlackPoint(array $buckets):int{ // Find the tallest peak in the histogram. @@ -101,7 +100,7 @@ final class Binarizer{ // If there is too little contrast in the image to pick a meaningful black point, throw rather // than waste time trying to decode the image, and risk false positives. if($secondPeak - $firstPeak <= $numBuckets / 16){ - throw new RuntimeException('no meaningful dark point found'); + throw new QRCodeDecoderException('no meaningful dark point found'); } // Find a valley between them that is low and closer to the white peak. diff --git a/src/Decoder/BitMatrix.php b/src/Decoder/BitMatrix.php index a355d1283..66f708507 100644 --- a/src/Decoder/BitMatrix.php +++ b/src/Decoder/BitMatrix.php @@ -12,7 +12,6 @@ namespace chillerlan\QRCode\Decoder; use chillerlan\QRCode\Common\{FormatInformation, Version}; -use InvalidArgumentException, RuntimeException; use function array_fill, count; use const PHP_INT_MAX, PHP_INT_SIZE; @@ -74,23 +73,23 @@ final class BitMatrix{ * @param int $width ; The width of the region * @param int $height ; The height of the region * - * @throws \InvalidArgumentException + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ public function setRegion(int $left, int $top, int $width, int $height):self{ if($top < 0 || $left < 0){ - throw new InvalidArgumentException('Left and top must be nonnegative'); + throw new QRCodeDecoderException('Left and top must be non-negative'); } if($height < 1 || $width < 1){ - throw new InvalidArgumentException('Height and width must be at least 1'); + throw new QRCodeDecoderException('Height and width must be at least 1'); } $right = $left + $width; $bottom = $top + $height; if($bottom > $this->dimension || $right > $this->dimension){ - throw new InvalidArgumentException('The region must fit inside the matrix'); + throw new QRCodeDecoderException('The region must fit inside the matrix'); } for($y = $top; $y < $bottom; $y++){ @@ -256,7 +255,7 @@ final class BitMatrix{ * QR Code. * * @return array bytes encoded within the QR Code - * @throws \RuntimeException if the exact number of bytes expected is not read + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException if the exact number of bytes expected is not read */ public function readCodewords():array{ $this->formatInfo = $this->readFormatInformation(); @@ -308,7 +307,7 @@ final class BitMatrix{ } if($resultOffset !== $this->version->getTotalCodewords()){ - throw new RuntimeException('offset differs from total codewords for version'); + throw new QRCodeDecoderException('offset differs from total codewords for version'); } return $result; @@ -317,9 +316,9 @@ final class BitMatrix{ /** * Reads format information from one of its two locations within the QR Code. * - * @return \chillerlan\QRCode\Common\FormatInformation encapsulating the QR Code's format info - * @throws \RuntimeException if both format information locations cannot be parsed as - * the valid encoding of format information + * @return \chillerlan\QRCode\Common\FormatInformation encapsulating the QR Code's format info + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException if both format information locations cannot be parsed as + * the valid encoding of format information */ private function readFormatInformation():FormatInformation{ @@ -372,7 +371,7 @@ final class BitMatrix{ return $this->formatInfo; } - throw new RuntimeException('failed to read format info'); + throw new QRCodeDecoderException('failed to read format info'); } /** @@ -424,9 +423,9 @@ final class BitMatrix{ /** * Reads version information from one of its two locations within the QR Code. * - * @return \chillerlan\QRCode\Common\Version encapsulating the QR Code's version - * @throws \RuntimeException if both version information locations cannot be parsed as - * the valid encoding of version information + * @return \chillerlan\QRCode\Common\Version encapsulating the QR Code's version + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException if both version information locations cannot be parsed as + * the valid encoding of version information */ private function readVersion():Version{ @@ -471,7 +470,7 @@ final class BitMatrix{ return $this->version; } - throw new RuntimeException('failed to read version'); + throw new QRCodeDecoderException('failed to read version'); } /** diff --git a/src/Decoder/Decoder.php b/src/Decoder/Decoder.php index ef1801ec5..cafac9872 100644 --- a/src/Decoder/Decoder.php +++ b/src/Decoder/Decoder.php @@ -11,7 +11,7 @@ namespace chillerlan\QRCode\Decoder; -use InvalidArgumentException, RuntimeException, Throwable; +use Throwable; use chillerlan\QRCode\Common\{BitBuffer, EccLevel, Mode, ReedSolomonDecoder, Version}; use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Kanji, Number}; use chillerlan\QRCode\Detector\Detector; @@ -33,8 +33,8 @@ final class Decoder{ * * @param \chillerlan\QRCode\Decoder\LuminanceSourceInterface $source * - * @return \chillerlan\QRCode\Decoder\DecoderResult text and bytes encoded within the QR Code - * @throws \Throwable if the QR Code cannot be decoded + * @return \chillerlan\QRCode\Decoder\DecoderResult text and bytes encoded within the QR Code + * @throws \Throwable|\chillerlan\QRCode\Decoder\QRCodeDecoderException if the QR Code cannot be decoded */ public function decode(LuminanceSourceInterface $source):DecoderResult{ $bitMatrix = (new Detector($source))->detect(); @@ -66,9 +66,7 @@ final class Decoder{ } /** - * @param \chillerlan\QRCode\Decoder\BitMatrix $bitMatrix - * - * @return \chillerlan\QRCode\Decoder\DecoderResult + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ private function decodeMatrix(BitMatrix $bitMatrix):DecoderResult{ // Read raw codewords @@ -78,7 +76,7 @@ final class Decoder{ // technically this shouldn't happen as the respective read meathods would throw first if($version === null || $formatInfo === null){ - throw new RuntimeException('unable to read version or ecc level'); + throw new QRCodeDecoderException('unable to read version or ecc level'); } $eccLevel = $formatInfo->getErrorCorrectionLevel(); @@ -114,12 +112,12 @@ final class Decoder{ * @param \chillerlan\QRCode\Common\EccLevel $eccLevel error-correction level of the QR Code * * @return array DataBlocks containing original bytes, "de-interleaved" from representation in the QR Code - * @throws \InvalidArgumentException + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ private function getDataBlocks(array $rawCodewords, Version $version, EccLevel $eccLevel):array{ if(count($rawCodewords) !== $version->getTotalCodewords()){ - throw new InvalidArgumentException('$rawCodewords differ from total codewords for version'); + throw new QRCodeDecoderException('$rawCodewords differ from total codewords for version'); } // Figure out the number and size of data blocks used by this version and @@ -210,7 +208,7 @@ final class Decoder{ } /** - * @throws \RuntimeException + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ private function decodeBitStream(array $bytes, Version $version, EccLevel $ecLevel):DecoderResult{ $bits = new BitBuffer($bytes); @@ -242,7 +240,7 @@ final class Decoder{ } elseif($datamode === Mode::STRCTURED_APPEND){ if($bits->available() < 16){ - throw new RuntimeException('structured append: not enough bits left'); + throw new QRCodeDecoderException('structured append: not enough bits left'); } // sequence number and parity is added later to the result metadata // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue @@ -312,7 +310,7 @@ final class Decoder{ $result .= Kanji::decodeSegment($bits, $versionNumber); } else{ - throw new RuntimeException('invalid data mode'); + throw new QRCodeDecoderException('invalid data mode'); } # } } diff --git a/src/Decoder/GDLuminanceSource.php b/src/Decoder/GDLuminanceSource.php index 00e372abb..db4cc1344 100644 --- a/src/Decoder/GDLuminanceSource.php +++ b/src/Decoder/GDLuminanceSource.php @@ -13,7 +13,6 @@ namespace chillerlan\QRCode\Decoder; -use InvalidArgumentException; use function file_get_contents, get_resource_type, imagecolorat, imagecolorsforindex, imagecreatefromstring, imagesx, imagesy, is_resource; use const PHP_MAJOR_VERSION; @@ -34,7 +33,7 @@ final class GDLuminanceSource extends LuminanceSourceAbstract{ * * @param resource|\GdImage $gdImage * - * @throws \InvalidArgumentException + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ public function __construct($gdImage){ @@ -43,7 +42,7 @@ final class GDLuminanceSource extends LuminanceSourceAbstract{ (PHP_MAJOR_VERSION >= 8 && !$gdImage instanceof \GdImage) || (PHP_MAJOR_VERSION < 8 && (!is_resource($gdImage) || get_resource_type($gdImage) !== 'gd')) ){ - throw new InvalidArgumentException('Invalid GD image source.'); + throw new QRCodeDecoderException('Invalid GD image source.'); } parent::__construct(imagesx($gdImage), imagesy($gdImage)); diff --git a/src/Decoder/LuminanceSourceAbstract.php b/src/Decoder/LuminanceSourceAbstract.php index 6ce4f71be..1fa3dabda 100644 --- a/src/Decoder/LuminanceSourceAbstract.php +++ b/src/Decoder/LuminanceSourceAbstract.php @@ -11,7 +11,6 @@ namespace chillerlan\QRCode\Decoder; -use InvalidArgumentException; use function array_slice, array_splice, file_exists, is_file, is_readable, realpath; /** @@ -59,7 +58,7 @@ abstract class LuminanceSourceAbstract implements LuminanceSourceInterface{ public function getRow(int $y):array{ if($y < 0 || $y >= $this->getHeight()){ - throw new InvalidArgumentException('Requested row is outside the image: '.$y); + throw new QRCodeDecoderException('Requested row is outside the image: '.$y); } $arr = []; @@ -81,19 +80,19 @@ abstract class LuminanceSourceAbstract implements LuminanceSourceInterface{ } /** - * + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ protected static function checkFile(string $path):string{ $path = trim($path); if(!file_exists($path) || !is_file($path) || !is_readable($path)){ - throw new InvalidArgumentException('invalid file: '.$path); + throw new QRCodeDecoderException('invalid file: '.$path); } $realpath = realpath($path); if($realpath === false){ - throw new InvalidArgumentException('unable to resolve path: '.$path); + throw new QRCodeDecoderException('unable to resolve path: '.$path); } return $realpath; diff --git a/src/Decoder/LuminanceSourceInterface.php b/src/Decoder/LuminanceSourceInterface.php index 7e3dbdf5a..871e381c4 100644 --- a/src/Decoder/LuminanceSourceInterface.php +++ b/src/Decoder/LuminanceSourceInterface.php @@ -44,6 +44,7 @@ interface LuminanceSourceInterface{ * @param int $y The row to fetch, which must be in [0,getHeight()) * * @return array An array containing the luminance data. + * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException */ public function getRow(int $y):array; diff --git a/src/Decoder/QRCodeDecoderException.php b/src/Decoder/QRCodeDecoderException.php new file mode 100644 index 000000000..8fb67d801 --- /dev/null +++ b/src/Decoder/QRCodeDecoderException.php @@ -0,0 +1,15 @@ + + * @copyright 2021 smiley + * @license MIT + */ + +namespace chillerlan\QRCode\Decoder; + +use chillerlan\QRCode\QRCodeException; + +class QRCodeDecoderException extends QRCodeException{} diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php index 0ba19bbaa..a9279f8b9 100644 --- a/src/Detector/Detector.php +++ b/src/Detector/Detector.php @@ -12,7 +12,6 @@ namespace chillerlan\QRCode\Detector; use chillerlan\QRCode\Decoder\{Binarizer, LuminanceSourceInterface}; -use RuntimeException; use chillerlan\QRCode\Common\Version; use chillerlan\QRCode\Decoder\BitMatrix; use function abs, is_nan, max, min, round; @@ -78,7 +77,7 @@ final class Detector{ * Computes an average estimated module size based on estimated derived from the positions * of the three finder patterns. * - * @throws \RuntimeException + * @throws \chillerlan\QRCode\Detector\QRCodeDetectorException */ private function calculateModuleSize(FinderPattern $topLeft, FinderPattern $topRight, FinderPattern $bottomLeft):float{ // Take the average @@ -88,7 +87,7 @@ final class Detector{ ) / 2.0; if($moduleSize < 1.0){ - throw new RuntimeException('module size < 1.0'); + throw new QRCodeDetectorException('module size < 1.0'); } return $moduleSize; @@ -244,7 +243,7 @@ final class Detector{ * Computes the dimension (number of modules on a size) of the QR Code based on the position * of the finder patterns and estimated module size. * - * @throws \RuntimeException + * @throws \chillerlan\QRCode\Detector\QRCodeDetectorException */ private function computeDimension( FinderPattern $topLeft, @@ -265,11 +264,11 @@ final class Detector{ $dimension--; break; case 3: - throw new RuntimeException('estimated dimension: '.$dimension); + throw new QRCodeDetectorException('estimated dimension: '.$dimension); } if($dimension % 4 !== 1){ - throw new RuntimeException('dimension mod 4 is not 1'); + throw new QRCodeDetectorException('dimension mod 4 is not 1'); } return $dimension; diff --git a/src/Detector/FinderPatternFinder.php b/src/Detector/FinderPatternFinder.php index 0b6cf6df6..9ba91d552 100644 --- a/src/Detector/FinderPatternFinder.php +++ b/src/Detector/FinderPatternFinder.php @@ -13,7 +13,6 @@ namespace chillerlan\QRCode\Detector; -use RuntimeException; use chillerlan\QRCode\Decoder\BitMatrix; use function abs, count, usort; use const PHP_FLOAT_MAX; @@ -617,13 +616,13 @@ final class FinderPatternFinder{ * @return \chillerlan\QRCode\Detector\FinderPattern[] the 3 best FinderPatterns from our list of candidates. The "best" are * those that have been detected at least #CENTER_QUORUM times, and whose module * size differs from the average among those patterns the least - * @throws \RuntimeException if 3 such finder patterns do not exist + * @throws \chillerlan\QRCode\Detector\QRCodeDetectorException if 3 such finder patterns do not exist */ private function selectBestPatterns():array{ $startSize = count($this->possibleCenters); if($startSize < 3){ - throw new RuntimeException('could not find enough finder patterns'); + throw new QRCodeDetectorException('could not find enough finder patterns'); } usort( @@ -708,7 +707,7 @@ final class FinderPatternFinder{ } if($distortion === PHP_FLOAT_MAX){ - throw new RuntimeException('finder patterns may be too distorted'); + throw new QRCodeDetectorException('finder patterns may be too distorted'); } return $bestPatterns; diff --git a/src/Detector/GridSampler.php b/src/Detector/GridSampler.php index dbbb3d780..27ae45098 100644 --- a/src/Detector/GridSampler.php +++ b/src/Detector/GridSampler.php @@ -11,8 +11,8 @@ namespace chillerlan\QRCode\Detector; -use Exception, RuntimeException; use chillerlan\QRCode\Decoder\BitMatrix; +use Throwable; use function array_fill, count, sprintf; /** @@ -44,7 +44,7 @@ final class GridSampler{ * @param \chillerlan\QRCode\Decoder\BitMatrix $bitMatrix image into which the points should map * @param float[] $points actual points in x1,y1,...,xn,yn form * - * @throws \RuntimeException if an endpoint is lies outside the image boundaries + * @throws \chillerlan\QRCode\Detector\QRCodeDetectorException if an endpoint is lies outside the image boundaries */ private function checkAndNudgePoints(BitMatrix $bitMatrix, array $points):void{ $dimension = $bitMatrix->getDimension(); @@ -57,7 +57,7 @@ final class GridSampler{ $y = (int)$points[$offset + 1]; if($x < -1 || $x > $dimension || $y < -1 || $y > $dimension){ - throw new RuntimeException(sprintf('checkAndNudgePoints 1, x: %s, y: %s, d: %s', $x, $y, $dimension)); + throw new QRCodeDetectorException(sprintf('checkAndNudgePoints 1, x: %s, y: %s, d: %s', $x, $y, $dimension)); } $nudged = false; @@ -87,7 +87,7 @@ final class GridSampler{ $y = (int)$points[$offset + 1]; if($x < -1 || $x > $dimension || $y < -1 || $y > $dimension){ - throw new RuntimeException(sprintf('checkAndNudgePoints 2, x: %s, y: %s, d: %s', $x, $y, $dimension)); + throw new QRCodeDetectorException(sprintf('checkAndNudgePoints 2, x: %s, y: %s, d: %s', $x, $y, $dimension)); } $nudged = false; @@ -118,13 +118,13 @@ final class GridSampler{ * * @return \chillerlan\QRCode\Decoder\BitMatrix representing a grid of points sampled from the image within a region * defined by the "from" parameters - * @throws \RuntimeException if image can't be sampled, for example, if the transformation defined + * @throws \chillerlan\QRCode\Detector\QRCodeDetectorException if image can't be sampled, for example, if the transformation defined * by the given points is invalid or results in sampling outside the image boundaries */ public function sampleGrid(BitMatrix $image, int $dimension, PerspectiveTransform $transform):BitMatrix{ if($dimension <= 0){ - throw new RuntimeException('invalid matrix size'); + throw new QRCodeDetectorException('invalid matrix size'); } $bits = new BitMatrix($dimension); @@ -152,7 +152,7 @@ final class GridSampler{ } } } - catch(Exception $aioobe){//ArrayIndexOutOfBoundsException + catch(Throwable $aioobe){//ArrayIndexOutOfBoundsException // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting // transform gets "twisted" such that it maps a straight line of points to a set of points // whose endpoints are in bounds, but others are not. There is probably some mathematical @@ -160,7 +160,7 @@ final class GridSampler{ // This results in an ugly runtime exception despite our clever checks above -- can't have // that. We could check each point's coordinates but that feels duplicative. We settle for // catching and wrapping ArrayIndexOutOfBoundsException. - throw new RuntimeException('ArrayIndexOutOfBoundsException'); + throw new QRCodeDetectorException('ArrayIndexOutOfBoundsException'); } } diff --git a/src/Detector/QRCodeDetectorException.php b/src/Detector/QRCodeDetectorException.php new file mode 100644 index 000000000..87834ebcb --- /dev/null +++ b/src/Detector/QRCodeDetectorException.php @@ -0,0 +1,15 @@ + + * @copyright 2021 smiley + * @license MIT + */ + +namespace chillerlan\QRCode\Detector; + +use chillerlan\QRCode\QRCodeException; + +class QRCodeDetectorException extends QRCodeException{}