`

erlang版的adobe amf3格式解析模块

阅读更多
-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.

分享到:
评论
1 楼 kebo 2009-07-27  
-define(INTEGER_MAX, 268435455).
-define(INTEGER_MIN, -268435456).
-define(MAX_RESTART,      5).
-define(MAX_TIME,        60).
-define(TIMEOUT,     120000).
-define(HS_HEADER,        3).
-define(HS_BODY_LEN,   1536).
-define(MIN_CLIENT_BUFFER, 100).


%% AMF3 data
-define(AMF3_UNDEFINED, 0).
-define(AMF3_NULL, 1).
-define(AMF3_FALSE, 2).
-define(AMF3_TRUE, 3).
-define(AMF3_INTEGER, 4).
-define(AMF3_NUMBER, 5).
-define(AMF3_STRING, 6).
-define(AMF3_XML, 7).
-define(AMF3_DATE,.
-define(AMF3_ARRAY, 9).
-define(AMF3_OBJECT, 10).
-define(AMF3_XML_STRING, 11).

-define(AMF3_OBJECT_OBJ_INLINE, 1).
-define(AMF3_OBJECT_CLASS_INLINE, 2).
-define(AMF3_OBJECT_PROP_DEF, 4).
-define(AMF3_OBJECT_PROP_SERIAL,.

%% AMF object
-define(AMF3_OBJECT_PROPERTY, 0).
-define(AMF3_OBJECT_EXTERNALIZABLE, 1).
-define(AMF3_OBJECT_VALUE, 2).
-define(AMF3_OBJECT_PROXY, 3).


-record(channel,{
id        = undefined,
timestamp = undefined,
length    = undefined,
type      = undefined,
stream    = undefined,
msg       = undefined
}).


-record(amf,{
command = [],
id      = [],
args    = [],
type = invoke %if invoke then id, otherwise notify
}).


-record(amf3, {strings=nil, stringcount=0, objectcount=0,objects=nil}).
   
-record(as_object, {type=nil,keyValue=nil,externalizable=false,dynamic=false}).

相关推荐

    amf3协议解析的例子

    AMF3(Action Message Format version 3)协议是Adobe公司为Flash Player和Flex应用程序之间通信设计的一种二进制数据交换格式。它旨在提高数据传输效率,同时保持足够的灵活性以适应不同类型的复杂数据结构。AMF3...

    开源amf协议解析封装

    4. **Lib**:项目中的"Lib"文件夹可能包含实现AMF解析和封装所需的库文件或类库,可能包含了AMF编码解码的关键算法。 5. **AMF3.Server**:这部分可能是一个实现AMF3协议的服务端组件,负责处理AMF3格式的请求和响应...

    AMF3 C++ 源码(修改版)

    AMF3,全称为Action Message Format 3,是Adobe公司为Flash Player和Flex应用程序之间进行数据交换设计的一种高效二进制序列化格式。这个“AMF3 C++ 源码(修改版)”提供了对AMF3协议的C++实现,支持序列化和对象化...

    AMF3 format

    **AMF3**(Action Message Format 3)是 Adobe 公司推出的一种紧凑的二进制格式,用于序列化 ActionScript 对象图。一旦对象图被序列化为 AMF 编码,就可以在不同的会话之间持久存储和检索应用程序的公共状态,或者...

    AMF3协议中文版定义.pdf

    AMF3 协议中文版定义 AMF(Action Message Format,动作信息格式)是一种压缩的二进制格式,用于序列化 ActionScript 对象图。序列化后的 AMF 编码对象图可以用来持久化,并在不同的会话中获得应用的公共状态,或者...

    amf解析构造易语言源码

    AMF,全称为Action Message Format,是由Adobe公司开发的一种数据序列化协议,主要用于在Flash ...通过阅读和分析这些源代码,你可以更好地理解AMF解析和构造的全过程,并可能从中获得灵感,改进或扩展现有的实现。

    amf解析,json解析 格式化

    总结来说,AMF解析和JSON格式化是Web开发中涉及数据交换的重要技术。AMF提供高效的二进制数据交换,适合性能敏感的应用,而JSON因其简洁和通用性成为互联网上最广泛使用的数据交换格式。掌握这两种技术,以及相关的...

    amf3_spec_05_05_08.zip_AMF3_above flash player_player

    AMF3,全称为Action Message Format 3,是Adobe Flex和Flash Player之间进行数据序列化和通信的一种高效格式。在标题“amf3_spec_05_05_08.zip_AMF3_above flash player_player”中,我们可以理解这是关于AMF3规范的...

    AMF3 C++ 源码库码库

    AMF3(Action Message Format version 3)是Adobe公司开发的一种二进制数据序列化格式,主要用于Flash Player和Flex应用程序与服务器之间的数据交换。在C++编程环境中,AMF3库可以帮助开发者高效地处理这种数据格式...

    AMF格式文件

    AMF(Action Message Format)是Adobe公司开发的一种紧凑的二进制格式,用于序列化ActionScript对象图。AMF格式文件最初在Flash Player 6中引入,并被广泛应用于网络通信,特别是在Adobe Flex框架和BlazeDS中间件中...

    amf3cplusplus

    AMF3(Action Message Format version 3)是Adobe公司开发的一种二进制数据序列化格式,主要用于Flash Player与服务器之间的数据交换。它提高了数据传输效率,支持多种数据类型,包括基本类型、对象、数组、日期等。...

    AMF数据分析器

    AMF(Action Message Format)是一种数据交换格式,主要用于Flash与服务器之间的通信,尤其在Adobe Flex应用中广泛应用。AMF数据分析器是一款专为处理和解析AMF数据而设计的专业工具,旨在提升开发人员对AMF数据的...

    lua-amf 解析库

    Lua-Amf 是一个专为 Lua 语言设计的AMF(Action Message Format)解析库,它使得在 Lua 环境中处理AMF3格式的数据变得简单高效。AMF是一种二进制序列化格式,常用于Flash与服务器之间的数据交换,如Adobe的Flex和...

    AMF数据分析器_V22

    支持AMF格式的通信封包编码、解码、向AMF服务端发送请求、返回AMF数据解析。 支持RTMP封包编码、解码。 支持Flex外部化类的AMF编码、解码。 支持解压还原LZMA算法压缩过的SWF文件(文件头三字节为:ZWS的 *.SWF...

    易语言amf解析构造

    易语言amf解析构造源码,amf解析构造,分析amf,取短整数_字节集,时间到双精度,到时间_双精度,取整数_字节集,integer_字节集,取双精度_字节集,amf3型数据,十六进制转字节集,分析数据段,解析amf数据,解析amf3数据,Utf8转...

    MP4AMF格式转换工具

    总之,"MP4AMF格式转换工具"是解决跨平台兼容性和播放问题的有效方案,通过解析、解码、重新编码和封装等一系列操作,帮助用户在MP4和AMF格式之间无缝切换。对于那些需要在不同环境中分享或播放多媒体内容的人来说,...

    AMF.NET 文件极小的开源AMF解析库

    综上所述,AMF.NET作为一个轻量级的AMF解析库,为.NET开发者提供了一种简洁、高效的解决方案,以处理与Flash和Flex应用之间的数据通信。其兼容性、易用性和性能优势使得它在处理AMF数据流的场景中具有显著价值。如果...

    amf解析构造.rar

    这个“amf解析构造.rar”压缩包文件包含的是易语言编写的AMF解析构造的源码,这对于理解AMF格式的工作原理以及在易语言环境下处理AMF数据具有重要的学习价值。 易语言是一种中国本土开发的编程语言,以其独特的汉字...

    socket+AMF3

    AMF3(Action Message Format version 3)是Adobe公司推出的一种高效的数据序列化格式,主要用于Flash与服务器之间的数据交换。AMF3能够快速地将复杂的数据结构如对象、数组、日期等编码为二进制流,然后在网络中...

    java socket amf3 flash game framework

    AMF3(Action Message Format version 3)是Adobe开发的一种二进制数据交换格式,用于在Flash Player和服务器之间高效地传输数据。相比AMF0,AMF3在序列化和反序列化过程中更加节省带宽,提高了数据传输速度,这对于...

Global site tag (gtag.js) - Google Analytics