Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ProtobufCS/0.9.1/ProtobufCS/src/ProtocolBuffers/CodedOutputStream.cs @ 7039

Last change on this file since 7039 was 3857, checked in by abeham, 15 years ago

#866

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