예제 #1
0
 static void ParseFieldFlags(Field field, string flag)
 {
     switch (flag)
     {
         case "external":
             field.OptionExternal = true;
             break;
         case "readonly":
             field.OptionReadOnly = true;
             break;
         default:
             throw new  NotImplementedException("Unknown field option: " + flag);
     }
 }
예제 #2
0
 static void ParseFieldOption(Field field, string key, string value)
 {
     switch (key)
     {
         case "access":
             field.OptionAccess = value;
             break;
         case "codetype":
             field.OptionCodeType = value;
             break;
         default:
             throw new NotImplementedException("Unknown field option: " + key);
     }
 }
예제 #3
0
        /// <summary>
        /// Detect field which have the same name as a submessage in the same message.
        /// </summary>
        /// <param name="m">Parent message</param>
        /// <param name="f">Field to check</param>
        void DetectNameClash(ProtoMessage m, Field f)
        {
            bool nameclash = false;
            if (m.CsType == f.CsName)
                nameclash = true;
            foreach (var tm in m.Messages.Values)
                if (tm.CsType == f.CsName)
                    nameclash = true;
            foreach (var te in m.Enums.Values)
                if (te.CsType == f.CsName)
                    nameclash = true;
            foreach (var tf in m.Fields.Values)
            {
                if (tf == f)
                    continue;
                if (tf.CsName == f.CsName)
                    nameclash = true;
            }
            if (nameclash == false)
                return;

            //Name clash
            if (options.FixNameclash)
            {
                if (ConvertToCamelCase)
                    f.CsName += "Field";
                else
                    f.CsName += "_field";


                Console.Error.WriteLine("Warning: renamed field: " + m.FullCsType + "." + f.CsName);

                //Make sure our change did not result in another name collission
                DetectNameClash(m, f);
            }
            else
                throw new ProtoFormatException("The field: " + m.FullCsType + "." + f.CsName +
                    " has the same name as a sibling class/enum type which is not allowed in C#. " +
                    "Use --fix-nameclash to automatically rename the field.", f.Source);
        }
예제 #4
0
 static string FieldWriterType(Field f, string stream, string binaryWriter, string instance)
 {
     if (f.OptionCodeType != null)
     {
         switch (f.OptionCodeType)
         {
             case "DateTime":
             case "TimeSpan":
                 return FieldWriterPrimitive(f, stream, binaryWriter, instance + ".Ticks");
             default: //enum
                 break;
         }
     }
     return FieldWriterPrimitive(f, stream, binaryWriter, instance);
 }
예제 #5
0
        static string FieldWriterPrimitive(Field f, string stream, string binaryWriter, string instance)
        {
            if (f.ProtoType is ProtoEnum)
                return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteUInt64(" + stream + ",(ulong)" + instance + ");";

            if (f.ProtoType is ProtoMessage)
            {
                ProtoMessage pm = f.ProtoType as ProtoMessage;
                CodeWriter cw = new CodeWriter();
                cw.Using("var ms" + f.ID + " = new MemoryStream()");
                cw.WriteLine(pm.FullSerializerType + ".Serialize(ms" + f.ID + ", " + instance + ");");
                BytesWriter(stream, "ms" + f.ID, cw);
                cw.EndBracket();
                return cw.Code;
            }

            switch (f.ProtoType.ProtoName)
            {
                case ProtoBuiltin.Double:
                case ProtoBuiltin.Float:
                case ProtoBuiltin.Fixed32:
                case ProtoBuiltin.Fixed64:
                case ProtoBuiltin.SFixed32:
                case ProtoBuiltin.SFixed64:
                    return binaryWriter + ".Write(" + instance + ");";
                case ProtoBuiltin.Int32: //Serialized as 64 bit varint
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteUInt64(" + stream + ",(ulong)" + instance + ");";
                case ProtoBuiltin.Int64:
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteUInt64(" + stream + ",(ulong)" + instance + ");";
                case ProtoBuiltin.UInt32:
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteUInt32(" + stream + ", " + instance + ");";
                case ProtoBuiltin.UInt64:
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteUInt64(" + stream + ", " + instance + ");";
                case ProtoBuiltin.SInt32:
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteZInt32(" + stream + ", " + instance + ");";
                case ProtoBuiltin.SInt64:
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteZInt64(" + stream + ", " + instance + ");";
                case ProtoBuiltin.Bool:
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteBool(" + stream + ", " + instance + ");";
                case ProtoBuiltin.String:
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteBytes(" + stream + ", Encoding.UTF8.GetBytes(" + instance + "));";
                case ProtoBuiltin.Bytes:
                    return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteBytes(" + stream + ", " + instance + ");";
            }

            throw new NotImplementedException();
        }
