Exemple #1
0
        static void ParseEnum(TokenReader tr, ProtoMessage parent, string package)
        {
            ProtoEnum me = new ProtoEnum(parent, package);

            LocalParser.ParseComments(me, lastComment, tr);
            me.ProtoName = tr.ReadNext();

            parent.Enums.Add(me.ProtoName, me); //must be after .ProtoName is read

            if (tr.ReadNext() != "{")
                throw new ProtoFormatException("Expected: {", tr);

            while (true)
            {
                string name = tr.ReadNext();

                if (ParseComment(name))
                    continue;

                if (name == "}")
                    return;

                //Ignore options
                if (name == "option")
                {
                    ParseOption(tr, null);
                    lastComment.Clear();
                    continue;
                }

                ParseEnumValue(tr, me, name);
            }
        }
        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;
        }
Exemple #3
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();
                }

            }

            //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
        }
        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 + " static 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;
        }
Exemple #5
0
 static void GenerateEnums(ProtoMessage m, CodeWriter cw)
 {
     foreach (ProtoEnum me in m.Enums.Values)
     {
         GenerateEnum(me, cw);
     }
 }
        void PrepareMessage(ProtoMessage m)
        {
            //Name of message and enums
            m.CsType = GetCamelCase(m.ProtoName);
            foreach (ProtoEnum e in m.Enums.Values)
            {
                e.CsType = GetCamelCase(e.ProtoName);
            }

            foreach (ProtoMessage sub in m.Messages.Values)
                PrepareMessage(sub);

            //Prepare fields
            foreach (Field f in m.Fields.Values)
            {
                PrepareProtoType(m, f);

                DetectNameClash(m, f);

                if (f.OptionDefault != null)
                {
                    if (f.ProtoType is ProtoBuiltin && ((ProtoBuiltin)f.ProtoType).ProtoName == "bytes")
                        throw new NotImplementedException();
                    if (f.ProtoType is ProtoMessage)
                        throw new ProtoFormatException("Message can't have a default", f.Source);
                }
            }

        }
        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);

            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;
        }
Exemple #8
0
 /// <summary>
 /// Used by types within a namespace
 /// </summary>
 public ProtoType(ProtoMessage parent, string package)
     : this()
 {
     if (this is ProtoCollection == false)
     {
         if (parent == null)
             throw new ArgumentNullException("parent");
         if (package == null)
             throw new ArgumentNullException("package");
     }
     this.Parent = parent;
     this.Package = package;
 }
 static void ParseMessageFlags(ProtoMessage message, string flag)
 {
     switch (flag)
     {
         case "triggers":
             message.OptionTriggers = true;
             break;
         case "preserveunknown":
             message.OptionPreserveUnknown = true;
             break;
         case "external":
             message.OptionExternal = true;
             break;
         default:
             throw new NotImplementedException("Unknown option: " + flag);
     }
 }
