1ffe3c632Sopenharmony_ci#region Copyright notice and license
2ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format
3ffe3c632Sopenharmony_ci// Copyright 2008 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.Collections;
34ffe3c632Sopenharmony_ciusing System;
35ffe3c632Sopenharmony_ciusing System.IO;
36ffe3c632Sopenharmony_ciusing System.Security;
37ffe3c632Sopenharmony_ciusing System.Text;
38ffe3c632Sopenharmony_ci
39ffe3c632Sopenharmony_cinamespace Google.Protobuf
40ffe3c632Sopenharmony_ci{
41ffe3c632Sopenharmony_ci    /// <summary>
42ffe3c632Sopenharmony_ci    /// Encodes and writes protocol message fields.
43ffe3c632Sopenharmony_ci    /// </summary>
44ffe3c632Sopenharmony_ci    /// <remarks>
45ffe3c632Sopenharmony_ci    /// <para>
46ffe3c632Sopenharmony_ci    /// This class is generally used by generated code to write appropriate
47ffe3c632Sopenharmony_ci    /// primitives to the stream. It effectively encapsulates the lowest
48ffe3c632Sopenharmony_ci    /// levels of protocol buffer format. Unlike some other implementations,
49ffe3c632Sopenharmony_ci    /// this does not include combined "write tag and value" methods. Generated
50ffe3c632Sopenharmony_ci    /// code knows the exact byte representations of the tags they're going to write,
51ffe3c632Sopenharmony_ci    /// so there's no need to re-encode them each time. Manually-written code calling
52ffe3c632Sopenharmony_ci    /// this class should just call one of the <c>WriteTag</c> overloads before each value.
53ffe3c632Sopenharmony_ci    /// </para>
54ffe3c632Sopenharmony_ci    /// <para>
55ffe3c632Sopenharmony_ci    /// Repeated fields and map fields are not handled by this class; use <c>RepeatedField&lt;T&gt;</c>
56ffe3c632Sopenharmony_ci    /// and <c>MapField&lt;TKey, TValue&gt;</c> to serialize such fields.
57ffe3c632Sopenharmony_ci    /// </para>
58ffe3c632Sopenharmony_ci    /// </remarks>
59ffe3c632Sopenharmony_ci    [SecuritySafeCritical]
60ffe3c632Sopenharmony_ci    public sealed partial class CodedOutputStream : IDisposable
61ffe3c632Sopenharmony_ci    {
62ffe3c632Sopenharmony_ci        /// <summary>
63ffe3c632Sopenharmony_ci        /// The buffer size used by CreateInstance(Stream).
64ffe3c632Sopenharmony_ci        /// </summary>
65ffe3c632Sopenharmony_ci        public static readonly int DefaultBufferSize = 4096;
66ffe3c632Sopenharmony_ci
67ffe3c632Sopenharmony_ci        private readonly bool leaveOpen;
68ffe3c632Sopenharmony_ci        private readonly byte[] buffer;
69ffe3c632Sopenharmony_ci        private WriterInternalState state;
70ffe3c632Sopenharmony_ci
71ffe3c632Sopenharmony_ci        private readonly Stream output;
72ffe3c632Sopenharmony_ci
73ffe3c632Sopenharmony_ci        #region Construction
74ffe3c632Sopenharmony_ci        /// <summary>
75ffe3c632Sopenharmony_ci        /// Creates a new CodedOutputStream that writes directly to the given
76ffe3c632Sopenharmony_ci        /// byte array. If more bytes are written than fit in the array,
77ffe3c632Sopenharmony_ci        /// OutOfSpaceException will be thrown.
78ffe3c632Sopenharmony_ci        /// </summary>
79ffe3c632Sopenharmony_ci        public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length)
80ffe3c632Sopenharmony_ci        {
81ffe3c632Sopenharmony_ci        }
82ffe3c632Sopenharmony_ci
83ffe3c632Sopenharmony_ci        /// <summary>
84ffe3c632Sopenharmony_ci        /// Creates a new CodedOutputStream that writes directly to the given
85ffe3c632Sopenharmony_ci        /// byte array slice. If more bytes are written than fit in the array,
86ffe3c632Sopenharmony_ci        /// OutOfSpaceException will be thrown.
87ffe3c632Sopenharmony_ci        /// </summary>
88ffe3c632Sopenharmony_ci        private CodedOutputStream(byte[] buffer, int offset, int length)
89ffe3c632Sopenharmony_ci        {
90ffe3c632Sopenharmony_ci            this.output = null;
91ffe3c632Sopenharmony_ci            this.buffer = ProtoPreconditions.CheckNotNull(buffer, nameof(buffer));
92ffe3c632Sopenharmony_ci            this.state.position = offset;
93ffe3c632Sopenharmony_ci            this.state.limit = offset + length;
94ffe3c632Sopenharmony_ci            WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper);
95ffe3c632Sopenharmony_ci            leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference
96ffe3c632Sopenharmony_ci        }
97ffe3c632Sopenharmony_ci
98ffe3c632Sopenharmony_ci        private CodedOutputStream(Stream output, byte[] buffer, bool leaveOpen)
99ffe3c632Sopenharmony_ci        {
100ffe3c632Sopenharmony_ci            this.output = ProtoPreconditions.CheckNotNull(output, nameof(output));
101ffe3c632Sopenharmony_ci            this.buffer = buffer;
102ffe3c632Sopenharmony_ci            this.state.position = 0;
103ffe3c632Sopenharmony_ci            this.state.limit = buffer.Length;
104ffe3c632Sopenharmony_ci            WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper);
105ffe3c632Sopenharmony_ci            this.leaveOpen = leaveOpen;
106ffe3c632Sopenharmony_ci        }
107ffe3c632Sopenharmony_ci
108ffe3c632Sopenharmony_ci        /// <summary>
109ffe3c632Sopenharmony_ci        /// Creates a new <see cref="CodedOutputStream" /> which write to the given stream, and disposes of that
110ffe3c632Sopenharmony_ci        /// stream when the returned <c>CodedOutputStream</c> is disposed.
111ffe3c632Sopenharmony_ci        /// </summary>
112ffe3c632Sopenharmony_ci        /// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
113ffe3c632Sopenharmony_ci        public CodedOutputStream(Stream output) : this(output, DefaultBufferSize, false)
114ffe3c632Sopenharmony_ci        {
115ffe3c632Sopenharmony_ci        }
116ffe3c632Sopenharmony_ci
117ffe3c632Sopenharmony_ci        /// <summary>
118ffe3c632Sopenharmony_ci        /// Creates a new CodedOutputStream which write to the given stream and uses
119ffe3c632Sopenharmony_ci        /// the specified buffer size.
120ffe3c632Sopenharmony_ci        /// </summary>
121ffe3c632Sopenharmony_ci        /// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
122ffe3c632Sopenharmony_ci        /// <param name="bufferSize">The size of buffer to use internally.</param>
123ffe3c632Sopenharmony_ci        public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize], false)
124ffe3c632Sopenharmony_ci        {
125ffe3c632Sopenharmony_ci        }
126ffe3c632Sopenharmony_ci
127ffe3c632Sopenharmony_ci        /// <summary>
128ffe3c632Sopenharmony_ci        /// Creates a new CodedOutputStream which write to the given stream.
129ffe3c632Sopenharmony_ci        /// </summary>
130ffe3c632Sopenharmony_ci        /// <param name="output">The stream to write to.</param>
131ffe3c632Sopenharmony_ci        /// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
132ffe3c632Sopenharmony_ci        /// if <c>false</c>, the provided stream is disposed as well.</param>
133ffe3c632Sopenharmony_ci        public CodedOutputStream(Stream output, bool leaveOpen) : this(output, DefaultBufferSize, leaveOpen)
134ffe3c632Sopenharmony_ci        {
135ffe3c632Sopenharmony_ci        }
136ffe3c632Sopenharmony_ci
137ffe3c632Sopenharmony_ci        /// <summary>
138ffe3c632Sopenharmony_ci        /// Creates a new CodedOutputStream which write to the given stream and uses
139ffe3c632Sopenharmony_ci        /// the specified buffer size.
140ffe3c632Sopenharmony_ci        /// </summary>
141ffe3c632Sopenharmony_ci        /// <param name="output">The stream to write to.</param>
142ffe3c632Sopenharmony_ci        /// <param name="bufferSize">The size of buffer to use internally.</param>
143ffe3c632Sopenharmony_ci        /// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
144ffe3c632Sopenharmony_ci        /// if <c>false</c>, the provided stream is disposed as well.</param>
145ffe3c632Sopenharmony_ci        public CodedOutputStream(Stream output, int bufferSize, bool leaveOpen) : this(output, new byte[bufferSize], leaveOpen)
146ffe3c632Sopenharmony_ci        {
147ffe3c632Sopenharmony_ci        }
148ffe3c632Sopenharmony_ci        #endregion
149ffe3c632Sopenharmony_ci
150ffe3c632Sopenharmony_ci        /// <summary>
151ffe3c632Sopenharmony_ci        /// Returns the current position in the stream, or the position in the output buffer
152ffe3c632Sopenharmony_ci        /// </summary>
153ffe3c632Sopenharmony_ci        public long Position
154ffe3c632Sopenharmony_ci        {
155ffe3c632Sopenharmony_ci            get
156ffe3c632Sopenharmony_ci            {
157ffe3c632Sopenharmony_ci                if (output != null)
158ffe3c632Sopenharmony_ci                {
159ffe3c632Sopenharmony_ci                    return output.Position + state.position;
160ffe3c632Sopenharmony_ci                }
161ffe3c632Sopenharmony_ci                return state.position;
162ffe3c632Sopenharmony_ci            }
163ffe3c632Sopenharmony_ci        }
164ffe3c632Sopenharmony_ci
165ffe3c632Sopenharmony_ci        #region Writing of values (not including tags)
166ffe3c632Sopenharmony_ci
167ffe3c632Sopenharmony_ci        /// <summary>
168ffe3c632Sopenharmony_ci        /// Writes a double field value, without a tag, to the stream.
169ffe3c632Sopenharmony_ci        /// </summary>
170ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
171ffe3c632Sopenharmony_ci        public void WriteDouble(double value)
172ffe3c632Sopenharmony_ci        {
173ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
174ffe3c632Sopenharmony_ci            WritingPrimitives.WriteDouble(ref span, ref state, value);
175ffe3c632Sopenharmony_ci        }
176ffe3c632Sopenharmony_ci
177ffe3c632Sopenharmony_ci        /// <summary>
178ffe3c632Sopenharmony_ci        /// Writes a float field value, without a tag, to the stream.
179ffe3c632Sopenharmony_ci        /// </summary>
180ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
181ffe3c632Sopenharmony_ci        public void WriteFloat(float value)
182ffe3c632Sopenharmony_ci        {
183ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
184ffe3c632Sopenharmony_ci            WritingPrimitives.WriteFloat(ref span, ref state, value);
185ffe3c632Sopenharmony_ci        }
186ffe3c632Sopenharmony_ci
187ffe3c632Sopenharmony_ci        /// <summary>
188ffe3c632Sopenharmony_ci        /// Writes a uint64 field value, without a tag, to the stream.
189ffe3c632Sopenharmony_ci        /// </summary>
190ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
191ffe3c632Sopenharmony_ci        public void WriteUInt64(ulong value)
192ffe3c632Sopenharmony_ci        {
193ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
194ffe3c632Sopenharmony_ci            WritingPrimitives.WriteUInt64(ref span, ref state, value);
195ffe3c632Sopenharmony_ci        }
196ffe3c632Sopenharmony_ci
197ffe3c632Sopenharmony_ci        /// <summary>
198ffe3c632Sopenharmony_ci        /// Writes an int64 field value, without a tag, to the stream.
199ffe3c632Sopenharmony_ci        /// </summary>
200ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
201ffe3c632Sopenharmony_ci        public void WriteInt64(long value)
202ffe3c632Sopenharmony_ci        {
203ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
204ffe3c632Sopenharmony_ci            WritingPrimitives.WriteInt64(ref span, ref state, value);
205ffe3c632Sopenharmony_ci        }
206ffe3c632Sopenharmony_ci
207ffe3c632Sopenharmony_ci        /// <summary>
208ffe3c632Sopenharmony_ci        /// Writes an int32 field value, without a tag, to the stream.
209ffe3c632Sopenharmony_ci        /// </summary>
210ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
211ffe3c632Sopenharmony_ci        public void WriteInt32(int value)
212ffe3c632Sopenharmony_ci        {
213ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
214ffe3c632Sopenharmony_ci            WritingPrimitives.WriteInt32(ref span, ref state, value);
215ffe3c632Sopenharmony_ci        }
216ffe3c632Sopenharmony_ci
217ffe3c632Sopenharmony_ci        /// <summary>
218ffe3c632Sopenharmony_ci        /// Writes a fixed64 field value, without a tag, to the stream.
219ffe3c632Sopenharmony_ci        /// </summary>
220ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
221ffe3c632Sopenharmony_ci        public void WriteFixed64(ulong value)
222ffe3c632Sopenharmony_ci        {
223ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
224ffe3c632Sopenharmony_ci            WritingPrimitives.WriteFixed64(ref span, ref state, value);
225ffe3c632Sopenharmony_ci        }
226ffe3c632Sopenharmony_ci
227ffe3c632Sopenharmony_ci        /// <summary>
228ffe3c632Sopenharmony_ci        /// Writes a fixed32 field value, without a tag, to the stream.
229ffe3c632Sopenharmony_ci        /// </summary>
230ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
231ffe3c632Sopenharmony_ci        public void WriteFixed32(uint value)
232ffe3c632Sopenharmony_ci        {
233ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
234ffe3c632Sopenharmony_ci            WritingPrimitives.WriteFixed32(ref span, ref state, value);
235ffe3c632Sopenharmony_ci        }
236ffe3c632Sopenharmony_ci
237ffe3c632Sopenharmony_ci        /// <summary>
238ffe3c632Sopenharmony_ci        /// Writes a bool field value, without a tag, to the stream.
239ffe3c632Sopenharmony_ci        /// </summary>
240ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
241ffe3c632Sopenharmony_ci        public void WriteBool(bool value)
242ffe3c632Sopenharmony_ci        {
243ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
244ffe3c632Sopenharmony_ci            WritingPrimitives.WriteBool(ref span, ref state, value);
245ffe3c632Sopenharmony_ci        }
246ffe3c632Sopenharmony_ci
247ffe3c632Sopenharmony_ci        /// <summary>
248ffe3c632Sopenharmony_ci        /// Writes a string field value, without a tag, to the stream.
249ffe3c632Sopenharmony_ci        /// The data is length-prefixed.
250ffe3c632Sopenharmony_ci        /// </summary>
251ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
252ffe3c632Sopenharmony_ci        public void WriteString(string value)
253ffe3c632Sopenharmony_ci        {
254ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
255ffe3c632Sopenharmony_ci            WritingPrimitives.WriteString(ref span, ref state, value);
256ffe3c632Sopenharmony_ci        }
257ffe3c632Sopenharmony_ci
258ffe3c632Sopenharmony_ci        /// <summary>
259ffe3c632Sopenharmony_ci        /// Writes a message, without a tag, to the stream.
260ffe3c632Sopenharmony_ci        /// The data is length-prefixed.
261ffe3c632Sopenharmony_ci        /// </summary>
262ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
263ffe3c632Sopenharmony_ci        public void WriteMessage(IMessage value)
264ffe3c632Sopenharmony_ci        {
265ffe3c632Sopenharmony_ci            // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalWriteTo method),
266ffe3c632Sopenharmony_ci            // what we're doing here works fine, but could be more efficient.
267ffe3c632Sopenharmony_ci            // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it).
268ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
269ffe3c632Sopenharmony_ci            WriteContext.Initialize(ref span, ref state, out WriteContext ctx);
270ffe3c632Sopenharmony_ci            try
271ffe3c632Sopenharmony_ci            {
272ffe3c632Sopenharmony_ci                WritingPrimitivesMessages.WriteMessage(ref ctx, value);
273ffe3c632Sopenharmony_ci            }
274ffe3c632Sopenharmony_ci            finally
275ffe3c632Sopenharmony_ci            {
276ffe3c632Sopenharmony_ci                ctx.CopyStateTo(this);
277ffe3c632Sopenharmony_ci            }
278ffe3c632Sopenharmony_ci        }
279ffe3c632Sopenharmony_ci
280ffe3c632Sopenharmony_ci        /// <summary>
281ffe3c632Sopenharmony_ci        /// Writes a message, without a tag, to the stream.
282ffe3c632Sopenharmony_ci        /// Only the message data is written, without a length-delimiter.
283ffe3c632Sopenharmony_ci        /// </summary>
284ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
285ffe3c632Sopenharmony_ci        public void WriteRawMessage(IMessage value)
286ffe3c632Sopenharmony_ci        {
287ffe3c632Sopenharmony_ci            // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalWriteTo method),
288ffe3c632Sopenharmony_ci            // what we're doing here works fine, but could be more efficient.
289ffe3c632Sopenharmony_ci            // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it).
290ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
291ffe3c632Sopenharmony_ci            WriteContext.Initialize(ref span, ref state, out WriteContext ctx);
292ffe3c632Sopenharmony_ci            try
293ffe3c632Sopenharmony_ci            {
294ffe3c632Sopenharmony_ci                WritingPrimitivesMessages.WriteRawMessage(ref ctx, value);
295ffe3c632Sopenharmony_ci            }
296ffe3c632Sopenharmony_ci            finally
297ffe3c632Sopenharmony_ci            {
298ffe3c632Sopenharmony_ci                ctx.CopyStateTo(this);
299ffe3c632Sopenharmony_ci            }
300ffe3c632Sopenharmony_ci        }
301ffe3c632Sopenharmony_ci
302ffe3c632Sopenharmony_ci        /// <summary>
303ffe3c632Sopenharmony_ci        /// Writes a group, without a tag, to the stream.
304ffe3c632Sopenharmony_ci        /// </summary>
305ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
306ffe3c632Sopenharmony_ci        public void WriteGroup(IMessage value)
307ffe3c632Sopenharmony_ci        {
308ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
309ffe3c632Sopenharmony_ci            WriteContext.Initialize(ref span, ref state, out WriteContext ctx);
310ffe3c632Sopenharmony_ci            try
311ffe3c632Sopenharmony_ci            {
312ffe3c632Sopenharmony_ci                WritingPrimitivesMessages.WriteGroup(ref ctx, value);
313ffe3c632Sopenharmony_ci            }
314ffe3c632Sopenharmony_ci            finally
315ffe3c632Sopenharmony_ci            {
316ffe3c632Sopenharmony_ci                ctx.CopyStateTo(this);
317ffe3c632Sopenharmony_ci            }
318ffe3c632Sopenharmony_ci        }
319ffe3c632Sopenharmony_ci
320ffe3c632Sopenharmony_ci        /// <summary>
321ffe3c632Sopenharmony_ci        /// Write a byte string, without a tag, to the stream.
322ffe3c632Sopenharmony_ci        /// The data is length-prefixed.
323ffe3c632Sopenharmony_ci        /// </summary>
324ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
325ffe3c632Sopenharmony_ci        public void WriteBytes(ByteString value)
326ffe3c632Sopenharmony_ci        {
327ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
328ffe3c632Sopenharmony_ci            WritingPrimitives.WriteBytes(ref span, ref state, value);
329ffe3c632Sopenharmony_ci        }
330ffe3c632Sopenharmony_ci
331ffe3c632Sopenharmony_ci        /// <summary>
332ffe3c632Sopenharmony_ci        /// Writes a uint32 value, without a tag, to the stream.
333ffe3c632Sopenharmony_ci        /// </summary>
334ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
335ffe3c632Sopenharmony_ci        public void WriteUInt32(uint value)
336ffe3c632Sopenharmony_ci        {
337ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
338ffe3c632Sopenharmony_ci            WritingPrimitives.WriteUInt32(ref span, ref state, value);
339ffe3c632Sopenharmony_ci        }
340ffe3c632Sopenharmony_ci
341ffe3c632Sopenharmony_ci        /// <summary>
342ffe3c632Sopenharmony_ci        /// Writes an enum value, without a tag, to the stream.
343ffe3c632Sopenharmony_ci        /// </summary>
344ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
345ffe3c632Sopenharmony_ci        public void WriteEnum(int value)
346ffe3c632Sopenharmony_ci        {
347ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
348ffe3c632Sopenharmony_ci            WritingPrimitives.WriteEnum(ref span, ref state, value);
349ffe3c632Sopenharmony_ci        }
350ffe3c632Sopenharmony_ci
351ffe3c632Sopenharmony_ci        /// <summary>
352ffe3c632Sopenharmony_ci        /// Writes an sfixed32 value, without a tag, to the stream.
353ffe3c632Sopenharmony_ci        /// </summary>
354ffe3c632Sopenharmony_ci        /// <param name="value">The value to write.</param>
355ffe3c632Sopenharmony_ci        public void WriteSFixed32(int value)
356ffe3c632Sopenharmony_ci        {
357ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
358ffe3c632Sopenharmony_ci            WritingPrimitives.WriteSFixed32(ref span, ref state, value);
359ffe3c632Sopenharmony_ci        }
360ffe3c632Sopenharmony_ci
361ffe3c632Sopenharmony_ci        /// <summary>
362ffe3c632Sopenharmony_ci        /// Writes an sfixed64 value, without a tag, to the stream.
363ffe3c632Sopenharmony_ci        /// </summary>
364ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
365ffe3c632Sopenharmony_ci        public void WriteSFixed64(long value)
366ffe3c632Sopenharmony_ci        {
367ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
368ffe3c632Sopenharmony_ci            WritingPrimitives.WriteSFixed64(ref span, ref state, value);
369ffe3c632Sopenharmony_ci        }
370ffe3c632Sopenharmony_ci
371ffe3c632Sopenharmony_ci        /// <summary>
372ffe3c632Sopenharmony_ci        /// Writes an sint32 value, without a tag, to the stream.
373ffe3c632Sopenharmony_ci        /// </summary>
374ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
375ffe3c632Sopenharmony_ci        public void WriteSInt32(int value)
376ffe3c632Sopenharmony_ci        {
377ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
378ffe3c632Sopenharmony_ci            WritingPrimitives.WriteSInt32(ref span, ref state, value);
379ffe3c632Sopenharmony_ci        }
380ffe3c632Sopenharmony_ci
381ffe3c632Sopenharmony_ci        /// <summary>
382ffe3c632Sopenharmony_ci        /// Writes an sint64 value, without a tag, to the stream.
383ffe3c632Sopenharmony_ci        /// </summary>
384ffe3c632Sopenharmony_ci        /// <param name="value">The value to write</param>
385ffe3c632Sopenharmony_ci        public void WriteSInt64(long value)
386ffe3c632Sopenharmony_ci        {
387ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
388ffe3c632Sopenharmony_ci            WritingPrimitives.WriteSInt64(ref span, ref state, value);
389ffe3c632Sopenharmony_ci        }
390ffe3c632Sopenharmony_ci
391ffe3c632Sopenharmony_ci        /// <summary>
392ffe3c632Sopenharmony_ci        /// Writes a length (in bytes) for length-delimited data.
393ffe3c632Sopenharmony_ci        /// </summary>
394ffe3c632Sopenharmony_ci        /// <remarks>
395ffe3c632Sopenharmony_ci        /// This method simply writes a rawint, but exists for clarity in calling code.
396ffe3c632Sopenharmony_ci        /// </remarks>
397ffe3c632Sopenharmony_ci        /// <param name="length">Length value, in bytes.</param>
398ffe3c632Sopenharmony_ci        public void WriteLength(int length)
399ffe3c632Sopenharmony_ci        {
400ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
401ffe3c632Sopenharmony_ci            WritingPrimitives.WriteLength(ref span, ref state, length);
402ffe3c632Sopenharmony_ci        }
403ffe3c632Sopenharmony_ci
404ffe3c632Sopenharmony_ci        #endregion
405ffe3c632Sopenharmony_ci
406ffe3c632Sopenharmony_ci        #region Raw tag writing
407ffe3c632Sopenharmony_ci        /// <summary>
408ffe3c632Sopenharmony_ci        /// Encodes and writes a tag.
409ffe3c632Sopenharmony_ci        /// </summary>
410ffe3c632Sopenharmony_ci        /// <param name="fieldNumber">The number of the field to write the tag for</param>
411ffe3c632Sopenharmony_ci        /// <param name="type">The wire format type of the tag to write</param>
412ffe3c632Sopenharmony_ci        public void WriteTag(int fieldNumber, WireFormat.WireType type)
413ffe3c632Sopenharmony_ci        {
414ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
415ffe3c632Sopenharmony_ci            WritingPrimitives.WriteTag(ref span, ref state, fieldNumber, type);
416ffe3c632Sopenharmony_ci        }
417ffe3c632Sopenharmony_ci
418ffe3c632Sopenharmony_ci        /// <summary>
419ffe3c632Sopenharmony_ci        /// Writes an already-encoded tag.
420ffe3c632Sopenharmony_ci        /// </summary>
421ffe3c632Sopenharmony_ci        /// <param name="tag">The encoded tag</param>
422ffe3c632Sopenharmony_ci        public void WriteTag(uint tag)
423ffe3c632Sopenharmony_ci        {
424ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
425ffe3c632Sopenharmony_ci            WritingPrimitives.WriteTag(ref span, ref state, tag);
426ffe3c632Sopenharmony_ci        }
427ffe3c632Sopenharmony_ci
428ffe3c632Sopenharmony_ci        /// <summary>
429ffe3c632Sopenharmony_ci        /// Writes the given single-byte tag directly to the stream.
430ffe3c632Sopenharmony_ci        /// </summary>
431ffe3c632Sopenharmony_ci        /// <param name="b1">The encoded tag</param>
432ffe3c632Sopenharmony_ci        public void WriteRawTag(byte b1)
433ffe3c632Sopenharmony_ci        {
434ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
435ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawTag(ref span, ref state, b1);
436ffe3c632Sopenharmony_ci        }
437ffe3c632Sopenharmony_ci
438ffe3c632Sopenharmony_ci        /// <summary>
439ffe3c632Sopenharmony_ci        /// Writes the given two-byte tag directly to the stream.
440ffe3c632Sopenharmony_ci        /// </summary>
441ffe3c632Sopenharmony_ci        /// <param name="b1">The first byte of the encoded tag</param>
442ffe3c632Sopenharmony_ci        /// <param name="b2">The second byte of the encoded tag</param>
443ffe3c632Sopenharmony_ci        public void WriteRawTag(byte b1, byte b2)
444ffe3c632Sopenharmony_ci        {
445ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
446ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2);
447ffe3c632Sopenharmony_ci        }
448ffe3c632Sopenharmony_ci
449ffe3c632Sopenharmony_ci        /// <summary>
450ffe3c632Sopenharmony_ci        /// Writes the given three-byte tag directly to the stream.
451ffe3c632Sopenharmony_ci        /// </summary>
452ffe3c632Sopenharmony_ci        /// <param name="b1">The first byte of the encoded tag</param>
453ffe3c632Sopenharmony_ci        /// <param name="b2">The second byte of the encoded tag</param>
454ffe3c632Sopenharmony_ci        /// <param name="b3">The third byte of the encoded tag</param>
455ffe3c632Sopenharmony_ci        public void WriteRawTag(byte b1, byte b2, byte b3)
456ffe3c632Sopenharmony_ci        {
457ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
458ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3);
459ffe3c632Sopenharmony_ci        }
460ffe3c632Sopenharmony_ci
461ffe3c632Sopenharmony_ci        /// <summary>
462ffe3c632Sopenharmony_ci        /// Writes the given four-byte tag directly to the stream.
463ffe3c632Sopenharmony_ci        /// </summary>
464ffe3c632Sopenharmony_ci        /// <param name="b1">The first byte of the encoded tag</param>
465ffe3c632Sopenharmony_ci        /// <param name="b2">The second byte of the encoded tag</param>
466ffe3c632Sopenharmony_ci        /// <param name="b3">The third byte of the encoded tag</param>
467ffe3c632Sopenharmony_ci        /// <param name="b4">The fourth byte of the encoded tag</param>
468ffe3c632Sopenharmony_ci        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)
469ffe3c632Sopenharmony_ci        {
470ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
471ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4);
472ffe3c632Sopenharmony_ci        }
473ffe3c632Sopenharmony_ci
474ffe3c632Sopenharmony_ci        /// <summary>
475ffe3c632Sopenharmony_ci        /// Writes the given five-byte tag directly to the stream.
476ffe3c632Sopenharmony_ci        /// </summary>
477ffe3c632Sopenharmony_ci        /// <param name="b1">The first byte of the encoded tag</param>
478ffe3c632Sopenharmony_ci        /// <param name="b2">The second byte of the encoded tag</param>
479ffe3c632Sopenharmony_ci        /// <param name="b3">The third byte of the encoded tag</param>
480ffe3c632Sopenharmony_ci        /// <param name="b4">The fourth byte of the encoded tag</param>
481ffe3c632Sopenharmony_ci        /// <param name="b5">The fifth byte of the encoded tag</param>
482ffe3c632Sopenharmony_ci        public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)
483ffe3c632Sopenharmony_ci        {
484ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
485ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4, b5);
486ffe3c632Sopenharmony_ci        }
487ffe3c632Sopenharmony_ci        #endregion
488ffe3c632Sopenharmony_ci
489ffe3c632Sopenharmony_ci        #region Underlying writing primitives
490ffe3c632Sopenharmony_ci
491ffe3c632Sopenharmony_ci        /// <summary>
492ffe3c632Sopenharmony_ci        /// Writes a 32 bit value as a varint. The fast route is taken when
493ffe3c632Sopenharmony_ci        /// there's enough buffer space left to whizz through without checking
494ffe3c632Sopenharmony_ci        /// for each byte; otherwise, we resort to calling WriteRawByte each time.
495ffe3c632Sopenharmony_ci        /// </summary>
496ffe3c632Sopenharmony_ci        internal void WriteRawVarint32(uint value)
497ffe3c632Sopenharmony_ci        {
498ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
499ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawVarint32(ref span, ref state, value);
500ffe3c632Sopenharmony_ci        }
501ffe3c632Sopenharmony_ci
502ffe3c632Sopenharmony_ci        internal void WriteRawVarint64(ulong value)
503ffe3c632Sopenharmony_ci        {
504ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
505ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawVarint64(ref span, ref state, value);
506ffe3c632Sopenharmony_ci        }
507ffe3c632Sopenharmony_ci
508ffe3c632Sopenharmony_ci        internal void WriteRawLittleEndian32(uint value)
509ffe3c632Sopenharmony_ci        {
510ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
511ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawLittleEndian32(ref span, ref state, value);
512ffe3c632Sopenharmony_ci        }
513ffe3c632Sopenharmony_ci
514ffe3c632Sopenharmony_ci        internal void WriteRawLittleEndian64(ulong value)
515ffe3c632Sopenharmony_ci        {
516ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
517ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawLittleEndian64(ref span, ref state, value);
518ffe3c632Sopenharmony_ci        }
519ffe3c632Sopenharmony_ci
520ffe3c632Sopenharmony_ci        /// <summary>
521ffe3c632Sopenharmony_ci        /// Writes out an array of bytes.
522ffe3c632Sopenharmony_ci        /// </summary>
523ffe3c632Sopenharmony_ci        internal void WriteRawBytes(byte[] value)
524ffe3c632Sopenharmony_ci        {
525ffe3c632Sopenharmony_ci            WriteRawBytes(value, 0, value.Length);
526ffe3c632Sopenharmony_ci        }
527ffe3c632Sopenharmony_ci
528ffe3c632Sopenharmony_ci        /// <summary>
529ffe3c632Sopenharmony_ci        /// Writes out part of an array of bytes.
530ffe3c632Sopenharmony_ci        /// </summary>
531ffe3c632Sopenharmony_ci        internal void WriteRawBytes(byte[] value, int offset, int length)
532ffe3c632Sopenharmony_ci        {
533ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
534ffe3c632Sopenharmony_ci            WritingPrimitives.WriteRawBytes(ref span, ref state, value, offset, length);
535ffe3c632Sopenharmony_ci        }
536ffe3c632Sopenharmony_ci
537ffe3c632Sopenharmony_ci        #endregion
538ffe3c632Sopenharmony_ci
539ffe3c632Sopenharmony_ci        /// <summary>
540ffe3c632Sopenharmony_ci        /// Indicates that a CodedOutputStream wrapping a flat byte array
541ffe3c632Sopenharmony_ci        /// ran out of space.
542ffe3c632Sopenharmony_ci        /// </summary>
543ffe3c632Sopenharmony_ci        public sealed class OutOfSpaceException : IOException
544ffe3c632Sopenharmony_ci        {
545ffe3c632Sopenharmony_ci            internal OutOfSpaceException()
546ffe3c632Sopenharmony_ci                : base("CodedOutputStream was writing to a flat byte array and ran out of space.")
547ffe3c632Sopenharmony_ci            {
548ffe3c632Sopenharmony_ci            }
549ffe3c632Sopenharmony_ci        }
550ffe3c632Sopenharmony_ci
551ffe3c632Sopenharmony_ci        /// <summary>
552ffe3c632Sopenharmony_ci        /// Flushes any buffered data and optionally closes the underlying stream, if any.
553ffe3c632Sopenharmony_ci        /// </summary>
554ffe3c632Sopenharmony_ci        /// <remarks>
555ffe3c632Sopenharmony_ci        /// <para>
556ffe3c632Sopenharmony_ci        /// By default, any underlying stream is closed by this method. To configure this behaviour,
557ffe3c632Sopenharmony_ci        /// use a constructor overload with a <c>leaveOpen</c> parameter. If this instance does not
558ffe3c632Sopenharmony_ci        /// have an underlying stream, this method does nothing.
559ffe3c632Sopenharmony_ci        /// </para>
560ffe3c632Sopenharmony_ci        /// <para>
561ffe3c632Sopenharmony_ci        /// For the sake of efficiency, calling this method does not prevent future write calls - but
562ffe3c632Sopenharmony_ci        /// if a later write ends up writing to a stream which has been disposed, that is likely to
563ffe3c632Sopenharmony_ci        /// fail. It is recommend that you not call any other methods after this.
564ffe3c632Sopenharmony_ci        /// </para>
565ffe3c632Sopenharmony_ci        /// </remarks>
566ffe3c632Sopenharmony_ci        public void Dispose()
567ffe3c632Sopenharmony_ci        {
568ffe3c632Sopenharmony_ci            Flush();
569ffe3c632Sopenharmony_ci            if (!leaveOpen)
570ffe3c632Sopenharmony_ci            {
571ffe3c632Sopenharmony_ci                output.Dispose();
572ffe3c632Sopenharmony_ci            }
573ffe3c632Sopenharmony_ci        }
574ffe3c632Sopenharmony_ci
575ffe3c632Sopenharmony_ci        /// <summary>
576ffe3c632Sopenharmony_ci        /// Flushes any buffered data to the underlying stream (if there is one).
577ffe3c632Sopenharmony_ci        /// </summary>
578ffe3c632Sopenharmony_ci        public void Flush()
579ffe3c632Sopenharmony_ci        {
580ffe3c632Sopenharmony_ci            var span = new Span<byte>(buffer);
581ffe3c632Sopenharmony_ci            WriteBufferHelper.Flush(ref span, ref state);
582ffe3c632Sopenharmony_ci        }
583ffe3c632Sopenharmony_ci
584ffe3c632Sopenharmony_ci        /// <summary>
585ffe3c632Sopenharmony_ci        /// Verifies that SpaceLeft returns zero. It's common to create a byte array
586ffe3c632Sopenharmony_ci        /// that is exactly big enough to hold a message, then write to it with
587ffe3c632Sopenharmony_ci        /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
588ffe3c632Sopenharmony_ci        /// the message was actually as big as expected, which can help finding bugs.
589ffe3c632Sopenharmony_ci        /// </summary>
590ffe3c632Sopenharmony_ci        public void CheckNoSpaceLeft()
591ffe3c632Sopenharmony_ci        {
592ffe3c632Sopenharmony_ci            WriteBufferHelper.CheckNoSpaceLeft(ref state);
593ffe3c632Sopenharmony_ci        }
594ffe3c632Sopenharmony_ci
595ffe3c632Sopenharmony_ci        /// <summary>
596ffe3c632Sopenharmony_ci        /// If writing to a flat array, returns the space left in the array. Otherwise,
597ffe3c632Sopenharmony_ci        /// throws an InvalidOperationException.
598ffe3c632Sopenharmony_ci        /// </summary>
599ffe3c632Sopenharmony_ci        public int SpaceLeft => WriteBufferHelper.GetSpaceLeft(ref state);
600ffe3c632Sopenharmony_ci
601ffe3c632Sopenharmony_ci        internal byte[] InternalBuffer => buffer;
602ffe3c632Sopenharmony_ci
603ffe3c632Sopenharmony_ci        internal Stream InternalOutputStream => output;
604ffe3c632Sopenharmony_ci
605ffe3c632Sopenharmony_ci        internal ref WriterInternalState InternalState => ref state;
606ffe3c632Sopenharmony_ci    }
607ffe3c632Sopenharmony_ci}
608