blob: ee8a5dc6887db78edba7f886f99753a063e1a6e6 [file] [log] [blame]
csharptest71f662c2011-05-20 15:15:34 -05001#region Copyright notice and license
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc. All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15// * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19// * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35#endregion
36
37using System;
csharptest90922db2011-06-03 11:57:47 -050038using System.Globalization;
csharptest71f662c2011-05-20 15:15:34 -050039using System.IO;
40using System.Text;
41using Google.ProtocolBuffers.Descriptors;
42
43namespace Google.ProtocolBuffers
44{
45 /// <summary>
46 /// Encodes and writes protocol message fields.
47 /// </summary>
48 /// <remarks>
49 /// This class contains two kinds of methods: methods that write specific
50 /// protocol message constructs and field types (e.g. WriteTag and
51 /// WriteInt32) and methods that write low-level values (e.g.
52 /// WriteRawVarint32 and WriteRawBytes). If you are writing encoded protocol
53 /// messages, you should use the former methods, but if you are writing some
54 /// other format of your own design, use the latter. The names of the former
55 /// methods are taken from the protocol buffer type names, not .NET types.
56 /// (Hence WriteFloat instead of WriteSingle, and WriteBool instead of WriteBoolean.)
57 /// </remarks>
csharptest45a93fa2011-06-02 10:52:37 -050058 public sealed partial class CodedOutputStream
csharptest71f662c2011-05-20 15:15:34 -050059 {
60 /// <summary>
61 /// The buffer size used by CreateInstance(Stream).
62 /// </summary>
63 public static readonly int DefaultBufferSize = 4096;
64
65 private readonly byte[] buffer;
66 private readonly int limit;
67 private int position;
68 private readonly Stream output;
69
70 #region Construction
71
72 private CodedOutputStream(byte[] buffer, int offset, int length)
73 {
74 this.output = null;
75 this.buffer = buffer;
76 this.position = offset;
77 this.limit = offset + length;
78 }
79
80 private CodedOutputStream(Stream output, byte[] buffer)
81 {
82 this.output = output;
83 this.buffer = buffer;
84 this.position = 0;
85 this.limit = buffer.Length;
86 }
87
88 /// <summary>
89 /// Creates a new CodedOutputStream which write to the given stream.
90 /// </summary>
91 public static CodedOutputStream CreateInstance(Stream output)
92 {
93 return CreateInstance(output, DefaultBufferSize);
94 }
95
96 /// <summary>
97 /// Creates a new CodedOutputStream which write to the given stream and uses
98 /// the specified buffer size.
99 /// </summary>
100 public static CodedOutputStream CreateInstance(Stream output, int bufferSize)
101 {
102 return new CodedOutputStream(output, new byte[bufferSize]);
103 }
104
105 /// <summary>
106 /// Creates a new CodedOutputStream that writes directly to the given
107 /// byte array. If more bytes are written than fit in the array,
108 /// OutOfSpaceException will be thrown.
109 /// </summary>
110 public static CodedOutputStream CreateInstance(byte[] flatArray)
111 {
112 return CreateInstance(flatArray, 0, flatArray.Length);
113 }
114
115 /// <summary>
116 /// Creates a new CodedOutputStream that writes directly to the given
117 /// byte array slice. If more bytes are written than fit in the array,
118 /// OutOfSpaceException will be thrown.
119 /// </summary>
120 public static CodedOutputStream CreateInstance(byte[] flatArray, int offset, int length)
121 {
122 return new CodedOutputStream(flatArray, offset, length);
123 }
124
125 #endregion
126
127 #region Writing of tags etc
128
129 /// <summary>
130 /// Writes a double field value, including tag, to the stream.
131 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500132 public void WriteDouble(int fieldNumber, string fieldName, double value)
csharptest71f662c2011-05-20 15:15:34 -0500133 {
134 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
135 WriteDoubleNoTag(value);
136 }
137
138 /// <summary>
139 /// Writes a float field value, including tag, to the stream.
140 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500141 public void WriteFloat(int fieldNumber, string fieldName, float value)
csharptest71f662c2011-05-20 15:15:34 -0500142 {
143 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
144 WriteFloatNoTag(value);
145 }
146
147 /// <summary>
148 /// Writes a uint64 field value, including tag, to the stream.
149 /// </summary>
150 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500151 public void WriteUInt64(int fieldNumber, string fieldName, ulong value)
csharptest71f662c2011-05-20 15:15:34 -0500152 {
153 WriteTag(fieldNumber, WireFormat.WireType.Varint);
154 WriteRawVarint64(value);
155 }
156
157 /// <summary>
158 /// Writes an int64 field value, including tag, to the stream.
159 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500160 public void WriteInt64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500161 {
162 WriteTag(fieldNumber, WireFormat.WireType.Varint);
163 WriteRawVarint64((ulong) value);
164 }
165
166 /// <summary>
167 /// Writes an int32 field value, including tag, to the stream.
168 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500169 public void WriteInt32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500170 {
171 WriteTag(fieldNumber, WireFormat.WireType.Varint);
172 if (value >= 0)
173 {
174 WriteRawVarint32((uint) value);
175 }
176 else
177 {
178 // Must sign-extend.
179 WriteRawVarint64((ulong) value);
180 }
181 }
182
183 /// <summary>
184 /// Writes a fixed64 field value, including tag, to the stream.
185 /// </summary>
186 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500187 public void WriteFixed64(int fieldNumber, string fieldName, ulong value)
csharptest71f662c2011-05-20 15:15:34 -0500188 {
189 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
190 WriteRawLittleEndian64(value);
191 }
192
193 /// <summary>
194 /// Writes a fixed32 field value, including tag, to the stream.
195 /// </summary>
196 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500197 public void WriteFixed32(int fieldNumber, string fieldName, uint value)
csharptest71f662c2011-05-20 15:15:34 -0500198 {
199 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
200 WriteRawLittleEndian32(value);
201 }
202
203 /// <summary>
204 /// Writes a bool field value, including tag, to the stream.
205 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500206 public void WriteBool(int fieldNumber, string fieldName, bool value)
csharptest71f662c2011-05-20 15:15:34 -0500207 {
208 WriteTag(fieldNumber, WireFormat.WireType.Varint);
209 WriteRawByte(value ? (byte) 1 : (byte) 0);
210 }
211
212 /// <summary>
213 /// Writes a string field value, including tag, to the stream.
214 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500215 public void WriteString(int fieldNumber, string fieldName, string value)
csharptest71f662c2011-05-20 15:15:34 -0500216 {
217 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
218 // Optimise the case where we have enough space to write
219 // the string directly to the buffer, which should be common.
220 int length = Encoding.UTF8.GetByteCount(value);
221 WriteRawVarint32((uint) length);
222 if (limit - position >= length)
223 {
224 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
225 position += length;
226 }
227 else
228 {
229 byte[] bytes = Encoding.UTF8.GetBytes(value);
230 WriteRawBytes(bytes);
231 }
232 }
233
234 /// <summary>
235 /// Writes a group field value, including tag, to the stream.
236 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500237 public void WriteGroup(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500238 {
239 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
240 value.WriteTo(this);
241 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
242 }
243
244 [Obsolete]
csharptest90922db2011-06-03 11:57:47 -0500245 public void WriteUnknownGroup(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500246 {
247 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
248 value.WriteTo(this);
249 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
250 }
251
csharptest90922db2011-06-03 11:57:47 -0500252 public void WriteMessage(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500253 {
254 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
255 WriteRawVarint32((uint) value.SerializedSize);
256 value.WriteTo(this);
257 }
258
csharptest90922db2011-06-03 11:57:47 -0500259 public void WriteBytes(int fieldNumber, string fieldName, ByteString value)
csharptest71f662c2011-05-20 15:15:34 -0500260 {
csharptest71f662c2011-05-20 15:15:34 -0500261 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
csharptest45a93fa2011-06-02 10:52:37 -0500262 WriteRawVarint32((uint)value.Length);
263 value.WriteTo(this);
csharptest71f662c2011-05-20 15:15:34 -0500264 }
265
266 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500267 public void WriteUInt32(int fieldNumber, string fieldName, uint value)
csharptest71f662c2011-05-20 15:15:34 -0500268 {
269 WriteTag(fieldNumber, WireFormat.WireType.Varint);
270 WriteRawVarint32(value);
271 }
272
csharptest90922db2011-06-03 11:57:47 -0500273 public void WriteEnum(int fieldNumber, string fieldName, int value, string textValue)
csharptest71f662c2011-05-20 15:15:34 -0500274 {
275 WriteTag(fieldNumber, WireFormat.WireType.Varint);
276 WriteRawVarint32((uint) value);
277 }
278
csharptest90922db2011-06-03 11:57:47 -0500279 public void WriteSFixed32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500280 {
281 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
282 WriteRawLittleEndian32((uint) value);
283 }
284
csharptest90922db2011-06-03 11:57:47 -0500285 public void WriteSFixed64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500286 {
287 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
288 WriteRawLittleEndian64((ulong) value);
289 }
290
csharptest90922db2011-06-03 11:57:47 -0500291 public void WriteSInt32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500292 {
293 WriteTag(fieldNumber, WireFormat.WireType.Varint);
294 WriteRawVarint32(EncodeZigZag32(value));
295 }
296
csharptest90922db2011-06-03 11:57:47 -0500297 public void WriteSInt64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500298 {
299 WriteTag(fieldNumber, WireFormat.WireType.Varint);
300 WriteRawVarint64(EncodeZigZag64(value));
301 }
302
csharptest90922db2011-06-03 11:57:47 -0500303 public void WriteMessageSetExtension(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500304 {
305 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
csharptest90922db2011-06-03 11:57:47 -0500306 WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
307 WriteMessage(WireFormat.MessageSetField.Message, "message", value);
csharptest71f662c2011-05-20 15:15:34 -0500308 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
309 }
310
311 public void WriteRawMessageSetExtension(int fieldNumber, ByteString value)
312 {
313 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
csharptest90922db2011-06-03 11:57:47 -0500314 WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
315 WriteBytes(WireFormat.MessageSetField.Message, "message", value);
csharptest71f662c2011-05-20 15:15:34 -0500316 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
317 }
318
csharptest90922db2011-06-03 11:57:47 -0500319 public void WriteMessageArray(int fieldNumber, string fieldName, System.Collections.IEnumerable list)
320 {
321 foreach (IMessageLite msg in list)
322 WriteMessage(fieldNumber, fieldName, msg);
323 }
324
325 public void WriteGroupArray(int fieldNumber, string fieldName, System.Collections.IEnumerable list)
326 {
327 foreach (IMessageLite msg in list)
328 WriteGroup(fieldNumber, fieldName, msg);
329 }
330
331 public void WriteArray(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.IEnumerable list)
332 {
333 foreach (object element in list)
334 WriteField(fieldType, fieldNumber, fieldName, element);
335 }
336
337 public void WritePackedArray(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.IEnumerable list)
338 {
339 int calculatedSize = 0;
340 foreach (object element in list)
341 calculatedSize += CodedOutputStream.ComputeFieldSizeNoTag(fieldType, element);
342 WritePackedArray(fieldType, fieldNumber, fieldName, calculatedSize, list);
343 }
344
345 public void WritePackedArray(FieldType fieldType, int fieldNumber, string fieldName, int calculatedSize, System.Collections.IEnumerable list)
346 {
347 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
348 WriteRawVarint32((uint)calculatedSize);
349
350 foreach (object element in list)
351 WriteFieldNoTag(fieldType, element);
352 }
353
354 public void WriteField(FieldType fieldType, int fieldNumber, string fieldName, object value)
csharptest71f662c2011-05-20 15:15:34 -0500355 {
356 switch (fieldType)
357 {
358 case FieldType.Double:
csharptest90922db2011-06-03 11:57:47 -0500359 WriteDouble(fieldNumber, fieldName, (double) value);
csharptest71f662c2011-05-20 15:15:34 -0500360 break;
361 case FieldType.Float:
csharptest90922db2011-06-03 11:57:47 -0500362 WriteFloat(fieldNumber, fieldName, (float) value);
csharptest71f662c2011-05-20 15:15:34 -0500363 break;
364 case FieldType.Int64:
csharptest90922db2011-06-03 11:57:47 -0500365 WriteInt64(fieldNumber, fieldName, (long) value);
csharptest71f662c2011-05-20 15:15:34 -0500366 break;
367 case FieldType.UInt64:
csharptest90922db2011-06-03 11:57:47 -0500368 WriteUInt64(fieldNumber, fieldName, (ulong) value);
csharptest71f662c2011-05-20 15:15:34 -0500369 break;
370 case FieldType.Int32:
csharptest90922db2011-06-03 11:57:47 -0500371 WriteInt32(fieldNumber, fieldName, (int) value);
csharptest71f662c2011-05-20 15:15:34 -0500372 break;
373 case FieldType.Fixed64:
csharptest90922db2011-06-03 11:57:47 -0500374 WriteFixed64(fieldNumber, fieldName, (ulong) value);
csharptest71f662c2011-05-20 15:15:34 -0500375 break;
376 case FieldType.Fixed32:
csharptest90922db2011-06-03 11:57:47 -0500377 WriteFixed32(fieldNumber, fieldName, (uint) value);
csharptest71f662c2011-05-20 15:15:34 -0500378 break;
379 case FieldType.Bool:
csharptest90922db2011-06-03 11:57:47 -0500380 WriteBool(fieldNumber, fieldName, (bool) value);
csharptest71f662c2011-05-20 15:15:34 -0500381 break;
382 case FieldType.String:
csharptest90922db2011-06-03 11:57:47 -0500383 WriteString(fieldNumber, fieldName, (string) value);
csharptest71f662c2011-05-20 15:15:34 -0500384 break;
385 case FieldType.Group:
csharptest90922db2011-06-03 11:57:47 -0500386 WriteGroup(fieldNumber, fieldName, (IMessageLite) value);
csharptest71f662c2011-05-20 15:15:34 -0500387 break;
388 case FieldType.Message:
csharptest90922db2011-06-03 11:57:47 -0500389 WriteMessage(fieldNumber, fieldName, (IMessageLite) value);
csharptest71f662c2011-05-20 15:15:34 -0500390 break;
391 case FieldType.Bytes:
csharptest90922db2011-06-03 11:57:47 -0500392 WriteBytes(fieldNumber, fieldName, (ByteString) value);
csharptest71f662c2011-05-20 15:15:34 -0500393 break;
394 case FieldType.UInt32:
csharptest90922db2011-06-03 11:57:47 -0500395 WriteUInt32(fieldNumber, fieldName, (uint) value);
csharptest71f662c2011-05-20 15:15:34 -0500396 break;
397 case FieldType.SFixed32:
csharptest90922db2011-06-03 11:57:47 -0500398 WriteSFixed32(fieldNumber, fieldName, (int) value);
csharptest71f662c2011-05-20 15:15:34 -0500399 break;
400 case FieldType.SFixed64:
csharptest90922db2011-06-03 11:57:47 -0500401 WriteSFixed64(fieldNumber, fieldName, (long) value);
csharptest71f662c2011-05-20 15:15:34 -0500402 break;
403 case FieldType.SInt32:
csharptest90922db2011-06-03 11:57:47 -0500404 WriteSInt32(fieldNumber, fieldName, (int) value);
csharptest71f662c2011-05-20 15:15:34 -0500405 break;
406 case FieldType.SInt64:
csharptest90922db2011-06-03 11:57:47 -0500407 WriteSInt64(fieldNumber, fieldName, (long) value);
csharptest71f662c2011-05-20 15:15:34 -0500408 break;
409 case FieldType.Enum:
csharptest90922db2011-06-03 11:57:47 -0500410 if(value is System.Enum)
411 WriteEnum(fieldNumber, fieldName, ((IConvertible)value).ToInt32(CultureInfo.InvariantCulture), value.ToString());
412 else
413 WriteEnum(fieldNumber, fieldName, ((IEnumLite) value).Number, ((IEnumLite) value).Name);
csharptest71f662c2011-05-20 15:15:34 -0500414 break;
415 }
416 }
417
418 public void WriteFieldNoTag(FieldType fieldType, object value)
419 {
420 switch (fieldType)
421 {
422 case FieldType.Double:
423 WriteDoubleNoTag((double) value);
424 break;
425 case FieldType.Float:
426 WriteFloatNoTag((float) value);
427 break;
428 case FieldType.Int64:
429 WriteInt64NoTag((long) value);
430 break;
431 case FieldType.UInt64:
432 WriteUInt64NoTag((ulong) value);
433 break;
434 case FieldType.Int32:
435 WriteInt32NoTag((int) value);
436 break;
437 case FieldType.Fixed64:
438 WriteFixed64NoTag((ulong) value);
439 break;
440 case FieldType.Fixed32:
441 WriteFixed32NoTag((uint) value);
442 break;
443 case FieldType.Bool:
444 WriteBoolNoTag((bool) value);
445 break;
446 case FieldType.String:
447 WriteStringNoTag((string) value);
448 break;
449 case FieldType.Group:
450 WriteGroupNoTag((IMessageLite) value);
451 break;
452 case FieldType.Message:
453 WriteMessageNoTag((IMessageLite) value);
454 break;
455 case FieldType.Bytes:
456 WriteBytesNoTag((ByteString) value);
457 break;
458 case FieldType.UInt32:
459 WriteUInt32NoTag((uint) value);
460 break;
461 case FieldType.SFixed32:
462 WriteSFixed32NoTag((int) value);
463 break;
464 case FieldType.SFixed64:
465 WriteSFixed64NoTag((long) value);
466 break;
467 case FieldType.SInt32:
468 WriteSInt32NoTag((int) value);
469 break;
470 case FieldType.SInt64:
471 WriteSInt64NoTag((long) value);
472 break;
473 case FieldType.Enum:
csharptest90922db2011-06-03 11:57:47 -0500474 if (value is System.Enum)
475 WriteEnumNoTag(((IConvertible)value).ToInt32(CultureInfo.InvariantCulture));
476 else
477 WriteEnumNoTag(((IEnumLite) value).Number);
csharptest71f662c2011-05-20 15:15:34 -0500478 break;
479 }
480 }
481
482 #endregion
483
484 #region Writing of values without tags
485
486 /// <summary>
487 /// Writes a double field value, including tag, to the stream.
488 /// </summary>
489 public void WriteDoubleNoTag(double value)
490 {
csharptest71f662c2011-05-20 15:15:34 -0500491#if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
csharptest8a2d0f42011-06-02 17:02:41 -0500492 byte[] rawBytes = BitConverter.GetBytes(value);
493 if (!BitConverter.IsLittleEndian)
494 Array.Reverse(rawBytes);
495 WriteRawBytes(rawBytes, 0, 8);
csharptest71f662c2011-05-20 15:15:34 -0500496#else
csharptest8a2d0f42011-06-02 17:02:41 -0500497 WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
csharptest71f662c2011-05-20 15:15:34 -0500498#endif
499 }
500
501 /// <summary>
502 /// Writes a float field value, without a tag, to the stream.
503 /// </summary>
504 public void WriteFloatNoTag(float value)
505 {
csharptest71f662c2011-05-20 15:15:34 -0500506 byte[] rawBytes = BitConverter.GetBytes(value);
csharptest8a2d0f42011-06-02 17:02:41 -0500507 if (!BitConverter.IsLittleEndian)
508 Array.Reverse(rawBytes);
509 WriteRawBytes(rawBytes, 0, 4);
csharptest71f662c2011-05-20 15:15:34 -0500510 }
511
512 /// <summary>
513 /// Writes a uint64 field value, without a tag, to the stream.
514 /// </summary>
515 [CLSCompliant(false)]
516 public void WriteUInt64NoTag(ulong value)
517 {
518 WriteRawVarint64(value);
519 }
520
521 /// <summary>
522 /// Writes an int64 field value, without a tag, to the stream.
523 /// </summary>
524 public void WriteInt64NoTag(long value)
525 {
526 WriteRawVarint64((ulong) value);
527 }
528
529 /// <summary>
530 /// Writes an int32 field value, without a tag, to the stream.
531 /// </summary>
532 public void WriteInt32NoTag(int value)
533 {
534 if (value >= 0)
535 {
536 WriteRawVarint32((uint) value);
537 }
538 else
539 {
540 // Must sign-extend.
541 WriteRawVarint64((ulong) value);
542 }
543 }
544
545 /// <summary>
546 /// Writes a fixed64 field value, without a tag, to the stream.
547 /// </summary>
548 [CLSCompliant(false)]
549 public void WriteFixed64NoTag(ulong value)
550 {
551 WriteRawLittleEndian64(value);
552 }
553
554 /// <summary>
555 /// Writes a fixed32 field value, without a tag, to the stream.
556 /// </summary>
557 [CLSCompliant(false)]
558 public void WriteFixed32NoTag(uint value)
559 {
560 WriteRawLittleEndian32(value);
561 }
562
563 /// <summary>
564 /// Writes a bool field value, without a tag, to the stream.
565 /// </summary>
566 public void WriteBoolNoTag(bool value)
567 {
568 WriteRawByte(value ? (byte) 1 : (byte) 0);
569 }
570
571 /// <summary>
572 /// Writes a string field value, without a tag, to the stream.
573 /// </summary>
574 public void WriteStringNoTag(string value)
575 {
576 // Optimise the case where we have enough space to write
577 // the string directly to the buffer, which should be common.
578 int length = Encoding.UTF8.GetByteCount(value);
579 WriteRawVarint32((uint) length);
580 if (limit - position >= length)
581 {
582 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
583 position += length;
584 }
585 else
586 {
587 byte[] bytes = Encoding.UTF8.GetBytes(value);
588 WriteRawBytes(bytes);
589 }
590 }
591
592 /// <summary>
593 /// Writes a group field value, without a tag, to the stream.
594 /// </summary>
595 public void WriteGroupNoTag(IMessageLite value)
596 {
597 value.WriteTo(this);
598 }
599
600 public void WriteMessageNoTag(IMessageLite value)
601 {
602 WriteRawVarint32((uint) value.SerializedSize);
603 value.WriteTo(this);
604 }
605
606 public void WriteBytesNoTag(ByteString value)
607 {
csharptest45a93fa2011-06-02 10:52:37 -0500608 WriteRawVarint32((uint)value.Length);
609 value.WriteTo(this);
csharptest71f662c2011-05-20 15:15:34 -0500610 }
611
612 [CLSCompliant(false)]
613 public void WriteUInt32NoTag(uint value)
614 {
615 WriteRawVarint32(value);
616 }
617
618 public void WriteEnumNoTag(int value)
619 {
620 WriteRawVarint32((uint) value);
621 }
622
623 public void WriteSFixed32NoTag(int value)
624 {
625 WriteRawLittleEndian32((uint) value);
626 }
627
628 public void WriteSFixed64NoTag(long value)
629 {
630 WriteRawLittleEndian64((ulong) value);
631 }
632
633 public void WriteSInt32NoTag(int value)
634 {
635 WriteRawVarint32(EncodeZigZag32(value));
636 }
637
638 public void WriteSInt64NoTag(long value)
639 {
640 WriteRawVarint64(EncodeZigZag64(value));
641 }
642
643 #endregion
644
645 #region Underlying writing primitives
646
647 /// <summary>
648 /// Encodes and writes a tag.
649 /// </summary>
650 [CLSCompliant(false)]
651 public void WriteTag(int fieldNumber, WireFormat.WireType type)
652 {
653 WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
654 }
655
656 private void SlowWriteRawVarint32(uint value)
657 {
658 while (true)
659 {
660 if ((value & ~0x7F) == 0)
661 {
662 WriteRawByte(value);
663 return;
664 }
665 else
666 {
667 WriteRawByte((value & 0x7F) | 0x80);
668 value >>= 7;
669 }
670 }
671 }
672
673 /// <summary>
674 /// Writes a 32 bit value as a varint. The fast route is taken when
675 /// there's enough buffer space left to whizz through without checking
676 /// for each byte; otherwise, we resort to calling WriteRawByte each time.
677 /// </summary>
678 [CLSCompliant(false)]
679 public void WriteRawVarint32(uint value)
680 {
681 if (position + 5 > limit)
682 {
683 SlowWriteRawVarint32(value);
684 return;
685 }
686
687 while (true)
688 {
689 if ((value & ~0x7F) == 0)
690 {
691 buffer[position++] = (byte) value;
692 return;
693 }
694 else
695 {
696 buffer[position++] = (byte) ((value & 0x7F) | 0x80);
697 value >>= 7;
698 }
699 }
700 }
701
702 [CLSCompliant(false)]
703 public void WriteRawVarint64(ulong value)
704 {
705 while (true)
706 {
707 if ((value & ~0x7FUL) == 0)
708 {
709 WriteRawByte((uint) value);
710 return;
711 }
712 else
713 {
714 WriteRawByte(((uint) value & 0x7F) | 0x80);
715 value >>= 7;
716 }
717 }
718 }
719
720 [CLSCompliant(false)]
721 public void WriteRawLittleEndian32(uint value)
722 {
723 WriteRawByte((byte) value);
724 WriteRawByte((byte) (value >> 8));
725 WriteRawByte((byte) (value >> 16));
726 WriteRawByte((byte) (value >> 24));
727 }
728
729 [CLSCompliant(false)]
730 public void WriteRawLittleEndian64(ulong value)
731 {
732 WriteRawByte((byte) value);
733 WriteRawByte((byte) (value >> 8));
734 WriteRawByte((byte) (value >> 16));
735 WriteRawByte((byte) (value >> 24));
736 WriteRawByte((byte) (value >> 32));
737 WriteRawByte((byte) (value >> 40));
738 WriteRawByte((byte) (value >> 48));
739 WriteRawByte((byte) (value >> 56));
740 }
741
742 public void WriteRawByte(byte value)
743 {
744 if (position == limit)
745 {
746 RefreshBuffer();
747 }
748
749 buffer[position++] = value;
750 }
751
752 [CLSCompliant(false)]
753 public void WriteRawByte(uint value)
754 {
755 WriteRawByte((byte) value);
756 }
757
758 /// <summary>
759 /// Writes out an array of bytes.
760 /// </summary>
761 public void WriteRawBytes(byte[] value)
762 {
763 WriteRawBytes(value, 0, value.Length);
764 }
765
766 /// <summary>
767 /// Writes out part of an array of bytes.
768 /// </summary>
769 public void WriteRawBytes(byte[] value, int offset, int length)
770 {
771 if (limit - position >= length)
772 {
773 Array.Copy(value, offset, buffer, position, length);
774 // We have room in the current buffer.
775 position += length;
776 }
777 else
778 {
779 // Write extends past current buffer. Fill the rest of this buffer and
780 // flush.
781 int bytesWritten = limit - position;
782 Array.Copy(value, offset, buffer, position, bytesWritten);
783 offset += bytesWritten;
784 length -= bytesWritten;
785 position = limit;
786 RefreshBuffer();
787
788 // Now deal with the rest.
789 // Since we have an output stream, this is our buffer
790 // and buffer offset == 0
791 if (length <= limit)
792 {
793 // Fits in new buffer.
794 Array.Copy(value, offset, buffer, 0, length);
795 position = length;
796 }
797 else
798 {
799 // Write is very big. Let's do it all at once.
800 output.Write(value, offset, length);
801 }
802 }
803 }
804
805 #endregion
806
807 #region Size computations
808
809 private const int LittleEndian64Size = 8;
810 private const int LittleEndian32Size = 4;
811
812 /// <summary>
813 /// Compute the number of bytes that would be needed to encode a
814 /// double field, including the tag.
815 /// </summary>
816 public static int ComputeDoubleSize(int fieldNumber, double value)
817 {
818 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
819 }
820
821 /// <summary>
822 /// Compute the number of bytes that would be needed to encode a
823 /// float field, including the tag.
824 /// </summary>
825 public static int ComputeFloatSize(int fieldNumber, float value)
826 {
827 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
828 }
829
830 /// <summary>
831 /// Compute the number of bytes that would be needed to encode a
832 /// uint64 field, including the tag.
833 /// </summary>
834 [CLSCompliant(false)]
835 public static int ComputeUInt64Size(int fieldNumber, ulong value)
836 {
837 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(value);
838 }
839
840 /// <summary>
841 /// Compute the number of bytes that would be needed to encode an
842 /// int64 field, including the tag.
843 /// </summary>
844 public static int ComputeInt64Size(int fieldNumber, long value)
845 {
846 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size((ulong) value);
847 }
848
849 /// <summary>
850 /// Compute the number of bytes that would be needed to encode an
851 /// int32 field, including the tag.
852 /// </summary>
853 public static int ComputeInt32Size(int fieldNumber, int value)
854 {
855 if (value >= 0)
856 {
857 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint) value);
858 }
859 else
860 {
861 // Must sign-extend.
862 return ComputeTagSize(fieldNumber) + 10;
863 }
864 }
865
866 /// <summary>
867 /// Compute the number of bytes that would be needed to encode a
868 /// fixed64 field, including the tag.
869 /// </summary>
870 [CLSCompliant(false)]
871 public static int ComputeFixed64Size(int fieldNumber, ulong value)
872 {
873 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
874 }
875
876 /// <summary>
877 /// Compute the number of bytes that would be needed to encode a
878 /// fixed32 field, including the tag.
879 /// </summary>
880 [CLSCompliant(false)]
881 public static int ComputeFixed32Size(int fieldNumber, uint value)
882 {
883 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
884 }
885
886 /// <summary>
887 /// Compute the number of bytes that would be needed to encode a
888 /// bool field, including the tag.
889 /// </summary>
890 public static int ComputeBoolSize(int fieldNumber, bool value)
891 {
892 return ComputeTagSize(fieldNumber) + 1;
893 }
894
895 /// <summary>
896 /// Compute the number of bytes that would be needed to encode a
897 /// string field, including the tag.
898 /// </summary>
899 public static int ComputeStringSize(int fieldNumber, String value)
900 {
901 int byteArraySize = Encoding.UTF8.GetByteCount(value);
902 return ComputeTagSize(fieldNumber) +
903 ComputeRawVarint32Size((uint) byteArraySize) +
904 byteArraySize;
905 }
906
907 /// <summary>
908 /// Compute the number of bytes that would be needed to encode a
909 /// group field, including the tag.
910 /// </summary>
911 public static int ComputeGroupSize(int fieldNumber, IMessageLite value)
912 {
913 return ComputeTagSize(fieldNumber)*2 + value.SerializedSize;
914 }
915
916 /// <summary>
917 /// Compute the number of bytes that would be needed to encode a
918 /// group field represented by an UnknownFieldSet, including the tag.
919 /// </summary>
920 [Obsolete]
921 public static int ComputeUnknownGroupSize(int fieldNumber,
922 IMessageLite value)
923 {
924 return ComputeTagSize(fieldNumber)*2 + value.SerializedSize;
925 }
926
927 /// <summary>
928 /// Compute the number of bytes that would be needed to encode an
929 /// embedded message field, including the tag.
930 /// </summary>
931 public static int ComputeMessageSize(int fieldNumber, IMessageLite value)
932 {
933 int size = value.SerializedSize;
934 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint) size) + size;
935 }
936
937 /// <summary>
938 /// Compute the number of bytes that would be needed to encode a
939 /// bytes field, including the tag.
940 /// </summary>
941 public static int ComputeBytesSize(int fieldNumber, ByteString value)
942 {
943 return ComputeTagSize(fieldNumber) +
944 ComputeRawVarint32Size((uint) value.Length) +
945 value.Length;
946 }
947
948 /// <summary>
949 /// Compute the number of bytes that would be needed to encode a
950 /// uint32 field, including the tag.
951 /// </summary>
952 [CLSCompliant(false)]
953 public static int ComputeUInt32Size(int fieldNumber, uint value)
954 {
955 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(value);
956 }
957
958 /// <summary>
959 /// Compute the number of bytes that would be needed to encode a
960 /// enum field, including the tag. The caller is responsible for
961 /// converting the enum value to its numeric value.
962 /// </summary>
963 public static int ComputeEnumSize(int fieldNumber, int value)
964 {
965 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint) value);
966 }
967
968 /// <summary>
969 /// Compute the number of bytes that would be needed to encode an
970 /// sfixed32 field, including the tag.
971 /// </summary>
972 public static int ComputeSFixed32Size(int fieldNumber, int value)
973 {
974 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
975 }
976
977 /// <summary>
978 /// Compute the number of bytes that would be needed to encode an
979 /// sfixed64 field, including the tag.
980 /// </summary>
981 public static int ComputeSFixed64Size(int fieldNumber, long value)
982 {
983 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
984 }
985
986 /// <summary>
987 /// Compute the number of bytes that would be needed to encode an
988 /// sint32 field, including the tag.
989 /// </summary>
990 public static int ComputeSInt32Size(int fieldNumber, int value)
991 {
992 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(EncodeZigZag32(value));
993 }
994
995 /// <summary>
996 /// Compute the number of bytes that would be needed to encode an
997 /// sint64 field, including the tag.
998 /// </summary>
999 public static int ComputeSInt64Size(int fieldNumber, long value)
1000 {
1001 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(EncodeZigZag64(value));
1002 }
1003
1004 /// <summary>
1005 /// Compute the number of bytes that would be needed to encode a
1006 /// double field, including the tag.
1007 /// </summary>
1008 public static int ComputeDoubleSizeNoTag(double value)
1009 {
1010 return LittleEndian64Size;
1011 }
1012
1013 /// <summary>
1014 /// Compute the number of bytes that would be needed to encode a
1015 /// float field, including the tag.
1016 /// </summary>
1017 public static int ComputeFloatSizeNoTag(float value)
1018 {
1019 return LittleEndian32Size;
1020 }
1021
1022 /// <summary>
1023 /// Compute the number of bytes that would be needed to encode a
1024 /// uint64 field, including the tag.
1025 /// </summary>
1026 [CLSCompliant(false)]
1027 public static int ComputeUInt64SizeNoTag(ulong value)
1028 {
1029 return ComputeRawVarint64Size(value);
1030 }
1031
1032 /// <summary>
1033 /// Compute the number of bytes that would be needed to encode an
1034 /// int64 field, including the tag.
1035 /// </summary>
1036 public static int ComputeInt64SizeNoTag(long value)
1037 {
1038 return ComputeRawVarint64Size((ulong) value);
1039 }
1040
1041 /// <summary>
1042 /// Compute the number of bytes that would be needed to encode an
1043 /// int32 field, including the tag.
1044 /// </summary>
1045 public static int ComputeInt32SizeNoTag(int value)
1046 {
1047 if (value >= 0)
1048 {
1049 return ComputeRawVarint32Size((uint) value);
1050 }
1051 else
1052 {
1053 // Must sign-extend.
1054 return 10;
1055 }
1056 }
1057
1058 /// <summary>
1059 /// Compute the number of bytes that would be needed to encode a
1060 /// fixed64 field, including the tag.
1061 /// </summary>
1062 [CLSCompliant(false)]
1063 public static int ComputeFixed64SizeNoTag(ulong value)
1064 {
1065 return LittleEndian64Size;
1066 }
1067
1068 /// <summary>
1069 /// Compute the number of bytes that would be needed to encode a
1070 /// fixed32 field, including the tag.
1071 /// </summary>
1072 [CLSCompliant(false)]
1073 public static int ComputeFixed32SizeNoTag(uint value)
1074 {
1075 return LittleEndian32Size;
1076 }
1077
1078 /// <summary>
1079 /// Compute the number of bytes that would be needed to encode a
1080 /// bool field, including the tag.
1081 /// </summary>
1082 public static int ComputeBoolSizeNoTag(bool value)
1083 {
1084 return 1;
1085 }
1086
1087 /// <summary>
1088 /// Compute the number of bytes that would be needed to encode a
1089 /// string field, including the tag.
1090 /// </summary>
1091 public static int ComputeStringSizeNoTag(String value)
1092 {
1093 int byteArraySize = Encoding.UTF8.GetByteCount(value);
1094 return ComputeRawVarint32Size((uint) byteArraySize) +
1095 byteArraySize;
1096 }
1097
1098 /// <summary>
1099 /// Compute the number of bytes that would be needed to encode a
1100 /// group field, including the tag.
1101 /// </summary>
1102 public static int ComputeGroupSizeNoTag(IMessageLite value)
1103 {
1104 return value.SerializedSize;
1105 }
1106
1107 /// <summary>
1108 /// Compute the number of bytes that would be needed to encode a
1109 /// group field represented by an UnknownFieldSet, including the tag.
1110 /// </summary>
1111 [Obsolete]
1112 public static int ComputeUnknownGroupSizeNoTag(IMessageLite value)
1113 {
1114 return value.SerializedSize;
1115 }
1116
1117 /// <summary>
1118 /// Compute the number of bytes that would be needed to encode an
1119 /// embedded message field, including the tag.
1120 /// </summary>
1121 public static int ComputeMessageSizeNoTag(IMessageLite value)
1122 {
1123 int size = value.SerializedSize;
1124 return ComputeRawVarint32Size((uint) size) + size;
1125 }
1126
1127 /// <summary>
1128 /// Compute the number of bytes that would be needed to encode a
1129 /// bytes field, including the tag.
1130 /// </summary>
1131 public static int ComputeBytesSizeNoTag(ByteString value)
1132 {
1133 return ComputeRawVarint32Size((uint) value.Length) +
1134 value.Length;
1135 }
1136
1137 /// <summary>
1138 /// Compute the number of bytes that would be needed to encode a
1139 /// uint32 field, including the tag.
1140 /// </summary>
1141 [CLSCompliant(false)]
1142 public static int ComputeUInt32SizeNoTag(uint value)
1143 {
1144 return ComputeRawVarint32Size(value);
1145 }
1146
1147 /// <summary>
1148 /// Compute the number of bytes that would be needed to encode a
1149 /// enum field, including the tag. The caller is responsible for
1150 /// converting the enum value to its numeric value.
1151 /// </summary>
1152 public static int ComputeEnumSizeNoTag(int value)
1153 {
1154 return ComputeRawVarint32Size((uint) value);
1155 }
1156
1157 /// <summary>
1158 /// Compute the number of bytes that would be needed to encode an
1159 /// sfixed32 field, including the tag.
1160 /// </summary>
1161 public static int ComputeSFixed32SizeNoTag(int value)
1162 {
1163 return LittleEndian32Size;
1164 }
1165
1166 /// <summary>
1167 /// Compute the number of bytes that would be needed to encode an
1168 /// sfixed64 field, including the tag.
1169 /// </summary>
1170 public static int ComputeSFixed64SizeNoTag(long value)
1171 {
1172 return LittleEndian64Size;
1173 }
1174
1175 /// <summary>
1176 /// Compute the number of bytes that would be needed to encode an
1177 /// sint32 field, including the tag.
1178 /// </summary>
1179 public static int ComputeSInt32SizeNoTag(int value)
1180 {
1181 return ComputeRawVarint32Size(EncodeZigZag32(value));
1182 }
1183
1184 /// <summary>
1185 /// Compute the number of bytes that would be needed to encode an
1186 /// sint64 field, including the tag.
1187 /// </summary>
1188 public static int ComputeSInt64SizeNoTag(long value)
1189 {
1190 return ComputeRawVarint64Size(EncodeZigZag64(value));
1191 }
1192
1193 /*
1194 * Compute the number of bytes that would be needed to encode a
1195 * MessageSet extension to the stream. For historical reasons,
1196 * the wire format differs from normal fields.
1197 */
1198
1199 /// <summary>
1200 /// Compute the number of bytes that would be needed to encode a
1201 /// MessageSet extension to the stream. For historical reasons,
1202 /// the wire format differs from normal fields.
1203 /// </summary>
1204 public static int ComputeMessageSetExtensionSize(int fieldNumber, IMessageLite value)
1205 {
1206 return ComputeTagSize(WireFormat.MessageSetField.Item)*2 +
1207 ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
1208 ComputeMessageSize(WireFormat.MessageSetField.Message, value);
1209 }
1210
1211 /// <summary>
1212 /// Compute the number of bytes that would be needed to encode an
1213 /// unparsed MessageSet extension field to the stream. For
1214 /// historical reasons, the wire format differs from normal fields.
1215 /// </summary>
1216 public static int ComputeRawMessageSetExtensionSize(int fieldNumber, ByteString value)
1217 {
1218 return ComputeTagSize(WireFormat.MessageSetField.Item)*2 +
1219 ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
1220 ComputeBytesSize(WireFormat.MessageSetField.Message, value);
1221 }
1222
1223 /// <summary>
1224 /// Compute the number of bytes that would be needed to encode a varint.
1225 /// </summary>
1226 [CLSCompliant(false)]
1227 public static int ComputeRawVarint32Size(uint value)
1228 {
1229 if ((value & (0xffffffff << 7)) == 0) return 1;
1230 if ((value & (0xffffffff << 14)) == 0) return 2;
1231 if ((value & (0xffffffff << 21)) == 0) return 3;
1232 if ((value & (0xffffffff << 28)) == 0) return 4;
1233 return 5;
1234 }
1235
1236 /// <summary>
1237 /// Compute the number of bytes that would be needed to encode a varint.
1238 /// </summary>
1239 [CLSCompliant(false)]
1240 public static int ComputeRawVarint64Size(ulong value)
1241 {
1242 if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
1243 if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
1244 if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
1245 if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
1246 if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
1247 if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
1248 if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
1249 if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
1250 if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
1251 return 10;
1252 }
1253
1254 /// <summary>
1255 /// Compute the number of bytes that would be needed to encode a
1256 /// field of arbitrary type, including the tag, to the stream.
1257 /// </summary>
1258 public static int ComputeFieldSize(FieldType fieldType, int fieldNumber, Object value)
1259 {
1260 switch (fieldType)
1261 {
1262 case FieldType.Double:
1263 return ComputeDoubleSize(fieldNumber, (double) value);
1264 case FieldType.Float:
1265 return ComputeFloatSize(fieldNumber, (float) value);
1266 case FieldType.Int64:
1267 return ComputeInt64Size(fieldNumber, (long) value);
1268 case FieldType.UInt64:
1269 return ComputeUInt64Size(fieldNumber, (ulong) value);
1270 case FieldType.Int32:
1271 return ComputeInt32Size(fieldNumber, (int) value);
1272 case FieldType.Fixed64:
1273 return ComputeFixed64Size(fieldNumber, (ulong) value);
1274 case FieldType.Fixed32:
1275 return ComputeFixed32Size(fieldNumber, (uint) value);
1276 case FieldType.Bool:
1277 return ComputeBoolSize(fieldNumber, (bool) value);
1278 case FieldType.String:
1279 return ComputeStringSize(fieldNumber, (string) value);
1280 case FieldType.Group:
1281 return ComputeGroupSize(fieldNumber, (IMessageLite) value);
1282 case FieldType.Message:
1283 return ComputeMessageSize(fieldNumber, (IMessageLite) value);
1284 case FieldType.Bytes:
1285 return ComputeBytesSize(fieldNumber, (ByteString) value);
1286 case FieldType.UInt32:
1287 return ComputeUInt32Size(fieldNumber, (uint) value);
1288 case FieldType.SFixed32:
1289 return ComputeSFixed32Size(fieldNumber, (int) value);
1290 case FieldType.SFixed64:
1291 return ComputeSFixed64Size(fieldNumber, (long) value);
1292 case FieldType.SInt32:
1293 return ComputeSInt32Size(fieldNumber, (int) value);
1294 case FieldType.SInt64:
1295 return ComputeSInt64Size(fieldNumber, (long) value);
1296 case FieldType.Enum:
csharptest90922db2011-06-03 11:57:47 -05001297 if (value is System.Enum)
1298 return ComputeEnumSize(fieldNumber, ((IConvertible)value).ToInt32(CultureInfo.InvariantCulture));
1299 else
1300 return ComputeEnumSize(fieldNumber, ((IEnumLite) value).Number);
csharptest71f662c2011-05-20 15:15:34 -05001301 default:
1302 throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
1303 }
1304 }
1305
1306 /// <summary>
1307 /// Compute the number of bytes that would be needed to encode a
1308 /// field of arbitrary type, excluding the tag, to the stream.
1309 /// </summary>
1310 public static int ComputeFieldSizeNoTag(FieldType fieldType, Object value)
1311 {
1312 switch (fieldType)
1313 {
1314 case FieldType.Double:
1315 return ComputeDoubleSizeNoTag((double) value);
1316 case FieldType.Float:
1317 return ComputeFloatSizeNoTag((float) value);
1318 case FieldType.Int64:
1319 return ComputeInt64SizeNoTag((long) value);
1320 case FieldType.UInt64:
1321 return ComputeUInt64SizeNoTag((ulong) value);
1322 case FieldType.Int32:
1323 return ComputeInt32SizeNoTag((int) value);
1324 case FieldType.Fixed64:
1325 return ComputeFixed64SizeNoTag((ulong) value);
1326 case FieldType.Fixed32:
1327 return ComputeFixed32SizeNoTag((uint) value);
1328 case FieldType.Bool:
1329 return ComputeBoolSizeNoTag((bool) value);
1330 case FieldType.String:
1331 return ComputeStringSizeNoTag((string) value);
1332 case FieldType.Group:
1333 return ComputeGroupSizeNoTag((IMessageLite) value);
1334 case FieldType.Message:
1335 return ComputeMessageSizeNoTag((IMessageLite) value);
1336 case FieldType.Bytes:
1337 return ComputeBytesSizeNoTag((ByteString) value);
1338 case FieldType.UInt32:
1339 return ComputeUInt32SizeNoTag((uint) value);
1340 case FieldType.SFixed32:
1341 return ComputeSFixed32SizeNoTag((int) value);
1342 case FieldType.SFixed64:
1343 return ComputeSFixed64SizeNoTag((long) value);
1344 case FieldType.SInt32:
1345 return ComputeSInt32SizeNoTag((int) value);
1346 case FieldType.SInt64:
1347 return ComputeSInt64SizeNoTag((long) value);
1348 case FieldType.Enum:
csharptest90922db2011-06-03 11:57:47 -05001349 if (value is System.Enum)
1350 return ComputeEnumSizeNoTag(((IConvertible)value).ToInt32(CultureInfo.InvariantCulture));
1351 else
1352 return ComputeEnumSizeNoTag(((IEnumLite) value).Number);
csharptest71f662c2011-05-20 15:15:34 -05001353 default:
1354 throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
1355 }
1356 }
1357
1358 /// <summary>
1359 /// Compute the number of bytes that would be needed to encode a tag.
1360 /// </summary>
1361 public static int ComputeTagSize(int fieldNumber)
1362 {
1363 return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));
1364 }
1365
1366 #endregion
1367
1368 /// <summary>
1369 /// Encode a 32-bit value with ZigZag encoding.
1370 /// </summary>
1371 /// <remarks>
1372 /// ZigZag encodes signed integers into values that can be efficiently
1373 /// encoded with varint. (Otherwise, negative values must be
1374 /// sign-extended to 64 bits to be varint encoded, thus always taking
1375 /// 10 bytes on the wire.)
1376 /// </remarks>
1377 [CLSCompliant(false)]
1378 public static uint EncodeZigZag32(int n)
1379 {
1380 // Note: the right-shift must be arithmetic
1381 return (uint) ((n << 1) ^ (n >> 31));
1382 }
1383
1384 /// <summary>
1385 /// Encode a 64-bit value with ZigZag encoding.
1386 /// </summary>
1387 /// <remarks>
1388 /// ZigZag encodes signed integers into values that can be efficiently
1389 /// encoded with varint. (Otherwise, negative values must be
1390 /// sign-extended to 64 bits to be varint encoded, thus always taking
1391 /// 10 bytes on the wire.)
1392 /// </remarks>
1393 [CLSCompliant(false)]
1394 public static ulong EncodeZigZag64(long n)
1395 {
1396 return (ulong) ((n << 1) ^ (n >> 63));
1397 }
1398
1399 private void RefreshBuffer()
1400 {
1401 if (output == null)
1402 {
1403 // We're writing to a single buffer.
1404 throw new OutOfSpaceException();
1405 }
1406
1407 // Since we have an output stream, this is our buffer
1408 // and buffer offset == 0
1409 output.Write(buffer, 0, position);
1410 position = 0;
1411 }
1412
1413 /// <summary>
1414 /// Indicates that a CodedOutputStream wrapping a flat byte array
1415 /// ran out of space.
1416 /// </summary>
1417 public sealed class OutOfSpaceException : IOException
1418 {
1419 internal OutOfSpaceException()
1420 : base("CodedOutputStream was writing to a flat byte array and ran out of space.")
1421 {
1422 }
1423 }
1424
1425 public void Flush()
1426 {
1427 if (output != null)
1428 {
1429 RefreshBuffer();
1430 }
1431 }
1432
1433 /// <summary>
1434 /// Verifies that SpaceLeft returns zero. It's common to create a byte array
1435 /// that is exactly big enough to hold a message, then write to it with
1436 /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
1437 /// the message was actually as big as expected, which can help bugs.
1438 /// </summary>
1439 public void CheckNoSpaceLeft()
1440 {
1441 if (SpaceLeft != 0)
1442 {
1443 throw new InvalidOperationException("Did not write as much data as expected.");
1444 }
1445 }
1446
1447 /// <summary>
1448 /// If writing to a flat array, returns the space left in the array. Otherwise,
1449 /// throws an InvalidOperationException.
1450 /// </summary>
1451 public int SpaceLeft
1452 {
1453 get
1454 {
1455 if (output == null)
1456 {
1457 return limit - position;
1458 }
1459 else
1460 {
1461 throw new InvalidOperationException(
1462 "SpaceLeft can only be called on CodedOutputStreams that are " +
1463 "writing to a flat array.");
1464 }
1465 }
1466 }
1467 }
1468}