Ладно, я потратил примерно два часа на это, а это гораздо больше, чем я планировал потратить на это. Но я был заинтригован.
Я думаю, что вы, возможно, обнаружили законную ошибку в кодировке AMF в ActionScript (или в том, как класс Dictionary
выделяется с помощью AMF). Эта ошибка влияет на все, что использует AMF, поэтому точно такую же ошибку можно воспроизвести с помощью ByteArray
, поэтому я собираюсь использовать ее в демонстрационных целях.
Рассмотрим следующий код:
var d:Dictionary = new Dictionary(false);
d["goodbye"] = "world";
d["hello"] = "world";
delete d["hello"]
var ba:ByteArray = new ByteArray();
ba.writeObject(d);
var len:uint = ba.position;
ba.position = 0;
for(var i:uint=0;i<len;i++) {
trace(ba.readUnsignedByte().toString(16));
}
Вывод будет:
11 05 00 06 0f 67 6f 6f 64 62 79 65 06 0b 77 6f 72 6c 64
А что если мы никогда не введем "hello"
в качестве ключа:
var d:Dictionary = new Dictionary(false);
d["goodbye"] = "world";
var ba:ByteArray = new ByteArray();
ba.writeObject(d);
var len:uint = ba.position;
ba.position = 0;
for(var i:uint=0;i<len;i++) {
trace(ba.readUnsignedByte().toString(16));
}
Тогда вывод:
11 03 00 06 0f 67 6f 6f 64 62 79 65 06 0b 77 6f 72 6c 64
Обратите внимание, что длина абсолютно одинакова, однако они отличаются во втором байте.
Теперь давайте посмотрим на сериализацию, если я не удаляю "hello"
:
11 05 01 06 0b 68 65 6c 6c 6f 06 0b 77 6f 72 6c 64 06 0f 67 6f 6f 64 62 79 65 06 02
Обратите внимание, что 05
во втором байте такой же, как когда мы его удалили. Я думаю, что это указывает количество элементов в словаре. Я говорю «я думаю», потому что я довольно долго копался в документации по AMF0 / 3, пытаясь точно выяснить, что здесь происходит, потому что не похоже, что это должна быть сериализация для словаря, но она достаточно последовательна , но я не понимаю.
Так что я думаю, что именно поэтому вы нажимаете исключение (в частности, ошибку «Конец файла»), потому что он все еще думает, что в словаре должен быть еще один элемент, который он должен десериализовать.
Ваш альтернативный метод работает, потому что вы создаете новый Словарь и заполняете его ... Его "внутренний счетчик" только увеличивается, поэтому он работает как талисман.
Еще один момент, на который следует обратить внимание: если вы установите d["Hello"] = undefined
, он не выдаст исключение, но элемент не будет удален из словаря. Ключ сериализуется со значением undefined
в потоке AMF. Таким образом, результирующий поток байтов длиннее, чем если бы его никогда не было.
Использование Object
, похоже, не демонстрирует такого же поведения. Мало того, что не выдает ошибку, сгенерированный байт-код больше соответствует документации AMF0 / 3, которую я мог найти в Adobe. И полученный «ключ» буквально отбрасывается из сериализации, как это было на самом деле никогда не было. Поэтому я не уверен, какой особый случай они используют для Dictionary
(очевидно, недокументированный тип данных AMF3 0x11
), но он не подходит для удаления из него элементов.
Мне кажется, это настоящая ошибка.
редактировать
Так что я немного покопался и обнаружил, что другие люди говорят о AMF-сериализации Dictionary
.
0x11 : Dictionary Data Type
0x05 : Bit code: XXXX XXXY
: If y == 0 then X is a reference to a previously encoded object in the stream
: If y == 1 then X is the number of key/val pairs in the dictionary.
Так что, если в этом случае 5&1 == 1
и 5>>1 == 2
, значит, в «плохой» сериализованной версии ожидается две пары ключ / вал.