Я пытаюсь декодировать строку в определенном формате (код колоды Hearthstone), используя PHP, например:
AAEBAc2xAgjAAe0E7QX3DdYRh6wC8fsCoIADC8kDqwTLBPsMhRDH0wKW6AK0/ALNiQPXiQOfmwMA
или
AAEBAf0GBAD6DoyAA6CAAw37AZwCigbJB/gHlA+CEIUQrRDy0AL2/QKJgAPRgAMA
Спецификация ( исходное описание ):
Строка данных представляет собой base64
кодированную строку байтов.
в противном случае каждое последующее значение является целым числом, закодированным как unsigned varint
.
Блок заголовка
- Зарезервированный байт 0x00
- Версия (1)
- Формат
Блок данных
Блок данных разбит на четыре пары длины + массив вв следующем порядке:
- Герои
- Карты с одним экземпляром
- Карты с 2 копиями
- Карты с n-копиями
Каждая пара имеет начальный varint
, определяющий количество элементов в массиве.Для первых трех блоков это массивы varints
.Для последнего блока это массив пар varints
.Цель этой структуры - сделать строку данных максимально компактной.
Я начал что-то собирать, но я новичок, когда дело доходит до обработки необработанных байтов.Мой код:
// I found this to decode Variable-length quantity (varint)
function vlq_decode(array $bytes) {
$result = [];
$integer = 0;
foreach ($bytes as $byte) {
if ($integer > 0xfffffff - 0x7f) {
throw new OverflowException('The value exceeds the maximum allowed.');
}
$integer <<= 7;
$integer |= 0x7f & $byte;
if (($byte & 0x80) === 0) {
$result[] = $integer;
$integer = 0;
}
}
if (($byte & 0x80) !== 0) {
throw new InvalidArgumentException('Incomplete byte sequence.');
}
return $result;
}
$datastring = 'AAEBAc2xAgjAAe0E7QX3DdYRh6wC8fsCoIADC8kDqwTLBPsMhRDH0wKW6AK0/ALNiQPXiQOfmwMA';
$raw = base64_decode($datastring);
$byte_array = unpack('C*', $raw);
$result = vlq_decode($byte_array);
print_r($result);
Единственное, в чем я уверен, это base64_decode
.Я не могу сказать, правильные ли параметры unpack
, или работает ли функция vlq_decode
, как предполагалось, потому что я сам ее не написал.
На оригинальном сайте есть эталонные реализации в Python и Javascript, но они у меня над головой, и я не могу использовать код для своей работы.
Обновление:
Код действительно выдает array
, который выглядит примерно так, как я ожидал, но многие значения не кажутся правильными.Я думаю, что преобразование из varint
все еще несколько отклонено.
// this is the $result I get (wrong)
Array (
[0] => 0 // this is always 0
[1] => 1 // Version
[2] => 1 // Format
[3] => 1 // What follows is an array of length 1 (data block Heroes)
[4] => 1267842
[5] => 8 // What follows is an array of length 8 (data block single-copy cards)
[6] => 8193
[7] => 13956
[8] => 13957
[9] => 15245
[10] => 11025
[11] => 120322
[12] => 1867138
[13] => 524291
[14] => 11 // What follows is an array of length 11 (data block 2-copy cards)
[15] => 9347
[16] => 5508
[17] => 9604
[18] => 15756
[19] => 656
[20] => 1173890
[21] => 373762
[22] => 867842
[23] => 1262723
[24] => 1426563
[25] => 511363
[26] => 0 // What follows is an array of length 0 (data block n-copy cards)
)
Реализация Python ( Gist ) выдает разные числа в несколько ином формате, которые хорошо соответствуют база данных , содержащая данные для идентификаторов (в поле dbfId
)
// this is the expected (correct) $result
Array (
[0] => 0
[1] => 1
[2] => 1
[3] => 1
[4] => 39117
[5] => 8
[6] => 192
[7] => 621
[8] => 749
[9] => 1783
[10] => 2262
[11] => 38407
[12] => 48625
[13] => 49184
[14] => 11
[15] => 457
[16] => 555
[17] => 587
[18] => 1659
[19] => 2053
[20] => 43463
[21] => 46102
[22] => 48692
[23] => 50381
[24] => 50391
[25] => 52639
[26] => 0
)
Любая помощь приветствуется!
Там уже есть вопрос по этой теме , но он был плохо написан без примеров кода, поэтому я делаю еще один шаг.