Beispiel #1
0
        public void GenerateClassSerializer(ProtoMessage m)
        {
            if (m.OptionExternal || m.OptionType == "interface")
            {
                //Don't make partial class of external classes or interfaces
                //Make separate static class for them
                cw.Bracket(m.OptionAccess + " static class " + m.SerializerType);
            }
            else
            {
                cw.Attribute("System.Serializable()");
                cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.SerializerType);
            }

            GenerateReader(m);

            GenerateWriter(m);
            foreach (ProtoMessage sub in m.Messages.Values)
            {
                cw.WriteLine();
                GenerateClassSerializer(sub);
            }
            cw.EndBracket();
            cw.WriteLine();
            return;
        }
Beispiel #2
0
        public void GenerateClass(ProtoMessage m)
        {
            if (options.NoGenerateImported && m.IsImported)
            {
                Console.Error.WriteLine("Skipping imported " + m.FullProtoName);
                return;
            }

            //Default class
            cw.Summary(m.Comments);
            cw.Bracket("public partial class " + m.CsType);

            GenerateCtor(m);

            GenerateEnums(m);

            GenerateProperties(m);

            GenerateClear(m);

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                GenerateClass(sub);
                cw.WriteLine();
            }
            cw.EndBracket();
            return;
        }
Beispiel #3
0
        public void GenerateClassSerializer(ProtoMessage m)
        {
            if (options.NoGenerateImported && m.IsImported)
            {
                Console.Error.WriteLine("Skipping imported " + m.FullProtoName);
                return;
            }

            if (m.OptionExternal || m.OptionType == "interface")
            {
                //Don't make partial class of external classes or interfaces
                //Make separate static class for them
                cw.Bracket(m.OptionAccess + " static class " + m.SerializerType);
            }
            else
            {
                if (options.SerializableAttributes)
                {
                    cw.Attribute("System.Serializable");
                }
                cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.SerializerType);
            }

            GenerateReader(m);

            GenerateWriter(m);
            foreach (ProtoMessage sub in m.Messages.Values)
            {
                cw.WriteLine();
                GenerateClassSerializer(sub);
            }
            cw.EndBracket();
            cw.WriteLine();
            return;
        }
Beispiel #4
0
        public void GenerateClassSerializer(ProtoMessage m)
        {
            if (options.NoGenerateImported && m.IsImported)
            {
                Console.Error.WriteLine("Skipping imported " + m.FullProtoName);
                return;
            }
            else
            {
                cw.Attribute("System.Serializable");
                cw.Bracket("public partial class " + m.SerializerType);
            }

            GenerateReader(m);

            GenerateWriter(m);
            foreach (ProtoMessage sub in m.Messages.Values)
            {
                cw.WriteLine();
                GenerateClassSerializer(sub);
            }
            cw.EndBracket();
            cw.WriteLine();
            return;
        }
Beispiel #5
0
        public void GenerateClass(ProtoMessage m)
        {
            if (options.NoGenerateImported && m.IsImported)
            {
                Console.Error.WriteLine("Skipping imported " + m.FullProtoName);
                return;
            }

            //Do not generate class code for external classes
            if (m.OptionExternal)
            {
                cw.Comment("Written elsewhere");
                cw.Comment(m.OptionAccess + " " + m.OptionType + " " + m.CsType + " {}");
                return;
            }

            //Default class
            cw.Summary(m.Comments);
            if (options.DataContractAttributes)
            {
                cw.Attribute("DataContract");
            }
            cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.CsType);

            if (options.GenerateDefaultConstructors)
            {
                GenerateCtorForDefaults(m);
            }

            GenerateEnums(m);

            GenerateProperties(m);

            //if(options.GenerateToString...
            // ...

            if (m.OptionPreserveUnknown)
            {
                cw.Summary("Values for unknown fields.");
                cw.WriteLine("public List<global::SilentOrbit.ProtocolBuffers.KeyValue> PreservedFields;");
                cw.WriteLine();
            }

            if (m.OptionTriggers)
            {
                cw.Comment("protected virtual void BeforeSerialize() {}");
                cw.Comment("protected virtual void AfterDeserialize() {}");
                cw.WriteLine();
            }

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                GenerateClass(sub);
                cw.WriteLine();
            }
            cw.EndBracket();
            return;
        }
Beispiel #6
0
 /// <summary>
 /// Generates code for writing one field
 /// </summary>
 public void FieldWriter(ProtoMessage m, Field f, CodeWriter cw, Options options)
 {
     if (f.Rule == FieldRule.Repeated)
     {
         //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();
     }
     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("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)
         {
             KeyWriter("stream", f.ID, f.ProtoType.WireType, cw);
             FieldWriterType(f, "stream", "bw", "instance." + f.CsName, cw);
             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.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);
 }
Beispiel #7
0
        public void GenerateClass(ProtoMessage m)
        {
            var baseclass = m.BaseClass ?? "";

            if (baseclass.Length > 0)
            {
                baseclass = " : " + baseclass;
            }

            //Do not generate class code for external classes
            if (m.OptionExternal)
            {
                cw.Comment("Written elsewhere");
                cw.Comment(m.OptionAccess + " " + m.OptionType + " " + m.CsType + " {}");
                return;
            }


            //Default class
            cw.Summary(m.Comments);
            cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.CsType + baseclass);

            if (options.GenerateDefaultConstructors)
            {
                GenerateCtorForDefaults(m);
            }

            GenerateEnums(m);

            GenerateProperties(m);

            //if(options.GenerateToString...
            // ...

            if (m.OptionPreserveUnknown)
            {
                cw.Summary("Values for unknown fields.");
                cw.WriteLine("public List<global::SilentOrbit.ProtocolBuffers.KeyValue> PreservedFields;");
                cw.WriteLine();
            }

            if (m.OptionTriggers)
            {
                cw.Comment("protected virtual void BeforeSerialize() {}");
                cw.Comment("protected virtual void AfterDeserialize() {}");
                cw.WriteLine();
            }

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                GenerateClass(sub);
                cw.WriteLine();
            }
            cw.EndBracket();
            return;
        }
Beispiel #8
0
        public static void GenerateClassSerializer(ProtoMessage m, CodeWriter cw, Options options)
        {
            if (m.OptionExternal || m.OptionType == "interface")
            {
                //Don't make partial class of external classes or interfaces
                //Make separate static class for them
                cw.Bracket(m.OptionAccess + " static class " + m.SerializerType);
            }
            else
            {
                cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.SerializerType);
            }

            if (m.OptionType == "class")
            {
                GeneratePooled(m, cw, options);
            }

            GenerateReader(m, cw, options);
            GenerateWriter(m, cw, options);

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                cw.WriteLine();
                GenerateClassSerializer(sub, cw, options);
            }
            cw.EndBracket();
            cw.WriteLine();
            return;
        }
Beispiel #9
0
        static void GenerateCtorForDefaults(ProtoMessage m, CodeWriter cw)
        {
            // Collect all fields with default values.
            var fieldsWithDefaults = new List <Field>();

            foreach (Field field in m.Fields.Values)
            {
                if (field.OptionDefault != null)
                {
                    fieldsWithDefaults.Add(field);
                }
            }

            if (fieldsWithDefaults.Count > 0)
            {
                cw.Bracket("public " + m.CsType + "()");
                foreach (var field in fieldsWithDefaults)
                {
                    string formattedValue = field.FormatForTypeAssignment();
                    string line           = string.Format("{0} = {1};", field.CsName, formattedValue);
                    cw.WriteLine(line);
                }
                cw.EndBracket();
            }
        }
        public static void GenerateClassSerializer(ProtoMessage m, CodeWriter cw)
        {
            if (m.OptionExternal || m.OptionType == "interface")
            {
                //Don't make partial class of external classes or interfaces
                //Make separate static class for them
                cw.Bracket(m.OptionAccess + " class " + m.SerializerType);
            } else
            {
                cw.Attribute("System.Serializable()");
                cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.SerializerType);
            }

            GenerateReader(m, cw);

            GenerateWriter(m, cw);
            foreach (ProtoMessage sub in m.Messages.Values)
            {
                cw.WriteLine();
                GenerateClassSerializer(sub, cw);
            }
            cw.EndBracket();
            cw.WriteLine();
            return;
        }
Beispiel #11
0
        /// <summary>
        /// Generates code for writing a class/message
        /// </summary>
        static void GenerateWriter(ProtoMessage m, CodeWriter cw)
        {
            cw.Summary("Serialize the instance into the stream");
            cw.Bracket(m.OptionAccess + " static void Serialize(CitoStream stream, " + m.FullCsType + " instance)");
            if (m.OptionTriggers)
            {
                cw.WriteLine("instance.BeforeSerialize();");
                cw.WriteLine();
            }
            if (m.IsUsingBinaryWriter)
            {
                cw.WriteLine("BinaryWriter bw = new BinaryWriter(stream);");
            }

            foreach (Field f in m.Fields.Values)
            {
                FieldSerializer.FieldWriter(m, f, cw);
            }

            if (m.OptionPreserveUnknown)
            {
                cw.IfBracket("instance.PreservedFields != null");
                cw.ForeachBracket("var kv in instance.PreservedFields");
                cw.WriteLine("ProtocolParser.WriteKey(stream, kv.Key);");
                cw.WriteLine("stream.Write(kv.Value, 0, kv.Value.Length);");
                cw.EndBracket();
                cw.EndBracket();
            }
            cw.EndBracket();
            cw.WriteLine();

            cw.Summary("Helper: Serialize into a MemoryStream and return its byte array");
            cw.Bracket(m.OptionAccess + " static byte[] SerializeToBytes(" + m.FullCsType + " instance)");
            cw.WriteLine("CitoMemoryStream ms = new CitoMemoryStream();");
            cw.WriteLine("Serialize(ms, instance);");
            cw.WriteLine("return ms.ToArray();");
            //cw.EndBracket();
            cw.EndBracket();

            cw.Summary("Helper: Serialize with a varint length prefix");
            cw.Bracket(m.OptionAccess + " static void SerializeLengthDelimited(CitoStream stream, " + m.FullCsType + " instance)");
            cw.WriteLine("byte[] data = SerializeToBytes(instance);");
            cw.WriteLine("ProtocolParser.WriteUInt32_(stream, ProtoPlatform.ArrayLength(data));");
            cw.WriteLine("stream.Write(data, 0, ProtoPlatform.ArrayLength(data));");
            cw.EndBracket();
        }
Beispiel #12
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();
        }