예제 #6
0
        static string FieldReaderType(Field f, string stream, string binaryReader, string instance)
        {
            if (f.OptionCodeType != null)
            {
                switch (f.OptionCodeType)
                {
                    case "DateTime":
                        switch (f.ProtoType.ProtoName)
                        {
                            case ProtoBuiltin.UInt64:
                            case ProtoBuiltin.Int64:
                            case ProtoBuiltin.Fixed64:
                            case ProtoBuiltin.SFixed64:
                                return "new DateTime((long)" + FieldReaderPrimitive(f, stream, binaryReader, instance) + ")";
                        }
                        throw new FormatException("Local feature, DateTime, must be stored in a 64 bit field");

                    case "TimeSpan":
                        switch (f.ProtoType.ProtoName)
                        {
                            case ProtoBuiltin.UInt64:
                            case ProtoBuiltin.Int64:
                            case ProtoBuiltin.Fixed64:
                            case ProtoBuiltin.SFixed64:
                                return "new TimeSpan((long)" + FieldReaderPrimitive(f, stream, binaryReader, instance) + ")";
                        }
                        throw new FormatException("Local feature, TimeSpan, must be stored in a 64 bit field");

                    default:
                        //Assume enum
                        return "(" + f.OptionCodeType + ")" + FieldReaderPrimitive(f, stream, binaryReader, instance);
                }
            }

            return FieldReaderPrimitive(f, stream, binaryReader, instance);
        }
예제 #7
0
        string GenerateProperty(Field f)
        {
            string type = f.ProtoType.FullCsType;
            if (f.OptionCodeType != null)
                type = f.OptionCodeType;
            if (f.Rule == FieldRule.Repeated)
                type = "List<" + type + ">";
            if (f.Rule == FieldRule.Optional && !f.ProtoType.Nullable && options.Nullable)
                type = type + "?";

            if (f.OptionReadOnly)
                return f.OptionAccess + " readonly " + type + " " + f.CsName + " = new " + type + "();";
            else if (f.ProtoType is ProtoMessage && f.ProtoType.OptionType == "struct")
                return f.OptionAccess + " " + type + " " + f.CsName + ";";
            else
            {
                string line = "private " + type + " _" + f.CsName;
                switch (f.ProtoType.ProtoName)
                {
                    case ProtoBuiltin.Double:
                        line += " = 0.0D";
                        break;
                    case ProtoBuiltin.Float:
                        line += " = 0.0F";
                        break;
                    case ProtoBuiltin.Int32: //Wire format is 64 bit varint
                        line += " = 0";
                        break;
                    case ProtoBuiltin.Int64:
                        line += " = 0l";
                        break;
                    case ProtoBuiltin.UInt32:
                        line += " = 0u";
                        break;
                    case ProtoBuiltin.UInt64:
                        line += " = 0ul";
                        break;
                    case ProtoBuiltin.SInt32:
                        line += " = 0";
                        break;
                    case ProtoBuiltin.SInt64:
                        line += " = 0";
                        break;
                    case ProtoBuiltin.Fixed32:
                        line += " = 0";
                        break;
                    case ProtoBuiltin.Fixed64:
                        line += " = 0";
                        break;
                    case ProtoBuiltin.SFixed32:
                        line += " = 0";
                        break;
                    case ProtoBuiltin.SFixed64:
                        line += " = 0";
                        break;
                    case ProtoBuiltin.Bool:
                        line += " = false";
                        break;
                    case ProtoBuiltin.String:
                        line += " = null";
                        break;
                }
                line += ";\r\n";
                line += f.OptionAccess + " " + type + " " + f.CsName;
                line += " \r\n{";
                line += "\r\n\tget\r\n\t{\r\n\t\treturn _" + f.CsName + ";\r\n\t}";
                line += "\r\n\tset\r\n\t{\r\n\t\tChangedProp += \"" + f.CsName + ",\";\r\n\t\t_" + f.CsName + " = value;\r\n\t}\r\n}";
                return line;
            }
        }
