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