Beispiel #13
0
 public static void GenerateEnum(ProtoEnum me, CodeWriter cw)
 {
     cw.Bracket("public class " + me.CsNamespace + "_" + me.CsType + "Enum");
     foreach (var epair in me.Enums)
     {
         cw.Summary(epair.Comment);
         cw.WriteLine("public const int " + epair.Name + " = " + epair.Value + ";");
     }
     cw.EndBracket();
     cw.WriteLine();
 }
Beispiel #14
0
 public static void GenerateEnum(ProtoEnum me, CodeWriter cw)
 {
     cw.Bracket("public enum " + me.CsType);
     foreach (var epair in me.Enums)
     {
         cw.Summary(epair.Comment);
         cw.WriteLine(epair.Name + " = " + epair.Value + ",");
     }
     cw.EndBracket();
     cw.WriteLine();
 }
Beispiel #15
0
 public static void GenerateEnum(ProtoEnum me, CodeWriter cw)
 {
     cw.Bracket("public enum " + me.CsType);
     foreach (var epair in me.Enums)
     {
         cw.Summary(epair.Comment);
         cw.WriteLine(epair.Name + " = " + epair.Value + ",");
     }
     cw.EndBracket();
     cw.WriteLine();
 }
Beispiel #16
0
 public static void GenerateEnum(ProtoEnum me, CodeWriter cw)
 {
     cw.Bracket("public class " + me.CsNamespace + "_" + me.CsType + "Enum");
     foreach (var epair in me.Enums)
     {
         cw.Summary(epair.Comment);
         cw.WriteLine("public const int " + epair.Name + " = " + epair.Value + ";");
     }
     cw.EndBracket();
     cw.WriteLine();
 }
Beispiel #17
0
 public static void GenerateEnum(ProtoEnum me, CodeWriter cw)
 {
     cw.Bracket("public enum " + me.CsType);
     foreach (var epair in me.Enums)
     {
         if (me.EnumsComments.ContainsKey(epair.Key))
             cw.Summary(me.EnumsComments [epair.Key]);
         cw.WriteLine(epair.Key + " = " + epair.Value + ",");
     }
     cw.EndBracket();
     cw.WriteLine();
 }
Beispiel #18
0
        /// <summary>
        /// Generates code for writing a class/message
        /// </summary>
        static void GenerateWriter(ProtoMessage m, CodeWriter cw, Options options)
        {
            string stack = "global::SilentOrbit.ProtocolBuffers.ProtocolParser.Stack";

            if (options.ExperimentalStack != null)
            {
                cw.WriteLine("[ThreadStatic]");
                cw.WriteLine("static global::SilentOrbit.ProtocolBuffers.MemoryStreamStack stack = new " + options.ExperimentalStack + "();");
                stack = "stack";
            }

            cw.Summary("Serialize the instance into the stream");
            cw.Bracket(m.OptionAccess + " static void Serialize(Stream stream, " + m.CsType + " instance)");
            if (m.OptionTriggers)
            {
                cw.WriteLine("instance.BeforeSerialize();");
                cw.WriteLine();
            }
            if (m.IsUsingBinaryWriter)
            {
                cw.WriteLine("BinaryWriter bw = new BinaryWriter(stream);");
            }

            //Shared memorystream for all fields
            cw.WriteLine("var msField = " + stack + ".Pop();");

            foreach (Field f in m.Fields.Values)
            {
                FieldSerializer.FieldWriter(m, f, cw);
            }

            cw.WriteLine(stack + ".Push(msField);");

            if (m.OptionPreserveUnknown)
            {
                cw.IfBracket("instance.PreservedFields != null");
                cw.ForeachBracket("var kv in instance.PreservedFields");
                cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteKey(stream, kv.Key);");
                cw.WriteLine("stream.Write(kv.Value, 0, kv.Value.Length);");
                cw.EndBracket();
                cw.EndBracket();
            }
            cw.EndBracket();
            cw.WriteLine();

            cw.Summary("Helper: Serialize into a MemoryStream and return its byte array");
            cw.Bracket(m.OptionAccess + " static byte[] SerializeToBytes(" + m.CsType + " instance)");
            cw.Using("var ms = new MemoryStream()");
            cw.WriteLine("Serialize(ms, instance);");
            cw.WriteLine("return ms.ToArray();");
            cw.EndBracket();
            cw.EndBracket();

            cw.Summary("Helper: Serialize with a varint length prefix");
            cw.Bracket(m.OptionAccess + " static void SerializeLengthDelimited(Stream stream, " + m.CsType + " instance)");
            cw.WriteLine("var data = SerializeToBytes(instance);");
            cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteUInt32(stream, (uint)data.Length);");
            cw.WriteLine("stream.Write(data, 0, data.Length);");
            cw.EndBracket();
        }
Beispiel #19
0
        /// <summary>
        /// Generates code for writing a class/message
        /// </summary>
        static void GenerateWriter(ProtoMessage m, CodeWriter cw)
        {
            cw.Summary("Serialize the instance into the stream");
            cw.Bracket(m.OptionAccess + " static void Serialize(Stream stream, " + m.CsType + " instance)");
            if (m.OptionTriggers)
            {
                cw.WriteLine("instance.BeforeSerialize();");
                cw.WriteLine();
            }
            if (m.IsUsingBinaryWriter)
            {
                cw.WriteLine("BinaryWriter bw = new BinaryWriter(stream);");
            }

            foreach (Field f in m.Fields.Values)
            {
                FieldSerializer.FieldWriter(m, f, cw);
            }

            if (m.OptionPreserveUnknown)
            {
                cw.IfBracket("instance.PreservedFields != null");
                cw.ForeachBracket("var kv in instance.PreservedFields");
                cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteKey(stream, kv.Key);");
                cw.WriteLine("stream.Write(kv.Value, 0, kv.Value.Length);");
                cw.EndBracket();
                cw.EndBracket();
            }
            cw.EndBracket();
            cw.WriteLine();

            cw.Summary("Helper: Serialize into a MemoryStream and return its byte array");
            cw.Bracket(m.OptionAccess + " static byte[] SerializeToBytes(" + m.CsType + " instance)");
            cw.Using("var ms = new MemoryStream()");
            cw.WriteLine("Serialize(ms, instance);");
            cw.WriteLine("return ms.ToArray();");
            cw.EndBracket();
            cw.EndBracket();
        }
Beispiel #20
0
        public static void GenerateClass(ProtoMessage m, CodeWriter cw, Options options)
        {
            //Do not generate class code for external classes
            if (m.OptionExternal)
            {
                cw.Comment("Written elsewhere");
                cw.Comment(m.OptionAccess + " " + m.OptionType + " " + m.CsType + " {}");
                return;
            }

            //Default class
            cw.Summary(m.Comments);
            cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.CsType + " : IDisposable, Pool.IPooled, IProto");

            GenerateEnums(m, cw);

            GenerateProperties(m, cw, options);

            //if(options.GenerateToString...
            // ...

            if (m.OptionPreserveUnknown)
            {
                cw.Summary("Values for unknown fields.");
                cw.WriteLine("public List<global::SilentOrbit.ProtocolBuffers.KeyValue> PreservedFields;");
                cw.WriteLine();
            }

            if (m.OptionTriggers)
            {
                cw.Comment("protected virtual void BeforeSerialize() {}");
                cw.Comment("protected virtual void AfterDeserialize() {}");
                cw.WriteLine();
            }

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                GenerateClass(sub, cw, options);
                cw.WriteLine();
            }
            cw.EndBracket();
            return;
        }
Beispiel #21
0
        public static void GenerateClass(ProtoMessage m, CodeWriter cw, Options options)
        {
            //Do not generate class code for external classes
            if (m.OptionExternal)
            {
                cw.Comment("Written elsewhere");
                cw.Comment(m.OptionAccess + " " + m.OptionType + " " + m.CsType + " {}");
                return;
            }

            //Default class
            cw.Summary(m.Comments);
            cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.CsType);

            GenerateEnums(m, cw);

            GenerateProperties(m, cw);

            //if(options.GenerateToString...
            // ...

            if (m.OptionPreserveUnknown)
            {
                cw.Summary("Values for unknown fields.");
                cw.WriteLine("public List<global::SilentOrbit.ProtocolBuffers.KeyValue> PreservedFields;");
                cw.WriteLine();
            }

            if (m.OptionTriggers)
            {
                cw.Comment("protected virtual void BeforeSerialize() {}");
                cw.Comment("protected virtual void AfterDeserialize() {}");
                cw.WriteLine();
            }

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                GenerateClass(sub, cw, options);
                cw.WriteLine();
            }
            cw.EndBracket();
            return;
        }
Beispiel #22
0
        public static void GenerateClass(ProtoMessage m, CodeWriter cw)
        {
            //Do not generate class code for external classes

            /*if (m.OptionExternal)
             * {
             *  cw.Comment("Written elsewhere");
             *  cw.Comment(m.OptionAccess + " " + m.OptionType + " " + m.CsNamespace + "_" + m.CsType + " {}");
             *  return;
             * }*/

            //Default class
            cw.Summary(m.Comments);
            cw.Bracket(m.OptionAccess + " " + m.OptionType + " " + m.CsNamespace + "_" + m.CsType);

            GenerateEnums(m, cw);

            GenerateProperties(m, cw);

            if (m.OptionPreserveUnknown)
            {
                cw.Summary("Values for unknown fields.");
                cw.WriteLine("public List<KeyValue> PreservedFields;");
                cw.WriteLine();
            }

            if (m.OptionTriggers)
            {
                cw.Comment("protected virtual void BeforeSerialize() {}");
                cw.Comment("protected virtual void AfterDeserialize() {}");
                cw.WriteLine();
            }

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                GenerateClass(sub, cw);
                cw.WriteLine();
            }
            cw.EndBracket();
            return;
        }
Beispiel #23
0
        public static void GenerateClass(ProtoMessage m, CodeWriter cw)
        {
            //Do not generate class code for external classes
            /*if (m.OptionExternal)
            {
                cw.Comment("Written elsewhere");
                cw.Comment(m.OptionAccess + " " + m.OptionType + " " + m.CsNamespace + "_" + m.CsType + " {}");
                return;
            }*/

            //Default class
            cw.Summary(m.Comments);
            cw.Bracket(m.OptionAccess + " " + m.OptionType + " " + m.CsNamespace + "_" + m.CsType);

            GenerateEnums(m, cw);

            GenerateProperties(m, cw);

            if (m.OptionPreserveUnknown)
            {
                cw.Summary("Values for unknown fields.");
                cw.WriteLine("public List<KeyValue> PreservedFields;");
                cw.WriteLine();
            }

            if (m.OptionTriggers)
            {
                cw.Comment("protected virtual void BeforeSerialize() {}");
                cw.Comment("protected virtual void AfterDeserialize() {}");
                cw.WriteLine();
            }

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                GenerateClass(sub, cw);
                cw.WriteLine();
            }
            cw.EndBracket();
            return;
        }