예제 #8
0
 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;
         default:
             Console.WriteLine("Warning: Unknown field option: " + key);
             break;
     }
 }
 void FieldWriterType(Field f, string stream, string binaryWriter, string instance, CodeWriter cw)
 {
     if (f.OptionCodeType != null)
     {
         switch (f.OptionCodeType)
         {
             case "DateTime":
                 if (options.Utc)
                 {
                     cw.WriteLine(FieldWriterPrimitive(f, stream, binaryWriter, "(" + instance + ".Kind == DateTimeKind.Utc ? " + instance + " : " + instance + ".ToUniversalTime()).Ticks"));
                 }
                 else
                     cw.WriteLine(FieldWriterPrimitive(f, stream, binaryWriter, instance + ".Ticks"));
                 return;
             case "TimeSpan":
                 cw.WriteLine(FieldWriterPrimitive(f, stream, binaryWriter, instance + ".Ticks"));
                 return;
             default: //enum
                 break;
         }
     }
     cw.WriteLine(FieldWriterPrimitive(f, stream, binaryWriter, instance));
     return;
 }
        /// <summary>
        /// Generates code for writing one field
        /// </summary>
        public void FieldWriter(ProtoMessage m, Field f, CodeWriter cw, Options options)
        {
            if (f.Rule == FieldRule.Repeated)
            {
                if (f.OptionPacked == true)
                {
                    //Repeated packed
                    cw.IfBracket("instance." + f.CsName + " != null");

                    KeyWriter("stream", f.ID, Wire.LengthDelimited, cw);
                    if (f.ProtoType.WireSize < 0)
                    {
                        //Un-optimized, unknown size
                        cw.WriteLine("msField.SetLength(0);");
                        if (f.IsUsingBinaryWriter)
                            cw.WriteLine("BinaryWriter bw" + f.ID + " = new BinaryWriter(ms" + f.ID + ");");

                        cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName);
                        FieldWriterType(f, "msField", "bw" + f.ID, "i" + f.ID, cw);
                        cw.EndBracket();

                        BytesWriter(f, "stream", cw);
                    }
                    else
                    {
                        //Optimized with known size
                        //No memorystream buffering, write size first at once

                        //For constant size messages we can skip serializing to the MemoryStream
                        cw.WriteLine(ProtocolParser.Base + ".WriteUInt32(stream, " + f.ProtoType.WireSize + "u * (uint)instance." + f.CsName + ".Count);");

                        cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName);
                        FieldWriterType(f, "stream", "bw", "i" + f.ID, cw);
                        cw.EndBracket();
                    }
                    cw.EndBracket();
                }
                else
                {
                    //Repeated not packet
                    cw.IfBracket("instance." + f.CsName + " != null");
                    cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName);
                    KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                    FieldWriterType(f, "stream", "bw", "i" + f.ID, cw);
                    cw.EndBracket();
                    cw.EndBracket();
                }
                return;
            }
            else if (f.Rule == FieldRule.Optional)
            {
                bool skip = options.SkipSerializeDefault && f.OptionDefault != null;

                if (options.Nullable ||
                    f.ProtoType is ProtoMessage ||
                    f.ProtoType.ProtoName == ProtoBuiltin.String ||
                    f.ProtoType.ProtoName == ProtoBuiltin.Bytes)
                {
                    if (f.ProtoType.Nullable || options.Nullable) //Struct always exist, not optional
                        cw.IfBracket("instance." + f.CsName + " != null");
                    KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                    var needValue = !f.ProtoType.Nullable && options.Nullable;
                    FieldWriterType(f, "stream", "bw", "instance." + f.CsName + (needValue ? ".Value" : ""), cw);
                    if (f.ProtoType.Nullable || options.Nullable) //Struct always exist, not optional
                        cw.EndBracket();
                    return;
                }
                if (f.ProtoType is ProtoEnum)
                {
                    if (skip)
                        cw.IfBracket("instance." + f.CsName + " != " + f.FormatDefaultForTypeAssignment());
                    KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                    FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw);
                    if (skip)
                        cw.EndBracket();
                    return;
                }
                if (skip) //Skip writing value if default
                    cw.IfBracket("instance." + f.CsName + " != " + f.FormatDefaultForTypeAssignment());
                KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw);
                if (skip)
                    cw.EndBracket();
                return;
            }
            else if (f.Rule == FieldRule.Required)
            {
                if (f.ProtoType is ProtoMessage && f.ProtoType.OptionType != "struct" ||
                    f.ProtoType.ProtoName == ProtoBuiltin.String ||
                    f.ProtoType.ProtoName == ProtoBuiltin.Bytes)
                {
                    cw.WriteLine("if (instance." + f.CsName + " == null)");
                    cw.WriteIndent("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"" + f.CsName + " is required by the proto specification.\");");
                }
                KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw);
                return;
            }
            throw new NotImplementedException("Unknown rule: " + f.Rule);
        }
        /// <summary>
        /// Return true for normal code and false if generated thrown exception.
        /// In the latter case a break is not needed to be generated afterwards.
        /// </summary>
        public bool FieldReader(Field f)
        {
            if (f.Rule == FieldRule.Repeated)
            {
                //Make sure we are not reading a list of interfaces
                if (f.ProtoType.OptionType == "interface")
                {
                    cw.WriteLine("throw new NotSupportedException(\"Can't deserialize a list of interfaces\");");
                    return false;
                }

                if (f.OptionPacked == true)
                {
                    cw.Comment("repeated packed");
                    cw.WriteLine("long end" + f.ID + " = " + ProtocolParser.Base + ".ReadUInt32(stream);");
                    cw.WriteLine("end" + f.ID + " += stream.Position;");
                    cw.WhileBracket("stream.Position < end" + f.ID);
                    cw.WriteLine("instance." + f.CsName + ".Add(" + FieldReaderType(f, "stream", "br", null) + ");");
                    cw.EndBracket();

                    cw.WriteLine("if (stream.Position != end" + f.ID + ")");
                    cw.WriteIndent("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"Read too many bytes in packed data\");");
                }
                else
                {
                    cw.Comment("repeated");
                    cw.WriteLine("instance." + f.CsName + ".Add(" + FieldReaderType(f, "stream", "br", null) + ");");
                }
            }
            else
            {
                if (f.OptionReadOnly)
                {
                    //The only "readonly" fields we can modify
                    //We could possibly support bytes primitive too but it would require the incoming length to match the wire length
                    if (f.ProtoType is ProtoMessage)
                    {
                        cw.WriteLine(FieldReaderType(f, "stream", "br", "instance." + f.CsName) + ";");
                        return true;
                    }
                    cw.WriteLine("throw new InvalidOperationException(\"Can't deserialize into a readonly primitive field\");");
                    return false;
                }

                if (f.ProtoType is ProtoMessage)
                {
                    if (f.ProtoType.OptionType == "struct")
                    {
                        if (options.Nullable)
                            cw.WriteLine("instance." + f.CsName + " = " + FieldReaderType(f, "stream", "br", null) + ";");
                        else
                            cw.WriteLine(FieldReaderType(f, "stream", "br", "ref instance." + f.CsName) + ";");
                        return true;
                    }

                    cw.WriteLine("if (instance." + f.CsName + " == null)");
                    if (f.ProtoType.OptionType == "interface")
                        cw.WriteIndent("throw new InvalidOperationException(\"Can't deserialize into a interfaces null pointer\");");
                    else
                        cw.WriteIndent("instance." + f.CsName + " = " + FieldReaderType(f, "stream", "br", null) + ";");
                    cw.WriteLine("else");
                    cw.WriteIndent(FieldReaderType(f, "stream", "br", "instance." + f.CsName) + ";");
                    return true;
                }

                cw.WriteLine("instance." + f.CsName + " = " + FieldReaderType(f, "stream", "br", "instance." + f.CsName) + ";");
            }
            return true;
        }
        /// <summary>
        /// Generates inline writer of a length delimited byte array
        /// </summary>
        static void BytesWriter(Field f, string stream, CodeWriter cw)
        {
            cw.Comment("Length delimited byte array");

            //Original
            //cw.WriteLine("ProtocolParser.WriteBytes(" + stream + ", " + memoryStream + ".ToArray());");

            //Much slower than original
            /*
            cw.WriteLine("ProtocolParser.WriteUInt32(" + stream + ", (uint)" + memoryStream + ".Length);");
            cw.WriteLine(memoryStream + ".Seek(0, System.IO.SeekOrigin.Begin);");
            cw.WriteLine(memoryStream + ".CopyTo(" + stream + ");");
            */

            //Same speed as original
            /*
            cw.WriteLine("ProtocolParser.WriteUInt32(" + stream + ", (uint)" + memoryStream + ".Length);");
            cw.WriteLine(stream + ".Write(" + memoryStream + ".ToArray(), 0, (int)" + memoryStream + ".Length);");
            */

            //10% faster than original using GetBuffer rather than ToArray
            cw.WriteLine("uint length" + f.ID + " = (uint)msField.Length;");
            cw.WriteLine(ProtocolParser.Base + ".WriteUInt32(" + stream + ", length" + f.ID + ");");
            cw.WriteLine("msField.WriteTo(" + stream + ");");
        }
