好吧,我刚刚花了两个小时左右的时间来研究这个,这比我计划花的时间要多得多。但我很好奇。
我认为您可能已经发现了 ActionScript 的 AMF 编码(或者如何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
,它不会抛出异常,但该项目会抛出异常not从字典中删除。键被序列化为值undefined
在 AMF 流中。因此,生成的字节流比它不存在时要长。
使用Object
似乎没有表现出同样的行为。不仅不会产生错误,生成的字节码更符合我可以从 Adobe 找到的 AMF0/3 文档。生成的“密钥”实际上从序列化中删除,就像它实际上从未存在过一样。所以我不确定他们使用什么特殊情况Dictionary
(显然未记录的 AMF3 数据类型0x11
),但从其中删除项目时效果不佳。
对我来说这似乎是一个合法的错误。
edit
所以我进一步挖掘并发现其他人在谈论AMF 序列化Dictionary http://dev.pyamf.org/attachment/ticket/696/dict.patch.
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
and 5>>1 == 2
,因此它期望“坏”序列化版本中有两个键/值对。