Beispiel #24
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);
        }
Beispiel #25
0
        /// <summary>
        /// Generate code for reading and writing protocol buffer messages
        /// </summary>
        public static void Save(ProtoCollection file, string csPath)
        {
            string ext = Path.GetExtension(csPath);
            string prefix = csPath.Substring(0, csPath.Length - ext.Length);

            string csDir = Path.GetDirectoryName(csPath);
            if (Directory.Exists(csDir) == false)
                Directory.CreateDirectory(csDir);

            //Basic structures
            using (var cw = new CodeWriter(csPath))
            {
                cw.Comment(@"Classes and structures being serialized");
                cw.WriteLine();
                cw.Comment(@"Generated by ProtocolBuffer
            - a pure c# code generation implementation of protocol buffers
            Report bugs to: https://silentorbit.com/protobuf/");
                cw.WriteLine();
                cw.Comment(@"DO NOT EDIT
            This file will be overwritten when CodeGenerator is run.
            To make custom modifications, edit the .proto file and add //:external before the message line
            then write the code and the changes in a separate file.");

                cw.WriteLine("using System;");
                cw.WriteLine("using System.Collections.Generic;");
                cw.WriteLine();

                string ns = null; //avoid writing namespace between classes if they belong to the same
                foreach (ProtoMessage m in file.Messages.Values)
                {
                    if (ns != m.CsNamespace)
                    {
                        if (ns != null) //First time
                            cw.EndBracket();
                        cw.Bracket("namespace " + m.CsNamespace);
                        ns = m.CsNamespace;
                    }
                    MessageCode.GenerateClass(m, cw);
                    cw.WriteLine();
                }

                foreach (ProtoEnum e in file.Enums.Values)
                {
                    if (ns != e.CsNamespace)
                    {
                        if (ns != null) //First time
                            cw.EndBracket();
                        cw.Bracket("namespace " + e.CsNamespace);
                        ns = e.CsNamespace;
                    }
                    MessageCode.GenerateEnum(e, cw);
                    cw.WriteLine();
                }

                cw.EndBracket();
            }

            //.Serializer.cs
            //Code for Reading/Writing
            using (var cw = new CodeWriter(prefix + ".Serializer" + ext))
            {
                cw.Comment(@"This is the backend code for reading and writing");
                cw.WriteLine();
                cw.Comment(@"Generated by ProtocolBuffer
            - a pure c# code generation implementation of protocol buffers
            Report bugs to: https://silentorbit.com/protobuf/");
                cw.WriteLine();
                cw.Comment(@"DO NOT EDIT
            This file will be overwritten when CodeGenerator is run.");

                cw.WriteLine("using System;");
                cw.WriteLine("using System.IO;");
                cw.WriteLine("using System.Text;");
                cw.WriteLine("using System.Collections.Generic;");
                cw.WriteLine();

                string ns = null; //avoid writing namespace between classes if they belong to the same
                foreach (ProtoMessage m in file.Messages.Values)
                {
                    if (ns != m.CsNamespace)
                    {
                        if (ns != null) //First time
                            cw.EndBracket();
                        cw.Bracket("namespace " + m.CsNamespace);
                        ns = m.CsNamespace;
                    }
                    MessageSerializer.GenerateClassSerializer(m, cw);
                }
                cw.EndBracket();
            }

            string libPath = Path.Combine(Path.GetDirectoryName(csPath), "ProtocolParser.cs");
            using (TextWriter codeWriter = new StreamWriter(libPath, false, Encoding.UTF8))
            {
                codeWriter.NewLine = "\r\n";
                ReadCode(codeWriter, "ProtocolParser", true);
                ReadCode(codeWriter, "ProtocolParserFixed", false);
                ReadCode(codeWriter, "ProtocolParserKey", false);
                ReadCode(codeWriter, "ProtocolParserVarInt", false);
            }
        }
Beispiel #26
0
        public void GenerateClassSerializer(ProtoMessage m)
        {
            String identName = null;

            if (m.OptionIdentifier > 0)
            {
                identName = "MessageIdentifier";
                cw.Attribute("ProtoBuf.MessageIdent(" + identName + ")");
            }

            if (m.OptionExternal || m.OptionType == "interface")
            {
                //Don't make partial class of external classes or interfaces
                //Make separate static class for them
                cw.Bracket(m.OptionAccess + " partial class " + m.SerializerType);
            }
            else
            {
                cw.Attribute("System.Serializable()");
                cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.SerializerType);
            }

            if (m.OptionIdentifier > 0)
            {
                cw.WriteLine(String.Format("public const uint {0} = 0x{1:x8};", identName, m.OptionIdentifier));
                cw.WriteLine();
            }

            GenerateReader(m);

            GenerateWriter(m);
            foreach (ProtoMessage sub in m.Messages.Values)
            {
                cw.WriteLine();
                GenerateClassSerializer(sub);
            }
            cw.EndBracket();
            cw.WriteLine();
            return;
        }
Beispiel #27
0
        /// <summary>
        /// Generates the properties.
        /// </summary>
        /// <param name='template'>
        /// if true it will generate only properties that are not included by default, because of the [generate=false] option.
        /// </param>
        static void GenerateProperties(ProtoMessage m, CodeWriter cw)
        {
            foreach (Field f in m.Fields.Values)
            {
                if (f.OptionExternal)
                    cw.WriteLine("//" + GenerateProperty(f) + " // Implemented by user elsewhere");
                else
                {
                    if (f.Comments != null)
                        cw.Summary(f.Comments);
                    cw.WriteLine(GenerateProperty(f));
                    cw.WriteLine();
                }

            }

            // Implement ToString
            cw.Bracket("public override string ToString()");
            string returnStatement = "return \"\"";
            Dictionary<int, Field>.ValueCollection fields = m.Fields.Values;
            if (fields.Count > 0)
            {
                List<string> fieldElements = new List<string>();
                foreach (Field f in fields)
                {
                    string fieldHeaderCode = "\"" + f.CsName + ": \" + ";
                    string fieldToStringCode;
                    string fieldCommaCode = " + \", \"";

                    if (f.Rule == FieldRule.Optional && f.ProtoType.Nullable)
                    {
                        // Hide optional nullable fields: this makes logging cleaner for union types
                        fieldToStringCode = string.Format("({0} != null ? {1}{0}{2}:  \"\")", f.CsName, fieldHeaderCode, fieldCommaCode);
                    }
                    else if (f.Rule == FieldRule.Repeated && f.ProtoTypeName == "bytes")
                    {
                        // Always output repeated fields with []
                        fieldToStringCode = string.Format("{1}\"[\" + ({0} != null ? string.Join(\", \", {0}.ConvertAll<string>(o => o != null ? BitConverter.ToString(o) : \"\").ToArray()) : \"\") + \"]\"{2}", f.CsName, fieldHeaderCode, fieldCommaCode);
                    }
                    else if (f.Rule == FieldRule.Repeated)
                    {
                        // Always output repeated fields with []
                        fieldToStringCode = string.Format("{1}\"[\" + ({0} != null ? string.Join(\", \", {0}.ConvertAll<string>(o => o.ToString()).ToArray()) : \"\") + \"]\"{2}", f.CsName, fieldHeaderCode, fieldCommaCode);
                    }
                    else if (f.ProtoTypeName == "bytes")
                    {
                        // Special code to output bytes
                        fieldToStringCode = string.Format("{1}\"[\" + ({0} != null ? BitConverter.ToString({0}) : \"\") + \"]\"{2}", f.CsName, fieldHeaderCode, fieldCommaCode);
                    }
                    else
                    {
                        fieldToStringCode = fieldHeaderCode + f.CsName + fieldCommaCode;
                    }
                    fieldElements.Add(fieldToStringCode);
                }
                returnStatement = "return " + string.Join(" + \n", fieldElements) + ";";
            }
            cw.WriteLine(returnStatement);
            cw.EndBracket();

            //Wire format field ID
            #if DEBUG
            cw.Comment("ProtocolBuffers wire field id");
            foreach (Field f in m.Fields.Values)
            {
                cw.WriteLine("public const int " + f.CsName + "FieldID = " + f.ID + ";");
            }
            #endif
        }
Beispiel #28
0
        public void GenerateClass(ProtoMessage m)
        {
            if (options.NoGenerateImported && m.IsImported)
            {
                Console.Error.WriteLine("Skipping imported " + m.FullProtoName);
                return;
            }

            //Do not generate class code for external classes
            if (m.OptionExternal)
            {
                cw.Comment("Written elsewhere");
                cw.Comment(m.OptionAccess + " " + m.OptionType + " " + m.CsType + " {}");
                return;
            }

            //Default class
            cw.Summary(m.Comments);
            cw.Bracket(m.OptionAccess + " partial " + m.OptionType + " " + m.CsType + " : ProtoBuf.IExtensible, ProtoBuf.IMessage");
            cw.WriteLine("global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing){ return null; }");
            cw.WriteLine("public byte[] SerializeToBytes(){return SerializeToBytes(this);}");
            cw.WriteLine("public void SerializeLengthDelimited(Stream stream){SerializeLengthDelimited(stream, this);}");
            cw.WriteLine(@"public struct stMessageOperator : ProtoBuf.IMessageOperator
{
    public ProtoBuf.IMessage New() { return new MessageClass(); }
    public ProtoBuf.IMessage Deserialize(Stream stream) { return MessageClass.Deserialize(stream); }
    public ProtoBuf.IMessage DeserializeLengthDelimited(Stream stream) { return MessageClass.DeserializeLengthDelimited(stream); }
    public ProtoBuf.IMessage DeserializeLength(Stream stream, int length) { return MessageClass.DeserializeLength(stream, length); }
    public ProtoBuf.IMessage Deserialize(byte[] buffer) { return MessageClass.Deserialize(buffer); }
    public ProtoBuf.IMessage Deserialize(byte[] buffer, ProtoBuf.IMessage instance) { return MessageClass.Deserialize(buffer, (MessageClass)instance); }
    public ProtoBuf.IMessage Deserialize(Stream stream, ProtoBuf.IMessage instance) { return MessageClass.Deserialize(stream, (MessageClass)instance); }
    public ProtoBuf.IMessage DeserializeLengthDelimited(Stream stream, ProtoBuf.IMessage instance) { return MessageClass.DeserializeLengthDelimited(stream, (MessageClass)instance); }
    public ProtoBuf.IMessage DeserializeLength(Stream stream, int length, ProtoBuf.IMessage instance) { return MessageClass.DeserializeLength(stream, length, (MessageClass)instance); }
    public void Serialize(Stream stream, ProtoBuf.IMessage instance) { MessageClass.Serialize(stream, (MessageClass)instance); }
    public byte[] SerializeToBytes(ProtoBuf.IMessage instance) { return MessageClass.SerializeToBytes((MessageClass)instance); }
    public void SerializeLengthDelimited(Stream stream, ProtoBuf.IMessage instance) { MessageClass.SerializeLengthDelimited(stream, (MessageClass)instance); }
}
public static ProtoBuf.IMessageOperator MessageOperator = new stMessageOperator();
".Replace("MessageClass", m.CsType));

            if (options.GenerateDefaultConstructors)
            {
                GenerateCtorForDefaults(m);
            }

            GenerateEnums(m);

            GenerateProperties(m);

            //if(options.GenerateToString...
            // ...

            if (m.OptionPreserveUnknown)
            {
                cw.Summary("Values for unknown fields.");
                cw.WriteLine("public List<global::SilentOrbit.ProtocolBuffers.KeyValue> PreservedFields;");
                cw.WriteLine();
            }

            if (m.OptionTriggers)
            {
                cw.Comment("protected virtual void BeforeSerialize() {}");
                cw.Comment("protected virtual void AfterDeserialize() {}");
                cw.WriteLine();
            }

            foreach (ProtoMessage sub in m.Messages.Values)
            {
                GenerateClass(sub);
                cw.WriteLine();
            }
            cw.EndBracket();
            return;
        }
Beispiel #29
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);
        }
Beispiel #30
0
        /// <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 + " = global::SilentOrbit.ProtocolBuffers.ProtocolParser.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 code for writing a class/message
        /// </summary>
        static void GenerateWriter(ProtoMessage m, CodeWriter cw)
        {
            cw.Summary("Serialize the instance into the stream");
            cw.Bracket(m.OptionAccess + " static void Serialize(CitoStream stream, " + m.FullCsType + " instance)");
            if (m.OptionTriggers)
            {
                cw.WriteLine("instance.BeforeSerialize();");
                cw.WriteLine();
            }
            if (m.IsUsingBinaryWriter)
                cw.WriteLine("BinaryWriter bw = new BinaryWriter(stream);");

            foreach (Field f in m.Fields.Values)
                FieldSerializer.FieldWriter(m, f, cw);

            if (m.OptionPreserveUnknown)
            {
                cw.IfBracket("instance.PreservedFields != null");
                cw.ForeachBracket("var kv in instance.PreservedFields");
                cw.WriteLine("ProtocolParser.WriteKey(stream, kv.Key);");
                cw.WriteLine("stream.Write(kv.Value, 0, kv.Value.Length);");
                cw.EndBracket();
                cw.EndBracket();
            }
            cw.EndBracket();
            cw.WriteLine();

            cw.Summary("Helper: Serialize into a MemoryStream and return its byte array");
            cw.Bracket(m.OptionAccess + " static byte[] SerializeToBytes(" + m.FullCsType + " instance)");
            cw.WriteLine("CitoMemoryStream ms = new CitoMemoryStream();");
            cw.WriteLine("Serialize(ms, instance);");
            cw.WriteLine("return ms.ToArray();");
            //cw.EndBracket();
            cw.EndBracket();

            cw.Summary("Helper: Serialize with a varint length prefix");
            cw.Bracket(m.OptionAccess + " static void SerializeLengthDelimited(CitoStream stream, " + m.FullCsType + " instance)");
            cw.WriteLine("byte[] data = SerializeToBytes(instance);");
            cw.WriteLine("ProtocolParser.WriteUInt32_(stream, ProtoPlatform.ArrayLength(data));");
            cw.WriteLine("stream.Write(data, 0, ProtoPlatform.ArrayLength(data));");
            cw.EndBracket();
        }
Beispiel #32
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;
        }
Beispiel #33
0
        static void GenerateReader(ProtoMessage m, CodeWriter cw)
        {
            #region Helper Deserialize Methods
            string refstr = (m.OptionType == "struct") ? "ref " : "";
            if (m.OptionType != "interface")
            {
                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.CsType + " Deserialize(Stream stream)");
                cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                cw.WriteLine("Deserialize(stream, " + refstr + "instance);");
                cw.WriteLine("return instance;");
                cw.EndBracketSpace();

                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.CsType + " DeserializeLengthDelimited(Stream stream)");
                cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                cw.WriteLine("DeserializeLengthDelimited(stream, " + refstr + "instance);");
                cw.WriteLine("return instance;");
                cw.EndBracketSpace();

                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.CsType + " DeserializeLength(Stream stream, int length)");
                cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                cw.WriteLine("DeserializeLength(stream, length, " + refstr + "instance);");
                cw.WriteLine("return instance;");
                cw.EndBracketSpace();

                cw.Summary("Helper: put the buffer into a MemoryStream and create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.CsType + " Deserialize(byte[] buffer)");
                cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                cw.WriteLine("using (var ms = new MemoryStream(buffer))");
                cw.WriteIndent("Deserialize(ms, " + refstr + "instance);");
                cw.WriteLine("return instance;");
                cw.EndBracketSpace();
            }

            cw.Summary("Helper: put the buffer into a MemoryStream before deserializing");
            cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " Deserialize(byte[] buffer, " + refstr + m.FullCsType + " instance)");
            cw.WriteLine("using (var ms = new MemoryStream(buffer))");
            cw.WriteIndent("Deserialize(ms, " + refstr + "instance);");
            cw.WriteLine("return instance;");
            cw.EndBracketSpace();
            #endregion

            string[] methods = new string[]
            {
                "Deserialize",                //Default old one
                "DeserializeLengthDelimited", //Start by reading length prefix and stay within that limit
                "DeserializeLength",          //Read at most length bytes given by argument
            };

            //Main Deserialize
            foreach (string method in methods)
            {
                if (method == "Deserialize")
                {
                    cw.Summary("Takes the remaining content of the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(Stream stream, " + refstr + m.FullCsType + " instance)");
                }
                else if (method == "DeserializeLengthDelimited")
                {
                    cw.Summary("Read the VarInt length prefix and the given number of bytes from the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(Stream stream, " + refstr + m.FullCsType + " instance)");
                }
                else if (method == "DeserializeLength")
                {
                    cw.Summary("Read the given number of bytes from the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(Stream stream, int length, " + refstr + m.FullCsType + " instance)");
                }
                else
                {
                    throw new NotImplementedException();
                }

                if (m.IsUsingBinaryWriter)
                {
                    cw.WriteLine("BinaryReader br = new BinaryReader(stream);");
                }

                //Prepare List<> and default values
                foreach (Field f in m.Fields.Values)
                {
                    if (f.Rule == FieldRule.Repeated)
                    {
                        if (f.OptionReadOnly == false)
                        {
                            //Initialize lists of the custom DateTime or TimeSpan type.
                            string csType = f.ProtoType.FullCsType;
                            if (f.OptionCodeType != null)
                            {
                                csType = f.OptionCodeType;
                            }

                            cw.WriteLine("if (instance." + f.CsName + " == null)");
                            cw.WriteIndent("instance." + f.CsName + " = new List<" + csType + ">();");
                        }
                    }
                    else if (f.OptionDefault != null)
                    {
                        cw.WriteLine("instance." + f.CsName + " = " + f.FormatForTypeAssignment() + ";");
                    }
                    else if (f.Rule == FieldRule.Optional)
                    {
                        if (f.ProtoType is ProtoEnum)
                        {
                            ProtoEnum pe = f.ProtoType as ProtoEnum;
                            //the default value is the first value listed in the enum's type definition
                            foreach (var kvp in pe.Enums)
                            {
                                cw.WriteLine("instance." + f.CsName + " = " + pe.FullCsType + "." + kvp.Name + ";");
                                break;
                            }
                        }
                    }
                }

                if (method == "DeserializeLengthDelimited")
                {
                    //Important to read stream position after we have read the length field
                    cw.WriteLine("long limit = global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadUInt32(stream);");
                    cw.WriteLine("limit += stream.Position;");
                }
                if (method == "DeserializeLength")
                {
                    //Important to read stream position after we have read the length field
                    cw.WriteLine("long limit = stream.Position + length;");
                }

                cw.WhileBracket("true");

                if (method == "DeserializeLengthDelimited" || method == "DeserializeLength")
                {
                    cw.IfBracket("stream.Position >= limit");
                    cw.WriteLine("if (stream.Position == limit)");
                    cw.WriteIndent("break;");
                    cw.WriteLine("else");
                    cw.WriteIndent("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"Read past max limit\");");
                    cw.EndBracket();
                }

                cw.WriteLine("int keyByte = stream.ReadByte();");
                cw.WriteLine("if (keyByte == -1)");
                if (method == "Deserialize")
                {
                    cw.WriteIndent("break;");
                }
                else
                {
                    cw.WriteIndent("throw new System.IO.EndOfStreamException();");
                }

                //Determine if we need the lowID optimization
                bool hasLowID = false;
                foreach (Field f in m.Fields.Values)
                {
                    if (f.ID < 16)
                    {
                        hasLowID = true;
                        break;
                    }
                }

                if (hasLowID)
                {
                    cw.Comment("Optimized reading of known fields with field ID < 16");
                    cw.Switch("keyByte");
                    foreach (Field f in m.Fields.Values)
                    {
                        if (f.ID >= 16)
                        {
                            continue;
                        }
                        cw.Dedent();
                        cw.Comment("Field " + f.ID + " " + f.WireType);
                        cw.Indent();
                        cw.Case(((f.ID << 3) | (int)f.WireType));
                        if (FieldSerializer.FieldReader(f, cw))
                        {
                            cw.WriteLine("continue;");
                        }
                    }
                    cw.SwitchEnd();
                    cw.WriteLine();
                }
                cw.WriteLine("var key = global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadKey((byte)keyByte, stream);");

                cw.WriteLine();

                cw.Comment("Reading field ID > 16 and unknown field ID/wire type combinations");
                cw.Switch("key.Field");
                cw.Case(0);
                cw.WriteLine("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"Invalid field id: 0, something went wrong in the stream\");");
                foreach (Field f in m.Fields.Values)
                {
                    if (f.ID < 16)
                    {
                        continue;
                    }
                    cw.Case(f.ID);
                    //Makes sure we got the right wire type
                    cw.WriteLine("if(key.WireType != global::SilentOrbit.ProtocolBuffers.Wire." + f.WireType + ")");
                    cw.WriteIndent("break;"); //This can be changed to throw an exception for unknown formats.
                    if (FieldSerializer.FieldReader(f, cw))
                    {
                        cw.WriteLine("continue;");
                    }
                }
                cw.CaseDefault();
                if (m.OptionPreserveUnknown)
                {
                    cw.WriteLine("if (instance.PreservedFields == null)");
                    cw.WriteIndent("instance.PreservedFields = new List<global::SilentOrbit.ProtocolBuffers.KeyValue>();");
                    cw.WriteLine("instance.PreservedFields.Add(new global::SilentOrbit.ProtocolBuffers.KeyValue(key, global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadValueBytes(stream, key)));");
                }
                else
                {
                    cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.SkipKey(stream, key);");
                }
                cw.WriteLine("break;");
                cw.SwitchEnd();
                cw.EndBracket();
                cw.WriteLine();

                if (m.OptionTriggers)
                {
                    cw.WriteLine("instance.AfterDeserialize();");
                }
                cw.WriteLine("return instance;");
                cw.EndBracket();
                cw.WriteLine();
            }

            return;
        }
