xref: /aosp_15_r20/external/protobuf/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker #region Copyright notice and license
2*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format
3*1b3f573fSAndroid Build Coastguard Worker // Copyright 2008 Google Inc.  All rights reserved.
4*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/
5*1b3f573fSAndroid Build Coastguard Worker //
6*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
7*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
8*1b3f573fSAndroid Build Coastguard Worker // met:
9*1b3f573fSAndroid Build Coastguard Worker //
10*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions of source code must retain the above copyright
11*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
12*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions in binary form must reproduce the above
13*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
14*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
15*1b3f573fSAndroid Build Coastguard Worker // distribution.
16*1b3f573fSAndroid Build Coastguard Worker //     * Neither the name of Google Inc. nor the names of its
17*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
18*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission.
19*1b3f573fSAndroid Build Coastguard Worker //
20*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*1b3f573fSAndroid Build Coastguard Worker #endregion
32*1b3f573fSAndroid Build Coastguard Worker 
33*1b3f573fSAndroid Build Coastguard Worker using System;
34*1b3f573fSAndroid Build Coastguard Worker using System.Buffers;
35*1b3f573fSAndroid Build Coastguard Worker using System.IO;
36*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.TestProtos;
37*1b3f573fSAndroid Build Coastguard Worker using Proto2 = Google.Protobuf.TestProtos.Proto2;
38*1b3f573fSAndroid Build Coastguard Worker using NUnit.Framework;
39*1b3f573fSAndroid Build Coastguard Worker 
40*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf
41*1b3f573fSAndroid Build Coastguard Worker {
42*1b3f573fSAndroid Build Coastguard Worker     public class CodedInputStreamTest
43*1b3f573fSAndroid Build Coastguard Worker     {
44*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
45*1b3f573fSAndroid Build Coastguard Worker         /// Helper to construct a byte array from a bunch of bytes.  The inputs are
46*1b3f573fSAndroid Build Coastguard Worker         /// actually ints so that I can use hex notation and not get stupid errors
47*1b3f573fSAndroid Build Coastguard Worker         /// about precision.
48*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
Bytes(params int[] bytesAsInts)49*1b3f573fSAndroid Build Coastguard Worker         private static byte[] Bytes(params int[] bytesAsInts)
50*1b3f573fSAndroid Build Coastguard Worker         {
51*1b3f573fSAndroid Build Coastguard Worker             byte[] bytes = new byte[bytesAsInts.Length];
52*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < bytesAsInts.Length; i++)
53*1b3f573fSAndroid Build Coastguard Worker             {
54*1b3f573fSAndroid Build Coastguard Worker                 bytes[i] = (byte) bytesAsInts[i];
55*1b3f573fSAndroid Build Coastguard Worker             }
56*1b3f573fSAndroid Build Coastguard Worker             return bytes;
57*1b3f573fSAndroid Build Coastguard Worker         }
58*1b3f573fSAndroid Build Coastguard Worker 
59*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
60*1b3f573fSAndroid Build Coastguard Worker         /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64()
61*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
AssertReadVarint(byte[] data, ulong value)62*1b3f573fSAndroid Build Coastguard Worker         private static void AssertReadVarint(byte[] data, ulong value)
63*1b3f573fSAndroid Build Coastguard Worker         {
64*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(data);
65*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual((uint) value, input.ReadRawVarint32());
66*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(input.IsAtEnd);
67*1b3f573fSAndroid Build Coastguard Worker 
68*1b3f573fSAndroid Build Coastguard Worker             input = new CodedInputStream(data);
69*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(value, input.ReadRawVarint64());
70*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(input.IsAtEnd);
71*1b3f573fSAndroid Build Coastguard Worker 
72*1b3f573fSAndroid Build Coastguard Worker             AssertReadFromParseContext(new ReadOnlySequence<byte>(data), (ref ParseContext ctx) =>
73*1b3f573fSAndroid Build Coastguard Worker             {
74*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual((uint) value, ctx.ReadUInt32());
75*1b3f573fSAndroid Build Coastguard Worker             }, true);
76*1b3f573fSAndroid Build Coastguard Worker 
77*1b3f573fSAndroid Build Coastguard Worker             AssertReadFromParseContext(new ReadOnlySequence<byte>(data), (ref ParseContext ctx) =>
78*1b3f573fSAndroid Build Coastguard Worker             {
79*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(value, ctx.ReadUInt64());
80*1b3f573fSAndroid Build Coastguard Worker             }, true);
81*1b3f573fSAndroid Build Coastguard Worker 
82*1b3f573fSAndroid Build Coastguard Worker             // Try different block sizes.
83*1b3f573fSAndroid Build Coastguard Worker             for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2)
84*1b3f573fSAndroid Build Coastguard Worker             {
85*1b3f573fSAndroid Build Coastguard Worker                 input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize));
86*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual((uint) value, input.ReadRawVarint32());
87*1b3f573fSAndroid Build Coastguard Worker 
88*1b3f573fSAndroid Build Coastguard Worker                 input = new CodedInputStream(new SmallBlockInputStream(data, bufferSize));
89*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(value, input.ReadRawVarint64());
90*1b3f573fSAndroid Build Coastguard Worker                 Assert.IsTrue(input.IsAtEnd);
91*1b3f573fSAndroid Build Coastguard Worker 
92*1b3f573fSAndroid Build Coastguard Worker                 AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, bufferSize), (ref ParseContext ctx) =>
93*1b3f573fSAndroid Build Coastguard Worker                 {
94*1b3f573fSAndroid Build Coastguard Worker                     Assert.AreEqual((uint) value, ctx.ReadUInt32());
95*1b3f573fSAndroid Build Coastguard Worker                 }, true);
96*1b3f573fSAndroid Build Coastguard Worker 
97*1b3f573fSAndroid Build Coastguard Worker                 AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, bufferSize), (ref ParseContext ctx) =>
98*1b3f573fSAndroid Build Coastguard Worker                 {
99*1b3f573fSAndroid Build Coastguard Worker                     Assert.AreEqual(value, ctx.ReadUInt64());
100*1b3f573fSAndroid Build Coastguard Worker                 }, true);
101*1b3f573fSAndroid Build Coastguard Worker             }
102*1b3f573fSAndroid Build Coastguard Worker 
103*1b3f573fSAndroid Build Coastguard Worker             // Try reading directly from a MemoryStream. We want to verify that it
104*1b3f573fSAndroid Build Coastguard Worker             // doesn't read past the end of the input, so write an extra byte - this
105*1b3f573fSAndroid Build Coastguard Worker             // lets us test the position at the end.
106*1b3f573fSAndroid Build Coastguard Worker             MemoryStream memoryStream = new MemoryStream();
107*1b3f573fSAndroid Build Coastguard Worker             memoryStream.Write(data, 0, data.Length);
108*1b3f573fSAndroid Build Coastguard Worker             memoryStream.WriteByte(0);
109*1b3f573fSAndroid Build Coastguard Worker             memoryStream.Position = 0;
110*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual((uint) value, CodedInputStream.ReadRawVarint32(memoryStream));
111*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(data.Length, memoryStream.Position);
112*1b3f573fSAndroid Build Coastguard Worker         }
113*1b3f573fSAndroid Build Coastguard Worker 
114*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
115*1b3f573fSAndroid Build Coastguard Worker         /// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() and
116*1b3f573fSAndroid Build Coastguard Worker         /// expects them to fail with an InvalidProtocolBufferException whose
117*1b3f573fSAndroid Build Coastguard Worker         /// description matches the given one.
118*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data)119*1b3f573fSAndroid Build Coastguard Worker         private static void AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data)
120*1b3f573fSAndroid Build Coastguard Worker         {
121*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(data);
122*1b3f573fSAndroid Build Coastguard Worker             var exception = Assert.Throws<InvalidProtocolBufferException>(() => input.ReadRawVarint32());
123*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected.Message, exception.Message);
124*1b3f573fSAndroid Build Coastguard Worker 
125*1b3f573fSAndroid Build Coastguard Worker             input = new CodedInputStream(data);
126*1b3f573fSAndroid Build Coastguard Worker             exception = Assert.Throws<InvalidProtocolBufferException>(() => input.ReadRawVarint64());
127*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected.Message, exception.Message);
128*1b3f573fSAndroid Build Coastguard Worker 
129*1b3f573fSAndroid Build Coastguard Worker             AssertReadFromParseContext(new ReadOnlySequence<byte>(data), (ref ParseContext ctx) =>
130*1b3f573fSAndroid Build Coastguard Worker             {
131*1b3f573fSAndroid Build Coastguard Worker                 try
132*1b3f573fSAndroid Build Coastguard Worker                 {
133*1b3f573fSAndroid Build Coastguard Worker                     ctx.ReadUInt32();
134*1b3f573fSAndroid Build Coastguard Worker                     Assert.Fail();
135*1b3f573fSAndroid Build Coastguard Worker                 }
136*1b3f573fSAndroid Build Coastguard Worker                 catch (InvalidProtocolBufferException ex)
137*1b3f573fSAndroid Build Coastguard Worker                 {
138*1b3f573fSAndroid Build Coastguard Worker                     Assert.AreEqual(expected.Message, ex.Message);
139*1b3f573fSAndroid Build Coastguard Worker                 }
140*1b3f573fSAndroid Build Coastguard Worker             }, false);
141*1b3f573fSAndroid Build Coastguard Worker 
142*1b3f573fSAndroid Build Coastguard Worker             AssertReadFromParseContext(new ReadOnlySequence<byte>(data), (ref ParseContext ctx) =>
143*1b3f573fSAndroid Build Coastguard Worker             {
144*1b3f573fSAndroid Build Coastguard Worker                 try
145*1b3f573fSAndroid Build Coastguard Worker                 {
146*1b3f573fSAndroid Build Coastguard Worker                     ctx.ReadUInt64();
147*1b3f573fSAndroid Build Coastguard Worker                     Assert.Fail();
148*1b3f573fSAndroid Build Coastguard Worker                 }
149*1b3f573fSAndroid Build Coastguard Worker                 catch (InvalidProtocolBufferException ex)
150*1b3f573fSAndroid Build Coastguard Worker                 {
151*1b3f573fSAndroid Build Coastguard Worker                     Assert.AreEqual(expected.Message, ex.Message);
152*1b3f573fSAndroid Build Coastguard Worker                 }
153*1b3f573fSAndroid Build Coastguard Worker             }, false);
154*1b3f573fSAndroid Build Coastguard Worker 
155*1b3f573fSAndroid Build Coastguard Worker             // Make sure we get the same error when reading directly from a Stream.
156*1b3f573fSAndroid Build Coastguard Worker             exception = Assert.Throws<InvalidProtocolBufferException>(() => CodedInputStream.ReadRawVarint32(new MemoryStream(data)));
157*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected.Message, exception.Message);
158*1b3f573fSAndroid Build Coastguard Worker         }
159*1b3f573fSAndroid Build Coastguard Worker 
ParseContextAssertAction(ref ParseContext ctx)160*1b3f573fSAndroid Build Coastguard Worker         private delegate void ParseContextAssertAction(ref ParseContext ctx);
161*1b3f573fSAndroid Build Coastguard Worker 
AssertReadFromParseContext(ReadOnlySequence<byte> input, ParseContextAssertAction assertAction, bool assertIsAtEnd)162*1b3f573fSAndroid Build Coastguard Worker         private static void AssertReadFromParseContext(ReadOnlySequence<byte> input, ParseContextAssertAction assertAction, bool assertIsAtEnd)
163*1b3f573fSAndroid Build Coastguard Worker         {
164*1b3f573fSAndroid Build Coastguard Worker             // Check as ReadOnlySequence<byte>
165*1b3f573fSAndroid Build Coastguard Worker             ParseContext.Initialize(input, out ParseContext parseCtx);
166*1b3f573fSAndroid Build Coastguard Worker             assertAction(ref parseCtx);
167*1b3f573fSAndroid Build Coastguard Worker             if (assertIsAtEnd)
168*1b3f573fSAndroid Build Coastguard Worker             {
169*1b3f573fSAndroid Build Coastguard Worker                 Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref parseCtx.buffer, ref parseCtx.state));
170*1b3f573fSAndroid Build Coastguard Worker             }
171*1b3f573fSAndroid Build Coastguard Worker 
172*1b3f573fSAndroid Build Coastguard Worker             // Check as ReadOnlySpan<byte>
173*1b3f573fSAndroid Build Coastguard Worker             ParseContext.Initialize(input.ToArray().AsSpan(), out ParseContext spanParseContext);
174*1b3f573fSAndroid Build Coastguard Worker             assertAction(ref spanParseContext);
175*1b3f573fSAndroid Build Coastguard Worker             if (assertIsAtEnd)
176*1b3f573fSAndroid Build Coastguard Worker             {
177*1b3f573fSAndroid Build Coastguard Worker                 Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref spanParseContext.buffer, ref spanParseContext.state));
178*1b3f573fSAndroid Build Coastguard Worker             }
179*1b3f573fSAndroid Build Coastguard Worker         }
180*1b3f573fSAndroid Build Coastguard Worker 
181*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadVarint()182*1b3f573fSAndroid Build Coastguard Worker         public void ReadVarint()
183*1b3f573fSAndroid Build Coastguard Worker         {
184*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarint(Bytes(0x00), 0);
185*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarint(Bytes(0x01), 1);
186*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarint(Bytes(0x7f), 127);
187*1b3f573fSAndroid Build Coastguard Worker             // 14882
188*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarint(Bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
189*1b3f573fSAndroid Build Coastguard Worker             // 2961488830
190*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
191*1b3f573fSAndroid Build Coastguard Worker                              (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
192*1b3f573fSAndroid Build Coastguard Worker                              (0x0bL << 28));
193*1b3f573fSAndroid Build Coastguard Worker 
194*1b3f573fSAndroid Build Coastguard Worker             // 64-bit
195*1b3f573fSAndroid Build Coastguard Worker             // 7256456126
196*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarint(Bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
197*1b3f573fSAndroid Build Coastguard Worker                              (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
198*1b3f573fSAndroid Build Coastguard Worker                              (0x1bL << 28));
199*1b3f573fSAndroid Build Coastguard Worker             // 41256202580718336
200*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarint(Bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
201*1b3f573fSAndroid Build Coastguard Worker                              (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
202*1b3f573fSAndroid Build Coastguard Worker                              (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
203*1b3f573fSAndroid Build Coastguard Worker             // 11964378330978735131
204*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarint(Bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
205*1b3f573fSAndroid Build Coastguard Worker                              (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
206*1b3f573fSAndroid Build Coastguard Worker                              (0x3bUL << 28) | (0x56UL << 35) | (0x00UL << 42) |
207*1b3f573fSAndroid Build Coastguard Worker                              (0x05UL << 49) | (0x26UL << 56) | (0x01UL << 63));
208*1b3f573fSAndroid Build Coastguard Worker 
209*1b3f573fSAndroid Build Coastguard Worker             // Failures
210*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarintFailure(
211*1b3f573fSAndroid Build Coastguard Worker                 InvalidProtocolBufferException.MalformedVarint(),
212*1b3f573fSAndroid Build Coastguard Worker                 Bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
213*1b3f573fSAndroid Build Coastguard Worker                       0x00));
214*1b3f573fSAndroid Build Coastguard Worker             AssertReadVarintFailure(
215*1b3f573fSAndroid Build Coastguard Worker                 InvalidProtocolBufferException.TruncatedMessage(),
216*1b3f573fSAndroid Build Coastguard Worker                 Bytes(0x80));
217*1b3f573fSAndroid Build Coastguard Worker         }
218*1b3f573fSAndroid Build Coastguard Worker 
219*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
220*1b3f573fSAndroid Build Coastguard Worker         /// Parses the given bytes using ReadRawLittleEndian32() and checks
221*1b3f573fSAndroid Build Coastguard Worker         /// that the result matches the given value.
222*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
AssertReadLittleEndian32(byte[] data, uint value)223*1b3f573fSAndroid Build Coastguard Worker         private static void AssertReadLittleEndian32(byte[] data, uint value)
224*1b3f573fSAndroid Build Coastguard Worker         {
225*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(data);
226*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(value, input.ReadRawLittleEndian32());
227*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(input.IsAtEnd);
228*1b3f573fSAndroid Build Coastguard Worker 
229*1b3f573fSAndroid Build Coastguard Worker             AssertReadFromParseContext(new ReadOnlySequence<byte>(data), (ref ParseContext ctx) =>
230*1b3f573fSAndroid Build Coastguard Worker             {
231*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(value, ctx.ReadFixed32());
232*1b3f573fSAndroid Build Coastguard Worker             }, true);
233*1b3f573fSAndroid Build Coastguard Worker 
234*1b3f573fSAndroid Build Coastguard Worker             // Try different block sizes.
235*1b3f573fSAndroid Build Coastguard Worker             for (int blockSize = 1; blockSize <= 16; blockSize *= 2)
236*1b3f573fSAndroid Build Coastguard Worker             {
237*1b3f573fSAndroid Build Coastguard Worker                 input = new CodedInputStream(
238*1b3f573fSAndroid Build Coastguard Worker                     new SmallBlockInputStream(data, blockSize));
239*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(value, input.ReadRawLittleEndian32());
240*1b3f573fSAndroid Build Coastguard Worker                 Assert.IsTrue(input.IsAtEnd);
241*1b3f573fSAndroid Build Coastguard Worker 
242*1b3f573fSAndroid Build Coastguard Worker                 AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, blockSize), (ref ParseContext ctx) =>
243*1b3f573fSAndroid Build Coastguard Worker                 {
244*1b3f573fSAndroid Build Coastguard Worker                     Assert.AreEqual(value, ctx.ReadFixed32());
245*1b3f573fSAndroid Build Coastguard Worker                 }, true);
246*1b3f573fSAndroid Build Coastguard Worker             }
247*1b3f573fSAndroid Build Coastguard Worker         }
248*1b3f573fSAndroid Build Coastguard Worker 
249*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
250*1b3f573fSAndroid Build Coastguard Worker         /// Parses the given bytes using ReadRawLittleEndian64() and checks
251*1b3f573fSAndroid Build Coastguard Worker         /// that the result matches the given value.
252*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
AssertReadLittleEndian64(byte[] data, ulong value)253*1b3f573fSAndroid Build Coastguard Worker         private static void AssertReadLittleEndian64(byte[] data, ulong value)
254*1b3f573fSAndroid Build Coastguard Worker         {
255*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(data);
256*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(value, input.ReadRawLittleEndian64());
257*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(input.IsAtEnd);
258*1b3f573fSAndroid Build Coastguard Worker 
259*1b3f573fSAndroid Build Coastguard Worker             AssertReadFromParseContext(new ReadOnlySequence<byte>(data), (ref ParseContext ctx) =>
260*1b3f573fSAndroid Build Coastguard Worker             {
261*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(value, ctx.ReadFixed64());
262*1b3f573fSAndroid Build Coastguard Worker             }, true);
263*1b3f573fSAndroid Build Coastguard Worker 
264*1b3f573fSAndroid Build Coastguard Worker             // Try different block sizes.
265*1b3f573fSAndroid Build Coastguard Worker             for (int blockSize = 1; blockSize <= 16; blockSize *= 2)
266*1b3f573fSAndroid Build Coastguard Worker             {
267*1b3f573fSAndroid Build Coastguard Worker                 input = new CodedInputStream(
268*1b3f573fSAndroid Build Coastguard Worker                     new SmallBlockInputStream(data, blockSize));
269*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(value, input.ReadRawLittleEndian64());
270*1b3f573fSAndroid Build Coastguard Worker                 Assert.IsTrue(input.IsAtEnd);
271*1b3f573fSAndroid Build Coastguard Worker 
272*1b3f573fSAndroid Build Coastguard Worker                 AssertReadFromParseContext(ReadOnlySequenceFactory.CreateWithContent(data, blockSize), (ref ParseContext ctx) =>
273*1b3f573fSAndroid Build Coastguard Worker                 {
274*1b3f573fSAndroid Build Coastguard Worker                     Assert.AreEqual(value, ctx.ReadFixed64());
275*1b3f573fSAndroid Build Coastguard Worker                 }, true);
276*1b3f573fSAndroid Build Coastguard Worker             }
277*1b3f573fSAndroid Build Coastguard Worker         }
278*1b3f573fSAndroid Build Coastguard Worker 
279*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadLittleEndian()280*1b3f573fSAndroid Build Coastguard Worker         public void ReadLittleEndian()
281*1b3f573fSAndroid Build Coastguard Worker         {
282*1b3f573fSAndroid Build Coastguard Worker             AssertReadLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
283*1b3f573fSAndroid Build Coastguard Worker             AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
284*1b3f573fSAndroid Build Coastguard Worker 
285*1b3f573fSAndroid Build Coastguard Worker             AssertReadLittleEndian64(Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
286*1b3f573fSAndroid Build Coastguard Worker                                      0x123456789abcdef0L);
287*1b3f573fSAndroid Build Coastguard Worker             AssertReadLittleEndian64(
288*1b3f573fSAndroid Build Coastguard Worker                 Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678UL);
289*1b3f573fSAndroid Build Coastguard Worker         }
290*1b3f573fSAndroid Build Coastguard Worker 
291*1b3f573fSAndroid Build Coastguard Worker         [Test]
DecodeZigZag32()292*1b3f573fSAndroid Build Coastguard Worker         public void DecodeZigZag32()
293*1b3f573fSAndroid Build Coastguard Worker         {
294*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(0));
295*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(1));
296*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(2));
297*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag32(3));
298*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0x3FFFFFFF, ParsingPrimitives.DecodeZigZag32(0x7FFFFFFE));
299*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(unchecked((int) 0xC0000000), ParsingPrimitives.DecodeZigZag32(0x7FFFFFFF));
300*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0x7FFFFFFF, ParsingPrimitives.DecodeZigZag32(0xFFFFFFFE));
301*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(unchecked((int) 0x80000000), ParsingPrimitives.DecodeZigZag32(0xFFFFFFFF));
302*1b3f573fSAndroid Build Coastguard Worker         }
303*1b3f573fSAndroid Build Coastguard Worker 
304*1b3f573fSAndroid Build Coastguard Worker         [Test]
DecodeZigZag64()305*1b3f573fSAndroid Build Coastguard Worker         public void DecodeZigZag64()
306*1b3f573fSAndroid Build Coastguard Worker         {
307*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(0));
308*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(1));
309*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(2));
310*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag64(3));
311*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0x000000003FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFEL));
312*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(unchecked((long) 0xFFFFFFFFC0000000L), ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFFL));
313*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0x000000007FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFEL));
314*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(unchecked((long) 0xFFFFFFFF80000000L), ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFFL));
315*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0x7FFFFFFFFFFFFFFFL, ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFEL));
316*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(unchecked((long) 0x8000000000000000L), ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFFL));
317*1b3f573fSAndroid Build Coastguard Worker         }
318*1b3f573fSAndroid Build Coastguard Worker 
319*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadWholeMessage_VaryingBlockSizes()320*1b3f573fSAndroid Build Coastguard Worker         public void ReadWholeMessage_VaryingBlockSizes()
321*1b3f573fSAndroid Build Coastguard Worker         {
322*1b3f573fSAndroid Build Coastguard Worker             TestAllTypes message = SampleMessages.CreateFullTestAllTypes();
323*1b3f573fSAndroid Build Coastguard Worker 
324*1b3f573fSAndroid Build Coastguard Worker             byte[] rawBytes = message.ToByteArray();
325*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(rawBytes.Length, message.CalculateSize());
326*1b3f573fSAndroid Build Coastguard Worker             TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes);
327*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(message, message2);
328*1b3f573fSAndroid Build Coastguard Worker 
329*1b3f573fSAndroid Build Coastguard Worker             // Try different block sizes.
330*1b3f573fSAndroid Build Coastguard Worker             for (int blockSize = 1; blockSize < 256; blockSize *= 2)
331*1b3f573fSAndroid Build Coastguard Worker             {
332*1b3f573fSAndroid Build Coastguard Worker                 message2 = TestAllTypes.Parser.ParseFrom(new SmallBlockInputStream(rawBytes, blockSize));
333*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(message, message2);
334*1b3f573fSAndroid Build Coastguard Worker             }
335*1b3f573fSAndroid Build Coastguard Worker         }
336*1b3f573fSAndroid Build Coastguard Worker 
337*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadWholeMessage_VaryingBlockSizes_FromSequence()338*1b3f573fSAndroid Build Coastguard Worker         public void ReadWholeMessage_VaryingBlockSizes_FromSequence()
339*1b3f573fSAndroid Build Coastguard Worker         {
340*1b3f573fSAndroid Build Coastguard Worker             TestAllTypes message = SampleMessages.CreateFullTestAllTypes();
341*1b3f573fSAndroid Build Coastguard Worker 
342*1b3f573fSAndroid Build Coastguard Worker             byte[] rawBytes = message.ToByteArray();
343*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(rawBytes.Length, message.CalculateSize());
344*1b3f573fSAndroid Build Coastguard Worker             TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes);
345*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(message, message2);
346*1b3f573fSAndroid Build Coastguard Worker 
347*1b3f573fSAndroid Build Coastguard Worker             // Try different block sizes.
348*1b3f573fSAndroid Build Coastguard Worker             for (int blockSize = 1; blockSize < 256; blockSize *= 2)
349*1b3f573fSAndroid Build Coastguard Worker             {
350*1b3f573fSAndroid Build Coastguard Worker                 message2 = TestAllTypes.Parser.ParseFrom(ReadOnlySequenceFactory.CreateWithContent(rawBytes, blockSize));
351*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(message, message2);
352*1b3f573fSAndroid Build Coastguard Worker             }
353*1b3f573fSAndroid Build Coastguard Worker         }
354*1b3f573fSAndroid Build Coastguard Worker 
355*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadInt32Wrapper_VariableBlockSizes()356*1b3f573fSAndroid Build Coastguard Worker         public void ReadInt32Wrapper_VariableBlockSizes()
357*1b3f573fSAndroid Build Coastguard Worker         {
358*1b3f573fSAndroid Build Coastguard Worker             byte[] rawBytes = new byte[] { 202, 1, 11, 8, 254, 255, 255, 255, 255, 255, 255, 255, 255, 1 };
359*1b3f573fSAndroid Build Coastguard Worker 
360*1b3f573fSAndroid Build Coastguard Worker             for (int blockSize = 1; blockSize <= rawBytes.Length; blockSize++)
361*1b3f573fSAndroid Build Coastguard Worker             {
362*1b3f573fSAndroid Build Coastguard Worker                 ReadOnlySequence<byte> data = ReadOnlySequenceFactory.CreateWithContent(rawBytes, blockSize);
363*1b3f573fSAndroid Build Coastguard Worker                 AssertReadFromParseContext(data, (ref ParseContext ctx) =>
364*1b3f573fSAndroid Build Coastguard Worker                 {
365*1b3f573fSAndroid Build Coastguard Worker                     ctx.ReadTag();
366*1b3f573fSAndroid Build Coastguard Worker 
367*1b3f573fSAndroid Build Coastguard Worker                     var value = ParsingPrimitivesWrappers.ReadInt32Wrapper(ref ctx);
368*1b3f573fSAndroid Build Coastguard Worker 
369*1b3f573fSAndroid Build Coastguard Worker                     Assert.AreEqual(-2, value);
370*1b3f573fSAndroid Build Coastguard Worker                 }, true);
371*1b3f573fSAndroid Build Coastguard Worker             }
372*1b3f573fSAndroid Build Coastguard Worker         }
373*1b3f573fSAndroid Build Coastguard Worker 
374*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadHugeBlob()375*1b3f573fSAndroid Build Coastguard Worker         public void ReadHugeBlob()
376*1b3f573fSAndroid Build Coastguard Worker         {
377*1b3f573fSAndroid Build Coastguard Worker             // Allocate and initialize a 1MB blob.
378*1b3f573fSAndroid Build Coastguard Worker             byte[] blob = new byte[1 << 20];
379*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < blob.Length; i++)
380*1b3f573fSAndroid Build Coastguard Worker             {
381*1b3f573fSAndroid Build Coastguard Worker                 blob[i] = (byte) i;
382*1b3f573fSAndroid Build Coastguard Worker             }
383*1b3f573fSAndroid Build Coastguard Worker 
384*1b3f573fSAndroid Build Coastguard Worker             // Make a message containing it.
385*1b3f573fSAndroid Build Coastguard Worker             var message = new TestAllTypes { SingleBytes = ByteString.CopyFrom(blob) };
386*1b3f573fSAndroid Build Coastguard Worker 
387*1b3f573fSAndroid Build Coastguard Worker             // Serialize and parse it.  Make sure to parse from an InputStream, not
388*1b3f573fSAndroid Build Coastguard Worker             // directly from a ByteString, so that CodedInputStream uses buffered
389*1b3f573fSAndroid Build Coastguard Worker             // reading.
390*1b3f573fSAndroid Build Coastguard Worker             TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(message.ToByteString());
391*1b3f573fSAndroid Build Coastguard Worker 
392*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(message, message2);
393*1b3f573fSAndroid Build Coastguard Worker         }
394*1b3f573fSAndroid Build Coastguard Worker 
395*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadMaliciouslyLargeBlob()396*1b3f573fSAndroid Build Coastguard Worker         public void ReadMaliciouslyLargeBlob()
397*1b3f573fSAndroid Build Coastguard Worker         {
398*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
399*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
400*1b3f573fSAndroid Build Coastguard Worker 
401*1b3f573fSAndroid Build Coastguard Worker             uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
402*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(tag);
403*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(0x7FFFFFFF);
404*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawBytes(new byte[32]); // Pad with a few random bytes.
405*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
406*1b3f573fSAndroid Build Coastguard Worker             ms.Position = 0;
407*1b3f573fSAndroid Build Coastguard Worker 
408*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(ms);
409*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(tag, input.ReadTag());
410*1b3f573fSAndroid Build Coastguard Worker 
411*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => input.ReadBytes());
412*1b3f573fSAndroid Build Coastguard Worker         }
413*1b3f573fSAndroid Build Coastguard Worker 
414*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadBlobGreaterThanCurrentLimit()415*1b3f573fSAndroid Build Coastguard Worker         public void ReadBlobGreaterThanCurrentLimit()
416*1b3f573fSAndroid Build Coastguard Worker         {
417*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
418*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
419*1b3f573fSAndroid Build Coastguard Worker             uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
420*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(tag);
421*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(4);
422*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawBytes(new byte[4]); // Pad with a few random bytes.
423*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
424*1b3f573fSAndroid Build Coastguard Worker             ms.Position = 0;
425*1b3f573fSAndroid Build Coastguard Worker 
426*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(ms);
427*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(tag, input.ReadTag());
428*1b3f573fSAndroid Build Coastguard Worker 
429*1b3f573fSAndroid Build Coastguard Worker             // Specify limit smaller than data length
430*1b3f573fSAndroid Build Coastguard Worker             input.PushLimit(3);
431*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => input.ReadBytes());
432*1b3f573fSAndroid Build Coastguard Worker 
433*1b3f573fSAndroid Build Coastguard Worker             AssertReadFromParseContext(new ReadOnlySequence<byte>(ms.ToArray()), (ref ParseContext ctx) =>
434*1b3f573fSAndroid Build Coastguard Worker             {
435*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(tag, ctx.ReadTag());
436*1b3f573fSAndroid Build Coastguard Worker                 SegmentedBufferHelper.PushLimit(ref ctx.state, 3);
437*1b3f573fSAndroid Build Coastguard Worker                 try
438*1b3f573fSAndroid Build Coastguard Worker                 {
439*1b3f573fSAndroid Build Coastguard Worker                     ctx.ReadBytes();
440*1b3f573fSAndroid Build Coastguard Worker                     Assert.Fail();
441*1b3f573fSAndroid Build Coastguard Worker                 }
442*1b3f573fSAndroid Build Coastguard Worker                 catch (InvalidProtocolBufferException) {}
443*1b3f573fSAndroid Build Coastguard Worker             }, true);
444*1b3f573fSAndroid Build Coastguard Worker         }
445*1b3f573fSAndroid Build Coastguard Worker 
446*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadStringGreaterThanCurrentLimit()447*1b3f573fSAndroid Build Coastguard Worker         public void ReadStringGreaterThanCurrentLimit()
448*1b3f573fSAndroid Build Coastguard Worker         {
449*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
450*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
451*1b3f573fSAndroid Build Coastguard Worker             uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
452*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(tag);
453*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(4);
454*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawBytes(new byte[4]); // Pad with a few random bytes.
455*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
456*1b3f573fSAndroid Build Coastguard Worker             ms.Position = 0;
457*1b3f573fSAndroid Build Coastguard Worker 
458*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(ms.ToArray());
459*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(tag, input.ReadTag());
460*1b3f573fSAndroid Build Coastguard Worker 
461*1b3f573fSAndroid Build Coastguard Worker             // Specify limit smaller than data length
462*1b3f573fSAndroid Build Coastguard Worker             input.PushLimit(3);
463*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => input.ReadString());
464*1b3f573fSAndroid Build Coastguard Worker 
465*1b3f573fSAndroid Build Coastguard Worker             AssertReadFromParseContext(new ReadOnlySequence<byte>(ms.ToArray()), (ref ParseContext ctx) =>
466*1b3f573fSAndroid Build Coastguard Worker             {
467*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(tag, ctx.ReadTag());
468*1b3f573fSAndroid Build Coastguard Worker                 SegmentedBufferHelper.PushLimit(ref ctx.state, 3);
469*1b3f573fSAndroid Build Coastguard Worker                 try
470*1b3f573fSAndroid Build Coastguard Worker                 {
471*1b3f573fSAndroid Build Coastguard Worker                     ctx.ReadString();
472*1b3f573fSAndroid Build Coastguard Worker                     Assert.Fail();
473*1b3f573fSAndroid Build Coastguard Worker                 }
474*1b3f573fSAndroid Build Coastguard Worker                 catch (InvalidProtocolBufferException) { }
475*1b3f573fSAndroid Build Coastguard Worker             }, true);
476*1b3f573fSAndroid Build Coastguard Worker         }
477*1b3f573fSAndroid Build Coastguard Worker 
478*1b3f573fSAndroid Build Coastguard Worker         // Representations of a tag for field 0 with various wire types
479*1b3f573fSAndroid Build Coastguard Worker         [Test]
480*1b3f573fSAndroid Build Coastguard Worker         [TestCase(0)]
481*1b3f573fSAndroid Build Coastguard Worker         [TestCase(1)]
482*1b3f573fSAndroid Build Coastguard Worker         [TestCase(2)]
483*1b3f573fSAndroid Build Coastguard Worker         [TestCase(3)]
484*1b3f573fSAndroid Build Coastguard Worker         [TestCase(4)]
485*1b3f573fSAndroid Build Coastguard Worker         [TestCase(5)]
ReadTag_ZeroFieldRejected(byte tag)486*1b3f573fSAndroid Build Coastguard Worker         public void ReadTag_ZeroFieldRejected(byte tag)
487*1b3f573fSAndroid Build Coastguard Worker         {
488*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream cis = new CodedInputStream(new byte[] { tag });
489*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => cis.ReadTag());
490*1b3f573fSAndroid Build Coastguard Worker         }
491*1b3f573fSAndroid Build Coastguard Worker 
MakeRecursiveMessage(int depth)492*1b3f573fSAndroid Build Coastguard Worker         internal static TestRecursiveMessage MakeRecursiveMessage(int depth)
493*1b3f573fSAndroid Build Coastguard Worker         {
494*1b3f573fSAndroid Build Coastguard Worker             if (depth == 0)
495*1b3f573fSAndroid Build Coastguard Worker             {
496*1b3f573fSAndroid Build Coastguard Worker                 return new TestRecursiveMessage { I = 5 };
497*1b3f573fSAndroid Build Coastguard Worker             }
498*1b3f573fSAndroid Build Coastguard Worker             else
499*1b3f573fSAndroid Build Coastguard Worker             {
500*1b3f573fSAndroid Build Coastguard Worker                 return new TestRecursiveMessage { A = MakeRecursiveMessage(depth - 1) };
501*1b3f573fSAndroid Build Coastguard Worker             }
502*1b3f573fSAndroid Build Coastguard Worker         }
503*1b3f573fSAndroid Build Coastguard Worker 
AssertMessageDepth(TestRecursiveMessage message, int depth)504*1b3f573fSAndroid Build Coastguard Worker         internal static void AssertMessageDepth(TestRecursiveMessage message, int depth)
505*1b3f573fSAndroid Build Coastguard Worker         {
506*1b3f573fSAndroid Build Coastguard Worker             if (depth == 0)
507*1b3f573fSAndroid Build Coastguard Worker             {
508*1b3f573fSAndroid Build Coastguard Worker                 Assert.IsNull(message.A);
509*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(5, message.I);
510*1b3f573fSAndroid Build Coastguard Worker             }
511*1b3f573fSAndroid Build Coastguard Worker             else
512*1b3f573fSAndroid Build Coastguard Worker             {
513*1b3f573fSAndroid Build Coastguard Worker                 Assert.IsNotNull(message.A);
514*1b3f573fSAndroid Build Coastguard Worker                 AssertMessageDepth(message.A, depth - 1);
515*1b3f573fSAndroid Build Coastguard Worker             }
516*1b3f573fSAndroid Build Coastguard Worker         }
517*1b3f573fSAndroid Build Coastguard Worker 
518*1b3f573fSAndroid Build Coastguard Worker         [Test]
MaliciousRecursion()519*1b3f573fSAndroid Build Coastguard Worker         public void MaliciousRecursion()
520*1b3f573fSAndroid Build Coastguard Worker         {
521*1b3f573fSAndroid Build Coastguard Worker             ByteString atRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit).ToByteString();
522*1b3f573fSAndroid Build Coastguard Worker             ByteString beyondRecursiveLimit = MakeRecursiveMessage(CodedInputStream.DefaultRecursionLimit + 1).ToByteString();
523*1b3f573fSAndroid Build Coastguard Worker 
524*1b3f573fSAndroid Build Coastguard Worker             AssertMessageDepth(TestRecursiveMessage.Parser.ParseFrom(atRecursiveLimit), CodedInputStream.DefaultRecursionLimit);
525*1b3f573fSAndroid Build Coastguard Worker 
526*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => TestRecursiveMessage.Parser.ParseFrom(beyondRecursiveLimit));
527*1b3f573fSAndroid Build Coastguard Worker 
528*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = CodedInputStream.CreateWithLimits(new MemoryStream(atRecursiveLimit.ToByteArray()), 1000000, CodedInputStream.DefaultRecursionLimit - 1);
529*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => TestRecursiveMessage.Parser.ParseFrom(input));
530*1b3f573fSAndroid Build Coastguard Worker         }
531*1b3f573fSAndroid Build Coastguard Worker 
MakeMaliciousRecursionUnknownFieldsPayload(int recursionDepth)532*1b3f573fSAndroid Build Coastguard Worker         private static byte[] MakeMaliciousRecursionUnknownFieldsPayload(int recursionDepth)
533*1b3f573fSAndroid Build Coastguard Worker         {
534*1b3f573fSAndroid Build Coastguard Worker             // generate recursively nested groups that will be parsed as unknown fields
535*1b3f573fSAndroid Build Coastguard Worker             int unknownFieldNumber = 14;  // an unused field number
536*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
537*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
538*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < recursionDepth; i++)
539*1b3f573fSAndroid Build Coastguard Worker             {
540*1b3f573fSAndroid Build Coastguard Worker                 output.WriteTag(WireFormat.MakeTag(unknownFieldNumber, WireFormat.WireType.StartGroup));
541*1b3f573fSAndroid Build Coastguard Worker             }
542*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < recursionDepth; i++)
543*1b3f573fSAndroid Build Coastguard Worker             {
544*1b3f573fSAndroid Build Coastguard Worker                 output.WriteTag(WireFormat.MakeTag(unknownFieldNumber, WireFormat.WireType.EndGroup));
545*1b3f573fSAndroid Build Coastguard Worker             }
546*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
547*1b3f573fSAndroid Build Coastguard Worker             return ms.ToArray();
548*1b3f573fSAndroid Build Coastguard Worker         }
549*1b3f573fSAndroid Build Coastguard Worker 
550*1b3f573fSAndroid Build Coastguard Worker         [Test]
MaliciousRecursion_UnknownFields()551*1b3f573fSAndroid Build Coastguard Worker         public void MaliciousRecursion_UnknownFields()
552*1b3f573fSAndroid Build Coastguard Worker         {
553*1b3f573fSAndroid Build Coastguard Worker             byte[] payloadAtRecursiveLimit = MakeMaliciousRecursionUnknownFieldsPayload(CodedInputStream.DefaultRecursionLimit);
554*1b3f573fSAndroid Build Coastguard Worker             byte[] payloadBeyondRecursiveLimit = MakeMaliciousRecursionUnknownFieldsPayload(CodedInputStream.DefaultRecursionLimit + 1);
555*1b3f573fSAndroid Build Coastguard Worker 
556*1b3f573fSAndroid Build Coastguard Worker             Assert.DoesNotThrow(() => TestRecursiveMessage.Parser.ParseFrom(payloadAtRecursiveLimit));
557*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => TestRecursiveMessage.Parser.ParseFrom(payloadBeyondRecursiveLimit));
558*1b3f573fSAndroid Build Coastguard Worker         }
559*1b3f573fSAndroid Build Coastguard Worker 
560*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadGroup_WrongEndGroupTag()561*1b3f573fSAndroid Build Coastguard Worker         public void ReadGroup_WrongEndGroupTag()
562*1b3f573fSAndroid Build Coastguard Worker         {
563*1b3f573fSAndroid Build Coastguard Worker             int groupFieldNumber = Proto2.TestAllTypes.OptionalGroupFieldNumber;
564*1b3f573fSAndroid Build Coastguard Worker 
565*1b3f573fSAndroid Build Coastguard Worker             // write Proto2.TestAllTypes with "optional_group" set, but use wrong EndGroup closing tag
566*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
567*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
568*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(WireFormat.MakeTag(groupFieldNumber, WireFormat.WireType.StartGroup));
569*1b3f573fSAndroid Build Coastguard Worker             output.WriteGroup(new Proto2.TestAllTypes.Types.OptionalGroup { A = 12345 });
570*1b3f573fSAndroid Build Coastguard Worker             // end group with different field number
571*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(WireFormat.MakeTag(groupFieldNumber + 1, WireFormat.WireType.EndGroup));
572*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
573*1b3f573fSAndroid Build Coastguard Worker             var payload = ms.ToArray();
574*1b3f573fSAndroid Build Coastguard Worker 
575*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => Proto2.TestAllTypes.Parser.ParseFrom(payload));
576*1b3f573fSAndroid Build Coastguard Worker         }
577*1b3f573fSAndroid Build Coastguard Worker 
578*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadGroup_UnknownFields_WrongEndGroupTag()579*1b3f573fSAndroid Build Coastguard Worker         public void ReadGroup_UnknownFields_WrongEndGroupTag()
580*1b3f573fSAndroid Build Coastguard Worker         {
581*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
582*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
583*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(WireFormat.MakeTag(14, WireFormat.WireType.StartGroup));
584*1b3f573fSAndroid Build Coastguard Worker             // end group with different field number
585*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(WireFormat.MakeTag(15, WireFormat.WireType.EndGroup));
586*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
587*1b3f573fSAndroid Build Coastguard Worker             var payload = ms.ToArray();
588*1b3f573fSAndroid Build Coastguard Worker 
589*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => TestRecursiveMessage.Parser.ParseFrom(payload));
590*1b3f573fSAndroid Build Coastguard Worker         }
591*1b3f573fSAndroid Build Coastguard Worker 
592*1b3f573fSAndroid Build Coastguard Worker         [Test]
SizeLimit()593*1b3f573fSAndroid Build Coastguard Worker         public void SizeLimit()
594*1b3f573fSAndroid Build Coastguard Worker         {
595*1b3f573fSAndroid Build Coastguard Worker             // Have to use a Stream rather than ByteString.CreateCodedInput as SizeLimit doesn't
596*1b3f573fSAndroid Build Coastguard Worker             // apply to the latter case.
597*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream(SampleMessages.CreateFullTestAllTypes().ToByteArray());
598*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = CodedInputStream.CreateWithLimits(ms, 16, 100);
599*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(input));
600*1b3f573fSAndroid Build Coastguard Worker         }
601*1b3f573fSAndroid Build Coastguard Worker 
602*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
603*1b3f573fSAndroid Build Coastguard Worker         /// Tests that if we read an string that contains invalid UTF-8, no exception
604*1b3f573fSAndroid Build Coastguard Worker         /// is thrown.  Instead, the invalid bytes are replaced with the Unicode
605*1b3f573fSAndroid Build Coastguard Worker         /// "replacement character" U+FFFD.
606*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
607*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadInvalidUtf8()608*1b3f573fSAndroid Build Coastguard Worker         public void ReadInvalidUtf8()
609*1b3f573fSAndroid Build Coastguard Worker         {
610*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
611*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
612*1b3f573fSAndroid Build Coastguard Worker 
613*1b3f573fSAndroid Build Coastguard Worker             uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
614*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(tag);
615*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(1);
616*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawBytes(new byte[] {0x80});
617*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
618*1b3f573fSAndroid Build Coastguard Worker             ms.Position = 0;
619*1b3f573fSAndroid Build Coastguard Worker 
620*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(ms);
621*1b3f573fSAndroid Build Coastguard Worker 
622*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(tag, input.ReadTag());
623*1b3f573fSAndroid Build Coastguard Worker             string text = input.ReadString();
624*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual('\ufffd', text[0]);
625*1b3f573fSAndroid Build Coastguard Worker         }
626*1b3f573fSAndroid Build Coastguard Worker 
627*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadNegativeSizedStringThrowsInvalidProtocolBufferException()628*1b3f573fSAndroid Build Coastguard Worker         public void ReadNegativeSizedStringThrowsInvalidProtocolBufferException()
629*1b3f573fSAndroid Build Coastguard Worker         {
630*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
631*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
632*1b3f573fSAndroid Build Coastguard Worker 
633*1b3f573fSAndroid Build Coastguard Worker             uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
634*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(tag);
635*1b3f573fSAndroid Build Coastguard Worker             output.WriteLength(-1);
636*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
637*1b3f573fSAndroid Build Coastguard Worker             ms.Position = 0;
638*1b3f573fSAndroid Build Coastguard Worker 
639*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(ms);
640*1b3f573fSAndroid Build Coastguard Worker 
641*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(tag, input.ReadTag());
642*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => input.ReadString());
643*1b3f573fSAndroid Build Coastguard Worker         }
644*1b3f573fSAndroid Build Coastguard Worker 
645*1b3f573fSAndroid Build Coastguard Worker         [Test]
ReadNegativeSizedBytesThrowsInvalidProtocolBufferException()646*1b3f573fSAndroid Build Coastguard Worker         public void ReadNegativeSizedBytesThrowsInvalidProtocolBufferException()
647*1b3f573fSAndroid Build Coastguard Worker         {
648*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
649*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
650*1b3f573fSAndroid Build Coastguard Worker 
651*1b3f573fSAndroid Build Coastguard Worker             uint tag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
652*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(tag);
653*1b3f573fSAndroid Build Coastguard Worker             output.WriteLength(-1);
654*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
655*1b3f573fSAndroid Build Coastguard Worker             ms.Position = 0;
656*1b3f573fSAndroid Build Coastguard Worker 
657*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(ms);
658*1b3f573fSAndroid Build Coastguard Worker 
659*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(tag, input.ReadTag());
660*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => input.ReadBytes());
661*1b3f573fSAndroid Build Coastguard Worker         }
662*1b3f573fSAndroid Build Coastguard Worker 
663*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
664*1b3f573fSAndroid Build Coastguard Worker         /// A stream which limits the number of bytes it reads at a time.
665*1b3f573fSAndroid Build Coastguard Worker         /// We use this to make sure that CodedInputStream doesn't screw up when
666*1b3f573fSAndroid Build Coastguard Worker         /// reading in small blocks.
667*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
668*1b3f573fSAndroid Build Coastguard Worker         private sealed class SmallBlockInputStream : MemoryStream
669*1b3f573fSAndroid Build Coastguard Worker         {
670*1b3f573fSAndroid Build Coastguard Worker             private readonly int blockSize;
671*1b3f573fSAndroid Build Coastguard Worker 
SmallBlockInputStream(byte[] data, int blockSize)672*1b3f573fSAndroid Build Coastguard Worker             public SmallBlockInputStream(byte[] data, int blockSize)
673*1b3f573fSAndroid Build Coastguard Worker                 : base(data)
674*1b3f573fSAndroid Build Coastguard Worker             {
675*1b3f573fSAndroid Build Coastguard Worker                 this.blockSize = blockSize;
676*1b3f573fSAndroid Build Coastguard Worker             }
677*1b3f573fSAndroid Build Coastguard Worker 
Read(byte[] buffer, int offset, int count)678*1b3f573fSAndroid Build Coastguard Worker             public override int Read(byte[] buffer, int offset, int count)
679*1b3f573fSAndroid Build Coastguard Worker             {
680*1b3f573fSAndroid Build Coastguard Worker                 return base.Read(buffer, offset, Math.Min(count, blockSize));
681*1b3f573fSAndroid Build Coastguard Worker             }
682*1b3f573fSAndroid Build Coastguard Worker         }
683*1b3f573fSAndroid Build Coastguard Worker 
684*1b3f573fSAndroid Build Coastguard Worker         [Test]
TestNegativeEnum()685*1b3f573fSAndroid Build Coastguard Worker         public void TestNegativeEnum()
686*1b3f573fSAndroid Build Coastguard Worker         {
687*1b3f573fSAndroid Build Coastguard Worker             byte[] bytes = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 };
688*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(bytes);
689*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual((int)SampleEnum.NegativeValue, input.ReadEnum());
690*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(input.IsAtEnd);
691*1b3f573fSAndroid Build Coastguard Worker         }
692*1b3f573fSAndroid Build Coastguard Worker 
693*1b3f573fSAndroid Build Coastguard Worker         //Issue 71:	CodedInputStream.ReadBytes go to slow path unnecessarily
694*1b3f573fSAndroid Build Coastguard Worker         [Test]
TestSlowPathAvoidance()695*1b3f573fSAndroid Build Coastguard Worker         public void TestSlowPathAvoidance()
696*1b3f573fSAndroid Build Coastguard Worker         {
697*1b3f573fSAndroid Build Coastguard Worker             using (var ms = new MemoryStream())
698*1b3f573fSAndroid Build Coastguard Worker             {
699*1b3f573fSAndroid Build Coastguard Worker                 CodedOutputStream output = new CodedOutputStream(ms);
700*1b3f573fSAndroid Build Coastguard Worker                 output.WriteTag(1, WireFormat.WireType.LengthDelimited);
701*1b3f573fSAndroid Build Coastguard Worker                 output.WriteBytes(ByteString.CopyFrom(new byte[100]));
702*1b3f573fSAndroid Build Coastguard Worker                 output.WriteTag(2, WireFormat.WireType.LengthDelimited);
703*1b3f573fSAndroid Build Coastguard Worker                 output.WriteBytes(ByteString.CopyFrom(new byte[100]));
704*1b3f573fSAndroid Build Coastguard Worker                 output.Flush();
705*1b3f573fSAndroid Build Coastguard Worker 
706*1b3f573fSAndroid Build Coastguard Worker                 ms.Position = 0;
707*1b3f573fSAndroid Build Coastguard Worker                 CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false);
708*1b3f573fSAndroid Build Coastguard Worker 
709*1b3f573fSAndroid Build Coastguard Worker                 uint tag = input.ReadTag();
710*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag));
711*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(100, input.ReadBytes().Length);
712*1b3f573fSAndroid Build Coastguard Worker 
713*1b3f573fSAndroid Build Coastguard Worker                 tag = input.ReadTag();
714*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag));
715*1b3f573fSAndroid Build Coastguard Worker                 Assert.AreEqual(100, input.ReadBytes().Length);
716*1b3f573fSAndroid Build Coastguard Worker             }
717*1b3f573fSAndroid Build Coastguard Worker         }
718*1b3f573fSAndroid Build Coastguard Worker 
719*1b3f573fSAndroid Build Coastguard Worker         [Test]
MaximumFieldNumber()720*1b3f573fSAndroid Build Coastguard Worker         public void MaximumFieldNumber()
721*1b3f573fSAndroid Build Coastguard Worker         {
722*1b3f573fSAndroid Build Coastguard Worker             MemoryStream ms = new MemoryStream();
723*1b3f573fSAndroid Build Coastguard Worker             CodedOutputStream output = new CodedOutputStream(ms);
724*1b3f573fSAndroid Build Coastguard Worker 
725*1b3f573fSAndroid Build Coastguard Worker             int fieldNumber = 0x1FFFFFFF;
726*1b3f573fSAndroid Build Coastguard Worker             uint tag = WireFormat.MakeTag(fieldNumber, WireFormat.WireType.LengthDelimited);
727*1b3f573fSAndroid Build Coastguard Worker             output.WriteRawVarint32(tag);
728*1b3f573fSAndroid Build Coastguard Worker             output.WriteString("field 1");
729*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
730*1b3f573fSAndroid Build Coastguard Worker             ms.Position = 0;
731*1b3f573fSAndroid Build Coastguard Worker 
732*1b3f573fSAndroid Build Coastguard Worker             CodedInputStream input = new CodedInputStream(ms);
733*1b3f573fSAndroid Build Coastguard Worker 
734*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(tag, input.ReadTag());
735*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(fieldNumber, WireFormat.GetTagFieldNumber(tag));
736*1b3f573fSAndroid Build Coastguard Worker         }
737*1b3f573fSAndroid Build Coastguard Worker 
738*1b3f573fSAndroid Build Coastguard Worker         [Test]
Tag0Throws()739*1b3f573fSAndroid Build Coastguard Worker         public void Tag0Throws()
740*1b3f573fSAndroid Build Coastguard Worker         {
741*1b3f573fSAndroid Build Coastguard Worker             var input = new CodedInputStream(new byte[] { 0 });
742*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(() => input.ReadTag());
743*1b3f573fSAndroid Build Coastguard Worker         }
744*1b3f573fSAndroid Build Coastguard Worker 
745*1b3f573fSAndroid Build Coastguard Worker         [Test]
SkipGroup()746*1b3f573fSAndroid Build Coastguard Worker         public void SkipGroup()
747*1b3f573fSAndroid Build Coastguard Worker         {
748*1b3f573fSAndroid Build Coastguard Worker             // Create an output stream with a group in:
749*1b3f573fSAndroid Build Coastguard Worker             // Field 1: string "field 1"
750*1b3f573fSAndroid Build Coastguard Worker             // Field 2: group containing:
751*1b3f573fSAndroid Build Coastguard Worker             //   Field 1: fixed int32 value 100
752*1b3f573fSAndroid Build Coastguard Worker             //   Field 2: string "ignore me"
753*1b3f573fSAndroid Build Coastguard Worker             //   Field 3: nested group containing
754*1b3f573fSAndroid Build Coastguard Worker             //      Field 1: fixed int64 value 1000
755*1b3f573fSAndroid Build Coastguard Worker             // Field 3: string "field 3"
756*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream();
757*1b3f573fSAndroid Build Coastguard Worker             var output = new CodedOutputStream(stream);
758*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(1, WireFormat.WireType.LengthDelimited);
759*1b3f573fSAndroid Build Coastguard Worker             output.WriteString("field 1");
760*1b3f573fSAndroid Build Coastguard Worker 
761*1b3f573fSAndroid Build Coastguard Worker             // The outer group...
762*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(2, WireFormat.WireType.StartGroup);
763*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(1, WireFormat.WireType.Fixed32);
764*1b3f573fSAndroid Build Coastguard Worker             output.WriteFixed32(100);
765*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(2, WireFormat.WireType.LengthDelimited);
766*1b3f573fSAndroid Build Coastguard Worker             output.WriteString("ignore me");
767*1b3f573fSAndroid Build Coastguard Worker             // The nested group...
768*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(3, WireFormat.WireType.StartGroup);
769*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(1, WireFormat.WireType.Fixed64);
770*1b3f573fSAndroid Build Coastguard Worker             output.WriteFixed64(1000);
771*1b3f573fSAndroid Build Coastguard Worker             // Note: Not sure the field number is relevant for end group...
772*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(3, WireFormat.WireType.EndGroup);
773*1b3f573fSAndroid Build Coastguard Worker 
774*1b3f573fSAndroid Build Coastguard Worker             // End the outer group
775*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(2, WireFormat.WireType.EndGroup);
776*1b3f573fSAndroid Build Coastguard Worker 
777*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(3, WireFormat.WireType.LengthDelimited);
778*1b3f573fSAndroid Build Coastguard Worker             output.WriteString("field 3");
779*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
780*1b3f573fSAndroid Build Coastguard Worker             stream.Position = 0;
781*1b3f573fSAndroid Build Coastguard Worker 
782*1b3f573fSAndroid Build Coastguard Worker             // Now act like a generated client
783*1b3f573fSAndroid Build Coastguard Worker             var input = new CodedInputStream(stream);
784*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag());
785*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual("field 1", input.ReadString());
786*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag());
787*1b3f573fSAndroid Build Coastguard Worker             input.SkipLastField(); // Should consume the whole group, including the nested one.
788*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(WireFormat.MakeTag(3, WireFormat.WireType.LengthDelimited), input.ReadTag());
789*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual("field 3", input.ReadString());
790*1b3f573fSAndroid Build Coastguard Worker         }
791*1b3f573fSAndroid Build Coastguard Worker 
792*1b3f573fSAndroid Build Coastguard Worker         [Test]
SkipGroup_WrongEndGroupTag()793*1b3f573fSAndroid Build Coastguard Worker         public void SkipGroup_WrongEndGroupTag()
794*1b3f573fSAndroid Build Coastguard Worker         {
795*1b3f573fSAndroid Build Coastguard Worker             // Create an output stream with:
796*1b3f573fSAndroid Build Coastguard Worker             // Field 1: string "field 1"
797*1b3f573fSAndroid Build Coastguard Worker             // Start group 2
798*1b3f573fSAndroid Build Coastguard Worker             //   Field 3: fixed int32
799*1b3f573fSAndroid Build Coastguard Worker             // End group 4 (should give an error)
800*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream();
801*1b3f573fSAndroid Build Coastguard Worker             var output = new CodedOutputStream(stream);
802*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(1, WireFormat.WireType.LengthDelimited);
803*1b3f573fSAndroid Build Coastguard Worker             output.WriteString("field 1");
804*1b3f573fSAndroid Build Coastguard Worker 
805*1b3f573fSAndroid Build Coastguard Worker             // The outer group...
806*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(2, WireFormat.WireType.StartGroup);
807*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(3, WireFormat.WireType.Fixed32);
808*1b3f573fSAndroid Build Coastguard Worker             output.WriteFixed32(100);
809*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(4, WireFormat.WireType.EndGroup);
810*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
811*1b3f573fSAndroid Build Coastguard Worker             stream.Position = 0;
812*1b3f573fSAndroid Build Coastguard Worker 
813*1b3f573fSAndroid Build Coastguard Worker             // Now act like a generated client
814*1b3f573fSAndroid Build Coastguard Worker             var input = new CodedInputStream(stream);
815*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag());
816*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual("field 1", input.ReadString());
817*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag());
818*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);
819*1b3f573fSAndroid Build Coastguard Worker         }
820*1b3f573fSAndroid Build Coastguard Worker 
821*1b3f573fSAndroid Build Coastguard Worker         [Test]
RogueEndGroupTag()822*1b3f573fSAndroid Build Coastguard Worker         public void RogueEndGroupTag()
823*1b3f573fSAndroid Build Coastguard Worker         {
824*1b3f573fSAndroid Build Coastguard Worker             // If we have an end-group tag without a leading start-group tag, generated
825*1b3f573fSAndroid Build Coastguard Worker             // code will just call SkipLastField... so that should fail.
826*1b3f573fSAndroid Build Coastguard Worker 
827*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream();
828*1b3f573fSAndroid Build Coastguard Worker             var output = new CodedOutputStream(stream);
829*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(1, WireFormat.WireType.EndGroup);
830*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
831*1b3f573fSAndroid Build Coastguard Worker             stream.Position = 0;
832*1b3f573fSAndroid Build Coastguard Worker 
833*1b3f573fSAndroid Build Coastguard Worker             var input = new CodedInputStream(stream);
834*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.EndGroup), input.ReadTag());
835*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);
836*1b3f573fSAndroid Build Coastguard Worker         }
837*1b3f573fSAndroid Build Coastguard Worker 
838*1b3f573fSAndroid Build Coastguard Worker         [Test]
EndOfStreamReachedWhileSkippingGroup()839*1b3f573fSAndroid Build Coastguard Worker         public void EndOfStreamReachedWhileSkippingGroup()
840*1b3f573fSAndroid Build Coastguard Worker         {
841*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream();
842*1b3f573fSAndroid Build Coastguard Worker             var output = new CodedOutputStream(stream);
843*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(1, WireFormat.WireType.StartGroup);
844*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(2, WireFormat.WireType.StartGroup);
845*1b3f573fSAndroid Build Coastguard Worker             output.WriteTag(2, WireFormat.WireType.EndGroup);
846*1b3f573fSAndroid Build Coastguard Worker 
847*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
848*1b3f573fSAndroid Build Coastguard Worker             stream.Position = 0;
849*1b3f573fSAndroid Build Coastguard Worker 
850*1b3f573fSAndroid Build Coastguard Worker             // Now act like a generated client
851*1b3f573fSAndroid Build Coastguard Worker             var input = new CodedInputStream(stream);
852*1b3f573fSAndroid Build Coastguard Worker             input.ReadTag();
853*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);
854*1b3f573fSAndroid Build Coastguard Worker         }
855*1b3f573fSAndroid Build Coastguard Worker 
856*1b3f573fSAndroid Build Coastguard Worker         [Test]
RecursionLimitAppliedWhileSkippingGroup()857*1b3f573fSAndroid Build Coastguard Worker         public void RecursionLimitAppliedWhileSkippingGroup()
858*1b3f573fSAndroid Build Coastguard Worker         {
859*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream();
860*1b3f573fSAndroid Build Coastguard Worker             var output = new CodedOutputStream(stream);
861*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++)
862*1b3f573fSAndroid Build Coastguard Worker             {
863*1b3f573fSAndroid Build Coastguard Worker                 output.WriteTag(1, WireFormat.WireType.StartGroup);
864*1b3f573fSAndroid Build Coastguard Worker             }
865*1b3f573fSAndroid Build Coastguard Worker             for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++)
866*1b3f573fSAndroid Build Coastguard Worker             {
867*1b3f573fSAndroid Build Coastguard Worker                 output.WriteTag(1, WireFormat.WireType.EndGroup);
868*1b3f573fSAndroid Build Coastguard Worker             }
869*1b3f573fSAndroid Build Coastguard Worker             output.Flush();
870*1b3f573fSAndroid Build Coastguard Worker             stream.Position = 0;
871*1b3f573fSAndroid Build Coastguard Worker 
872*1b3f573fSAndroid Build Coastguard Worker             // Now act like a generated client
873*1b3f573fSAndroid Build Coastguard Worker             var input = new CodedInputStream(stream);
874*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag());
875*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<InvalidProtocolBufferException>(input.SkipLastField);
876*1b3f573fSAndroid Build Coastguard Worker         }
877*1b3f573fSAndroid Build Coastguard Worker 
878*1b3f573fSAndroid Build Coastguard Worker         [Test]
Construction_Invalid()879*1b3f573fSAndroid Build Coastguard Worker         public void Construction_Invalid()
880*1b3f573fSAndroid Build Coastguard Worker         {
881*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<ArgumentNullException>(() => new CodedInputStream((byte[]) null));
882*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<ArgumentNullException>(() => new CodedInputStream(null, 0, 0));
883*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<ArgumentNullException>(() => new CodedInputStream((Stream) null));
884*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<ArgumentOutOfRangeException>(() => new CodedInputStream(new byte[10], 100, 0));
885*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<ArgumentOutOfRangeException>(() => new CodedInputStream(new byte[10], 5, 10));
886*1b3f573fSAndroid Build Coastguard Worker         }
887*1b3f573fSAndroid Build Coastguard Worker 
888*1b3f573fSAndroid Build Coastguard Worker         [Test]
CreateWithLimits_InvalidLimits()889*1b3f573fSAndroid Build Coastguard Worker         public void CreateWithLimits_InvalidLimits()
890*1b3f573fSAndroid Build Coastguard Worker         {
891*1b3f573fSAndroid Build Coastguard Worker             var stream = new MemoryStream();
892*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<ArgumentOutOfRangeException>(() => CodedInputStream.CreateWithLimits(stream, 0, 1));
893*1b3f573fSAndroid Build Coastguard Worker             Assert.Throws<ArgumentOutOfRangeException>(() => CodedInputStream.CreateWithLimits(stream, 1, 0));
894*1b3f573fSAndroid Build Coastguard Worker         }
895*1b3f573fSAndroid Build Coastguard Worker 
896*1b3f573fSAndroid Build Coastguard Worker         [Test]
Dispose_DisposesUnderlyingStream()897*1b3f573fSAndroid Build Coastguard Worker         public void Dispose_DisposesUnderlyingStream()
898*1b3f573fSAndroid Build Coastguard Worker         {
899*1b3f573fSAndroid Build Coastguard Worker             var memoryStream = new MemoryStream();
900*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(memoryStream.CanRead);
901*1b3f573fSAndroid Build Coastguard Worker             using (var cis = new CodedInputStream(memoryStream))
902*1b3f573fSAndroid Build Coastguard Worker             {
903*1b3f573fSAndroid Build Coastguard Worker             }
904*1b3f573fSAndroid Build Coastguard Worker             Assert.IsFalse(memoryStream.CanRead); // Disposed
905*1b3f573fSAndroid Build Coastguard Worker         }
906*1b3f573fSAndroid Build Coastguard Worker 
907*1b3f573fSAndroid Build Coastguard Worker         [Test]
Dispose_WithLeaveOpen()908*1b3f573fSAndroid Build Coastguard Worker         public void Dispose_WithLeaveOpen()
909*1b3f573fSAndroid Build Coastguard Worker         {
910*1b3f573fSAndroid Build Coastguard Worker             var memoryStream = new MemoryStream();
911*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(memoryStream.CanRead);
912*1b3f573fSAndroid Build Coastguard Worker             using (var cis = new CodedInputStream(memoryStream, true))
913*1b3f573fSAndroid Build Coastguard Worker             {
914*1b3f573fSAndroid Build Coastguard Worker             }
915*1b3f573fSAndroid Build Coastguard Worker             Assert.IsTrue(memoryStream.CanRead); // We left the stream open
916*1b3f573fSAndroid Build Coastguard Worker         }
917*1b3f573fSAndroid Build Coastguard Worker 
918*1b3f573fSAndroid Build Coastguard Worker         [Test]
Dispose_FromByteArray()919*1b3f573fSAndroid Build Coastguard Worker         public void Dispose_FromByteArray()
920*1b3f573fSAndroid Build Coastguard Worker         {
921*1b3f573fSAndroid Build Coastguard Worker             var stream = new CodedInputStream(new byte[10]);
922*1b3f573fSAndroid Build Coastguard Worker             stream.Dispose();
923*1b3f573fSAndroid Build Coastguard Worker         }
924*1b3f573fSAndroid Build Coastguard Worker 
925*1b3f573fSAndroid Build Coastguard Worker         [Test]
TestParseMessagesCloseTo2G()926*1b3f573fSAndroid Build Coastguard Worker         public void TestParseMessagesCloseTo2G()
927*1b3f573fSAndroid Build Coastguard Worker         {
928*1b3f573fSAndroid Build Coastguard Worker             byte[] serializedMessage = GenerateBigSerializedMessage();
929*1b3f573fSAndroid Build Coastguard Worker             // How many of these big messages do we need to take us near our 2GB limit?
930*1b3f573fSAndroid Build Coastguard Worker             int count = Int32.MaxValue / serializedMessage.Length;
931*1b3f573fSAndroid Build Coastguard Worker             // Now make a MemoryStream that will fake a near-2GB stream of messages by returning
932*1b3f573fSAndroid Build Coastguard Worker             // our big serialized message 'count' times.
933*1b3f573fSAndroid Build Coastguard Worker             using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count))
934*1b3f573fSAndroid Build Coastguard Worker             {
935*1b3f573fSAndroid Build Coastguard Worker                 Assert.DoesNotThrow(()=>TestAllTypes.Parser.ParseFrom(stream));
936*1b3f573fSAndroid Build Coastguard Worker             }
937*1b3f573fSAndroid Build Coastguard Worker         }
938*1b3f573fSAndroid Build Coastguard Worker 
939*1b3f573fSAndroid Build Coastguard Worker         [Test]
TestParseMessagesOver2G()940*1b3f573fSAndroid Build Coastguard Worker         public void TestParseMessagesOver2G()
941*1b3f573fSAndroid Build Coastguard Worker         {
942*1b3f573fSAndroid Build Coastguard Worker             byte[] serializedMessage = GenerateBigSerializedMessage();
943*1b3f573fSAndroid Build Coastguard Worker             // How many of these big messages do we need to take us near our 2GB limit?
944*1b3f573fSAndroid Build Coastguard Worker             int count = Int32.MaxValue / serializedMessage.Length;
945*1b3f573fSAndroid Build Coastguard Worker             // Now add one to take us over the 2GB limit
946*1b3f573fSAndroid Build Coastguard Worker             count++;
947*1b3f573fSAndroid Build Coastguard Worker             // Now make a MemoryStream that will fake a near-2GB stream of messages by returning
948*1b3f573fSAndroid Build Coastguard Worker             // our big serialized message 'count' times.
949*1b3f573fSAndroid Build Coastguard Worker             using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count))
950*1b3f573fSAndroid Build Coastguard Worker             {
951*1b3f573fSAndroid Build Coastguard Worker                 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream),
952*1b3f573fSAndroid Build Coastguard Worker                     "Protocol message was too large.  May be malicious.  " +
953*1b3f573fSAndroid Build Coastguard Worker                     "Use CodedInputStream.SetSizeLimit() to increase the size limit.");
954*1b3f573fSAndroid Build Coastguard Worker             }
955*1b3f573fSAndroid Build Coastguard Worker         }
956*1b3f573fSAndroid Build Coastguard Worker 
957*1b3f573fSAndroid Build Coastguard Worker         /// <returns>A serialized big message</returns>
GenerateBigSerializedMessage()958*1b3f573fSAndroid Build Coastguard Worker         private static byte[] GenerateBigSerializedMessage()
959*1b3f573fSAndroid Build Coastguard Worker         {
960*1b3f573fSAndroid Build Coastguard Worker             byte[] value = new byte[16 * 1024 * 1024];
961*1b3f573fSAndroid Build Coastguard Worker             TestAllTypes message = SampleMessages.CreateFullTestAllTypes();
962*1b3f573fSAndroid Build Coastguard Worker             message.SingleBytes = ByteString.CopyFrom(value);
963*1b3f573fSAndroid Build Coastguard Worker             return message.ToByteArray();
964*1b3f573fSAndroid Build Coastguard Worker         }
965*1b3f573fSAndroid Build Coastguard Worker 
966*1b3f573fSAndroid Build Coastguard Worker         /// <summary>
967*1b3f573fSAndroid Build Coastguard Worker         /// A MemoryStream that repeats a byte arrays' content a number of times.
968*1b3f573fSAndroid Build Coastguard Worker         /// Simulates really large input without consuming loads of memory. Used above
969*1b3f573fSAndroid Build Coastguard Worker         /// to test the parsing behavior when the input size exceeds 2GB or close to it.
970*1b3f573fSAndroid Build Coastguard Worker         /// </summary>
971*1b3f573fSAndroid Build Coastguard Worker         private class RepeatingMemoryStream: MemoryStream
972*1b3f573fSAndroid Build Coastguard Worker         {
973*1b3f573fSAndroid Build Coastguard Worker             private readonly byte[] bytes;
974*1b3f573fSAndroid Build Coastguard Worker             private readonly int maxIterations;
975*1b3f573fSAndroid Build Coastguard Worker             private int index = 0;
976*1b3f573fSAndroid Build Coastguard Worker 
RepeatingMemoryStream(byte[] bytes, int maxIterations)977*1b3f573fSAndroid Build Coastguard Worker             public RepeatingMemoryStream(byte[] bytes, int maxIterations)
978*1b3f573fSAndroid Build Coastguard Worker             {
979*1b3f573fSAndroid Build Coastguard Worker                 this.bytes = bytes;
980*1b3f573fSAndroid Build Coastguard Worker                 this.maxIterations = maxIterations;
981*1b3f573fSAndroid Build Coastguard Worker             }
982*1b3f573fSAndroid Build Coastguard Worker 
Read(byte[] buffer, int offset, int count)983*1b3f573fSAndroid Build Coastguard Worker             public override int Read(byte[] buffer, int offset, int count)
984*1b3f573fSAndroid Build Coastguard Worker             {
985*1b3f573fSAndroid Build Coastguard Worker                 if (bytes.Length == 0)
986*1b3f573fSAndroid Build Coastguard Worker                 {
987*1b3f573fSAndroid Build Coastguard Worker                     return 0;
988*1b3f573fSAndroid Build Coastguard Worker                 }
989*1b3f573fSAndroid Build Coastguard Worker                 int numBytesCopiedTotal = 0;
990*1b3f573fSAndroid Build Coastguard Worker                 while (numBytesCopiedTotal < count && index < maxIterations)
991*1b3f573fSAndroid Build Coastguard Worker                 {
992*1b3f573fSAndroid Build Coastguard Worker                     int numBytesToCopy = Math.Min(bytes.Length - (int)Position, count);
993*1b3f573fSAndroid Build Coastguard Worker                     Array.Copy(bytes, (int)Position, buffer, offset, numBytesToCopy);
994*1b3f573fSAndroid Build Coastguard Worker                     numBytesCopiedTotal += numBytesToCopy;
995*1b3f573fSAndroid Build Coastguard Worker                     offset += numBytesToCopy;
996*1b3f573fSAndroid Build Coastguard Worker                     count -= numBytesCopiedTotal;
997*1b3f573fSAndroid Build Coastguard Worker                     Position += numBytesToCopy;
998*1b3f573fSAndroid Build Coastguard Worker                     if (Position >= bytes.Length)
999*1b3f573fSAndroid Build Coastguard Worker                     {
1000*1b3f573fSAndroid Build Coastguard Worker                         Position = 0;
1001*1b3f573fSAndroid Build Coastguard Worker                         index++;
1002*1b3f573fSAndroid Build Coastguard Worker                     }
1003*1b3f573fSAndroid Build Coastguard Worker                 }
1004*1b3f573fSAndroid Build Coastguard Worker                 return numBytesCopiedTotal;
1005*1b3f573fSAndroid Build Coastguard Worker             }
1006*1b3f573fSAndroid Build Coastguard Worker         }
1007*1b3f573fSAndroid Build Coastguard Worker     }
1008*1b3f573fSAndroid Build Coastguard Worker }
1009