using System; using System.IO; using System.Xml; using System.Text; namespace Google.ProtocolBuffers.Serialization.Http { /// /// Extensions and helpers to abstract the reading/writing of messages by a client-specified content type. /// public static class MessageFormatFactory { /// /// Constructs an ICodedInputStream from the input stream based on the contentType provided /// /// Options specific to reading this message and/or content type /// The mime type of the input stream content /// The stream to read the message from /// The ICodedInputStream that can be given to the IBuilder.MergeFrom(...) method public static ICodedInputStream CreateInputStream(MessageFormatOptions options, string contentType, Stream input) { FormatType inputType = ContentTypeToFormat(contentType, options.DefaultContentType); ICodedInputStream codedInput; if (inputType == FormatType.ProtoBuffer) { codedInput = CodedInputStream.CreateInstance(input); } else if (inputType == FormatType.Json) { JsonFormatReader reader = JsonFormatReader.CreateInstance(input); codedInput = reader; } else if (inputType == FormatType.Xml) { XmlFormatReader reader = XmlFormatReader.CreateInstance(input); reader.RootElementName = options.XmlReaderRootElementName; reader.Options = options.XmlReaderOptions; codedInput = reader; } else throw new NotSupportedException(); return codedInput; } /// /// Merges the message from the input stream based on the contentType provided /// /// A type derived from IBuilderLite /// An instance of a message builder /// Options specific to reading this message and/or content type /// The mime type of the input stream content /// The stream to read the message from /// The same builder instance that was supplied in the builder parameter public static TBuilder MergeFrom(this TBuilder builder, MessageFormatOptions options, string contentType, Stream input) where TBuilder : IBuilderLite { ICodedInputStream codedInput = CreateInputStream(options, contentType, input); codedInput.ReadMessageStart(); return (TBuilder)builder.WeakMergeFrom(codedInput, options.ExtensionRegistry); } /// /// Writes the message instance to the stream using the content type provided /// /// Options specific to writing this message and/or content type /// The mime type of the content to be written /// The stream to write the message to /// If you do not dispose of ICodedOutputStream some formats may yield incomplete output public static ICodedOutputStream CreateOutputStream(MessageFormatOptions options, string contentType, Stream output) { FormatType outputType = ContentTypeToFormat(contentType, options.DefaultContentType); ICodedOutputStream codedOutput; if (outputType == FormatType.ProtoBuffer) { codedOutput = CodedOutputStream.CreateInstance(output); } else if (outputType == FormatType.Json) { JsonFormatWriter writer = JsonFormatWriter.CreateInstance(output); if (options.FormattedOutput) { writer.Formatted(); } codedOutput = writer; } else if (outputType == FormatType.Xml) { XmlFormatWriter writer; if (!options.FormattedOutput) { writer = XmlFormatWriter.CreateInstance(output); } else { XmlWriterSettings settings = new XmlWriterSettings() { CheckCharacters = false, NewLineHandling = NewLineHandling.Entitize, OmitXmlDeclaration = true, Encoding = new UTF8Encoding(false), Indent = true, IndentChars = " ", NewLineChars = Environment.NewLine, }; writer = XmlFormatWriter.CreateInstance(XmlWriter.Create(output, settings)); } writer.RootElementName = options.XmlWriterRootElementName; writer.Options = options.XmlWriterOptions; codedOutput = writer; } else throw new NotSupportedException(); return codedOutput; } /// /// Writes the message instance to the stream using the content type provided /// /// An instance of a message /// Options specific to writing this message and/or content type /// The mime type of the content to be written /// The stream to write the message to public static void WriteTo(this IMessageLite message, MessageFormatOptions options, string contentType, Stream output) { ICodedOutputStream codedOutput = CreateOutputStream(options, contentType, output); // Output the appropriate message preamble codedOutput.WriteMessageStart(); // Write the message content to the output message.WriteTo(codedOutput); // Write the closing message fragment codedOutput.WriteMessageEnd(); } enum FormatType { ProtoBuffer, Json, Xml }; private static FormatType ContentTypeToFormat(string contentType, string defaultType) { switch ((contentType ?? String.Empty).Split(';')[0].Trim().ToLower()) { case "application/json": case "application/x-json": case "application/x-javascript": case "text/javascript": case "text/x-javascript": case "text/x-json": case "text/json": { return FormatType.Json; } case "text/xml": case "application/xml": { return FormatType.Xml; } case "application/binary": case "application/x-protobuf": case "application/vnd.google.protobuf": { return FormatType.ProtoBuffer; } case "": case null: if (!String.IsNullOrEmpty(defaultType)) { return ContentTypeToFormat(defaultType, null); } break; } throw new ArgumentOutOfRangeException("contentType"); } } }