Exemple #10
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;
        }
 static void ParseMessageOption(ProtoMessage message, string key, string value)
 {
     //Parse value
     switch (key)
     {
         case "namespace":
             message.OptionNamespace = value;
             break;
         case "access":
             message.OptionAccess = value;
             break;
         case "type":
             message.OptionType = value;
             break;
         case "buffer":
             message.BufferSize = int.Parse(value);
             break;
         default:
             throw new NotImplementedException("Unknown option: " + key);
     }
 }
        /// <summary>
        /// Detect field which have the same name as a submessage in the same message.
        /// </summary>
        /// <param name="m">Parent message</param>
        /// <param name="f">Field to check</param>
        void DetectNameClash(ProtoMessage m, Field f)
        {
            bool nameclash = false;
            if (m.CsType == f.CsName)
                nameclash = true;
            foreach (var tm in m.Messages.Values)
                if (tm.CsType == f.CsName)
                    nameclash = true;
            foreach (var te in m.Enums.Values)
                if (te.CsType == f.CsName)
                    nameclash = true;
            foreach (var tf in m.Fields.Values)
            {
                if (tf == f)
                    continue;
                if (tf.CsName == f.CsName)
                    nameclash = true;
            }
            if (nameclash == false)
                return;

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


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

                //Make sure our change did not result in another name collission
                DetectNameClash(m, f);
            }
            else
                throw new ProtoFormatException("The field: " + m.FullCsType + "." + f.CsName +
                    " has the same name as a sibling class/enum type which is not allowed in C#. " +
                    "Use --fix-nameclash to automatically rename the field.", f.Source);
        }
        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;
        }
        static ProtoType SearchSubMessages(ProtoMessage msg, string fullPath)
        {
            foreach (ProtoMessage sub in msg.Messages.Values)
            {
                if (fullPath == sub.FullProtoName)
                    return sub;

                if (fullPath.StartsWith(sub.FullProtoName + "."))
                {
                    ProtoType pt = SearchSubMessages(sub, fullPath);
                    if (pt != null)
                        return pt;
                }
            }

            foreach (ProtoEnum subEnum in msg.Enums.Values)
            {
                if (fullPath == subEnum.FullProtoName)
                    return subEnum;
            }

            return null;
        }
        /// <summary>
        /// Search for message in hierarchy
        /// </summary>
        public static ProtoType GetProtoType(ProtoMessage msg, string path)
        {
            //Search for message or enum
            ProtoType pt;

            //Search from one level up until a match is found
            while (msg is ProtoCollection == false)
            {
                //Search sub messages
                pt = SearchSubMessages(msg, msg.Package + "." + msg.ProtoName + "." + path);
                if (pt != null)
                    return pt;

                //Search siblings
                pt = SearchSubMessages(msg.Parent, msg.Package + "." + path);
                if (pt != null)
                    return pt;

                msg = msg.Parent;
            }

            //Finally search for global namespace
            return SearchSubMessages(msg, path);
        }
        void GenerateCtorForDefaults(ProtoMessage m)
        {
            // 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.FormatDefaultForTypeAssignment();
                    string line = string.Format("{0} = {1};", field.CsName, formattedValue);
                    cw.WriteLine(line);
                }
                cw.EndBracket();
            }
        }
Exemple #17
0
        static void ParseMessage(TokenReader tr, ProtoMessage parent, string package)
        {
            var msg = new ProtoMessage(parent, package);
            LocalParser.ParseComments(msg, lastComment, tr);
            msg.ProtoName = tr.ReadNext();

            tr.ReadNextOrThrow("{");

            try
            {
                while (ParseField(tr, msg))
                    continue;
            }
            catch (Exception e)
            {
                throw new ProtoFormatException(e.Message, e, tr);
            }

            parent.Messages.Add(msg.ProtoName, msg);
        }
Exemple #18
0
        static bool ParseField(TokenReader tr, ProtoMessage m)
        {
            string rule = tr.ReadNext();
            while (true)
            {
                if (ParseComment(rule) == false)
                    break;
                rule = tr.ReadNext();
            }

            Field f = new Field(tr);

            //Rule
            switch (rule)
            {
                case ";":
                    lastComment.Clear();
                    return true;
                case "}":
                    lastComment.Clear();
                    return false;
                case "required":
                    f.Rule = FieldRule.Required;
                    break;
                case "optional":
                    f.Rule = FieldRule.Optional;
                    break;
                case "repeated":
                    f.Rule = FieldRule.Repeated;
                    break;
                case "option":
                    //Save options
                    ParseOption(tr, m);
                    return true;
                case "message":
                    ParseMessage(tr, m, m.Package + "." + m.ProtoName);
                    return true;
                case "enum":
                    ParseEnum(tr, m, m.Package + "." + m.ProtoName);
                    return true;
                case "extensions":
                    ParseExtensions(tr, m);
                    return true;
                default:
                    throw new ProtoFormatException("unknown rule: " + rule, tr);
            }

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

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

            //Name
            f.ProtoName = tr.ReadNext();

            //ID
            tr.ReadNextOrThrow("=");
            f.ID = int.Parse(tr.ReadNext());
            if (19000 <= f.ID && f.ID <= 19999)
                throw new ProtoFormatException("Can't use reserved field ID 19000-19999", tr);
            if (f.ID > (1 << 29) - 1)
                throw new ProtoFormatException("Maximum field id is 2^29 - 1", tr);

            //Add Field to message
            m.Fields.Add(f.ID, f);

            //Determine if extra options
            string extra = tr.ReadNext();
            if (extra == ";")
                return true;

            //Field options
            if (extra != "[")
                throw new ProtoFormatException("Expected: [ got " + extra, tr);

            ParseFieldOptions(tr, f);
            return true;
        }
