blob: 241c4acbad2e9ae7f28ee44a0e1695a076a7a77d [file] [log] [blame]
Jon Skeet60c059b2008-10-23 21:17:56 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// http://github.com/jskeet/dotnet-protobufs/
4// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01005// http://code.google.com/p/protobuf/
6//
Jon Skeet60c059b2008-10-23 21:17:56 +01007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
Jon Skeet68036862008-10-22 13:30:34 +010010//
Jon Skeet60c059b2008-10-23 21:17:56 +010011// * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17// * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010020//
Jon Skeet60c059b2008-10-23 21:17:56 +010021// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet68036862008-10-22 13:30:34 +010032using System;
33using System.IO;
34using System.Text;
35using Google.ProtocolBuffers.Descriptors;
36
37namespace Google.ProtocolBuffers {
38
39 /// <summary>
40 /// Encodes and writes protocol message fields.
41 /// </summary>
42 /// <remarks>
43 /// This class contains two kinds of methods: methods that write specific
44 /// protocol message constructs and field types (e.g. WriteTag and
45 /// WriteInt32) and methods that write low-level values (e.g.
46 /// WriteRawVarint32 and WriteRawBytes). If you are writing encoded protocol
47 /// messages, you should use the former methods, but if you are writing some
48 /// other format of your own design, use the latter. The names of the former
49 /// methods are taken from the protocol buffer type names, not .NET types.
50 /// (Hence WriteFloat instead of WriteSingle, and WriteBool instead of WriteBoolean.)
51 /// </remarks>
52 public sealed class CodedOutputStream {
53 /// <summary>
54 /// The buffer size used by CreateInstance(Stream).
55 /// </summary>
56 public static readonly int DefaultBufferSize = 4096;
57
58 private readonly byte[] buffer;
59 private readonly int limit;
60 private int position;
61 private readonly Stream output;
62
63 #region Construction
64 private CodedOutputStream(byte[] buffer, int offset, int length) {
65 this.output = null;
66 this.buffer = buffer;
67 this.position = offset;
68 this.limit = offset + length;
69 }
70
71 private CodedOutputStream(Stream output, byte[] buffer) {
72 this.output = output;
73 this.buffer = buffer;
74 this.position = 0;
75 this.limit = buffer.Length;
76 }
77
78 /// <summary>
79 /// Creates a new CodedOutputStream which write to the given stream.
80 /// </summary>
81 public static CodedOutputStream CreateInstance(Stream output) {
82 return CreateInstance(output, DefaultBufferSize);
83 }
84
85 /// <summary>
86 /// Creates a new CodedOutputStream which write to the given stream and uses
87 /// the specified buffer size.
88 /// </summary>
89 public static CodedOutputStream CreateInstance(Stream output, int bufferSize) {
90 return new CodedOutputStream(output, new byte[bufferSize]);
91 }
92
93 /// <summary>
94 /// Creates a new CodedOutputStream that writes directly to the given
95 /// byte array. If more bytes are written than fit in the array,
96 /// OutOfSpaceException will be thrown.
97 /// </summary>
98 public static CodedOutputStream CreateInstance(byte[] flatArray) {
99 return CreateInstance(flatArray, 0, flatArray.Length);
100 }
101
102 /// <summary>
103 /// Creates a new CodedOutputStream that writes directly to the given
104 /// byte array slice. If more bytes are written than fit in the array,
105 /// OutOfSpaceException will be thrown.
106 /// </summary>
107 public static CodedOutputStream CreateInstance(byte[] flatArray, int offset, int length) {
108 return new CodedOutputStream(flatArray, offset, length);
109 }
110 #endregion
111
112 #region Writing of tags etc
113 /// <summary>
114 /// Writes a double field value, including tag, to the stream.
115 /// </summary>
116 public void WriteDouble(int fieldNumber, double value) {
Jon Skeet68036862008-10-22 13:30:34 +0100117 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
Jon Skeet3c808862009-09-09 13:22:36 +0100118 WriteDoubleNoTag(value);
Jon Skeet68036862008-10-22 13:30:34 +0100119 }
120
121 /// <summary>
122 /// Writes a float field value, including tag, to the stream.
123 /// </summary>
124 public void WriteFloat(int fieldNumber, float value) {
125 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
Jon Skeet3c808862009-09-09 13:22:36 +0100126 WriteFloatNoTag(value);
Jon Skeet68036862008-10-22 13:30:34 +0100127 }
128
129 /// <summary>
130 /// Writes a uint64 field value, including tag, to the stream.
131 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100132 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100133 public void WriteUInt64(int fieldNumber, ulong value) {
134 WriteTag(fieldNumber, WireFormat.WireType.Varint);
135 WriteRawVarint64(value);
136 }
137
138 /// <summary>
139 /// Writes an int64 field value, including tag, to the stream.
140 /// </summary>
141 public void WriteInt64(int fieldNumber, long value) {
142 WriteTag(fieldNumber, WireFormat.WireType.Varint);
143 WriteRawVarint64((ulong)value);
144 }
145
146 /// <summary>
147 /// Writes an int32 field value, including tag, to the stream.
148 /// </summary>
149 public void WriteInt32(int fieldNumber, int value) {
150 WriteTag(fieldNumber, WireFormat.WireType.Varint);
151 if (value >= 0) {
152 WriteRawVarint32((uint)value);
153 } else {
154 // Must sign-extend.
155 WriteRawVarint64((ulong)value);
156 }
157 }
158
159 /// <summary>
160 /// Writes a fixed64 field value, including tag, to the stream.
161 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100162 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100163 public void WriteFixed64(int fieldNumber, ulong value) {
164 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
165 WriteRawLittleEndian64(value);
166 }
167
168 /// <summary>
169 /// Writes a fixed32 field value, including tag, to the stream.
170 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100171 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100172 public void WriteFixed32(int fieldNumber, uint value) {
173 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
174 WriteRawLittleEndian32(value);
175 }
176
177 /// <summary>
178 /// Writes a bool field value, including tag, to the stream.
179 /// </summary>
180 public void WriteBool(int fieldNumber, bool value) {
181 WriteTag(fieldNumber, WireFormat.WireType.Varint);
182 WriteRawByte(value ? (byte)1 : (byte)0);
183 }
184
185 /// <summary>
186 /// Writes a string field value, including tag, to the stream.
187 /// </summary>
188 public void WriteString(int fieldNumber, string value) {
189 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
190 // Optimise the case where we have enough space to write
191 // the string directly to the buffer, which should be common.
192 int length = Encoding.UTF8.GetByteCount(value);
193 WriteRawVarint32((uint) length);
194 if (limit - position >= length) {
195 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
196 position += length;
197 } else {
198 byte[] bytes = Encoding.UTF8.GetBytes(value);
199 WriteRawBytes(bytes);
200 }
201 }
202
203 /// <summary>
204 /// Writes a group field value, including tag, to the stream.
205 /// </summary>
206 public void WriteGroup(int fieldNumber, IMessage value) {
207 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
208 value.WriteTo(this);
209 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
210 }
211
212 public void WriteUnknownGroup(int fieldNumber, UnknownFieldSet value) {
213 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
214 value.WriteTo(this);
215 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
216 }
217
218 public void WriteMessage(int fieldNumber, IMessage value) {
219 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
220 WriteRawVarint32((uint)value.SerializedSize);
221 value.WriteTo(this);
222 }
223
224 public void WriteBytes(int fieldNumber, ByteString value) {
225 // TODO(jonskeet): Optimise this! (No need to copy the bytes twice.)
226 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
227 byte[] bytes = value.ToByteArray();
228 WriteRawVarint32((uint)bytes.Length);
229 WriteRawBytes(bytes);
230 }
231
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100232 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100233 public void WriteUInt32(int fieldNumber, uint value) {
234 WriteTag(fieldNumber, WireFormat.WireType.Varint);
235 WriteRawVarint32(value);
236 }
237
238 public void WriteEnum(int fieldNumber, int value) {
239 WriteTag(fieldNumber, WireFormat.WireType.Varint);
240 WriteRawVarint32((uint)value);
241 }
242
243 public void WriteSFixed32(int fieldNumber, int value) {
244 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
245 WriteRawLittleEndian32((uint)value);
246 }
247
248 public void WriteSFixed64(int fieldNumber, long value) {
249 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
250 WriteRawLittleEndian64((ulong)value);
251 }
252
253 public void WriteSInt32(int fieldNumber, int value) {
254 WriteTag(fieldNumber, WireFormat.WireType.Varint);
255 WriteRawVarint32(EncodeZigZag32(value));
256 }
257
258 public void WriteSInt64(int fieldNumber, long value) {
259 WriteTag(fieldNumber, WireFormat.WireType.Varint);
260 WriteRawVarint64(EncodeZigZag64(value));
261 }
262
263 public void WriteMessageSetExtension(int fieldNumber, IMessage value) {
264 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
265 WriteUInt32(WireFormat.MessageSetField.TypeID, (uint)fieldNumber);
266 WriteMessage(WireFormat.MessageSetField.Message, value);
267 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
268 }
269
270 public void WriteRawMessageSetExtension(int fieldNumber, ByteString value) {
271 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
272 WriteUInt32(WireFormat.MessageSetField.TypeID, (uint)fieldNumber);
273 WriteBytes(WireFormat.MessageSetField.Message, value);
274 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
275 }
276
277 public void WriteField(FieldType fieldType, int fieldNumber, object value) {
278 switch (fieldType) {
279 case FieldType.Double: WriteDouble(fieldNumber, (double)value); break;
280 case FieldType.Float: WriteFloat(fieldNumber, (float)value); break;
281 case FieldType.Int64: WriteInt64(fieldNumber, (long)value); break;
282 case FieldType.UInt64: WriteUInt64(fieldNumber, (ulong)value); break;
283 case FieldType.Int32: WriteInt32(fieldNumber, (int)value); break;
284 case FieldType.Fixed64: WriteFixed64(fieldNumber, (ulong)value); break;
285 case FieldType.Fixed32: WriteFixed32(fieldNumber, (uint)value); break;
286 case FieldType.Bool: WriteBool(fieldNumber, (bool)value); break;
287 case FieldType.String: WriteString(fieldNumber, (string)value); break;
288 case FieldType.Group: WriteGroup(fieldNumber, (IMessage)value); break;
289 case FieldType.Message: WriteMessage(fieldNumber, (IMessage)value); break;
290 case FieldType.Bytes: WriteBytes(fieldNumber, (ByteString)value); break;
291 case FieldType.UInt32: WriteUInt32(fieldNumber, (uint)value); break;
292 case FieldType.SFixed32: WriteSFixed32(fieldNumber, (int)value); break;
293 case FieldType.SFixed64: WriteSFixed64(fieldNumber, (long)value); break;
294 case FieldType.SInt32: WriteSInt32(fieldNumber, (int)value); break;
295 case FieldType.SInt64: WriteSInt64(fieldNumber, (long)value); break;
296 case FieldType.Enum: WriteEnum(fieldNumber, ((EnumValueDescriptor)value).Number);
297 break;
298 }
299 }
300
Jon Skeet25a28582009-02-18 16:06:22 +0000301 public void WriteFieldNoTag(FieldType fieldType, object value) {
302 switch (fieldType) {
303 case FieldType.Double: WriteDoubleNoTag((double)value); break;
304 case FieldType.Float: WriteFloatNoTag((float)value); break;
305 case FieldType.Int64: WriteInt64NoTag((long)value); break;
306 case FieldType.UInt64: WriteUInt64NoTag((ulong)value); break;
307 case FieldType.Int32: WriteInt32NoTag((int)value); break;
308 case FieldType.Fixed64: WriteFixed64NoTag((ulong)value); break;
309 case FieldType.Fixed32: WriteFixed32NoTag((uint)value); break;
310 case FieldType.Bool: WriteBoolNoTag((bool)value); break;
311 case FieldType.String: WriteStringNoTag((string)value); break;
312 case FieldType.Group: WriteGroupNoTag((IMessage)value); break;
313 case FieldType.Message: WriteMessageNoTag((IMessage)value); break;
314 case FieldType.Bytes: WriteBytesNoTag((ByteString)value); break;
315 case FieldType.UInt32: WriteUInt32NoTag((uint)value); break;
316 case FieldType.SFixed32: WriteSFixed32NoTag((int)value); break;
317 case FieldType.SFixed64: WriteSFixed64NoTag((long)value); break;
318 case FieldType.SInt32: WriteSInt32NoTag((int)value); break;
319 case FieldType.SInt64: WriteSInt64NoTag((long)value); break;
320 case FieldType.Enum: WriteEnumNoTag(((EnumValueDescriptor)value).Number);
321 break;
322 }
323 }
324 #endregion
325
326 #region Writing of values without tags
327 /// <summary>
328 /// Writes a double field value, including tag, to the stream.
329 /// </summary>
330 public void WriteDoubleNoTag(double value) {
Jon Skeet3c808862009-09-09 13:22:36 +0100331 // TODO(jonskeet): Test this on different endiannesses
332#if SILVERLIGHT2
333 byte[] bytes = BitConverter.GetBytes(value);
334 WriteRawBytes(bytes, 0, 8);
335#else
Jon Skeet25a28582009-02-18 16:06:22 +0000336 WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
Jon Skeet3c808862009-09-09 13:22:36 +0100337#endif
Jon Skeet25a28582009-02-18 16:06:22 +0000338 }
339
340 /// <summary>
341 /// Writes a float field value, without a tag, to the stream.
342 /// </summary>
343 public void WriteFloatNoTag(float value) {
344 // TODO(jonskeet): Test this on different endiannesses
345 byte[] rawBytes = BitConverter.GetBytes(value);
346 uint asInteger = BitConverter.ToUInt32(rawBytes, 0);
347 WriteRawLittleEndian32(asInteger);
348 }
349
350 /// <summary>
351 /// Writes a uint64 field value, without a tag, to the stream.
352 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100353 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000354 public void WriteUInt64NoTag(ulong value) {
355 WriteRawVarint64(value);
356 }
357
358 /// <summary>
359 /// Writes an int64 field value, without a tag, to the stream.
360 /// </summary>
361 public void WriteInt64NoTag(long value) {
362 WriteRawVarint64((ulong)value);
363 }
364
365 /// <summary>
366 /// Writes an int32 field value, without a tag, to the stream.
367 /// </summary>
368 public void WriteInt32NoTag(int value) {
369 if (value >= 0) {
370 WriteRawVarint32((uint)value);
371 } else {
372 // Must sign-extend.
373 WriteRawVarint64((ulong)value);
374 }
375 }
376
377 /// <summary>
378 /// Writes a fixed64 field value, without a tag, to the stream.
379 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100380 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000381 public void WriteFixed64NoTag(ulong value) {
382 WriteRawLittleEndian64(value);
383 }
384
385 /// <summary>
386 /// Writes a fixed32 field value, without a tag, to the stream.
387 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100388 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000389 public void WriteFixed32NoTag(uint value) {
390 WriteRawLittleEndian32(value);
391 }
392
393 /// <summary>
394 /// Writes a bool field value, without a tag, to the stream.
395 /// </summary>
396 public void WriteBoolNoTag(bool value) {
397 WriteRawByte(value ? (byte)1 : (byte)0);
398 }
399
400 /// <summary>
401 /// Writes a string field value, without a tag, to the stream.
402 /// </summary>
403 public void WriteStringNoTag(string value) {
404 // Optimise the case where we have enough space to write
405 // the string directly to the buffer, which should be common.
406 int length = Encoding.UTF8.GetByteCount(value);
407 WriteRawVarint32((uint)length);
408 if (limit - position >= length) {
409 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
410 position += length;
411 } else {
412 byte[] bytes = Encoding.UTF8.GetBytes(value);
413 WriteRawBytes(bytes);
414 }
415 }
416
417 /// <summary>
418 /// Writes a group field value, without a tag, to the stream.
419 /// </summary>
420 public void WriteGroupNoTag(IMessage value) {
421 value.WriteTo(this);
422 }
423
424 public void WriteMessageNoTag(IMessage value) {
425 WriteRawVarint32((uint)value.SerializedSize);
426 value.WriteTo(this);
427 }
428
429 public void WriteBytesNoTag(ByteString value) {
430 // TODO(jonskeet): Optimise this! (No need to copy the bytes twice.)
431 byte[] bytes = value.ToByteArray();
432 WriteRawVarint32((uint)bytes.Length);
433 WriteRawBytes(bytes);
434 }
435
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100436 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000437 public void WriteUInt32NoTag(uint value) {
438 WriteRawVarint32(value);
439 }
440
441 public void WriteEnumNoTag(int value) {
442 WriteRawVarint32((uint)value);
443 }
444
445 public void WriteSFixed32NoTag(int value) {
446 WriteRawLittleEndian32((uint)value);
447 }
448
449 public void WriteSFixed64NoTag(long value) {
450 WriteRawLittleEndian64((ulong)value);
451 }
452
453 public void WriteSInt32NoTag(int value) {
454 WriteRawVarint32(EncodeZigZag32(value));
455 }
456
457 public void WriteSInt64NoTag(long value) {
458 WriteRawVarint64(EncodeZigZag64(value));
459 }
460
Jon Skeet68036862008-10-22 13:30:34 +0100461 #endregion
462
463 #region Underlying writing primitives
464 /// <summary>
465 /// Encodes and writes a tag.
466 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100467 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100468 public void WriteTag(int fieldNumber, WireFormat.WireType type) {
469 WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
470 }
471
472 private void SlowWriteRawVarint32(uint value) {
473 while (true) {
474 if ((value & ~0x7F) == 0) {
475 WriteRawByte(value);
476 return;
477 } else {
478 WriteRawByte((value & 0x7F) | 0x80);
479 value >>= 7;
480 }
481 }
482 }
483
484 /// <summary>
485 /// Writes a 32 bit value as a varint. The fast route is taken when
486 /// there's enough buffer space left to whizz through without checking
487 /// for each byte; otherwise, we resort to calling WriteRawByte each time.
488 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100489 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100490 public void WriteRawVarint32(uint value) {
491 if (position + 5 > limit) {
492 SlowWriteRawVarint32(value);
493 return;
494 }
495
496 while (true) {
497 if ((value & ~0x7F) == 0) {
498 buffer[position++] = (byte) value;
499 return;
500 } else {
501 buffer[position++] = (byte)((value & 0x7F) | 0x80);
502 value >>= 7;
503 }
504 }
505 }
506
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100507 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100508 public void WriteRawVarint64(ulong value) {
509 while (true) {
510 if ((value & ~0x7FUL) == 0) {
511 WriteRawByte((uint)value);
512 return;
513 } else {
514 WriteRawByte(((uint)value & 0x7F) | 0x80);
515 value >>= 7;
516 }
517 }
518 }
519
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100520 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100521 public void WriteRawLittleEndian32(uint value) {
522 WriteRawByte((byte)value);
523 WriteRawByte((byte)(value >> 8));
524 WriteRawByte((byte)(value >> 16));
525 WriteRawByte((byte)(value >> 24));
526 }
527
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100528 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100529 public void WriteRawLittleEndian64(ulong value) {
530 WriteRawByte((byte)value);
531 WriteRawByte((byte)(value >> 8));
532 WriteRawByte((byte)(value >> 16));
533 WriteRawByte((byte)(value >> 24));
534 WriteRawByte((byte)(value >> 32));
535 WriteRawByte((byte)(value >> 40));
536 WriteRawByte((byte)(value >> 48));
537 WriteRawByte((byte)(value >> 56));
538 }
539
540 public void WriteRawByte(byte value) {
541 if (position == limit) {
542 RefreshBuffer();
543 }
544
545 buffer[position++] = value;
546 }
547
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100548 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100549 public void WriteRawByte(uint value) {
550 WriteRawByte((byte)value);
551 }
552
553 /// <summary>
554 /// Writes out an array of bytes.
555 /// </summary>
556 public void WriteRawBytes(byte[] value) {
557 WriteRawBytes(value, 0, value.Length);
558 }
559
560 /// <summary>
561 /// Writes out part of an array of bytes.
562 /// </summary>
563 public void WriteRawBytes(byte[] value, int offset, int length) {
564 if (limit - position >= length) {
565 Array.Copy(value, offset, buffer, position, length);
566 // We have room in the current buffer.
567 position += length;
568 } else {
569 // Write extends past current buffer. Fill the rest of this buffer and
570 // flush.
571 int bytesWritten = limit - position;
572 Array.Copy(value, offset, buffer, position, bytesWritten);
573 offset += bytesWritten;
574 length -= bytesWritten;
575 position = limit;
576 RefreshBuffer();
577
578 // Now deal with the rest.
579 // Since we have an output stream, this is our buffer
580 // and buffer offset == 0
581 if (length <= limit) {
582 // Fits in new buffer.
583 Array.Copy(value, offset, buffer, 0, length);
584 position = length;
585 } else {
586 // Write is very big. Let's do it all at once.
587 output.Write(value, offset, length);
588 }
589 }
590 }
591 #endregion
592
593 #region Size computations
594
595 const int LittleEndian64Size = 8;
596 const int LittleEndian32Size = 4;
597
598 /// <summary>
599 /// Compute the number of bytes that would be needed to encode a
600 /// double field, including the tag.
601 /// </summary>
602 public static int ComputeDoubleSize(int fieldNumber, double value) {
603 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
604 }
605
606 /// <summary>
607 /// Compute the number of bytes that would be needed to encode a
608 /// float field, including the tag.
609 /// </summary>
610 public static int ComputeFloatSize(int fieldNumber, float value) {
611 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
612 }
613
614 /// <summary>
615 /// Compute the number of bytes that would be needed to encode a
616 /// uint64 field, including the tag.
617 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100618 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100619 public static int ComputeUInt64Size(int fieldNumber, ulong value) {
620 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(value);
621 }
622
623 /// <summary>
624 /// Compute the number of bytes that would be needed to encode an
625 /// int64 field, including the tag.
626 /// </summary>
627 public static int ComputeInt64Size(int fieldNumber, long value) {
628 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size((ulong)value);
629 }
630
631 /// <summary>
632 /// Compute the number of bytes that would be needed to encode an
633 /// int32 field, including the tag.
634 /// </summary>
635 public static int ComputeInt32Size(int fieldNumber, int value) {
636 if (value >= 0) {
637 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint)value);
638 } else {
639 // Must sign-extend.
640 return ComputeTagSize(fieldNumber) + 10;
641 }
642 }
643
644 /// <summary>
645 /// Compute the number of bytes that would be needed to encode a
646 /// fixed64 field, including the tag.
647 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100648 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100649 public static int ComputeFixed64Size(int fieldNumber, ulong value) {
650 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
651 }
652
653 /// <summary>
654 /// Compute the number of bytes that would be needed to encode a
655 /// fixed32 field, including the tag.
656 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100657 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100658 public static int ComputeFixed32Size(int fieldNumber, uint value) {
659 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
660 }
661
662 /// <summary>
663 /// Compute the number of bytes that would be needed to encode a
664 /// bool field, including the tag.
665 /// </summary>
666 public static int ComputeBoolSize(int fieldNumber, bool value) {
667 return ComputeTagSize(fieldNumber) + 1;
668 }
669
670 /// <summary>
671 /// Compute the number of bytes that would be needed to encode a
672 /// string field, including the tag.
673 /// </summary>
674 public static int ComputeStringSize(int fieldNumber, String value) {
675 int byteArraySize = Encoding.UTF8.GetByteCount(value);
676 return ComputeTagSize(fieldNumber) +
677 ComputeRawVarint32Size((uint)byteArraySize) +
678 byteArraySize;
679 }
680
681 /// <summary>
682 /// Compute the number of bytes that would be needed to encode a
683 /// group field, including the tag.
684 /// </summary>
685 public static int ComputeGroupSize(int fieldNumber, IMessage value) {
686 return ComputeTagSize(fieldNumber) * 2 + value.SerializedSize;
687 }
688
689 /// <summary>
690 /// Compute the number of bytes that would be needed to encode a
691 /// group field represented by an UnknownFieldSet, including the tag.
692 /// </summary>
693 public static int ComputeUnknownGroupSize(int fieldNumber,
694 UnknownFieldSet value) {
695 return ComputeTagSize(fieldNumber) * 2 + value.SerializedSize;
696 }
697
698 /// <summary>
699 /// Compute the number of bytes that would be needed to encode an
700 /// embedded message field, including the tag.
701 /// </summary>
702 public static int ComputeMessageSize(int fieldNumber, IMessage value) {
703 int size = value.SerializedSize;
704 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint)size) + size;
705 }
706
707 /// <summary>
708 /// Compute the number of bytes that would be needed to encode a
709 /// bytes field, including the tag.
710 /// </summary>
711 public static int ComputeBytesSize(int fieldNumber, ByteString value) {
712 return ComputeTagSize(fieldNumber) +
713 ComputeRawVarint32Size((uint)value.Length) +
714 value.Length;
715 }
716
717 /// <summary>
718 /// Compute the number of bytes that would be needed to encode a
719 /// uint32 field, including the tag.
720 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100721 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100722 public static int ComputeUInt32Size(int fieldNumber, uint value) {
723 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(value);
724 }
725
726 /// <summary>
727 /// Compute the number of bytes that would be needed to encode a
728 /// enum field, including the tag. The caller is responsible for
729 /// converting the enum value to its numeric value.
730 /// </summary>
731 public static int ComputeEnumSize(int fieldNumber, int value) {
732 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint)value);
733 }
734
735 /// <summary>
736 /// Compute the number of bytes that would be needed to encode an
737 /// sfixed32 field, including the tag.
738 /// </summary>
739 public static int ComputeSFixed32Size(int fieldNumber, int value) {
740 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
741 }
742
743 /// <summary>
744 /// Compute the number of bytes that would be needed to encode an
745 /// sfixed64 field, including the tag.
746 /// </summary>
747 public static int ComputeSFixed64Size(int fieldNumber, long value) {
748 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
749 }
750
751 /// <summary>
752 /// Compute the number of bytes that would be needed to encode an
753 /// sint32 field, including the tag.
754 /// </summary>
755 public static int ComputeSInt32Size(int fieldNumber, int value) {
Jon Skeet25a28582009-02-18 16:06:22 +0000756 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(EncodeZigZag32(value));
Jon Skeet68036862008-10-22 13:30:34 +0100757 }
758
759 /// <summary>
760 /// Compute the number of bytes that would be needed to encode an
761 /// sint64 field, including the tag.
762 /// </summary>
763 public static int ComputeSInt64Size(int fieldNumber, long value) {
Jon Skeet25a28582009-02-18 16:06:22 +0000764 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(EncodeZigZag64(value));
765 }
766
767 /// <summary>
768 /// Compute the number of bytes that would be needed to encode a
769 /// double field, including the tag.
770 /// </summary>
771 public static int ComputeDoubleSizeNoTag(double value) {
772 return LittleEndian64Size;
773 }
774
775 /// <summary>
776 /// Compute the number of bytes that would be needed to encode a
777 /// float field, including the tag.
778 /// </summary>
779 public static int ComputeFloatSizeNoTag(float value) {
780 return LittleEndian32Size;
781 }
782
783 /// <summary>
784 /// Compute the number of bytes that would be needed to encode a
785 /// uint64 field, including the tag.
786 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100787 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000788 public static int ComputeUInt64SizeNoTag(ulong value) {
789 return ComputeRawVarint64Size(value);
790 }
791
792 /// <summary>
793 /// Compute the number of bytes that would be needed to encode an
794 /// int64 field, including the tag.
795 /// </summary>
796 public static int ComputeInt64SizeNoTag(long value) {
797 return ComputeRawVarint64Size((ulong)value);
798 }
799
800 /// <summary>
801 /// Compute the number of bytes that would be needed to encode an
802 /// int32 field, including the tag.
803 /// </summary>
804 public static int ComputeInt32SizeNoTag(int value) {
805 if (value >= 0) {
806 return ComputeRawVarint32Size((uint)value);
807 } else {
808 // Must sign-extend.
809 return 10;
810 }
811 }
812
813 /// <summary>
814 /// Compute the number of bytes that would be needed to encode a
815 /// fixed64 field, including the tag.
816 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100817 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000818 public static int ComputeFixed64SizeNoTag(ulong value) {
819 return LittleEndian64Size;
820 }
821
822 /// <summary>
823 /// Compute the number of bytes that would be needed to encode a
824 /// fixed32 field, including the tag.
825 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100826 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000827 public static int ComputeFixed32SizeNoTag(uint value) {
828 return LittleEndian32Size;
829 }
830
831 /// <summary>
832 /// Compute the number of bytes that would be needed to encode a
833 /// bool field, including the tag.
834 /// </summary>
835 public static int ComputeBoolSizeNoTag(bool value) {
836 return 1;
837 }
838
839 /// <summary>
840 /// Compute the number of bytes that would be needed to encode a
841 /// string field, including the tag.
842 /// </summary>
843 public static int ComputeStringSizeNoTag(String value) {
844 int byteArraySize = Encoding.UTF8.GetByteCount(value);
845 return ComputeRawVarint32Size((uint)byteArraySize) +
846 byteArraySize;
847 }
848
849 /// <summary>
850 /// Compute the number of bytes that would be needed to encode a
851 /// group field, including the tag.
852 /// </summary>
853 public static int ComputeGroupSizeNoTag(IMessage value) {
854 return value.SerializedSize;
855 }
856
857 /// <summary>
858 /// Compute the number of bytes that would be needed to encode a
859 /// group field represented by an UnknownFieldSet, including the tag.
860 /// </summary>
861 public static int ComputeUnknownGroupSizeNoTag(UnknownFieldSet value) {
862 return value.SerializedSize;
863 }
864
865 /// <summary>
866 /// Compute the number of bytes that would be needed to encode an
867 /// embedded message field, including the tag.
868 /// </summary>
869 public static int ComputeMessageSizeNoTag(IMessage value) {
870 int size = value.SerializedSize;
871 return ComputeRawVarint32Size((uint)size) + size;
872 }
873
874 /// <summary>
875 /// Compute the number of bytes that would be needed to encode a
876 /// bytes field, including the tag.
877 /// </summary>
878 public static int ComputeBytesSizeNoTag(ByteString value) {
879 return ComputeRawVarint32Size((uint)value.Length) +
880 value.Length;
881 }
882
883 /// <summary>
884 /// Compute the number of bytes that would be needed to encode a
885 /// uint32 field, including the tag.
886 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100887 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000888 public static int ComputeUInt32SizeNoTag(uint value) {
889 return ComputeRawVarint32Size(value);
890 }
891
892 /// <summary>
893 /// Compute the number of bytes that would be needed to encode a
894 /// enum field, including the tag. The caller is responsible for
895 /// converting the enum value to its numeric value.
896 /// </summary>
897 public static int ComputeEnumSizeNoTag(int value) {
898 return ComputeRawVarint32Size((uint)value);
899 }
900
901 /// <summary>
902 /// Compute the number of bytes that would be needed to encode an
903 /// sfixed32 field, including the tag.
904 /// </summary>
905 public static int ComputeSFixed32SizeNoTag(int value) {
906 return LittleEndian32Size;
907 }
908
909 /// <summary>
910 /// Compute the number of bytes that would be needed to encode an
911 /// sfixed64 field, including the tag.
912 /// </summary>
913 public static int ComputeSFixed64SizeNoTag(long value) {
914 return LittleEndian64Size;
915 }
916
917 /// <summary>
918 /// Compute the number of bytes that would be needed to encode an
919 /// sint32 field, including the tag.
920 /// </summary>
921 public static int ComputeSInt32SizeNoTag(int value) {
922 return ComputeRawVarint32Size(EncodeZigZag32(value));
923 }
924
925 /// <summary>
926 /// Compute the number of bytes that would be needed to encode an
927 /// sint64 field, including the tag.
928 /// </summary>
929 public static int ComputeSInt64SizeNoTag(long value) {
930 return ComputeRawVarint64Size(EncodeZigZag64(value));
Jon Skeet68036862008-10-22 13:30:34 +0100931 }
932
933 /*
934 * Compute the number of bytes that would be needed to encode a
935 * MessageSet extension to the stream. For historical reasons,
936 * the wire format differs from normal fields.
937 */
938 /// <summary>
939 /// Compute the number of bytes that would be needed to encode a
940 /// MessageSet extension to the stream. For historical reasons,
941 /// the wire format differs from normal fields.
942 /// </summary>
943 public static int ComputeMessageSetExtensionSize(int fieldNumber, IMessage value) {
944 return ComputeTagSize(WireFormat.MessageSetField.Item) * 2 +
945 ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
946 ComputeMessageSize(WireFormat.MessageSetField.Message, value);
947 }
948
949 /// <summary>
950 /// Compute the number of bytes that would be needed to encode an
951 /// unparsed MessageSet extension field to the stream. For
952 /// historical reasons, the wire format differs from normal fields.
953 /// </summary>
954 public static int ComputeRawMessageSetExtensionSize(int fieldNumber, ByteString value) {
955 return ComputeTagSize(WireFormat.MessageSetField.Item) * 2 +
956 ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
957 ComputeBytesSize(WireFormat.MessageSetField.Message, value);
958 }
959
960 /// <summary>
961 /// Compute the number of bytes that would be needed to encode a varint.
962 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100963 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100964 public static int ComputeRawVarint32Size(uint value) {
965 if ((value & (0xffffffff << 7)) == 0) return 1;
966 if ((value & (0xffffffff << 14)) == 0) return 2;
967 if ((value & (0xffffffff << 21)) == 0) return 3;
968 if ((value & (0xffffffff << 28)) == 0) return 4;
969 return 5;
970 }
971
972 /// <summary>
973 /// Compute the number of bytes that would be needed to encode a varint.
974 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100975 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100976 public static int ComputeRawVarint64Size(ulong value) {
977 if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
978 if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
979 if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
980 if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
981 if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
982 if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
983 if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
984 if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
985 if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
986 return 10;
987 }
988
Jon Skeet25a28582009-02-18 16:06:22 +0000989 /// <summary>
990 /// Compute the number of bytes that would be needed to encode a
991 /// field of arbitrary type, including the tag, to the stream.
992 /// </summary>
Jon Skeet68036862008-10-22 13:30:34 +0100993 public static int ComputeFieldSize(FieldType fieldType, int fieldNumber, Object value) {
994 switch (fieldType) {
995 case FieldType.Double: return ComputeDoubleSize(fieldNumber, (double)value);
996 case FieldType.Float: return ComputeFloatSize(fieldNumber, (float)value);
997 case FieldType.Int64: return ComputeInt64Size(fieldNumber, (long)value);
998 case FieldType.UInt64: return ComputeUInt64Size(fieldNumber, (ulong)value);
999 case FieldType.Int32: return ComputeInt32Size(fieldNumber, (int)value);
1000 case FieldType.Fixed64: return ComputeFixed64Size(fieldNumber, (ulong)value);
1001 case FieldType.Fixed32: return ComputeFixed32Size(fieldNumber, (uint)value);
1002 case FieldType.Bool: return ComputeBoolSize(fieldNumber, (bool)value);
1003 case FieldType.String: return ComputeStringSize(fieldNumber, (string)value);
1004 case FieldType.Group: return ComputeGroupSize(fieldNumber, (IMessage)value);
1005 case FieldType.Message: return ComputeMessageSize(fieldNumber, (IMessage)value);
1006 case FieldType.Bytes: return ComputeBytesSize(fieldNumber, (ByteString)value);
1007 case FieldType.UInt32: return ComputeUInt32Size(fieldNumber, (uint)value);
1008 case FieldType.SFixed32: return ComputeSFixed32Size(fieldNumber, (int)value);
1009 case FieldType.SFixed64: return ComputeSFixed64Size(fieldNumber, (long)value);
1010 case FieldType.SInt32: return ComputeSInt32Size(fieldNumber, (int)value);
1011 case FieldType.SInt64: return ComputeSInt64Size(fieldNumber, (long)value);
1012 case FieldType.Enum: return ComputeEnumSize(fieldNumber, ((EnumValueDescriptor)value).Number);
1013 default:
1014 throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
1015 }
1016 }
1017
1018 /// <summary>
Jon Skeet25a28582009-02-18 16:06:22 +00001019 /// Compute the number of bytes that would be needed to encode a
1020 /// field of arbitrary type, excluding the tag, to the stream.
1021 /// </summary>
1022 public static int ComputeFieldSizeNoTag(FieldType fieldType, Object value) {
1023 switch (fieldType) {
1024 case FieldType.Double: return ComputeDoubleSizeNoTag((double)value);
1025 case FieldType.Float: return ComputeFloatSizeNoTag((float)value);
1026 case FieldType.Int64: return ComputeInt64SizeNoTag((long)value);
1027 case FieldType.UInt64: return ComputeUInt64SizeNoTag((ulong)value);
1028 case FieldType.Int32: return ComputeInt32SizeNoTag((int)value);
1029 case FieldType.Fixed64: return ComputeFixed64SizeNoTag((ulong)value);
1030 case FieldType.Fixed32: return ComputeFixed32SizeNoTag((uint)value);
1031 case FieldType.Bool: return ComputeBoolSizeNoTag((bool)value);
1032 case FieldType.String: return ComputeStringSizeNoTag((string)value);
1033 case FieldType.Group: return ComputeGroupSizeNoTag((IMessage)value);
1034 case FieldType.Message: return ComputeMessageSizeNoTag((IMessage)value);
1035 case FieldType.Bytes: return ComputeBytesSizeNoTag((ByteString)value);
1036 case FieldType.UInt32: return ComputeUInt32SizeNoTag((uint)value);
1037 case FieldType.SFixed32: return ComputeSFixed32SizeNoTag((int)value);
1038 case FieldType.SFixed64: return ComputeSFixed64SizeNoTag((long)value);
1039 case FieldType.SInt32: return ComputeSInt32SizeNoTag((int)value);
1040 case FieldType.SInt64: return ComputeSInt64SizeNoTag((long)value);
1041 case FieldType.Enum: return ComputeEnumSizeNoTag(((EnumValueDescriptor)value).Number);
1042 default:
1043 throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
1044 }
1045 }
1046
1047 /// <summary>
Jon Skeet68036862008-10-22 13:30:34 +01001048 /// Compute the number of bytes that would be needed to encode a tag.
1049 /// </summary>
1050 public static int ComputeTagSize(int fieldNumber) {
1051 return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));
1052 }
1053 #endregion
1054
1055 /// <summary>
1056 /// Encode a 32-bit value with ZigZag encoding.
1057 /// </summary>
1058 /// <remarks>
1059 /// ZigZag encodes signed integers into values that can be efficiently
1060 /// encoded with varint. (Otherwise, negative values must be
1061 /// sign-extended to 64 bits to be varint encoded, thus always taking
1062 /// 10 bytes on the wire.)
1063 /// </remarks>
Jon Skeetd6dd0a42009-06-05 22:00:05 +01001064 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +01001065 public static uint EncodeZigZag32(int n) {
1066 // Note: the right-shift must be arithmetic
1067 return (uint)((n << 1) ^ (n >> 31));
1068 }
1069
1070 /// <summary>
1071 /// Encode a 64-bit value with ZigZag encoding.
1072 /// </summary>
1073 /// <remarks>
1074 /// ZigZag encodes signed integers into values that can be efficiently
1075 /// encoded with varint. (Otherwise, negative values must be
1076 /// sign-extended to 64 bits to be varint encoded, thus always taking
1077 /// 10 bytes on the wire.)
1078 /// </remarks>
Jon Skeetd6dd0a42009-06-05 22:00:05 +01001079 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +01001080 public static ulong EncodeZigZag64(long n) {
1081 return (ulong)((n << 1) ^ (n >> 63));
1082 }
1083
1084 private void RefreshBuffer() {
1085 if (output == null) {
1086 // We're writing to a single buffer.
1087 throw new OutOfSpaceException();
1088 }
1089
1090 // Since we have an output stream, this is our buffer
1091 // and buffer offset == 0
1092 output.Write(buffer, 0, position);
1093 position = 0;
1094 }
1095
1096 /// <summary>
1097 /// Indicates that a CodedOutputStream wrapping a flat byte array
1098 /// ran out of space.
1099 /// </summary>
1100 public sealed class OutOfSpaceException : IOException {
1101 internal OutOfSpaceException()
1102 : base("CodedOutputStream was writing to a flat byte array and ran out of space.") {
1103 }
1104 }
1105
1106 public void Flush() {
1107 if (output != null) {
1108 RefreshBuffer();
1109 }
1110 }
1111
1112 /// <summary>
1113 /// Verifies that SpaceLeft returns zero. It's common to create a byte array
1114 /// that is exactly big enough to hold a message, then write to it with
1115 /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
1116 /// the message was actually as big as expected, which can help bugs.
1117 /// </summary>
1118 public void CheckNoSpaceLeft() {
1119 if (SpaceLeft != 0) {
1120 throw new InvalidOperationException("Did not write as much data as expected.");
1121 }
1122 }
1123
1124 /// <summary>
1125 /// If writing to a flat array, returns the space left in the array. Otherwise,
1126 /// throws an InvalidOperationException.
1127 /// </summary>
1128 public int SpaceLeft {
1129 get {
1130 if (output == null) {
1131 return limit - position;
1132 } else {
1133 throw new InvalidOperationException(
1134 "SpaceLeft can only be called on CodedOutputStreams that are " +
1135 "writing to a flat array.");
1136 }
1137 }
1138 }
1139 }
1140}