예제 #13
0
        void FieldSizeWriterType(Field f, string instance, CodeWriter cw)
        {
            if (f.OptionCodeType != null)
                Console.WriteLine("not support");

            cw.Bracket();
            cw.WriteLine(FieldSizeWriterPrimitive(f, instance));
            cw.EndBracket();
        }
예제 #14
0
        static string FieldSizeWriterPrimitive(Field f, string instance)
        {
            string numPlusLine = "num += 1u;\r\n";
            if (f.ProtoType is ProtoEnum)
            {
                return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
            }

            if (f.ProtoType is ProtoMessage)
            {
                return numPlusLine + "uint serializedSize = " + instance + ".GetSerializedSize();\r\n"
                     + "num += serializedSize + " + ProtocolParser.Base + ".SizeOfUInt32(serializedSize);";
            }

            switch(f.ProtoType.ProtoName)
            {
                case ProtoBuiltin.Double:
                case ProtoBuiltin.Float:
                case ProtoBuiltin.Fixed32:
                case ProtoBuiltin.Fixed64:
                case ProtoBuiltin.SFixed32:
                case ProtoBuiltin.SFixed64:
                    return "unit serializedSize = 1;\r\n";
                case ProtoBuiltin.Int32: //Serialized as 64 bit varint
                    return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
                case ProtoBuiltin.Int64:
                    return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
                case ProtoBuiltin.UInt32:
                    return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
                case ProtoBuiltin.UInt64:
                    return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
                case ProtoBuiltin.SInt32:
                    return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
                case ProtoBuiltin.SInt64:
                    return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
                case ProtoBuiltin.Bool:
                    return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
                case ProtoBuiltin.String:
                    return numPlusLine + "uint byteCount = (uint)Encoding.UTF8.GetByteCount(" + instance + ");\r\n"
                        + "num += " + ProtocolParser.Base + ".SizeOfUInt32(byteCount) + byteCount;";
                case ProtoBuiltin.Bytes:
                    return numPlusLine + "num += " + ProtocolParser.Base + ".SizeOfUInt64((ulong)" + instance + ");";
            }

            throw new NotImplementedException();
        }
