/thirdparty/breakpad/third_party/protobuf/protobuf/src/google/protobuf/io/coded_stream.cc

http://github.com/tomahawk-player/tomahawk · C++ · 839 lines · 584 code · 115 blank · 140 comment · 164 complexity · d1b669963ae433a35dea887deab409e4 MD5 · raw file

  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // http://code.google.com/p/protobuf/
  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. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. //
  34. // This implementation is heavily optimized to make reads and writes
  35. // of small values (especially varints) as fast as possible. In
  36. // particular, we optimize for the common case that a read or a write
  37. // will not cross the end of the buffer, since we can avoid a lot
  38. // of branching in this case.
  39. #include <google/protobuf/io/coded_stream_inl.h>
  40. #include <algorithm>
  41. #include <limits.h>
  42. #include <google/protobuf/io/zero_copy_stream.h>
  43. #include <google/protobuf/stubs/common.h>
  44. #include <google/protobuf/stubs/stl_util-inl.h>
  45. namespace google {
  46. namespace protobuf {
  47. namespace io {
  48. namespace {
  49. static const int kMaxVarintBytes = 10;
  50. static const int kMaxVarint32Bytes = 5;
  51. inline bool NextNonEmpty(ZeroCopyInputStream* input,
  52. const void** data, int* size) {
  53. bool success;
  54. do {
  55. success = input->Next(data, size);
  56. } while (success && *size == 0);
  57. return success;
  58. }
  59. } // namespace
  60. // CodedInputStream ==================================================
  61. void CodedInputStream::BackUpInputToCurrentPosition() {
  62. int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
  63. if (backup_bytes > 0) {
  64. input_->BackUp(backup_bytes);
  65. // total_bytes_read_ doesn't include overflow_bytes_.
  66. total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
  67. buffer_end_ = buffer_;
  68. buffer_size_after_limit_ = 0;
  69. overflow_bytes_ = 0;
  70. }
  71. }
  72. inline void CodedInputStream::RecomputeBufferLimits() {
  73. buffer_end_ += buffer_size_after_limit_;
  74. int closest_limit = min(current_limit_, total_bytes_limit_);
  75. if (closest_limit < total_bytes_read_) {
  76. // The limit position is in the current buffer. We must adjust
  77. // the buffer size accordingly.
  78. buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
  79. buffer_end_ -= buffer_size_after_limit_;
  80. } else {
  81. buffer_size_after_limit_ = 0;
  82. }
  83. }
  84. CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
  85. // Current position relative to the beginning of the stream.
  86. int current_position = total_bytes_read_ -
  87. (BufferSize() + buffer_size_after_limit_);
  88. Limit old_limit = current_limit_;
  89. // security: byte_limit is possibly evil, so check for negative values
  90. // and overflow.
  91. if (byte_limit >= 0 &&
  92. byte_limit <= INT_MAX - current_position) {
  93. current_limit_ = current_position + byte_limit;
  94. } else {
  95. // Negative or overflow.
  96. current_limit_ = INT_MAX;
  97. }
  98. // We need to enforce all limits, not just the new one, so if the previous
  99. // limit was before the new requested limit, we continue to enforce the
  100. // previous limit.
  101. current_limit_ = min(current_limit_, old_limit);
  102. RecomputeBufferLimits();
  103. return old_limit;
  104. }
  105. void CodedInputStream::PopLimit(Limit limit) {
  106. // The limit passed in is actually the *old* limit, which we returned from
  107. // PushLimit().
  108. current_limit_ = limit;
  109. RecomputeBufferLimits();
  110. // We may no longer be at a legitimate message end. ReadTag() needs to be
  111. // called again to find out.
  112. legitimate_message_end_ = false;
  113. }
  114. int CodedInputStream::BytesUntilLimit() {
  115. if (current_limit_ == INT_MAX) return -1;
  116. int current_position = total_bytes_read_ -
  117. (BufferSize() + buffer_size_after_limit_);
  118. return current_limit_ - current_position;
  119. }
  120. void CodedInputStream::SetTotalBytesLimit(
  121. int total_bytes_limit, int warning_threshold) {
  122. // Make sure the limit isn't already past, since this could confuse other
  123. // code.
  124. int current_position = total_bytes_read_ -
  125. (BufferSize() + buffer_size_after_limit_);
  126. total_bytes_limit_ = max(current_position, total_bytes_limit);
  127. total_bytes_warning_threshold_ = warning_threshold;
  128. RecomputeBufferLimits();
  129. }
  130. void CodedInputStream::PrintTotalBytesLimitError() {
  131. GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
  132. "big (more than " << total_bytes_limit_
  133. << " bytes). To increase the limit (or to disable these "
  134. "warnings), see CodedInputStream::SetTotalBytesLimit() "
  135. "in google/protobuf/io/coded_stream.h.";
  136. }
  137. bool CodedInputStream::Skip(int count) {
  138. if (count < 0) return false; // security: count is often user-supplied
  139. const int original_buffer_size = BufferSize();
  140. if (count <= original_buffer_size) {
  141. // Just skipping within the current buffer. Easy.
  142. Advance(count);
  143. return true;
  144. }
  145. if (buffer_size_after_limit_ > 0) {
  146. // We hit a limit inside this buffer. Advance to the limit and fail.
  147. Advance(original_buffer_size);
  148. return false;
  149. }
  150. count -= original_buffer_size;
  151. buffer_ = NULL;
  152. buffer_end_ = buffer_;
  153. // Make sure this skip doesn't try to skip past the current limit.
  154. int closest_limit = min(current_limit_, total_bytes_limit_);
  155. int bytes_until_limit = closest_limit - total_bytes_read_;
  156. if (bytes_until_limit < count) {
  157. // We hit the limit. Skip up to it then fail.
  158. if (bytes_until_limit > 0) {
  159. total_bytes_read_ = closest_limit;
  160. input_->Skip(bytes_until_limit);
  161. }
  162. return false;
  163. }
  164. total_bytes_read_ += count;
  165. return input_->Skip(count);
  166. }
  167. bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
  168. if (BufferSize() == 0 && !Refresh()) return false;
  169. *data = buffer_;
  170. *size = BufferSize();
  171. return true;
  172. }
  173. bool CodedInputStream::ReadRaw(void* buffer, int size) {
  174. int current_buffer_size;
  175. while ((current_buffer_size = BufferSize()) < size) {
  176. // Reading past end of buffer. Copy what we have, then refresh.
  177. memcpy(buffer, buffer_, current_buffer_size);
  178. buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
  179. size -= current_buffer_size;
  180. Advance(current_buffer_size);
  181. if (!Refresh()) return false;
  182. }
  183. memcpy(buffer, buffer_, size);
  184. Advance(size);
  185. return true;
  186. }
  187. bool CodedInputStream::ReadString(string* buffer, int size) {
  188. if (size < 0) return false; // security: size is often user-supplied
  189. return InternalReadStringInline(buffer, size);
  190. }
  191. bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
  192. if (!buffer->empty()) {
  193. buffer->clear();
  194. }
  195. int current_buffer_size;
  196. while ((current_buffer_size = BufferSize()) < size) {
  197. // Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
  198. if (current_buffer_size != 0) {
  199. // Note: string1.append(string2) is O(string2.size()) (as opposed to
  200. // O(string1.size() + string2.size()), which would be bad).
  201. buffer->append(reinterpret_cast<const char*>(buffer_),
  202. current_buffer_size);
  203. }
  204. size -= current_buffer_size;
  205. Advance(current_buffer_size);
  206. if (!Refresh()) return false;
  207. }
  208. buffer->append(reinterpret_cast<const char*>(buffer_), size);
  209. Advance(size);
  210. return true;
  211. }
  212. bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
  213. uint8 bytes[sizeof(*value)];
  214. const uint8* ptr;
  215. if (BufferSize() >= sizeof(*value)) {
  216. // Fast path: Enough bytes in the buffer to read directly.
  217. ptr = buffer_;
  218. Advance(sizeof(*value));
  219. } else {
  220. // Slow path: Had to read past the end of the buffer.
  221. if (!ReadRaw(bytes, sizeof(*value))) return false;
  222. ptr = bytes;
  223. }
  224. ReadLittleEndian32FromArray(ptr, value);
  225. return true;
  226. }
  227. bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
  228. uint8 bytes[sizeof(*value)];
  229. const uint8* ptr;
  230. if (BufferSize() >= sizeof(*value)) {
  231. // Fast path: Enough bytes in the buffer to read directly.
  232. ptr = buffer_;
  233. Advance(sizeof(*value));
  234. } else {
  235. // Slow path: Had to read past the end of the buffer.
  236. if (!ReadRaw(bytes, sizeof(*value))) return false;
  237. ptr = bytes;
  238. }
  239. ReadLittleEndian64FromArray(ptr, value);
  240. return true;
  241. }
  242. namespace {
  243. inline const uint8* ReadVarint32FromArray(
  244. const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
  245. inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
  246. // Fast path: We have enough bytes left in the buffer to guarantee that
  247. // this read won't cross the end, so we can skip the checks.
  248. const uint8* ptr = buffer;
  249. uint32 b;
  250. uint32 result;
  251. b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done;
  252. b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
  253. b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
  254. b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
  255. b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done;
  256. // If the input is larger than 32 bits, we still need to read it all
  257. // and discard the high-order bits.
  258. for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
  259. b = *(ptr++); if (!(b & 0x80)) goto done;
  260. }
  261. // We have overrun the maximum size of a varint (10 bytes). Assume
  262. // the data is corrupt.
  263. return NULL;
  264. done:
  265. *value = result;
  266. return ptr;
  267. }
  268. } // namespace
  269. bool CodedInputStream::ReadVarint32Slow(uint32* value) {
  270. uint64 result;
  271. // Directly invoke ReadVarint64Fallback, since we already tried to optimize
  272. // for one-byte varints.
  273. if (!ReadVarint64Fallback(&result)) return false;
  274. *value = (uint32)result;
  275. return true;
  276. }
  277. bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
  278. if (BufferSize() >= kMaxVarintBytes ||
  279. // Optimization: If the varint ends at exactly the end of the buffer,
  280. // we can detect that and still use the fast path.
  281. (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
  282. const uint8* end = ReadVarint32FromArray(buffer_, value);
  283. if (end == NULL) return false;
  284. buffer_ = end;
  285. return true;
  286. } else {
  287. // Really slow case: we will incur the cost of an extra function call here,
  288. // but moving this out of line reduces the size of this function, which
  289. // improves the common case. In micro benchmarks, this is worth about 10-15%
  290. return ReadVarint32Slow(value);
  291. }
  292. }
  293. uint32 CodedInputStream::ReadTagSlow() {
  294. if (buffer_ == buffer_end_) {
  295. // Call refresh.
  296. if (!Refresh()) {
  297. // Refresh failed. Make sure that it failed due to EOF, not because
  298. // we hit total_bytes_limit_, which, unlike normal limits, is not a
  299. // valid place to end a message.
  300. int current_position = total_bytes_read_ - buffer_size_after_limit_;
  301. if (current_position >= total_bytes_limit_) {
  302. // Hit total_bytes_limit_. But if we also hit the normal limit,
  303. // we're still OK.
  304. legitimate_message_end_ = current_limit_ == total_bytes_limit_;
  305. } else {
  306. legitimate_message_end_ = true;
  307. }
  308. return 0;
  309. }
  310. }
  311. // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
  312. // again, since we have now refreshed the buffer.
  313. uint64 result;
  314. if (!ReadVarint64(&result)) return 0;
  315. return static_cast<uint32>(result);
  316. }
  317. uint32 CodedInputStream::ReadTagFallback() {
  318. if (BufferSize() >= kMaxVarintBytes ||
  319. // Optimization: If the varint ends at exactly the end of the buffer,
  320. // we can detect that and still use the fast path.
  321. (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
  322. uint32 tag;
  323. const uint8* end = ReadVarint32FromArray(buffer_, &tag);
  324. if (end == NULL) {
  325. return 0;
  326. }
  327. buffer_ = end;
  328. return tag;
  329. } else {
  330. // We are commonly at a limit when attempting to read tags. Try to quickly
  331. // detect this case without making another function call.
  332. if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 &&
  333. // Make sure that the limit we hit is not total_bytes_limit_, since
  334. // in that case we still need to call Refresh() so that it prints an
  335. // error.
  336. total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
  337. // We hit a byte limit.
  338. legitimate_message_end_ = true;
  339. return 0;
  340. }
  341. return ReadTagSlow();
  342. }
  343. }
  344. bool CodedInputStream::ReadVarint64Slow(uint64* value) {
  345. // Slow path: This read might cross the end of the buffer, so we
  346. // need to check and refresh the buffer if and when it does.
  347. uint64 result = 0;
  348. int count = 0;
  349. uint32 b;
  350. do {
  351. if (count == kMaxVarintBytes) return false;
  352. while (buffer_ == buffer_end_) {
  353. if (!Refresh()) return false;
  354. }
  355. b = *buffer_;
  356. result |= static_cast<uint64>(b & 0x7F) << (7 * count);
  357. Advance(1);
  358. ++count;
  359. } while (b & 0x80);
  360. *value = result;
  361. return true;
  362. }
  363. bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
  364. if (BufferSize() >= kMaxVarintBytes ||
  365. // Optimization: If the varint ends at exactly the end of the buffer,
  366. // we can detect that and still use the fast path.
  367. (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
  368. // Fast path: We have enough bytes left in the buffer to guarantee that
  369. // this read won't cross the end, so we can skip the checks.
  370. const uint8* ptr = buffer_;
  371. uint32 b;
  372. // Splitting into 32-bit pieces gives better performance on 32-bit
  373. // processors.
  374. uint32 part0 = 0, part1 = 0, part2 = 0;
  375. b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
  376. b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
  377. b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
  378. b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
  379. b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
  380. b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
  381. b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
  382. b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
  383. b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
  384. b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
  385. // We have overrun the maximum size of a varint (10 bytes). The data
  386. // must be corrupt.
  387. return NULL;
  388. done:
  389. Advance(ptr - buffer_);
  390. *value = (static_cast<uint64>(part0) ) |
  391. (static_cast<uint64>(part1) << 28) |
  392. (static_cast<uint64>(part2) << 56);
  393. return true;
  394. } else {
  395. return ReadVarint64Slow(value);
  396. }
  397. }
  398. bool CodedInputStream::Refresh() {
  399. GOOGLE_DCHECK_EQ(0, BufferSize());
  400. if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
  401. total_bytes_read_ == current_limit_) {
  402. // We've hit a limit. Stop.
  403. int current_position = total_bytes_read_ - buffer_size_after_limit_;
  404. if (current_position >= total_bytes_limit_ &&
  405. total_bytes_limit_ != current_limit_) {
  406. // Hit total_bytes_limit_.
  407. PrintTotalBytesLimitError();
  408. }
  409. return false;
  410. }
  411. if (total_bytes_warning_threshold_ >= 0 &&
  412. total_bytes_read_ >= total_bytes_warning_threshold_) {
  413. GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the "
  414. "message turns out to be larger than "
  415. << total_bytes_limit_ << " bytes, parsing will be halted "
  416. "for security reasons. To increase the limit (or to "
  417. "disable these warnings), see "
  418. "CodedInputStream::SetTotalBytesLimit() in "
  419. "google/protobuf/io/coded_stream.h.";
  420. // Don't warn again for this stream.
  421. total_bytes_warning_threshold_ = -1;
  422. }
  423. const void* void_buffer;
  424. int buffer_size;
  425. if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
  426. buffer_ = reinterpret_cast<const uint8*>(void_buffer);
  427. buffer_end_ = buffer_ + buffer_size;
  428. GOOGLE_CHECK_GE(buffer_size, 0);
  429. if (total_bytes_read_ <= INT_MAX - buffer_size) {
  430. total_bytes_read_ += buffer_size;
  431. } else {
  432. // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
  433. // We can't get that far anyway, because total_bytes_limit_ is guaranteed
  434. // to be less than it. We need to keep track of the number of bytes
  435. // we discarded, though, so that we can call input_->BackUp() to back
  436. // up over them on destruction.
  437. // The following line is equivalent to:
  438. // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
  439. // except that it avoids overflows. Signed integer overflow has
  440. // undefined results according to the C standard.
  441. overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
  442. buffer_end_ -= overflow_bytes_;
  443. total_bytes_read_ = INT_MAX;
  444. }
  445. RecomputeBufferLimits();
  446. return true;
  447. } else {
  448. buffer_ = NULL;
  449. buffer_end_ = NULL;
  450. return false;
  451. }
  452. }
  453. // CodedOutputStream =================================================
  454. CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
  455. : output_(output),
  456. buffer_(NULL),
  457. buffer_size_(0),
  458. total_bytes_(0),
  459. had_error_(false) {
  460. // Eagerly Refresh() so buffer space is immediately available.
  461. Refresh();
  462. // The Refresh() may have failed. If the client doesn't write any data,
  463. // though, don't consider this an error. If the client does write data, then
  464. // another Refresh() will be attempted and it will set the error once again.
  465. had_error_ = false;
  466. }
  467. CodedOutputStream::~CodedOutputStream() {
  468. if (buffer_size_ > 0) {
  469. output_->BackUp(buffer_size_);
  470. }
  471. }
  472. bool CodedOutputStream::Skip(int count) {
  473. if (count < 0) return false;
  474. while (count > buffer_size_) {
  475. count -= buffer_size_;
  476. if (!Refresh()) return false;
  477. }
  478. Advance(count);
  479. return true;
  480. }
  481. bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
  482. if (buffer_size_ == 0 && !Refresh()) return false;
  483. *data = buffer_;
  484. *size = buffer_size_;
  485. return true;
  486. }
  487. void CodedOutputStream::WriteRaw(const void* data, int size) {
  488. while (buffer_size_ < size) {
  489. memcpy(buffer_, data, buffer_size_);
  490. size -= buffer_size_;
  491. data = reinterpret_cast<const uint8*>(data) + buffer_size_;
  492. if (!Refresh()) return;
  493. }
  494. memcpy(buffer_, data, size);
  495. Advance(size);
  496. }
  497. uint8* CodedOutputStream::WriteRawToArray(
  498. const void* data, int size, uint8* target) {
  499. memcpy(target, data, size);
  500. return target + size;
  501. }
  502. void CodedOutputStream::WriteLittleEndian32(uint32 value) {
  503. uint8 bytes[sizeof(value)];
  504. bool use_fast = buffer_size_ >= sizeof(value);
  505. uint8* ptr = use_fast ? buffer_ : bytes;
  506. WriteLittleEndian32ToArray(value, ptr);
  507. if (use_fast) {
  508. Advance(sizeof(value));
  509. } else {
  510. WriteRaw(bytes, sizeof(value));
  511. }
  512. }
  513. void CodedOutputStream::WriteLittleEndian64(uint64 value) {
  514. uint8 bytes[sizeof(value)];
  515. bool use_fast = buffer_size_ >= sizeof(value);
  516. uint8* ptr = use_fast ? buffer_ : bytes;
  517. WriteLittleEndian64ToArray(value, ptr);
  518. if (use_fast) {
  519. Advance(sizeof(value));
  520. } else {
  521. WriteRaw(bytes, sizeof(value));
  522. }
  523. }
  524. inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
  525. uint32 value, uint8* target) {
  526. target[0] = static_cast<uint8>(value | 0x80);
  527. if (value >= (1 << 7)) {
  528. target[1] = static_cast<uint8>((value >> 7) | 0x80);
  529. if (value >= (1 << 14)) {
  530. target[2] = static_cast<uint8>((value >> 14) | 0x80);
  531. if (value >= (1 << 21)) {
  532. target[3] = static_cast<uint8>((value >> 21) | 0x80);
  533. if (value >= (1 << 28)) {
  534. target[4] = static_cast<uint8>(value >> 28);
  535. return target + 5;
  536. } else {
  537. target[3] &= 0x7F;
  538. return target + 4;
  539. }
  540. } else {
  541. target[2] &= 0x7F;
  542. return target + 3;
  543. }
  544. } else {
  545. target[1] &= 0x7F;
  546. return target + 2;
  547. }
  548. } else {
  549. target[0] &= 0x7F;
  550. return target + 1;
  551. }
  552. }
  553. void CodedOutputStream::WriteVarint32(uint32 value) {
  554. if (buffer_size_ >= kMaxVarint32Bytes) {
  555. // Fast path: We have enough bytes left in the buffer to guarantee that
  556. // this write won't cross the end, so we can skip the checks.
  557. uint8* target = buffer_;
  558. uint8* end = WriteVarint32FallbackToArrayInline(value, target);
  559. int size = end - target;
  560. Advance(size);
  561. } else {
  562. // Slow path: This write might cross the end of the buffer, so we
  563. // compose the bytes first then use WriteRaw().
  564. uint8 bytes[kMaxVarint32Bytes];
  565. int size = 0;
  566. while (value > 0x7F) {
  567. bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
  568. value >>= 7;
  569. }
  570. bytes[size++] = static_cast<uint8>(value) & 0x7F;
  571. WriteRaw(bytes, size);
  572. }
  573. }
  574. uint8* CodedOutputStream::WriteVarint32FallbackToArray(
  575. uint32 value, uint8* target) {
  576. return WriteVarint32FallbackToArrayInline(value, target);
  577. }
  578. inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
  579. uint64 value, uint8* target) {
  580. // Splitting into 32-bit pieces gives better performance on 32-bit
  581. // processors.
  582. uint32 part0 = static_cast<uint32>(value );
  583. uint32 part1 = static_cast<uint32>(value >> 28);
  584. uint32 part2 = static_cast<uint32>(value >> 56);
  585. int size;
  586. // Here we can't really optimize for small numbers, since the value is
  587. // split into three parts. Cheking for numbers < 128, for instance,
  588. // would require three comparisons, since you'd have to make sure part1
  589. // and part2 are zero. However, if the caller is using 64-bit integers,
  590. // it is likely that they expect the numbers to often be very large, so
  591. // we probably don't want to optimize for small numbers anyway. Thus,
  592. // we end up with a hardcoded binary search tree...
  593. if (part2 == 0) {
  594. if (part1 == 0) {
  595. if (part0 < (1 << 14)) {
  596. if (part0 < (1 << 7)) {
  597. size = 1; goto size1;
  598. } else {
  599. size = 2; goto size2;
  600. }
  601. } else {
  602. if (part0 < (1 << 21)) {
  603. size = 3; goto size3;
  604. } else {
  605. size = 4; goto size4;
  606. }
  607. }
  608. } else {
  609. if (part1 < (1 << 14)) {
  610. if (part1 < (1 << 7)) {
  611. size = 5; goto size5;
  612. } else {
  613. size = 6; goto size6;
  614. }
  615. } else {
  616. if (part1 < (1 << 21)) {
  617. size = 7; goto size7;
  618. } else {
  619. size = 8; goto size8;
  620. }
  621. }
  622. }
  623. } else {
  624. if (part2 < (1 << 7)) {
  625. size = 9; goto size9;
  626. } else {
  627. size = 10; goto size10;
  628. }
  629. }
  630. GOOGLE_LOG(FATAL) << "Can't get here.";
  631. size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
  632. size9 : target[8] = static_cast<uint8>((part2 ) | 0x80);
  633. size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
  634. size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
  635. size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
  636. size5 : target[4] = static_cast<uint8>((part1 ) | 0x80);
  637. size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
  638. size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
  639. size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
  640. size1 : target[0] = static_cast<uint8>((part0 ) | 0x80);
  641. target[size-1] &= 0x7F;
  642. return target + size;
  643. }
  644. void CodedOutputStream::WriteVarint64(uint64 value) {
  645. if (buffer_size_ >= kMaxVarintBytes) {
  646. // Fast path: We have enough bytes left in the buffer to guarantee that
  647. // this write won't cross the end, so we can skip the checks.
  648. uint8* target = buffer_;
  649. uint8* end = WriteVarint64ToArrayInline(value, target);
  650. int size = end - target;
  651. Advance(size);
  652. } else {
  653. // Slow path: This write might cross the end of the buffer, so we
  654. // compose the bytes first then use WriteRaw().
  655. uint8 bytes[kMaxVarintBytes];
  656. int size = 0;
  657. while (value > 0x7F) {
  658. bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
  659. value >>= 7;
  660. }
  661. bytes[size++] = static_cast<uint8>(value) & 0x7F;
  662. WriteRaw(bytes, size);
  663. }
  664. }
  665. uint8* CodedOutputStream::WriteVarint64ToArray(
  666. uint64 value, uint8* target) {
  667. return WriteVarint64ToArrayInline(value, target);
  668. }
  669. bool CodedOutputStream::Refresh() {
  670. void* void_buffer;
  671. if (output_->Next(&void_buffer, &buffer_size_)) {
  672. buffer_ = reinterpret_cast<uint8*>(void_buffer);
  673. total_bytes_ += buffer_size_;
  674. return true;
  675. } else {
  676. buffer_ = NULL;
  677. buffer_size_ = 0;
  678. had_error_ = true;
  679. return false;
  680. }
  681. }
  682. int CodedOutputStream::VarintSize32Fallback(uint32 value) {
  683. if (value < (1 << 7)) {
  684. return 1;
  685. } else if (value < (1 << 14)) {
  686. return 2;
  687. } else if (value < (1 << 21)) {
  688. return 3;
  689. } else if (value < (1 << 28)) {
  690. return 4;
  691. } else {
  692. return 5;
  693. }
  694. }
  695. int CodedOutputStream::VarintSize64(uint64 value) {
  696. if (value < (1ull << 35)) {
  697. if (value < (1ull << 7)) {
  698. return 1;
  699. } else if (value < (1ull << 14)) {
  700. return 2;
  701. } else if (value < (1ull << 21)) {
  702. return 3;
  703. } else if (value < (1ull << 28)) {
  704. return 4;
  705. } else {
  706. return 5;
  707. }
  708. } else {
  709. if (value < (1ull << 42)) {
  710. return 6;
  711. } else if (value < (1ull << 49)) {
  712. return 7;
  713. } else if (value < (1ull << 56)) {
  714. return 8;
  715. } else if (value < (1ull << 63)) {
  716. return 9;
  717. } else {
  718. return 10;
  719. }
  720. }
  721. }
  722. } // namespace io
  723. } // namespace protobuf
  724. } // namespace google