1ffe3c632Sopenharmony_ci#region Copyright notice and license 2ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format 3ffe3c632Sopenharmony_ci// Copyright 2015 Google Inc. All rights reserved. 4ffe3c632Sopenharmony_ci// https://developers.google.com/protocol-buffers/ 5ffe3c632Sopenharmony_ci// 6ffe3c632Sopenharmony_ci// Redistribution and use in source and binary forms, with or without 7ffe3c632Sopenharmony_ci// modification, are permitted provided that the following conditions are 8ffe3c632Sopenharmony_ci// met: 9ffe3c632Sopenharmony_ci// 10ffe3c632Sopenharmony_ci// * Redistributions of source code must retain the above copyright 11ffe3c632Sopenharmony_ci// notice, this list of conditions and the following disclaimer. 12ffe3c632Sopenharmony_ci// * Redistributions in binary form must reproduce the above 13ffe3c632Sopenharmony_ci// copyright notice, this list of conditions and the following disclaimer 14ffe3c632Sopenharmony_ci// in the documentation and/or other materials provided with the 15ffe3c632Sopenharmony_ci// distribution. 16ffe3c632Sopenharmony_ci// * Neither the name of Google Inc. nor the names of its 17ffe3c632Sopenharmony_ci// contributors may be used to endorse or promote products derived from 18ffe3c632Sopenharmony_ci// this software without specific prior written permission. 19ffe3c632Sopenharmony_ci// 20ffe3c632Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21ffe3c632Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22ffe3c632Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23ffe3c632Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24ffe3c632Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25ffe3c632Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26ffe3c632Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27ffe3c632Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28ffe3c632Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29ffe3c632Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30ffe3c632Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31ffe3c632Sopenharmony_ci#endregion 32ffe3c632Sopenharmony_ci 33ffe3c632Sopenharmony_ciusing Google.Protobuf.Reflection; 34ffe3c632Sopenharmony_ciusing System.Buffers; 35ffe3c632Sopenharmony_ciusing System.Collections; 36ffe3c632Sopenharmony_ciusing System; 37ffe3c632Sopenharmony_ciusing System.IO; 38ffe3c632Sopenharmony_ciusing System.Linq; 39ffe3c632Sopenharmony_ciusing System.Security; 40ffe3c632Sopenharmony_ci 41ffe3c632Sopenharmony_cinamespace Google.Protobuf 42ffe3c632Sopenharmony_ci{ 43ffe3c632Sopenharmony_ci /// <summary> 44ffe3c632Sopenharmony_ci /// Extension methods on <see cref="IMessage"/> and <see cref="IMessage{T}"/>. 45ffe3c632Sopenharmony_ci /// </summary> 46ffe3c632Sopenharmony_ci public static class MessageExtensions 47ffe3c632Sopenharmony_ci { 48ffe3c632Sopenharmony_ci /// <summary> 49ffe3c632Sopenharmony_ci /// Merges data from the given byte array into an existing message. 50ffe3c632Sopenharmony_ci /// </summary> 51ffe3c632Sopenharmony_ci /// <param name="message">The message to merge the data into.</param> 52ffe3c632Sopenharmony_ci /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param> 53ffe3c632Sopenharmony_ci public static void MergeFrom(this IMessage message, byte[] data) => 54ffe3c632Sopenharmony_ci MergeFrom(message, data, false, null); 55ffe3c632Sopenharmony_ci 56ffe3c632Sopenharmony_ci /// <summary> 57ffe3c632Sopenharmony_ci /// Merges data from the given byte array slice into an existing message. 58ffe3c632Sopenharmony_ci /// </summary> 59ffe3c632Sopenharmony_ci /// <param name="message">The message to merge the data into.</param> 60ffe3c632Sopenharmony_ci /// <param name="data">The data containing the slice to merge, which must be protobuf-encoded binary data.</param> 61ffe3c632Sopenharmony_ci /// <param name="offset">The offset of the slice to merge.</param> 62ffe3c632Sopenharmony_ci /// <param name="length">The length of the slice to merge.</param> 63ffe3c632Sopenharmony_ci public static void MergeFrom(this IMessage message, byte[] data, int offset, int length) => 64ffe3c632Sopenharmony_ci MergeFrom(message, data, offset, length, false, null); 65ffe3c632Sopenharmony_ci 66ffe3c632Sopenharmony_ci /// <summary> 67ffe3c632Sopenharmony_ci /// Merges data from the given byte string into an existing message. 68ffe3c632Sopenharmony_ci /// </summary> 69ffe3c632Sopenharmony_ci /// <param name="message">The message to merge the data into.</param> 70ffe3c632Sopenharmony_ci /// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param> 71ffe3c632Sopenharmony_ci public static void MergeFrom(this IMessage message, ByteString data) => 72ffe3c632Sopenharmony_ci MergeFrom(message, data, false, null); 73ffe3c632Sopenharmony_ci 74ffe3c632Sopenharmony_ci /// <summary> 75ffe3c632Sopenharmony_ci /// Merges data from the given stream into an existing message. 76ffe3c632Sopenharmony_ci /// </summary> 77ffe3c632Sopenharmony_ci /// <param name="message">The message to merge the data into.</param> 78ffe3c632Sopenharmony_ci /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param> 79ffe3c632Sopenharmony_ci public static void MergeFrom(this IMessage message, Stream input) => 80ffe3c632Sopenharmony_ci MergeFrom(message, input, false, null); 81ffe3c632Sopenharmony_ci 82ffe3c632Sopenharmony_ci /// <summary> 83ffe3c632Sopenharmony_ci /// Merges length-delimited data from the given stream into an existing message. 84ffe3c632Sopenharmony_ci /// </summary> 85ffe3c632Sopenharmony_ci /// <remarks> 86ffe3c632Sopenharmony_ci /// The stream is expected to contain a length and then the data. Only the amount of data 87ffe3c632Sopenharmony_ci /// specified by the length will be consumed. 88ffe3c632Sopenharmony_ci /// </remarks> 89ffe3c632Sopenharmony_ci /// <param name="message">The message to merge the data into.</param> 90ffe3c632Sopenharmony_ci /// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param> 91ffe3c632Sopenharmony_ci public static void MergeDelimitedFrom(this IMessage message, Stream input) => 92ffe3c632Sopenharmony_ci MergeDelimitedFrom(message, input, false, null); 93ffe3c632Sopenharmony_ci 94ffe3c632Sopenharmony_ci /// <summary> 95ffe3c632Sopenharmony_ci /// Converts the given message into a byte array in protobuf encoding. 96ffe3c632Sopenharmony_ci /// </summary> 97ffe3c632Sopenharmony_ci /// <param name="message">The message to convert.</param> 98ffe3c632Sopenharmony_ci /// <returns>The message data as a byte array.</returns> 99ffe3c632Sopenharmony_ci public static byte[] ToByteArray(this IMessage message) 100ffe3c632Sopenharmony_ci { 101ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 102ffe3c632Sopenharmony_ci byte[] result = new byte[message.CalculateSize()]; 103ffe3c632Sopenharmony_ci CodedOutputStream output = new CodedOutputStream(result); 104ffe3c632Sopenharmony_ci message.WriteTo(output); 105ffe3c632Sopenharmony_ci output.CheckNoSpaceLeft(); 106ffe3c632Sopenharmony_ci return result; 107ffe3c632Sopenharmony_ci } 108ffe3c632Sopenharmony_ci 109ffe3c632Sopenharmony_ci /// <summary> 110ffe3c632Sopenharmony_ci /// Writes the given message data to the given stream in protobuf encoding. 111ffe3c632Sopenharmony_ci /// </summary> 112ffe3c632Sopenharmony_ci /// <param name="message">The message to write to the stream.</param> 113ffe3c632Sopenharmony_ci /// <param name="output">The stream to write to.</param> 114ffe3c632Sopenharmony_ci public static void WriteTo(this IMessage message, Stream output) 115ffe3c632Sopenharmony_ci { 116ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 117ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(output, "output"); 118ffe3c632Sopenharmony_ci CodedOutputStream codedOutput = new CodedOutputStream(output); 119ffe3c632Sopenharmony_ci message.WriteTo(codedOutput); 120ffe3c632Sopenharmony_ci codedOutput.Flush(); 121ffe3c632Sopenharmony_ci } 122ffe3c632Sopenharmony_ci 123ffe3c632Sopenharmony_ci /// <summary> 124ffe3c632Sopenharmony_ci /// Writes the length and then data of the given message to a stream. 125ffe3c632Sopenharmony_ci /// </summary> 126ffe3c632Sopenharmony_ci /// <param name="message">The message to write.</param> 127ffe3c632Sopenharmony_ci /// <param name="output">The output stream to write to.</param> 128ffe3c632Sopenharmony_ci public static void WriteDelimitedTo(this IMessage message, Stream output) 129ffe3c632Sopenharmony_ci { 130ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 131ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(output, "output"); 132ffe3c632Sopenharmony_ci CodedOutputStream codedOutput = new CodedOutputStream(output); 133ffe3c632Sopenharmony_ci codedOutput.WriteLength(message.CalculateSize()); 134ffe3c632Sopenharmony_ci message.WriteTo(codedOutput); 135ffe3c632Sopenharmony_ci codedOutput.Flush(); 136ffe3c632Sopenharmony_ci } 137ffe3c632Sopenharmony_ci 138ffe3c632Sopenharmony_ci /// <summary> 139ffe3c632Sopenharmony_ci /// Converts the given message into a byte string in protobuf encoding. 140ffe3c632Sopenharmony_ci /// </summary> 141ffe3c632Sopenharmony_ci /// <param name="message">The message to convert.</param> 142ffe3c632Sopenharmony_ci /// <returns>The message data as a byte string.</returns> 143ffe3c632Sopenharmony_ci public static ByteString ToByteString(this IMessage message) 144ffe3c632Sopenharmony_ci { 145ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 146ffe3c632Sopenharmony_ci return ByteString.AttachBytes(message.ToByteArray()); 147ffe3c632Sopenharmony_ci } 148ffe3c632Sopenharmony_ci 149ffe3c632Sopenharmony_ci /// <summary> 150ffe3c632Sopenharmony_ci /// Writes the given message data to the given buffer writer in protobuf encoding. 151ffe3c632Sopenharmony_ci /// </summary> 152ffe3c632Sopenharmony_ci /// <param name="message">The message to write to the stream.</param> 153ffe3c632Sopenharmony_ci /// <param name="output">The stream to write to.</param> 154ffe3c632Sopenharmony_ci [SecuritySafeCritical] 155ffe3c632Sopenharmony_ci public static void WriteTo(this IMessage message, IBufferWriter<byte> output) 156ffe3c632Sopenharmony_ci { 157ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, nameof(message)); 158ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(output, nameof(output)); 159ffe3c632Sopenharmony_ci 160ffe3c632Sopenharmony_ci WriteContext.Initialize(output, out WriteContext ctx); 161ffe3c632Sopenharmony_ci WritingPrimitivesMessages.WriteRawMessage(ref ctx, message); 162ffe3c632Sopenharmony_ci ctx.Flush(); 163ffe3c632Sopenharmony_ci } 164ffe3c632Sopenharmony_ci 165ffe3c632Sopenharmony_ci /// <summary> 166ffe3c632Sopenharmony_ci /// Writes the given message data to the given span in protobuf encoding. 167ffe3c632Sopenharmony_ci /// The size of the destination span needs to fit the serialized size 168ffe3c632Sopenharmony_ci /// of the message exactly, otherwise an exception is thrown. 169ffe3c632Sopenharmony_ci /// </summary> 170ffe3c632Sopenharmony_ci /// <param name="message">The message to write to the stream.</param> 171ffe3c632Sopenharmony_ci /// <param name="output">The span to write to. Size must match size of the message exactly.</param> 172ffe3c632Sopenharmony_ci [SecuritySafeCritical] 173ffe3c632Sopenharmony_ci public static void WriteTo(this IMessage message, Span<byte> output) 174ffe3c632Sopenharmony_ci { 175ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, nameof(message)); 176ffe3c632Sopenharmony_ci 177ffe3c632Sopenharmony_ci WriteContext.Initialize(ref output, out WriteContext ctx); 178ffe3c632Sopenharmony_ci WritingPrimitivesMessages.WriteRawMessage(ref ctx, message); 179ffe3c632Sopenharmony_ci ctx.CheckNoSpaceLeft(); 180ffe3c632Sopenharmony_ci } 181ffe3c632Sopenharmony_ci 182ffe3c632Sopenharmony_ci /// <summary> 183ffe3c632Sopenharmony_ci /// Checks if all required fields in a message have values set. For proto3 messages, this returns true 184ffe3c632Sopenharmony_ci /// </summary> 185ffe3c632Sopenharmony_ci public static bool IsInitialized(this IMessage message) 186ffe3c632Sopenharmony_ci { 187ffe3c632Sopenharmony_ci if (message.Descriptor.File.Syntax == Syntax.Proto3) 188ffe3c632Sopenharmony_ci { 189ffe3c632Sopenharmony_ci return true; 190ffe3c632Sopenharmony_ci } 191ffe3c632Sopenharmony_ci 192ffe3c632Sopenharmony_ci if (!message.Descriptor.IsExtensionsInitialized(message)) 193ffe3c632Sopenharmony_ci { 194ffe3c632Sopenharmony_ci return false; 195ffe3c632Sopenharmony_ci } 196ffe3c632Sopenharmony_ci 197ffe3c632Sopenharmony_ci return message.Descriptor 198ffe3c632Sopenharmony_ci .Fields 199ffe3c632Sopenharmony_ci .InDeclarationOrder() 200ffe3c632Sopenharmony_ci .All(f => 201ffe3c632Sopenharmony_ci { 202ffe3c632Sopenharmony_ci if (f.IsMap) 203ffe3c632Sopenharmony_ci { 204ffe3c632Sopenharmony_ci var valueField = f.MessageType.Fields[2]; 205ffe3c632Sopenharmony_ci if (valueField.FieldType == FieldType.Message) 206ffe3c632Sopenharmony_ci { 207ffe3c632Sopenharmony_ci var map = (IDictionary)f.Accessor.GetValue(message); 208ffe3c632Sopenharmony_ci return map.Values.Cast<IMessage>().All(IsInitialized); 209ffe3c632Sopenharmony_ci } 210ffe3c632Sopenharmony_ci else 211ffe3c632Sopenharmony_ci { 212ffe3c632Sopenharmony_ci return true; 213ffe3c632Sopenharmony_ci } 214ffe3c632Sopenharmony_ci } 215ffe3c632Sopenharmony_ci else if (f.IsRepeated && f.FieldType == FieldType.Message || f.FieldType == FieldType.Group) 216ffe3c632Sopenharmony_ci { 217ffe3c632Sopenharmony_ci var enumerable = (IEnumerable)f.Accessor.GetValue(message); 218ffe3c632Sopenharmony_ci return enumerable.Cast<IMessage>().All(IsInitialized); 219ffe3c632Sopenharmony_ci } 220ffe3c632Sopenharmony_ci else if (f.FieldType == FieldType.Message || f.FieldType == FieldType.Group) 221ffe3c632Sopenharmony_ci { 222ffe3c632Sopenharmony_ci if (f.Accessor.HasValue(message)) 223ffe3c632Sopenharmony_ci { 224ffe3c632Sopenharmony_ci return ((IMessage)f.Accessor.GetValue(message)).IsInitialized(); 225ffe3c632Sopenharmony_ci } 226ffe3c632Sopenharmony_ci else 227ffe3c632Sopenharmony_ci { 228ffe3c632Sopenharmony_ci return !f.IsRequired; 229ffe3c632Sopenharmony_ci } 230ffe3c632Sopenharmony_ci } 231ffe3c632Sopenharmony_ci else if (f.IsRequired) 232ffe3c632Sopenharmony_ci { 233ffe3c632Sopenharmony_ci return f.Accessor.HasValue(message); 234ffe3c632Sopenharmony_ci } 235ffe3c632Sopenharmony_ci else 236ffe3c632Sopenharmony_ci { 237ffe3c632Sopenharmony_ci return true; 238ffe3c632Sopenharmony_ci } 239ffe3c632Sopenharmony_ci }); 240ffe3c632Sopenharmony_ci } 241ffe3c632Sopenharmony_ci 242ffe3c632Sopenharmony_ci // Implementations allowing unknown fields to be discarded. 243ffe3c632Sopenharmony_ci internal static void MergeFrom(this IMessage message, byte[] data, bool discardUnknownFields, ExtensionRegistry registry) 244ffe3c632Sopenharmony_ci { 245ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 246ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(data, "data"); 247ffe3c632Sopenharmony_ci CodedInputStream input = new CodedInputStream(data); 248ffe3c632Sopenharmony_ci input.DiscardUnknownFields = discardUnknownFields; 249ffe3c632Sopenharmony_ci input.ExtensionRegistry = registry; 250ffe3c632Sopenharmony_ci message.MergeFrom(input); 251ffe3c632Sopenharmony_ci input.CheckReadEndOfStreamTag(); 252ffe3c632Sopenharmony_ci } 253ffe3c632Sopenharmony_ci 254ffe3c632Sopenharmony_ci internal static void MergeFrom(this IMessage message, byte[] data, int offset, int length, bool discardUnknownFields, ExtensionRegistry registry) 255ffe3c632Sopenharmony_ci { 256ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 257ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(data, "data"); 258ffe3c632Sopenharmony_ci CodedInputStream input = new CodedInputStream(data, offset, length); 259ffe3c632Sopenharmony_ci input.DiscardUnknownFields = discardUnknownFields; 260ffe3c632Sopenharmony_ci input.ExtensionRegistry = registry; 261ffe3c632Sopenharmony_ci message.MergeFrom(input); 262ffe3c632Sopenharmony_ci input.CheckReadEndOfStreamTag(); 263ffe3c632Sopenharmony_ci } 264ffe3c632Sopenharmony_ci 265ffe3c632Sopenharmony_ci internal static void MergeFrom(this IMessage message, ByteString data, bool discardUnknownFields, ExtensionRegistry registry) 266ffe3c632Sopenharmony_ci { 267ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 268ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(data, "data"); 269ffe3c632Sopenharmony_ci CodedInputStream input = data.CreateCodedInput(); 270ffe3c632Sopenharmony_ci input.DiscardUnknownFields = discardUnknownFields; 271ffe3c632Sopenharmony_ci input.ExtensionRegistry = registry; 272ffe3c632Sopenharmony_ci message.MergeFrom(input); 273ffe3c632Sopenharmony_ci input.CheckReadEndOfStreamTag(); 274ffe3c632Sopenharmony_ci } 275ffe3c632Sopenharmony_ci 276ffe3c632Sopenharmony_ci internal static void MergeFrom(this IMessage message, Stream input, bool discardUnknownFields, ExtensionRegistry registry) 277ffe3c632Sopenharmony_ci { 278ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 279ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(input, "input"); 280ffe3c632Sopenharmony_ci CodedInputStream codedInput = new CodedInputStream(input); 281ffe3c632Sopenharmony_ci codedInput.DiscardUnknownFields = discardUnknownFields; 282ffe3c632Sopenharmony_ci codedInput.ExtensionRegistry = registry; 283ffe3c632Sopenharmony_ci message.MergeFrom(codedInput); 284ffe3c632Sopenharmony_ci codedInput.CheckReadEndOfStreamTag(); 285ffe3c632Sopenharmony_ci } 286ffe3c632Sopenharmony_ci 287ffe3c632Sopenharmony_ci [SecuritySafeCritical] 288ffe3c632Sopenharmony_ci internal static void MergeFrom(this IMessage message, ReadOnlySequence<byte> data, bool discardUnknownFields, ExtensionRegistry registry) 289ffe3c632Sopenharmony_ci { 290ffe3c632Sopenharmony_ci ParseContext.Initialize(data, out ParseContext ctx); 291ffe3c632Sopenharmony_ci ctx.DiscardUnknownFields = discardUnknownFields; 292ffe3c632Sopenharmony_ci ctx.ExtensionRegistry = registry; 293ffe3c632Sopenharmony_ci ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message); 294ffe3c632Sopenharmony_ci ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref ctx.state); 295ffe3c632Sopenharmony_ci } 296ffe3c632Sopenharmony_ci 297ffe3c632Sopenharmony_ci internal static void MergeDelimitedFrom(this IMessage message, Stream input, bool discardUnknownFields, ExtensionRegistry registry) 298ffe3c632Sopenharmony_ci { 299ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(message, "message"); 300ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(input, "input"); 301ffe3c632Sopenharmony_ci int size = (int) CodedInputStream.ReadRawVarint32(input); 302ffe3c632Sopenharmony_ci Stream limitedStream = new LimitedInputStream(input, size); 303ffe3c632Sopenharmony_ci MergeFrom(message, limitedStream, discardUnknownFields, registry); 304ffe3c632Sopenharmony_ci } 305ffe3c632Sopenharmony_ci } 306ffe3c632Sopenharmony_ci} 307