예제 #15
0
        public void FieldSizeWriter(ProtoMessage m, Field f, CodeWriter cw, Options options)
        {
            if (f.Rule == FieldRule.Repeated)
            {
                if (f.OptionPacked == true)
                {
                    Console.WriteLine("not support");
                }
                else
                {
                    //Repeated not packet
                    cw.IfBracket("this." + f.CsName + " != null");
                    cw.ForeachBracket("var i" + f.ID + " in this." + f.CsName);
                    //KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                    FieldSizeWriterType(f, "i" + f.ID, cw);
                    cw.EndBracket();
                    cw.EndBracket();
                }
                return;
            }
            else if (f.Rule == FieldRule.Optional)
            {
                if (options.Nullable ||
                    f.ProtoType is ProtoMessage ||
                    f.ProtoType.ProtoName == ProtoBuiltin.String ||
                    f.ProtoType.ProtoName == ProtoBuiltin.Bytes)
                {
                    if (f.ProtoType.Nullable || options.Nullable) //Struct always exist, not optional
                        cw.IfBracket("this." + f.CsName + " != null");

                    FieldSizeWriterType(f, "this." + f.CsName, cw);

                    if (f.ProtoType.Nullable || options.Nullable) //Struct always exist, not optional
                        cw.EndBracket();
                    return;
                }
                if (f.ProtoType is ProtoEnum)
                {
                    if (f.OptionDefault != null)
                        cw.IfBracket("this." + f.CsName + " != " + f.ProtoType.CsType + "." + f.OptionDefault);

                    FieldSizeWriterType(f, "this." + f.CsName, cw);

                    if (f.OptionDefault != null)
                        cw.EndBracket();
                    return;
                }
                KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw);
                return;
            }
            else if (f.Rule == FieldRule.Required)
            {
                if (f.ProtoType is ProtoMessage && f.ProtoType.OptionType != "struct" ||
                    f.ProtoType.ProtoName == ProtoBuiltin.String ||
                    f.ProtoType.ProtoName == ProtoBuiltin.Bytes)
                {
                    cw.WriteLine("if (this." + f.CsName + " == null)");
                    cw.WriteIndent("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"" + f.CsName + " is required by the proto specification.\");");
                }
                cw.WriteLine();
                FieldSizeWriterType(f, "this." + f.CsName, cw);
                return;
            }
            throw new NotImplementedException("Unknown rule: " + f.Rule);
        }
예제 #16
0
        /// <summary>
        /// Generates code for writing one field
        /// </summary>
        public static void FieldWriter(ProtoMessage m, Field f, CodeWriter cw)
        {
            if (f.Rule == FieldRule.Repeated)
            {
                if (f.OptionPacked == true)
                {
                    //Repeated packed
                    cw.IfBracket("instance." + f.CsName + " != null");

                    KeyWriter("stream", f.ID, Wire.LengthDelimited, cw);
                    if (f.ProtoType.WireSize < 0)
                    {
                        //Un-optimized, unknown size
                        cw.Using("var ms" + f.ID + " = new MemoryStream()");
                        if (f.IsUsingBinaryWriter)
                            cw.WriteLine("BinaryWriter bw" + f.ID + " = new BinaryWriter(ms" + f.ID + ");");

                        cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName);
                        cw.WriteLine(FieldWriterType(f, "ms" + f.ID, "bw" + f.ID, "i" + f.ID));
                        cw.EndBracket();

                        BytesWriter("stream", "ms" + f.ID, cw);
                        cw.EndBracket();
                    }
                    else
                    {
                        //Optimized with known size
                        //No memorystream buffering, write size first at once

                        //For constant size messages we can skip serializing to the MemoryStream
                        cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteUInt32(stream, " + f.ProtoType.WireSize + "u * (uint)instance." + f.CsName + ".Count);");

                        cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName);
                        cw.WriteLine(FieldWriterType(f, "stream", "bw", "i" + f.ID));
                        cw.EndBracket();
                    }
                    cw.EndBracket();
                }
                else
                {
                    //Repeated not packet
                    cw.IfBracket("instance." + f.CsName + " != null");
                    cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName);
                    KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                    cw.WriteLine(FieldWriterType(f, "stream", "bw", "i" + f.ID));
                    cw.EndBracket();
                    cw.EndBracket();
                }
                return;
            }
            else if (f.Rule == FieldRule.Optional)
            {
                if (f.ProtoType is ProtoMessage ||
                    f.ProtoType.ProtoName == ProtoBuiltin.String ||
                    f.ProtoType.ProtoName == ProtoBuiltin.Bytes)
                {
                    if (f.ProtoType.Nullable) //Struct always exist, not optional
                        cw.IfBracket("instance." + f.CsName + " != null");
                    KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                    cw.WriteLine(FieldWriterType(f, "stream", "bw", "instance." + f.CsName));
                    if (f.ProtoType.Nullable) //Struct always exist, not optional
                        cw.EndBracket();
                    return;
                }
                if (f.ProtoType is ProtoEnum)
                {
                    if (f.OptionDefault != null)
                        cw.IfBracket("instance." + f.CsName + " != " + f.ProtoType.CsType + "." + f.OptionDefault);
                    KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                    cw.WriteLine(FieldWriterType(f, "stream", "bw", "instance." + f.CsName));
                    if (f.OptionDefault != null)
                        cw.EndBracket();
                    return;
                }
                KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                cw.WriteLine(FieldWriterType(f, "stream", "bw", "instance." + f.CsName));
                return;
            }
            else if (f.Rule == FieldRule.Required)
            {
                if (f.ProtoType is ProtoMessage && f.ProtoType.OptionType != "struct" ||
                    f.ProtoType.ProtoName == ProtoBuiltin.String ||
                    f.ProtoType.ProtoName == ProtoBuiltin.Bytes)
                {
                    cw.WriteLine("if (instance." + f.CsName + " == null)");
                    cw.WriteIndent("throw new ArgumentNullException(\"" + f.CsName + "\", \"Required by proto specification.\");");
                }
                KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
                cw.WriteLine(FieldWriterType(f, "stream", "bw", "instance." + f.CsName));
                return;
            }
            throw new NotImplementedException("Unknown rule: " + f.Rule);
        }
