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