Beispiel #34
0
        /// <summary>
        /// Generates code for writing a class/message
        /// </summary>
        static void GenerateWriter(ProtoMessage m, CodeWriter cw)
        {
            cw.Summary("Serialize the instance into the stream");
            cw.Bracket(m.OptionAccess + " static void Serialize(Stream stream, " + m.CsType + " instance)");
            if (m.OptionTriggers)
            {
                cw.WriteLine("instance.BeforeSerialize();");
                cw.WriteLine();
            }
            if (m.IsUsingBinaryWriter)
                cw.WriteLine("BinaryWriter bw = new BinaryWriter(stream);");

            foreach (Field f in m.Fields.Values)
                FieldSerializer.FieldWriter(m, f, cw);

            if (m.OptionPreserveUnknown)
            {
                cw.IfBracket("instance.PreservedFields != null");
                cw.ForeachBracket("var kv in instance.PreservedFields");
                cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteKey(stream, kv.Key);");
                cw.WriteLine("stream.Write(kv.Value, 0, kv.Value.Length);");
                cw.EndBracket();
                cw.EndBracket();
            }
            cw.EndBracket();
            cw.WriteLine();

            cw.Summary("Helper: Serialize into a MemoryStream and return its byte array");
            cw.Bracket(m.OptionAccess + " static byte[] SerializeToBytes(" + m.CsType + " instance)");
            cw.Using("var ms = new MemoryStream()");
            cw.WriteLine("Serialize(ms, instance);");
            cw.WriteLine("return ms.ToArray();");
            cw.EndBracket();
            cw.EndBracket();
        }
