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