Skip to content
Browse files

amf0 and amf3 implementation

  • Loading branch information...
1 parent 6882faa commit a3db284e83622643e5c59f8d6fb8898265876a18 @trung committed Sep 30, 2009
Showing with 163 additions and 0 deletions.
  1. +28 −0 temp/server/action_message.hrl
  2. +76 −0 temp/server/amf0.erl
  3. +59 −0 temp/server/deserializer.erl
View
28 temp/server/action_message.hrl
@@ -0,0 +1,28 @@
+%% define amf0
+-define(VERSION_1, 1).
+%% not used anymore but just there
+-define(VERSION_2, 2).
+%% define amf3
+-define(VERSION_3, 3).
+
+-define(STATUS_METHOD, "/onStatus").
+-define(RESULT_METHOD, "/onResult").
+
+-define(AMF_CONTENT_TYPE, "application/x-amf").
+-define(XML_CONTENT_TYPE, "application/xml").
+
+-record(header, {headerName = "", mustUnderstand = false, data = <<>>}).
+-record(body, {targetUri = "", responseUri = "", data = <<>> }).
+
+-record(action_message, {
+ version = ?VERSION_1,
+ headers = [], %% list of 'header'
+ bodies = [] %% list of 'body'
+ }).
+
+-record(trait, {
+ className = "",
+ externalizable = false,
+ dynamic = false,
+ properties = []
+ }).
View
76 temp/server/amf0.erl
@@ -0,0 +1,76 @@
+-module(amf0).
+-author("trung@mdkt.org").
+
+-export([read_object/1, read_u8/1, read_u16/1, read_u32/1, read_string/1]).
+
+-include("action_message.hrl").
+
+-define(number_marker, 16#00).
+-define(boolean_marker, 16#01).
+-define(string_marker, 16#02).
+-define(object_marker, 16#03).
+-define(movieclip_marker, 16#04). %% reserved, not supported
+-define(null_marker, 16#05).
+-define(undefined_marker, 16#06).
+-define(reference_marker, 16#07).
+-define(ecma_array_marker, 16#08).
+-define(object_end_marker, 16#09).
+-define(strict_array_marker, 16#0A).
+-define(date_marker, 16#0B).
+-define(long_string_marker, 16#0C).
+-define(unsupported_marker, 16#0D).
+-define(recordset_marker, 16#0E). %% reserved, not supported
+-define(xml_document_marker, 16#0F).
+-define(typed_object_marker, 16#10).
+-define(avm_plus_object_marker, 16#11).
+
+read_u8(<<Value:8, Rest/binary>>) ->
+ {ok, Value, Rest}.
+
+read_u16(<<Value:16, Rest/binary>>) ->
+ {ok, Value, Rest}.
+
+read_u32(<<Value:32, Rest/binary>>) ->
+ {ok, Value, Rest}.
+
+read_string(Bin) ->
+ {ok, StringLen, Rest} = read_u16(Bin),
+ {StringBin, Rest1} = split_binary(Rest, StringLen),
+ {ok, String} = utf8:from_binary(StringBin),
+ {ok, String, Rest1}.
+
+read_number(<<Value/float, Rest/binary>>) ->
+ {ok, Value, Rest};
+read_number(Something) ->
+ {bad, {"Can't read number", Something}}.
+
+read_boolean(<<Value:8, Rest/binary>>) ->
+ case Value of
+ 0 ->
+ {ok, false, Rest};
+ _ ->
+ {ok, true, Rest}
+ end;
+read_boolean(Something) ->
+ {bad, {"Can't read boolean", Something}}.
+
+%% return {ok, value/Value, Rest} or {bad, Reason}
+read_object(<<?number_marker:8, Rest/binary>>) -> read_number(Rest);
+read_object(<<?boolean_marker:8, Rest/binary>>) -> read_boolean(Rest);
+read_object(<<?string_marker:8, Rest/binary>>) -> read_string(Rest);
+read_object(<<?object_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?movieclip_marker:8, Rest/binary>>) -> {bad, {"Reserved, not supported", Rest}};
+read_object(<<?null_marker:8, Rest/binary>>) -> {ok, null, Rest};
+read_object(<<?undefined_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?reference_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?ecma_array_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?object_end_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?strict_array_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?date_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?long_string_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?unsupported_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?recordset_marker:8, Rest/binary>>) -> {bad, {"Reserved, not supported", Rest}};
+read_object(<<?xml_document_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?typed_object_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+%% switch to AMF3
+read_object(<<?avm_plus_object_marker:8, Rest/binary>>) -> amf3:read_object(Rest).
View
59 temp/server/deserializer.erl
@@ -0,0 +1,59 @@
+-module(deserializer).
+-author("trung@mdkt.org").
+
+-export([read/1]).
+
+-include("action_message.hrl").
+
+read_header(Bin) ->
+ io:fwrite("Bin = ~n~p~n", [Bin]),
+ {ok, HeaderName, BinAfterHeaderName} = amf0:read_string(Bin),
+ {ok, MustUnderstand, BinAfterMustUnderstand} = amf0:read_u8(BinAfterHeaderName),
+ {ok, _DataLen, DataBin} = amf0:read_u32(BinAfterMustUnderstand),
+ %% Don't care about DataLen, just read
+ %% {DataBin, NextBin} = split_binary(Rest2, DataLen),
+ {ok, Data, NextBin} = amf0:read_object(DataBin),
+ Header = #header{headerName = HeaderName, mustUnderstand = case MustUnderstand of 0 -> false; _Other -> true end, data = Data},
+ {ok, Header, NextBin}.
+
+read_headers(Bin, Count, Total, Acc) when Count == Total ->
+ {ok, Acc, Bin};
+read_headers(Bin, Count, Total, Acc) ->
+ {ok, Header, NextBin} = read_header(Bin),
+ io:fwrite("Parsed header ~p : ~p~n", [Count + 1, Header]),
+ read_headers(NextBin, Count + 1, Total, Acc ++ [Header]).
+
+read_body(Bin) ->
+ {ok, TargetUri, BinAfterTargetUri} = amf0:read_string(Bin),
+ {ok, ResponseUri, BinAfterResponseUri} = amf0:read_string(BinAfterTargetUri),
+ {ok, _DataLen, DataBin} = amf0:read_u32(BinAfterResponseUri),
+ %% Don't care about DataLen, just read
+ %% {DataBin, NextBin} = split_binary(Rest2, DataLen),
+ {ok, Data, NextBin} = amf0:read_object(DataBin),
+ Body = #body{targetUri = TargetUri, responseUri = ResponseUri, data=Data},
+ {ok, Body, NextBin}.
+
+read_bodies(Bin, Count, Total, Acc) when Count == Total ->
+ {ok, Acc, Bin};
+read_bodies(Bin, Count, Total, Acc) ->
+ {ok, Body, NextBin} = read_body(Bin),
+ read_bodies(NextBin, Count + 1, Total, Acc ++ [Body]).
+
+%% Read binary and translate to action_message record
+%% Msg = #action_message
+%% return {ok, Msg, Rest} or {bad, Reason}
+%% ideally, Rest must be <<>>
+read(<<?VERSION_1:16, Rest/binary>>) -> read_now(?VERSION_1, Rest);
+read(<<?VERSION_3:16, Rest/binary>>) -> read_now(?VERSION_3, Rest);
+read(_) ->
+ {bad, "Not a valid binary or version not supported"}.
+
+read_now(Version, Bin) ->
+ {ok, HeaderCount, BinAfterHeaderCount} = amf0:read_u16(Bin),
+ io:fwrite("There are ~p header(s)~n", [HeaderCount]),
+ {ok, Headers, BinAfterHeaders} = read_headers(BinAfterHeaderCount, 0, HeaderCount, []),
+ {ok, BodyCount, BinAfterBodyCount} = amf0:read_u16(BinAfterHeaders),
+ io:fwrite("There are ~p body(s)~n", [BodyCount]),
+ {ok, Bodies, BinAfterBodies} = read_bodies(BinAfterBodyCount, 0, BodyCount, []),
+ Msg = #action_message{version = Version, headers = Headers, bodies = Bodies},
+ {ok, Msg, BinAfterBodies}.

0 comments on commit a3db284

Please sign in to comment.
Something went wrong with that request. Please try again.