Beispiel #35
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();
        }
Beispiel #36
0
 /// <summary>
 /// Generates code for writing one field as a JSON string
 /// </summary>
 public static void FieldJsonWriter(ProtoMessage m, Field f, CodeWriter cw, Options options)
 {
     cw.WriteLine("writer.Write(\"\\\"" + f.ProtoName + "\\\":\");");
     if (f.Rule == FieldRule.Repeated)
     {
         cw.WriteLine();
         cw.IfBracket("instance." + f.CsName + " != null");
         cw.WriteLine("writer.Write(\"[\");");
         cw.WriteLine("var first = true;");
         cw.ForeachBracket("var i" + f.ID + " in instance." + f.CsName);
         cw.WriteLine("if (!first) writer.Write(\",\");");
         cw.WriteLine("else first = false;");
         cw.WriteLine(FieldWriterJsonType(f, m.RequiredMessageTables, "writer", "i" + f.ID));
         cw.EndBracket();
         cw.WriteLine("writer.Write(\"]\");");
         cw.ElseBracket();
         cw.WriteLine("writer.Write(\"null\");");
         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)
         {
             var nullable = (f.ProtoType.Nullable || options.Nullable) && !(f.ProtoType.OptionType == "interface" && m.RequiredMessageTables.Contains(f.ProtoType));
             if (nullable) //Struct always exist, not optional
             {
                 cw.IfBracket("instance." + f.CsName + " != null");
             }
             var needValue = !f.ProtoType.Nullable && options.Nullable;
             cw.WriteLine(FieldWriterJsonType(f, m.RequiredMessageTables, "writer", "instance." + f.CsName + (needValue ? ".Value" : "")));
             if (nullable)   //Struct always exist, not optional
             {
                 cw.ElseBracket();
                 cw.WriteLine("writer.Write(\"null\");");
                 cw.EndBracket();
             }
             return;
         }
         if (f.ProtoType is ProtoEnum)
         {
             cw.WriteLine(FieldWriterJsonType(f, m.RequiredMessageTables, "writer", "instance." + f.CsName));
             return;
         }
         cw.WriteLine(FieldWriterJsonType(f, m.RequiredMessageTables, "writer", "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.\");");
         }
         cw.WriteLine(FieldWriterJsonType(f, m.RequiredMessageTables, "writer", "instance." + f.CsName));
         return;
     }
     throw new NotImplementedException("Unknown rule: " + f.Rule);
 }
