AMF中整形数值的转换方法

AAUTO2014-03-04 00:06

截取了一小段16进制的AMF3数据「04 88 DB 34」,对应的整形10进制数值为「142772」,以下说明两者之间如何转换。

开头的「04」在AMF3格式中表示当前值为整形数据,而「88 DB 34」则是UTF编码表示的具体整形数值。

二进制表示为:(UTF是变长编码,所以最后一个字节的最高位为0,用于表明结束当前值)
10001000 11011011 00110100

去掉每个字节的最高位,剩下21位:
0001000 1011011 0110100

从后面算起,每4位为一个新字节,重新排一下位置(还是21位):
0 0010 0010 1101 1011 0100

每4位转为一个16进制值显示,即:
0x22DB4

也就是10进制值:
142772

下面使用AAUTO编写转换的函数,分为繁琐的每步操作版和简化版,用于详细地了解数值是如何转换的。

16进制转整形(按步骤操作版):

var hex2int = function(value){
    value = string.replace(value, "[\t\ \n]+", "") //删除多余的空白符号
    value = (string.replace(value,".{2}",function(s){
        return string.format("%08b", tonumber(s,16)) //16进制转为2进制格式
    }))
    value = (string.replace(value,".{8}",function(s){
        return string.right(s,7) //去掉每个字节的最高位,即保留右7
    }))
    value = string.repeat( 4 - (#value % 4), "0" ) ++ value //前面补0,为下方每4位处理作准备
    value = (string.replace(value,".{4}",function(s){
        return string.format( "%X", tonumber(s,2) ) //每四位2进制数转为16进制显示
    }))
    return ( tonumber(value,16) ); //16进制转为10进制格式
}

16进制转整形(简化版,推荐):

var hex2int = function(value){
    value = string.replace(value, "[\t\ \n]+", "") //删除多余的空白符号
    value = string.format("%b", tonumber(value,16)) //16进制转为2进制格式
    value = string.replace(value, ".(.{7})", "\1") //去掉每个字节的最高位,即保留右7
    return ( tonumber(value,2) ); //2进制转为10进制格式并返回
}

整形转16进制(按步骤操作版):

var int2hex = function(value){
    value = string.format("%X", tonumber(value))
    value = string.replace(value,".",function(s){ //每个数转为四位的2进制值
        return string.format("%04b", tonumber(s,16)); 
    })

    value = string.repeat( 7 - (#value % 7), "0" ) ++ value; //前面补0,为下面补最高位作准备
    value = string.reverse(value) //反转字串,方便从后方开始补最高位

    value = string.replace(value, ".{7}", function(s){
        return s++"1"; //补最高位1
    })
    value = string.replace(value, "^(.{7})1", "\10") //8位值需要为0,表示数值的结束
    value = string.reverse(value) //补位完成,再反转为正常状态

    return string.format("%02X", tonumber(value,2)); //返回16进制显示
}

整形转16进制(简化版,推荐):

var int2hex = function(value){
    value = string.format("%b", value); //转为2进制
    value = string.repeat( 7 - (#value % 7), "0" ) ++ value; //前面补0,为下面补最高位作准备
    value = string.replace(value, "(.{7})", "1\1"); //7位补一个最高位,用于生成新的字节
    value = string.replace(value, "1(.{7})$", "0\1"); //末尾字节最高位为0,表示数值的结束
    return string.format("%X", tonumber(value,2)); //返回16进制显示
}

关键是要了解UTF的解码方法(PS:大数值转换时以上算法需要改进,请自行对比二进制值即可找到原因)
UTF编码是变长的,用来表示整型数据时,最高位为1表示下面还有字节,为0表示已经到达最后一个字节了。
所以根据最高位可以判断这个数据的字节长度及是否到达结尾,然后去掉最高位后剩下的数据就是实际值了。

参考:
AMF3协议中文版 - 百度文库
AMF数据解析的问题 - CSDN论坛
AMF学习2远程调用的封装 - 深蓝
谈AMF和AMF Message - 逆水行舟 【荐】


原文链接: http://blog.jtwo.me/integer-conversion-method-in-amf