-module(ems_amf3).
-export([decode/1, decode/3]).
-export([parse_integer/1, parse_string/2,
parse_array/3, parse_object/3]).
-export([get/2]).
-include("../include/ems.hrl").
decode(Data) ->
<<Code, Rest/binary>> = iolist_to_binary(Data),
{Value, Rest_, State} = decode(Code, Rest, #amf3{}),
{{amf3, Value, State}, Rest_}.
decode(?AMF3_UNDEFINED, Data, S) ->
{undefined, Data, S};
decode(?AMF3_NULL, Data, S) ->
{null, Data, S};
decode(?AMF3_FALSE, Data, S) ->
{false, Data, S};
decode(?AMF3_TRUE, Data, S) ->
{true, Data, S};
decode(?AMF3_INTEGER, Data, S) ->
{Num, Rest} = parse_integer(Data),
{Num, Rest, S};
decode(?AMF3_NUMBER, Data, S) ->
<<Float:64/float, Rest/binary>> = Data,
{Float, Rest, S};
decode(?AMF3_STRING, Data, S) ->
parse_string(Data, S);
decode(?AMF3_XML, Data, S) ->
{String, Rest, S1} = parse_string(Data, S),
{{xml, String}, Rest, S1};
decode(?AMF3_DATE, Data, S) ->
{Type, Rest1} = parse_integer(Data),
case Type band 1 of
1 ->
<<Float:64/float, Rest2/binary>> = Rest1,
{Ref, S1} = add_object({date, ems_util:float_to_datetime(Float/1000)}, S),
{Ref, Rest2, S1};
0 ->
{{ref, Type bsr 1}, Rest1, S}
end;
decode(?AMF3_ARRAY, Data, S) ->
{Type, Rest1} = parse_integer(Data),
Length = Type bsr 1,
case Type band 1 of
1 ->
parse_array(Length, Rest1, S);
0 ->
{{ref, Length}, Rest1, S}
end;
decode(?AMF3_OBJECT, Data, S) ->
{Type, Rest1} = parse_integer(Data),
TypeInfo = Type bsr 1,
case Type band 1 of
0 ->
{{ref, TypeInfo}, Rest1, S}; %% o-ref
1 ->
parse_object(Type, Rest1, S)
end;
decode(?AMF3_XML_STRING, Data, S) ->
{Type, Rest1} = parse_integer(Data),
0 = Type band 1,
Length = Type bsr 1,
<<String:Length/binary, Rest2/binary>> = Rest1,
{{xml, String}, Rest2, S}.
parse_integer(Data) ->
parse_integer(Data, 0, 0).
parse_integer(<<1:1, Num:7, Data/binary>>, Result, N) when N < 3 ->
parse_integer(Data, (Result bsl 7) bor Num, N + 1);
parse_integer(<<0:1, Num:7, Data/binary>>, Result, N) when N < 3 ->
{(Result bsl 7) bor Num, Data};
parse_integer(<<Byte, Data/binary>>, Result, _N) ->
Result1 = (Result bsl 8) bor Byte,
Result3 = case Result1 band 16#10000000 of
16#10000000 ->
Extended = Result1 bor 16#e0000000,
<<Result2:32/signed>> = <<Extended:32>>,
Result2;
0 ->
Result1
end,
{Result3, Data}.
parse_string(Data, S) ->
{Type, Rest} = parse_integer(Data),
Length = Type bsr 1,
case Type band 1 of
0 ->
{get_string(Length, S), Rest, S};
1 ->
<<StringB:Length/binary, Rest1/binary>> = Rest,
{String,S1} = add_string(binary_to_list(StringB), S),
{String, Rest1, S1}
end.
parse_array(Length, <<1, Data/binary>>, S) ->
{RefNum, S1} = new_object(S),
{Array, Rest, S2} = parse_array(Length, Data, S1, [], Length),
{Ref, S3} = finish_object(RefNum, Array, S2),
{Ref, Rest, S3}.
parse_array(0, Data, S, Acc, OrigLength) ->
{{array, OrigLength, lists:reverse(Acc)}, Data, S};
parse_array(Length, Data, S, Acc, OrigLength) ->
<<Code, Data1/binary>> = Data,
{Item, Rest, S1} = decode(Code, Data1, S),
parse_array(Length - 1, Rest, S1, [Item | Acc], OrigLength).
parse_object(Type, Data, S) ->
{RefNum, S1} = new_object(S),
{Object, Rest1, S2} = parse_object_info(Type, Data, S1),
{Ref, S3} = finish_object(RefNum, Object, S2),
{Ref, Rest1, S3}.
%%traits-ref
parse_object_info(Type, Data, S) when (Type band 3) == 1 ->
{Type, Data, S};
%%traits-ext
parse_object_info(Type, Data, S) when (Type band 7) == 7 ->
{Type, Data, S};
parse_object_info(Type, Data, S) ->
Externalizable = ((Type band 4) == 4),
Dynamic = ((Type band 8) == 8),
{ClassName, Rest, S1} = parse_string(Data, S),
Count = Type bsr 4,
{Rest1,S2,NameList} = readPropertyName(Count,Rest,S1,Count,[]),
{Rest2,S3,ValueList} = readPropertyValue(Count,Rest1,S2,Count,[]),
KeyValues = keyValue(NameList,ValueList,[]),
{Rest3,S4,KeyValues1} = readDynamicProperty(Dynamic,Rest2,S3,KeyValues,true),
Object = #as_object{type=ClassName,keyValue=KeyValues1,externalizable=Externalizable,dynamic=Dynamic},
{Object, Rest3, S4}.
readPropertyName(0,Data,S,Length,List) ->
{Data,S,lists:reverse(List)};
readPropertyName(Index,Data,S,Length,List) ->
{String, Rest1, S1} = parse_string(Data,S),
readPropertyName(Index-1,Rest1,S1,Length,[String|List]).
readPropertyValue(0,Data,S,Length,List) ->
{Data,S,lists:reverse(List)};
readPropertyValue(Index,Data,S,Length,List) ->
<<Code, Rest/binary>> = iolist_to_binary(Data),
{Ref, Rest1, S1} = decode(Code, Rest, S),
readPropertyValue(Index-1,Rest1,S1,Length,[get(Ref,S1)|List]).
readDynamicProperty(_,Data,S,KeyValues,false) ->
{<<>>,S,KeyValues};
readDynamicProperty(false,Data,S,KeyValues,_) ->
{Data,S,KeyValues};
readDynamicProperty(true,Data,S,KeyValues,_) ->
{String, Rest1, S1} = parse_string(Data,S),
<<Code, Rest2/binary>> = iolist_to_binary(Rest1),
{Ref, Rest3, S2} = decode(Code, Rest2, S1),
{String1, _, _} = parse_string(Rest3,S2),
Loop = (String1 =/= ""),
readDynamicProperty(true,Rest3,S2,[{String,get(Ref,S2)}|KeyValues],Loop).
keyValue([],[],KeyValues) ->
KeyValues;
keyValue([Name|Names],[Value|Values],KeyValues) ->
keyValue(Names,Values,[{list_to_atom(Name),Value}|KeyValues]).
add_object(Object, S) ->
OldTree = case S#amf3.objects of
nil ->
gb_trees:from_orddict([]);
_Tree ->
_Tree
end,
RefNum = S#amf3.objectcount,
Tree = gb_trees:insert(RefNum, Object, OldTree),
{{ref, RefNum}, S#amf3{objects=Tree, objectcount=1 + RefNum}}.
new_object(S) ->
RefNum = S#amf3.objectcount,
{RefNum, S#amf3{objectcount=1 + RefNum}}.
finish_object(RefNum, Object, S) ->
OldTree = case S#amf3.objects of
nil ->
gb_trees:from_orddict([]);
_Tree ->
_Tree
end,
Tree = gb_trees:insert(RefNum, Object, OldTree),
{{ref, RefNum}, S#amf3{objects=Tree}}.
add_string("", S) ->
{"",S};
add_string(String, S) ->
OldTree = case S#amf3.strings of
nil ->
gb_trees:from_orddict([]);
_Tree ->
_Tree
end,
RefNum = S#amf3.stringcount,
Tree = gb_trees:insert(RefNum, String, OldTree),
{String, S#amf3{strings=Tree, stringcount=1 + RefNum}}.
get_object(RefNum, S) ->
gb_trees:get(RefNum, S#amf3.objects).
get_string(RefNum, S) ->
gb_trees:get(RefNum, S#amf3.strings).
get({ref, RefNum}, S) ->
get_object(RefNum, S);
get(Object, _) ->
Object.
分享到:
相关推荐
之前测试解析amf3协议数据进行树化便于观察的,解析的有可能不是很完美,正常用来观察里面的数据没什么问题
支持AMF格式的通信封包编码、解码、向AMF服务端发送请求、返回AMF数据解析。 支持RTMP封包编码、解码。 支持Flex外部化类的AMF编码、解码。 支持解压还原LZMA算法压缩过的SWF文件(文件头三字节为:ZWS的 *.SWF...
一个用C++编写的,amf3协议解析模块,可以实现flash通信协议的解析
amf3 的格式说明,英文版,做rtmp协议或者做与flash数据交互服务器端必备的参考
易语言amf解析构造源码,amf解析构造,分析amf,取短整数_字节集,时间到双精度,到时间_双精度,取整数_字节集,integer_字节集,取双精度_字节集,amf3型数据,十六进制转字节集,分析数据段,解析amf数据,解析amf3数据,Utf8转...
AMF3 C++ 源码 修改版 支持序列化和对象化的AMF3解析
lua-amf3:用于Lua的AMF3编码解码模块
用于 分析 解析amf数据包,以便开发或修改接口,具体请看工具提示
AMF3协议中文版定义.pdf
amf c# flex服务端协议解析和封装。
amf解析构造易语言源码
用于分析AMF数据分析的工具,使用简单方便,帮助提高AMF分析效率
Adobe Flex BlazeDS AMF File Format 熟悉下这个东西后,可以自己实现BlazeDS的前端和后端,至少也能在浏览器里的F12开发环境里搞明白AMF的内容了。
amf3_spec amf3_spec amf3_spec amf3_spamf3_specec
AMF3 C++ AMF3 C++ 源码库码库
lua-amf 解析库 可以在lua 中方便的解析和编码amf3数据
amf0 原版文档 完整版
自己写的flash webgame 搭建的java 后台 解决了安全沙箱问题,可以进行聊天,和后台java函数的请求及响应。amf3 编码。
PKG解析amf数据分析器_v30,可一键读取PKG,解密PKG内容
易语言源码易语言amf解析构造源码.rar 易语言源码易语言amf解析构造源码.rar 易语言源码易语言amf解析构造源码.rar 易语言源码易语言amf解析构造源码.rar 易语言源码易语言amf解析构造源码.rar 易语言源码...