blob: 37355412b83452f8e401e83830f83252859e0b55 [file] [log] [blame]
csharptest71f662c2011-05-20 15:15:34 -05001#region Copyright notice and license
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc. All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15// * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19// * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35#endregion
36
37using System;
csharptestc671a4b2011-06-08 11:51:24 -050038using System.Collections.Generic;
csharptest90922db2011-06-03 11:57:47 -050039using System.Globalization;
csharptest71f662c2011-05-20 15:15:34 -050040using System.IO;
csharptest2772dfe2011-06-08 15:50:58 -050041using System.Runtime.InteropServices;
csharptest71f662c2011-05-20 15:15:34 -050042using System.Text;
csharptestced18e12011-06-09 19:47:56 -050043using Google.ProtocolBuffers.Collections;
csharptest71f662c2011-05-20 15:15:34 -050044using Google.ProtocolBuffers.Descriptors;
45
46namespace Google.ProtocolBuffers
47{
48 /// <summary>
49 /// Encodes and writes protocol message fields.
50 /// </summary>
51 /// <remarks>
52 /// This class contains two kinds of methods: methods that write specific
53 /// protocol message constructs and field types (e.g. WriteTag and
54 /// WriteInt32) and methods that write low-level values (e.g.
55 /// WriteRawVarint32 and WriteRawBytes). If you are writing encoded protocol
56 /// messages, you should use the former methods, but if you are writing some
57 /// other format of your own design, use the latter. The names of the former
58 /// methods are taken from the protocol buffer type names, not .NET types.
59 /// (Hence WriteFloat instead of WriteSingle, and WriteBool instead of WriteBoolean.)
60 /// </remarks>
csharptestcc8d2aa2011-06-03 12:15:42 -050061 public sealed partial class CodedOutputStream : ICodedOutputStream
csharptest71f662c2011-05-20 15:15:34 -050062 {
63 /// <summary>
64 /// The buffer size used by CreateInstance(Stream).
65 /// </summary>
66 public static readonly int DefaultBufferSize = 4096;
67
68 private readonly byte[] buffer;
69 private readonly int limit;
70 private int position;
71 private readonly Stream output;
72
73 #region Construction
74
75 private CodedOutputStream(byte[] buffer, int offset, int length)
76 {
77 this.output = null;
78 this.buffer = buffer;
79 this.position = offset;
80 this.limit = offset + length;
81 }
82
83 private CodedOutputStream(Stream output, byte[] buffer)
84 {
85 this.output = output;
86 this.buffer = buffer;
87 this.position = 0;
88 this.limit = buffer.Length;
89 }
90
91 /// <summary>
92 /// Creates a new CodedOutputStream which write to the given stream.
93 /// </summary>
94 public static CodedOutputStream CreateInstance(Stream output)
95 {
96 return CreateInstance(output, DefaultBufferSize);
97 }
98
99 /// <summary>
100 /// Creates a new CodedOutputStream which write to the given stream and uses
101 /// the specified buffer size.
102 /// </summary>
103 public static CodedOutputStream CreateInstance(Stream output, int bufferSize)
104 {
105 return new CodedOutputStream(output, new byte[bufferSize]);
106 }
107
108 /// <summary>
109 /// Creates a new CodedOutputStream that writes directly to the given
110 /// byte array. If more bytes are written than fit in the array,
111 /// OutOfSpaceException will be thrown.
112 /// </summary>
113 public static CodedOutputStream CreateInstance(byte[] flatArray)
114 {
115 return CreateInstance(flatArray, 0, flatArray.Length);
116 }
117
118 /// <summary>
119 /// Creates a new CodedOutputStream that writes directly to the given
120 /// byte array slice. If more bytes are written than fit in the array,
121 /// OutOfSpaceException will be thrown.
122 /// </summary>
123 public static CodedOutputStream CreateInstance(byte[] flatArray, int offset, int length)
124 {
125 return new CodedOutputStream(flatArray, offset, length);
126 }
127
128 #endregion
129
130 #region Writing of tags etc
131
132 /// <summary>
133 /// Writes a double field value, including tag, to the stream.
134 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500135 public void WriteDouble(int fieldNumber, string fieldName, double value)
csharptest71f662c2011-05-20 15:15:34 -0500136 {
137 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
138 WriteDoubleNoTag(value);
139 }
140
141 /// <summary>
142 /// Writes a float field value, including tag, to the stream.
143 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500144 public void WriteFloat(int fieldNumber, string fieldName, float value)
csharptest71f662c2011-05-20 15:15:34 -0500145 {
146 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
147 WriteFloatNoTag(value);
148 }
149
150 /// <summary>
151 /// Writes a uint64 field value, including tag, to the stream.
152 /// </summary>
153 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500154 public void WriteUInt64(int fieldNumber, string fieldName, ulong value)
csharptest71f662c2011-05-20 15:15:34 -0500155 {
156 WriteTag(fieldNumber, WireFormat.WireType.Varint);
157 WriteRawVarint64(value);
158 }
159
160 /// <summary>
161 /// Writes an int64 field value, including tag, to the stream.
162 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500163 public void WriteInt64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500164 {
165 WriteTag(fieldNumber, WireFormat.WireType.Varint);
166 WriteRawVarint64((ulong) value);
167 }
168
169 /// <summary>
170 /// Writes an int32 field value, including tag, to the stream.
171 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500172 public void WriteInt32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500173 {
174 WriteTag(fieldNumber, WireFormat.WireType.Varint);
175 if (value >= 0)
176 {
177 WriteRawVarint32((uint) value);
178 }
179 else
180 {
181 // Must sign-extend.
182 WriteRawVarint64((ulong) value);
183 }
184 }
185
186 /// <summary>
187 /// Writes a fixed64 field value, including tag, to the stream.
188 /// </summary>
189 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500190 public void WriteFixed64(int fieldNumber, string fieldName, ulong value)
csharptest71f662c2011-05-20 15:15:34 -0500191 {
192 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
193 WriteRawLittleEndian64(value);
194 }
195
196 /// <summary>
197 /// Writes a fixed32 field value, including tag, to the stream.
198 /// </summary>
199 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500200 public void WriteFixed32(int fieldNumber, string fieldName, uint value)
csharptest71f662c2011-05-20 15:15:34 -0500201 {
202 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
203 WriteRawLittleEndian32(value);
204 }
205
206 /// <summary>
207 /// Writes a bool field value, including tag, to the stream.
208 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500209 public void WriteBool(int fieldNumber, string fieldName, bool value)
csharptest71f662c2011-05-20 15:15:34 -0500210 {
211 WriteTag(fieldNumber, WireFormat.WireType.Varint);
212 WriteRawByte(value ? (byte) 1 : (byte) 0);
213 }
214
215 /// <summary>
216 /// Writes a string field value, including tag, to the stream.
217 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500218 public void WriteString(int fieldNumber, string fieldName, string value)
csharptest71f662c2011-05-20 15:15:34 -0500219 {
220 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
221 // Optimise the case where we have enough space to write
222 // the string directly to the buffer, which should be common.
223 int length = Encoding.UTF8.GetByteCount(value);
224 WriteRawVarint32((uint) length);
225 if (limit - position >= length)
226 {
227 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
228 position += length;
229 }
230 else
231 {
232 byte[] bytes = Encoding.UTF8.GetBytes(value);
233 WriteRawBytes(bytes);
234 }
235 }
236
237 /// <summary>
238 /// Writes a group field value, including tag, to the stream.
239 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500240 public void WriteGroup(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500241 {
242 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
243 value.WriteTo(this);
244 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
245 }
246
247 [Obsolete]
csharptest90922db2011-06-03 11:57:47 -0500248 public void WriteUnknownGroup(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500249 {
250 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
251 value.WriteTo(this);
252 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
253 }
254
csharptest90922db2011-06-03 11:57:47 -0500255 public void WriteMessage(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500256 {
257 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
258 WriteRawVarint32((uint) value.SerializedSize);
259 value.WriteTo(this);
260 }
261
csharptest90922db2011-06-03 11:57:47 -0500262 public void WriteBytes(int fieldNumber, string fieldName, ByteString value)
csharptest71f662c2011-05-20 15:15:34 -0500263 {
csharptest71f662c2011-05-20 15:15:34 -0500264 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
csharptest45a93fa2011-06-02 10:52:37 -0500265 WriteRawVarint32((uint)value.Length);
266 value.WriteTo(this);
csharptest71f662c2011-05-20 15:15:34 -0500267 }
268
269 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500270 public void WriteUInt32(int fieldNumber, string fieldName, uint value)
csharptest71f662c2011-05-20 15:15:34 -0500271 {
272 WriteTag(fieldNumber, WireFormat.WireType.Varint);
273 WriteRawVarint32(value);
274 }
275
csharptestced18e12011-06-09 19:47:56 -0500276 public void WriteEnum(int fieldNumber, string fieldName, int value, object textValue)
csharptest71f662c2011-05-20 15:15:34 -0500277 {
278 WriteTag(fieldNumber, WireFormat.WireType.Varint);
279 WriteRawVarint32((uint) value);
280 }
281
csharptest90922db2011-06-03 11:57:47 -0500282 public void WriteSFixed32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500283 {
284 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
285 WriteRawLittleEndian32((uint) value);
286 }
287
csharptest90922db2011-06-03 11:57:47 -0500288 public void WriteSFixed64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500289 {
290 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
291 WriteRawLittleEndian64((ulong) value);
292 }
293
csharptest90922db2011-06-03 11:57:47 -0500294 public void WriteSInt32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500295 {
296 WriteTag(fieldNumber, WireFormat.WireType.Varint);
297 WriteRawVarint32(EncodeZigZag32(value));
298 }
299
csharptest90922db2011-06-03 11:57:47 -0500300 public void WriteSInt64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500301 {
302 WriteTag(fieldNumber, WireFormat.WireType.Varint);
303 WriteRawVarint64(EncodeZigZag64(value));
304 }
305
csharptest90922db2011-06-03 11:57:47 -0500306 public void WriteMessageSetExtension(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500307 {
308 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
csharptest90922db2011-06-03 11:57:47 -0500309 WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
310 WriteMessage(WireFormat.MessageSetField.Message, "message", value);
csharptest71f662c2011-05-20 15:15:34 -0500311 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
312 }
313
csharptestffafdaa2011-06-03 12:58:14 -0500314 public void WriteMessageSetExtension(int fieldNumber, string fieldName, ByteString value)
csharptest71f662c2011-05-20 15:15:34 -0500315 {
316 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
csharptest90922db2011-06-03 11:57:47 -0500317 WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
318 WriteBytes(WireFormat.MessageSetField.Message, "message", value);
csharptest71f662c2011-05-20 15:15:34 -0500319 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
320 }
csharptestc671a4b2011-06-08 11:51:24 -0500321
csharptest90922db2011-06-03 11:57:47 -0500322 public void WriteArray(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.IEnumerable list)
323 {
324 foreach (object element in list)
325 WriteField(fieldType, fieldNumber, fieldName, element);
326 }
327
csharptestc671a4b2011-06-08 11:51:24 -0500328 public void WriteArray<T>(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<T> list)
329 {
330 switch (fieldType)
331 {
332 case FieldType.String:
333 foreach (string value in ((IEnumerable<string>)list))
334 WriteString(fieldNumber, fieldName, value);
335 break;
336 case FieldType.Message:
337 foreach (T value in list)
338 WriteMessage(fieldNumber, fieldName, (IMessageLite)value);
339 break;
340 case FieldType.Group:
341 foreach (T value in list)
342 WriteGroup(fieldNumber, fieldName, (IMessageLite)value);
343 break;
344 case FieldType.Bytes:
345 foreach (ByteString value in ((IEnumerable<ByteString>)list))
346 WriteBytes(fieldNumber, fieldName, value);
347 break;
348 case FieldType.Bool:
349 foreach (bool value in ((IEnumerable<bool>)list))
350 WriteBool(fieldNumber, fieldName, value);
351 break;
352 case FieldType.Enum:
csharptestced18e12011-06-09 19:47:56 -0500353 if (default(T) is System.Enum)
csharptestc671a4b2011-06-08 11:51:24 -0500354 {
csharptestced18e12011-06-09 19:47:56 -0500355 foreach (int value in ((ICastArray)list).CastArray<int>())
356 WriteEnum(fieldNumber, fieldName, value, null/*not used*/);
357 }
358 else
359 {
360 foreach (T value in list)
csharptestc671a4b2011-06-08 11:51:24 -0500361 WriteEnum(fieldNumber, fieldName, ((IEnumLite)value).Number, null/*not used*/);
362 }
363 break;
364 case FieldType.Int32:
365 foreach (int value in ((IEnumerable<int>)list))
366 WriteInt32(fieldNumber, fieldName, value);
367 break;
368 case FieldType.Int64:
369 foreach (long value in ((IEnumerable<long>)list))
370 WriteInt64(fieldNumber, fieldName, value);
371 break;
372 case FieldType.UInt32:
373 foreach (uint value in ((IEnumerable<uint>)list))
374 WriteUInt32(fieldNumber, fieldName, value);
375 break;
376 case FieldType.UInt64:
377 foreach (ulong value in ((IEnumerable<ulong>)list))
378 WriteUInt64(fieldNumber, fieldName, value);
379 break;
380 case FieldType.SInt32:
381 foreach (int value in ((IEnumerable<int>)list))
382 WriteSInt32(fieldNumber, fieldName, value);
383 break;
384 case FieldType.SInt64:
385 foreach (long value in ((IEnumerable<long>)list))
386 WriteSInt64(fieldNumber, fieldName, value);
387 break;
388 case FieldType.Fixed32:
389 foreach (uint value in ((IEnumerable<uint>)list))
390 WriteFixed32(fieldNumber, fieldName, value);
391 break;
392 case FieldType.Fixed64:
393 foreach (ulong value in ((IEnumerable<ulong>)list))
394 WriteFixed64(fieldNumber, fieldName, value);
395 break;
396 case FieldType.SFixed32:
397 foreach (int value in ((IEnumerable<int>)list))
398 WriteSFixed32(fieldNumber, fieldName, value);
399 break;
400 case FieldType.SFixed64:
401 foreach (long value in ((IEnumerable<long>)list))
402 WriteSFixed64(fieldNumber, fieldName, value);
403 break;
404 case FieldType.Double:
405 foreach (double value in ((IEnumerable<double>)list))
406 WriteDouble(fieldNumber, fieldName, value);
407 break;
408 case FieldType.Float:
409 foreach (float value in ((IEnumerable<float>)list))
410 WriteFloat(fieldNumber, fieldName, value);
411 break;
412 }
413 }
414
csharptest90922db2011-06-03 11:57:47 -0500415 public void WritePackedArray(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.IEnumerable list)
416 {
417 int calculatedSize = 0;
418 foreach (object element in list)
419 calculatedSize += CodedOutputStream.ComputeFieldSizeNoTag(fieldType, element);
csharptestc671a4b2011-06-08 11:51:24 -0500420
csharptest90922db2011-06-03 11:57:47 -0500421 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
422 WriteRawVarint32((uint)calculatedSize);
423
424 foreach (object element in list)
425 WriteFieldNoTag(fieldType, element);
426 }
427
csharptestc671a4b2011-06-08 11:51:24 -0500428 public void WritePackedArray<T>(FieldType fieldType, int fieldNumber, string fieldName, int calculatedSize, System.Collections.Generic.IEnumerable<T> list)
429 {
430 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
431 WriteRawVarint32((uint)calculatedSize);
432
433 switch (fieldType)
434 {
435 case FieldType.String:
436 foreach (string value in ((IEnumerable<string>)list))
437 WriteStringNoTag(value);
438 break;
439 case FieldType.Message:
440 foreach (T value in list)
441 WriteMessageNoTag((IMessageLite)value);
442 break;
443 case FieldType.Group:
444 foreach (T value in list)
445 WriteGroupNoTag((IMessageLite)value);
446 break;
447 case FieldType.Bytes:
448 foreach (ByteString value in ((IEnumerable<ByteString>)list))
449 WriteBytesNoTag(value);
450 break;
451 case FieldType.Bool:
452 foreach (bool value in ((IEnumerable<bool>)list))
453 WriteBoolNoTag(value);
454 break;
455 case FieldType.Enum:
csharptestced18e12011-06-09 19:47:56 -0500456 if (default(T) is System.Enum)
csharptestc671a4b2011-06-08 11:51:24 -0500457 {
csharptestced18e12011-06-09 19:47:56 -0500458 foreach (int value in ((ICastArray)list).CastArray<int>())
459 WriteEnumNoTag(value);
460 }
461 else
462 {
463 foreach (T value in list)
csharptestc671a4b2011-06-08 11:51:24 -0500464 WriteEnumNoTag(((IEnumLite)value).Number);
465 }
466 break;
467 case FieldType.Int32:
468 foreach (int value in ((IEnumerable<int>)list))
469 WriteInt32NoTag(value);
470 break;
471 case FieldType.Int64:
472 foreach (long value in ((IEnumerable<long>)list))
473 WriteInt64NoTag(value);
474 break;
475 case FieldType.UInt32:
476 foreach (uint value in ((IEnumerable<uint>)list))
477 WriteUInt32NoTag(value);
478 break;
479 case FieldType.UInt64:
480 foreach (ulong value in ((IEnumerable<ulong>)list))
481 WriteUInt64NoTag(value);
482 break;
483 case FieldType.SInt32:
484 foreach (int value in ((IEnumerable<int>)list))
485 WriteSInt32NoTag(value);
486 break;
487 case FieldType.SInt64:
488 foreach (long value in ((IEnumerable<long>)list))
489 WriteSInt64NoTag(value);
490 break;
491 case FieldType.Fixed32:
492 foreach (uint value in ((IEnumerable<uint>)list))
493 WriteFixed32NoTag(value);
494 break;
495 case FieldType.Fixed64:
496 foreach (ulong value in ((IEnumerable<ulong>)list))
497 WriteFixed64NoTag(value);
498 break;
499 case FieldType.SFixed32:
500 foreach (int value in ((IEnumerable<int>)list))
501 WriteSFixed32NoTag(value);
502 break;
503 case FieldType.SFixed64:
504 foreach (long value in ((IEnumerable<long>)list))
505 WriteSFixed64NoTag(value);
506 break;
507 case FieldType.Double:
508 foreach (double value in ((IEnumerable<double>)list))
509 WriteDoubleNoTag(value);
510 break;
511 case FieldType.Float:
512 foreach (float value in ((IEnumerable<float>)list))
513 WriteFloatNoTag(value);
514 break;
515 }
516 }
517
csharptest90922db2011-06-03 11:57:47 -0500518 public void WriteField(FieldType fieldType, int fieldNumber, string fieldName, object value)
csharptest71f662c2011-05-20 15:15:34 -0500519 {
520 switch (fieldType)
521 {
csharptestc671a4b2011-06-08 11:51:24 -0500522 case FieldType.String:
523 WriteString(fieldNumber, fieldName, (string)value);
csharptest71f662c2011-05-20 15:15:34 -0500524 break;
csharptestc671a4b2011-06-08 11:51:24 -0500525 case FieldType.Message:
526 WriteMessage(fieldNumber, fieldName, (IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500527 break;
csharptestc671a4b2011-06-08 11:51:24 -0500528 case FieldType.Group:
529 WriteGroup(fieldNumber, fieldName, (IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500530 break;
csharptestc671a4b2011-06-08 11:51:24 -0500531 case FieldType.Bytes:
532 WriteBytes(fieldNumber, fieldName, (ByteString)value);
533 break;
534 case FieldType.Bool:
535 WriteBool(fieldNumber, fieldName, (bool)value);
536 break;
537 case FieldType.Enum:
538 if (value is System.Enum)
csharptestced18e12011-06-09 19:47:56 -0500539 WriteEnum(fieldNumber, fieldName, (int)value, null/*not used*/);
csharptestc671a4b2011-06-08 11:51:24 -0500540 else
541 WriteEnum(fieldNumber, fieldName, ((IEnumLite)value).Number, null/*not used*/);
csharptest71f662c2011-05-20 15:15:34 -0500542 break;
543 case FieldType.Int32:
csharptest90922db2011-06-03 11:57:47 -0500544 WriteInt32(fieldNumber, fieldName, (int) value);
csharptest71f662c2011-05-20 15:15:34 -0500545 break;
csharptestc671a4b2011-06-08 11:51:24 -0500546 case FieldType.Int64:
547 WriteInt64(fieldNumber, fieldName, (long) value);
548 break;
549 case FieldType.UInt32:
550 WriteUInt32(fieldNumber, fieldName, (uint) value);
551 break;
552 case FieldType.UInt64:
553 WriteUInt64(fieldNumber, fieldName, (ulong) value);
554 break;
555 case FieldType.SInt32:
556 WriteSInt32(fieldNumber, fieldName, (int)value);
557 break;
558 case FieldType.SInt64:
559 WriteSInt64(fieldNumber, fieldName, (long)value);
csharptest71f662c2011-05-20 15:15:34 -0500560 break;
561 case FieldType.Fixed32:
csharptest90922db2011-06-03 11:57:47 -0500562 WriteFixed32(fieldNumber, fieldName, (uint) value);
csharptest71f662c2011-05-20 15:15:34 -0500563 break;
csharptestc671a4b2011-06-08 11:51:24 -0500564 case FieldType.Fixed64:
565 WriteFixed64(fieldNumber, fieldName, (ulong) value);
csharptest71f662c2011-05-20 15:15:34 -0500566 break;
567 case FieldType.SFixed32:
csharptest90922db2011-06-03 11:57:47 -0500568 WriteSFixed32(fieldNumber, fieldName, (int) value);
csharptest71f662c2011-05-20 15:15:34 -0500569 break;
570 case FieldType.SFixed64:
csharptest90922db2011-06-03 11:57:47 -0500571 WriteSFixed64(fieldNumber, fieldName, (long) value);
csharptest71f662c2011-05-20 15:15:34 -0500572 break;
csharptestc671a4b2011-06-08 11:51:24 -0500573 case FieldType.Double:
574 WriteDouble(fieldNumber, fieldName, (double)value);
csharptest71f662c2011-05-20 15:15:34 -0500575 break;
csharptestc671a4b2011-06-08 11:51:24 -0500576 case FieldType.Float:
577 WriteFloat(fieldNumber, fieldName, (float)value);
csharptest71f662c2011-05-20 15:15:34 -0500578 break;
579 }
580 }
581
582 public void WriteFieldNoTag(FieldType fieldType, object value)
583 {
584 switch (fieldType)
585 {
csharptestc671a4b2011-06-08 11:51:24 -0500586 case FieldType.String:
587 WriteStringNoTag((string)value);
csharptest71f662c2011-05-20 15:15:34 -0500588 break;
csharptestc671a4b2011-06-08 11:51:24 -0500589 case FieldType.Message:
590 WriteMessageNoTag((IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500591 break;
csharptestc671a4b2011-06-08 11:51:24 -0500592 case FieldType.Group:
593 WriteGroupNoTag((IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500594 break;
csharptestc671a4b2011-06-08 11:51:24 -0500595 case FieldType.Bytes:
596 WriteBytesNoTag((ByteString)value);
597 break;
598 case FieldType.Bool:
599 WriteBoolNoTag((bool)value);
600 break;
601 case FieldType.Enum:
602 if (value is System.Enum)
csharptestced18e12011-06-09 19:47:56 -0500603 WriteEnumNoTag((int)value);
csharptestc671a4b2011-06-08 11:51:24 -0500604 else
605 WriteEnumNoTag(((IEnumLite)value).Number);
csharptest71f662c2011-05-20 15:15:34 -0500606 break;
607 case FieldType.Int32:
608 WriteInt32NoTag((int) value);
609 break;
csharptestc671a4b2011-06-08 11:51:24 -0500610 case FieldType.Int64:
611 WriteInt64NoTag((long) value);
csharptest71f662c2011-05-20 15:15:34 -0500612 break;
613 case FieldType.UInt32:
614 WriteUInt32NoTag((uint) value);
615 break;
csharptestc671a4b2011-06-08 11:51:24 -0500616 case FieldType.UInt64:
617 WriteUInt64NoTag((ulong) value);
csharptest71f662c2011-05-20 15:15:34 -0500618 break;
619 case FieldType.SInt32:
620 WriteSInt32NoTag((int) value);
621 break;
622 case FieldType.SInt64:
623 WriteSInt64NoTag((long) value);
624 break;
csharptestc671a4b2011-06-08 11:51:24 -0500625 case FieldType.Fixed32:
626 WriteFixed32NoTag((uint) value);
627 break;
628 case FieldType.Fixed64:
629 WriteFixed64NoTag((ulong) value);
630 break;
631 case FieldType.SFixed32:
632 WriteSFixed32NoTag((int) value);
633 break;
634 case FieldType.SFixed64:
635 WriteSFixed64NoTag((long) value);
636 break;
637 case FieldType.Double:
638 WriteDoubleNoTag((double)value);
639 break;
640 case FieldType.Float:
641 WriteFloatNoTag((float)value);
csharptest71f662c2011-05-20 15:15:34 -0500642 break;
643 }
644 }
645
646 #endregion
647
648 #region Writing of values without tags
649
650 /// <summary>
651 /// Writes a double field value, including tag, to the stream.
652 /// </summary>
653 public void WriteDoubleNoTag(double value)
654 {
csharptest71f662c2011-05-20 15:15:34 -0500655#if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
csharptest8a2d0f42011-06-02 17:02:41 -0500656 byte[] rawBytes = BitConverter.GetBytes(value);
657 if (!BitConverter.IsLittleEndian)
csharptestaef072a2011-06-08 18:00:43 -0500658 ByteArray.Reverse(rawBytes);
csharptest2772dfe2011-06-08 15:50:58 -0500659
660 if (limit - position >= 8)
661 {
662 buffer[position++] = rawBytes[0];
663 buffer[position++] = rawBytes[1];
664 buffer[position++] = rawBytes[2];
665 buffer[position++] = rawBytes[3];
666 buffer[position++] = rawBytes[4];
667 buffer[position++] = rawBytes[5];
668 buffer[position++] = rawBytes[6];
669 buffer[position++] = rawBytes[7];
670 }
671 else
672 WriteRawBytes(rawBytes, 0, 8);
csharptest71f662c2011-05-20 15:15:34 -0500673#else
csharptest8a2d0f42011-06-02 17:02:41 -0500674 WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
csharptest71f662c2011-05-20 15:15:34 -0500675#endif
676 }
677
678 /// <summary>
679 /// Writes a float field value, without a tag, to the stream.
680 /// </summary>
681 public void WriteFloatNoTag(float value)
682 {
csharptest71f662c2011-05-20 15:15:34 -0500683 byte[] rawBytes = BitConverter.GetBytes(value);
csharptestaef072a2011-06-08 18:00:43 -0500684 if (!BitConverter.IsLittleEndian)
685 ByteArray.Reverse(rawBytes);
csharptest2772dfe2011-06-08 15:50:58 -0500686
687 if (limit - position >= 4)
688 {
689 buffer[position++] = rawBytes[0];
690 buffer[position++] = rawBytes[1];
691 buffer[position++] = rawBytes[2];
692 buffer[position++] = rawBytes[3];
693 }
694 else
695 WriteRawBytes(rawBytes, 0, 4);
csharptest71f662c2011-05-20 15:15:34 -0500696 }
697
698 /// <summary>
699 /// Writes a uint64 field value, without a tag, to the stream.
700 /// </summary>
701 [CLSCompliant(false)]
702 public void WriteUInt64NoTag(ulong value)
703 {
704 WriteRawVarint64(value);
705 }
706
707 /// <summary>
708 /// Writes an int64 field value, without a tag, to the stream.
709 /// </summary>
710 public void WriteInt64NoTag(long value)
711 {
712 WriteRawVarint64((ulong) value);
713 }
714
715 /// <summary>
716 /// Writes an int32 field value, without a tag, to the stream.
717 /// </summary>
718 public void WriteInt32NoTag(int value)
719 {
720 if (value >= 0)
721 {
722 WriteRawVarint32((uint) value);
723 }
724 else
725 {
726 // Must sign-extend.
727 WriteRawVarint64((ulong) value);
728 }
729 }
730
731 /// <summary>
732 /// Writes a fixed64 field value, without a tag, to the stream.
733 /// </summary>
734 [CLSCompliant(false)]
735 public void WriteFixed64NoTag(ulong value)
736 {
737 WriteRawLittleEndian64(value);
738 }
739
740 /// <summary>
741 /// Writes a fixed32 field value, without a tag, to the stream.
742 /// </summary>
743 [CLSCompliant(false)]
744 public void WriteFixed32NoTag(uint value)
745 {
746 WriteRawLittleEndian32(value);
747 }
748
749 /// <summary>
750 /// Writes a bool field value, without a tag, to the stream.
751 /// </summary>
752 public void WriteBoolNoTag(bool value)
753 {
754 WriteRawByte(value ? (byte) 1 : (byte) 0);
755 }
756
757 /// <summary>
758 /// Writes a string field value, without a tag, to the stream.
759 /// </summary>
760 public void WriteStringNoTag(string value)
761 {
762 // Optimise the case where we have enough space to write
763 // the string directly to the buffer, which should be common.
764 int length = Encoding.UTF8.GetByteCount(value);
765 WriteRawVarint32((uint) length);
766 if (limit - position >= length)
767 {
768 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
769 position += length;
770 }
771 else
772 {
773 byte[] bytes = Encoding.UTF8.GetBytes(value);
774 WriteRawBytes(bytes);
775 }
776 }
777
778 /// <summary>
779 /// Writes a group field value, without a tag, to the stream.
780 /// </summary>
781 public void WriteGroupNoTag(IMessageLite value)
782 {
783 value.WriteTo(this);
784 }
785
786 public void WriteMessageNoTag(IMessageLite value)
787 {
788 WriteRawVarint32((uint) value.SerializedSize);
789 value.WriteTo(this);
790 }
791
792 public void WriteBytesNoTag(ByteString value)
793 {
csharptest45a93fa2011-06-02 10:52:37 -0500794 WriteRawVarint32((uint)value.Length);
795 value.WriteTo(this);
csharptest71f662c2011-05-20 15:15:34 -0500796 }
797
798 [CLSCompliant(false)]
799 public void WriteUInt32NoTag(uint value)
800 {
801 WriteRawVarint32(value);
802 }
803
804 public void WriteEnumNoTag(int value)
805 {
806 WriteRawVarint32((uint) value);
807 }
808
809 public void WriteSFixed32NoTag(int value)
810 {
811 WriteRawLittleEndian32((uint) value);
812 }
813
814 public void WriteSFixed64NoTag(long value)
815 {
816 WriteRawLittleEndian64((ulong) value);
817 }
818
819 public void WriteSInt32NoTag(int value)
820 {
821 WriteRawVarint32(EncodeZigZag32(value));
822 }
823
824 public void WriteSInt64NoTag(long value)
825 {
826 WriteRawVarint64(EncodeZigZag64(value));
827 }
828
829 #endregion
830
831 #region Underlying writing primitives
832
833 /// <summary>
834 /// Encodes and writes a tag.
835 /// </summary>
836 [CLSCompliant(false)]
837 public void WriteTag(int fieldNumber, WireFormat.WireType type)
838 {
839 WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
840 }
841
csharptestc671a4b2011-06-08 11:51:24 -0500842#if false
csharptest71f662c2011-05-20 15:15:34 -0500843 private void SlowWriteRawVarint32(uint value)
844 {
845 while (true)
846 {
847 if ((value & ~0x7F) == 0)
848 {
849 WriteRawByte(value);
850 return;
851 }
852 else
853 {
854 WriteRawByte((value & 0x7F) | 0x80);
855 value >>= 7;
856 }
857 }
858 }
csharptestc671a4b2011-06-08 11:51:24 -0500859#endif
csharptest71f662c2011-05-20 15:15:34 -0500860 /// <summary>
861 /// Writes a 32 bit value as a varint. The fast route is taken when
862 /// there's enough buffer space left to whizz through without checking
863 /// for each byte; otherwise, we resort to calling WriteRawByte each time.
864 /// </summary>
865 [CLSCompliant(false)]
866 public void WriteRawVarint32(uint value)
867 {
csharptestc671a4b2011-06-08 11:51:24 -0500868#if true
869 while (value > 127 && position < limit)
870 {
871 buffer[position++] = (byte)((value & 0x7F) | 0x80);
872 value >>= 7;
873 }
874 while (value > 127)
875 {
876 WriteRawByte((byte)((value & 0x7F) | 0x80));
877 value >>= 7;
878 }
879 if(position < limit)
880 buffer[position++] = (byte)value;
881 else
882 WriteRawByte((byte)value);
883#else
csharptest71f662c2011-05-20 15:15:34 -0500884 if (position + 5 > limit)
885 {
886 SlowWriteRawVarint32(value);
887 return;
888 }
889
890 while (true)
891 {
892 if ((value & ~0x7F) == 0)
893 {
894 buffer[position++] = (byte) value;
895 return;
896 }
897 else
898 {
899 buffer[position++] = (byte) ((value & 0x7F) | 0x80);
900 value >>= 7;
901 }
902 }
csharptestc671a4b2011-06-08 11:51:24 -0500903#endif
csharptest71f662c2011-05-20 15:15:34 -0500904 }
905
906 [CLSCompliant(false)]
907 public void WriteRawVarint64(ulong value)
908 {
csharptestc671a4b2011-06-08 11:51:24 -0500909#if true
910 while (value > 127 && position < limit)
911 {
912 buffer[position++] = (byte)((value & 0x7F) | 0x80);
913 value >>= 7;
914 }
915 while (value > 127)
916 {
917 WriteRawByte((byte)((value & 0x7F) | 0x80));
918 value >>= 7;
919 }
920 if(position < limit)
921 buffer[position++] = (byte)value;
922 else
923 WriteRawByte((byte)value);
924#else
csharptest71f662c2011-05-20 15:15:34 -0500925 while (true)
926 {
927 if ((value & ~0x7FUL) == 0)
928 {
929 WriteRawByte((uint) value);
930 return;
931 }
932 else
933 {
934 WriteRawByte(((uint) value & 0x7F) | 0x80);
935 value >>= 7;
936 }
937 }
csharptestc671a4b2011-06-08 11:51:24 -0500938#endif
csharptest71f662c2011-05-20 15:15:34 -0500939 }
940
941 [CLSCompliant(false)]
942 public void WriteRawLittleEndian32(uint value)
943 {
csharptestc671a4b2011-06-08 11:51:24 -0500944 if (position + 4 > limit)
945 {
946 WriteRawByte((byte) value);
947 WriteRawByte((byte) (value >> 8));
948 WriteRawByte((byte) (value >> 16));
949 WriteRawByte((byte) (value >> 24));
950 }
951 else
952 {
953 buffer[position++] = ((byte)value);
954 buffer[position++] = ((byte)(value >> 8));
955 buffer[position++] = ((byte)(value >> 16));
956 buffer[position++] = ((byte)(value >> 24));
957 }
csharptest71f662c2011-05-20 15:15:34 -0500958 }
959
960 [CLSCompliant(false)]
961 public void WriteRawLittleEndian64(ulong value)
962 {
csharptestc671a4b2011-06-08 11:51:24 -0500963 if (position + 8 > limit)
964 {
965 WriteRawByte((byte) value);
966 WriteRawByte((byte) (value >> 8));
967 WriteRawByte((byte) (value >> 16));
968 WriteRawByte((byte) (value >> 24));
969 WriteRawByte((byte) (value >> 32));
970 WriteRawByte((byte) (value >> 40));
971 WriteRawByte((byte) (value >> 48));
972 WriteRawByte((byte) (value >> 56));
973 }
974 else
975 {
976 buffer[position++] = ((byte)value);
977 buffer[position++] = ((byte)(value >> 8));
978 buffer[position++] = ((byte)(value >> 16));
979 buffer[position++] = ((byte)(value >> 24));
980 buffer[position++] = ((byte)(value >> 32));
981 buffer[position++] = ((byte)(value >> 40));
982 buffer[position++] = ((byte)(value >> 48));
983 buffer[position++] = ((byte)(value >> 56));
984 }
csharptest71f662c2011-05-20 15:15:34 -0500985 }
986
987 public void WriteRawByte(byte value)
988 {
989 if (position == limit)
990 {
991 RefreshBuffer();
992 }
993
994 buffer[position++] = value;
995 }
996
997 [CLSCompliant(false)]
998 public void WriteRawByte(uint value)
999 {
1000 WriteRawByte((byte) value);
1001 }
1002
1003 /// <summary>
1004 /// Writes out an array of bytes.
1005 /// </summary>
1006 public void WriteRawBytes(byte[] value)
1007 {
1008 WriteRawBytes(value, 0, value.Length);
1009 }
1010
1011 /// <summary>
1012 /// Writes out part of an array of bytes.
1013 /// </summary>
1014 public void WriteRawBytes(byte[] value, int offset, int length)
1015 {
1016 if (limit - position >= length)
1017 {
csharptestaef072a2011-06-08 18:00:43 -05001018 ByteArray.Copy(value, offset, buffer, position, length);
csharptest71f662c2011-05-20 15:15:34 -05001019 // We have room in the current buffer.
1020 position += length;
1021 }
1022 else
1023 {
1024 // Write extends past current buffer. Fill the rest of this buffer and
1025 // flush.
1026 int bytesWritten = limit - position;
csharptestaef072a2011-06-08 18:00:43 -05001027 ByteArray.Copy(value, offset, buffer, position, bytesWritten);
csharptest71f662c2011-05-20 15:15:34 -05001028 offset += bytesWritten;
1029 length -= bytesWritten;
1030 position = limit;
1031 RefreshBuffer();
1032
1033 // Now deal with the rest.
1034 // Since we have an output stream, this is our buffer
1035 // and buffer offset == 0
1036 if (length <= limit)
1037 {
1038 // Fits in new buffer.
csharptestaef072a2011-06-08 18:00:43 -05001039 ByteArray.Copy(value, offset, buffer, 0, length);
csharptest71f662c2011-05-20 15:15:34 -05001040 position = length;
1041 }
1042 else
1043 {
1044 // Write is very big. Let's do it all at once.
1045 output.Write(value, offset, length);
1046 }
1047 }
1048 }
1049
1050 #endregion
csharptest71f662c2011-05-20 15:15:34 -05001051 /// <summary>
1052 /// Encode a 32-bit value with ZigZag encoding.
1053 /// </summary>
1054 /// <remarks>
1055 /// ZigZag encodes signed integers into values that can be efficiently
1056 /// encoded with varint. (Otherwise, negative values must be
1057 /// sign-extended to 64 bits to be varint encoded, thus always taking
1058 /// 10 bytes on the wire.)
1059 /// </remarks>
1060 [CLSCompliant(false)]
1061 public static uint EncodeZigZag32(int n)
1062 {
1063 // Note: the right-shift must be arithmetic
1064 return (uint) ((n << 1) ^ (n >> 31));
1065 }
1066
1067 /// <summary>
1068 /// Encode a 64-bit value with ZigZag encoding.
1069 /// </summary>
1070 /// <remarks>
1071 /// ZigZag encodes signed integers into values that can be efficiently
1072 /// encoded with varint. (Otherwise, negative values must be
1073 /// sign-extended to 64 bits to be varint encoded, thus always taking
1074 /// 10 bytes on the wire.)
1075 /// </remarks>
1076 [CLSCompliant(false)]
1077 public static ulong EncodeZigZag64(long n)
1078 {
1079 return (ulong) ((n << 1) ^ (n >> 63));
1080 }
1081
1082 private void RefreshBuffer()
1083 {
1084 if (output == null)
1085 {
1086 // We're writing to a single buffer.
1087 throw new OutOfSpaceException();
1088 }
1089
1090 // Since we have an output stream, this is our buffer
1091 // and buffer offset == 0
1092 output.Write(buffer, 0, position);
1093 position = 0;
1094 }
1095
1096 /// <summary>
1097 /// Indicates that a CodedOutputStream wrapping a flat byte array
1098 /// ran out of space.
1099 /// </summary>
1100 public sealed class OutOfSpaceException : IOException
1101 {
1102 internal OutOfSpaceException()
1103 : base("CodedOutputStream was writing to a flat byte array and ran out of space.")
1104 {
1105 }
1106 }
1107
1108 public void Flush()
1109 {
1110 if (output != null)
1111 {
1112 RefreshBuffer();
1113 }
1114 }
1115
1116 /// <summary>
1117 /// Verifies that SpaceLeft returns zero. It's common to create a byte array
1118 /// that is exactly big enough to hold a message, then write to it with
1119 /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
1120 /// the message was actually as big as expected, which can help bugs.
1121 /// </summary>
1122 public void CheckNoSpaceLeft()
1123 {
1124 if (SpaceLeft != 0)
1125 {
1126 throw new InvalidOperationException("Did not write as much data as expected.");
1127 }
1128 }
1129
1130 /// <summary>
1131 /// If writing to a flat array, returns the space left in the array. Otherwise,
1132 /// throws an InvalidOperationException.
1133 /// </summary>
1134 public int SpaceLeft
1135 {
1136 get
1137 {
1138 if (output == null)
1139 {
1140 return limit - position;
1141 }
1142 else
1143 {
1144 throw new InvalidOperationException(
1145 "SpaceLeft can only be called on CodedOutputStreams that are " +
1146 "writing to a flat array.");
1147 }
1148 }
1149 }
1150 }
1151}