AMF中整形数值的转换方法

Published: Tags: AAUTO

截取了一小段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 - 逆水行舟 【荐】