Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: third_party/protobuf/csharp/src/Google.Protobuf/CodedOutputStream.cs

Issue 1842653006: Update //third_party/protobuf to version 3. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2008 Google Inc. All rights reserved.
4 // https://developers.google.com/protocol-buffers/
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 // * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #endregion
32
33 using Google.Protobuf.Collections;
34 using System;
35 using System.IO;
36 using System.Text;
37
38 namespace Google.Protobuf
39 {
40 /// <summary>
41 /// Encodes and writes protocol message fields.
42 /// </summary>
43 /// <remarks>
44 /// <para>
45 /// This class is generally used by generated code to write appropriate
46 /// primitives to the stream. It effectively encapsulates the lowest
47 /// levels of protocol buffer format. Unlike some other implementations,
48 /// this does not include combined "write tag and value" methods. Generated
49 /// code knows the exact byte representations of the tags they're going to w rite,
50 /// so there's no need to re-encode them each time. Manually-written code ca lling
51 /// this class should just call one of the <c>WriteTag</c> overloads before each value.
52 /// </para>
53 /// <para>
54 /// Repeated fields and map fields are not handled by this class; use <c>Rep eatedField&lt;T&gt;</c>
55 /// and <c>MapField&lt;TKey, TValue&gt;</c> to serialize such fields.
56 /// </para>
57 /// </remarks>
58 public sealed partial class CodedOutputStream
59 {
60 // "Local" copy of Encoding.UTF8, for efficiency. (Yes, it makes a diffe rence.)
61 internal static readonly Encoding Utf8Encoding = Encoding.UTF8;
62
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 /// <summary>
75 /// Creates a new CodedOutputStream that writes directly to the given
76 /// byte array. If more bytes are written than fit in the array,
77 /// OutOfSpaceException will be thrown.
78 /// </summary>
79 public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArra y.Length)
80 {
81 }
82
83 /// <summary>
84 /// Creates a new CodedOutputStream that writes directly to the given
85 /// byte array slice. If more bytes are written than fit in the array,
86 /// OutOfSpaceException will be thrown.
87 /// </summary>
88 private CodedOutputStream(byte[] buffer, int offset, int length)
89 {
90 this.output = null;
91 this.buffer = buffer;
92 this.position = offset;
93 this.limit = offset + length;
94 }
95
96 private CodedOutputStream(Stream output, byte[] buffer)
97 {
98 this.output = output;
99 this.buffer = buffer;
100 this.position = 0;
101 this.limit = buffer.Length;
102 }
103
104 /// <summary>
105 /// Creates a new CodedOutputStream which write to the given stream.
106 /// </summary>
107 public CodedOutputStream(Stream output) : this(output, DefaultBufferSize )
108 {
109 }
110
111 /// <summary>
112 /// Creates a new CodedOutputStream which write to the given stream and uses
113 /// the specified buffer size.
114 /// </summary>
115 public CodedOutputStream(Stream output, int bufferSize) : this(output, n ew byte[bufferSize])
116 {
117 }
118 #endregion
119
120 /// <summary>
121 /// Returns the current position in the stream, or the position in the o utput buffer
122 /// </summary>
123 public long Position
124 {
125 get
126 {
127 if (output != null)
128 {
129 return output.Position + position;
130 }
131 return position;
132 }
133 }
134
135 #region Writing of values (not including tags)
136
137 /// <summary>
138 /// Writes a double field value, without a tag, to the stream.
139 /// </summary>
140 /// <param name="value">The value to write</param>
141 public void WriteDouble(double value)
142 {
143 WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value)) ;
144 }
145
146 /// <summary>
147 /// Writes a float field value, without a tag, to the stream.
148 /// </summary>
149 /// <param name="value">The value to write</param>
150 public void WriteFloat(float value)
151 {
152 byte[] rawBytes = BitConverter.GetBytes(value);
153 if (!BitConverter.IsLittleEndian)
154 {
155 ByteArray.Reverse(rawBytes);
156 }
157
158 if (limit - position >= 4)
159 {
160 buffer[position++] = rawBytes[0];
161 buffer[position++] = rawBytes[1];
162 buffer[position++] = rawBytes[2];
163 buffer[position++] = rawBytes[3];
164 }
165 else
166 {
167 WriteRawBytes(rawBytes, 0, 4);
168 }
169 }
170
171 /// <summary>
172 /// Writes a uint64 field value, without a tag, to the stream.
173 /// </summary>
174 /// <param name="value">The value to write</param>
175 public void WriteUInt64(ulong value)
176 {
177 WriteRawVarint64(value);
178 }
179
180 /// <summary>
181 /// Writes an int64 field value, without a tag, to the stream.
182 /// </summary>
183 /// <param name="value">The value to write</param>
184 public void WriteInt64(long value)
185 {
186 WriteRawVarint64((ulong) value);
187 }
188
189 /// <summary>
190 /// Writes an int32 field value, without a tag, to the stream.
191 /// </summary>
192 /// <param name="value">The value to write</param>
193 public void WriteInt32(int value)
194 {
195 if (value >= 0)
196 {
197 WriteRawVarint32((uint) value);
198 }
199 else
200 {
201 // Must sign-extend.
202 WriteRawVarint64((ulong) value);
203 }
204 }
205
206 /// <summary>
207 /// Writes a fixed64 field value, without a tag, to the stream.
208 /// </summary>
209 /// <param name="value">The value to write</param>
210 public void WriteFixed64(ulong value)
211 {
212 WriteRawLittleEndian64(value);
213 }
214
215 /// <summary>
216 /// Writes a fixed32 field value, without a tag, to the stream.
217 /// </summary>
218 /// <param name="value">The value to write</param>
219 public void WriteFixed32(uint value)
220 {
221 WriteRawLittleEndian32(value);
222 }
223
224 /// <summary>
225 /// Writes a bool field value, without a tag, to the stream.
226 /// </summary>
227 /// <param name="value">The value to write</param>
228 public void WriteBool(bool value)
229 {
230 WriteRawByte(value ? (byte) 1 : (byte) 0);
231 }
232
233 /// <summary>
234 /// Writes a string field value, without a tag, to the stream.
235 /// The data is length-prefixed.
236 /// </summary>
237 /// <param name="value">The value to write</param>
238 public void WriteString(string value)
239 {
240 // Optimise the case where we have enough space to write
241 // the string directly to the buffer, which should be common.
242 int length = Utf8Encoding.GetByteCount(value);
243 WriteLength(length);
244 if (limit - position >= length)
245 {
246 if (length == value.Length) // Must be all ASCII...
247 {
248 for (int i = 0; i < length; i++)
249 {
250 buffer[position + i] = (byte)value[i];
251 }
252 }
253 else
254 {
255 Utf8Encoding.GetBytes(value, 0, value.Length, buffer, positi on);
256 }
257 position += length;
258 }
259 else
260 {
261 byte[] bytes = Utf8Encoding.GetBytes(value);
262 WriteRawBytes(bytes);
263 }
264 }
265
266 /// <summary>
267 /// Writes a message, without a tag, to the stream.
268 /// The data is length-prefixed.
269 /// </summary>
270 /// <param name="value">The value to write</param>
271 public void WriteMessage(IMessage value)
272 {
273 WriteLength(value.CalculateSize());
274 value.WriteTo(this);
275 }
276
277 /// <summary>
278 /// Write a byte string, without a tag, to the stream.
279 /// The data is length-prefixed.
280 /// </summary>
281 /// <param name="value">The value to write</param>
282 public void WriteBytes(ByteString value)
283 {
284 WriteLength(value.Length);
285 value.WriteRawBytesTo(this);
286 }
287
288 /// <summary>
289 /// Writes a uint32 value, without a tag, to the stream.
290 /// </summary>
291 /// <param name="value">The value to write</param>
292 public void WriteUInt32(uint value)
293 {
294 WriteRawVarint32(value);
295 }
296
297 /// <summary>
298 /// Writes an enum value, without a tag, to the stream.
299 /// </summary>
300 /// <param name="value">The value to write</param>
301 public void WriteEnum(int value)
302 {
303 WriteInt32(value);
304 }
305
306 /// <summary>
307 /// Writes an sfixed32 value, without a tag, to the stream.
308 /// </summary>
309 /// <param name="value">The value to write.</param>
310 public void WriteSFixed32(int value)
311 {
312 WriteRawLittleEndian32((uint) value);
313 }
314
315 /// <summary>
316 /// Writes an sfixed64 value, without a tag, to the stream.
317 /// </summary>
318 /// <param name="value">The value to write</param>
319 public void WriteSFixed64(long value)
320 {
321 WriteRawLittleEndian64((ulong) value);
322 }
323
324 /// <summary>
325 /// Writes an sint32 value, without a tag, to the stream.
326 /// </summary>
327 /// <param name="value">The value to write</param>
328 public void WriteSInt32(int value)
329 {
330 WriteRawVarint32(EncodeZigZag32(value));
331 }
332
333 /// <summary>
334 /// Writes an sint64 value, without a tag, to the stream.
335 /// </summary>
336 /// <param name="value">The value to write</param>
337 public void WriteSInt64(long value)
338 {
339 WriteRawVarint64(EncodeZigZag64(value));
340 }
341
342 /// <summary>
343 /// Writes a length (in bytes) for length-delimited data.
344 /// </summary>
345 /// <remarks>
346 /// This method simply writes a rawint, but exists for clarity in callin g code.
347 /// </remarks>
348 /// <param name="length">Length value, in bytes.</param>
349 public void WriteLength(int length)
350 {
351 WriteRawVarint32((uint) length);
352 }
353
354 #endregion
355
356 #region Raw tag writing
357 /// <summary>
358 /// Encodes and writes a tag.
359 /// </summary>
360 /// <param name="fieldNumber">The number of the field to write the tag f or</param>
361 /// <param name="type">The wire format type of the tag to write</param>
362 public void WriteTag(int fieldNumber, WireFormat.WireType type)
363 {
364 WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
365 }
366
367 /// <summary>
368 /// Writes an already-encoded tag.
369 /// </summary>
370 /// <param name="tag">The encoded tag</param>
371 public void WriteTag(uint tag)
372 {
373 WriteRawVarint32(tag);
374 }
375
376 /// <summary>
377 /// Writes the given single-byte tag directly to the stream.
378 /// </summary>
379 /// <param name="b1">The encoded tag</param>
380 public void WriteRawTag(byte b1)
381 {
382 WriteRawByte(b1);
383 }
384
385 /// <summary>
386 /// Writes the given two-byte tag directly to the stream.
387 /// </summary>
388 /// <param name="b1">The first byte of the encoded tag</param>
389 /// <param name="b2">The second byte of the encoded tag</param>
390 public void WriteRawTag(byte b1, byte b2)
391 {
392 WriteRawByte(b1);
393 WriteRawByte(b2);
394 }
395
396 /// <summary>
397 /// Writes the given three-byte tag directly to the stream.
398 /// </summary>
399 /// <param name="b1">The first byte of the encoded tag</param>
400 /// <param name="b2">The second byte of the encoded tag</param>
401 /// <param name="b3">The third byte of the encoded tag</param>
402 public void WriteRawTag(byte b1, byte b2, byte b3)
403 {
404 WriteRawByte(b1);
405 WriteRawByte(b2);
406 WriteRawByte(b3);
407 }
408
409 /// <summary>
410 /// Writes the given four-byte tag directly to the stream.
411 /// </summary>
412 /// <param name="b1">The first byte of the encoded tag</param>
413 /// <param name="b2">The second byte of the encoded tag</param>
414 /// <param name="b3">The third byte of the encoded tag</param>
415 /// <param name="b4">The fourth byte of the encoded tag</param>
416 public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)
417 {
418 WriteRawByte(b1);
419 WriteRawByte(b2);
420 WriteRawByte(b3);
421 WriteRawByte(b4);
422 }
423
424 /// <summary>
425 /// Writes the given five-byte tag directly to the stream.
426 /// </summary>
427 /// <param name="b1">The first byte of the encoded tag</param>
428 /// <param name="b2">The second byte of the encoded tag</param>
429 /// <param name="b3">The third byte of the encoded tag</param>
430 /// <param name="b4">The fourth byte of the encoded tag</param>
431 /// <param name="b5">The fifth byte of the encoded tag</param>
432 public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)
433 {
434 WriteRawByte(b1);
435 WriteRawByte(b2);
436 WriteRawByte(b3);
437 WriteRawByte(b4);
438 WriteRawByte(b5);
439 }
440 #endregion
441
442 #region Underlying writing primitives
443 /// <summary>
444 /// Writes a 32 bit value as a varint. The fast route is taken when
445 /// there's enough buffer space left to whizz through without checking
446 /// for each byte; otherwise, we resort to calling WriteRawByte each tim e.
447 /// </summary>
448 internal void WriteRawVarint32(uint value)
449 {
450 // Optimize for the common case of a single byte value
451 if (value < 128 && position < limit)
452 {
453 buffer[position++] = (byte)value;
454 return;
455 }
456
457 while (value > 127 && position < limit)
458 {
459 buffer[position++] = (byte) ((value & 0x7F) | 0x80);
460 value >>= 7;
461 }
462 while (value > 127)
463 {
464 WriteRawByte((byte) ((value & 0x7F) | 0x80));
465 value >>= 7;
466 }
467 if (position < limit)
468 {
469 buffer[position++] = (byte) value;
470 }
471 else
472 {
473 WriteRawByte((byte) value);
474 }
475 }
476
477 internal void WriteRawVarint64(ulong value)
478 {
479 while (value > 127 && position < limit)
480 {
481 buffer[position++] = (byte) ((value & 0x7F) | 0x80);
482 value >>= 7;
483 }
484 while (value > 127)
485 {
486 WriteRawByte((byte) ((value & 0x7F) | 0x80));
487 value >>= 7;
488 }
489 if (position < limit)
490 {
491 buffer[position++] = (byte) value;
492 }
493 else
494 {
495 WriteRawByte((byte) value);
496 }
497 }
498
499 internal void WriteRawLittleEndian32(uint value)
500 {
501 if (position + 4 > limit)
502 {
503 WriteRawByte((byte) value);
504 WriteRawByte((byte) (value >> 8));
505 WriteRawByte((byte) (value >> 16));
506 WriteRawByte((byte) (value >> 24));
507 }
508 else
509 {
510 buffer[position++] = ((byte) value);
511 buffer[position++] = ((byte) (value >> 8));
512 buffer[position++] = ((byte) (value >> 16));
513 buffer[position++] = ((byte) (value >> 24));
514 }
515 }
516
517 internal void WriteRawLittleEndian64(ulong value)
518 {
519 if (position + 8 > limit)
520 {
521 WriteRawByte((byte) value);
522 WriteRawByte((byte) (value >> 8));
523 WriteRawByte((byte) (value >> 16));
524 WriteRawByte((byte) (value >> 24));
525 WriteRawByte((byte) (value >> 32));
526 WriteRawByte((byte) (value >> 40));
527 WriteRawByte((byte) (value >> 48));
528 WriteRawByte((byte) (value >> 56));
529 }
530 else
531 {
532 buffer[position++] = ((byte) value);
533 buffer[position++] = ((byte) (value >> 8));
534 buffer[position++] = ((byte) (value >> 16));
535 buffer[position++] = ((byte) (value >> 24));
536 buffer[position++] = ((byte) (value >> 32));
537 buffer[position++] = ((byte) (value >> 40));
538 buffer[position++] = ((byte) (value >> 48));
539 buffer[position++] = ((byte) (value >> 56));
540 }
541 }
542
543 internal void WriteRawByte(byte value)
544 {
545 if (position == limit)
546 {
547 RefreshBuffer();
548 }
549
550 buffer[position++] = value;
551 }
552
553 internal void WriteRawByte(uint value)
554 {
555 WriteRawByte((byte) value);
556 }
557
558 /// <summary>
559 /// Writes out an array of bytes.
560 /// </summary>
561 internal void WriteRawBytes(byte[] value)
562 {
563 WriteRawBytes(value, 0, value.Length);
564 }
565
566 /// <summary>
567 /// Writes out part of an array of bytes.
568 /// </summary>
569 internal void WriteRawBytes(byte[] value, int offset, int length)
570 {
571 if (limit - position >= length)
572 {
573 ByteArray.Copy(value, offset, buffer, position, length);
574 // We have room in the current buffer.
575 position += length;
576 }
577 else
578 {
579 // Write extends past current buffer. Fill the rest of this buf fer and
580 // flush.
581 int bytesWritten = limit - position;
582 ByteArray.Copy(value, offset, buffer, position, bytesWritten);
583 offset += bytesWritten;
584 length -= bytesWritten;
585 position = limit;
586 RefreshBuffer();
587
588 // Now deal with the rest.
589 // Since we have an output stream, this is our buffer
590 // and buffer offset == 0
591 if (length <= limit)
592 {
593 // Fits in new buffer.
594 ByteArray.Copy(value, offset, buffer, 0, length);
595 position = length;
596 }
597 else
598 {
599 // Write is very big. Let's do it all at once.
600 output.Write(value, offset, length);
601 }
602 }
603 }
604
605 #endregion
606
607 /// <summary>
608 /// Encode a 32-bit value with ZigZag encoding.
609 /// </summary>
610 /// <remarks>
611 /// ZigZag encodes signed integers into values that can be efficiently
612 /// encoded with varint. (Otherwise, negative values must be
613 /// sign-extended to 64 bits to be varint encoded, thus always taking
614 /// 10 bytes on the wire.)
615 /// </remarks>
616 internal static uint EncodeZigZag32(int n)
617 {
618 // Note: the right-shift must be arithmetic
619 return (uint) ((n << 1) ^ (n >> 31));
620 }
621
622 /// <summary>
623 /// Encode a 64-bit value with ZigZag encoding.
624 /// </summary>
625 /// <remarks>
626 /// ZigZag encodes signed integers into values that can be efficiently
627 /// encoded with varint. (Otherwise, negative values must be
628 /// sign-extended to 64 bits to be varint encoded, thus always taking
629 /// 10 bytes on the wire.)
630 /// </remarks>
631 internal static ulong EncodeZigZag64(long n)
632 {
633 return (ulong) ((n << 1) ^ (n >> 63));
634 }
635
636 private void RefreshBuffer()
637 {
638 if (output == null)
639 {
640 // We're writing to a single buffer.
641 throw new OutOfSpaceException();
642 }
643
644 // Since we have an output stream, this is our buffer
645 // and buffer offset == 0
646 output.Write(buffer, 0, position);
647 position = 0;
648 }
649
650 /// <summary>
651 /// Indicates that a CodedOutputStream wrapping a flat byte array
652 /// ran out of space.
653 /// </summary>
654 public sealed class OutOfSpaceException : IOException
655 {
656 internal OutOfSpaceException()
657 : base("CodedOutputStream was writing to a flat byte array and r an out of space.")
658 {
659 }
660 }
661
662 /// <summary>
663 /// Flushes any buffered data to the underlying stream (if there is one) .
664 /// </summary>
665 public void Flush()
666 {
667 if (output != null)
668 {
669 RefreshBuffer();
670 }
671 }
672
673 /// <summary>
674 /// Verifies that SpaceLeft returns zero. It's common to create a byte a rray
675 /// that is exactly big enough to hold a message, then write to it with
676 /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
677 /// the message was actually as big as expected, which can help bugs.
678 /// </summary>
679 public void CheckNoSpaceLeft()
680 {
681 if (SpaceLeft != 0)
682 {
683 throw new InvalidOperationException("Did not write as much data as expected.");
684 }
685 }
686
687 /// <summary>
688 /// If writing to a flat array, returns the space left in the array. Oth erwise,
689 /// throws an InvalidOperationException.
690 /// </summary>
691 public int SpaceLeft
692 {
693 get
694 {
695 if (output == null)
696 {
697 return limit - position;
698 }
699 else
700 {
701 throw new InvalidOperationException(
702 "SpaceLeft can only be called on CodedOutputStreams that are " +
703 "writing to a flat array.");
704 }
705 }
706 }
707 }
708 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698