Exemple #19
0
 static void ParseExtensions(TokenReader tr, ProtoMessage m)
 {
     //extensions 100 to max;
     tr.ReadNext(); //100
     tr.ReadNextOrThrow("to");
     tr.ReadNext(); //number or max
     tr.ReadNextOrThrow(";");
 }
        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)
                    {
                        //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)
                    {
                        if (f.ProtoType is ProtoEnum)
                            cw.WriteLine("instance." + f.CsName + " = " + f.ProtoType.FullCsType + "." + 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("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 InvalidOperationException(\"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 InvalidDataException(\"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;
        }
        /// <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);");

            //Shared memorystream for all fields
            cw.Using("var msField = new MemoryStream(" + m.MaxFieldBufferSize() + ")");

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

            cw.EndBracket();

            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();
        }
        /// <summary>
        /// Generates code for writing a class/message
        /// </summary>
        private void GenerateWriter(ProtoMessage m)
        {
            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.Using("var bw = new BinaryWriter(stream, Encoding.UTF8, true)");
            //Shared memorystream for all fields
            cw.WriteLine("var msField = " + stack + ".Pop();");

            foreach (Field f in m.Fields.Values)
            {
                if (f.OptionDeprecated)
                    cw.WritePragma("warning disable 612");

                fieldSerializer.FieldWriter(m, f, cw, options);

                if (f.OptionDeprecated)
                    cw.WritePragma("warning restore 612");
            }

            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();
            }
            if (m.IsUsingBinaryWriter)
                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();
        }
        /// <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();
        }
Exemple #24
0
 public ProtoMessage(ProtoMessage parent, string package)
     : base(parent, package)
 {
     this.OptionType = "class";
 }
Exemple #25
0
 void GenerateEnums(ProtoMessage m)
 {
     foreach (ProtoEnum me in m.Enums.Values)
     {
         GenerateEnum(me);
     }
 }
        /// <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);
        }
Exemple #27
0
        /// <summary>
        /// File or Message options
        /// </summary>
        static void ParseOption(TokenReader tr, ProtoMessage m)
        {
            //Read name
            string key = tr.ReadNext();
            if (tr.ReadNext() != "=")
                throw new ProtoFormatException("Expected: = got " + tr.NextCharacter, tr);
            //Read value
            string value = tr.ReadNext();
            if (tr.ReadNext() != ";")
                throw new ProtoFormatException("Expected: ; got " + tr.NextCharacter, tr);

            //null = ignore option
            if (m == null)
                return;

            switch (key)
            {
                //None at the moment
                //case "namespace":
                //    m.OptionNamespace = value;
                //    break;
                default:
                    Console.WriteLine("Warning: Unknown option: " + key + " = " + value);
                    break;
            }
        }
Exemple #28
0
 public ProtoEnum(ProtoMessage parent, string package)
     : base(parent, package)
 {
 }
        /// <summary>
        /// Prepare: ProtoType, WireType and CSType
        /// </summary>
        void PrepareProtoType(ProtoMessage m, Field f)
        {
            //Change property name to C# style, CamelCase.
            f.CsName = GetCSPropertyName(m, f.ProtoName);

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

            if (f.OptionPacked)
            {
                if (f.ProtoType.WireType == Wire.LengthDelimited)
                    throw new ProtoFormatException("Length delimited types cannot be packed", f.Source);
            }
        }
        /// <summary>
        /// Gets the C# CamelCase version of a given name.
        /// Name collisions with enums are avoided.
        /// </summary>
        string GetCSPropertyName(ProtoMessage m, string name)
        {
            string csname = GetCamelCase(name);

            foreach (ProtoEnum me in m.Enums.Values)
                if (me.CsType == csname)
                    return name;

            return csname;
        }