-module(protoMsg). -export([encode/1, decode/1, encodeRec/1, decodeRec/2]). -define(bool(V), (case V of true -> <<1:8>>; _ -> <<0:8>> end)). -define(int8(V), <>). -define(uint8(V), <>). -define(int16(V), <>). -define(uint16(V), <>). -define(int32(V), <>). -define(uint32(V), <>). -define(int64(V), <>). -define(uint64(V), <>). -define(float(V), <>). -define(double(V), <>). -define(string(V), (string(V))). -define(record(V), (case V of undefined -> [<<0:8>>]; V -> [<<1:8>>, encodeRec(V)] end)). -define(list_bool(List), [<<(length(List)):16/big>>, [?bool(V) || V <- List]]). -define(list_int8(List), [<<(length(List)):16/big>>, [?int8(V) || V <- List]]). -define(list_uint8(List), [<<(length(List)):16/big>>, [?uint8(V) || V <- List]]). -define(list_int16(List), [<<(length(List)):16/big>>, [?int16(V) || V <- List]]). -define(list_uint16(List), [<<(length(List)):16/big>>, [?uint16(V) || V <- List]]). -define(list_int32(List), [<<(length(List)):16/big>>, [?int32(V) || V <- List]]). -define(list_uint32(List), [<<(length(List)):16/big>>, [?uint32(V) || V <- List]]). -define(list_int64(List), [<<(length(List)):16/big>>, [?int64(V) || V <- List]]). -define(list_uint64(List), [<<(length(List)):16/big>>, [?uint64(V) || V <- List]]). -define(list_float(List), [<<(length(List)):16/big>>, [?float(V) || V <- List]]). -define(list_double(List), [<<(length(List)):16/big>>, [?double(V) || V <- List]]). -define(list_string(List), [<<(length(List)):16/big>>, [string(V) || V <- List]]). -define(list_record(List), [<<(length(List)):16/big>>, [encodeRec(V) || V <- List]]). string(Str) when is_binary(Str) -> [<<(byte_size(Str)):16/big>>, Str]; string(Str) -> Str2 = unicode:characters_to_binary(Str, utf8), [<<(byte_size(Str2)):16/big>>, Str2]. encode(Record) -> MsgBin = encodeRec(Record), MsgId = getMsgId(element(1, Record)), [<>, MsgBin]. decode(Bin) -> <> = Bin, SchList = getMsgSchema(MsgId), {<<>>, ResultList} = decodeField(SchList, MsgBin, [getMsgType(MsgId)]), list_to_tuple(ResultList). decodeRec(RecordName, Bin) -> SchList = getMsgSchema(RecordName), {LeftBin, Result} = decodeField(SchList, Bin, [RecordName]), {LeftBin, list_to_tuple(Result)}. decodeField([], LeftBin, Result) -> {LeftBin, lists:reverse(Result)}; decodeField([Type | SchList], MsgBin, Result) -> case Type of int32 -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); uint32 -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); string -> <> = MsgBin, decodeField(SchList, LeftBin, [StrBin | Result]); int16 -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); uint16 -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); int8 -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); uint8 -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); int64 -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); uint64 -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); bool -> <> = MsgBin, case Bool =:= 1 of true -> decodeField(SchList, LeftBin, [true | Result]); _ -> decodeField(SchList, LeftBin, [false | Result]) end; falat -> <> = MsgBin, decodeField(SchList, LeftBin, [Float | Result]); double -> <> = MsgBin, decodeField(SchList, LeftBin, [Float | Result]); {list, int32} -> <> = MsgBin, {LeftBin, RetList} = deInt32List(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, uint32} -> <> = MsgBin, {LeftBin, RetList} = deUint32List(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, int16} -> <> = MsgBin, {LeftBin, RetList} = deInt16List(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, uint16} -> <> = MsgBin, {LeftBin, RetList} = deUint16List(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, int8} -> <> = MsgBin, {LeftBin, RetList} = deInt8List(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, uint8} -> <> = MsgBin, {LeftBin, RetList} = deUint8List(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, string} -> <> = MsgBin, {LeftBin, RetList} = deStringList(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, int64} -> <> = MsgBin, {LeftBin, RetList} = deInt64List(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, uint64} -> <> = MsgBin, {LeftBin, RetList} = deUint64List(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, bool} -> <> = MsgBin, {LeftBin, RetList} = deBoolList(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, flat} -> <> = MsgBin, {LeftBin, RetList} = deFloatList(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, double} -> <> = MsgBin, {LeftBin, RetList} = deDoubleList(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, RecordName} -> <> = MsgBin, {LeftBin, RetList} = deRecordList(Len, RecordName, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); RecordName -> <> = MsgBin, case IsUndef of 0 -> decodeField(SchList, LeftBin, [undefined | Result]); _ -> SubSchList = getMsgSchema(RecordName), {SubLeftBin, SubResultList} = decodeField(SubSchList, LeftBin, [RecordName]), decodeField(SchList, SubLeftBin, [list_to_tuple(SubResultList) | Result]) end end. deBoolList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deBoolList(N, <>, RetList) -> case Bool =:= 1 of true -> deBoolList(N - 1, LeftBin, [true | RetList]); _ -> deBoolList(N - 1, LeftBin, [false | RetList]) end. deInt8List(0, MsgBin, RetList) -> {MsgBin, RetList}; deInt8List(N, <>, RetList) -> deInt8List(N - 1, LeftBin, [Int | RetList]). deUint8List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deUint8List(N, <>, RetList) -> deUint8List(N - 1, LeftBin, [Int | RetList]). deInt16List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deInt16List(N, <>, RetList) -> deInt16List(N - 1, LeftBin, [Int | RetList]). deUint16List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deUint16List(N, <>, RetList) -> deUint16List(N - 1, LeftBin, [Int | RetList]). deInt32List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deInt32List(N, <>, RetList) -> deInt32List(N - 1, LeftBin, [Int | RetList]). deUint32List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deUint32List(N, <>, RetList) -> deUint32List(N - 1, LeftBin, [Int | RetList]). deInt64List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deInt64List(N, <>, RetList) -> deInt64List(N - 1, LeftBin, [Int | RetList]). deUint64List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deUint64List(N, <>, RetList) -> deUint64List(N - 1, LeftBin, [Int | RetList]). deFloatList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deFloatList(N, <>, RetList) -> deFloatList(N - 1, LeftBin, [Float | RetList]). deDoubleList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deDoubleList(N, <>, RetList) -> deDoubleList(N - 1, LeftBin, [Float | RetList]). deStringList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deStringList(N, <>, RetList) -> deStringList(N - 1, LeftBin, [StrBin | RetList]). deRecordList(0, _RecordName, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deRecordList(N, RecordName, MsgBin, RetList) -> {LeftBin, Tuple} = decodeRec(RecordName, MsgBin), deRecordList(N - 1, RecordName, LeftBin, [Tuple | RetList]). getMsgType(1)-> test; getMsgType(2)-> phoneNumber; getMsgType(3)-> person; getMsgType(4)-> addressBook; getMsgType(_) -> undefined. getMsgId(test)-> 1; getMsgId(phoneNumber)-> 2; getMsgId(person)-> 3; getMsgId(addressBook)-> 4; getMsgId(_) -> 0. encodeRec({test, V1}) -> [?string(V1)]; encodeRec({phoneNumber, V1, V2}) -> [?record(V1), ?int32(V2)]; encodeRec({person, V1, V2, V3, V4}) -> [?string(V1), ?int32(V2), ?string(V3), ?list_record(V4)]; encodeRec({addressBook, V1, V2}) -> [?list_record(V1), ?list_record(V2)]; encodeRec(_) -> []. getMsgSchema(test)-> getMsgSchema(1); getMsgSchema(1)-> [string]; getMsgSchema(phoneNumber)-> getMsgSchema(2); getMsgSchema(2)-> [test,int32]; getMsgSchema(person)-> getMsgSchema(3); getMsgSchema(3)-> [string,int32,string,{list,phoneNumber}]; getMsgSchema(addressBook)-> getMsgSchema(4); getMsgSchema(4)-> [{list,person},{list,person}]; getMsgSchema(_) -> [].