blob: 0bc4a462e845ec464d22c4fdd23b4db06a3094e5 [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;
43using Google.ProtocolBuffers.Descriptors;
44
45namespace Google.ProtocolBuffers
46{
47 /// <summary>
48 /// Encodes and writes protocol message fields.
49 /// </summary>
50 /// <remarks>
51 /// This class contains two kinds of methods: methods that write specific
52 /// protocol message constructs and field types (e.g. WriteTag and
53 /// WriteInt32) and methods that write low-level values (e.g.
54 /// WriteRawVarint32 and WriteRawBytes). If you are writing encoded protocol
55 /// messages, you should use the former methods, but if you are writing some
56 /// other format of your own design, use the latter. The names of the former
57 /// methods are taken from the protocol buffer type names, not .NET types.
58 /// (Hence WriteFloat instead of WriteSingle, and WriteBool instead of WriteBoolean.)
59 /// </remarks>
csharptestcc8d2aa2011-06-03 12:15:42 -050060 public sealed partial class CodedOutputStream : ICodedOutputStream
csharptest71f662c2011-05-20 15:15:34 -050061 {
62 /// <summary>
63 /// The buffer size used by CreateInstance(Stream).
64 /// </summary>
65 public static readonly int DefaultBufferSize = 4096;
66
67 private readonly byte[] buffer;
68 private readonly int limit;
69 private int position;
70 private readonly Stream output;
71
72 #region Construction
73
74 private CodedOutputStream(byte[] buffer, int offset, int length)
75 {
76 this.output = null;
77 this.buffer = buffer;
78 this.position = offset;
79 this.limit = offset + length;
80 }
81
82 private CodedOutputStream(Stream output, byte[] buffer)
83 {
84 this.output = output;
85 this.buffer = buffer;
86 this.position = 0;
87 this.limit = buffer.Length;
88 }
89
90 /// <summary>
91 /// Creates a new CodedOutputStream which write to the given stream.
92 /// </summary>
93 public static CodedOutputStream CreateInstance(Stream output)
94 {
95 return CreateInstance(output, DefaultBufferSize);
96 }
97
98 /// <summary>
99 /// Creates a new CodedOutputStream which write to the given stream and uses
100 /// the specified buffer size.
101 /// </summary>
102 public static CodedOutputStream CreateInstance(Stream output, int bufferSize)
103 {
104 return new CodedOutputStream(output, new byte[bufferSize]);
105 }
106
107 /// <summary>
108 /// Creates a new CodedOutputStream that writes directly to the given
109 /// byte array. If more bytes are written than fit in the array,
110 /// OutOfSpaceException will be thrown.
111 /// </summary>
112 public static CodedOutputStream CreateInstance(byte[] flatArray)
113 {
114 return CreateInstance(flatArray, 0, flatArray.Length);
115 }
116
117 /// <summary>
118 /// Creates a new CodedOutputStream that writes directly to the given
119 /// byte array slice. If more bytes are written than fit in the array,
120 /// OutOfSpaceException will be thrown.
121 /// </summary>
122 public static CodedOutputStream CreateInstance(byte[] flatArray, int offset, int length)
123 {
124 return new CodedOutputStream(flatArray, offset, length);
125 }
126
127 #endregion
128
129 #region Writing of tags etc
130
131 /// <summary>
132 /// Writes a double field value, including tag, to the stream.
133 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500134 public void WriteDouble(int fieldNumber, string fieldName, double value)
csharptest71f662c2011-05-20 15:15:34 -0500135 {
136 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
137 WriteDoubleNoTag(value);
138 }
139
140 /// <summary>
141 /// Writes a float field value, including tag, to the stream.
142 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500143 public void WriteFloat(int fieldNumber, string fieldName, float value)
csharptest71f662c2011-05-20 15:15:34 -0500144 {
145 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
146 WriteFloatNoTag(value);
147 }
148
149 /// <summary>
150 /// Writes a uint64 field value, including tag, to the stream.
151 /// </summary>
152 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500153 public void WriteUInt64(int fieldNumber, string fieldName, ulong value)
csharptest71f662c2011-05-20 15:15:34 -0500154 {
155 WriteTag(fieldNumber, WireFormat.WireType.Varint);
156 WriteRawVarint64(value);
157 }
158
159 /// <summary>
160 /// Writes an int64 field value, including tag, to the stream.
161 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500162 public void WriteInt64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500163 {
164 WriteTag(fieldNumber, WireFormat.WireType.Varint);
165 WriteRawVarint64((ulong) value);
166 }
167
168 /// <summary>
169 /// Writes an int32 field value, including tag, to the stream.
170 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500171 public void WriteInt32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500172 {
173 WriteTag(fieldNumber, WireFormat.WireType.Varint);
174 if (value >= 0)
175 {
176 WriteRawVarint32((uint) value);
177 }
178 else
179 {
180 // Must sign-extend.
181 WriteRawVarint64((ulong) value);
182 }
183 }
184
185 /// <summary>
186 /// Writes a fixed64 field value, including tag, to the stream.
187 /// </summary>
188 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500189 public void WriteFixed64(int fieldNumber, string fieldName, ulong value)
csharptest71f662c2011-05-20 15:15:34 -0500190 {
191 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
192 WriteRawLittleEndian64(value);
193 }
194
195 /// <summary>
196 /// Writes a fixed32 field value, including tag, to the stream.
197 /// </summary>
198 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500199 public void WriteFixed32(int fieldNumber, string fieldName, uint value)
csharptest71f662c2011-05-20 15:15:34 -0500200 {
201 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
202 WriteRawLittleEndian32(value);
203 }
204
205 /// <summary>
206 /// Writes a bool field value, including tag, to the stream.
207 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500208 public void WriteBool(int fieldNumber, string fieldName, bool value)
csharptest71f662c2011-05-20 15:15:34 -0500209 {
210 WriteTag(fieldNumber, WireFormat.WireType.Varint);
211 WriteRawByte(value ? (byte) 1 : (byte) 0);
212 }
213
214 /// <summary>
215 /// Writes a string field value, including tag, to the stream.
216 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500217 public void WriteString(int fieldNumber, string fieldName, string value)
csharptest71f662c2011-05-20 15:15:34 -0500218 {
219 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
220 // Optimise the case where we have enough space to write
221 // the string directly to the buffer, which should be common.
222 int length = Encoding.UTF8.GetByteCount(value);
223 WriteRawVarint32((uint) length);
224 if (limit - position >= length)
225 {
226 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
227 position += length;
228 }
229 else
230 {
231 byte[] bytes = Encoding.UTF8.GetBytes(value);
232 WriteRawBytes(bytes);
233 }
234 }
235
236 /// <summary>
237 /// Writes a group field value, including tag, to the stream.
238 /// </summary>
csharptest90922db2011-06-03 11:57:47 -0500239 public void WriteGroup(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500240 {
241 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
242 value.WriteTo(this);
243 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
244 }
245
246 [Obsolete]
csharptest90922db2011-06-03 11:57:47 -0500247 public void WriteUnknownGroup(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500248 {
249 WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
250 value.WriteTo(this);
251 WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
252 }
253
csharptest90922db2011-06-03 11:57:47 -0500254 public void WriteMessage(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500255 {
256 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
257 WriteRawVarint32((uint) value.SerializedSize);
258 value.WriteTo(this);
259 }
260
csharptest90922db2011-06-03 11:57:47 -0500261 public void WriteBytes(int fieldNumber, string fieldName, ByteString value)
csharptest71f662c2011-05-20 15:15:34 -0500262 {
csharptest71f662c2011-05-20 15:15:34 -0500263 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
csharptest45a93fa2011-06-02 10:52:37 -0500264 WriteRawVarint32((uint)value.Length);
265 value.WriteTo(this);
csharptest71f662c2011-05-20 15:15:34 -0500266 }
267
268 [CLSCompliant(false)]
csharptest90922db2011-06-03 11:57:47 -0500269 public void WriteUInt32(int fieldNumber, string fieldName, uint value)
csharptest71f662c2011-05-20 15:15:34 -0500270 {
271 WriteTag(fieldNumber, WireFormat.WireType.Varint);
272 WriteRawVarint32(value);
273 }
274
csharptest90922db2011-06-03 11:57:47 -0500275 public void WriteEnum(int fieldNumber, string fieldName, int value, string textValue)
csharptest71f662c2011-05-20 15:15:34 -0500276 {
277 WriteTag(fieldNumber, WireFormat.WireType.Varint);
278 WriteRawVarint32((uint) value);
279 }
280
csharptest90922db2011-06-03 11:57:47 -0500281 public void WriteSFixed32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500282 {
283 WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
284 WriteRawLittleEndian32((uint) value);
285 }
286
csharptest90922db2011-06-03 11:57:47 -0500287 public void WriteSFixed64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500288 {
289 WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
290 WriteRawLittleEndian64((ulong) value);
291 }
292
csharptest90922db2011-06-03 11:57:47 -0500293 public void WriteSInt32(int fieldNumber, string fieldName, int value)
csharptest71f662c2011-05-20 15:15:34 -0500294 {
295 WriteTag(fieldNumber, WireFormat.WireType.Varint);
296 WriteRawVarint32(EncodeZigZag32(value));
297 }
298
csharptest90922db2011-06-03 11:57:47 -0500299 public void WriteSInt64(int fieldNumber, string fieldName, long value)
csharptest71f662c2011-05-20 15:15:34 -0500300 {
301 WriteTag(fieldNumber, WireFormat.WireType.Varint);
302 WriteRawVarint64(EncodeZigZag64(value));
303 }
304
csharptest90922db2011-06-03 11:57:47 -0500305 public void WriteMessageSetExtension(int fieldNumber, string fieldName, IMessageLite value)
csharptest71f662c2011-05-20 15:15:34 -0500306 {
307 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
csharptest90922db2011-06-03 11:57:47 -0500308 WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
309 WriteMessage(WireFormat.MessageSetField.Message, "message", value);
csharptest71f662c2011-05-20 15:15:34 -0500310 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
311 }
312
csharptestffafdaa2011-06-03 12:58:14 -0500313 public void WriteMessageSetExtension(int fieldNumber, string fieldName, ByteString value)
csharptest71f662c2011-05-20 15:15:34 -0500314 {
315 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
csharptest90922db2011-06-03 11:57:47 -0500316 WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
317 WriteBytes(WireFormat.MessageSetField.Message, "message", value);
csharptest71f662c2011-05-20 15:15:34 -0500318 WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
319 }
csharptestc671a4b2011-06-08 11:51:24 -0500320
csharptest90922db2011-06-03 11:57:47 -0500321 public void WriteArray(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.IEnumerable list)
322 {
323 foreach (object element in list)
324 WriteField(fieldType, fieldNumber, fieldName, element);
325 }
326
csharptestc671a4b2011-06-08 11:51:24 -0500327 public void WriteArray<T>(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.Generic.IEnumerable<T> list)
328 {
329 switch (fieldType)
330 {
331 case FieldType.String:
332 foreach (string value in ((IEnumerable<string>)list))
333 WriteString(fieldNumber, fieldName, value);
334 break;
335 case FieldType.Message:
336 foreach (T value in list)
337 WriteMessage(fieldNumber, fieldName, (IMessageLite)value);
338 break;
339 case FieldType.Group:
340 foreach (T value in list)
341 WriteGroup(fieldNumber, fieldName, (IMessageLite)value);
342 break;
343 case FieldType.Bytes:
344 foreach (ByteString value in ((IEnumerable<ByteString>)list))
345 WriteBytes(fieldNumber, fieldName, value);
346 break;
347 case FieldType.Bool:
348 foreach (bool value in ((IEnumerable<bool>)list))
349 WriteBool(fieldNumber, fieldName, value);
350 break;
351 case FieldType.Enum:
352 foreach (T value in list)
353 {
354 if (value is System.Enum)
355 WriteEnum(fieldNumber, fieldName, ((IConvertible)value).ToInt32(CultureInfo.InvariantCulture), null/*not used*/);
356 else
357 WriteEnum(fieldNumber, fieldName, ((IEnumLite)value).Number, null/*not used*/);
358 }
359 break;
360 case FieldType.Int32:
361 foreach (int value in ((IEnumerable<int>)list))
362 WriteInt32(fieldNumber, fieldName, value);
363 break;
364 case FieldType.Int64:
365 foreach (long value in ((IEnumerable<long>)list))
366 WriteInt64(fieldNumber, fieldName, value);
367 break;
368 case FieldType.UInt32:
369 foreach (uint value in ((IEnumerable<uint>)list))
370 WriteUInt32(fieldNumber, fieldName, value);
371 break;
372 case FieldType.UInt64:
373 foreach (ulong value in ((IEnumerable<ulong>)list))
374 WriteUInt64(fieldNumber, fieldName, value);
375 break;
376 case FieldType.SInt32:
377 foreach (int value in ((IEnumerable<int>)list))
378 WriteSInt32(fieldNumber, fieldName, value);
379 break;
380 case FieldType.SInt64:
381 foreach (long value in ((IEnumerable<long>)list))
382 WriteSInt64(fieldNumber, fieldName, value);
383 break;
384 case FieldType.Fixed32:
385 foreach (uint value in ((IEnumerable<uint>)list))
386 WriteFixed32(fieldNumber, fieldName, value);
387 break;
388 case FieldType.Fixed64:
389 foreach (ulong value in ((IEnumerable<ulong>)list))
390 WriteFixed64(fieldNumber, fieldName, value);
391 break;
392 case FieldType.SFixed32:
393 foreach (int value in ((IEnumerable<int>)list))
394 WriteSFixed32(fieldNumber, fieldName, value);
395 break;
396 case FieldType.SFixed64:
397 foreach (long value in ((IEnumerable<long>)list))
398 WriteSFixed64(fieldNumber, fieldName, value);
399 break;
400 case FieldType.Double:
401 foreach (double value in ((IEnumerable<double>)list))
402 WriteDouble(fieldNumber, fieldName, value);
403 break;
404 case FieldType.Float:
405 foreach (float value in ((IEnumerable<float>)list))
406 WriteFloat(fieldNumber, fieldName, value);
407 break;
408 }
409 }
410
csharptest90922db2011-06-03 11:57:47 -0500411 public void WritePackedArray(FieldType fieldType, int fieldNumber, string fieldName, System.Collections.IEnumerable list)
412 {
413 int calculatedSize = 0;
414 foreach (object element in list)
415 calculatedSize += CodedOutputStream.ComputeFieldSizeNoTag(fieldType, element);
csharptestc671a4b2011-06-08 11:51:24 -0500416
csharptest90922db2011-06-03 11:57:47 -0500417 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
418 WriteRawVarint32((uint)calculatedSize);
419
420 foreach (object element in list)
421 WriteFieldNoTag(fieldType, element);
422 }
423
csharptestc671a4b2011-06-08 11:51:24 -0500424 public void WritePackedArray<T>(FieldType fieldType, int fieldNumber, string fieldName, int calculatedSize, System.Collections.Generic.IEnumerable<T> list)
425 {
426 WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
427 WriteRawVarint32((uint)calculatedSize);
428
429 switch (fieldType)
430 {
431 case FieldType.String:
432 foreach (string value in ((IEnumerable<string>)list))
433 WriteStringNoTag(value);
434 break;
435 case FieldType.Message:
436 foreach (T value in list)
437 WriteMessageNoTag((IMessageLite)value);
438 break;
439 case FieldType.Group:
440 foreach (T value in list)
441 WriteGroupNoTag((IMessageLite)value);
442 break;
443 case FieldType.Bytes:
444 foreach (ByteString value in ((IEnumerable<ByteString>)list))
445 WriteBytesNoTag(value);
446 break;
447 case FieldType.Bool:
448 foreach (bool value in ((IEnumerable<bool>)list))
449 WriteBoolNoTag(value);
450 break;
451 case FieldType.Enum:
452 foreach (T value in list)
453 {
454 if (value is System.Enum)
455 WriteEnumNoTag(((IConvertible)value).ToInt32(CultureInfo.InvariantCulture));
456 else
457 WriteEnumNoTag(((IEnumLite)value).Number);
458 }
459 break;
460 case FieldType.Int32:
461 foreach (int value in ((IEnumerable<int>)list))
462 WriteInt32NoTag(value);
463 break;
464 case FieldType.Int64:
465 foreach (long value in ((IEnumerable<long>)list))
466 WriteInt64NoTag(value);
467 break;
468 case FieldType.UInt32:
469 foreach (uint value in ((IEnumerable<uint>)list))
470 WriteUInt32NoTag(value);
471 break;
472 case FieldType.UInt64:
473 foreach (ulong value in ((IEnumerable<ulong>)list))
474 WriteUInt64NoTag(value);
475 break;
476 case FieldType.SInt32:
477 foreach (int value in ((IEnumerable<int>)list))
478 WriteSInt32NoTag(value);
479 break;
480 case FieldType.SInt64:
481 foreach (long value in ((IEnumerable<long>)list))
482 WriteSInt64NoTag(value);
483 break;
484 case FieldType.Fixed32:
485 foreach (uint value in ((IEnumerable<uint>)list))
486 WriteFixed32NoTag(value);
487 break;
488 case FieldType.Fixed64:
489 foreach (ulong value in ((IEnumerable<ulong>)list))
490 WriteFixed64NoTag(value);
491 break;
492 case FieldType.SFixed32:
493 foreach (int value in ((IEnumerable<int>)list))
494 WriteSFixed32NoTag(value);
495 break;
496 case FieldType.SFixed64:
497 foreach (long value in ((IEnumerable<long>)list))
498 WriteSFixed64NoTag(value);
499 break;
500 case FieldType.Double:
501 foreach (double value in ((IEnumerable<double>)list))
502 WriteDoubleNoTag(value);
503 break;
504 case FieldType.Float:
505 foreach (float value in ((IEnumerable<float>)list))
506 WriteFloatNoTag(value);
507 break;
508 }
509 }
510
csharptest90922db2011-06-03 11:57:47 -0500511 public void WriteField(FieldType fieldType, int fieldNumber, string fieldName, object value)
csharptest71f662c2011-05-20 15:15:34 -0500512 {
513 switch (fieldType)
514 {
csharptestc671a4b2011-06-08 11:51:24 -0500515 case FieldType.String:
516 WriteString(fieldNumber, fieldName, (string)value);
csharptest71f662c2011-05-20 15:15:34 -0500517 break;
csharptestc671a4b2011-06-08 11:51:24 -0500518 case FieldType.Message:
519 WriteMessage(fieldNumber, fieldName, (IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500520 break;
csharptestc671a4b2011-06-08 11:51:24 -0500521 case FieldType.Group:
522 WriteGroup(fieldNumber, fieldName, (IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500523 break;
csharptestc671a4b2011-06-08 11:51:24 -0500524 case FieldType.Bytes:
525 WriteBytes(fieldNumber, fieldName, (ByteString)value);
526 break;
527 case FieldType.Bool:
528 WriteBool(fieldNumber, fieldName, (bool)value);
529 break;
530 case FieldType.Enum:
531 if (value is System.Enum)
532 WriteEnum(fieldNumber, fieldName, ((IConvertible)value).ToInt32(CultureInfo.InvariantCulture), null/*not used*/);
533 else
534 WriteEnum(fieldNumber, fieldName, ((IEnumLite)value).Number, null/*not used*/);
csharptest71f662c2011-05-20 15:15:34 -0500535 break;
536 case FieldType.Int32:
csharptest90922db2011-06-03 11:57:47 -0500537 WriteInt32(fieldNumber, fieldName, (int) value);
csharptest71f662c2011-05-20 15:15:34 -0500538 break;
csharptestc671a4b2011-06-08 11:51:24 -0500539 case FieldType.Int64:
540 WriteInt64(fieldNumber, fieldName, (long) value);
541 break;
542 case FieldType.UInt32:
543 WriteUInt32(fieldNumber, fieldName, (uint) value);
544 break;
545 case FieldType.UInt64:
546 WriteUInt64(fieldNumber, fieldName, (ulong) value);
547 break;
548 case FieldType.SInt32:
549 WriteSInt32(fieldNumber, fieldName, (int)value);
550 break;
551 case FieldType.SInt64:
552 WriteSInt64(fieldNumber, fieldName, (long)value);
csharptest71f662c2011-05-20 15:15:34 -0500553 break;
554 case FieldType.Fixed32:
csharptest90922db2011-06-03 11:57:47 -0500555 WriteFixed32(fieldNumber, fieldName, (uint) value);
csharptest71f662c2011-05-20 15:15:34 -0500556 break;
csharptestc671a4b2011-06-08 11:51:24 -0500557 case FieldType.Fixed64:
558 WriteFixed64(fieldNumber, fieldName, (ulong) value);
csharptest71f662c2011-05-20 15:15:34 -0500559 break;
560 case FieldType.SFixed32:
csharptest90922db2011-06-03 11:57:47 -0500561 WriteSFixed32(fieldNumber, fieldName, (int) value);
csharptest71f662c2011-05-20 15:15:34 -0500562 break;
563 case FieldType.SFixed64:
csharptest90922db2011-06-03 11:57:47 -0500564 WriteSFixed64(fieldNumber, fieldName, (long) value);
csharptest71f662c2011-05-20 15:15:34 -0500565 break;
csharptestc671a4b2011-06-08 11:51:24 -0500566 case FieldType.Double:
567 WriteDouble(fieldNumber, fieldName, (double)value);
csharptest71f662c2011-05-20 15:15:34 -0500568 break;
csharptestc671a4b2011-06-08 11:51:24 -0500569 case FieldType.Float:
570 WriteFloat(fieldNumber, fieldName, (float)value);
csharptest71f662c2011-05-20 15:15:34 -0500571 break;
572 }
573 }
574
575 public void WriteFieldNoTag(FieldType fieldType, object value)
576 {
577 switch (fieldType)
578 {
csharptestc671a4b2011-06-08 11:51:24 -0500579 case FieldType.String:
580 WriteStringNoTag((string)value);
csharptest71f662c2011-05-20 15:15:34 -0500581 break;
csharptestc671a4b2011-06-08 11:51:24 -0500582 case FieldType.Message:
583 WriteMessageNoTag((IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500584 break;
csharptestc671a4b2011-06-08 11:51:24 -0500585 case FieldType.Group:
586 WriteGroupNoTag((IMessageLite)value);
csharptest71f662c2011-05-20 15:15:34 -0500587 break;
csharptestc671a4b2011-06-08 11:51:24 -0500588 case FieldType.Bytes:
589 WriteBytesNoTag((ByteString)value);
590 break;
591 case FieldType.Bool:
592 WriteBoolNoTag((bool)value);
593 break;
594 case FieldType.Enum:
595 if (value is System.Enum)
596 WriteEnumNoTag(((IConvertible)value).ToInt32(CultureInfo.InvariantCulture));
597 else
598 WriteEnumNoTag(((IEnumLite)value).Number);
csharptest71f662c2011-05-20 15:15:34 -0500599 break;
600 case FieldType.Int32:
601 WriteInt32NoTag((int) value);
602 break;
csharptestc671a4b2011-06-08 11:51:24 -0500603 case FieldType.Int64:
604 WriteInt64NoTag((long) value);
csharptest71f662c2011-05-20 15:15:34 -0500605 break;
606 case FieldType.UInt32:
607 WriteUInt32NoTag((uint) value);
608 break;
csharptestc671a4b2011-06-08 11:51:24 -0500609 case FieldType.UInt64:
610 WriteUInt64NoTag((ulong) value);
csharptest71f662c2011-05-20 15:15:34 -0500611 break;
612 case FieldType.SInt32:
613 WriteSInt32NoTag((int) value);
614 break;
615 case FieldType.SInt64:
616 WriteSInt64NoTag((long) value);
617 break;
csharptestc671a4b2011-06-08 11:51:24 -0500618 case FieldType.Fixed32:
619 WriteFixed32NoTag((uint) value);
620 break;
621 case FieldType.Fixed64:
622 WriteFixed64NoTag((ulong) value);
623 break;
624 case FieldType.SFixed32:
625 WriteSFixed32NoTag((int) value);
626 break;
627 case FieldType.SFixed64:
628 WriteSFixed64NoTag((long) value);
629 break;
630 case FieldType.Double:
631 WriteDoubleNoTag((double)value);
632 break;
633 case FieldType.Float:
634 WriteFloatNoTag((float)value);
csharptest71f662c2011-05-20 15:15:34 -0500635 break;
636 }
637 }
638
639 #endregion
640
641 #region Writing of values without tags
642
643 /// <summary>
644 /// Writes a double field value, including tag, to the stream.
645 /// </summary>
646 public void WriteDoubleNoTag(double value)
647 {
csharptest71f662c2011-05-20 15:15:34 -0500648#if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
csharptest8a2d0f42011-06-02 17:02:41 -0500649 byte[] rawBytes = BitConverter.GetBytes(value);
650 if (!BitConverter.IsLittleEndian)
csharptestaef072a2011-06-08 18:00:43 -0500651 ByteArray.Reverse(rawBytes);
csharptest2772dfe2011-06-08 15:50:58 -0500652
653 if (limit - position >= 8)
654 {
655 buffer[position++] = rawBytes[0];
656 buffer[position++] = rawBytes[1];
657 buffer[position++] = rawBytes[2];
658 buffer[position++] = rawBytes[3];
659 buffer[position++] = rawBytes[4];
660 buffer[position++] = rawBytes[5];
661 buffer[position++] = rawBytes[6];
662 buffer[position++] = rawBytes[7];
663 }
664 else
665 WriteRawBytes(rawBytes, 0, 8);
csharptest71f662c2011-05-20 15:15:34 -0500666#else
csharptest8a2d0f42011-06-02 17:02:41 -0500667 WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
csharptest71f662c2011-05-20 15:15:34 -0500668#endif
669 }
670
671 /// <summary>
672 /// Writes a float field value, without a tag, to the stream.
673 /// </summary>
674 public void WriteFloatNoTag(float value)
675 {
csharptest71f662c2011-05-20 15:15:34 -0500676 byte[] rawBytes = BitConverter.GetBytes(value);
csharptestaef072a2011-06-08 18:00:43 -0500677 if (!BitConverter.IsLittleEndian)
678 ByteArray.Reverse(rawBytes);
csharptest2772dfe2011-06-08 15:50:58 -0500679
680 if (limit - position >= 4)
681 {
682 buffer[position++] = rawBytes[0];
683 buffer[position++] = rawBytes[1];
684 buffer[position++] = rawBytes[2];
685 buffer[position++] = rawBytes[3];
686 }
687 else
688 WriteRawBytes(rawBytes, 0, 4);
csharptest71f662c2011-05-20 15:15:34 -0500689 }
690
691 /// <summary>
692 /// Writes a uint64 field value, without a tag, to the stream.
693 /// </summary>
694 [CLSCompliant(false)]
695 public void WriteUInt64NoTag(ulong value)
696 {
697 WriteRawVarint64(value);
698 }
699
700 /// <summary>
701 /// Writes an int64 field value, without a tag, to the stream.
702 /// </summary>
703 public void WriteInt64NoTag(long value)
704 {
705 WriteRawVarint64((ulong) value);
706 }
707
708 /// <summary>
709 /// Writes an int32 field value, without a tag, to the stream.
710 /// </summary>
711 public void WriteInt32NoTag(int value)
712 {
713 if (value >= 0)
714 {
715 WriteRawVarint32((uint) value);
716 }
717 else
718 {
719 // Must sign-extend.
720 WriteRawVarint64((ulong) value);
721 }
722 }
723
724 /// <summary>
725 /// Writes a fixed64 field value, without a tag, to the stream.
726 /// </summary>
727 [CLSCompliant(false)]
728 public void WriteFixed64NoTag(ulong value)
729 {
730 WriteRawLittleEndian64(value);
731 }
732
733 /// <summary>
734 /// Writes a fixed32 field value, without a tag, to the stream.
735 /// </summary>
736 [CLSCompliant(false)]
737 public void WriteFixed32NoTag(uint value)
738 {
739 WriteRawLittleEndian32(value);
740 }
741
742 /// <summary>
743 /// Writes a bool field value, without a tag, to the stream.
744 /// </summary>
745 public void WriteBoolNoTag(bool value)
746 {
747 WriteRawByte(value ? (byte) 1 : (byte) 0);
748 }
749
750 /// <summary>
751 /// Writes a string field value, without a tag, to the stream.
752 /// </summary>
753 public void WriteStringNoTag(string value)
754 {
755 // Optimise the case where we have enough space to write
756 // the string directly to the buffer, which should be common.
757 int length = Encoding.UTF8.GetByteCount(value);
758 WriteRawVarint32((uint) length);
759 if (limit - position >= length)
760 {
761 Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
762 position += length;
763 }
764 else
765 {
766 byte[] bytes = Encoding.UTF8.GetBytes(value);
767 WriteRawBytes(bytes);
768 }
769 }
770
771 /// <summary>
772 /// Writes a group field value, without a tag, to the stream.
773 /// </summary>
774 public void WriteGroupNoTag(IMessageLite value)
775 {
776 value.WriteTo(this);
777 }
778
779 public void WriteMessageNoTag(IMessageLite value)
780 {
781 WriteRawVarint32((uint) value.SerializedSize);
782 value.WriteTo(this);
783 }
784
785 public void WriteBytesNoTag(ByteString value)
786 {
csharptest45a93fa2011-06-02 10:52:37 -0500787 WriteRawVarint32((uint)value.Length);
788 value.WriteTo(this);
csharptest71f662c2011-05-20 15:15:34 -0500789 }
790
791 [CLSCompliant(false)]
792 public void WriteUInt32NoTag(uint value)
793 {
794 WriteRawVarint32(value);
795 }
796
797 public void WriteEnumNoTag(int value)
798 {
799 WriteRawVarint32((uint) value);
800 }
801
802 public void WriteSFixed32NoTag(int value)
803 {
804 WriteRawLittleEndian32((uint) value);
805 }
806
807 public void WriteSFixed64NoTag(long value)
808 {
809 WriteRawLittleEndian64((ulong) value);
810 }
811
812 public void WriteSInt32NoTag(int value)
813 {
814 WriteRawVarint32(EncodeZigZag32(value));
815 }
816
817 public void WriteSInt64NoTag(long value)
818 {
819 WriteRawVarint64(EncodeZigZag64(value));
820 }
821
822 #endregion
823
824 #region Underlying writing primitives
825
826 /// <summary>
827 /// Encodes and writes a tag.
828 /// </summary>
829 [CLSCompliant(false)]
830 public void WriteTag(int fieldNumber, WireFormat.WireType type)
831 {
832 WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
833 }
834
csharptestc671a4b2011-06-08 11:51:24 -0500835#if false
csharptest71f662c2011-05-20 15:15:34 -0500836 private void SlowWriteRawVarint32(uint value)
837 {
838 while (true)
839 {
840 if ((value & ~0x7F) == 0)
841 {
842 WriteRawByte(value);
843 return;
844 }
845 else
846 {
847 WriteRawByte((value & 0x7F) | 0x80);
848 value >>= 7;
849 }
850 }
851 }
csharptestc671a4b2011-06-08 11:51:24 -0500852#endif
csharptest71f662c2011-05-20 15:15:34 -0500853 /// <summary>
854 /// Writes a 32 bit value as a varint. The fast route is taken when
855 /// there's enough buffer space left to whizz through without checking
856 /// for each byte; otherwise, we resort to calling WriteRawByte each time.
857 /// </summary>
858 [CLSCompliant(false)]
859 public void WriteRawVarint32(uint value)
860 {
csharptestc671a4b2011-06-08 11:51:24 -0500861#if true
862 while (value > 127 && position < limit)
863 {
864 buffer[position++] = (byte)((value & 0x7F) | 0x80);
865 value >>= 7;
866 }
867 while (value > 127)
868 {
869 WriteRawByte((byte)((value & 0x7F) | 0x80));
870 value >>= 7;
871 }
872 if(position < limit)
873 buffer[position++] = (byte)value;
874 else
875 WriteRawByte((byte)value);
876#else
csharptest71f662c2011-05-20 15:15:34 -0500877 if (position + 5 > limit)
878 {
879 SlowWriteRawVarint32(value);
880 return;
881 }
882
883 while (true)
884 {
885 if ((value & ~0x7F) == 0)
886 {
887 buffer[position++] = (byte) value;
888 return;
889 }
890 else
891 {
892 buffer[position++] = (byte) ((value & 0x7F) | 0x80);
893 value >>= 7;
894 }
895 }
csharptestc671a4b2011-06-08 11:51:24 -0500896#endif
csharptest71f662c2011-05-20 15:15:34 -0500897 }
898
899 [CLSCompliant(false)]
900 public void WriteRawVarint64(ulong value)
901 {
csharptestc671a4b2011-06-08 11:51:24 -0500902#if true
903 while (value > 127 && position < limit)
904 {
905 buffer[position++] = (byte)((value & 0x7F) | 0x80);
906 value >>= 7;
907 }
908 while (value > 127)
909 {
910 WriteRawByte((byte)((value & 0x7F) | 0x80));
911 value >>= 7;
912 }
913 if(position < limit)
914 buffer[position++] = (byte)value;
915 else
916 WriteRawByte((byte)value);
917#else
csharptest71f662c2011-05-20 15:15:34 -0500918 while (true)
919 {
920 if ((value & ~0x7FUL) == 0)
921 {
922 WriteRawByte((uint) value);
923 return;
924 }
925 else
926 {
927 WriteRawByte(((uint) value & 0x7F) | 0x80);
928 value >>= 7;
929 }
930 }
csharptestc671a4b2011-06-08 11:51:24 -0500931#endif
csharptest71f662c2011-05-20 15:15:34 -0500932 }
933
934 [CLSCompliant(false)]
935 public void WriteRawLittleEndian32(uint value)
936 {
csharptestc671a4b2011-06-08 11:51:24 -0500937 if (position + 4 > limit)
938 {
939 WriteRawByte((byte) value);
940 WriteRawByte((byte) (value >> 8));
941 WriteRawByte((byte) (value >> 16));
942 WriteRawByte((byte) (value >> 24));
943 }
944 else
945 {
946 buffer[position++] = ((byte)value);
947 buffer[position++] = ((byte)(value >> 8));
948 buffer[position++] = ((byte)(value >> 16));
949 buffer[position++] = ((byte)(value >> 24));
950 }
csharptest71f662c2011-05-20 15:15:34 -0500951 }
952
953 [CLSCompliant(false)]
954 public void WriteRawLittleEndian64(ulong value)
955 {
csharptestc671a4b2011-06-08 11:51:24 -0500956 if (position + 8 > limit)
957 {
958 WriteRawByte((byte) value);
959 WriteRawByte((byte) (value >> 8));
960 WriteRawByte((byte) (value >> 16));
961 WriteRawByte((byte) (value >> 24));
962 WriteRawByte((byte) (value >> 32));
963 WriteRawByte((byte) (value >> 40));
964 WriteRawByte((byte) (value >> 48));
965 WriteRawByte((byte) (value >> 56));
966 }
967 else
968 {
969 buffer[position++] = ((byte)value);
970 buffer[position++] = ((byte)(value >> 8));
971 buffer[position++] = ((byte)(value >> 16));
972 buffer[position++] = ((byte)(value >> 24));
973 buffer[position++] = ((byte)(value >> 32));
974 buffer[position++] = ((byte)(value >> 40));
975 buffer[position++] = ((byte)(value >> 48));
976 buffer[position++] = ((byte)(value >> 56));
977 }
csharptest71f662c2011-05-20 15:15:34 -0500978 }
979
980 public void WriteRawByte(byte value)
981 {
982 if (position == limit)
983 {
984 RefreshBuffer();
985 }
986
987 buffer[position++] = value;
988 }
989
990 [CLSCompliant(false)]
991 public void WriteRawByte(uint value)
992 {
993 WriteRawByte((byte) value);
994 }
995
996 /// <summary>
997 /// Writes out an array of bytes.
998 /// </summary>
999 public void WriteRawBytes(byte[] value)
1000 {
1001 WriteRawBytes(value, 0, value.Length);
1002 }
1003
1004 /// <summary>
1005 /// Writes out part of an array of bytes.
1006 /// </summary>
1007 public void WriteRawBytes(byte[] value, int offset, int length)
1008 {
1009 if (limit - position >= length)
1010 {
csharptestaef072a2011-06-08 18:00:43 -05001011 ByteArray.Copy(value, offset, buffer, position, length);
csharptest71f662c2011-05-20 15:15:34 -05001012 // We have room in the current buffer.
1013 position += length;
1014 }
1015 else
1016 {
1017 // Write extends past current buffer. Fill the rest of this buffer and
1018 // flush.
1019 int bytesWritten = limit - position;
csharptestaef072a2011-06-08 18:00:43 -05001020 ByteArray.Copy(value, offset, buffer, position, bytesWritten);
csharptest71f662c2011-05-20 15:15:34 -05001021 offset += bytesWritten;
1022 length -= bytesWritten;
1023 position = limit;
1024 RefreshBuffer();
1025
1026 // Now deal with the rest.
1027 // Since we have an output stream, this is our buffer
1028 // and buffer offset == 0
1029 if (length <= limit)
1030 {
1031 // Fits in new buffer.
csharptestaef072a2011-06-08 18:00:43 -05001032 ByteArray.Copy(value, offset, buffer, 0, length);
csharptest71f662c2011-05-20 15:15:34 -05001033 position = length;
1034 }
1035 else
1036 {
1037 // Write is very big. Let's do it all at once.
1038 output.Write(value, offset, length);
1039 }
1040 }
1041 }
1042
1043 #endregion
csharptest71f662c2011-05-20 15:15:34 -05001044 /// <summary>
1045 /// Encode a 32-bit value with ZigZag encoding.
1046 /// </summary>
1047 /// <remarks>
1048 /// ZigZag encodes signed integers into values that can be efficiently
1049 /// encoded with varint. (Otherwise, negative values must be
1050 /// sign-extended to 64 bits to be varint encoded, thus always taking
1051 /// 10 bytes on the wire.)
1052 /// </remarks>
1053 [CLSCompliant(false)]
1054 public static uint EncodeZigZag32(int n)
1055 {
1056 // Note: the right-shift must be arithmetic
1057 return (uint) ((n << 1) ^ (n >> 31));
1058 }
1059
1060 /// <summary>
1061 /// Encode a 64-bit value with ZigZag encoding.
1062 /// </summary>
1063 /// <remarks>
1064 /// ZigZag encodes signed integers into values that can be efficiently
1065 /// encoded with varint. (Otherwise, negative values must be
1066 /// sign-extended to 64 bits to be varint encoded, thus always taking
1067 /// 10 bytes on the wire.)
1068 /// </remarks>
1069 [CLSCompliant(false)]
1070 public static ulong EncodeZigZag64(long n)
1071 {
1072 return (ulong) ((n << 1) ^ (n >> 63));
1073 }
1074
1075 private void RefreshBuffer()
1076 {
1077 if (output == null)
1078 {
1079 // We're writing to a single buffer.
1080 throw new OutOfSpaceException();
1081 }
1082
1083 // Since we have an output stream, this is our buffer
1084 // and buffer offset == 0
1085 output.Write(buffer, 0, position);
1086 position = 0;
1087 }
1088
1089 /// <summary>
1090 /// Indicates that a CodedOutputStream wrapping a flat byte array
1091 /// ran out of space.
1092 /// </summary>
1093 public sealed class OutOfSpaceException : IOException
1094 {
1095 internal OutOfSpaceException()
1096 : base("CodedOutputStream was writing to a flat byte array and ran out of space.")
1097 {
1098 }
1099 }
1100
1101 public void Flush()
1102 {
1103 if (output != null)
1104 {
1105 RefreshBuffer();
1106 }
1107 }
1108
1109 /// <summary>
1110 /// Verifies that SpaceLeft returns zero. It's common to create a byte array
1111 /// that is exactly big enough to hold a message, then write to it with
1112 /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
1113 /// the message was actually as big as expected, which can help bugs.
1114 /// </summary>
1115 public void CheckNoSpaceLeft()
1116 {
1117 if (SpaceLeft != 0)
1118 {
1119 throw new InvalidOperationException("Did not write as much data as expected.");
1120 }
1121 }
1122
1123 /// <summary>
1124 /// If writing to a flat array, returns the space left in the array. Otherwise,
1125 /// throws an InvalidOperationException.
1126 /// </summary>
1127 public int SpaceLeft
1128 {
1129 get
1130 {
1131 if (output == null)
1132 {
1133 return limit - position;
1134 }
1135 else
1136 {
1137 throw new InvalidOperationException(
1138 "SpaceLeft can only be called on CodedOutputStreams that are " +
1139 "writing to a flat array.");
1140 }
1141 }
1142 }
1143 }
1144}