示例#1
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);
        }
        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;
        }
示例#3
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;
        }
示例#4
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;
        }
示例#5
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);
        }
示例#6
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;
        }
示例#7
0
        void GenerateReader(ProtoMessage m)
        {
            string mTableParamDefs, mTableParams;

            FindMessageTableParams(m, out mTableParamDefs, out mTableParams);

            #region Helper Deserialize Methods
            string refstr = (m.OptionType == "struct") ? "ref " : "";
            if (m.OptionType != "interface")
            {
                if (!m.OptionNoInstancing)
                {
                    cw.Summary("Helper: create a new instance to deserializing into");
                    cw.Bracket(m.OptionAccess + " static " + m.CsType + " Deserialize(Stream stream" + mTableParamDefs + ")");
                    cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                    cw.WriteLine("Deserialize(stream" + mTableParams + ", " + 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" + mTableParamDefs + ")");
                    cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                    cw.WriteLine("DeserializeLengthDelimited(stream" + mTableParams + ", " + 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" + mTableParamDefs + ", int length)");
                    cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                    cw.WriteLine("DeserializeLength(stream" + mTableParams + ", 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" + mTableParamDefs + ")");
                    cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                    cw.WriteLine("using (var ms = new MemoryStream(buffer))");
                    cw.WriteIndent("Deserialize(ms" + mTableParams + ", " + refstr + "instance);");
                    cw.WriteLine("return instance;");
                    cw.EndBracketSpace();

                    cw.Summary("Helper: create a new instance when deserializing a JObject");
                    cw.Bracket(m.OptionAccess + " static " + m.CsType + " Deserialize(global::Newtonsoft.Json.Linq.JObject obj" + mTableParamDefs + ")");
                    cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                    cw.WriteLine("Deserialize(obj" + mTableParams + ", " + refstr + "instance);");
                    cw.WriteLine("return instance;");
                    cw.EndBracketSpace();

                    cw.Summary("Helper: create a new instance and deserialize JSON from a string");
                    cw.Bracket(m.OptionAccess + " static " + m.CsType + " Deserialize(string json" + mTableParamDefs + ")");
                    cw.WriteLine(m.CsType + " instance = new " + m.CsType + "();");
                    cw.WriteLine("Deserialize(global::Newtonsoft.Json.Linq.JObject.Parse(json)" + mTableParams + ", " + refstr + "instance);");
                    cw.WriteLine("return instance;");
                    cw.EndBracketSpace();
                }

                if (!m.OptionNoPartials)
                {
                    cw.Summary("Load this value from a proto buffer");
                    cw.Bracket(m.OptionAccess + " void FromProto(Stream stream" + mTableParamDefs + ")");
                    cw.WriteLine("Deserialize(stream" + mTableParams + ", this );");
                    cw.EndBracketSpace();

                    cw.Summary("Load this value from a json object");
                    cw.Bracket(m.OptionAccess + " void FromJson(global::Newtonsoft.Json.Linq.JObject obj" + mTableParamDefs + ")");
                    cw.WriteLine("Deserialize(obj" + mTableParams + ", this );");
                    cw.EndBracketSpace();
                }
            }

            cw.Summary("Helper: put the buffer into a MemoryStream before deserializing");
            cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " Deserialize(byte[] buffer" + mTableParamDefs + ", " + refstr + m.FullCsType + " instance)");
            cw.WriteLine("using (var ms = new MemoryStream(buffer))");
            cw.WriteIndent("Deserialize(ms" + mTableParams + ", " + 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" + mTableParamDefs + ", " + 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" + mTableParamDefs + ", " + 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" + mTableParamDefs + ", int length, " + refstr + m.FullCsType + " instance)");
                }
                else
                {
                    throw new NotImplementedException();
                }

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

                GenerateDefaults(m);

                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, m.RequiredMessageTables))
                        {
                            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, m.RequiredMessageTables))
                    {
                        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();
            }

            //JSON deserialize
            cw.Summary("Deserializes an instance from a JSON object.");
            cw.Bracket(m.OptionAccess + " static " + m.FullCsType + " Deserialize(global::Newtonsoft.Json.Linq.JObject obj" + mTableParamDefs + ", " + refstr + m.FullCsType + " instance)");

            GenerateDefaults(m);

            cw.WriteLine();
            cw.Bracket("foreach (var property in obj.Properties())");
            cw.Switch("property.Name");

            foreach (var f in m.Fields.Values)
            {
                cw.Case("\"" + f.CsName + "\"");
                fieldSerializer.JsonFieldReader(f, m.RequiredMessageTables, "property.Value");
                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;
        }