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.

你可能感兴趣的:(xml,erlang,REST,ext,Adobe)