private Dictionary <T, SprotoObject> DecodeSprotoObjectDict <T> (SprotoMgr sprotomgr, SprotoType type, SprotoField field, SprotoStream reader) { Dictionary <T, SprotoObject> dict = new Dictionary <T, SprotoObject>(); UInt32 size = this.ReadUInt32(reader); while (size > 0) { UInt32 elem_size = this.ReadUInt32(reader); UInt32 need_size = elem_size + SprotoCodec.SIZEOF_LENGTH; size = size - need_size; if (size < 0) { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObjectDict] fail"); } SprotoObject elemobj = this.DecodeSprotoObject(sprotomgr, type, reader); SprotoObject keyobj = elemobj.Get(field.key); T key = (T)keyobj.val; dict[key] = elemobj; } if (size != 0) { SprotoHelper.Error("[SprotoCodec.DecodeSprotoObjectDict] fail"); } return(dict); }
private UInt32 EncodeSprotoObjectDict <T> (SprotoMgr sprotomgr, Dictionary <T, SprotoObject> dict, SprotoField field, SprotoStream writer) { UInt32 size = 0; List <T> keys = new List <T>(dict.Keys); keys.Sort(); // keep encode stable foreach (var key in keys) { SprotoObject elemobj = dict[key]; if (elemobj.Get(field.key) == null) { SprotoHelper.Error("[SprotoCodec.EncodeSprotoObjectDict] exist null mainindex '{0}' in field '{1}'", field.key, field.name); } SprotoType elemtype = sprotomgr.GetType(elemobj.type); int elemsize_pos = writer.Position; writer.Seek(SprotoCodec.SIZEOF_LENGTH, SprotoStream.SEEK_CUR); UInt32 elemsize = this.EncodeSprotoObject(sprotomgr, elemtype, elemobj, writer); this.FillSize(writer, elemsize_pos, elemsize); size += (SprotoCodec.SIZEOF_LENGTH + elemsize); } return(size); }
// Parser from binary(*.spb) private static void _ParseFromBinary(SprotoMgr sprotomgr, byte[] bytes, int length) { SprotoMgr meta = SprotoParser.Parse(meta_proto); SprotoStream reader = new SprotoStream(); reader.Write(bytes, 0, length); reader.Seek(0, SprotoStream.SEEK_BEGIN); SprotoObject group = meta.Decode("group", reader); List <SprotoObject> types = null; List <SprotoObject> protocols = null; if (group.Get("type") != null) { types = group.Get("type"); foreach (SprotoObject meta_type in types) { SprotoType type = new SprotoType(); type.name = meta_type["name"]; if (meta_type.Has("fields")) { List <SprotoObject> fields = meta_type["fields"]; foreach (SprotoObject meta_field in fields) { SprotoField field = new SprotoField(); field.name = meta_field["name"]; field.tag = (UInt16)meta_field["tag"]; field.is_array = false; if (meta_field.Has("array")) { field.is_array = (bool)meta_field["array"]; } Int64 type_id; if (meta_field.Has("buildin")) { type_id = meta_field["buildin"]; field.type = SprotoParser.BuildInTypeId2Name[type_id]; if (type_id == 0 && meta_field.Has("type")) { // fixed float field.digit = (UInt16)meta_field["type"]; } else if (type_id == 2 && meta_field.Has("type")) { // binary field.type = "binary"; } } else { type_id = meta_field["type"]; SprotoObject t = types[(int)type_id]; field.type = t["name"]; // map if (meta_field.Has("key")) { SprotoHelper.Assert(field.is_array); UInt16 map_index = (UInt16)meta_field["key"]; List <SprotoObject> t_fields = t["fields"]; string name = null; foreach (SprotoObject f in t_fields) { if (f["tag"] == map_index) { name = f["name"]; break; } } SprotoHelper.Assert(name != null, String.Format("map index {0} cann't find in type '{1}'", map_index, field.type)); field.key = name; } } type.AddField(field); } } sprotomgr.AddType(type); } } if (group.Get("protocol") != null) { protocols = group.Get("protocol"); foreach (SprotoObject meta_protocol in protocols) { SprotoProtocol protocol = new SprotoProtocol(); protocol.name = meta_protocol["name"]; protocol.tag = (UInt16)meta_protocol["tag"]; if (meta_protocol["request"] != null) { Int64 request = meta_protocol["request"]; protocol.request = types[(int)request]["name"]; } if (meta_protocol["response"] != null) { Int64 response = meta_protocol["response"]; protocol.response = types[(int)response]["name"]; } bool confirm = meta_protocol["confirm"]; if (confirm) { protocol.response = null; } sprotomgr.AddProtocol(protocol); } } }
private UInt32 EncodeSprotoObject(SprotoMgr sprotomgr, SprotoType type, SprotoObject obj, SprotoStream writer) { // encode header part List <UInt16> tags = new List <UInt16>(type.tagfields.Keys); tags.Sort(); UInt16 fieldnum = 0; Int16 lasttag = -1; int fieldnum_pos = writer.Position; writer.Seek(SprotoCodec.SIZEOF_FIELD, SprotoStream.SEEK_CUR); List <UInt16> data_tags = new List <UInt16>(); for (int i = 0; i < tags.Count; i++) { UInt16 tag = tags[i]; SprotoField field = type.GetField(tag); SprotoObject fieldobj = obj.Get(field.name); if (fieldobj != null) { UInt16 skiptag = (UInt16)(tag - lasttag); //Console.WriteLine("skiptag: tag={0},lasttag={1},skiptag={2}",tag,lasttag,skiptag); lasttag = (Int16)tag; if (skiptag > 1) { skiptag = (UInt16)((skiptag - 1) * 2 - 1); this.WriteTag(writer, skiptag); fieldnum++; } fieldnum++; bool encode_in_header = false; if (!field.is_array) { if (field.type == "integer") { Int64 integer; if (field.digit == 0) { integer = (Int64)fieldobj.val; } else { integer = (Int64)(Math.Round((double)fieldobj.val * MathPow(10, field.digit))); } if (this.IsSmallInteger(integer)) { encode_in_header = true; UInt16 number = (UInt16)((integer + 1) * 2); this.WriteTag(writer, number); } } else if (field.type == "boolean") { encode_in_header = true; bool ok = (bool)fieldobj.val; UInt16 integer = (UInt16)(ok ? 1 : 0); UInt16 number = (UInt16)((integer + 1) * 2); this.WriteTag(writer, number); } } if (!encode_in_header) { this.WriteTag(writer, 0); data_tags.Add(tag); } else { } } } this.FillFieldNum(writer, fieldnum_pos, fieldnum); UInt32 size = SprotoCodec.SIZEOF_FIELD + fieldnum * SprotoCodec.SIZEOF_FIELD; // encode data part foreach (UInt16 tag in data_tags) { SprotoField field = type.GetField(tag); SprotoType fieldtype = sprotomgr.GetType(field.type); SprotoObject fieldobj = obj.Get(field.name); int fieldsize_pos = writer.Position; UInt32 fieldsize = 0; writer.Seek(SprotoCodec.SIZEOF_LENGTH, SprotoStream.SEEK_CUR); if (SprotoHelper.IsBuildInType(field.type)) { fieldsize = this.EncodeBuildInType(field, fieldobj, writer); } else { if (field.is_array) { if (field.key != null) { string keytype = fieldtype.GetField(field.key).type; if (keytype == "integer") { Dictionary <Int64, SprotoObject> dict = fieldobj.val as Dictionary <Int64, SprotoObject>; fieldsize = this.EncodeSprotoObjectDict <Int64>(sprotomgr, dict, field, writer); } else if (keytype == "string") { Dictionary <string, SprotoObject> dict = fieldobj.val as Dictionary <string, SprotoObject>; fieldsize = this.EncodeSprotoObjectDict <string>(sprotomgr, dict, field, writer); } else if (keytype == "boolean") { Dictionary <bool, SprotoObject> dict = fieldobj.val as Dictionary <bool, SprotoObject>; fieldsize = this.EncodeSprotoObjectDict <bool>(sprotomgr, dict, field, writer); } else { SprotoHelper.Error("[SprotoCodec.EncodeSprotoObject] keytype expect 'integer/boolean/string' got '{0}'", keytype); } } else { List <SprotoObject> list = fieldobj.val as List <SprotoObject>; fieldsize = this.EncodeSprotoObjectList(sprotomgr, list, writer); } } else { fieldsize = this.EncodeSprotoObject(sprotomgr, fieldtype, fieldobj, writer); } } this.FillSize(writer, fieldsize_pos, fieldsize); size += (fieldsize + SprotoCodec.SIZEOF_LENGTH); } return(size); }