Beispiel #37
0
        /// <summary>
        /// Generate code for reading and writing protocol buffer messages
        /// </summary>
        public static void Save(ProtoCollection file, Options options)
        {
            string csPath = options.OutputPath;

            CodeWriter.DefaultIndentPrefix = options.UseTabs ? "\t" : "    ";

            string ext    = Path.GetExtension(csPath);
            string prefix = csPath.Substring(0, csPath.Length - ext.Length);

            string csDir = Path.GetDirectoryName(csPath);

            if (Directory.Exists(csDir) == false)
            {
                Directory.CreateDirectory(csDir);
            }

            //Basic structures
            using (var cw = new CodeWriter(csPath))
            {
                cw.Comment(@"Classes and structures being serialized");
                cw.WriteLine();
                cw.Comment(@"Generated by ProtocolBuffer
- a pure c# code generation implementation of protocol buffers
Report bugs to: https://silentorbit.com/protobuf/");
                cw.WriteLine();
                cw.Comment(@"DO NOT EDIT
This file will be overwritten when CodeGenerator is run.
To make custom modifications, edit the .proto file and add //:external before the message line
then write the code and the changes in a separate file.");

                cw.WriteLine("using System;");
                cw.WriteLine("using System.Collections.Generic;");
                cw.WriteLine();

                var messageCode = new MessageCode(cw, options);

                string ns = null; //avoid writing namespace between classes if they belong to the same
                foreach (ProtoMessage m in file.Messages.Values)
                {
                    if (ns != m.CsNamespace)
                    {
                        if (ns != null) //First time
                        {
                            cw.EndBracket();
                        }

                        if (m.CsNamespace == "global")
                        {
                            ns = null;
                        }
                        else
                        {
                            cw.Bracket("namespace " + m.CsNamespace);
                            ns = m.CsNamespace;
                        }
                    }
                    messageCode.GenerateClass(m);
                    cw.WriteLine();
                }

                foreach (ProtoEnum e in file.Enums.Values)
                {
                    if (ns != e.CsNamespace)
                    {
                        if (ns != null) //First time
                        {
                            cw.EndBracket();
                        }
                        cw.Bracket("namespace " + e.CsNamespace);
                        ns = e.CsNamespace;
                    }
                    messageCode.GenerateEnum(e);
                    cw.WriteLine();
                }

                if (ns != null)
                {
                    cw.EndBracket();
                }
            }

            //.Serializer.cs
            //Code for Reading/Writing
            using (var cw = new CodeWriter(prefix + ".Serializer" + ext))
            {
                cw.Comment(@"This is the backend code for reading and writing");
                cw.WriteLine();
                cw.Comment(@"Generated by ProtocolBuffer
- a pure c# code generation implementation of protocol buffers
Report bugs to: https://silentorbit.com/protobuf/");
                cw.WriteLine();
                cw.Comment(@"DO NOT EDIT
This file will be overwritten when CodeGenerator is run.");

                cw.WriteLine("using System;");
                cw.WriteLine("using System.IO;");
                cw.WriteLine("using System.Text;");
                cw.WriteLine("using System.Collections.Generic;");
                cw.WriteLine();

                cw.WriteLine("#pragma warning disable 0472, 0162");
                cw.WriteLine();

                string ns = null; //avoid writing namespace between classes if they belong to the same
                foreach (ProtoMessage m in file.Messages.Values)
                {
                    if (ns != m.CsNamespace)
                    {
                        if (ns != null) //First time
                        {
                            cw.EndBracket();
                        }

                        if (m.CsNamespace == "global")
                        {
                            ns = null;
                        }
                        else
                        {
                            cw.Bracket("namespace " + m.CsNamespace);
                            ns = m.CsNamespace;
                        }
                    }
                    var messageSerializer = new MessageSerializer(cw, options);
                    messageSerializer.GenerateClassSerializer(m);
                }

                if (ns != null)
                {
                    cw.EndBracket();
                }
            }

            string libPath = Path.Combine(Path.GetDirectoryName(csPath), "ProtocolParser.cs");

            using (TextWriter codeWriter = new StreamWriter(libPath, false, Encoding.UTF8))
            {
                codeWriter.NewLine = "\r\n";
                ReadCode(codeWriter, "MessageTable", true);
                ReadCode(codeWriter, "ProtocolParser", false);
                ReadCode(codeWriter, "ProtocolParserExceptions", false);
                ReadCode(codeWriter, "ProtocolParserFixed", false);
                ReadCode(codeWriter, "ProtocolParserKey", false);
                ReadCode(codeWriter, "ProtocolParserMemory", false);
                ReadCode(codeWriter, "ProtocolParserVarInt", false);
            }
        }
Beispiel #38
0
        static void GenerateReader(ProtoMessage m, CodeWriter cw, Options options)
        {
            cw.WriteLine("#region [Methods] Reader");

            #region [Method] ReadFromStream
            if (m.OptionExternal == false)
            {
                cw.Bracket("public void ReadFromStream(Stream stream, int size)");
                {
                    cw.WriteLine("DeserializeLength(stream, size, this);");
                }
                cw.EndBracketSpace();
            }
            #endregion

            #region Helper Deserialize Methods
            string refstr = (m.OptionType == "struct") ? "ref " : "";
            if (m.OptionType != "interface")
            {
                var newInstance = m.OptionType == "struct" ? $"new {m.CsType}();" : $"Pool.Get<{m.CsType}>();";

                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.CsType + " Deserialize(Stream stream)");
                {
                    cw.WriteLine(m.CsType + " instance = " + newInstance);
                    cw.WriteLine("Deserialize(stream, " + refstr + "instance);");
                    cw.WriteLine("return instance;");
                }
                cw.EndBracketSpace();

                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.CsType + " DeserializeLengthDelimited(Stream stream)");
                {
                    cw.WriteLine(m.CsType + " instance = " + newInstance);
                    cw.WriteLine("DeserializeLengthDelimited(stream, " + refstr + "instance);");
                    cw.WriteLine("return instance;");
                }
                cw.EndBracketSpace();

                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.CsType + " DeserializeLength(Stream stream, int length)");
                {
                    cw.WriteLine(m.CsType + " instance = " + newInstance);
                    cw.WriteLine("DeserializeLength(stream, length, " + refstr + "instance);");
                    cw.WriteLine("return instance;");
                }
                cw.EndBracketSpace();

                cw.Summary("Helper: put the buffer into a MemoryStream and create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.CsType + " Deserialize(byte[] buffer)");
                {
                    cw.WriteLine(m.CsType + " instance = " + newInstance);
                    cw.WriteLine("var ms = Pool.Get<MemoryStream>();");
                    cw.WriteLine("ms.Write(buffer, 0 ,buffer.Length);");
                    cw.WriteLine("ms.Position = 0;");
                    cw.WriteLine("Deserialize(ms, " + refstr + "instance);");
                    cw.WriteLine("Pool.FreeMemoryStream(ref ms);");
                    cw.WriteLine("return instance;");
                }
                cw.EndBracketSpace();
            }

            cw.Summary("Helper: put the buffer into a MemoryStream before deserializing");
            cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " Deserialize(byte[] buffer, " + refstr + m.FullCsType + " instance)");
            cw.WriteLine("var ms = Pool.Get<MemoryStream>();");
            cw.WriteLine("ms.Write(buffer, 0 ,buffer.Length);");
            cw.WriteLine("ms.Position = 0;");
            cw.WriteLine("Deserialize(ms, " + refstr + "instance);");
            cw.WriteLine("Pool.FreeMemoryStream(ref ms);");
            cw.WriteLine("return instance;");
            cw.EndBracketSpace();
            #endregion

            string[] methods = new string[]
            {
                "Deserialize",                //Default old one
                "DeserializeLengthDelimited", //Start by reading length prefix and stay within that limit
                "DeserializeLength",          //Read at most length bytes given by argument
            };

            //Main Deserialize
            foreach (string method in methods)
            {
                if (method == "Deserialize")
                {
                    cw.Summary("Takes the remaining content of the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(Stream stream, " + refstr + m.FullCsType + " instance)");
                }
                else if (method == "DeserializeLengthDelimited")
                {
                    cw.Summary("Read the VarInt length prefix and the given number of bytes from the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(Stream stream, " + refstr + m.FullCsType + " instance)");
                }
                else if (method == "DeserializeLength")
                {
                    cw.Summary("Read the given number of bytes from the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(Stream stream, int length, " + refstr + m.FullCsType + " instance)");
                }
                else
                {
                    throw new NotImplementedException();
                }

                GenerateDefaults(m, cw, options);

                if (method == "DeserializeLengthDelimited")
                {
                    //Important to read stream position after we have read the length field
                    cw.WriteLine("long limit = global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadUInt32(stream);");
                    cw.WriteLine("limit += stream.Position;");
                }
                if (method == "DeserializeLength")
                {
                    //Important to read stream position after we have read the length field
                    cw.WriteLine("long limit = stream.Position + length;");
                }

                cw.WhileBracket("true");

                if (method == "DeserializeLengthDelimited" || method == "DeserializeLength")
                {
                    cw.IfBracket("stream.Position >= limit");
                    cw.WriteLine("if (stream.Position == limit)");
                    cw.WriteIndent("break;");
                    cw.WriteLine("else");
                    cw.WriteIndent("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"Read past max limit\");");
                    cw.EndBracket();
                }

                cw.WriteLine("int keyByte = stream.ReadByte();");
                cw.WriteLine("if (keyByte == -1)");
                if (method == "Deserialize")
                {
                    cw.WriteIndent("break;");
                }
                else
                {
                    cw.WriteIndent("throw new System.IO.EndOfStreamException();");
                }

                //Determine if we need the lowID optimization
                bool hasLowID = false;
                foreach (Field f in m.Fields.Values)
                {
                    if (f.ID < 16)
                    {
                        hasLowID = true;
                        break;
                    }
                }

                if (hasLowID)
                {
                    cw.Comment("Optimized reading of known fields with field ID < 16");
                    cw.Switch("keyByte");
                    foreach (Field f in m.Fields.Values)
                    {
                        if (f.ID >= 16)
                        {
                            continue;
                        }
                        cw.Dedent();
                        cw.Comment("Field " + f.ID + " " + f.WireType);
                        cw.Indent();
                        cw.Case(((f.ID << 3) | (int)f.WireType));
                        if (FieldSerializer.FieldReader(f, cw))
                        {
                            cw.WriteLine("continue;");
                        }
                    }
                    cw.SwitchEnd();
                    cw.WriteLine();
                }
                cw.WriteLine("var key = global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadKey((byte)keyByte, stream);");

                cw.WriteLine();

                cw.Comment("Reading field ID > 16 and unknown field ID/wire type combinations");
                cw.Switch("key.Field");
                cw.Case(0);
                cw.WriteLine("throw new global::SilentOrbit.ProtocolBuffers.ProtocolBufferException(\"Invalid field id: 0, something went wrong in the stream\");");
                foreach (Field f in m.Fields.Values)
                {
                    if (f.ID < 16)
                    {
                        continue;
                    }
                    cw.Case(f.ID);
                    //Makes sure we got the right wire type
                    cw.WriteLine("if(key.WireType != global::SilentOrbit.ProtocolBuffers.Wire." + f.WireType + ")");
                    cw.WriteIndent("break;"); //This can be changed to throw an exception for unknown formats.
                    if (FieldSerializer.FieldReader(f, cw))
                    {
                        cw.WriteLine("continue;");
                    }
                }
                cw.CaseDefault();
                if (m.OptionPreserveUnknown)
                {
                    cw.WriteLine("if (instance.PreservedFields == null)");
                    cw.WriteIndent("instance.PreservedFields = new List<global::SilentOrbit.ProtocolBuffers.KeyValue>();");
                    cw.WriteLine("instance.PreservedFields.Add(new global::SilentOrbit.ProtocolBuffers.KeyValue(key, global::SilentOrbit.ProtocolBuffers.ProtocolParser.ReadValueBytes(stream, key)));");
                }
                else
                {
                    cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.SkipKey(stream, key);");
                }
                cw.WriteLine("break;");
                cw.SwitchEnd();
                cw.EndBracket();
                cw.WriteLine();

                if (m.OptionTriggers)
                {
                    cw.WriteLine("instance.AfterDeserialize();");
                }
                cw.WriteLine("return instance;");
                cw.EndBracket();
                cw.WriteLine();
            }
            cw.WriteLine("#endregion");
            return;
        }
Beispiel #39
0
        /// <summary>
        /// Generates code for writing one field
        /// </summary>
        public static 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);
                        cw.WriteLine(FieldWriterType(f, "msField", "bw" + f.ID, "i" + f.ID));
                        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("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 (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;
                    cw.WriteLine(FieldWriterType(f, "stream", "bw", "instance." + f.CsName + (needValue ? ".Value" : "")));
                    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("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);
        }
Beispiel #40
0
        static void GeneratePooled(ProtoMessage m, CodeWriter cw, Options options)
        {
            cw.WriteLine("#region [Methods] Pooled");
            cw.WriteLine("private bool _disposed;");
            cw.WriteLine("public bool ShouldPool = true;");
            cw.WriteLine();

            #region [Method] Dispose
            cw.Bracket("public virtual void Dispose()");
            cw.WriteLine("if (this._disposed)");
            cw.WriteIndent("return;");
            cw.WriteLine("this.ResetToPool();");
            cw.WriteLine("this._disposed = true;");
            cw.EndBracketSpace();
            #endregion

            #region [Method] ResetToPool
            cw.Bracket("public void ResetToPool()");
            cw.WriteLine("ResetToPool(this);");
            cw.EndBracketSpace();
            #endregion

            #region [Method] [Static] ResetToPool
            cw.Bracket($"public static void ResetToPool({m.CsType} instance)");
            cw.WriteLine("if (!instance.ShouldPool)");
            cw.WriteIndent("return;");


            string GetFieldType(Field field)
            {
                string csType = field.ProtoType.FullCsType;

                if (field.OptionCodeType != null)
                {
                    csType = field.OptionCodeType;
                }
                return(csType);
            }

            // Generate Default Structs
            List <string> defStructs = new List <string>();

            foreach (var field in m.Fields.Values)
            {
                string csFullType = GetFieldType(field);
                string csType     = field.ProtoType.CsType;
                string fName      = field.CsName;
                cw.Comment($"[{csType}] {fName}");

                // Generate Default Structs
                if (field.Rule != FieldRule.Repeated && field.ProtoType.OptionType == "struct" &&
                    string.IsNullOrEmpty(field.OptionDefault) &&
                    defStructs.Contains(csFullType) == false)
                {
                    cw.WriteLine($"{csFullType} def{csType} = new {csFullType}();");
                    defStructs.Add(csFullType);
                }

                if (field.Rule == FieldRule.Repeated)
                {
                    cw.Bracket($"if (instance.{field.CsName} != null)");
                    if (field.ProtoType is ProtoMessage)
                    {
                        cw.ForBracket($"int i = 0; i < instance.{fName}.Count; i++");
                        cw.Bracket($"if (instance.{fName}[i] != null)");
                        cw.WriteLine($"instance.{fName}[i].ResetToPool();");
                        cw.WriteLine($"instance.{fName}[i] = null;");
                        cw.EndBracket();
                        cw.EndBracket();
                    }

                    cw.WriteLine($"List<{csFullType}> ins{fName} = instance.{fName};");
                    cw.WriteLine($"Pool.FreeList<{csFullType}>(ref ins{fName});");
                    cw.WriteLine($"instance.{fName} = ins{fName};");
                    cw.EndBracket();
                }
                else
                {
                    if (field.ProtoType is ProtoMessage && field.ProtoType.OptionType != "struct")
                    {
                        cw.Bracket($"if (instance.{fName} != null)");
                        cw.WriteLine($"instance.{fName}.ResetToPool();");
                        cw.WriteLine($"instance.{fName} = null;");
                        cw.EndBracket();
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(field.OptionDefault) == false)
                        {
                            cw.WriteLine($"instance.{fName} = {field.FormatForTypeAssignment()};");
                        }
                        else if (field.ProtoType.OptionType == "struct")
                        {
                            cw.WriteLine($"instance.{fName} = def{csType};");
                        }
                        else
                        {
                            cw.WriteLine($"instance.{fName} = default({csFullType});");
                        }
                    }
                }

                cw.WriteLine();
            }

            defStructs.Clear();

            cw.WriteLine($"Pool.Free<{m.FullCsType}>(ref instance);");
            cw.EndBracketSpace();
            #endregion

            #region [Method] EnterPool
            cw.Bracket("public virtual void EnterPool()");
            cw.WriteLine("this._disposed = true;");
            cw.EndBracketSpace();
            #endregion

            #region [Method] LeavePool
            cw.Bracket("public virtual void LeavePool()");
            cw.WriteLine("this._disposed = false;");
            cw.EndBracketSpace();
            #endregion

            cw.WriteLine("#endregion");
        }
        static void GenerateReader(ProtoMessage m, CodeWriter cw)
        {
            #region Helper Deserialize Methods
            string refstr = (m.OptionType == "struct") ? "ref " : "";
            if (m.OptionType != "interface")
            {/*
                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " Deserialize(CitoStream stream)");
                cw.WriteLine(m.FullCsType + " instance = new " + m.FullCsType + "();");
                cw.WriteLine("Deserialize(stream, " + refstr + "instance);");
                cw.WriteLine("return instance;");
                cw.EndBracketSpace();
                */
                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " DeserializeLengthDelimitedNew(CitoStream stream)");
                cw.WriteLine(m.FullCsType + " instance = new " + m.FullCsType + "();");
                cw.WriteLine("DeserializeLengthDelimited(stream, " + refstr + "instance);");
                cw.WriteLine("return instance;");
                cw.EndBracketSpace();
                /*
                cw.Summary("Helper: create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " DeserializeLength(CitoStream stream, int length)");
                cw.WriteLine(m.FullCsType + " instance = new " + m.FullCsType + "();");
                cw.WriteLine("DeserializeLength(stream, length, " + refstr + "instance);");
                cw.WriteLine("return instance;");
                cw.EndBracketSpace();

                cw.Summary("Helper: put the buffer into a MemoryStream and create a new instance to deserializing into");
                cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " Deserialize(byte[] buffer, int length)");
                cw.WriteLine(m.FullCsType + " instance = new " + m.FullCsType + "();");
                cw.WriteLine("CitoMemoryStream ms = CitoMemoryStream.Create(buffer, length);");
                cw.WriteIndent("Deserialize(ms, " + refstr + "instance);");
                cw.WriteLine("return instance;");
                cw.EndBracketSpace();*/
            }

            cw.Summary("Helper: put the buffer into a MemoryStream before deserializing");
            cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " DeserializeBuffer(byte[] buffer, int length, " + refstr + m.FullCsType + " instance)");
            cw.WriteLine("CitoMemoryStream ms = CitoMemoryStream.Create(buffer, length);");
            cw.WriteIndent("Deserialize(ms, " + refstr + "instance);");
            cw.WriteLine("return instance;");
            cw.EndBracketSpace();
            #endregion

            string[] methods = new string[]
            {
                "Deserialize", //Default old one
                "DeserializeLengthDelimited", //Start by reading length prefix and stay within that limit
                "DeserializeLength", //Read at most length bytes given by argument
            };

            //Main Deserialize
            foreach (string method in methods)
            {
                if (method == "Deserialize")
                {
                    cw.Summary("Takes the remaining content of the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(CitoStream stream, " + refstr + m.FullCsType + " instance)");
                } else if (method == "DeserializeLengthDelimited")
                {
                    cw.Summary("Read the VarInt length prefix and the given number of bytes from the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(CitoStream stream, " + refstr + m.FullCsType + " instance)");
                } else if (method == "DeserializeLength")
                {
                    cw.Summary("Read the given number of bytes from the stream and deserialze it into the instance.");
                    cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " " + method + "(CitoStream stream, int length, " + refstr + m.FullCsType + " instance)");
                } else
                    throw new NotImplementedException();

                if (m.IsUsingBinaryWriter)
                    cw.WriteLine("BinaryReader br = new BinaryReader(stream);");

                //Prepare List<> and default values
                foreach (Field f in m.Fields.Values)
                {
                    if (f.Rule == FieldRule.Repeated)
                    {
                        cw.WriteLine("if (instance." + f.CsName + " == null)");
                        cw.WriteLine("{");
                        cw.WriteIndent("instance." + f.CsName + " = new " + f.ProtoType.FullCsType + "[1];");
                        cw.WriteIndent("instance." + f.CsName + "Count = 0;");
                        cw.WriteIndent("instance." + f.CsName + "Length = 1;");
                        cw.WriteLine("}");
                    } else if (f.OptionDefault != null)
                    {
                        if (f.ProtoType is ProtoEnum)
                            cw.WriteLine("instance." + f.CsName + " = " + f.ProtoType.FullCsType + "Enum." + f.OptionDefault + ";");
                        else
                            cw.WriteLine("instance." + f.CsName + " = " + f.OptionDefault + ";");
                    } else if (f.Rule == FieldRule.Optional)
                    {
                        if (f.ProtoType is ProtoEnum)
                        {
                            ProtoEnum pe = f.ProtoType as ProtoEnum;
                            //the default value is the first value listed in the enum's type definition
                            foreach (var kvp in pe.Enums)
                            {
                                cw.WriteLine("instance." + f.CsName + " = " + pe.FullCsType + "_" + kvp.Name + ";");
                                break;
                            }
                        }
                    }
                }

                if (method == "DeserializeLengthDelimited")
                {
                    //Important to read stream position after we have read the length field
                    cw.WriteLine("int limit = ProtocolParser.ReadUInt32(stream);");
                    cw.WriteLine("limit += stream.Position();");
                }
                if (method == "DeserializeLength")
                {
                    //Important to read stream position after we have read the length field
                    cw.WriteLine("int limit = stream.Position() + length;");
                }

                cw.WhileBracket("true");

                if (method == "DeserializeLengthDelimited" || method == "DeserializeLength")
                {
                    cw.IfBracket("stream.Position() >= limit");
                    cw.WriteLine("if(stream.Position() == limit)");
                    cw.WriteIndent("break;");
                    cw.WriteLine("else");
                    cw.WriteIndent("//throw new InvalidOperationException(\"Read past max limit\");");
                    cw.WriteIndent("return null;");
                    cw.EndBracket();
                }

                cw.WriteLine("int keyByte = stream.ReadByte();");
                cw.WriteLine("if (keyByte == -1)");
                if (method == "Deserialize")
                    cw.WriteIndent("break;");
                else
                {
                    cw.WriteIndent("//throw new System.IO.EndOfStreamException();");
                    cw.WriteIndent("return null;");
                }

                //Determine if we need the lowID optimization
                bool hasLowID = false;
                foreach (Field f in m.Fields.Values)
                {
                    if (f.ID < 16)
                    {
                        hasLowID = true;
                        break;
                    }
                }

                if (hasLowID)
                {
                    cw.Comment("Optimized reading of known fields with field ID < 16");
                    cw.Switch("keyByte");
                    foreach (Field f in m.Fields.Values)
                    {
                        if (f.ID >= 16)
                            continue;
                        cw.Comment("Field " + f.ID + " " + f.WireType);
                        cw.Case(((f.ID << 3) | (int)f.WireType));
                        if (FieldSerializer.FieldReader(f, cw))
                            cw.WriteLine("continue;");
                    }
                    cw.WriteLine("default: break;");
                    cw.EndBracket();
                    cw.WriteLine();
                }
                cw.WriteLine("#if CITO\n Key key = ProtocolParser.ReadKey_(keyByte.LowByte, stream);");
                cw.WriteLine("#else\n Key key = ProtocolParser.ReadKey_((byte)keyByte, stream);\n#endif");

                cw.WriteLine();

                cw.Comment("Reading field ID > 16 and unknown field ID/wire type combinations");
                cw.Switch("key.GetField()");
                cw.Case(0);
                cw.WriteLine("//throw new InvalidDataException(\"Invalid field id: 0, something went wrong in the stream\");");
                cw.WriteLine("return null;");
                foreach (Field f in m.Fields.Values)
                {
                    if (f.ID < 16)
                        continue;
                    cw.Case(f.ID);
                    //Makes sure we got the right wire type
                    cw.WriteLine("if(key.GetWireType() != Wire." + f.WireType + ")");
                    cw.WriteIndent("break;"); //This can be changed to throw an exception for unknown formats.
                    if (FieldSerializer.FieldReader(f, cw))
                        cw.WriteLine("continue;");
                }
                cw.CaseDefault();
                if (m.OptionPreserveUnknown)
                {
                    cw.WriteLine("if (instance.PreservedFields == null)");
                    cw.WriteIndent("instance.PreservedFields = new List<KeyValue>();");
                    cw.WriteLine("instance.PreservedFields.Add(new KeyValue(key, ProtocolParser.ReadValueBytes(stream, key)));");
                } else
                {
                    cw.WriteLine("ProtocolParser.SkipKey(stream, key);");
                }
                cw.WriteLine("break;");
                cw.EndBracket();
                cw.EndBracket();
                cw.WriteLine();

                if (m.OptionTriggers)
                    cw.WriteLine("instance.AfterDeserialize();");
                cw.WriteLine("return instance;");
                cw.EndBracket();
                cw.WriteLine();
            }

            return;
        }