예제 #17
0
        /// <summary>
        /// Prepare: ProtoType, WireType and CSType
        /// </summary>
        void PrepareProtoType(ProtoMessage m, Field f)
        {
            //Change property name to C# style, CamelCase.
            f.CsName = GetCSPropertyName(m, f.ProtoName);

            f.ProtoType = GetBuiltinProtoType(f.ProtoTypeName);
            if (f.ProtoType == null)
                f.ProtoType = Search.GetProtoType(m, f.ProtoTypeName);
            if (f.ProtoType == null)
            {
#if DEBUG
                //this will still return null but we keep it here for debugging purposes
                f.ProtoType = Search.GetProtoType(m, f.ProtoTypeName);
#endif
                throw new ProtoFormatException("Field type \"" + f.ProtoTypeName + "\" not found for field " + f.ProtoName + " in message " + m.FullProtoName, f.Source);
            }

            if (f.OptionPacked)
            {
                if (f.ProtoType.WireType == Wire.LengthDelimited)
                    throw new ProtoFormatException("Length delimited types cannot be packed", f.Source);
            }
        }
        static string FieldWriterPrimitive(Field f, string stream, string binaryWriter, string instance)
        {
            if (f.ProtoType is ProtoEnum)
                return ProtocolParser.Base + ".WriteUInt64(" + stream + ",(ulong)" + instance + ");";

            if (f.ProtoType is ProtoMessage)
            {
                ProtoMessage pm = f.ProtoType as ProtoMessage;
                CodeWriter cw = new CodeWriter();
                cw.WriteLine("msField.SetLength(0);");
                cw.WriteLine(pm.FullSerializerType + ".Serialize(msField, " + instance + ");");
                BytesWriter(f, stream, cw);
                return cw.Code;
            }

            switch (f.ProtoType.ProtoName)
            {
                case ProtoBuiltin.Double:
                case ProtoBuiltin.Float:
                case ProtoBuiltin.Fixed32:
                case ProtoBuiltin.Fixed64:
                case ProtoBuiltin.SFixed32:
                case ProtoBuiltin.SFixed64:
                    return binaryWriter + ".Write(" + instance + ");";
                case ProtoBuiltin.Int32: //Serialized as 64 bit varint
                    return ProtocolParser.Base + ".WriteUInt64(" + stream + ",(ulong)" + instance + ");";
                case ProtoBuiltin.Int64:
                    return ProtocolParser.Base + ".WriteUInt64(" + stream + ",(ulong)" + instance + ");";
                case ProtoBuiltin.UInt32:
                    return ProtocolParser.Base + ".WriteUInt32(" + stream + ", " + instance + ");";
                case ProtoBuiltin.UInt64:
                    return ProtocolParser.Base + ".WriteUInt64(" + stream + ", " + instance + ");";
                case ProtoBuiltin.SInt32:
                    return ProtocolParser.Base + ".WriteZInt32(" + stream + ", " + instance + ");";
                case ProtoBuiltin.SInt64:
                    return ProtocolParser.Base + ".WriteZInt64(" + stream + ", " + instance + ");";
                case ProtoBuiltin.Bool:
                    return ProtocolParser.Base + ".WriteBool(" + stream + ", " + instance + ");";
                case ProtoBuiltin.String:
                    return ProtocolParser.Base + ".WriteBytes(" + stream + ", Encoding.UTF8.GetBytes(" + instance + "));";
                case ProtoBuiltin.Bytes:
                    return ProtocolParser.Base + ".WriteBytes(" + stream + ", " + instance + ");";
            }

            throw new NotImplementedException();
        }
예제 #19
0
        string GenerateProperty(Field f)
        {
            string type = f.ProtoType.FullCsType;
            if (f.OptionCodeType != null)
                type = f.OptionCodeType;
            if (f.Rule == FieldRule.Repeated)
                type = "List<" + type + ">";
            if (f.Rule == FieldRule.Optional && !f.ProtoType.Nullable && options.Nullable)
                type = type + "?";

            if (f.OptionReadOnly)
                return f.OptionAccess + " readonly " + type + " " + f.CsName + " = new " + type + "();";
            else if (f.ProtoType is ProtoMessage && f.ProtoType.OptionType == "struct")
                return f.OptionAccess + " " + type + " " + f.CsName + ";";
            else
                return f.OptionAccess + " " + type + " " + f.CsName + " { get; set; }";
        }
