public static string GenerateFieldReader(Field f) { string code = ""; if (f.Rule == FieldRule.Repeated) { if (f.OptionPacked == true) { code += "using(MemoryStream ms" + f.ID + " = new MemoryStream(ProtocolParser.ReadBytes(stream)))\n"; code += "{\n"; code += " while(true)\n"; code += " {\n"; code += " if(ms" + f.ID + ".Position == ms" + f.ID + ".Length)\n"; code += " break;\n"; code += " instance." + f.Name + ".Add(" + GenerateFieldTypeReader (f, "ms" + f.ID, "br", null) + ");\n"; code += " }\n"; code += "}\n"; } else { code += "instance." + f.Name + ".Add(" + GenerateFieldTypeReader (f, "stream", "br", null) + ");\n"; } } else { if (f.ProtoType == ProtoTypes.Message) { code += "if(instance." + f.Name + " == null)\n"; code += " instance." + f.Name + " = " + GenerateFieldTypeReader (f, "stream", "br", null) + ";\n"; code += "else\n"; code += " instance." + f.Name + " = " + GenerateFieldTypeReader (f, "stream", "br", "instance." + f.Name) + ";"; } else code += "instance." + f.Name + " = " + GenerateFieldTypeReader (f, "stream", "br", "instance." + f.Name) + ";"; } return code; }
/// <summary> /// Get the default value in c# form /// </summary> static string GetCSDefaultValue(Field f) { switch (f.ProtoType) { case ProtoTypes.Double: case ProtoTypes.Float: case ProtoTypes.Fixed32: case ProtoTypes.Fixed64: case ProtoTypes.Sfixed32: case ProtoTypes.Sfixed64: case ProtoTypes.Int32: case ProtoTypes.Int64: case ProtoTypes.Uint32: case ProtoTypes.Uint64: case ProtoTypes.Sint32: case ProtoTypes.Sint64: case ProtoTypes.Bool: return f.OptionDefault; case ProtoTypes.String: return f.OptionDefault; case ProtoTypes.Bytes: throw new NotImplementedException (); case ProtoTypes.Enum: return f.OptionDefault; case ProtoTypes.Message: throw new InvalidDataException ("Don't think there can be a default for messages"); default: throw new NotImplementedException (); } }
public static string GenerateFieldTypeWriter(Field f, string stream, string binaryWriter, string instance) { if (f.OptionCodeType != null) { switch (f.OptionCodeType) { case "DateTime": case "TimeSpan": return "ProtocolParser.WriteUInt64 (" + stream + ", (ulong)" + instance + ".Ticks);\n"; default: //enum break; } } switch (f.ProtoType) { case ProtoTypes.Double: case ProtoTypes.Float: case ProtoTypes.Fixed32: case ProtoTypes.Fixed64: case ProtoTypes.Sfixed32: case ProtoTypes.Sfixed64: return binaryWriter + ".Write(" + instance + ");\n"; case ProtoTypes.Int32: return "ProtocolParser.WriteUInt32(" + stream + ", (uint)" + instance + ");\n"; case ProtoTypes.Int64: return "ProtocolParser.WriteUInt64(" + stream + ", (ulong)" + instance + ");\n"; case ProtoTypes.Uint32: return "ProtocolParser.WriteUInt32(" + stream + ", " + instance + ");\n"; case ProtoTypes.Uint64: return "ProtocolParser.WriteUInt64(" + stream + ", " + instance + ");\n"; case ProtoTypes.Sint32: return "ProtocolParser.WriteSInt32(" + stream + ", " + instance + ");\n"; case ProtoTypes.Sint64: return "ProtocolParser.WriteSInt64(" + stream + ", " + instance + ");\n"; case ProtoTypes.Bool: return "ProtocolParser.WriteBool(" + stream + ", " + instance + ");\n"; case ProtoTypes.String: return "ProtocolParser.WriteString(" + stream + ", " + instance + ");\n"; case ProtoTypes.Bytes: return "ProtocolParser.WriteBytes(" + stream + ", " + instance + ");\n"; case ProtoTypes.Enum: return "ProtocolParser.WriteUInt32(" + stream + ", (uint)" + instance + ");\n"; case ProtoTypes.Message: string code = ""; code += "using(MemoryStream ms" + f.ID + " = new MemoryStream())\n"; code += "{\n"; code += " " + f.FullPath + ".Serialize(ms" + f.ID + ", " + instance + ");\n"; code += " ProtocolParser.WriteBytes(" + stream + ", ms" + f.ID + ".ToArray());\n"; code += "}\n"; return code; default: throw new NotImplementedException (); } }
protected virtual string GenerateProperty(Field f) { return f.OptionAccess + " " + f.PropertyType + " " + f.Name + " { get; set; }"; }
/// <summary> /// Prepare: ProtoType, WireType and CSType /// </summary> static void PrepareProtoType(Message m, Field f) { //Change property name to C# style, CamelCase. f.Name = GetCSPropertyName (m, f.Name); f.ProtoType = GetScalarProtoType (f.ProtoTypeName); //Wire, and set type switch (f.ProtoType) { case ProtoTypes.Double: case ProtoTypes.Fixed64: case ProtoTypes.Sfixed64: f.WireType = Wire.Fixed64; break; case ProtoTypes.Float: case ProtoTypes.Fixed32: case ProtoTypes.Sfixed32: f.WireType = Wire.Fixed32; break; case ProtoTypes.Int32: case ProtoTypes.Int64: case ProtoTypes.Uint32: case ProtoTypes.Uint64: case ProtoTypes.Sint32: case ProtoTypes.Sint64: case ProtoTypes.Bool: f.WireType = Wire.Varint; break; case ProtoTypes.String: case ProtoTypes.Bytes: f.WireType = Wire.LengthDelimited; break; default: MessageEnumBase pt = GetProtoType (m, f.ProtoTypeName); if (pt == null) { //Assumed to be a message defined elsewhere f.ProtoType = ProtoTypes.Message; f.WireType = Wire.LengthDelimited; f.ProtoTypeMessage = new MessageName (m, f.ProtoTypeName); } if (pt is MessageEnum) { f.ProtoType = ProtoTypes.Enum; f.WireType = Wire.Varint; f.ProtoTypeEnum = (MessageEnum)pt; } if (pt is Message) { f.ProtoType = ProtoTypes.Message; f.WireType = Wire.LengthDelimited; f.ProtoTypeMessage = (Message)pt; } string[] parts = f.ProtoTypeName.Split ('.'); string cc = GetCamelCase (parts [parts.Length - 1]); if (pt is Message) { f.CSClass = cc; #if GENERATE_INTERFACE f.CSType += "I" + cc; #else f.CSType += cc; #endif break; } else f.CSType = cc; break; } if (f.OptionPacked) { if (f.WireType == Wire.LengthDelimited) throw new InvalidDataException ("Packed field not allowed for length delimited types"); f.WireType = Wire.LengthDelimited; } if (f.OptionCodeType != null) { f.CSClass = f.OptionCodeType; f.CSType = f.OptionCodeType; } if (f.CSType == null) { f.CSType = GetCSType (f.ProtoType); f.CSClass = f.CSType; } }
static void ParseFieldOption(string key, string val, Field f) { switch (key) { case "default": f.OptionDefault = val; break; case "packed": f.OptionPacked = Boolean.Parse (val); break; case "deprecated": f.OptionDeprecated = Boolean.Parse (val); break; //Local options: case "access": f.OptionAccess = val; break; case "codetype": if (val == "DateTime" || val == "TimeSpan") { if (f.ProtoTypeName != "int64") throw new ProtoFormatException ("DateTime and TimeSpan must be stored in int64. was " + f.ProtoTypeName); } f.OptionCodeType = val; break; case "generate": f.OptionGenerate = Boolean.Parse (val); break; default: Console.WriteLine ("Warning: Unknown field option: " + key); break; } }
static bool ParseField(TokenReader tr, Message m) { string rule = tr.ReadNext (); while (true) { if (ParseComment (rule) == false) break; rule = tr.ReadNext (); } if (rule == "}") return false; if (rule == "enum") { MessageEnum me = ParseEnum (tr, m); m.Enums.Add (me); return true; } Field f = new Field (); f.Comments = lastComment; lastComment = null; //Rule switch (rule) { case "required": f.Rule = FieldRule.Required; break; case "optional": f.Rule = FieldRule.Optional; break; case "repeated": f.Rule = FieldRule.Repeated; break; case "option": //Save options ParseOption (tr, m); return true; case "message": m.Messages.Add (ParseMessage (tr, m)); return true; default: throw new ProtoFormatException ("unknown rule: " + rule); } //Type f.ProtoTypeName = tr.ReadNext (); //Name f.Name = tr.ReadNext (); //ID tr.ReadNextOrThrow ("="); f.ID = int.Parse (tr.ReadNext ()); if (19000 <= f.ID && f.ID <= 19999) throw new ProtoFormatException ("Can't use reserved field ID 19000-19999"); if (f.ID > (1 << 29) - 1) throw new ProtoFormatException ("Maximum field id is 2^29 - 1"); //Add Field to message m.Fields.Add (f.ID, f); //Determine if extra options string extra = tr.ReadNext (); if (extra == ";") return true; //Field options if (extra != "[") throw new ProtoFormatException ("Expected: [ got " + extra); while (true) { string key = tr.ReadNext (); tr.ReadNextOrThrow ("="); string val = tr.ReadNext (); ParseFieldOption (key, val, f); string optionSep = tr.ReadNext (); if (optionSep == "]") break; if (optionSep == ",") continue; throw new ProtoFormatException (@"Expected "","" or ""]"" got " + tr.Next); } tr.ReadNextOrThrow (";"); return true; }
/// <summary> /// Generates code for writing one field /// </summary> public static string GenerateFieldWriter(Message m, Field f) { string code = ""; if (f.Rule == FieldRule.Repeated) { if (f.OptionPacked == true) { string binaryWriter = ""; switch (f.ProtoType) { case ProtoTypes.Double: case ProtoTypes.Float: case ProtoTypes.Fixed32: case ProtoTypes.Fixed64: case ProtoTypes.Sfixed32: case ProtoTypes.Sfixed64: binaryWriter = "\nBinaryWriter bw" + f.ID + " = new BinaryWriter(ms" + f.ID + ");"; break; } code += "if(instance." + f.Name + " != null)\n"; code += "{\n"; code += " ProtocolParser.WriteKey(stream, new ProtocolBuffers.Key(" + f.ID + ", Wire." + f.WireType + "));\n"; code += " using(MemoryStream ms" + f.ID + " = new MemoryStream())\n"; code += " { " + binaryWriter + "\n"; code += " foreach(" + f.PropertyItemType + " i" + f.ID + " in instance." + f.Name + ")\n"; code += " {\n"; code += Code.Indent (3, GenerateFieldTypeWriter (f, "ms" + f.ID, "bw" + f.ID, "i" + f.ID)) + "\n"; code += " }\n"; code += " ProtocolParser.WriteBytes(stream, ms" + f.ID + ".ToArray());\n"; code += " }\n"; code += "}\n"; return code; } else { code += "if(instance." + f.Name + " != null)\n"; code += "{\n"; code += " foreach(" + f.PropertyItemType + " i" + f.ID + " in instance." + f.Name + ")\n"; code += " {\n"; code += " ProtocolParser.WriteKey(stream, new ProtocolBuffers.Key(" + f.ID + ", Wire." + f.WireType + "));\n"; code += Code.Indent (2, GenerateFieldTypeWriter (f, "stream", "bw", "i" + f.ID)) + "\n"; code += " }\n"; code += "}\n"; return code; } } else if (f.Rule == FieldRule.Optional) { switch (f.ProtoType) { case ProtoTypes.String: case ProtoTypes.Message: case ProtoTypes.Bytes: code += "if(instance." + f.Name + " != null)\n"; code += "{\n"; code += " ProtocolParser.WriteKey(stream, new ProtocolBuffers.Key(" + f.ID + ", Wire." + f.WireType + "));\n"; code += Code.Indent (GenerateFieldTypeWriter (f, "stream", "bw", "instance." + f.Name)); code += "}\n"; return code; case ProtoTypes.Enum: code += "if(instance." + f.Name + " != " + f.PropertyItemType + "." + f.OptionDefault + ")\n"; code += "{\n"; code += " ProtocolParser.WriteKey(stream, new ProtocolBuffers.Key(" + f.ID + ", Wire." + f.WireType + "));\n"; code += Code.Indent (GenerateFieldTypeWriter (f, "stream", "bw", "instance." + f.Name)); code += "}\n"; return code; default: code += "ProtocolParser.WriteKey(stream, new ProtocolBuffers.Key(" + f.ID + ", Wire." + f.WireType + "));\n"; code += GenerateFieldTypeWriter (f, "stream", "bw", "instance." + f.Name); return code; } } else if (f.Rule == FieldRule.Required) { switch (f.ProtoType) { case ProtoTypes.String: case ProtoTypes.Message: case ProtoTypes.Bytes: code += "if(instance." + f.Name + " == null)\n"; code += " throw new ArgumentNullException(\"" + f.Name + "\", \"Required by proto specification.\");\n"; break; } code += "ProtocolParser.WriteKey(stream, new ProtocolBuffers.Key(" + f.ID + ", Wire." + f.WireType + "));\n"; code += GenerateFieldTypeWriter (f, "stream", "bw", "instance." + f.Name); return code; } throw new NotImplementedException ("Unknown rule: " + f.Rule); }
static string GenerateFieldTypeReaderPrimitive(Field f, string stream, string instance) { switch (f.ProtoType) { case ProtoTypes.Double: return "br.ReadDouble ()"; case ProtoTypes.Float: return "br.ReadSingle ()"; case ProtoTypes.Fixed32: return "br.ReadUInt32 ()"; case ProtoTypes.Fixed64: return "br.ReadUInt64 ()"; case ProtoTypes.Sfixed32: return "br.ReadInt32 ()"; case ProtoTypes.Sfixed64: return "br.ReadInt64 ()"; case ProtoTypes.Int32: return "(int)ProtocolParser.ReadUInt32(" + stream + ")"; case ProtoTypes.Int64: return "(long)ProtocolParser.ReadUInt64(" + stream + ")"; case ProtoTypes.Uint32: return "ProtocolParser.ReadUInt32(" + stream + ")"; case ProtoTypes.Uint64: return "ProtocolParser.ReadUInt64(" + stream + ");"; case ProtoTypes.Sint32: return "ProtocolParser.ReadSInt32(" + stream + ");"; case ProtoTypes.Sint64: return "ProtocolParser.ReadSInt64(" + stream + ");"; case ProtoTypes.Bool: return "ProtocolParser.ReadBool(" + stream + ")"; case ProtoTypes.String: return "ProtocolParser.ReadString(" + stream + ")"; case ProtoTypes.Bytes: return "ProtocolParser.ReadBytes(" + stream + ")"; case ProtoTypes.Enum: return "(" + f.PropertyItemType + ")ProtocolParser.ReadUInt32(" + stream + ")"; case ProtoTypes.Message: if (f.Rule == FieldRule.Repeated) return f.FullPath + ".Deserialize(ProtocolParser.ReadBytes(" + stream + "))"; else { if (instance == null) return f.FullPath + ".Deserialize(ProtocolParser.ReadBytes(" + stream + "))"; else return f.FullPath + ".Deserialize(ProtocolParser.ReadBytes(" + stream + "), " + instance + ")"; } default: throw new NotImplementedException (); } }
static string GenerateFieldTypeReader(Field f, string stream, string binaryReader, string instance) { if (f.OptionCodeType != null) { switch (f.OptionCodeType) { case "DateTime": return "new DateTime((long)ProtocolParser.ReadUInt64 (" + stream + "))"; case "TimeSpan": return "new TimeSpan((long)ProtocolParser.ReadUInt64 (" + stream + "))"; default: //Assume enum return "(" + f.OptionCodeType + ")" + GenerateFieldTypeReaderPrimitive (f, stream, instance); } } return GenerateFieldTypeReaderPrimitive (f, stream, instance); }