123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- using System;
- using System.IO;
- using System.Xml;
- using System.Text;
- namespace Google.ProtocolBuffers.Serialization
- {
- /// <summary>
- /// Extensions and helpers to abstract the reading/writing of messages by a client-specified content type.
- /// </summary>
- public static class MessageFormatFactory
- {
- /// <summary>
- /// Constructs an ICodedInputStream from the input stream based on the contentType provided
- /// </summary>
- /// <param name="options">Options specific to reading this message and/or content type</param>
- /// <param name="contentType">The mime type of the input stream content</param>
- /// <param name="input">The stream to read the message from</param>
- /// <returns>The ICodedInputStream that can be given to the IBuilder.MergeFrom(...) method</returns>
- 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.ReadStartMessage();
- }
- else if (inputType == FormatType.Xml)
- {
- XmlFormatReader reader = XmlFormatReader.CreateInstance(input);
- reader.RootElementName = options.XmlReaderRootElementName;
- reader.Options = options.XmlReaderOptions;
- codedInput = reader.ReadStartMessage();
- }
- else
- throw new NotSupportedException();
- return codedInput;
- }
- /// <summary>
- /// Merges the message from the input stream based on the contentType provided
- /// </summary>
- /// <typeparam name="TBuilder">A type derived from IBuilderLite</typeparam>
- /// <param name="builder">An instance of a message builder</param>
- /// <param name="options">Options specific to reading this message and/or content type</param>
- /// <param name="contentType">The mime type of the input stream content</param>
- /// <param name="input">The stream to read the message from</param>
- /// <returns>The same builder instance that was supplied in the builder parameter</returns>
- public static TBuilder MergeFrom<TBuilder>(this TBuilder builder, MessageFormatOptions options, string contentType, Stream input) where TBuilder : IBuilderLite
- {
- ICodedInputStream codedInput = CreateInputStream(options, contentType, input);
- return (TBuilder)builder.WeakMergeFrom(codedInput, options.ExtensionRegistry);
- }
-
- /// <summary>
- /// Writes the message instance to the stream using the content type provided
- /// </summary>
- /// <param name="options">Options specific to writing this message and/or content type</param>
- /// <param name="contentType">The mime type of the content to be written</param>
- /// <param name="output">The stream to write the message to</param>
- /// <remarks> If you do not dispose of ICodedOutputStream some formats may yield incomplete output </remarks>
- 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();
- }
- writer.StartMessage();
- 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 = Encoding.UTF8,
- Indent = true,
- IndentChars = " ",
- NewLineChars = Environment.NewLine,
- };
- writer = XmlFormatWriter.CreateInstance(XmlWriter.Create(output, settings));
- }
- writer.RootElementName = options.XmlWriterRootElementName;
- writer.Options = options.XmlWriterOptions;
- writer.StartMessage();
- codedOutput = writer;
- }
- else
- throw new NotSupportedException();
- return codedOutput;
- }
- /// <summary>
- /// Writes the message instance to the stream using the content type provided
- /// </summary>
- /// <param name="message">An instance of a message</param>
- /// <param name="options">Options specific to writing this message and/or content type</param>
- /// <param name="contentType">The mime type of the content to be written</param>
- /// <param name="output">The stream to write the message to</param>
- public static void WriteTo(this IMessageLite message, MessageFormatOptions options, string contentType, Stream output)
- {
- using (ICodedOutputStream codedOutput = CreateOutputStream(options, contentType, output))
- {
- message.WriteTo(codedOutput);
- // This is effectivly done by Dispose(); however, if you need to finalize a message
- // without disposing the underlying stream, this is the only way to do it.
- if (codedOutput is AbstractWriter)
- ((AbstractWriter)codedOutput).EndMessage();
- codedOutput.Flush();
- }
- }
- 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");
- }
- }
- }
|