-module(protoGen). -export([ convertFile/1 , convert/1 , convertDir/0 , convertDir/1 , convertDir/3 ]). protoHrlHeader() -> "-opaque int8() :: -128..127. -opaque int16() :: -32768..32767. -opaque int32() :: -2147483648..2147483647. -opaque int64() :: -9223372036854775808..9223372036854775807. -opaque uint8() :: 0..255. -opaque uint16() :: 0..65536. -opaque uint32() :: 0..4294967295. -opaque uint64() :: 0..18446744073709551615. -opaque double() :: float().\n\n". protoErlHeader() -> "-module(protoMsg).\n\n -export([encode/1, decode/1, encodeRec/1, decodeRec/2]). -define(min8, -128). -define(max8, 127). -define(min16, -32768). -define(max16, 32767). -define(min32, -2147483648). -define(max32, 2147483647). -define(min64, -9223372036854775808). -define(max64, 9223372036854775807). -define(minF32, -3.4E+38). -define(maxF32, 3.4E+38). -define(minF64, -1.797E-308). -define(maxF64, 1.797E+308). -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(integer(V), (integer(V))). -define(number(V), (number(V))). -define(string(V), (string(V))). -define(float(V), <>). -define(double(V), <>). -define(bool(V), (case V of true -> <<1:8>>; _ -> <<0:8>> end)). -define(record(V), (case V of undefined -> [<<0:8>>]; V -> [<<1:8>>, encodeRec(V)] end)). -define(list_bool(List), [<<(length(List)):16/little>>, [?bool(V) || V <- List]]). -define(list_int8(List), [<<(length(List)):16/little>>, [?int8(V) || V <- List]]). -define(list_uint8(List), [<<(length(List)):16/little>>, [?uint8(V) || V <- List]]). -define(list_int16(List), [<<(length(List)):16/little>>, [?int16(V) || V <- List]]). -define(list_uint16(List), [<<(length(List)):16/little>>, [?uint16(V) || V <- List]]). -define(list_int32(List), [<<(length(List)):16/little>>, [?int32(V) || V <- List]]). -define(list_uint32(List), [<<(length(List)):16/little>>, [?uint32(V) || V <- List]]). -define(list_int64(List), [<<(length(List)):16/little>>, [?int64(V) || V <- List]]). -define(list_uint64(List), [<<(length(List)):16/little>>, [?uint64(V) || V <- List]]). -define(list_float(List), [<<(length(List)):16/little>>, [?float(V) || V <- List]]). -define(list_double(List), [<<(length(List)):16/little>>, [?double(V) || V <- List]]). -define(list_integer(List), [<<(length(List)):16/little>>, [integer(V) || V <- List]]). -define(list_number(List), [<<(length(List)):16/little>>, [number(V) || V <- List]]). -define(list_string(List), [<<(length(List)):16/little>>, [string(V) || V <- List]]). -define(list_record(List), [<<(length(List)):16/little>>, [encodeRec(V) || V <- List]]). integer(V) -> if V >= ?min8 andalso V =< ?max8 -> <<8:8, <>/binary>>; V >= ?min16 andalso V =< ?max16 -> <<16:8, <>/binary>>; V >= ?min32 andalso V =< ?max32 -> <<32:8, <>/binary>>; V >= ?min64 andalso V =< ?max64 -> <<64:8, <>/binary>>; true -> throw(exceeded_the_integer) end. numInteger(V) -> if V >= ?min8 andalso V =< ?max8 -> <<8:8, <>/binary>>; V >= ?min16 andalso V =< ?max16 -> <<16:8, <>/binary>>; V >= ?min32 andalso V =< ?max32 -> <<32:8, <>/binary>>; V >= ?min64 andalso V =< ?max64 -> <<64:8, <>/binary>>; true -> throw(exceeded_the_integer) end. numFloat(V) -> if V >= ?minF32 andalso V =< ?maxF32 -> <<33:8, <>/binary>>; V >= ?minF64 andalso V =< ?maxF64 -> <<65:8, <>/binary>>; true -> throw(exceeded_the_float) end. number(V) -> if erlang:is_integer(V) == true -> numInteger(V); erlang:is_float(V) == true -> numFloat(V); true -> throw(is_not_number) end. string(Str) when is_binary(Str) -> [<<(byte_size(Str)):16/little>>, Str]; string(Str) -> Str2 = unicode:characters_to_binary(Str, utf8), [<<(byte_size(Str2)):16/little>>, 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]); integer -> <> = MsgBin, decodeField(SchList, LeftBin, [Int | Result]); number -> <> = MsgBin, case NumBits of 33 -> <> = NumBin, decodeField(SchList, LeftBin, [Float | Result]); 65 -> <> = NumBin, decodeField(SchList, LeftBin, [Float | Result]); _ -> <> = NumBin, decodeField(SchList, LeftBin, [Int | Result]) end; bool -> <> = MsgBin, case Bool =:= 1 of true -> decodeField(SchList, LeftBin, [true | Result]); _ -> decodeField(SchList, LeftBin, [false | Result]) end; float -> <> = 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, integer} -> <> = MsgBin, {LeftBin, RetList} = deIntegerList(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, number} -> <> = MsgBin, {LeftBin, RetList} = deNumberList(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, bool} -> <> = MsgBin, {LeftBin, RetList} = deBoolList(Len, LeftListBin, []), decodeField(SchList, LeftBin, [RetList | Result]); {list, float} -> <> = 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, MsgBin, RetList) -> <> = MsgBin, 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, MsgBin, RetList) -> <> = MsgBin, deInt8List(N - 1, LeftBin, [Int | RetList]). deUint8List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deUint8List(N, MsgBin, RetList) -> <> = MsgBin, deUint8List(N - 1, LeftBin, [Int | RetList]). deInt16List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deInt16List(N, MsgBin, RetList) -> <> = MsgBin, deInt16List(N - 1, LeftBin, [Int | RetList]). deUint16List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deUint16List(N, MsgBin, RetList) -> <> = MsgBin, deUint16List(N - 1, LeftBin, [Int | RetList]). deInt32List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deInt32List(N, MsgBin, RetList) -> <> = MsgBin, deInt32List(N - 1, LeftBin, [Int | RetList]). deUint32List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deUint32List(N, MsgBin, RetList) -> <> = MsgBin, deUint32List(N - 1, LeftBin, [Int | RetList]). deInt64List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deInt64List(N, MsgBin, RetList) -> <> = MsgBin, deInt64List(N - 1, LeftBin, [Int | RetList]). deUint64List(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deUint64List(N, MsgBin, RetList) -> <> = MsgBin, deUint64List(N - 1, LeftBin, [Int | RetList]). deIntegerList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deIntegerList(N, MsgBin, RetList) -> <> = MsgBin, deIntegerList(N - 1, LeftBin, [Int | RetList]). deNumberList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deNumberList(N, MsgBin, RetList) -> <> = MsgBin, case NumBits of 33 -> <> = NumBin, deNumberList(N - 1, LeftBin, [Float | RetList]); 65 -> <> = NumBin, deNumberList(N - 1, LeftBin, [Float | RetList]); _ -> <> = NumBin, deNumberList(N - 1, LeftBin, [Int | RetList]) end. deFloatList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deFloatList(N, MsgBin, RetList) -> <> = MsgBin, deFloatList(N - 1, LeftBin, [Float | RetList]). deDoubleList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deDoubleList(N, MsgBin, RetList) -> <> = MsgBin, deDoubleList(N - 1, LeftBin, [Float | RetList]). deStringList(0, MsgBin, RetList) -> {MsgBin, lists:reverse(RetList)}; deStringList(N, MsgBin, RetList) -> <> = MsgBin, 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]).\n\n". genSchema({FieldType, _FieldName}, AccList) -> SchemaStr = protoField:getSchemaInfo(FieldType), [SchemaStr | AccList]. genMsgHrl(FieldInfo, {Index, Len, AccList}) -> TemStr = case Index of 1 -> ""; _ -> ", " end, RecStr = TemStr ++ protoField:builtRecStr(FieldInfo) ++ (case Index == Len of true -> ""; _ -> "\t" end), {Index - 1, Len, [RecStr | AccList]}. genEncodeRec({MsgName, _MsgId, FieldList}) -> FieldLen = length(FieldList), FunHead = fun(_, {Index, StrAcc}) -> {Index - 1, ", V" ++ integer_to_list(Index) ++ StrAcc} end, {_, TemStr} = lists:foldr(FunHead, {FieldLen, "}) ->\n\t"}, FieldList), HeadStr = "encodeRec({" ++ MsgName ++ TemStr, FunBody = fun({FieldType, _FieldName}, {Index, PStrAcc}) -> TemV = "V" ++ integer_to_list(Index), PackStr = protoField:builtPackStr(FieldType) ++ TemV ++ ")", case Index == 1 of true -> {Index - 1, PackStr ++ PStrAcc}; _ -> {Index - 1, ", " ++ PackStr ++ PStrAcc} end end, {_, LastStr} = lists:foldr(FunBody, {FieldLen, ""}, FieldList), case FieldLen > 0 of true -> HeadStr ++ "[" ++ LastStr ++ "];\n"; _ -> HeadStr ++ "[];\n" end. convertFile(File) -> protoParse:parseFile(File). convert([ProtoDir, HrlDir, ErlDir]) -> convertDir(atom_to_list(ProtoDir), atom_to_list(HrlDir), atom_to_list(ErlDir)). convertDir() -> convertDir("./", "./", "./"). convertDir(ProtoDir) -> convertDir(ProtoDir, "./", "./"). convertDir(ProtoDir, HrlDir, ErlDir) -> FunRead = fun(File, Acc) -> case filename:extension(File) == ".msg" of true -> io:format("Convert proto msg file: ~s ~n", [File]), BaseName = filename:basename(File, ".msg"), [ModIndex | _ModName] = re:split(BaseName, "_"), Index = binary_to_integer(ModIndex), put(messageid, Index * 1000 + 1), SProto = protoParse:parseFile(File), [SProto | Acc]; _ -> Acc end end, %% 下面文件帅选并不能准确的帅选出文件名为.msg结尾的文件 在FunRead函数中纠正处理一下 SProtoListOfList = filelib:fold_files(ProtoDir, "\\.msg", true, FunRead, []), SProtoList = lists:append(SProtoListOfList), SortedSProtoList = lists:sort(fun({_Name1, MessageId1, _FieldList1}, {_Name2, MessageId2, _FieldList2}) -> MessageId1 > MessageId2 end, SProtoList), FunSpell = fun({MsgName, MsgId, FieldList} = MsgInfo, {MsgHrlAcc, MsgTypeAcc, MsgIdAcc, MsgEndStr, MsgSchemaAcc}) -> TypeStr = "getMsgType(" ++ integer_to_list(MsgId) ++ ")-> " ++ MsgName ++ ";\n", IdStr = "getMsgId(" ++ MsgName ++ ")-> " ++ integer_to_list(MsgId) ++ ";\n", EncodeStr = genEncodeRec(MsgInfo), Len = erlang:length(FieldList), SchemaList = lists:foldr(fun genSchema/2, [], FieldList), SchemaStr = "getMsgSchema(" ++ MsgName ++ ")->\n\t" ++ "getMsgSchema(" ++ integer_to_list(MsgId) ++ ");\n" ++ "getMsgSchema(" ++ integer_to_list(MsgId) ++ ")->\n\t" ++ io_lib:format("~p", [SchemaList]) ++ ";\n", {_, Len, LastFieldStr} = lists:foldr(fun genMsgHrl/2, {Len, Len, ""}, FieldList), HrlStr = "-record(" ++ MsgName ++ " ,{\n\t" ++ LastFieldStr ++ "}).\n", {[HrlStr | MsgHrlAcc], [TypeStr | MsgTypeAcc], [IdStr | MsgIdAcc], [EncodeStr | MsgEndStr], [SchemaStr | MsgSchemaAcc]} end, {MsgHrlStr, MsgTypeStr, MsgIdStr, MsgEndStr, MsgSchemaStr} = lists:foldl(FunSpell, {[], ["getMsgType(_) -> undefined.\n\n"], ["getMsgId(_) -> 0.\n\n"], ["encodeRec(_) ->\n\t[].\n\n"], ["getMsgSchema(_) ->\n\t[].\n\n"]}, SortedSProtoList), ModStr = protoErlHeader(), OutputStr = ModStr ++ MsgTypeStr ++ MsgIdStr ++ MsgEndStr ++ MsgSchemaStr, HrlFilename = do_write_hrl(HrlDir, protoMsg, protoHrlHeader() ++ MsgHrlStr), ErlFilename = do_write_erl(ErlDir, protoMsg, OutputStr), io:format("protoConvert hrl dir : ~s ~n", [HrlDir]), io:format("protoConvert erl dir : ~s ~n", [ErlDir]), io:format("protoConvert to hrl file ~s succ.~n", [HrlFilename]), io:format("protoConvert to erl file ~s succ.~n", [ErlFilename]), ok. do_write_hrl(OutDir, Mod, Str) when is_list(OutDir) -> Filename = filename:join([OutDir, atom_to_list(Mod) ++ ".hrl"]), ok = file:write_file(Filename, Str), Filename. do_write_erl(OutDir, Mod, Str) when is_list(OutDir) -> Filename = filename:join([OutDir, atom_to_list(Mod) ++ ".erl"]), ok = file:write_file(Filename, Str), Filename.