summaryrefslogtreecommitdiffstats
path: root/vendor/maxmind-db/reader/src/MaxMind/Db/Reader
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2024-05-27 13:08:29 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2024-05-27 13:08:29 +0200
commit75160b12821f7f4299cce7f0b69c83c1502ae071 (patch)
tree27e25e4ccaef45f0c58b22831164050d1af1d4db /vendor/maxmind-db/reader/src/MaxMind/Db/Reader
parentprvi-commit (diff)
download1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.gz
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.bz2
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.lz
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.xz
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.tar.zst
1ka-75160b12821f7f4299cce7f0b69c83c1502ae071.zip
Diffstat (limited to 'vendor/maxmind-db/reader/src/MaxMind/Db/Reader')
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php134
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php9
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php156
-rw-r--r--vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php11
4 files changed, 201 insertions, 109 deletions
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
index 8f451b8..8786a01 100644
--- a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Decoder.php
@@ -5,14 +5,6 @@ declare(strict_types=1);
namespace MaxMind\Db\Reader;
// @codingStandardsIgnoreLine
-use RuntimeException;
-
-/*
- * @ignore
- *
- * We subtract 1 from the log to protect against precision loss.
- */
-\define(__NAMESPACE__ . '\_MM_MAX_INT_BYTES', (int) ((log(\PHP_INT_MAX, 2) - 1) / 8));
class Decoder
{
@@ -20,20 +12,19 @@ class Decoder
* @var resource
*/
private $fileStream;
+
/**
* @var int
*/
private $pointerBase;
- /**
- * @var float
- */
- private $pointerBaseByteSize;
+
/**
* This is only used for unit testing.
*
* @var bool
*/
private $pointerTestHack;
+
/**
* @var bool
*/
@@ -51,8 +42,8 @@ class Decoder
private const _UINT64 = 9;
private const _UINT128 = 10;
private const _ARRAY = 11;
- private const _CONTAINER = 12;
- private const _END_MARKER = 13;
+ // 12 is the container type
+ // 13 is the end marker type
private const _BOOLEAN = 14;
private const _FLOAT = 15;
@@ -67,7 +58,6 @@ class Decoder
$this->fileStream = $fileStream;
$this->pointerBase = $pointerBase;
- $this->pointerBaseByteSize = $pointerBase > 0 ? log($pointerBase, 2) / 8 : 0;
$this->pointerTestHack = $pointerTestHack;
$this->switchByteOrder = $this->isPlatformLittleEndian();
@@ -118,6 +108,9 @@ class Decoder
return $this->decodeByType($type, $offset, $size);
}
+ /**
+ * @param int<0, max> $size
+ */
private function decodeByType(int $type, int $offset, int $size): array
{
switch ($type) {
@@ -195,7 +188,13 @@ class Decoder
{
// This assumes IEEE 754 doubles, but most (all?) modern platforms
// use them.
- [, $double] = unpack('E', $bytes);
+ $rc = unpack('E', $bytes);
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack a double value from the given bytes.'
+ );
+ }
+ [, $double] = $rc;
return $double;
}
@@ -204,7 +203,13 @@ class Decoder
{
// This assumes IEEE 754 floats, but most (all?) modern platforms
// use them.
- [, $float] = unpack('G', $bytes);
+ $rc = unpack('G', $bytes);
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack a float value from the given bytes.'
+ );
+ }
+ [, $float] = $rc;
return $float;
}
@@ -231,7 +236,13 @@ class Decoder
);
}
- [, $int] = unpack('l', $this->maybeSwitchByteOrder($bytes));
+ $rc = unpack('l', $this->maybeSwitchByteOrder($bytes));
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack a 32bit integer value from the given bytes.'
+ );
+ }
+ [, $int] = $rc;
return $int;
}
@@ -254,19 +265,31 @@ class Decoder
$pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
- $offset = $offset + $pointerSize;
+ $offset += $pointerSize;
switch ($pointerSize) {
case 1:
$packed = \chr($ctrlByte & 0x7) . $buffer;
- [, $pointer] = unpack('n', $packed);
+ $rc = unpack('n', $packed);
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack an unsigned short value from the given bytes (pointerSize is 1).'
+ );
+ }
+ [, $pointer] = $rc;
$pointer += $this->pointerBase;
break;
case 2:
$packed = "\x00" . \chr($ctrlByte & 0x7) . $buffer;
- [, $pointer] = unpack('N', $packed);
+ $rc = unpack('N', $packed);
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack an unsigned long value from the given bytes (pointerSize is 2).'
+ );
+ }
+ [, $pointer] = $rc;
$pointer += $this->pointerBase + 2048;
break;
@@ -276,7 +299,13 @@ class Decoder
// It is safe to use 'N' here, even on 32 bit machines as the
// first bit is 0.
- [, $pointer] = unpack('N', $packed);
+ $rc = unpack('N', $packed);
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack an unsigned long value from the given bytes (pointerSize is 3).'
+ );
+ }
+ [, $pointer] = $rc;
$pointer += $this->pointerBase + 526336;
break;
@@ -291,7 +320,7 @@ class Decoder
if (\PHP_INT_MAX - $pointerBase >= $pointerOffset) {
$pointer = $pointerOffset + $pointerBase;
} else {
- throw new RuntimeException(
+ throw new \RuntimeException(
'The database offset is too large to be represented on your platform.'
);
}
@@ -314,37 +343,44 @@ class Decoder
return 0;
}
- $integer = 0;
-
- // PHP integers are signed. _MM_MAX_INT_BYTES is the number of
+ // PHP integers are signed. PHP_INT_SIZE - 1 is the number of
// complete bytes that can be converted to an integer. However,
// we can convert another byte if the leading bit is zero.
- $useRealInts = $byteLength <= _MM_MAX_INT_BYTES
- || ($byteLength === _MM_MAX_INT_BYTES + 1 && (\ord($bytes[0]) & 0x80) === 0);
+ $useRealInts = $byteLength <= \PHP_INT_SIZE - 1
+ || ($byteLength === \PHP_INT_SIZE && (\ord($bytes[0]) & 0x80) === 0);
+
+ if ($useRealInts) {
+ $integer = 0;
+ for ($i = 0; $i < $byteLength; ++$i) {
+ $part = \ord($bytes[$i]);
+ $integer = ($integer << 8) + $part;
+ }
+ return $integer;
+ }
+
+ // We only use gmp or bcmath if the final value is too big
+ $integerAsString = '0';
for ($i = 0; $i < $byteLength; ++$i) {
$part = \ord($bytes[$i]);
- // We only use gmp or bcmath if the final value is too big
- if ($useRealInts) {
- $integer = ($integer << 8) + $part;
- } elseif (\extension_loaded('gmp')) {
- $integer = gmp_strval(gmp_add(gmp_mul((string) $integer, '256'), $part));
+ if (\extension_loaded('gmp')) {
+ $integerAsString = gmp_strval(gmp_add(gmp_mul($integerAsString, '256'), $part));
} elseif (\extension_loaded('bcmath')) {
- $integer = bcadd(bcmul((string) $integer, '256'), (string) $part);
+ $integerAsString = bcadd(bcmul($integerAsString, '256'), (string) $part);
} else {
- throw new RuntimeException(
+ throw new \RuntimeException(
'The gmp or bcmath extension must be installed to read this database.'
);
}
}
- return $integer;
+ return $integerAsString;
}
private function sizeFromCtrlByte(int $ctrlByte, int $offset): array
{
- $size = $ctrlByte & 0x1f;
+ $size = $ctrlByte & 0x1F;
if ($size < 29) {
return [$size, $offset];
@@ -356,10 +392,22 @@ class Decoder
if ($size === 29) {
$size = 29 + \ord($bytes);
} elseif ($size === 30) {
- [, $adjust] = unpack('n', $bytes);
+ $rc = unpack('n', $bytes);
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack an unsigned short value from the given bytes.'
+ );
+ }
+ [, $adjust] = $rc;
$size = 285 + $adjust;
} else {
- [, $adjust] = unpack('N', "\x00" . $bytes);
+ $rc = unpack('N', "\x00" . $bytes);
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack an unsigned long value from the given bytes.'
+ );
+ }
+ [, $adjust] = $rc;
$size = $adjust + 65821;
}
@@ -375,7 +423,13 @@ class Decoder
{
$testint = 0x00FF;
$packed = pack('S', $testint);
+ $rc = unpack('v', $packed);
+ if ($rc === false) {
+ throw new InvalidDatabaseException(
+ 'Could not unpack an unsigned short value from the given bytes.'
+ );
+ }
- return $testint === current(unpack('v', $packed));
+ return $testint === current($rc);
}
}
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
index 543fde4..028e63f 100644
--- a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/InvalidDatabaseException.php
@@ -1,12 +1,11 @@
<?php
-namespace MaxMind\Db\Reader;
+declare(strict_types=1);
-use Exception;
+namespace MaxMind\Db\Reader;
/**
* This class should be thrown when unexpected data is found in the database.
*/
-class InvalidDatabaseException extends Exception
-{
-}
+// phpcs:disable
+class InvalidDatabaseException extends \Exception {}
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
index 94a5592..3c9be87 100644
--- a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Metadata.php
@@ -1,71 +1,108 @@
<?php
+declare(strict_types=1);
+
namespace MaxMind\Db\Reader;
/**
* This class provides the metadata for the MaxMind DB file.
- *
- * @property int $nodeCount This is an unsigned 32-bit
- * integer indicating the number of
- * nodes in the search tree.
- * @property int $recordSize This is an unsigned 16-bit
- * integer. It indicates the number
- * of bits in a record in the search
- * tree. Note that each node
- * consists of two records.
- * @property int $ipVersion This is an unsigned 16-bit
- * integer which is always 4 or 6.
- * It indicates whether the database
- * contains IPv4 or IPv6 address
- * data.
- * @property string $databaseType This is a string that indicates
- * the structure of each data record
- * associated with an IP address.
- * The actual definition of these
- * structures is left up to the
- * database creator.
- * @property array $languages An array of strings, each of
- * which is a language code. A given
- * record may contain data items
- * that have been localized to some
- * or all of these languages. This
- * may be undefined.
- * @property int $binaryFormatMajorVersion This is an unsigned 16-bit
- * integer indicating the major
- * version number for the database's
- * binary format.
- * @property int $binaryFormatMinorVersion This is an unsigned 16-bit
- * integer indicating the minor
- * version number for the database's
- * binary format.
- * @property int $buildEpoch This is an unsigned 64-bit
- * integer that contains the
- * database build timestamp as a
- * Unix epoch value.
- * @property array $description This key will always point to a
- * map (associative array). The keys
- * of that map will be language
- * codes, and the values will be a
- * description in that language as a
- * UTF-8 string. May be undefined
- * for some databases.
*/
class Metadata
{
- private $binaryFormatMajorVersion;
- private $binaryFormatMinorVersion;
- private $buildEpoch;
- private $databaseType;
- private $description;
- private $ipVersion;
- private $languages;
- private $nodeByteSize;
- private $nodeCount;
- private $recordSize;
- private $searchTreeSize;
+ /**
+ * This is an unsigned 16-bit integer indicating the major version number
+ * for the database's binary format.
+ *
+ * @var int
+ */
+ public $binaryFormatMajorVersion;
+
+ /**
+ * This is an unsigned 16-bit integer indicating the minor version number
+ * for the database's binary format.
+ *
+ * @var int
+ */
+ public $binaryFormatMinorVersion;
+
+ /**
+ * This is an unsigned 64-bit integer that contains the database build
+ * timestamp as a Unix epoch value.
+ *
+ * @var int
+ */
+ public $buildEpoch;
+
+ /**
+ * This is a string that indicates the structure of each data record
+ * associated with an IP address. The actual definition of these
+ * structures is left up to the database creator.
+ *
+ * @var string
+ */
+ public $databaseType;
+
+ /**
+ * This key will always point to a map (associative array). The keys of
+ * that map will be language codes, and the values will be a description
+ * in that language as a UTF-8 string. May be undefined for some
+ * databases.
+ *
+ * @var array
+ */
+ public $description;
+
+ /**
+ * This is an unsigned 16-bit integer which is always 4 or 6. It indicates
+ * whether the database contains IPv4 or IPv6 address data.
+ *
+ * @var int
+ */
+ public $ipVersion;
+
+ /**
+ * An array of strings, each of which is a language code. A given record
+ * may contain data items that have been localized to some or all of
+ * these languages. This may be undefined.
+ *
+ * @var array
+ */
+ public $languages;
+
+ /**
+ * @var int
+ */
+ public $nodeByteSize;
- public function __construct($metadata)
+ /**
+ * This is an unsigned 32-bit integer indicating the number of nodes in
+ * the search tree.
+ *
+ * @var int
+ */
+ public $nodeCount;
+
+ /**
+ * This is an unsigned 16-bit integer. It indicates the number of bits in a
+ * record in the search tree. Note that each node consists of two records.
+ *
+ * @var int
+ */
+ public $recordSize;
+
+ /**
+ * @var int
+ */
+ public $searchTreeSize;
+
+ public function __construct(array $metadata)
{
+ if (\func_num_args() !== 1) {
+ throw new \ArgumentCountError(
+ sprintf('%s() expects exactly 1 parameter, %d given', __METHOD__, \func_num_args())
+ );
+ }
+
$this->binaryFormatMajorVersion =
$metadata['binary_format_major_version'];
$this->binaryFormatMinorVersion =
@@ -80,9 +117,4 @@ class Metadata
$this->nodeByteSize = $this->recordSize / 4;
$this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
}
-
- public function __get($var)
- {
- return $this->$var;
- }
}
diff --git a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
index 149a5c4..b8c461e 100644
--- a/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
+++ b/vendor/maxmind-db/reader/src/MaxMind/Db/Reader/Util.php
@@ -1,10 +1,16 @@
<?php
+declare(strict_types=1);
+
namespace MaxMind\Db\Reader;
class Util
{
- public static function read($stream, $offset, $numberOfBytes)
+ /**
+ * @param resource $stream
+ * @param int<0, max> $numberOfBytes
+ */
+ public static function read($stream, int $offset, int $numberOfBytes): string
{
if ($numberOfBytes === 0) {
return '';
@@ -15,10 +21,11 @@ class Util
// We check that the number of bytes read is equal to the number
// asked for. We use ftell as getting the length of $value is
// much slower.
- if (ftell($stream) - $offset === $numberOfBytes) {
+ if ($value !== false && ftell($stream) - $offset === $numberOfBytes) {
return $value;
}
}
+
throw new InvalidDatabaseException(
'The MaxMind DB file contains bad data'
);