예제 #20
0
        /// <summary>
        /// Return true for normal code and false for generated throw.
        /// In the later case a break is not needed to be generated afterwards.
        /// </summary>
        public static bool FieldReader(Field f, CodeWriter cw)
        {
            if (f.Rule == FieldRule.Repeated)
            {
                //Make sure we are not reading a list of interfaces
                if (f.ProtoType.OptionType == "interface")
                {
                    cw.WriteLine("throw new InvalidOperationException(\"Can't deserialize a list of interfaces\");");
                    return false;
                }

                if (f.OptionPacked == true)
                {
                    //TODO: read without buffering
                    cw.Comment("repeated packed");
                    cw.Using("var ms" + f.ID + " = new MemoryStream(global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadBytes(stream))");
                    if (f.IsUsingBinaryWriter)
                        cw.WriteLine("BinaryReader br" + f.ID + " = new BinaryReader(ms" + f.ID + ");");
                    cw.WhileBracket("ms" + f.ID + ".Position < ms" + f.ID + ".Length");
                    cw.WriteLine("instance." + f.CsName + ".Add(" + FieldReaderType(f, "ms" + f.ID, "br" + f.ID, null) + ");");
                    cw.EndBracket();
                    cw.EndBracket();
                }
                else
                {
                    cw.Comment("repeated");
                    cw.WriteLine("instance." + f.CsName + ".Add(" + FieldReaderType(f, "stream", "br", null) + ");");
                }
            }
            else
            {
                if (f.OptionReadOnly)
                {
                    //The only "readonly" fields we can modify
                    //We could possibly support bytes primitive too but it would require the incoming length to match the wire length
                    if (f.ProtoType is ProtoMessage)
                    {
                        cw.WriteLine(FieldReaderType(f, "stream", "br", "instance." + f.CsName) + ";");
                        return true;
                    }
                    cw.WriteLine("throw new InvalidOperationException(\"Can't deserialize into a readonly primitive field\");");
                    return false;
                }

                if (f.ProtoType is ProtoMessage)
                {
                    if (f.ProtoType.OptionType == "struct")
                    {
                        cw.WriteLine(FieldReaderType(f, "stream", "br", "ref instance." + f.CsName) + ";");
                        return true;
                    }

                    cw.WriteLine("if (instance." + f.CsName + " == null)");
                    if (f.ProtoType.OptionType == "interface")
                        cw.WriteIndent("throw new InvalidOperationException(\"Can't deserialize into a interfaces null pointer\");");
                    else
                        cw.WriteIndent("instance." + f.CsName + " = " + FieldReaderType(f, "stream", "br", null) + ";");
                    cw.WriteLine("else");
                    cw.WriteIndent(FieldReaderType(f, "stream", "br", "instance." + f.CsName) + ";");
                    return true;
                }

                cw.WriteLine("instance." + f.CsName + " = " + FieldReaderType(f, "stream", "br", "instance." + f.CsName) + ";");
            }
            return true;
        }
예제 #21
0
        static bool ParseField(TokenReader tr, ProtoMessage m)
        {
            string rule = tr.ReadNext();
            while (true)
            {
                if (ParseComment(rule) == false)
                    break;
                rule = tr.ReadNext();
            }

            Field f = new Field(tr);

            //Rule
            switch (rule)
            {
                case ";":
                    lastComment.Clear();
                    return true;
                case "}":
                    lastComment.Clear();
                    return false;
                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":
                    ParseMessage(tr, m, m.Package + "." + m.ProtoName);
                    return true;
                case "enum":
                    ParseEnum(tr, m, m.Package + "." + m.ProtoName);
                    return true;
                case "extensions":
                    ParseExtensions(tr, m);
                    return true;
                default:
                    throw new ProtoFormatException("unknown rule: " + rule, tr);
            }

            //Field comments
            LocalParser.ParseComments(f, lastComment, tr);

            //Type
            f.ProtoTypeName = tr.ReadNext();

            //Name
            f.ProtoName = 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", tr);
            if (f.ID > (1 << 29) - 1)
                throw new ProtoFormatException("Maximum field id is 2^29 - 1", tr);

            //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, tr);

            ParseFieldOptions(tr, f);
            return true;
        }
