%PDF- %PDF-
Direktori : /www/varak.net/nextcloud.varak.net/apps_old/apps/bookmarks/vendor/rowbot/punycode/src/ |
Current File : //www/varak.net/nextcloud.varak.net/apps_old/apps/bookmarks/vendor/rowbot/punycode/src/Punycode.php |
<?php declare(strict_types=1); namespace Rowbot\Punycode; use Rowbot\Punycode\Exception\InvalidInputException; use Rowbot\Punycode\Exception\OutputSizeExceededException; use Rowbot\Punycode\Exception\OverflowException; use function array_map; use function array_splice; use function chr; use function func_num_args; use function implode; use function intdiv; use function ord; use function str_split; use function strlen; use function strrpos; /** * @see https://tools.ietf.org/html/rfc3492 * @see https://github.com/bestiejs/punycode.js/blob/master/punycode.js * @see https://github.com/unicode-org/icu/blob/master/icu4c/source/common/punycode.cpp * @see https://github.com/unicode-org/icu/blob/master/icu4j/main/classes/core/src/com/ibm/icu/impl/Punycode.java */ final class Punycode { private const BASE = 36; private const TMIN = 1; private const TMAX = 26; private const SKEW = 38; private const DAMP = 700; private const INITIAL_BIAS = 72; private const INITIAL_N = 128; private const DELIMITER = '-'; private const MAX_INT = 2147483647; /** * Contains the numeric value of a basic code point (for use in representing integers) in the * range 0 to BASE-1, or -1 if b is does not represent a value. * * @var array<int, int> */ private static $basicToDigit = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ]; /** * @codeCoverageIgnore */ private function __construct() { } /** * @see https://tools.ietf.org/html/rfc3492#section-6.1 */ private static function adaptBias(int $delta, int $numPoints, bool $firstTime): int { // xxx >> 1 is a faster way of doing intdiv(xxx, 2) $delta = $firstTime ? intdiv($delta, self::DAMP) : $delta >> 1; $delta += intdiv($delta, $numPoints); $k = 0; while ($delta > ((self::BASE - self::TMIN) * self::TMAX) >> 1) { $delta = intdiv($delta, self::BASE - self::TMIN); $k += self::BASE; } return $k + intdiv((self::BASE - self::TMIN + 1) * $delta, $delta + self::SKEW); } /** * @see https://tools.ietf.org/html/rfc3492#section-6.2 * * @param array<int, bool> $caseFlags */ public static function decode(string $input, int $outLength = null, array &$caseFlags = []): string { $n = self::INITIAL_N; $out = 0; $i = 0; $maxOut = $outLength ?? self::MAX_INT; $bias = self::INITIAL_BIAS; $lastDelimIndex = strrpos($input, self::DELIMITER); $b = $lastDelimIndex === false ? 0 : $lastDelimIndex; $inputLength = strlen($input); $output = []; $wantsCaseFlags = func_num_args() > 2; if ($b > $maxOut) { throw new OutputSizeExceededException(); } $bytes = array_map('ord', str_split($input)); for ($j = 0; $j < $b; ++$j) { if ($bytes[$j] > 0x7F) { throw new InvalidInputException(); } if ($wantsCaseFlags) { $caseFlags[$out] = self::flagged($bytes[$j]); } $output[$out++] = $input[$j]; } if ($b > 0) { $b += 1; } for ($in = $b; $in < $inputLength; ++$out) { $oldi = $i; $w = 1; for ($k = self::BASE; /* no condition */; $k += self::BASE) { if ($in >= $inputLength) { throw new InvalidInputException(); } $digit = self::$basicToDigit[$bytes[$in++] & 0xFF]; if ($digit < 0) { throw new InvalidInputException(); } if ($digit > intdiv(self::MAX_INT - $i, $w)) { throw new OverflowException(); } $i += $digit * $w; if ($k <= $bias) { $t = self::TMIN; } elseif ($k >= $bias + self::TMAX) { $t = self::TMAX; } else { $t = $k - $bias; } if ($digit < $t) { break; } $baseMinusT = self::BASE - $t; if ($w > intdiv(self::MAX_INT, $baseMinusT)) { throw new OverflowException(); } $w *= $baseMinusT; } $outPlusOne = $out + 1; $bias = self::adaptBias($i - $oldi, $outPlusOne, $oldi === 0); if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) { throw new OverflowException(); } $n += intdiv($i, $outPlusOne); $i %= $outPlusOne; if ($out >= $maxOut) { throw new OutputSizeExceededException(); } if ($wantsCaseFlags) { array_splice($caseFlags, $i, 0, [self::flagged($bytes[$n - 1])]); } array_splice($output, $i++, 0, [self::encodeCodePoint($n)]); } return implode('', $output); } /** * @see https://tools.ietf.org/html/rfc3492#section-6.3 * * @param array<int, bool> $caseFlags */ public static function encode(string $input, int $outLength = null, array $caseFlags = []): string { $n = self::INITIAL_N; $delta = 0; $out = 0; $maxOut = $outLength ?? self::MAX_INT; $bias = self::INITIAL_BIAS; $inputLength = 0; $output = ''; $codePoints = self::utf8Decode($input); foreach ($codePoints as $j => $codePoint) { ++$inputLength; if ($codePoint < 0x80) { if ($maxOut - $out < 2) { throw new OutputSizeExceededException(); } $output .= isset($caseFlags[$j]) ? self::encodeBasic($codePoint, $caseFlags[$j]) : chr($codePoint); ++$out; } } $h = $out; $b = $out; if ($b > 0) { $output .= self::DELIMITER; ++$out; } while ($h < $inputLength) { $m = self::MAX_INT; foreach ($codePoints as $codePoint) { if ($codePoint >= $n && $codePoint < $m) { $m = $codePoint; } } if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) { throw new OverflowException(); } $delta += ($m - $n) * ($h + 1); $n = $m; foreach ($codePoints as $j => $codePoint) { if ($codePoint < $n && ++$delta === 0) { throw new OverflowException(); } elseif ($codePoint === $n) { $q = $delta; for ($k = self::BASE; /* no condition */; $k += self::BASE) { if ($out >= $maxOut) { throw new OutputSizeExceededException(); } if ($k <= $bias) { $t = self::TMIN; } elseif ($k >= $bias + self::TMAX) { $t = self::TMAX; } else { $t = $k - $bias; } if ($q < $t) { break; } $qMinusT = $q - $t; $baseMinusT = self::BASE - $t; $output .= self::encodeDigit($t + ($qMinusT) % ($baseMinusT), false); ++$out; $q = intdiv($qMinusT, $baseMinusT); } $output .= self::encodeDigit($q, $caseFlags[$j] ?? false); ++$out; $bias = self::adaptBias($delta, $h + 1, $h === $b); $delta = 0; ++$h; } } ++$delta; ++$n; } return $output; } private static function encodeBasic(int $codePoint, bool $flag): string { $codePoint -= ($codePoint - 97 < 26 ? 1 : 0) << 5; return chr($codePoint + ((!$flag && ($codePoint - 65 < 26) ? 1 : 0) << 5)); } /** * Takes a Unicode code point and encodes it. The return behavior is undefined if the given * code point is outside the range 0..10FFFF. * * @see https://encoding.spec.whatwg.org/#utf-8-encoder */ private static function encodeCodePoint(int $codePoint): string { if ($codePoint >= 0x00 && $codePoint <= 0x7F) { return chr($codePoint); } $count = 0; $offset = 0; if ($codePoint >= 0x0080 && $codePoint <= 0x07FF) { $count = 1; $offset = 0xC0; } elseif ($codePoint >= 0x0800 && $codePoint <= 0xFFFF) { $count = 2; $offset = 0xE0; } elseif ($codePoint >= 0x10000 && $codePoint <= 0x10FFFF) { $count = 3; $offset = 0xF0; } $bytes = chr(($codePoint >> (6 * $count)) + $offset); while ($count > 0) { $temp = $codePoint >> (6 * ($count - 1)); $bytes .= chr(0x80 | ($temp & 0x3F)); --$count; } return $bytes; } private static function encodeDigit(int $d, bool $flag): string { return chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5)); } private static function flagged(int $codePoint): bool { return $codePoint - 65 < 26; } /** * Takes a UTF-8 encoded string and converts it into a series of integer code points. Any * invalid byte sequences will be replaced by a U+FFFD replacement code point. * * @see https://encoding.spec.whatwg.org/#utf-8-decoder * * @return array<int, int> */ private static function utf8Decode(string $input): array { $bytesSeen = 0; $bytesNeeded = 0; $lowerBoundary = 0x80; $upperBoundary = 0xBF; $codePoint = 0; $codePoints = []; $length = strlen($input); for ($i = 0; $i < $length; ++$i) { $byte = ord($input[$i]); if ($bytesNeeded === 0) { if ($byte >= 0x00 && $byte <= 0x7F) { $codePoints[] = $byte; continue; } if ($byte >= 0xC2 && $byte <= 0xDF) { $bytesNeeded = 1; $codePoint = $byte & 0x1F; } elseif ($byte >= 0xE0 && $byte <= 0xEF) { if ($byte === 0xE0) { $lowerBoundary = 0xA0; } elseif ($byte === 0xED) { $upperBoundary = 0x9F; } $bytesNeeded = 2; $codePoint = $byte & 0xF; } elseif ($byte >= 0xF0 && $byte <= 0xF4) { if ($byte === 0xF0) { $lowerBoundary = 0x90; } elseif ($byte === 0xF4) { $upperBoundary = 0x8F; } $bytesNeeded = 3; $codePoint = $byte & 0x7; } else { $codePoints[] = 0xFFFD; } continue; } if ($byte < $lowerBoundary || $byte > $upperBoundary) { $codePoint = 0; $bytesNeeded = 0; $bytesSeen = 0; $lowerBoundary = 0x80; $upperBoundary = 0xBF; --$i; $codePoints[] = 0xFFFD; continue; } $lowerBoundary = 0x80; $upperBoundary = 0xBF; $codePoint = ($codePoint << 6) | ($byte & 0x3F); if (++$bytesSeen !== $bytesNeeded) { continue; } $codePoints[] = $codePoint; $codePoint = 0; $bytesNeeded = 0; $bytesSeen = 0; } // String unexpectedly ended, so append a U+FFFD code point. if ($bytesNeeded !== 0) { $codePoints[] = 0xFFFD; } return $codePoints; } }