Initial Commit

This commit is contained in:
David Stone committed 2024-11-30 18:24:12 -07:00
commit e8f7955c1c
5432 files changed
+1397750

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
<?php
declare (strict_types=1);
namespace WP_Ultimo\Dependencies\Amp\Http;
use WP_Ultimo\Dependencies\Amp\Http\Internal\HPackNative;
use WP_Ultimo\Dependencies\Amp\Http\Internal\HPackNghttp2;
/**
* @psalm-type HeaderArray = list<array{string, string}>
*/
final class HPack
{
/** @var HPackNative|HPackNghttp2 */
private $implementation;
public function __construct(int $tableSizeLimit = 4096)
{
if (HPackNghttp2::isSupported()) {
$this->implementation = new HPackNghttp2($tableSizeLimit);
} else {
$this->implementation = new HPackNative($tableSizeLimit);
}
}
/**
* @param string $input Input to decode.
* @param int $maxSize Maximum deflated size.
*
* @return array|null Decoded headers.
*/
public function decode(string $input, int $maxSize) : ?array
{
return $this->implementation->decode($input, $maxSize);
}
/**
* @param HeaderArray $headers Headers to encode.
*
* @return string Encoded headers.
*
* @throws HPackException If encoding fails.
*/
public function encode(array $headers) : string
{
return $this->implementation->encode($headers);
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
declare (strict_types=1);
namespace WP_Ultimo\Dependencies\Amp\Http;
final class HPackException extends \Exception
{
}
File diff suppressed because it is too large. Load diff
+203
View File
@@ -0,0 +1,203 @@
<?php
declare (strict_types=1);
namespace WP_Ultimo\Dependencies\Amp\Http\Internal;
use WP_Ultimo\Dependencies\Amp\Http\HPack;
use WP_Ultimo\Dependencies\Amp\Http\HPackException;
use FFI;
/**
* @internal
* @psalm-import-type HeaderArray from HPack
*/
final class HPackNghttp2
{
private const FLAG_NO_INDEX = 0x1;
private const FLAG_NO_COPY_NAME = 0x2;
private const FLAG_NO_COPY_VALUE = 0x4;
private const FLAG_NO_COPY = self::FLAG_NO_COPY_NAME | self::FLAG_NO_COPY_VALUE;
private const FLAG_NO_COPY_SENSITIVE = self::FLAG_NO_COPY | self::FLAG_NO_INDEX;
private const SENSITIVE_HEADERS = ['authorization' => self::FLAG_NO_COPY_SENSITIVE, 'cookie' => self::FLAG_NO_COPY_SENSITIVE, 'proxy-authorization' => self::FLAG_NO_COPY_SENSITIVE, 'set-cookie' => self::FLAG_NO_COPY_SENSITIVE];
private static $ffi;
private static $deflatePtrType;
private static $inflatePtrType;
private static $nvType;
private static $nvSize;
private static $charType;
private static $uint8Type;
private static $uint8PtrType;
private static $decodeNv;
private static $decodeNvPtr;
private static $decodeFlags;
private static $decodeFlagsPtr;
private static $supported;
public static function isSupported() : bool
{
if (isset(self::$supported)) {
return self::$supported;
}
if (!\extension_loaded('ffi')) {
return self::$supported = \false;
}
if (!\class_exists(FFI::class)) {
return self::$supported = \false;
}
try {
self::init();
return self::$supported = \true;
} catch (\Throwable $e) {
return self::$supported = \false;
}
}
private static function init() : void
{
if (self::$ffi !== null) {
return;
}
$header = \file_get_contents(__DIR__ . '/amp-hpack.h');
$files = ['libnghttp2.so.14', 'libnghttp2.so', 'libnghttp2.dylib', '/opt/homebrew/lib/libnghttp2.dylib'];
$error = null;
foreach ($files as $file) {
try {
self::$ffi = FFI::cdef($header, $file);
$error = null;
break;
} catch (\Throwable $exception) {
$error = $error ?? $exception;
}
}
if ($error) {
throw $error;
}
self::$deflatePtrType = self::$ffi->type('nghttp2_hd_deflater*');
self::$inflatePtrType = self::$ffi->type('nghttp2_hd_inflater*');
self::$nvType = self::$ffi->type('nghttp2_nv');
self::$nvSize = FFI::sizeof(self::$nvType);
self::$charType = self::$ffi->type('char');
self::$uint8Type = self::$ffi->type('uint8_t');
self::$uint8PtrType = self::$ffi->type('uint8_t*');
self::$decodeNv = self::$ffi->new(self::$nvType);
self::$decodeNvPtr = FFI::addr(self::$decodeNv);
self::$decodeFlags = self::$ffi->new('int');
self::$decodeFlagsPtr = FFI::addr(self::$decodeFlags);
}
private static function createBufferFromString(string $value) : ?FFI\CData
{
$length = \strlen($value);
if (!$length) {
return null;
}
$buffer = self::$ffi->new(FFI::arrayType(self::$uint8Type, [$length]));
FFI::memcpy($buffer, $value, $length);
return $buffer;
}
private $deflatePtr;
private $inflatePtr;
/**
* @param int $maxSize Upper limit on table size.
*/
public function __construct(int $maxSize = 4096)
{
self::init();
$this->deflatePtr = self::$ffi->new(self::$deflatePtrType);
$this->inflatePtr = self::$ffi->new(self::$inflatePtrType);
$return = self::$ffi->nghttp2_hd_deflate_new(FFI::addr($this->deflatePtr), $maxSize);
if ($return !== 0) {
throw new \RuntimeException('Failed to init deflate context');
}
$return = self::$ffi->nghttp2_hd_inflate_new(FFI::addr($this->inflatePtr));
if ($return !== 0) {
throw new \RuntimeException('Failed to init inflate context');
}
}
/**
* @param string $input Encoded headers.
* @param int $maxSize Maximum length of the decoded header string.
*
* @return string[][]|null Returns null if decoding fails or if $maxSize is exceeded.
*/
public function decode(string $input, int $maxSize) : ?array
{
$ffi = self::$ffi;
$pair = self::$decodeNv;
$pairPtr = self::$decodeNvPtr;
$flags = self::$decodeFlags;
$flagsPtr = self::$decodeFlagsPtr;
$inflate = $this->inflatePtr;
$size = 0;
$bufferLength = \strlen($input);
$buffer = self::createBufferFromString($input);
if ($buffer === null) {
return [];
}
$offset = 0;
$bufferPtr = $ffi->cast(self::$uint8PtrType, $buffer);
$headers = [];
while (\true) {
$read = $ffi->nghttp2_hd_inflate_hd2($inflate, $pairPtr, $flagsPtr, $bufferPtr, $bufferLength - $offset, 1);
if ($read < 0) {
return null;
}
$offset += $read;
$bufferPtr += $read;
$cFlags = $flags->cdata;
if ($cFlags & 0x2) {
// NGHTTP2_HD_INFLATE_EMIT
$nameLength = $pair->namelen;
$valueLength = $pair->valuelen;
$headers[] = [FFI::string($pair->name, $nameLength), FFI::string($pair->value, $valueLength)];
$size += $nameLength + $valueLength;
if ($size > $maxSize) {
return null;
}
}
if ($cFlags & 0x1) {
// NGHTTP2_HD_INFLATE_FINAL
$ffi->nghttp2_hd_inflate_end_headers($inflate);
FFI::memset($pair, 0, self::$nvSize);
return $headers;
}
if ($read === 0 || $offset > $bufferLength) {
return null;
}
}
return null;
}
/**
* @param HeaderArray $headers
*
* @return string Encoded headers.
*/
public function encode(array $headers) : string
{
$ffi = self::$ffi;
// To keep memory buffers
$buffers = [];
$headerCount = \count($headers);
$current = 0;
$pairs = $ffi->new(FFI::arrayType(self::$nvType, [$headerCount]));
foreach ($headers as $index => [$name, $value]) {
\assert($index === $current);
$name = (string) $name;
$value = (string) $value;
$pair = $pairs[$current];
$nameBuffer = self::createBufferFromString($name);
$valueBuffer = self::createBufferFromString($value);
$pair->name = $ffi->cast(self::$uint8PtrType, $nameBuffer);
$pair->namelen = \strlen($name);
$pair->value = $ffi->cast(self::$uint8PtrType, $valueBuffer);
$pair->valuelen = \strlen($value);
$pair->flags = self::SENSITIVE_HEADERS[$name] ?? self::FLAG_NO_COPY;
$buffers[] = $nameBuffer;
$buffers[] = $valueBuffer;
$current++;
}
$bufferLength = $ffi->nghttp2_hd_deflate_bound($this->deflatePtr, $pairs, $headerCount);
$buffer = $ffi->new(FFI::arrayType(self::$uint8Type, [$bufferLength]));
$bufferLength = $ffi->nghttp2_hd_deflate_hd($this->deflatePtr, $buffer, $bufferLength, $pairs, $headerCount);
if ($bufferLength < 0) {
throw new HPackException('Failed to compress headers using nghttp2');
}
return FFI::string($buffer, $bufferLength);
}
}
+29
View File
@@ -0,0 +1,29 @@
#define FFI_SCOPE "amphp-hpack-nghttp2"
#define FFI_LIB "libnghttp2.so"
typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
typedef struct nghttp2_hd_inflater nghttp2_hd_inflater;
typedef struct {
uint8_t *name;
uint8_t *value;
size_t namelen;
size_t valuelen;
uint8_t flags;
} nghttp2_nv;
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr, size_t deflate_hd_table_bufsize_max);
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf, size_t buflen, const nghttp2_nv *nva, size_t nvlen);
size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, const nghttp2_nv *nva, size_t nvlen);
int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out, int *inflate_flags, const uint8_t *in, size_t inlen, int in_final);
int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
@@ -0,0 +1,6 @@
<?php
declare (strict_types=1);
namespace WP_Ultimo\Dependencies;
return [["\x00" => ["\xff", "\xc0"], "\x01" => ["\xff", "\xff", "\xb0"], "\x02" => ["\xff", "\xff", "\xfe", " "], "\x03" => ["\xff", "\xff", "\xfe", "0"], "\x04" => ["\xff", "\xff", "\xfe", "@"], "\x05" => ["\xff", "\xff", "\xfe", "P"], "\x06" => ["\xff", "\xff", "\xfe", "`"], "\x07" => ["\xff", "\xff", "\xfe", "p"], "\x08" => ["\xff", "\xff", "\xfe", "\x80"], "\t" => ["\xff", "\xff", "\xea"], "\n" => ["\xff", "\xff", "\xff", "\xf0"], "\v" => ["\xff", "\xff", "\xfe", "\x90"], "\f" => ["\xff", "\xff", "\xfe", "\xa0"], "\r" => ["\xff", "\xff", "\xff", "\xf4"], "\x0e" => ["\xff", "\xff", "\xfe", "\xb0"], "\x0f" => ["\xff", "\xff", "\xfe", "\xc0"], "\x10" => ["\xff", "\xff", "\xfe", "\xd0"], "\x11" => ["\xff", "\xff", "\xfe", "\xe0"], "\x12" => ["\xff", "\xff", "\xfe", "\xf0"], "\x13" => ["\xff", "\xff", "\xff", "\x00"], "\x14" => ["\xff", "\xff", "\xff", "\x10"], "\x15" => ["\xff", "\xff", "\xff", " "], "\x16" => ["\xff", "\xff", "\xff", "\xf8"], "\x17" => ["\xff", "\xff", "\xff", "0"], "\x18" => ["\xff", "\xff", "\xff", "@"], "\x19" => ["\xff", "\xff", "\xff", "P"], "\x1a" => ["\xff", "\xff", "\xff", "`"], "\x1b" => ["\xff", "\xff", "\xff", "p"], "\x1c" => ["\xff", "\xff", "\xff", "\x80"], "\x1d" => ["\xff", "\xff", "\xff", "\x90"], "\x1e" => ["\xff", "\xff", "\xff", "\xa0"], "\x1f" => ["\xff", "\xff", "\xff", "\xb0"], " " => ["P"], "!" => ["\xfe", "\x00"], "\"" => ["\xfe", "@"], "#" => ["\xff", "\xa0"], "\$" => ["\xff", "\xc8"], "%" => ["T"], "&" => ["\xf8"], "'" => ["\xff", "@"], "(" => ["\xfe", "\x80"], ")" => ["\xfe", "\xc0"], "*" => ["\xf9"], "+" => ["\xff", "`"], "," => ["\xfa"], "-" => ["X"], "." => ["\\"], "/" => ["`"], ["\x00"], ["\x08"], ["\x10"], ["d"], ["h"], ["l"], ["p"], ["t"], ["x"], ["|"], ":" => ["\xb8"], ";" => ["\xfb"], "<" => ["\xff", "\xf8"], "=" => ["\x80"], ">" => ["\xff", "\xb0"], "?" => ["\xff", "\x00"], "@" => ["\xff", "\xd0"], "A" => ["\x84"], "B" => ["\xba"], "C" => ["\xbc"], "D" => ["\xbe"], "E" => ["\xc0"], "F" => ["\xc2"], "G" => ["\xc4"], "H" => ["\xc6"], "I" => ["\xc8"], "J" => ["\xca"], "K" => ["\xcc"], "L" => ["\xce"], "M" => ["\xd0"], "N" => ["\xd2"], "O" => ["\xd4"], "P" => ["\xd6"], "Q" => ["\xd8"], "R" => ["\xda"], "S" => ["\xdc"], "T" => ["\xde"], "U" => ["\xe0"], "V" => ["\xe2"], "W" => ["\xe4"], "X" => ["\xfc"], "Y" => ["\xe6"], "Z" => ["\xfd"], "[" => ["\xff", "\xd8"], "\\" => ["\xff", "\xfe", "\x00"], "]" => ["\xff", "\xe0"], "^" => ["\xff", "\xf0"], "_" => ["\x88"], "`" => ["\xff", "\xfa"], "a" => ["\x18"], "b" => ["\x8c"], "c" => [" "], "d" => ["\x90"], "e" => ["("], "f" => ["\x94"], "g" => ["\x98"], "h" => ["\x9c"], "i" => ["0"], "j" => ["\xe8"], "k" => ["\xea"], "l" => ["\xa0"], "m" => ["\xa4"], "n" => ["\xa8"], "o" => ["8"], "p" => ["\xac"], "q" => ["\xec"], "r" => ["\xb0"], "s" => ["@"], "t" => ["H"], "u" => ["\xb4"], "v" => ["\xee"], "w" => ["\xf0"], "x" => ["\xf2"], "y" => ["\xf4"], "z" => ["\xf6"], "{" => ["\xff", "\xfc"], "|" => ["\xff", "\x80"], "}" => ["\xff", "\xf4"], "~" => ["\xff", "\xe8"], "" => ["\xff", "\xff", "\xff", "\xc0"], "\x80" => ["\xff", "\xfe", "`"], "\x81" => ["\xff", "\xff", "H"], "\x82" => ["\xff", "\xfe", "p"], "\x83" => ["\xff", "\xfe", "\x80"], "\x84" => ["\xff", "\xff", "L"], "\x85" => ["\xff", "\xff", "P"], "\x86" => ["\xff", "\xff", "T"], "\x87" => ["\xff", "\xff", "\xb2"], "\x88" => ["\xff", "\xff", "X"], "\x89" => ["\xff", "\xff", "\xb4"], "\x8a" => ["\xff", "\xff", "\xb6"], "\x8b" => ["\xff", "\xff", "\xb8"], "\x8c" => ["\xff", "\xff", "\xba"], "\x8d" => ["\xff", "\xff", "\xbc"], "\x8e" => ["\xff", "\xff", "\xeb"], "\x8f" => ["\xff", "\xff", "\xbe"], "\x90" => ["\xff", "\xff", "\xec"], "\x91" => ["\xff", "\xff", "\xed"], "\x92" => ["\xff", "\xff", "\\"], "\x93" => ["\xff", "\xff", "\xc0"], "\x94" => ["\xff", "\xff", "\xee"], "\x95" => ["\xff", "\xff", "\xc2"], "\x96" => ["\xff", "\xff", "\xc4"], "\x97" => ["\xff", "\xff", "\xc6"], "\x98" => ["\xff", "\xff", "\xc8"], "\x99" => ["\xff", "\xfe", "\xe0"], "\x9a" => ["\xff", "\xff", "`"], "\x9b" => ["\xff", "\xff", "\xca"], "\x9c" => ["\xff", "\xff", "d"], "\x9d" => ["\xff", "\xff", "\xcc"], "\x9e" => ["\xff", "\xff", "\xce"], "\x9f" => ["\xff", "\xff", "\xef"], "\xa0" => ["\xff", "\xff", "h"], "\xa1" => ["\xff", "\xfe", "\xe8"], "\xa2" => ["\xff", "\xfe", "\x90"], "\xa3" => ["\xff", "\xff", "l"], "\xa4" => ["\xff", "\xff", "p"], "\xa5" => ["\xff", "\xff", "\xd0"], "\xa6" => ["\xff", "\xff", "\xd2"], "\xa7" => ["\xff", "\xfe", "\xf0"], "\xa8" => ["\xff", "\xff", "\xd4"], "\xa9" => ["\xff", "\xff", "t"], "\xaa" => ["\xff", "\xff", "x"], "\xab" => ["\xff", "\xff", "\xf0"], "\xac" => ["\xff", "\xfe", "\xf8"], "\xad" => ["\xff", "\xff", "|"], "\xae" => ["\xff", "\xff", "\xd6"], "\xaf" => ["\xff", "\xff", "\xd8"], "\xb0" => ["\xff", "\xff", "\x00"], "\xb1" => ["\xff", "\xff", "\x08"], "\xb2" => ["\xff", "\xff", "\x80"], "\xb3" => ["\xff", "\xff", "\x10"], "\xb4" => ["\xff", "\xff", "\xda"], "\xb5" => ["\xff", "\xff", "\x84"], "\xb6" => ["\xff", "\xff", "\xdc"], "\xb7" => ["\xff", "\xffLine truncated
@@ -0,0 +1,6 @@
<?php
declare (strict_types=1);
namespace WP_Ultimo\Dependencies;
return [["\x00" => [93, "0"], "\x01" => [138, "0"], "\x02" => [75, "0"], "\x03" => [91, "0"], "\x04" => [108, "0"], "\x05" => [103, "0"], "\x06" => [114, "0"], "\x07" => [14, "0"], "\x08" => [93, "1"], "\t" => [138, "1"], "\n" => [75, "1"], "\v" => [91, "1"], "\f" => [108, "1"], "\r" => [103, "1"], "\x0e" => [114, "1"], "\x0f" => [14, "1"], "\x10" => [93, "2"], "\x11" => [138, "2"], "\x12" => [75, "2"], "\x13" => [91, "2"], "\x14" => [108, "2"], "\x15" => [103, "2"], "\x16" => [114, "2"], "\x17" => [14, "2"], "\x18" => [93, "a"], "\x19" => [138, "a"], "\x1a" => [75, "a"], "\x1b" => [91, "a"], "\x1c" => [108, "a"], "\x1d" => [103, "a"], "\x1e" => [114, "a"], "\x1f" => [14, "a"], " " => [93, "c"], "!" => [138, "c"], "\"" => [75, "c"], "#" => [91, "c"], "\$" => [108, "c"], "%" => [103, "c"], "&" => [114, "c"], "'" => [14, "c"], "(" => [93, "e"], ")" => [138, "e"], "*" => [75, "e"], "+" => [91, "e"], "," => [108, "e"], "-" => [103, "e"], "." => [114, "e"], "/" => [14, "e"], [93, "i"], [138, "i"], [75, "i"], [91, "i"], [108, "i"], [103, "i"], [114, "i"], [14, "i"], [93, "o"], [138, "o"], ":" => [75, "o"], ";" => [91, "o"], "<" => [108, "o"], "=" => [103, "o"], ">" => [114, "o"], "?" => [14, "o"], "@" => [93, "s"], "A" => [138, "s"], "B" => [75, "s"], "C" => [91, "s"], "D" => [108, "s"], "E" => [103, "s"], "F" => [114, "s"], "G" => [14, "s"], "H" => [93, "t"], "I" => [138, "t"], "J" => [75, "t"], "K" => [91, "t"], "L" => [108, "t"], "M" => [103, "t"], "N" => [114, "t"], "O" => [14, "t"], "P" => [94, " "], "Q" => [76, " "], "R" => [104, " "], "S" => [16, " "], "T" => [94, "%"], "U" => [76, "%"], "V" => [104, "%"], "W" => [16, "%"], "X" => [94, "-"], "Y" => [76, "-"], "Z" => [104, "-"], "[" => [16, "-"], "\\" => [94, "."], "]" => [76, "."], "^" => [104, "."], "_" => [16, "."], "`" => [94, "/"], "a" => [76, "/"], "b" => [104, "/"], "c" => [16, "/"], "d" => [94, "3"], "e" => [76, "3"], "f" => [104, "3"], "g" => [16, "3"], "h" => [94, "4"], "i" => [76, "4"], "j" => [104, "4"], "k" => [16, "4"], "l" => [94, "5"], "m" => [76, "5"], "n" => [104, "5"], "o" => [16, "5"], "p" => [94, "6"], "q" => [76, "6"], "r" => [104, "6"], "s" => [16, "6"], "t" => [94, "7"], "u" => [76, "7"], "v" => [104, "7"], "w" => [16, "7"], "x" => [94, "8"], "y" => [76, "8"], "z" => [104, "8"], "{" => [16, "8"], "|" => [94, "9"], "}" => [76, "9"], "~" => [104, "9"], "" => [16, "9"], "\x80" => [94, "="], "\x81" => [76, "="], "\x82" => [104, "="], "\x83" => [16, "="], "\x84" => [94, "A"], "\x85" => [76, "A"], "\x86" => [104, "A"], "\x87" => [16, "A"], "\x88" => [94, "_"], "\x89" => [76, "_"], "\x8a" => [104, "_"], "\x8b" => [16, "_"], "\x8c" => [94, "b"], "\x8d" => [76, "b"], "\x8e" => [104, "b"], "\x8f" => [16, "b"], "\x90" => [94, "d"], "\x91" => [76, "d"], "\x92" => [104, "d"], "\x93" => [16, "d"], "\x94" => [94, "f"], "\x95" => [76, "f"], "\x96" => [104, "f"], "\x97" => [16, "f"], "\x98" => [94, "g"], "\x99" => [76, "g"], "\x9a" => [104, "g"], "\x9b" => [16, "g"], "\x9c" => [94, "h"], "\x9d" => [76, "h"], "\x9e" => [104, "h"], "\x9f" => [16, "h"], "\xa0" => [94, "l"], "\xa1" => [76, "l"], "\xa2" => [104, "l"], "\xa3" => [16, "l"], "\xa4" => [94, "m"], "\xa5" => [76, "m"], "\xa6" => [104, "m"], "\xa7" => [16, "m"], "\xa8" => [94, "n"], "\xa9" => [76, "n"], "\xaa" => [104, "n"], "\xab" => [16, "n"], "\xac" => [94, "p"], "\xad" => [76, "p"], "\xae" => [104, "p"], "\xaf" => [16, "p"], "\xb0" => [94, "r"], "\xb1" => [76, "r"], "\xb2" => [104, "r"], "\xb3" => [16, "r"], "\xb4" => [94, "u"], "\xb5" => [76, "u"], "\xb6" => [104, "u"], "\xb7" => [16, "u"], "\xb8" => [77, ":"], "\xb9" => [18, ":"], "\xba" => [77, "B"], "\xbb" => [18, "B"], "\xbc" => [77, "C"], "\xbd" => [18, "C"], "\xbe" => [77, "D"], "\xbf" => [18, "D"], "\xc0" => [77, "E"], "\xc1" => [18, "E"], "\xc2" => [77, "F"], "\xc3" => [18, "F"], "\xc4" => [77, "G"], "\xc5" => [18, "G"], "\xc6" => [77, "H"], "\xc7" => [18, "H"], "\xc8" => [77, "I"], "\xc9" => [18, "I"], "\xca" => [77, "J"], "\xcb" => [18, "J"], "\xcc" => [77, "K"], "\xcd" => [18, "K"], "\xce" => [77, "L"], "\xcf" => [18, "L"], "\xd0" => [77, "M"], "\xd1" => [18, "M"], "\xd2" => [77, "N"], "\xd3" => [18, "N"], "\xd4" => [77, "O"], "\xd5" => [18, "O"], "\xd6" => [77, "P"], "\xd7" => [18, "P"], "\xd8" => [77, "Q"], "\xd9" => [18, "Q"], "\xda" => [77, "R"], "\xdb" => [18, "R"], "\xdc" => [77, "S"], "\xdd" => [18, "S"], "\xde" => [77, "T"], "\xdf" => [18, "T"], "\xe0" => [77, "U"], "\xe1" => [18, "U"], "\xe2" => [77, "V"], "\xe3" => [18, "V"], "\xe4" => [77, "W"], "\xe5" => [18, "W"], "\xe6" => [77, "Y"], "\xe7" => [18, "Y"], "\xe8" => [77, "j"], "\xe9" => [18, "j"], "\xea" => [77, "k"], "\xeb" => [18, "k"], "\xec" => [77, "q"], "\xed" => [18, "q"], "\xee" => [77, "v"], "\xef" => [18, "v"], "\xf0" => [77, "w"], "\xf1" => [18, "w"], "\xf2" => [77, "x"], "\xf3" => [18, "x"], "\xf4" => [77, "y"], "\xf5" => [18, "y"], "\xf6" => [77, "z"], "\xf7" => [18, "z"], "\xf8" => [0, "&"], "\xf9" => [0, "*"], "\xfa" => [0, ","], "\xfb" => [0, ";"], "Line truncated