예제 #22
0
        static string FieldReaderPrimitive(Field f, string stream, string binaryReader, string instance)
        {
            if (f.ProtoType is ProtoMessage)
            {
                var m = f.ProtoType as ProtoMessage;
                if (f.Rule == FieldRule.Repeated || instance == null)
                    return m.FullSerializerType + ".DeserializeLengthDelimited(" + stream + ")";
                else
                    return m.FullSerializerType + ".DeserializeLengthDelimited(" + stream + ", " + instance + ")";
            }

            if (f.ProtoType is ProtoEnum)
                return "(" + f.ProtoType.FullCsType + ")global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadUInt64(" + stream + ")";

            if (f.ProtoType is ProtoBuiltin)
            {
                switch (f.ProtoType.ProtoName)
                {
                    case ProtoBuiltin.Double:
                        return binaryReader + ".ReadDouble()";
                    case ProtoBuiltin.Float:
                        return binaryReader + ".ReadSingle()";
                    case ProtoBuiltin.Int32: //Wire format is 64 bit varint
                        return "(int)global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadUInt64(" + stream + ")";
                    case ProtoBuiltin.Int64:
                        return "(long)global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadUInt64(" + stream + ")";
                    case ProtoBuiltin.UInt32:
                        return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadUInt32(" + stream + ")";
                    case ProtoBuiltin.UInt64:
                        return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadUInt64(" + stream + ")";
                    case ProtoBuiltin.SInt32:
                        return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadZInt32(" + stream + ")";
                    case ProtoBuiltin.SInt64:
                        return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadZInt64(" + stream + ")";
                    case ProtoBuiltin.Fixed32:
                        return binaryReader + ".ReadUInt32()";
                    case ProtoBuiltin.Fixed64:
                        return binaryReader + ".ReadUInt64()";
                    case ProtoBuiltin.SFixed32:
                        return binaryReader + ".ReadInt32()";
                    case ProtoBuiltin.SFixed64:
                        return binaryReader + ".ReadInt64()";
                    case ProtoBuiltin.Bool:
                        return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadBool(" + stream + ")";
                    case ProtoBuiltin.String:
                        return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadString(" + stream + ")";
                    case ProtoBuiltin.Bytes:
                        return "global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadBytes(" + stream + ")";
                    default:
                        throw new ProtoFormatException("unknown build in: " + f.ProtoType.ProtoName, f.Source);
                }

            }

            throw new NotImplementedException();
        }
예제 #23
0
        static void ParseFieldOptions(TokenReader tr, Field f)
        {
            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.NextCharacter, tr);
            }
            tr.ReadNextOrThrow(";");
        }
예제 #24
0
        static string GenerateProperty(Field f)
        {
            string type = f.ProtoType.FullCsType;
            if (f.ProtoType is ProtoEnum)
            {
                type = "int";
            }
            if (f.OptionCodeType != null)
                type = f.OptionCodeType;
            if (f.Rule == FieldRule.Repeated)
                type = type + "[]";

            if (f.OptionReadOnly)
                return f.OptionAccess + " readonly " + type + " " + f.CsName + " = new " + type + "();";
            else if (f.ProtoType is ProtoMessage && f.ProtoType.OptionType == "struct")
                return f.OptionAccess + " " + type + " " + f.CsName + ";";
            else
            {
                string s = "\n#if !CITO\n internal\n#endif\n " + type + " " + f.CsName + ";" + Environment.NewLine;
                s += f.OptionAccess + " " + type + " " + "Get" + f.CsName + "() { return " + f.CsName + "; } " + Environment.NewLine;
                if (f.Rule != FieldRule.Repeated)
                {
                    s += f.OptionAccess + " void Set" + f.CsName + "(" + type + " value) { " + f.CsName + " = " + "value; } " + Environment.NewLine;
                }
                else
                {
                    s += f.OptionAccess + " void Set" + f.CsName + "(" + type + " value, int count, int length) { " + f.CsName + " = " + "value; " + f.CsName + "Count = count; " + f.CsName + "Length = length; } " + Environment.NewLine;
                    s += "\n#if !CITO\n internal\n#endif\n int" + " " + f.CsName + "Count;" + Environment.NewLine;
                    s += f.OptionAccess + " int Get" + f.CsName + "Count() { return " + f.CsName + "Count; } " + Environment.NewLine;
                    s += "\n#if !CITO\n internal\n#endif\n int" + " " + f.CsName + "Length;" + Environment.NewLine;
                    s += f.OptionAccess + " int Get" + f.CsName + "Length() { return " + f.CsName + "Length; } " + Environment.NewLine;
                    s += f.OptionAccess + " void " + f.CsName + "Add(" + type.Replace("[]", "") + " value)";
                    s += string.Format("{{if({0}Count >= {0}Length)\n", f.CsName);
                    s += "{\n";
                    s += string.Format("{0}[] {1}2 = new {0}[{1}Length*2];\n", type.Replace("[]", ""), f.CsName);
                    s += string.Format("{0}Length = {0}Length*2;\n", f.CsName);

                    s += string.Format("for(int i=0;i<{0}Count;i++)\n", f.CsName);
                    s += "{\n";
                    s += string.Format("{0}2[i] = {0}[i];\n", f.CsName);
                    s += "}\n";
                    s += string.Format("{0}={0}2;\n", f.CsName);

                    s += "}\n";
                    s += string.Format("{0}[{0}Count] = value;\n", f.CsName);
                    s += string.Format("{0}Count++;\n", f.CsName);
                    s += "}" + Environment.NewLine;
                }

                return s;
            }
        }