jcestruct就是类似于protobuff的序列化结构,qq主要就是使用的这个序列化结构,网上的资料比较少,都是Java的,我就写个python的解析吧。
格式内容:
ttlv结构,即tag,type,length,value三个内容。
jcestruct的结构都是一个head,接一个内容。
head结构
通常head为一个字节,既包含type,还包含一个tag表示序号。
一个head的低四位即为type类型,高四位位tag,若tag等于0xf,则head包含两个字节,第二个字节为tag值。
获取head的代码如下:
def readHead():
head = jcestruct.read(1)
headdata = struct.unpack('b',head)
for i in headdata:
#print(i)
print("headData:",end='')
print(hex(i))
headtag = ((i)& 0xF0)>>4
headtype = i&0xF
if 0xF == headtag:
headtag = jcestruct.read(1)
print("headtap:",end='')
print(headtag)
print("headtype:",end='')
print(headtype)
return headtag,headtype
type的格式列表如下:
值 | 类型 |
---|---|
0 | byte 或 bool |
1 | Short |
2 | Int |
3 | Long |
4 | Float |
5 | Double |
6,7 | String 6字符串比较短,1个字节代表长度,7字符串比较长,1个int表示长度 |
8 | Map 后面第一个int表示长度 |
9 | List |
10 | STRUCT_BEGIN 继承了JceStruct类的开始 |
11 | STRUCT_END 继承了JceStruct类的结束 |
12 | ZERO_TAG |
13 | TYPE_SIMPLE_LIST 后来加的一个结构,就是个bytes数组,不知道为什么要有这个结构,先接一个byte表示长度类型, |
# -*- coding: utf-8 -*-
"""
Created on Fri Feb 7 16:49:39 2020
@author: lth
"""
import struct
TYPE_BYTE = 0;
TYPE_SHORT = 1
TYPE_INT = 2
TYPE_LONG = 3
TYPE_FLOAT = 4
TYPE_DOUBLE = 5
TYPE_STRING1 = 6
TYPE_STRING4 = 7
TYPE_MAP = 8
TYPE_LIST = 9
#子结构 0A*******0B
TYPE_STRUCT_BEGIN = 10
TYPE_STRUCT_END = 11
TYPE_ZERO_TAG = 12
TYPE_SIMPLE_LIST = 13
def readHead():
head = jcestruct.read(1)
if b'' == head:
print('complete!')
return 0,12
print(head)
headdata = struct.unpack('b',head)
for i in headdata:
headtag = ((i)& 0xF0)>>4
headtype = i&0xF
if 0xF == headtag:
headtag = jcestruct.read(1)
'''
print("headData:",end='')
print(hex(i))
print("headtap:",end='')
print(headtag)
print("headtype:",end='')
print(headtype)
'''
return headtag,headtype
def switchType(typ):
if TYPE_BYTE == typ:
print("tag:byte")
jceData = jcestruct.read(1)
print(int.from_bytes(jceData,'little'))
return int.from_bytes(jceData,'little')
elif TYPE_SHORT == typ: ##short
print("tag:short")
jceData = jcestruct.read(2)
print(jceData)
elif TYPE_INT == typ: ##int
print("tag:int")
jceData = jcestruct.read(4)
print(jceData)
elif TYPE_LONG == typ: ##long
print("tag:long")
jceData = jcestruct.read(8)
print(jceData)
elif TYPE_FLOAT == typ: ##float
print("tag:float")
jceData = jcestruct.read(8)
print(jceData)
elif TYPE_DOUBLE == typ: ###double
print("tag:double")
jceData = jcestruct.read(8)
print(jceData)
elif TYPE_STRING1 == typ: ##sting
print("tag:string")
jceDatalen = jcestruct.read(1)
jceDatalen = int().from_bytes(jceDatalen,byteorder='big', signed=False)
#print(int().from_bytes(jceDatalen,byteorder='little', signed=False))
jceData = jcestruct.read(jceDatalen)
print(jceData)
elif TYPE_STRING4 == typ: ##long string
print("tag:long")
jceDatalen = jcestruct.read(4)
jceData = jcestruct.read(int(jceDatalen))
print(jceData)
elif TYPE_MAP == typ: ##map
print("tag:map",end='')
jceDatalen = jcestruct.read(2) ##取map个数格式
jceDatalen = int.from_bytes(jceDatalen,'big')
print(jceDatalen)
print('[')
for i in range(0,jceDatalen):
a,b = readHead()
print("key is:",end='')
switchType(b)
a,b = readHead()
print("value is:",end='')
switchType(b)
elif TYPE_LIST == typ: ##list
print("tag:list")
jceDatalen = jcestruct.read(2) ##取map个数格式
jceDatalen = int.from_bytes(jceDatalen,'big')
print(jceDatalen)
for i in range(0,jceDatalen):
tag,typ = readHead()
switchType(typ)
jceData = jcestruct.read(jceDatalen)
print(jceData)
elif TYPE_STRUCT_BEGIN == typ: ##0a begin 0b end
print("tag:begin")
tag,typ = readHead()
#print(typ)
switchType(typ)
# print(jceData)
elif TYPE_STRUCT_END == typ:
print("tag:end")
jceData = jcestruct.read(1)
print(jceData)
elif TYPE_ZERO_TAG == typ: ##zero
print("tag:deadline")
return
elif TYPE_SIMPLE_LIST == typ: ##simple list
jcestruct.read(1)
tag,typ = readHead()
if typ == TYPE_SHORT:
jceDatalen = jcestruct.read(2)
jceDatalen = int().from_bytes(jceDatalen,byteorder='big', signed=False)
jceData = jcestruct.read(jceDatalen)
print(jceData)
elif typ == TYPE_BYTE:
jceDatalen = jcestruct.read(1)
jceDatalen = int().from_bytes(jceDatalen,byteorder='big', signed=False)
jceData = jcestruct.read(jceDatalen)
print(jceData)
#print(headtag)
if __name__ == '__main__':
jcestruct = open('test.bin','rb') #output
tag1,type1 = readHead()
while(TYPE_ZERO_TAG != type1):
switchType(type1)
tag1,type1 = readHead()
jcestruct.close()