blob: 5533ed5b267bc2430c4a996ed6d309a05405d5c1 [file] [log] [blame]
csharptestcc8d2aa2011-06-03 12:15:42 -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;
38using System.Globalization;
39using 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>
58 public sealed partial class CodedOutputStream
59 {
60 private const int LittleEndian64Size = 8;
61 private const int LittleEndian32Size = 4;
62
63 /// <summary>
64 /// Compute the number of bytes that would be needed to encode a
65 /// double field, including the tag.
66 /// </summary>
67 public static int ComputeDoubleSize(int fieldNumber, double value)
68 {
69 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
70 }
71
72 /// <summary>
73 /// Compute the number of bytes that would be needed to encode a
74 /// float field, including the tag.
75 /// </summary>
76 public static int ComputeFloatSize(int fieldNumber, float value)
77 {
78 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
79 }
80
81 /// <summary>
82 /// Compute the number of bytes that would be needed to encode a
83 /// uint64 field, including the tag.
84 /// </summary>
85 [CLSCompliant(false)]
86 public static int ComputeUInt64Size(int fieldNumber, ulong value)
87 {
88 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(value);
89 }
90
91 /// <summary>
92 /// Compute the number of bytes that would be needed to encode an
93 /// int64 field, including the tag.
94 /// </summary>
95 public static int ComputeInt64Size(int fieldNumber, long value)
96 {
97 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size((ulong) value);
98 }
99
100 /// <summary>
101 /// Compute the number of bytes that would be needed to encode an
102 /// int32 field, including the tag.
103 /// </summary>
104 public static int ComputeInt32Size(int fieldNumber, int value)
105 {
106 if (value >= 0)
107 {
108 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint) value);
109 }
110 else
111 {
112 // Must sign-extend.
113 return ComputeTagSize(fieldNumber) + 10;
114 }
115 }
116
117 /// <summary>
118 /// Compute the number of bytes that would be needed to encode a
119 /// fixed64 field, including the tag.
120 /// </summary>
121 [CLSCompliant(false)]
122 public static int ComputeFixed64Size(int fieldNumber, ulong value)
123 {
124 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
125 }
126
127 /// <summary>
128 /// Compute the number of bytes that would be needed to encode a
129 /// fixed32 field, including the tag.
130 /// </summary>
131 [CLSCompliant(false)]
132 public static int ComputeFixed32Size(int fieldNumber, uint value)
133 {
134 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
135 }
136
137 /// <summary>
138 /// Compute the number of bytes that would be needed to encode a
139 /// bool field, including the tag.
140 /// </summary>
141 public static int ComputeBoolSize(int fieldNumber, bool value)
142 {
143 return ComputeTagSize(fieldNumber) + 1;
144 }
145
146 /// <summary>
147 /// Compute the number of bytes that would be needed to encode a
148 /// string field, including the tag.
149 /// </summary>
150 public static int ComputeStringSize(int fieldNumber, String value)
151 {
152 int byteArraySize = Encoding.UTF8.GetByteCount(value);
153 return ComputeTagSize(fieldNumber) +
154 ComputeRawVarint32Size((uint) byteArraySize) +
155 byteArraySize;
156 }
157
158 /// <summary>
159 /// Compute the number of bytes that would be needed to encode a
160 /// group field, including the tag.
161 /// </summary>
162 public static int ComputeGroupSize(int fieldNumber, IMessageLite value)
163 {
164 return ComputeTagSize(fieldNumber)*2 + value.SerializedSize;
165 }
166
167 /// <summary>
168 /// Compute the number of bytes that would be needed to encode a
169 /// group field represented by an UnknownFieldSet, including the tag.
170 /// </summary>
171 [Obsolete]
172 public static int ComputeUnknownGroupSize(int fieldNumber,
173 IMessageLite value)
174 {
175 return ComputeTagSize(fieldNumber)*2 + value.SerializedSize;
176 }
177
178 /// <summary>
179 /// Compute the number of bytes that would be needed to encode an
180 /// embedded message field, including the tag.
181 /// </summary>
182 public static int ComputeMessageSize(int fieldNumber, IMessageLite value)
183 {
184 int size = value.SerializedSize;
185 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint) size) + size;
186 }
187
188 /// <summary>
189 /// Compute the number of bytes that would be needed to encode a
190 /// bytes field, including the tag.
191 /// </summary>
192 public static int ComputeBytesSize(int fieldNumber, ByteString value)
193 {
194 return ComputeTagSize(fieldNumber) +
195 ComputeRawVarint32Size((uint) value.Length) +
196 value.Length;
197 }
198
199 /// <summary>
200 /// Compute the number of bytes that would be needed to encode a
201 /// uint32 field, including the tag.
202 /// </summary>
203 [CLSCompliant(false)]
204 public static int ComputeUInt32Size(int fieldNumber, uint value)
205 {
206 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(value);
207 }
208
209 /// <summary>
210 /// Compute the number of bytes that would be needed to encode a
211 /// enum field, including the tag. The caller is responsible for
212 /// converting the enum value to its numeric value.
213 /// </summary>
214 public static int ComputeEnumSize(int fieldNumber, int value)
215 {
216 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size((uint) value);
217 }
218
219 /// <summary>
220 /// Compute the number of bytes that would be needed to encode an
221 /// sfixed32 field, including the tag.
222 /// </summary>
223 public static int ComputeSFixed32Size(int fieldNumber, int value)
224 {
225 return ComputeTagSize(fieldNumber) + LittleEndian32Size;
226 }
227
228 /// <summary>
229 /// Compute the number of bytes that would be needed to encode an
230 /// sfixed64 field, including the tag.
231 /// </summary>
232 public static int ComputeSFixed64Size(int fieldNumber, long value)
233 {
234 return ComputeTagSize(fieldNumber) + LittleEndian64Size;
235 }
236
237 /// <summary>
238 /// Compute the number of bytes that would be needed to encode an
239 /// sint32 field, including the tag.
240 /// </summary>
241 public static int ComputeSInt32Size(int fieldNumber, int value)
242 {
243 return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(EncodeZigZag32(value));
244 }
245
246 /// <summary>
247 /// Compute the number of bytes that would be needed to encode an
248 /// sint64 field, including the tag.
249 /// </summary>
250 public static int ComputeSInt64Size(int fieldNumber, long value)
251 {
252 return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(EncodeZigZag64(value));
253 }
254
255 /// <summary>
256 /// Compute the number of bytes that would be needed to encode a
257 /// double field, including the tag.
258 /// </summary>
259 public static int ComputeDoubleSizeNoTag(double value)
260 {
261 return LittleEndian64Size;
262 }
263
264 /// <summary>
265 /// Compute the number of bytes that would be needed to encode a
266 /// float field, including the tag.
267 /// </summary>
268 public static int ComputeFloatSizeNoTag(float value)
269 {
270 return LittleEndian32Size;
271 }
272
273 /// <summary>
274 /// Compute the number of bytes that would be needed to encode a
275 /// uint64 field, including the tag.
276 /// </summary>
277 [CLSCompliant(false)]
278 public static int ComputeUInt64SizeNoTag(ulong value)
279 {
280 return ComputeRawVarint64Size(value);
281 }
282
283 /// <summary>
284 /// Compute the number of bytes that would be needed to encode an
285 /// int64 field, including the tag.
286 /// </summary>
287 public static int ComputeInt64SizeNoTag(long value)
288 {
289 return ComputeRawVarint64Size((ulong) value);
290 }
291
292 /// <summary>
293 /// Compute the number of bytes that would be needed to encode an
294 /// int32 field, including the tag.
295 /// </summary>
296 public static int ComputeInt32SizeNoTag(int value)
297 {
298 if (value >= 0)
299 {
300 return ComputeRawVarint32Size((uint) value);
301 }
302 else
303 {
304 // Must sign-extend.
305 return 10;
306 }
307 }
308
309 /// <summary>
310 /// Compute the number of bytes that would be needed to encode a
311 /// fixed64 field, including the tag.
312 /// </summary>
313 [CLSCompliant(false)]
314 public static int ComputeFixed64SizeNoTag(ulong value)
315 {
316 return LittleEndian64Size;
317 }
318
319 /// <summary>
320 /// Compute the number of bytes that would be needed to encode a
321 /// fixed32 field, including the tag.
322 /// </summary>
323 [CLSCompliant(false)]
324 public static int ComputeFixed32SizeNoTag(uint value)
325 {
326 return LittleEndian32Size;
327 }
328
329 /// <summary>
330 /// Compute the number of bytes that would be needed to encode a
331 /// bool field, including the tag.
332 /// </summary>
333 public static int ComputeBoolSizeNoTag(bool value)
334 {
335 return 1;
336 }
337
338 /// <summary>
339 /// Compute the number of bytes that would be needed to encode a
340 /// string field, including the tag.
341 /// </summary>
342 public static int ComputeStringSizeNoTag(String value)
343 {
344 int byteArraySize = Encoding.UTF8.GetByteCount(value);
345 return ComputeRawVarint32Size((uint) byteArraySize) +
346 byteArraySize;
347 }
348
349 /// <summary>
350 /// Compute the number of bytes that would be needed to encode a
351 /// group field, including the tag.
352 /// </summary>
353 public static int ComputeGroupSizeNoTag(IMessageLite value)
354 {
355 return value.SerializedSize;
356 }
357
358 /// <summary>
359 /// Compute the number of bytes that would be needed to encode a
360 /// group field represented by an UnknownFieldSet, including the tag.
361 /// </summary>
362 [Obsolete]
363 public static int ComputeUnknownGroupSizeNoTag(IMessageLite value)
364 {
365 return value.SerializedSize;
366 }
367
368 /// <summary>
369 /// Compute the number of bytes that would be needed to encode an
370 /// embedded message field, including the tag.
371 /// </summary>
372 public static int ComputeMessageSizeNoTag(IMessageLite value)
373 {
374 int size = value.SerializedSize;
375 return ComputeRawVarint32Size((uint) size) + size;
376 }
377
378 /// <summary>
379 /// Compute the number of bytes that would be needed to encode a
380 /// bytes field, including the tag.
381 /// </summary>
382 public static int ComputeBytesSizeNoTag(ByteString value)
383 {
384 return ComputeRawVarint32Size((uint) value.Length) +
385 value.Length;
386 }
387
388 /// <summary>
389 /// Compute the number of bytes that would be needed to encode a
390 /// uint32 field, including the tag.
391 /// </summary>
392 [CLSCompliant(false)]
393 public static int ComputeUInt32SizeNoTag(uint value)
394 {
395 return ComputeRawVarint32Size(value);
396 }
397
398 /// <summary>
399 /// Compute the number of bytes that would be needed to encode a
400 /// enum field, including the tag. The caller is responsible for
401 /// converting the enum value to its numeric value.
402 /// </summary>
403 public static int ComputeEnumSizeNoTag(int value)
404 {
405 return ComputeRawVarint32Size((uint) value);
406 }
407
408 /// <summary>
409 /// Compute the number of bytes that would be needed to encode an
410 /// sfixed32 field, including the tag.
411 /// </summary>
412 public static int ComputeSFixed32SizeNoTag(int value)
413 {
414 return LittleEndian32Size;
415 }
416
417 /// <summary>
418 /// Compute the number of bytes that would be needed to encode an
419 /// sfixed64 field, including the tag.
420 /// </summary>
421 public static int ComputeSFixed64SizeNoTag(long value)
422 {
423 return LittleEndian64Size;
424 }
425
426 /// <summary>
427 /// Compute the number of bytes that would be needed to encode an
428 /// sint32 field, including the tag.
429 /// </summary>
430 public static int ComputeSInt32SizeNoTag(int value)
431 {
432 return ComputeRawVarint32Size(EncodeZigZag32(value));
433 }
434
435 /// <summary>
436 /// Compute the number of bytes that would be needed to encode an
437 /// sint64 field, including the tag.
438 /// </summary>
439 public static int ComputeSInt64SizeNoTag(long value)
440 {
441 return ComputeRawVarint64Size(EncodeZigZag64(value));
442 }
443
444 /*
445 * Compute the number of bytes that would be needed to encode a
446 * MessageSet extension to the stream. For historical reasons,
447 * the wire format differs from normal fields.
448 */
449
450 /// <summary>
451 /// Compute the number of bytes that would be needed to encode a
452 /// MessageSet extension to the stream. For historical reasons,
453 /// the wire format differs from normal fields.
454 /// </summary>
455 public static int ComputeMessageSetExtensionSize(int fieldNumber, IMessageLite value)
456 {
457 return ComputeTagSize(WireFormat.MessageSetField.Item)*2 +
458 ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
459 ComputeMessageSize(WireFormat.MessageSetField.Message, value);
460 }
461
462 /// <summary>
463 /// Compute the number of bytes that would be needed to encode an
464 /// unparsed MessageSet extension field to the stream. For
465 /// historical reasons, the wire format differs from normal fields.
466 /// </summary>
467 public static int ComputeRawMessageSetExtensionSize(int fieldNumber, ByteString value)
468 {
469 return ComputeTagSize(WireFormat.MessageSetField.Item)*2 +
470 ComputeUInt32Size(WireFormat.MessageSetField.TypeID, (uint) fieldNumber) +
471 ComputeBytesSize(WireFormat.MessageSetField.Message, value);
472 }
473
474 /// <summary>
475 /// Compute the number of bytes that would be needed to encode a varint.
476 /// </summary>
477 [CLSCompliant(false)]
478 public static int ComputeRawVarint32Size(uint value)
479 {
480 if ((value & (0xffffffff << 7)) == 0) return 1;
481 if ((value & (0xffffffff << 14)) == 0) return 2;
482 if ((value & (0xffffffff << 21)) == 0) return 3;
483 if ((value & (0xffffffff << 28)) == 0) return 4;
484 return 5;
485 }
486
487 /// <summary>
488 /// Compute the number of bytes that would be needed to encode a varint.
489 /// </summary>
490 [CLSCompliant(false)]
491 public static int ComputeRawVarint64Size(ulong value)
492 {
493 if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
494 if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
495 if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
496 if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
497 if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
498 if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
499 if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
500 if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
501 if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
502 return 10;
503 }
504
505 /// <summary>
506 /// Compute the number of bytes that would be needed to encode a
507 /// field of arbitrary type, including the tag, to the stream.
508 /// </summary>
509 public static int ComputeFieldSize(FieldType fieldType, int fieldNumber, Object value)
510 {
511 switch (fieldType)
512 {
513 case FieldType.Double:
514 return ComputeDoubleSize(fieldNumber, (double) value);
515 case FieldType.Float:
516 return ComputeFloatSize(fieldNumber, (float) value);
517 case FieldType.Int64:
518 return ComputeInt64Size(fieldNumber, (long) value);
519 case FieldType.UInt64:
520 return ComputeUInt64Size(fieldNumber, (ulong) value);
521 case FieldType.Int32:
522 return ComputeInt32Size(fieldNumber, (int) value);
523 case FieldType.Fixed64:
524 return ComputeFixed64Size(fieldNumber, (ulong) value);
525 case FieldType.Fixed32:
526 return ComputeFixed32Size(fieldNumber, (uint) value);
527 case FieldType.Bool:
528 return ComputeBoolSize(fieldNumber, (bool) value);
529 case FieldType.String:
530 return ComputeStringSize(fieldNumber, (string) value);
531 case FieldType.Group:
532 return ComputeGroupSize(fieldNumber, (IMessageLite) value);
533 case FieldType.Message:
534 return ComputeMessageSize(fieldNumber, (IMessageLite) value);
535 case FieldType.Bytes:
536 return ComputeBytesSize(fieldNumber, (ByteString) value);
537 case FieldType.UInt32:
538 return ComputeUInt32Size(fieldNumber, (uint) value);
539 case FieldType.SFixed32:
540 return ComputeSFixed32Size(fieldNumber, (int) value);
541 case FieldType.SFixed64:
542 return ComputeSFixed64Size(fieldNumber, (long) value);
543 case FieldType.SInt32:
544 return ComputeSInt32Size(fieldNumber, (int) value);
545 case FieldType.SInt64:
546 return ComputeSInt64Size(fieldNumber, (long) value);
547 case FieldType.Enum:
548 if (value is System.Enum)
549 return ComputeEnumSize(fieldNumber, ((IConvertible)value).ToInt32(CultureInfo.InvariantCulture));
550 else
551 return ComputeEnumSize(fieldNumber, ((IEnumLite) value).Number);
552 default:
553 throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
554 }
555 }
556
557 /// <summary>
558 /// Compute the number of bytes that would be needed to encode a
559 /// field of arbitrary type, excluding the tag, to the stream.
560 /// </summary>
561 public static int ComputeFieldSizeNoTag(FieldType fieldType, Object value)
562 {
563 switch (fieldType)
564 {
565 case FieldType.Double:
566 return ComputeDoubleSizeNoTag((double) value);
567 case FieldType.Float:
568 return ComputeFloatSizeNoTag((float) value);
569 case FieldType.Int64:
570 return ComputeInt64SizeNoTag((long) value);
571 case FieldType.UInt64:
572 return ComputeUInt64SizeNoTag((ulong) value);
573 case FieldType.Int32:
574 return ComputeInt32SizeNoTag((int) value);
575 case FieldType.Fixed64:
576 return ComputeFixed64SizeNoTag((ulong) value);
577 case FieldType.Fixed32:
578 return ComputeFixed32SizeNoTag((uint) value);
579 case FieldType.Bool:
580 return ComputeBoolSizeNoTag((bool) value);
581 case FieldType.String:
582 return ComputeStringSizeNoTag((string) value);
583 case FieldType.Group:
584 return ComputeGroupSizeNoTag((IMessageLite) value);
585 case FieldType.Message:
586 return ComputeMessageSizeNoTag((IMessageLite) value);
587 case FieldType.Bytes:
588 return ComputeBytesSizeNoTag((ByteString) value);
589 case FieldType.UInt32:
590 return ComputeUInt32SizeNoTag((uint) value);
591 case FieldType.SFixed32:
592 return ComputeSFixed32SizeNoTag((int) value);
593 case FieldType.SFixed64:
594 return ComputeSFixed64SizeNoTag((long) value);
595 case FieldType.SInt32:
596 return ComputeSInt32SizeNoTag((int) value);
597 case FieldType.SInt64:
598 return ComputeSInt64SizeNoTag((long) value);
599 case FieldType.Enum:
600 if (value is System.Enum)
601 return ComputeEnumSizeNoTag(((IConvertible)value).ToInt32(CultureInfo.InvariantCulture));
602 else
603 return ComputeEnumSizeNoTag(((IEnumLite) value).Number);
604 default:
605 throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
606 }
607 }
608
609 /// <summary>
610 /// Compute the number of bytes that would be needed to encode a tag.
611 /// </summary>
612 public static int ComputeTagSize(int fieldNumber)
613 {
614 return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));
615 }
616 }
617}