您所看到的是字节的字符串表示形式AmfInteger
。第一个示例\xa2C
由两个字节组成:0xa2
又名 162 和C
,它是 67 的 ASCII 表示:
>>> ord("\xa2C"[0])
162
>>> ord("\xa2C"[1])
67
要将其转换为 AmfInteger,我们必须遵循AMF3 规范,第 1.3.1 节(AmfInteger 的格式在 AMF0 和 AMF3 中是相同的,所以我们看什么规范并不重要)。
在该部分中,U29(可变长度无符号 29 位整数,AmfIntegers 在内部使用它来表示值)被定义为 1、2、3 或 4 字节序列。每个字节编码关于值本身的信息,以及后面是否有另一个字节。要确定是否有另一个字节跟随当前字节,只需检查是否设置了最高有效位:
>>> (162 & 0x80) == 0x80
True
>>> (67 & 0x80) == 0x80
False
所以我们现在确认你看到的字节序列确实是一个完整的 U29:第一个字节设置了它的高位,表示它后面跟着另一个字节。第二个字节未设置位,以指示序列的结束。要从这些字节中获取实际值,我们现在只需要组合它们的值,同时屏蔽第一个字节的高位:
>>> 162 & 0x7f
34
>>> 34 << 7
4352
>>> 4352 | 67
4419
由此,应该很容易弄清楚为什么其他值会给出您观察到的结果。
为了完整起见,这里还有一个 Python 片段,其中包含一个解析 U29 的示例实现,包括所有极端情况:
def parse_u29(byte_sequence):
value = 0
# Handle the initial bytes
for byte in byte_sequence[:-1]:
# Ensure it has its high bit set.
assert ord(byte) & 0x80
# Extract the value and add it to the accumulator.
value <<= 7
value |= ord(byte) & 0x7F
# Handle the last byte.
value <<= 8 if len(byte_sequence) > 3 else 7
value |= ord(byte_sequence[-1])
# Handle sign.
value = (value + 2**28) % 2**29 - 2**28
return value
print parse_u29("\xa2C"), 4419
print parse_u29(map(chr, [0x88, 0x00])), 1024
print parse_u29(map(chr, [0xFF, 0xFF, 0x7E])), 0x1ffffe
print parse_u29(map(chr, [0x80, 0xC0, 0x80, 0x00])), 0x200000
print parse_u29(map(chr, [0xBF, 0xFF, 0xFF, 0xFE])), 0xffffffe
print parse_u29(map(chr, [0xC0, 0x80, 0x80, 0x01])), -268435455
print parse_u29(map(chr, [0xFF, 0xFF, 0xFF, 0x81])), -127