Beispiel #42
0
        /// <summary>
        /// Generates code for writing a class/message
        /// </summary>
        static void GenerateWriter(ProtoMessage m, CodeWriter cw, Options options)
        {
            cw.WriteLine("#region [Methods] Writer");

            #region [Method] Serialize
            cw.Summary("Serialize the instance into the stream");
            cw.Bracket(m.OptionAccess + " static void Serialize(Stream stream, " + m.CsType + " instance)");
            {
                if (m.OptionTriggers)
                {
                    cw.WriteLine("instance.BeforeSerialize();");
                    cw.WriteLine();
                }

                //Shared memorystream for all fields
                cw.WriteLine("var msField = Pool.Get<MemoryStream>();");

                foreach (Field f in m.Fields.Values)
                {
                    FieldSerializer.FieldWriter(m, f, cw, false);
                }

                cw.WriteLine("Pool.FreeMemoryStream(ref msField);");

                if (m.OptionPreserveUnknown)
                {
                    cw.IfBracket("instance.PreservedFields != null");
                    cw.ForeachBracket("var kv in instance.PreservedFields");
                    cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteKey(stream, kv.Key);");
                    cw.WriteLine("stream.Write(kv.Value, 0, kv.Value.Length);");
                    cw.EndBracket();
                    cw.EndBracket();
                }
            }
            cw.EndBracketSpace();
            #endregion

            #region [Method] SerializeToBytes
            cw.Summary("Helper: Serialize into a MemoryStream and return its byte array");
            cw.Bracket(m.OptionAccess + " static byte[] SerializeToBytes(" + m.CsType + " instance)");
            {
                cw.WriteLine("var ms = Pool.Get<MemoryStream>();");
                cw.WriteLine("Serialize(ms, instance);");
                cw.WriteLine("var arr = ms.ToArray();");
                cw.WriteLine("Pool.FreeMemoryStream(ref ms);");
                cw.WriteLine("return arr;");
            }
            cw.EndBracket();
            #endregion

            #region [Method] SerializeLengthDelimited
            cw.Summary("Helper: Serialize with a varint length prefix");
            cw.Bracket(m.OptionAccess + " static void SerializeLengthDelimited(Stream stream, " + m.CsType + " instance)");
            {
                cw.WriteLine("var data = SerializeToBytes(instance);");
                cw.WriteLine("global::SilentOrbit.ProtocolBuffers.ProtocolParser.WriteUInt32(stream, (uint)data.Length);");
                cw.WriteLine("stream.Write(data, 0, data.Length);");
            }
            cw.EndBracketSpace();
            #endregion

            #region [Method] SerializeDelta
            cw.Bracket($"public static void SerializeDelta(Stream stream, {m.CsType} instance, {m.CsType} previous)");
            {
                cw.WriteLine("var msField = Pool.Get<MemoryStream>();");

                foreach (Field f in m.Fields.Values)
                {
                    cw.IfBracket($"instance.{f.CsName} != previous.{f.CsName}");
                    FieldSerializer.FieldWriter(m, f, cw, true);
                    cw.EndBracket();
                }

                cw.WriteLine("Pool.FreeMemoryStream(ref msField);");
            }
            cw.EndBracket();
            #endregion

            #region [Method] WriteToStream
            if (m.OptionExternal == false)
            {
                cw.Bracket("public void WriteToStream(Stream stream)");
                {
                    cw.WriteLine("Serialize(stream, this);");
                }
                cw.EndBracket();
            }
            #endregion

            #region [Method] WriteToStreamDelta
            if (m.OptionExternal == false)
            {
                cw.Bracket($"public void WriteToStreamDelta(Stream stream, {m.CsType} previous)");
                {
                    cw.IfBracket("previous != null");
                    {
                        cw.WriteLine("SerializeDelta(stream, this, previous);");
                    }
                    cw.EndBracket();
                    cw.Bracket("else");
                    {
                        cw.WriteLine("Serialize(stream, this);");
                    }
                    cw.EndBracket();
                }
                cw.EndBracket();
            }
            #endregion

            cw.WriteLine("#endregion");
        }
