1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34 //
35 // This implementation is heavily optimized to make reads and writes
36 // of small values (especially varints) as fast as possible. In
37 // particular, we optimize for the common case that a read or a write
38 // will not cross the end of the buffer, since we can avoid a lot
39 // of branching in this case.
40
41 #include <google/protobuf/io/coded_stream_inl.h>
42 #include <algorithm>
43 #include <limits.h>
44 #include <google/protobuf/io/zero_copy_stream.h>
45 #include <google/protobuf/stubs/common.h>
46 #include <google/protobuf/stubs/stl_util.h>
47
48
49 namespace google {
50 namespace protobuf {
51 namespace io {
52
53 namespace {
54
55 static const int kMaxVarintBytes = 10;
56 static const int kMaxVarint32Bytes = 5;
57
58
NextNonEmpty(ZeroCopyInputStream * input,const void ** data,int * size)59 inline bool NextNonEmpty(ZeroCopyInputStream* input,
60 const void** data, int* size) {
61 bool success;
62 do {
63 success = input->Next(data, size);
64 } while (success && *size == 0);
65 return success;
66 }
67
68 } // namespace
69
70 // CodedInputStream ==================================================
71
~CodedInputStream()72 CodedInputStream::~CodedInputStream() {
73 if (input_ != NULL) {
74 BackUpInputToCurrentPosition();
75 }
76
77 if (total_bytes_warning_threshold_ == -2) {
78 GOOGLE_LOG(WARNING) << "The total number of bytes read was " << total_bytes_read_;
79 }
80 }
81
82 // Static.
83 int CodedInputStream::default_recursion_limit_ = 100;
84
85
EnableAliasing(bool enabled)86 void CodedOutputStream::EnableAliasing(bool enabled) {
87 aliasing_enabled_ = enabled && output_->AllowsAliasing();
88 }
89
BackUpInputToCurrentPosition()90 void CodedInputStream::BackUpInputToCurrentPosition() {
91 int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
92 if (backup_bytes > 0) {
93 input_->BackUp(backup_bytes);
94
95 // total_bytes_read_ doesn't include overflow_bytes_.
96 total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
97 buffer_end_ = buffer_;
98 buffer_size_after_limit_ = 0;
99 overflow_bytes_ = 0;
100 }
101 }
102
RecomputeBufferLimits()103 inline void CodedInputStream::RecomputeBufferLimits() {
104 buffer_end_ += buffer_size_after_limit_;
105 int closest_limit = min(current_limit_, total_bytes_limit_);
106 if (closest_limit < total_bytes_read_) {
107 // The limit position is in the current buffer. We must adjust
108 // the buffer size accordingly.
109 buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
110 buffer_end_ -= buffer_size_after_limit_;
111 } else {
112 buffer_size_after_limit_ = 0;
113 }
114 }
115
PushLimit(int byte_limit)116 CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
117 // Current position relative to the beginning of the stream.
118 int current_position = CurrentPosition();
119
120 Limit old_limit = current_limit_;
121
122 // security: byte_limit is possibly evil, so check for negative values
123 // and overflow.
124 if (byte_limit >= 0 &&
125 byte_limit <= INT_MAX - current_position) {
126 current_limit_ = current_position + byte_limit;
127 } else {
128 // Negative or overflow.
129 current_limit_ = INT_MAX;
130 }
131
132 // We need to enforce all limits, not just the new one, so if the previous
133 // limit was before the new requested limit, we continue to enforce the
134 // previous limit.
135 current_limit_ = min(current_limit_, old_limit);
136
137 RecomputeBufferLimits();
138 return old_limit;
139 }
140
PopLimit(Limit limit)141 void CodedInputStream::PopLimit(Limit limit) {
142 // The limit passed in is actually the *old* limit, which we returned from
143 // PushLimit().
144 current_limit_ = limit;
145 RecomputeBufferLimits();
146
147 // We may no longer be at a legitimate message end. ReadTag() needs to be
148 // called again to find out.
149 legitimate_message_end_ = false;
150 }
151
BytesUntilLimit() const152 int CodedInputStream::BytesUntilLimit() const {
153 if (current_limit_ == INT_MAX) return -1;
154 int current_position = CurrentPosition();
155
156 return current_limit_ - current_position;
157 }
158
SetTotalBytesLimit(int total_bytes_limit,int warning_threshold)159 void CodedInputStream::SetTotalBytesLimit(
160 int total_bytes_limit, int warning_threshold) {
161 // Make sure the limit isn't already past, since this could confuse other
162 // code.
163 int current_position = CurrentPosition();
164 total_bytes_limit_ = max(current_position, total_bytes_limit);
165 if (warning_threshold >= 0) {
166 total_bytes_warning_threshold_ = warning_threshold;
167 } else {
168 // warning_threshold is negative
169 total_bytes_warning_threshold_ = -1;
170 }
171 RecomputeBufferLimits();
172 }
173
BytesUntilTotalBytesLimit() const174 int CodedInputStream::BytesUntilTotalBytesLimit() const {
175 if (total_bytes_limit_ == INT_MAX) return -1;
176 return total_bytes_limit_ - CurrentPosition();
177 }
178
PrintTotalBytesLimitError()179 void CodedInputStream::PrintTotalBytesLimitError() {
180 GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
181 "big (more than " << total_bytes_limit_
182 << " bytes). To increase the limit (or to disable these "
183 "warnings), see CodedInputStream::SetTotalBytesLimit() "
184 "in google/protobuf/io/coded_stream.h.";
185 }
186
Skip(int count)187 bool CodedInputStream::Skip(int count) {
188 if (count < 0) return false; // security: count is often user-supplied
189
190 const int original_buffer_size = BufferSize();
191
192 if (count <= original_buffer_size) {
193 // Just skipping within the current buffer. Easy.
194 Advance(count);
195 return true;
196 }
197
198 if (buffer_size_after_limit_ > 0) {
199 // We hit a limit inside this buffer. Advance to the limit and fail.
200 Advance(original_buffer_size);
201 return false;
202 }
203
204 count -= original_buffer_size;
205 buffer_ = NULL;
206 buffer_end_ = buffer_;
207
208 // Make sure this skip doesn't try to skip past the current limit.
209 int closest_limit = min(current_limit_, total_bytes_limit_);
210 int bytes_until_limit = closest_limit - total_bytes_read_;
211 if (bytes_until_limit < count) {
212 // We hit the limit. Skip up to it then fail.
213 if (bytes_until_limit > 0) {
214 total_bytes_read_ = closest_limit;
215 input_->Skip(bytes_until_limit);
216 }
217 return false;
218 }
219
220 total_bytes_read_ += count;
221 return input_->Skip(count);
222 }
223
GetDirectBufferPointer(const void ** data,int * size)224 bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
225 if (BufferSize() == 0 && !Refresh()) return false;
226
227 *data = buffer_;
228 *size = BufferSize();
229 return true;
230 }
231
ReadRaw(void * buffer,int size)232 bool CodedInputStream::ReadRaw(void* buffer, int size) {
233 int current_buffer_size;
234 while ((current_buffer_size = BufferSize()) < size) {
235 // Reading past end of buffer. Copy what we have, then refresh.
236 memcpy(buffer, buffer_, current_buffer_size);
237 buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
238 size -= current_buffer_size;
239 Advance(current_buffer_size);
240 if (!Refresh()) return false;
241 }
242
243 memcpy(buffer, buffer_, size);
244 Advance(size);
245
246 return true;
247 }
248
ReadString(string * buffer,int size)249 bool CodedInputStream::ReadString(string* buffer, int size) {
250 if (size < 0) return false; // security: size is often user-supplied
251 return InternalReadStringInline(buffer, size);
252 }
253
ReadStringFallback(string * buffer,int size)254 bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
255 if (!buffer->empty()) {
256 buffer->clear();
257 }
258
259 int closest_limit = min(current_limit_, total_bytes_limit_);
260 if (closest_limit != INT_MAX) {
261 int bytes_to_limit = closest_limit - CurrentPosition();
262 if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) {
263 buffer->reserve(size);
264 }
265 }
266
267 int current_buffer_size;
268 while ((current_buffer_size = BufferSize()) < size) {
269 // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
270 if (current_buffer_size != 0) {
271 // Note: string1.append(string2) is O(string2.size()) (as opposed to
272 // O(string1.size() + string2.size()), which would be bad).
273 buffer->append(reinterpret_cast<const char*>(buffer_),
274 current_buffer_size);
275 }
276 size -= current_buffer_size;
277 Advance(current_buffer_size);
278 if (!Refresh()) return false;
279 }
280
281 buffer->append(reinterpret_cast<const char*>(buffer_), size);
282 Advance(size);
283
284 return true;
285 }
286
287
ReadLittleEndian32Fallback(uint32 * value)288 bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
289 uint8 bytes[sizeof(*value)];
290
291 const uint8* ptr;
292 if (BufferSize() >= sizeof(*value)) {
293 // Fast path: Enough bytes in the buffer to read directly.
294 ptr = buffer_;
295 Advance(sizeof(*value));
296 } else {
297 // Slow path: Had to read past the end of the buffer.
298 if (!ReadRaw(bytes, sizeof(*value))) return false;
299 ptr = bytes;
300 }
301 ReadLittleEndian32FromArray(ptr, value);
302 return true;
303 }
304
ReadLittleEndian64Fallback(uint64 * value)305 bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
306 uint8 bytes[sizeof(*value)];
307
308 const uint8* ptr;
309 if (BufferSize() >= sizeof(*value)) {
310 // Fast path: Enough bytes in the buffer to read directly.
311 ptr = buffer_;
312 Advance(sizeof(*value));
313 } else {
314 // Slow path: Had to read past the end of the buffer.
315 if (!ReadRaw(bytes, sizeof(*value))) return false;
316 ptr = bytes;
317 }
318 ReadLittleEndian64FromArray(ptr, value);
319 return true;
320 }
321
322 namespace {
323
324 inline const uint8* ReadVarint32FromArray(
325 const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
ReadVarint32FromArray(const uint8 * buffer,uint32 * value)326 inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
327 // Fast path: We have enough bytes left in the buffer to guarantee that
328 // this read won't cross the end, so we can skip the checks.
329 const uint8* ptr = buffer;
330 uint32 b;
331 uint32 result;
332
333 b = *(ptr++); result = b ; if (!(b & 0x80)) goto done;
334 result -= 0x80;
335 b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done;
336 result -= 0x80 << 7;
337 b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
338 result -= 0x80 << 14;
339 b = *(ptr++); result += b << 21; if (!(b & 0x80)) goto done;
340 result -= 0x80 << 21;
341 b = *(ptr++); result += b << 28; if (!(b & 0x80)) goto done;
342 // "result -= 0x80 << 28" is irrevelant.
343
344 // If the input is larger than 32 bits, we still need to read it all
345 // and discard the high-order bits.
346 for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
347 b = *(ptr++); if (!(b & 0x80)) goto done;
348 }
349
350 // We have overrun the maximum size of a varint (10 bytes). Assume
351 // the data is corrupt.
352 return NULL;
353
354 done:
355 *value = result;
356 return ptr;
357 }
358
359 } // namespace
360
ReadVarint32Slow(uint32 * value)361 bool CodedInputStream::ReadVarint32Slow(uint32* value) {
362 uint64 result;
363 // Directly invoke ReadVarint64Fallback, since we already tried to optimize
364 // for one-byte varints.
365 if (!ReadVarint64Fallback(&result)) return false;
366 *value = (uint32)result;
367 return true;
368 }
369
ReadVarint32Fallback(uint32 * value)370 bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
371 if (BufferSize() >= kMaxVarintBytes ||
372 // Optimization: We're also safe if the buffer is non-empty and it ends
373 // with a byte that would terminate a varint.
374 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
375 const uint8* end = ReadVarint32FromArray(buffer_, value);
376 if (end == NULL) return false;
377 buffer_ = end;
378 return true;
379 } else {
380 // Really slow case: we will incur the cost of an extra function call here,
381 // but moving this out of line reduces the size of this function, which
382 // improves the common case. In micro benchmarks, this is worth about 10-15%
383 return ReadVarint32Slow(value);
384 }
385 }
386
ReadTagSlow()387 uint32 CodedInputStream::ReadTagSlow() {
388 if (buffer_ == buffer_end_) {
389 // Call refresh.
390 if (!Refresh()) {
391 // Refresh failed. Make sure that it failed due to EOF, not because
392 // we hit total_bytes_limit_, which, unlike normal limits, is not a
393 // valid place to end a message.
394 int current_position = total_bytes_read_ - buffer_size_after_limit_;
395 if (current_position >= total_bytes_limit_) {
396 // Hit total_bytes_limit_. But if we also hit the normal limit,
397 // we're still OK.
398 legitimate_message_end_ = current_limit_ == total_bytes_limit_;
399 } else {
400 legitimate_message_end_ = true;
401 }
402 return 0;
403 }
404 }
405
406 // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
407 // again, since we have now refreshed the buffer.
408 uint64 result = 0;
409 if (!ReadVarint64(&result)) return 0;
410 return static_cast<uint32>(result);
411 }
412
ReadTagFallback()413 uint32 CodedInputStream::ReadTagFallback() {
414 const int buf_size = BufferSize();
415 if (buf_size >= kMaxVarintBytes ||
416 // Optimization: We're also safe if the buffer is non-empty and it ends
417 // with a byte that would terminate a varint.
418 (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
419 uint32 tag;
420 const uint8* end = ReadVarint32FromArray(buffer_, &tag);
421 if (end == NULL) {
422 return 0;
423 }
424 buffer_ = end;
425 return tag;
426 } else {
427 // We are commonly at a limit when attempting to read tags. Try to quickly
428 // detect this case without making another function call.
429 if ((buf_size == 0) &&
430 ((buffer_size_after_limit_ > 0) ||
431 (total_bytes_read_ == current_limit_)) &&
432 // Make sure that the limit we hit is not total_bytes_limit_, since
433 // in that case we still need to call Refresh() so that it prints an
434 // error.
435 total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
436 // We hit a byte limit.
437 legitimate_message_end_ = true;
438 return 0;
439 }
440 return ReadTagSlow();
441 }
442 }
443
ReadVarint64Slow(uint64 * value)444 bool CodedInputStream::ReadVarint64Slow(uint64* value) {
445 // Slow path: This read might cross the end of the buffer, so we
446 // need to check and refresh the buffer if and when it does.
447
448 uint64 result = 0;
449 int count = 0;
450 uint32 b;
451
452 do {
453 if (count == kMaxVarintBytes) return false;
454 while (buffer_ == buffer_end_) {
455 if (!Refresh()) return false;
456 }
457 b = *buffer_;
458 result |= static_cast<uint64>(b & 0x7F) << (7 * count);
459 Advance(1);
460 ++count;
461 } while (b & 0x80);
462
463 *value = result;
464 return true;
465 }
466
ReadVarint64Fallback(uint64 * value)467 bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
468 if (BufferSize() >= kMaxVarintBytes ||
469 // Optimization: We're also safe if the buffer is non-empty and it ends
470 // with a byte that would terminate a varint.
471 (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
472 // Fast path: We have enough bytes left in the buffer to guarantee that
473 // this read won't cross the end, so we can skip the checks.
474
475 const uint8* ptr = buffer_;
476 uint32 b;
477
478 // Splitting into 32-bit pieces gives better performance on 32-bit
479 // processors.
480 uint32 part0 = 0, part1 = 0, part2 = 0;
481
482 b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
483 part0 -= 0x80;
484 b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
485 part0 -= 0x80 << 7;
486 b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
487 part0 -= 0x80 << 14;
488 b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
489 part0 -= 0x80 << 21;
490 b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
491 part1 -= 0x80;
492 b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
493 part1 -= 0x80 << 7;
494 b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
495 part1 -= 0x80 << 14;
496 b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
497 part1 -= 0x80 << 21;
498 b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
499 part2 -= 0x80;
500 b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
501 // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
502
503 // We have overrun the maximum size of a varint (10 bytes). The data
504 // must be corrupt.
505 return false;
506
507 done:
508 Advance(ptr - buffer_);
509 *value = (static_cast<uint64>(part0) ) |
510 (static_cast<uint64>(part1) << 28) |
511 (static_cast<uint64>(part2) << 56);
512 return true;
513 } else {
514 return ReadVarint64Slow(value);
515 }
516 }
517
Refresh()518 bool CodedInputStream::Refresh() {
519 GOOGLE_DCHECK_EQ(0, BufferSize());
520
521 if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
522 total_bytes_read_ == current_limit_) {
523 // We've hit a limit. Stop.
524 int current_position = total_bytes_read_ - buffer_size_after_limit_;
525
526 if (current_position >= total_bytes_limit_ &&
527 total_bytes_limit_ != current_limit_) {
528 // Hit total_bytes_limit_.
529 PrintTotalBytesLimitError();
530 }
531
532 return false;
533 }
534
535 if (total_bytes_warning_threshold_ >= 0 &&
536 total_bytes_read_ >= total_bytes_warning_threshold_) {
537 GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the "
538 "message turns out to be larger than "
539 << total_bytes_limit_ << " bytes, parsing will be halted "
540 "for security reasons. To increase the limit (or to "
541 "disable these warnings), see "
542 "CodedInputStream::SetTotalBytesLimit() in "
543 "google/protobuf/io/coded_stream.h.";
544
545 // Don't warn again for this stream, and print total size at the end.
546 total_bytes_warning_threshold_ = -2;
547 }
548
549 const void* void_buffer;
550 int buffer_size;
551 if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
552 buffer_ = reinterpret_cast<const uint8*>(void_buffer);
553 buffer_end_ = buffer_ + buffer_size;
554 GOOGLE_CHECK_GE(buffer_size, 0);
555
556 if (total_bytes_read_ <= INT_MAX - buffer_size) {
557 total_bytes_read_ += buffer_size;
558 } else {
559 // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
560 // We can't get that far anyway, because total_bytes_limit_ is guaranteed
561 // to be less than it. We need to keep track of the number of bytes
562 // we discarded, though, so that we can call input_->BackUp() to back
563 // up over them on destruction.
564
565 // The following line is equivalent to:
566 // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
567 // except that it avoids overflows. Signed integer overflow has
568 // undefined results according to the C standard.
569 overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
570 buffer_end_ -= overflow_bytes_;
571 total_bytes_read_ = INT_MAX;
572 }
573
574 RecomputeBufferLimits();
575 return true;
576 } else {
577 buffer_ = NULL;
578 buffer_end_ = NULL;
579 return false;
580 }
581 }
582
583 // CodedOutputStream =================================================
584
CodedOutputStream(ZeroCopyOutputStream * output)585 CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
586 : output_(output),
587 buffer_(NULL),
588 buffer_size_(0),
589 total_bytes_(0),
590 had_error_(false),
591 aliasing_enabled_(false) {
592 // Eagerly Refresh() so buffer space is immediately available.
593 Refresh();
594 // The Refresh() may have failed. If the client doesn't write any data,
595 // though, don't consider this an error. If the client does write data, then
596 // another Refresh() will be attempted and it will set the error once again.
597 had_error_ = false;
598 }
599
~CodedOutputStream()600 CodedOutputStream::~CodedOutputStream() {
601 if (buffer_size_ > 0) {
602 output_->BackUp(buffer_size_);
603 }
604 }
605
Skip(int count)606 bool CodedOutputStream::Skip(int count) {
607 if (count < 0) return false;
608
609 while (count > buffer_size_) {
610 count -= buffer_size_;
611 if (!Refresh()) return false;
612 }
613
614 Advance(count);
615 return true;
616 }
617
GetDirectBufferPointer(void ** data,int * size)618 bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
619 if (buffer_size_ == 0 && !Refresh()) return false;
620
621 *data = buffer_;
622 *size = buffer_size_;
623 return true;
624 }
625
WriteRaw(const void * data,int size)626 void CodedOutputStream::WriteRaw(const void* data, int size) {
627 while (buffer_size_ < size) {
628 memcpy(buffer_, data, buffer_size_);
629 size -= buffer_size_;
630 data = reinterpret_cast<const uint8*>(data) + buffer_size_;
631 if (!Refresh()) return;
632 }
633
634 memcpy(buffer_, data, size);
635 Advance(size);
636 }
637
WriteRawToArray(const void * data,int size,uint8 * target)638 uint8* CodedOutputStream::WriteRawToArray(
639 const void* data, int size, uint8* target) {
640 memcpy(target, data, size);
641 return target + size;
642 }
643
644
WriteAliasedRaw(const void * data,int size)645 void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
646 if (size < buffer_size_
647 ) {
648 WriteRaw(data, size);
649 } else {
650 if (buffer_size_ > 0) {
651 output_->BackUp(buffer_size_);
652 total_bytes_ -= buffer_size_;
653 buffer_ = NULL;
654 buffer_size_ = 0;
655 }
656
657 total_bytes_ += size;
658 had_error_ |= !output_->WriteAliasedRaw(data, size);
659 }
660 }
661
WriteLittleEndian32(uint32 value)662 void CodedOutputStream::WriteLittleEndian32(uint32 value) {
663 uint8 bytes[sizeof(value)];
664
665 bool use_fast = buffer_size_ >= sizeof(value);
666 uint8* ptr = use_fast ? buffer_ : bytes;
667
668 WriteLittleEndian32ToArray(value, ptr);
669
670 if (use_fast) {
671 Advance(sizeof(value));
672 } else {
673 WriteRaw(bytes, sizeof(value));
674 }
675 }
676
WriteLittleEndian64(uint64 value)677 void CodedOutputStream::WriteLittleEndian64(uint64 value) {
678 uint8 bytes[sizeof(value)];
679
680 bool use_fast = buffer_size_ >= sizeof(value);
681 uint8* ptr = use_fast ? buffer_ : bytes;
682
683 WriteLittleEndian64ToArray(value, ptr);
684
685 if (use_fast) {
686 Advance(sizeof(value));
687 } else {
688 WriteRaw(bytes, sizeof(value));
689 }
690 }
691
WriteVarint32FallbackToArrayInline(uint32 value,uint8 * target)692 inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
693 uint32 value, uint8* target) {
694 target[0] = static_cast<uint8>(value | 0x80);
695 if (value >= (1 << 7)) {
696 target[1] = static_cast<uint8>((value >> 7) | 0x80);
697 if (value >= (1 << 14)) {
698 target[2] = static_cast<uint8>((value >> 14) | 0x80);
699 if (value >= (1 << 21)) {
700 target[3] = static_cast<uint8>((value >> 21) | 0x80);
701 if (value >= (1 << 28)) {
702 target[4] = static_cast<uint8>(value >> 28);
703 return target + 5;
704 } else {
705 target[3] &= 0x7F;
706 return target + 4;
707 }
708 } else {
709 target[2] &= 0x7F;
710 return target + 3;
711 }
712 } else {
713 target[1] &= 0x7F;
714 return target + 2;
715 }
716 } else {
717 target[0] &= 0x7F;
718 return target + 1;
719 }
720 }
721
WriteVarint32(uint32 value)722 void CodedOutputStream::WriteVarint32(uint32 value) {
723 if (buffer_size_ >= kMaxVarint32Bytes) {
724 // Fast path: We have enough bytes left in the buffer to guarantee that
725 // this write won't cross the end, so we can skip the checks.
726 uint8* target = buffer_;
727 uint8* end = WriteVarint32FallbackToArrayInline(value, target);
728 int size = end - target;
729 Advance(size);
730 } else {
731 // Slow path: This write might cross the end of the buffer, so we
732 // compose the bytes first then use WriteRaw().
733 uint8 bytes[kMaxVarint32Bytes];
734 int size = 0;
735 while (value > 0x7F) {
736 bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
737 value >>= 7;
738 }
739 bytes[size++] = static_cast<uint8>(value) & 0x7F;
740 WriteRaw(bytes, size);
741 }
742 }
743
WriteVarint32FallbackToArray(uint32 value,uint8 * target)744 uint8* CodedOutputStream::WriteVarint32FallbackToArray(
745 uint32 value, uint8* target) {
746 return WriteVarint32FallbackToArrayInline(value, target);
747 }
748
WriteVarint64ToArrayInline(uint64 value,uint8 * target)749 inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
750 uint64 value, uint8* target) {
751 // Splitting into 32-bit pieces gives better performance on 32-bit
752 // processors.
753 uint32 part0 = static_cast<uint32>(value );
754 uint32 part1 = static_cast<uint32>(value >> 28);
755 uint32 part2 = static_cast<uint32>(value >> 56);
756
757 int size;
758
759 // Here we can't really optimize for small numbers, since the value is
760 // split into three parts. Cheking for numbers < 128, for instance,
761 // would require three comparisons, since you'd have to make sure part1
762 // and part2 are zero. However, if the caller is using 64-bit integers,
763 // it is likely that they expect the numbers to often be very large, so
764 // we probably don't want to optimize for small numbers anyway. Thus,
765 // we end up with a hardcoded binary search tree...
766 if (part2 == 0) {
767 if (part1 == 0) {
768 if (part0 < (1 << 14)) {
769 if (part0 < (1 << 7)) {
770 size = 1; goto size1;
771 } else {
772 size = 2; goto size2;
773 }
774 } else {
775 if (part0 < (1 << 21)) {
776 size = 3; goto size3;
777 } else {
778 size = 4; goto size4;
779 }
780 }
781 } else {
782 if (part1 < (1 << 14)) {
783 if (part1 < (1 << 7)) {
784 size = 5; goto size5;
785 } else {
786 size = 6; goto size6;
787 }
788 } else {
789 if (part1 < (1 << 21)) {
790 size = 7; goto size7;
791 } else {
792 size = 8; goto size8;
793 }
794 }
795 }
796 } else {
797 if (part2 < (1 << 7)) {
798 size = 9; goto size9;
799 } else {
800 size = 10; goto size10;
801 }
802 }
803
804 GOOGLE_LOG(FATAL) << "Can't get here.";
805
806 size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
807 size9 : target[8] = static_cast<uint8>((part2 ) | 0x80);
808 size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
809 size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
810 size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
811 size5 : target[4] = static_cast<uint8>((part1 ) | 0x80);
812 size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
813 size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
814 size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
815 size1 : target[0] = static_cast<uint8>((part0 ) | 0x80);
816
817 target[size-1] &= 0x7F;
818 return target + size;
819 }
820
WriteVarint64(uint64 value)821 void CodedOutputStream::WriteVarint64(uint64 value) {
822 if (buffer_size_ >= kMaxVarintBytes) {
823 // Fast path: We have enough bytes left in the buffer to guarantee that
824 // this write won't cross the end, so we can skip the checks.
825 uint8* target = buffer_;
826
827 uint8* end = WriteVarint64ToArrayInline(value, target);
828 int size = end - target;
829 Advance(size);
830 } else {
831 // Slow path: This write might cross the end of the buffer, so we
832 // compose the bytes first then use WriteRaw().
833 uint8 bytes[kMaxVarintBytes];
834 int size = 0;
835 while (value > 0x7F) {
836 bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
837 value >>= 7;
838 }
839 bytes[size++] = static_cast<uint8>(value) & 0x7F;
840 WriteRaw(bytes, size);
841 }
842 }
843
WriteVarint64ToArray(uint64 value,uint8 * target)844 uint8* CodedOutputStream::WriteVarint64ToArray(
845 uint64 value, uint8* target) {
846 return WriteVarint64ToArrayInline(value, target);
847 }
848
Refresh()849 bool CodedOutputStream::Refresh() {
850 void* void_buffer;
851 if (output_->Next(&void_buffer, &buffer_size_)) {
852 buffer_ = reinterpret_cast<uint8*>(void_buffer);
853 total_bytes_ += buffer_size_;
854 return true;
855 } else {
856 buffer_ = NULL;
857 buffer_size_ = 0;
858 had_error_ = true;
859 return false;
860 }
861 }
862
VarintSize32Fallback(uint32 value)863 int CodedOutputStream::VarintSize32Fallback(uint32 value) {
864 if (value < (1 << 7)) {
865 return 1;
866 } else if (value < (1 << 14)) {
867 return 2;
868 } else if (value < (1 << 21)) {
869 return 3;
870 } else if (value < (1 << 28)) {
871 return 4;
872 } else {
873 return 5;
874 }
875 }
876
VarintSize64(uint64 value)877 int CodedOutputStream::VarintSize64(uint64 value) {
878 if (value < (1ull << 35)) {
879 if (value < (1ull << 7)) {
880 return 1;
881 } else if (value < (1ull << 14)) {
882 return 2;
883 } else if (value < (1ull << 21)) {
884 return 3;
885 } else if (value < (1ull << 28)) {
886 return 4;
887 } else {
888 return 5;
889 }
890 } else {
891 if (value < (1ull << 42)) {
892 return 6;
893 } else if (value < (1ull << 49)) {
894 return 7;
895 } else if (value < (1ull << 56)) {
896 return 8;
897 } else if (value < (1ull << 63)) {
898 return 9;
899 } else {
900 return 10;
901 }
902 }
903 }
904
WriteStringWithSizeToArray(const string & str,uint8 * target)905 uint8* CodedOutputStream::WriteStringWithSizeToArray(const string& str,
906 uint8* target) {
907 GOOGLE_DCHECK_LE(str.size(), kuint32max);
908 target = WriteVarint32ToArray(str.size(), target);
909 return WriteStringToArray(str, target);
910 }
911
912 } // namespace io
913 } // namespace protobuf
914 } // namespace google
915