blob: f16abf65b37f8f506d0102467929018faf419f17 [file] [log] [blame]
csharptest71f662c2011-05-20 15:15:34 -05001#region Copyright notice and license
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc. All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15// * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19// * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35#endregion
36
37using System;
csharptestc671a4b2011-06-08 11:51:24 -050038using System.Collections.Generic;
csharptest90922db2011-06-03 11:57:47 -050039using System.Globalization;
csharptest71f662c2011-05-20 15:15:34 -050040using System.IO;
csharptest2772dfe2011-06-08 15:50:58 -050041using System.Runtime.InteropServices;
csharptest71f662c2011-05-20 15:15:34 -050042using System.Text;
csharptestced18e12011-06-09 19:47:56 -050043using Google.ProtocolBuffers.Collections;
csharptest71f662c2011-05-20 15:15:34 -050044using Google.ProtocolBuffers.Descriptors;
45
46namespace Google.ProtocolBuffers
47{
48 /// <summary>
49 /// Encodes and writes protocol message fields.
50 /// </summary>
51 /// <remarks>
52 /// This class contains two kinds of methods: methods that write specific
53 /// protocol message constructs and field types (e.g. WriteTag and
54 /// WriteInt32) and methods that write low-level values (e.g.
55 /// WriteRawVarint32 and WriteRawBytes). If you are writing encoded protocol
56 /// messages, you should use the former methods, but if you are writing some
57 /// other format of your own design, use the latter. The names of the former
58 /// methods are taken from the protocol buffer type names, not .NET types.
59 /// (Hence WriteFloat instead of WriteSingle, and WriteBool instead of WriteBoolean.)
60 /// </remarks>
csharptestcc8d2aa2011-06-03 12:15:42 -050061 public sealed partial class CodedOutputStream : ICodedOutputStream
csharptest71f662c2011-05-20 15:15:34 -050062 {
63 /// <summary>
64 /// The buffer size used by CreateInstance(Stream).
65 /// </summary>
66 public static readonly int DefaultBufferSize = 4096;
67
68 private readonly byte[] buffer;
69 private readonly int limit;
70 private int position;
71 private readonly Stream output;
72
73 #region Construction
74
75 private CodedOutputStream(byte[] buffer, int offset, int length)
76 {
77 this.output = null;
78 this.buffer = buffer;
79 this.position = offset;
80 this.limit = offset + length;
81 }
82
83 private CodedOutputStream(Stream output, byte[] buffer)
84 {
85 this.output = output;
86 this.buffer = buffer;
87 this.position = 0;
88 this.limit = buffer.Length;
89 }
90
91 /// <summary>
92 /// Creates a new CodedOutputStream which write to the given stream.
93 /// </summary>
94 public static CodedOutputStream CreateInstance(Stream output)
95 {
96 return CreateInstance(output, DefaultBufferSize);
97 }
98
99 /// <summary>
100 /// Creates a new CodedOutputStream which write to the given stream and uses
101 /// the specified buffer size.
102 /// </summary>
103 public static CodedOutputStream CreateInstance(Stream output, int bufferSize)
104 {
105 return new CodedOutputStream(output, new byte[bufferSize]);
106 }
107
108 /// <summary>
109 /// Creates a new CodedOutputStream that writes directly to the given
110 /// byte array. If more bytes are written than fit in the array,
111 /// OutOfSpaceException will be thrown.
112 /// </summary>
113 public static CodedOutputStream CreateInstance(byte[] flatArray)
114 {
115 return CreateInstance(flatArray, 0, flatArray.Length);
116 }
117
118 /// <summary>
119 /// Creates a new CodedOutputStream that writes directly to the given
120 /// byte array slice. If more bytes are written than fit in the array,
121 /// OutOfSpaceException will be thrown.
122 /// </summary>
123 public static CodedOutputStream CreateInstance(byte[] flatArray, int offset, int length)
124 {
125 return new CodedOutputStream(flatArray, offset, length);
126 }
127
128 #endregion
129
csharptestb00ea132011-06-10 01:09:57 -0500130 #region Writing of tags and fields
131
132 public void WriteField(FieldType fieldType, int fieldNumber, string fieldName, object value)
133 {
134 switch (fieldType)
135 {
136 case FieldType.String:
137 WriteString(fieldNumber, fieldName, (string)value);
138 break;
139 case FieldType.Message:
140 WriteMessage(fieldNumber, fieldName, (IMessageLite)value);
141 break;
142 case FieldType.Group:
143 WriteGroup(fieldNumber, fieldName, (IMessageLite)value);
144 break;
145 case FieldType.Bytes:
146 WriteBytes(fieldNumber, fieldName, (ByteString)value);
147 break;
148 case FieldType.Bool:
149 WriteBool(fieldNumber, fieldName, (bool)value);
150 break;
151 case FieldType.Enum:
152 if (value is System.Enum)
153 WriteEnum(fieldNumber, fieldName, (int)value, null/*not used*/);
154 else
155 WriteEnum(fieldNumber, fieldName, ((IEnumLite)value).Number, null/*not used*/);
156 break;
157 case FieldType.Int32:
158 WriteInt32(fieldNumber, fieldName, (int)value);
159 break;
160 case FieldType.Int64:
161 WriteInt64(fieldNumber, fieldName, (long)value);
162 break;
163 case FieldType.UInt32:
164 WriteUInt32(fieldNumber, fieldName, (uint)value);
165 break;
166 case FieldType.UInt64:
167 WriteUInt64(fieldNumber, fieldName, (ulong)value);
168 break;
169 case FieldType.SInt32:
170 WriteSInt32(fieldNumber, fieldName, (int)value);
171 break;
172 case FieldType.SInt64:
173 WriteSInt64(fieldNumber, fieldName, (long)value);
174 break;
175 case FieldType.Fixed32:
176 WriteFixed32(fieldNumber, fieldName, (uint)value);
177 break;
178 case FieldType.Fixed64:
179 WriteFixed64(fieldNumber, fieldName, (ulong)value);
180 break;
181 case FieldType.SFixed32:
182 WriteSFixed32(fieldNumber, fieldName, (int)value);
183 break;
184 case FieldType.SFixed64:
185 WriteSFixed64(fieldNumber, fieldName, (long)value);
186 break;
187 case FieldType.Double:
188 WriteDouble(fieldNumber, fieldName, (double)value);
189 break;
190 case FieldType.Float:
191 WriteFloat(fieldNumber, fieldName, (float)value);
192 break;
193 }
194 }
csharptest71f662c2011-05-20 15:15:34 -0500195
196 /// <summary>
197 /// Writes a double field value, including tag, to the stream.
198 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500199 public void WriteDouble(int fieldNumber, string fieldName, double value)
csharptest71f662c2011-05-20 15:15:34 -0500200 {
201 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
202 WriteDoubleNoTag(value);
203 }
204
205 /// <summary>
206 /// Writes a float field value, including tag, to the stream.
207 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500208 public void WriteFloat(int fieldNumber, string fieldName, float value)
csharptest71f662c2011-05-20 15:15:34 -0500209 {
210 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
211 WriteFloatNoTag(value);
212 }
213
214 /// <summary>
215 /// Writes a uint64 field value, including tag, to the stream.
216 /// </summary>
217 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500218 public void WriteUInt64(int fieldNumber, string fieldName, ulong value)
csharptest71f662c2011-05-20 15:15:34 -0500219 {
220 WriteTag(fieldNumber, WireFormat.WireType.Varint);
221 WriteRawVarint64(value);
222 }
223
224 /// <summary>
225 /// Writes an int64 field value, including tag, to the stream.
226 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500227 public void WriteInt64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500228 {
229 WriteTag(fieldNumber, WireFormat.WireType.Varint);
230 WriteRawVarint64((ulong) value);
231 }
232
233 /// <summary>
234 /// Writes an int32 field value, including tag, to the stream.
235 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500236 public void WriteInt32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500237 {
238 WriteTag(fieldNumber, WireFormat.WireType.Varint);
239 if (value >= 0)
240 {
241 WriteRawVarint32((uint) value);
242 }
243 else
244 {
245 // Must sign-extend.
246 WriteRawVarint64((ulong) value);
247 }
248 }
249
250 /// <summary>
251 /// Writes a fixed64 field value, including tag, to the stream.
252 /// </summary>
253 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500254 public void WriteFixed64(int fieldNumber, string fieldName, ulong value)
csharptest71f662c2011-05-20 15:15:34 -0500255 {
256 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
257 WriteRawLittleEndian64(value);
258 }
259
260 /// <summary>
261 /// Writes a fixed32 field value, including tag, to the stream.
262 /// </summary>
263 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500264 public void WriteFixed32(int fieldNumber, string fieldName, uint value)
csharptest71f662c2011-05-20 15:15:34 -0500265 {
266 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
267 WriteRawLittleEndian32(value);
268 }
269
270 /// <summary>
271 /// Writes a bool field value, including tag, to the stream.
272 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500273 public void WriteBool(int fieldNumber, string fieldName, bool value)
csharptest71f662c2011-05-20 15:15:34 -0500274 {
275 WriteTag(fieldNumber, WireFormat.WireType.Varint);
276 WriteRawByte(value ? (byte) 1 : (byte) 0);
277 }
278
279 /// <summary>
280 /// Writes a string field value, including tag, to the stream.
281 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500282 public void WriteString(int fieldNumber, string fieldName, string value)
csharptest71f662c2011-05-20 15:15:34 -0500283 {
284 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
285 // Optimise the case where we have enough space to write
286 // the string directly to the buffer, which should be common.
287 int length = Encoding.UTF8.GetByteCount(value);
288 WriteRawVarint32((uint) length);
289 if (limit - position >= length)
290 {
291 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
292 position += length;
293 }
294 else
295 {
296 byte[] bytes = Encoding.UTF8.GetBytes(value);
297 WriteRawBytes(bytes);
298 }
299 }
300
301 /// <summary>
302 /// Writes a group field value, including tag, to the stream.
303 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500304 public void WriteGroup(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500305 {
306 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
307 value.WriteTo(this);
308 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
309 }
310
311 [Obsolete]
csharptest90922db2011-06-03 11:57:47 -0500312 public void WriteUnknownGroup(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500313 {
314 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
315 value.WriteTo(this);
316 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
317 }
318
csharptest90922db2011-06-03 11:57:47 -0500319 public void WriteMessage(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500320 {
321 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
322 WriteRawVarint32((uint) value.SerializedSize);
323 value.WriteTo(this);
324 }
325
csharptest90922db2011-06-03 11:57:47 -0500326 public void WriteBytes(int fieldNumber, string fieldName, ByteString value)
csharptest71f662c2011-05-20 15:15:34 -0500327 {
csharptest71f662c2011-05-20 15:15:34 -0500328 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
csharptest45a93fa2011-06-02 10:52:37 -0500329 WriteRawVarint32((uint)value.Length);
330 value.WriteTo(this);
csharptest71f662c2011-05-20 15:15:34 -0500331 }
332
333 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500334 public void WriteUInt32(int fieldNumber, string fieldName, uint value)
csharptest71f662c2011-05-20 15:15:34 -0500335 {
336 WriteTag(fieldNumber, WireFormat.WireType.Varint);
337 WriteRawVarint32(value);
338 }
339
csharptestced18e12011-06-09 19:47:56 -0500340 public void WriteEnum(int fieldNumber, string fieldName, int value, object textValue)
csharptest71f662c2011-05-20 15:15:34 -0500341 {
342 WriteTag(fieldNumber, WireFormat.WireType.Varint);
343 WriteRawVarint32((uint) value);
344 }
345
csharptest90922db2011-06-03 11:57:47 -0500346 public void WriteSFixed32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500347 {
348 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
349 WriteRawLittleEndian32((uint) value);
350 }
351
csharptest90922db2011-06-03 11:57:47 -0500352 public void WriteSFixed64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500353 {
354 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
355 WriteRawLittleEndian64((ulong) value);
356 }
357
csharptest90922db2011-06-03 11:57:47 -0500358 public void WriteSInt32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500359 {
360 WriteTag(fieldNumber, WireFormat.WireType.Varint);
361 WriteRawVarint32(EncodeZigZag32(value));
362 }
363
csharptest90922db2011-06-03 11:57:47 -0500364 public void WriteSInt64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500365 {
366 WriteTag(fieldNumber, WireFormat.WireType.Varint);
367 WriteRawVarint64(EncodeZigZag64(value));
368 }
369
csharptest90922db2011-06-03 11:57:47 -0500370 public void WriteMessageSetExtension(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500371 {
372 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
csharptest90922db2011-06-03 11:57:47 -0500373 WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
374 WriteMessage(WireFormat.MessageSetField.Message, "message", value);
csharptest71f662c2011-05-20 15:15:34 -0500375 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
376 }
377
csharptestffafdaa2011-06-03 12:58:14 -0500378 public void WriteMessageSetExtension(int fieldNumber, string fieldName, ByteString value)
csharptest71f662c2011-05-20 15:15:34 -0500379 {
380 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
csharptest90922db2011-06-03 11:57:47 -0500381 WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
382 WriteBytes(WireFormat.MessageSetField.Message, "message", value);
csharptest71f662c2011-05-20 15:15:34 -0500383 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
384 }
csharptest90922db2011-06-03 11:57:47 -0500385
csharptestb00ea132011-06-10 01:09:57 -0500386 #endregion
csharptestc671a4b2011-06-08 11:51:24 -0500387
csharptestb00ea132011-06-10 01:09:57 -0500388 #region Writing of values without tags
csharptest71f662c2011-05-20 15:15:34 -0500389
390 public void WriteFieldNoTag(FieldType fieldType, object value)
391 {
392 switch (fieldType)
393 {
csharptestc671a4b2011-06-08 11:51:24 -0500394 case FieldType.String:
395 WriteStringNoTag((string)value);
csharptest71f662c2011-05-20 15:15:34 -0500396 break;
csharptestc671a4b2011-06-08 11:51:24 -0500397 case FieldType.Message:
398 WriteMessageNoTag((IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500399 break;
csharptestc671a4b2011-06-08 11:51:24 -0500400 case FieldType.Group:
401 WriteGroupNoTag((IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500402 break;
csharptestc671a4b2011-06-08 11:51:24 -0500403 case FieldType.Bytes:
404 WriteBytesNoTag((ByteString)value);
405 break;
406 case FieldType.Bool:
407 WriteBoolNoTag((bool)value);
408 break;
409 case FieldType.Enum:
410 if (value is System.Enum)
csharptestced18e12011-06-09 19:47:56 -0500411 WriteEnumNoTag((int)value);
csharptestc671a4b2011-06-08 11:51:24 -0500412 else
413 WriteEnumNoTag(((IEnumLite)value).Number);
csharptest71f662c2011-05-20 15:15:34 -0500414 break;
415 case FieldType.Int32:
csharptestb00ea132011-06-10 01:09:57 -0500416 WriteInt32NoTag((int)value);
csharptest71f662c2011-05-20 15:15:34 -0500417 break;
csharptestc671a4b2011-06-08 11:51:24 -0500418 case FieldType.Int64:
csharptestb00ea132011-06-10 01:09:57 -0500419 WriteInt64NoTag((long)value);
csharptest71f662c2011-05-20 15:15:34 -0500420 break;
421 case FieldType.UInt32:
csharptestb00ea132011-06-10 01:09:57 -0500422 WriteUInt32NoTag((uint)value);
csharptest71f662c2011-05-20 15:15:34 -0500423 break;
csharptestc671a4b2011-06-08 11:51:24 -0500424 case FieldType.UInt64:
csharptestb00ea132011-06-10 01:09:57 -0500425 WriteUInt64NoTag((ulong)value);
csharptest71f662c2011-05-20 15:15:34 -0500426 break;
427 case FieldType.SInt32:
csharptestb00ea132011-06-10 01:09:57 -0500428 WriteSInt32NoTag((int)value);
csharptest71f662c2011-05-20 15:15:34 -0500429 break;
430 case FieldType.SInt64:
csharptestb00ea132011-06-10 01:09:57 -0500431 WriteSInt64NoTag((long)value);
csharptest71f662c2011-05-20 15:15:34 -0500432 break;
csharptestc671a4b2011-06-08 11:51:24 -0500433 case FieldType.Fixed32:
csharptestb00ea132011-06-10 01:09:57 -0500434 WriteFixed32NoTag((uint)value);
csharptestc671a4b2011-06-08 11:51:24 -0500435 break;
436 case FieldType.Fixed64:
csharptestb00ea132011-06-10 01:09:57 -0500437 WriteFixed64NoTag((ulong)value);
csharptestc671a4b2011-06-08 11:51:24 -0500438 break;
439 case FieldType.SFixed32:
csharptestb00ea132011-06-10 01:09:57 -0500440 WriteSFixed32NoTag((int)value);
csharptestc671a4b2011-06-08 11:51:24 -0500441 break;
442 case FieldType.SFixed64:
csharptestb00ea132011-06-10 01:09:57 -0500443 WriteSFixed64NoTag((long)value);
csharptestc671a4b2011-06-08 11:51:24 -0500444 break;
445 case FieldType.Double:
446 WriteDoubleNoTag((double)value);
447 break;
448 case FieldType.Float:
449 WriteFloatNoTag((float)value);
csharptest71f662c2011-05-20 15:15:34 -0500450 break;
451 }
452 }
453
csharptest71f662c2011-05-20 15:15:34 -0500454 /// <summary>
455 /// Writes a double field value, including tag, to the stream.
456 /// </summary>
457 public void WriteDoubleNoTag(double value)
458 {
csharptest71f662c2011-05-20 15:15:34 -0500459#if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
csharptest8a2d0f42011-06-02 17:02:41 -0500460 byte[] rawBytes = BitConverter.GetBytes(value);
461 if (!BitConverter.IsLittleEndian)
csharptestaef072a2011-06-08 18:00:43 -0500462 ByteArray.Reverse(rawBytes);
csharptest2772dfe2011-06-08 15:50:58 -0500463
464 if (limit - position >= 8)
465 {
466 buffer[position++] = rawBytes[0];
467 buffer[position++] = rawBytes[1];
468 buffer[position++] = rawBytes[2];
469 buffer[position++] = rawBytes[3];
470 buffer[position++] = rawBytes[4];
471 buffer[position++] = rawBytes[5];
472 buffer[position++] = rawBytes[6];
473 buffer[position++] = rawBytes[7];
474 }
475 else
476 WriteRawBytes(rawBytes, 0, 8);
csharptest71f662c2011-05-20 15:15:34 -0500477#else
csharptest8a2d0f42011-06-02 17:02:41 -0500478 WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
csharptest71f662c2011-05-20 15:15:34 -0500479#endif
480 }
481
482 /// <summary>
483 /// Writes a float field value, without a tag, to the stream.
484 /// </summary>
485 public void WriteFloatNoTag(float value)
486 {
csharptest71f662c2011-05-20 15:15:34 -0500487 byte[] rawBytes = BitConverter.GetBytes(value);
csharptestaef072a2011-06-08 18:00:43 -0500488 if (!BitConverter.IsLittleEndian)
489 ByteArray.Reverse(rawBytes);
csharptest2772dfe2011-06-08 15:50:58 -0500490
491 if (limit - position >= 4)
492 {
493 buffer[position++] = rawBytes[0];
494 buffer[position++] = rawBytes[1];
495 buffer[position++] = rawBytes[2];
496 buffer[position++] = rawBytes[3];
497 }
498 else
499 WriteRawBytes(rawBytes, 0, 4);
csharptest71f662c2011-05-20 15:15:34 -0500500 }
501
502 /// <summary>
503 /// Writes a uint64 field value, without a tag, to the stream.
504 /// </summary>
505 [CLSCompliant(false)]
506 public void WriteUInt64NoTag(ulong value)
507 {
508 WriteRawVarint64(value);
509 }
510
511 /// <summary>
512 /// Writes an int64 field value, without a tag, to the stream.
513 /// </summary>
514 public void WriteInt64NoTag(long value)
515 {
csharptestb00ea132011-06-10 01:09:57 -0500516 WriteRawVarint64((ulong)value);
csharptest71f662c2011-05-20 15:15:34 -0500517 }
518
519 /// <summary>
520 /// Writes an int32 field value, without a tag, to the stream.
521 /// </summary>
522 public void WriteInt32NoTag(int value)
523 {
524 if (value >= 0)
525 {
csharptestb00ea132011-06-10 01:09:57 -0500526 WriteRawVarint32((uint)value);
csharptest71f662c2011-05-20 15:15:34 -0500527 }
528 else
529 {
530 // Must sign-extend.
csharptestb00ea132011-06-10 01:09:57 -0500531 WriteRawVarint64((ulong)value);
csharptest71f662c2011-05-20 15:15:34 -0500532 }
533 }
534
535 /// <summary>
536 /// Writes a fixed64 field value, without a tag, to the stream.
537 /// </summary>
538 [CLSCompliant(false)]
539 public void WriteFixed64NoTag(ulong value)
540 {
541 WriteRawLittleEndian64(value);
542 }
543
544 /// <summary>
545 /// Writes a fixed32 field value, without a tag, to the stream.
546 /// </summary>
547 [CLSCompliant(false)]
548 public void WriteFixed32NoTag(uint value)
549 {
550 WriteRawLittleEndian32(value);
551 }
552
553 /// <summary>
554 /// Writes a bool field value, without a tag, to the stream.
555 /// </summary>
556 public void WriteBoolNoTag(bool value)
557 {
csharptestb00ea132011-06-10 01:09:57 -0500558 WriteRawByte(value ? (byte)1 : (byte)0);
csharptest71f662c2011-05-20 15:15:34 -0500559 }
560
561 /// <summary>
562 /// Writes a string field value, without a tag, to the stream.
563 /// </summary>
564 public void WriteStringNoTag(string value)
565 {
566 // Optimise the case where we have enough space to write
567 // the string directly to the buffer, which should be common.
568 int length = Encoding.UTF8.GetByteCount(value);
csharptestb00ea132011-06-10 01:09:57 -0500569 WriteRawVarint32((uint)length);
csharptest71f662c2011-05-20 15:15:34 -0500570 if (limit - position >= length)
571 {
572 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
573 position += length;
574 }
575 else
576 {
577 byte[] bytes = Encoding.UTF8.GetBytes(value);
578 WriteRawBytes(bytes);
579 }
580 }
581
582 /// <summary>
583 /// Writes a group field value, without a tag, to the stream.
584 /// </summary>
585 public void WriteGroupNoTag(IMessageLite value)
586 {
587 value.WriteTo(this);
588 }
589
590 public void WriteMessageNoTag(IMessageLite value)
591 {
csharptestb00ea132011-06-10 01:09:57 -0500592 WriteRawVarint32((uint)value.SerializedSize);
csharptest71f662c2011-05-20 15:15:34 -0500593 value.WriteTo(this);
594 }
595
596 public void WriteBytesNoTag(ByteString value)
597 {
csharptest45a93fa2011-06-02 10:52:37 -0500598 WriteRawVarint32((uint)value.Length);
599 value.WriteTo(this);
csharptest71f662c2011-05-20 15:15:34 -0500600 }
601
602 [CLSCompliant(false)]
603 public void WriteUInt32NoTag(uint value)
604 {
605 WriteRawVarint32(value);
606 }
607
608 public void WriteEnumNoTag(int value)
609 {
csharptestb00ea132011-06-10 01:09:57 -0500610 WriteRawVarint32((uint)value);
csharptest71f662c2011-05-20 15:15:34 -0500611 }
612
613 public void WriteSFixed32NoTag(int value)
614 {
csharptestb00ea132011-06-10 01:09:57 -0500615 WriteRawLittleEndian32((uint)value);
csharptest71f662c2011-05-20 15:15:34 -0500616 }
617
618 public void WriteSFixed64NoTag(long value)
619 {
csharptestb00ea132011-06-10 01:09:57 -0500620 WriteRawLittleEndian64((ulong)value);
csharptest71f662c2011-05-20 15:15:34 -0500621 }
622
623 public void WriteSInt32NoTag(int value)
624 {
625 WriteRawVarint32(EncodeZigZag32(value));
626 }
627
628 public void WriteSInt64NoTag(long value)
629 {
630 WriteRawVarint64(EncodeZigZag64(value));
631 }
632
633 #endregion
634
csharptestb00ea132011-06-10 01:09:57 -0500635 #region Write array members
636
637 public void WriteArray(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.IEnumerable list)
638 {
639 foreach (object element in list)
640 WriteField(fieldType, fieldNumber, fieldName, element);
641 }
642
643 public void WriteGroupArray<T>(int fieldNumber, string fieldName, IEnumerable<T> list)
644 where T : IMessageLite
645 {
646 foreach (IMessageLite value in list)
647 WriteGroup(fieldNumber, fieldName, value);
648 }
649
650 public void WriteMessageArray<T>(int fieldNumber, string fieldName, IEnumerable<T> list)
651 where T : IMessageLite
652 {
653 foreach (IMessageLite value in list)
654 WriteMessage(fieldNumber, fieldName, value);
655 }
656
657 public void WriteStringArray(int fieldNumber, string fieldName, IEnumerable<string> list)
658 {
659 foreach (var value in list)
660 WriteString(fieldNumber, fieldName, value);
661 }
662
663 public void WriteBytesArray(int fieldNumber, string fieldName, IEnumerable<ByteString> list)
664 {
665 foreach (var value in list)
666 WriteBytes(fieldNumber, fieldName, value);
667 }
668
669 public void WriteBoolArray(int fieldNumber, string fieldName, IEnumerable<bool> list)
670 {
671 foreach (var value in list)
672 WriteBool(fieldNumber, fieldName, value);
673 }
674
675 public void WriteInt32Array(int fieldNumber, string fieldName, IEnumerable<int> list)
676 {
677 foreach (var value in list)
678 WriteInt32(fieldNumber, fieldName, value);
679 }
680
681 public void WriteSInt32Array(int fieldNumber, string fieldName, IEnumerable<int> list)
682 {
683 foreach (var value in list)
684 WriteSInt32(fieldNumber, fieldName, value);
685 }
686
687 public void WriteUInt32Array(int fieldNumber, string fieldName, IEnumerable<uint> list)
688 {
689 foreach (var value in list)
690 WriteUInt32(fieldNumber, fieldName, value);
691 }
692
693 public void WriteFixed32Array(int fieldNumber, string fieldName, IEnumerable<uint> list)
694 {
695 foreach (var value in list)
696 WriteFixed32(fieldNumber, fieldName, value);
697 }
698
699 public void WriteSFixed32Array(int fieldNumber, string fieldName, IEnumerable<int> list)
700 {
701 foreach (var value in list)
702 WriteSFixed32(fieldNumber, fieldName, value);
703 }
704
705 public void WriteInt64Array(int fieldNumber, string fieldName, IEnumerable<long> list)
706 {
707 foreach (var value in list)
708 WriteInt64(fieldNumber, fieldName, value);
709 }
710
711 public void WriteSInt64Array(int fieldNumber, string fieldName, IEnumerable<long> list)
712 {
713 foreach (var value in list)
714 WriteSInt64(fieldNumber, fieldName, value);
715 }
716
717 public void WriteUInt64Array(int fieldNumber, string fieldName, IEnumerable<ulong> list)
718 {
719 foreach (var value in list)
720 WriteUInt64(fieldNumber, fieldName, value);
721 }
722
723 public void WriteFixed64Array(int fieldNumber, string fieldName, IEnumerable<ulong> list)
724 {
725 foreach (var value in list)
726 WriteFixed64(fieldNumber, fieldName, value);
727 }
728
729 public void WriteSFixed64Array(int fieldNumber, string fieldName, IEnumerable<long> list)
730 {
731 foreach (var value in list)
732 WriteSFixed64(fieldNumber, fieldName, value);
733 }
734
735 public void WriteDoubleArray(int fieldNumber, string fieldName, IEnumerable<double> list)
736 {
737 foreach (var value in list)
738 WriteDouble(fieldNumber, fieldName, value);
739 }
740
741 public void WriteFloatArray(int fieldNumber, string fieldName, IEnumerable<float> list)
742 {
743 foreach (var value in list)
744 WriteFloat(fieldNumber, fieldName, value);
745 }
746
747 [CLSCompliant(false)]
748 public void WriteEnumArray<T>(int fieldNumber, string fieldName, IEnumerable<T> list)
749 where T : struct, IComparable, IFormattable, IConvertible
750 {
751 if (list is ICastArray)
752 {
753 foreach (int value in ((ICastArray)list).CastArray<int>())
754 WriteEnum(fieldNumber, fieldName, value, null /*unused*/);
755 }
756 else
757 {
758 foreach (object value in list)
759 WriteEnum(fieldNumber, fieldName, (int) value, null /*unused*/);
760 }
761 }
762
763 #endregion
764
765 #region Write packed array members
766
767 public void WritePackedArray(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.IEnumerable list)
768 {
769 int calculatedSize = 0;
770 foreach (object element in list)
771 calculatedSize += CodedOutputStream.ComputeFieldSizeNoTag(fieldType, element);
772
773 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
774 WriteRawVarint32((uint)calculatedSize);
775
776 foreach (object element in list)
777 WriteFieldNoTag(fieldType, element);
778 }
779
780 public void WritePackedGroupArray<T>(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<T> list)
781 where T : IMessageLite
782 {
783 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
784 WriteRawVarint32((uint)calculatedSize);
785 foreach (IMessageLite value in list)
786 WriteGroupNoTag(value);
787 }
788
789 public void WritePackedMessageArray<T>(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<T> list)
790 where T : IMessageLite
791 {
792 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
793 WriteRawVarint32((uint)calculatedSize);
794 foreach (IMessageLite value in list)
795 WriteMessageNoTag(value);
796 }
797
798 public void WritePackedStringArray(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<string> list)
799 {
800 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
801 WriteRawVarint32((uint)calculatedSize);
802 foreach (var value in list)
803 WriteStringNoTag(value);
804 }
805
806 public void WritePackedBytesArray(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<ByteString> list)
807 {
808 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
809 WriteRawVarint32((uint)calculatedSize);
810 foreach (var value in list)
811 WriteBytesNoTag(value);
812 }
813
814 public void WritePackedBoolArray(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<bool> list)
815 {
816 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
817 WriteRawVarint32((uint)calculatedSize);
818 foreach (var value in list)
819 WriteBoolNoTag(value);
820 }
821
822 public void WritePackedInt32Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<int> list)
823 {
824 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
825 WriteRawVarint32((uint)calculatedSize);
826 foreach (var value in list)
827 WriteInt32NoTag(value);
828 }
829
830 public void WritePackedSInt32Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<int> list)
831 {
832 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
833 WriteRawVarint32((uint)calculatedSize);
834 foreach (var value in list)
835 WriteSInt32NoTag(value);
836 }
837
838 public void WritePackedUInt32Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<uint> list)
839 {
840 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
841 WriteRawVarint32((uint)calculatedSize);
842 foreach (var value in list)
843 WriteUInt32NoTag(value);
844 }
845
846 public void WritePackedFixed32Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<uint> list)
847 {
848 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
849 WriteRawVarint32((uint)calculatedSize);
850 foreach (var value in list)
851 WriteFixed32NoTag(value);
852 }
853
854 public void WritePackedSFixed32Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<int> list)
855 {
856 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
857 WriteRawVarint32((uint)calculatedSize);
858 foreach (var value in list)
859 WriteSFixed32NoTag(value);
860 }
861
862 public void WritePackedInt64Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<long> list)
863 {
864 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
865 WriteRawVarint32((uint)calculatedSize);
866 foreach (var value in list)
867 WriteInt64NoTag(value);
868 }
869
870 public void WritePackedSInt64Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<long> list)
871 {
872 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
873 WriteRawVarint32((uint)calculatedSize);
874 foreach (var value in list)
875 WriteSInt64NoTag(value);
876 }
877
878 public void WritePackedUInt64Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<ulong> list)
879 {
880 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
881 WriteRawVarint32((uint)calculatedSize);
882 foreach (var value in list)
883 WriteUInt64NoTag(value);
884 }
885
886 public void WritePackedFixed64Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<ulong> list)
887 {
888 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
889 WriteRawVarint32((uint)calculatedSize);
890 foreach (var value in list)
891 WriteFixed64NoTag(value);
892 }
893
894 public void WritePackedSFixed64Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<long> list)
895 {
896 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
897 WriteRawVarint32((uint)calculatedSize);
898 foreach (var value in list)
899 WriteSFixed64NoTag(value);
900 }
901
902 public void WritePackedDoubleArray(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<double> list)
903 {
904 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
905 WriteRawVarint32((uint)calculatedSize);
906 foreach (var value in list)
907 WriteDoubleNoTag(value);
908 }
909
910 public void WritePackedFloatArray(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<float> list)
911 {
912 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
913 WriteRawVarint32((uint)calculatedSize);
914 foreach (var value in list)
915 WriteFloatNoTag(value);
916 }
917
918 [CLSCompliant(false)]
919 public void WritePackedEnumArray<T>(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<T> list)
920 where T : struct, IComparable, IFormattable, IConvertible
921 {
922 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
923 WriteRawVarint32((uint)calculatedSize);
924 if (list is ICastArray)
925 {
926 foreach (int value in ((ICastArray)list).CastArray<int>())
927 WriteEnumNoTag(value);
928 }
929 else
930 {
931 foreach (object value in list)
932 WriteEnumNoTag((int)value);
933 }
934 }
935
936 #endregion
937
csharptest71f662c2011-05-20 15:15:34 -0500938 #region Underlying writing primitives
939
940 /// <summary>
941 /// Encodes and writes a tag.
942 /// </summary>
943 [CLSCompliant(false)]
944 public void WriteTag(int fieldNumber, WireFormat.WireType type)
945 {
946 WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
947 }
948
csharptestc671a4b2011-06-08 11:51:24 -0500949#if false
csharptest71f662c2011-05-20 15:15:34 -0500950 private void SlowWriteRawVarint32(uint value)
951 {
952 while (true)
953 {
954 if ((value & ~0x7F) == 0)
955 {
956 WriteRawByte(value);
957 return;
958 }
959 else
960 {
961 WriteRawByte((value & 0x7F) | 0x80);
962 value >>= 7;
963 }
964 }
965 }
csharptestc671a4b2011-06-08 11:51:24 -0500966#endif
csharptest71f662c2011-05-20 15:15:34 -0500967 /// <summary>
968 /// Writes a 32 bit value as a varint. The fast route is taken when
969 /// there's enough buffer space left to whizz through without checking
970 /// for each byte; otherwise, we resort to calling WriteRawByte each time.
971 /// </summary>
972 [CLSCompliant(false)]
973 public void WriteRawVarint32(uint value)
974 {
csharptestc671a4b2011-06-08 11:51:24 -0500975#if true
976 while (value > 127 && position < limit)
977 {
978 buffer[position++] = (byte)((value & 0x7F) | 0x80);
979 value >>= 7;
980 }
981 while (value > 127)
982 {
983 WriteRawByte((byte)((value & 0x7F) | 0x80));
984 value >>= 7;
985 }
986 if(position < limit)
987 buffer[position++] = (byte)value;
988 else
989 WriteRawByte((byte)value);
990#else
csharptest71f662c2011-05-20 15:15:34 -0500991 if (position + 5 > limit)
992 {
993 SlowWriteRawVarint32(value);
994 return;
995 }
996
997 while (true)
998 {
999 if ((value & ~0x7F) == 0)
1000 {
1001 buffer[position++] = (byte) value;
1002 return;
1003 }
1004 else
1005 {
1006 buffer[position++] = (byte) ((value & 0x7F) | 0x80);
1007 value >>= 7;
1008 }
1009 }
csharptestc671a4b2011-06-08 11:51:24 -05001010#endif
csharptest71f662c2011-05-20 15:15:34 -05001011 }
1012
1013 [CLSCompliant(false)]
1014 public void WriteRawVarint64(ulong value)
1015 {
csharptestc671a4b2011-06-08 11:51:24 -05001016#if true
1017 while (value > 127 && position < limit)
1018 {
1019 buffer[position++] = (byte)((value & 0x7F) | 0x80);
1020 value >>= 7;
1021 }
1022 while (value > 127)
1023 {
1024 WriteRawByte((byte)((value & 0x7F) | 0x80));
1025 value >>= 7;
1026 }
1027 if(position < limit)
1028 buffer[position++] = (byte)value;
1029 else
1030 WriteRawByte((byte)value);
1031#else
csharptest71f662c2011-05-20 15:15:34 -05001032 while (true)
1033 {
1034 if ((value & ~0x7FUL) == 0)
1035 {
1036 WriteRawByte((uint) value);
1037 return;
1038 }
1039 else
1040 {
1041 WriteRawByte(((uint) value & 0x7F) | 0x80);
1042 value >>= 7;
1043 }
1044 }
csharptestc671a4b2011-06-08 11:51:24 -05001045#endif
csharptest71f662c2011-05-20 15:15:34 -05001046 }
1047
1048 [CLSCompliant(false)]
1049 public void WriteRawLittleEndian32(uint value)
1050 {
csharptestc671a4b2011-06-08 11:51:24 -05001051 if (position + 4 > limit)
1052 {
1053 WriteRawByte((byte) value);
1054 WriteRawByte((byte) (value >> 8));
1055 WriteRawByte((byte) (value >> 16));
1056 WriteRawByte((byte) (value >> 24));
1057 }
1058 else
1059 {
1060 buffer[position++] = ((byte)value);
1061 buffer[position++] = ((byte)(value >> 8));
1062 buffer[position++] = ((byte)(value >> 16));
1063 buffer[position++] = ((byte)(value >> 24));
1064 }
csharptest71f662c2011-05-20 15:15:34 -05001065 }
1066
1067 [CLSCompliant(false)]
1068 public void WriteRawLittleEndian64(ulong value)
1069 {
csharptestc671a4b2011-06-08 11:51:24 -05001070 if (position + 8 > limit)
1071 {
1072 WriteRawByte((byte) value);
1073 WriteRawByte((byte) (value >> 8));
1074 WriteRawByte((byte) (value >> 16));
1075 WriteRawByte((byte) (value >> 24));
1076 WriteRawByte((byte) (value >> 32));
1077 WriteRawByte((byte) (value >> 40));
1078 WriteRawByte((byte) (value >> 48));
1079 WriteRawByte((byte) (value >> 56));
1080 }
1081 else
1082 {
1083 buffer[position++] = ((byte)value);
1084 buffer[position++] = ((byte)(value >> 8));
1085 buffer[position++] = ((byte)(value >> 16));
1086 buffer[position++] = ((byte)(value >> 24));
1087 buffer[position++] = ((byte)(value >> 32));
1088 buffer[position++] = ((byte)(value >> 40));
1089 buffer[position++] = ((byte)(value >> 48));
1090 buffer[position++] = ((byte)(value >> 56));
1091 }
csharptest71f662c2011-05-20 15:15:34 -05001092 }
1093
1094 public void WriteRawByte(byte value)
1095 {
1096 if (position == limit)
1097 {
1098 RefreshBuffer();
1099 }
1100
1101 buffer[position++] = value;
1102 }
1103
1104 [CLSCompliant(false)]
1105 public void WriteRawByte(uint value)
1106 {
1107 WriteRawByte((byte) value);
1108 }
1109
1110 /// <summary>
1111 /// Writes out an array of bytes.
1112 /// </summary>
1113 public void WriteRawBytes(byte[] value)
1114 {
1115 WriteRawBytes(value, 0, value.Length);
1116 }
1117
1118 /// <summary>
1119 /// Writes out part of an array of bytes.
1120 /// </summary>
1121 public void WriteRawBytes(byte[] value, int offset, int length)
1122 {
1123 if (limit - position >= length)
1124 {
csharptestaef072a2011-06-08 18:00:43 -05001125 ByteArray.Copy(value, offset, buffer, position, length);
csharptest71f662c2011-05-20 15:15:34 -05001126 // We have room in the current buffer.
1127 position += length;
1128 }
1129 else
1130 {
1131 // Write extends past current buffer. Fill the rest of this buffer and
1132 // flush.
1133 int bytesWritten = limit - position;
csharptestaef072a2011-06-08 18:00:43 -05001134 ByteArray.Copy(value, offset, buffer, position, bytesWritten);
csharptest71f662c2011-05-20 15:15:34 -05001135 offset += bytesWritten;
1136 length -= bytesWritten;
1137 position = limit;
1138 RefreshBuffer();
1139
1140 // Now deal with the rest.
1141 // Since we have an output stream, this is our buffer
1142 // and buffer offset == 0
1143 if (length <= limit)
1144 {
1145 // Fits in new buffer.
csharptestaef072a2011-06-08 18:00:43 -05001146 ByteArray.Copy(value, offset, buffer, 0, length);
csharptest71f662c2011-05-20 15:15:34 -05001147 position = length;
1148 }
1149 else
1150 {
1151 // Write is very big. Let's do it all at once.
1152 output.Write(value, offset, length);
1153 }
1154 }
1155 }
1156
1157 #endregion
csharptest71f662c2011-05-20 15:15:34 -05001158 /// <summary>
1159 /// Encode a 32-bit value with ZigZag encoding.
1160 /// </summary>
1161 /// <remarks>
1162 /// ZigZag encodes signed integers into values that can be efficiently
1163 /// encoded with varint. (Otherwise, negative values must be
1164 /// sign-extended to 64 bits to be varint encoded, thus always taking
1165 /// 10 bytes on the wire.)
1166 /// </remarks>
1167 [CLSCompliant(false)]
1168 public static uint EncodeZigZag32(int n)
1169 {
1170 // Note: the right-shift must be arithmetic
1171 return (uint) ((n << 1) ^ (n >> 31));
1172 }
1173
1174 /// <summary>
1175 /// Encode a 64-bit value with ZigZag encoding.
1176 /// </summary>
1177 /// <remarks>
1178 /// ZigZag encodes signed integers into values that can be efficiently
1179 /// encoded with varint. (Otherwise, negative values must be
1180 /// sign-extended to 64 bits to be varint encoded, thus always taking
1181 /// 10 bytes on the wire.)
1182 /// </remarks>
1183 [CLSCompliant(false)]
1184 public static ulong EncodeZigZag64(long n)
1185 {
1186 return (ulong) ((n << 1) ^ (n >> 63));
1187 }
1188
1189 private void RefreshBuffer()
1190 {
1191 if (output == null)
1192 {
1193 // We're writing to a single buffer.
1194 throw new OutOfSpaceException();
1195 }
1196
1197 // Since we have an output stream, this is our buffer
1198 // and buffer offset == 0
1199 output.Write(buffer, 0, position);
1200 position = 0;
1201 }
1202
1203 /// <summary>
1204 /// Indicates that a CodedOutputStream wrapping a flat byte array
1205 /// ran out of space.
1206 /// </summary>
1207 public sealed class OutOfSpaceException : IOException
1208 {
1209 internal OutOfSpaceException()
1210 : base("CodedOutputStream was writing to a flat byte array and ran out of space.")
1211 {
1212 }
1213 }
1214
1215 public void Flush()
1216 {
1217 if (output != null)
1218 {
1219 RefreshBuffer();
1220 }
1221 }
1222
1223 /// <summary>
1224 /// Verifies that SpaceLeft returns zero. It's common to create a byte array
1225 /// that is exactly big enough to hold a message, then write to it with
1226 /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
1227 /// the message was actually as big as expected, which can help bugs.
1228 /// </summary>
1229 public void CheckNoSpaceLeft()
1230 {
1231 if (SpaceLeft != 0)
1232 {
1233 throw new InvalidOperationException("Did not write as much data as expected.");
1234 }
1235 }
1236
1237 /// <summary>
1238 /// If writing to a flat array, returns the space left in the array. Otherwise,
1239 /// throws an InvalidOperationException.
1240 /// </summary>
1241 public int SpaceLeft
1242 {
1243 get
1244 {
1245 if (output == null)
1246 {
1247 return limit - position;
1248 }
1249 else
1250 {
1251 throw new InvalidOperationException(
1252 "SpaceLeft can only be called on CodedOutputStreams that are " +
1253 "writing to a flat array.");
1254 }
1255 }
1256 }
1257 }
1258}