Beispiel #43
0
        /// <summary>
        /// Generate code for reading and writing protocol buffer messages
        /// </summary>
        public static void Save(ProtoCollection file, Options options)
        {
            string csPath = options.OutputPath;

            CodeWriter.DefaultIndentPrefix = options.UseTabs ? "\t" : "    ";

            string ext    = Path.GetExtension(csPath);
            string prefix = csPath.Substring(0, csPath.Length - ext.Length);

            string csDir = Path.GetDirectoryName(csPath);

            if (Directory.Exists(csDir) == false)
            {
                Directory.CreateDirectory(csDir);
            }

            //Basic structures
            using (var cw = new CodeWriter(csPath))
            {
                if (string.IsNullOrWhiteSpace(file.Comments) == false)
                {
                    cw.Comment(file.Comments);
                    cw.WriteLine();
                }

                cw.Comment(@"Classes and structures being serialized");
                cw.WriteLine();
                cw.Comment(Disclamer);
                cw.WriteLine();
                cw.Comment(@"DO NOT EDIT
This file will be overwritten when CodeGenerator is run.
To make custom modifications, edit the .proto file and add //:external before the message line
then write the code and the changes in a separate file.");

                cw.WriteLine();
                cw.Comment("ReSharper disable InconsistentNaming");
                cw.WriteLine();

                cw.WriteLine("using System;");
                cw.WriteLine("using System.Collections.Generic;");
                if (options.DataContractAttributes)
                {
                    cw.WriteLine("using System.Runtime.Serialization;");
                }
                cw.WriteLine();

                var messageCode = new MessageCode(cw, options);

                string ns = null; //avoid writing namespace between classes if they belong to the same
                foreach (ProtoMessage m in file.Messages.Values)
                {
                    if (ns != m.CsNamespace)
                    {
                        if (ns != null) //First time
                        {
                            cw.EndBracket();
                        }
                        cw.Bracket("namespace " + m.CsNamespace);
                        ns = m.CsNamespace;
                    }
                    messageCode.GenerateClass(m);
                    cw.WriteLine();
                }

                foreach (ProtoEnum e in file.Enums.Values)
                {
                    if (ns != e.CsNamespace)
                    {
                        if (ns != null) //First time
                        {
                            cw.EndBracket();
                        }
                        cw.Bracket("namespace " + e.CsNamespace);
                        ns = e.CsNamespace;
                    }
                    messageCode.GenerateEnum(e);
                    cw.WriteLine();
                }

                if (ns != null)
                {
                    cw.EndBracket();
                }
            }

            //.Serializer.cs
            //Code for Reading/Writing
            using (var cw = new CodeWriter(prefix + ".Serializer" + ext))
            {
                if (string.IsNullOrWhiteSpace(file.Comments) == false)
                {
                    cw.Comment(file.Comments);
                    cw.WriteLine();
                }

                cw.Comment(@"This is the backend code for reading and writing");
                cw.WriteLine();
                cw.Comment(Disclamer);
                cw.WriteLine();
                cw.Comment(@"DO NOT EDIT
This file will be overwritten when CodeGenerator is run.");

                cw.WriteLine();
                cw.Comment("ReSharper disable InconsistentNaming");
                cw.WriteLine();

                cw.WriteLine("using System;");
                cw.WriteLine("using System.IO;");
                cw.WriteLine("using System.Text;");
                cw.WriteLine("using System.Collections.Generic;");
                cw.WriteLine();

                string ns = null; //avoid writing namespace between classes if they belong to the same
                foreach (ProtoMessage m in file.Messages.Values)
                {
                    if (ns != m.CsNamespace)
                    {
                        if (ns != null) //First time
                        {
                            cw.EndBracket();
                        }
                        cw.Bracket("namespace " + m.CsNamespace);
                        ns = m.CsNamespace;
                    }
                    var messageSerializer = new MessageSerializer(cw, options);
                    messageSerializer.GenerateClassSerializer(m);
                }
                if (ns != null)
                {
                    cw.EndBracket();
                }
            }

            //Option to no include ProtocolParser.cs in the output directory
            if (options.NoProtocolParser)
            {
                Console.Error.WriteLine("ProtocolParser.cs not (re)generated");
            }
            else
            {
                string libPath = Path.Combine(Path.GetDirectoryName(csPath), "ProtocolParser.cs");
                using (TextWriter codeWriter = new StreamWriter(libPath, false, Encoding.UTF8))
                {
                    codeWriter.NewLine = "\r\n";
                    ReadCode(codeWriter, "ProtocolParser", true);
                    ReadCode(codeWriter, "ProtocolParserExceptions", false);
                    ReadCode(codeWriter, "ProtocolParserFixed", false);
                    ReadCode(codeWriter, "ProtocolParserKey", false);
                    ReadCode(codeWriter, "ProtocolParserMemory", false);
                    if (options.Net2 == false)
                    {
                        ReadCode(codeWriter, "ProtocolParserMemory4", false);
                    }
                    ReadCode(codeWriter, "ProtocolParserVarInt", false);
                }
            }
        }
Beispiel #44
0
        /// <summary>
        /// Generates the properties.
        /// </summary>
        /// <param name='template'>
        /// if true it will generate only properties that are not included by default, because of the [generate=false] option.
        /// </param>
        static void GenerateProperties(ProtoMessage m, CodeWriter cw)
        {
            foreach (Field f in m.Fields.Values)
            {
                if (f.OptionExternal)
                {
                    cw.WriteLine("//" + GenerateProperty(f) + " // Implemented by user elsewhere");
                }
                else
                {
                    if (f.Comments != null)
                    {
                        cw.Summary(f.Comments);
                    }
                    cw.WriteLine(GenerateProperty(f));
                    cw.WriteLine();
                }
            }

            // Implement ToString
            cw.Bracket("public override string ToString()");
            string returnStatement = "return \"\"";

            Dictionary <int, Field> .ValueCollection fields = m.Fields.Values;
            if (fields.Count > 0)
            {
                List <string> fieldElements = new List <string>();
                foreach (Field f in fields)
                {
                    string fieldHeaderCode = "\"" + f.CsName + ": \" + ";
                    string fieldToStringCode;
                    string fieldCommaCode = " + \", \"";

                    if (f.Rule == FieldRule.Optional && f.ProtoType.Nullable)
                    {
                        // Hide optional nullable fields: this makes logging cleaner for union types
                        fieldToStringCode = string.Format("({0} != null ? {1}{0}{2}:  \"\")", f.CsName, fieldHeaderCode, fieldCommaCode);
                    }
                    else if (f.Rule == FieldRule.Repeated)
                    {
                        // Always output repeated fields with []
                        fieldToStringCode = string.Format("{1}\"[\" + ({0} != null ? string.Join(\", \", {0}.ConvertAll<string>(o => o.ToString()).ToArray()) : \"\") + \"]\"{2}", f.CsName, fieldHeaderCode, fieldCommaCode);
                    }
                    else if (f.ProtoTypeName == "bytes")
                    {
                        // Special code to output bytes
                        fieldToStringCode = string.Format("{1}\"[\" + ({0} != null ? BitConverter.ToString({0}) : \"\") + \"]\"{2}", f.CsName, fieldHeaderCode, fieldCommaCode);
                    }
                    else
                    {
                        fieldToStringCode = fieldHeaderCode + f.CsName + fieldCommaCode;
                    }
                    fieldElements.Add(fieldToStringCode);
                }
                returnStatement = "return " + string.Join(" + \n", fieldElements) + ";";
            }
            cw.WriteLine(returnStatement);
            cw.EndBracket();


            //Wire format field ID
#if DEBUG
            cw.Comment("ProtocolBuffers wire field id");
            foreach (Field f in m.Fields.Values)
            {
                cw.WriteLine("public const int " + f.CsName + "FieldID = " + f.ID + ";");
            }
#endif
        }