/src/sentencepiece/third_party/protobuf-lite/coded_stream.cc
Line | Count | Source (jump to first uncovered line) |
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.h> |
42 | | |
43 | | #include <limits.h> |
44 | | |
45 | | #include <algorithm> |
46 | | #include <cstring> |
47 | | #include <utility> |
48 | | |
49 | | #include <google/protobuf/stubs/logging.h> |
50 | | #include <google/protobuf/stubs/common.h> |
51 | | #include <google/protobuf/arena.h> |
52 | | #include <google/protobuf/io/zero_copy_stream.h> |
53 | | #include <google/protobuf/io/zero_copy_stream_impl_lite.h> |
54 | | #include <google/protobuf/stubs/stl_util.h> |
55 | | |
56 | | |
57 | | #include <google/protobuf/port_def.inc> |
58 | | |
59 | | namespace google { |
60 | | namespace protobuf { |
61 | | namespace io { |
62 | | |
63 | | namespace { |
64 | | |
65 | | static const int kMaxVarintBytes = 10; |
66 | | static const int kMaxVarint32Bytes = 5; |
67 | | |
68 | | |
69 | | inline bool NextNonEmpty(ZeroCopyInputStream* input, const void** data, |
70 | 0 | int* size) { |
71 | 0 | bool success; |
72 | 0 | do { |
73 | 0 | success = input->Next(data, size); |
74 | 0 | } while (success && *size == 0); |
75 | 0 | return success; |
76 | 0 | } |
77 | | |
78 | | } // namespace |
79 | | |
80 | | // CodedInputStream ================================================== |
81 | | |
82 | 0 | CodedInputStream::~CodedInputStream() { |
83 | 0 | if (input_ != NULL) { |
84 | 0 | BackUpInputToCurrentPosition(); |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | | // Static. |
89 | | int CodedInputStream::default_recursion_limit_ = 100; |
90 | | |
91 | | |
92 | 0 | void CodedInputStream::BackUpInputToCurrentPosition() { |
93 | 0 | int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_; |
94 | 0 | if (backup_bytes > 0) { |
95 | 0 | input_->BackUp(backup_bytes); |
96 | | |
97 | | // total_bytes_read_ doesn't include overflow_bytes_. |
98 | 0 | total_bytes_read_ -= BufferSize() + buffer_size_after_limit_; |
99 | 0 | buffer_end_ = buffer_; |
100 | 0 | buffer_size_after_limit_ = 0; |
101 | 0 | overflow_bytes_ = 0; |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | 0 | inline void CodedInputStream::RecomputeBufferLimits() { |
106 | 0 | buffer_end_ += buffer_size_after_limit_; |
107 | 0 | int closest_limit = std::min(current_limit_, total_bytes_limit_); |
108 | 0 | if (closest_limit < total_bytes_read_) { |
109 | | // The limit position is in the current buffer. We must adjust |
110 | | // the buffer size accordingly. |
111 | 0 | buffer_size_after_limit_ = total_bytes_read_ - closest_limit; |
112 | 0 | buffer_end_ -= buffer_size_after_limit_; |
113 | 0 | } else { |
114 | 0 | buffer_size_after_limit_ = 0; |
115 | 0 | } |
116 | 0 | } |
117 | | |
118 | 0 | CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { |
119 | | // Current position relative to the beginning of the stream. |
120 | 0 | int current_position = CurrentPosition(); |
121 | |
|
122 | 0 | Limit old_limit = current_limit_; |
123 | | |
124 | | // security: byte_limit is possibly evil, so check for negative values |
125 | | // and overflow. Also check that the new requested limit is before the |
126 | | // previous limit; otherwise we continue to enforce the previous limit. |
127 | 0 | if (PROTOBUF_PREDICT_TRUE(byte_limit >= 0 && |
128 | 0 | byte_limit <= INT_MAX - current_position && |
129 | 0 | byte_limit < current_limit_ - current_position)) { |
130 | 0 | current_limit_ = current_position + byte_limit; |
131 | 0 | RecomputeBufferLimits(); |
132 | 0 | } |
133 | |
|
134 | 0 | return old_limit; |
135 | 0 | } |
136 | | |
137 | 0 | void CodedInputStream::PopLimit(Limit limit) { |
138 | | // The limit passed in is actually the *old* limit, which we returned from |
139 | | // PushLimit(). |
140 | 0 | current_limit_ = limit; |
141 | 0 | RecomputeBufferLimits(); |
142 | | |
143 | | // We may no longer be at a legitimate message end. ReadTag() needs to be |
144 | | // called again to find out. |
145 | 0 | legitimate_message_end_ = false; |
146 | 0 | } |
147 | | |
148 | | std::pair<CodedInputStream::Limit, int> |
149 | 0 | CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) { |
150 | 0 | return std::make_pair(PushLimit(byte_limit), --recursion_budget_); |
151 | 0 | } |
152 | | |
153 | 0 | CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() { |
154 | 0 | uint32 length; |
155 | 0 | return PushLimit(ReadVarint32(&length) ? length : 0); |
156 | 0 | } |
157 | | |
158 | 0 | bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) { |
159 | 0 | bool result = ConsumedEntireMessage(); |
160 | 0 | PopLimit(limit); |
161 | 0 | GOOGLE_DCHECK_LT(recursion_budget_, recursion_limit_); |
162 | 0 | ++recursion_budget_; |
163 | 0 | return result; |
164 | 0 | } |
165 | | |
166 | 0 | bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) { |
167 | 0 | bool result = ConsumedEntireMessage(); |
168 | 0 | PopLimit(limit); |
169 | 0 | return result; |
170 | 0 | } |
171 | | |
172 | 0 | int CodedInputStream::BytesUntilLimit() const { |
173 | 0 | if (current_limit_ == INT_MAX) return -1; |
174 | 0 | int current_position = CurrentPosition(); |
175 | |
|
176 | 0 | return current_limit_ - current_position; |
177 | 0 | } |
178 | | |
179 | 0 | void CodedInputStream::SetTotalBytesLimit(int total_bytes_limit) { |
180 | | // Make sure the limit isn't already past, since this could confuse other |
181 | | // code. |
182 | 0 | int current_position = CurrentPosition(); |
183 | 0 | total_bytes_limit_ = std::max(current_position, total_bytes_limit); |
184 | 0 | RecomputeBufferLimits(); |
185 | 0 | } |
186 | | |
187 | 0 | int CodedInputStream::BytesUntilTotalBytesLimit() const { |
188 | 0 | if (total_bytes_limit_ == INT_MAX) return -1; |
189 | 0 | return total_bytes_limit_ - CurrentPosition(); |
190 | 0 | } |
191 | | |
192 | 0 | void CodedInputStream::PrintTotalBytesLimitError() { |
193 | 0 | GOOGLE_LOG(ERROR) |
194 | 0 | << "A protocol message was rejected because it was too " |
195 | 0 | "big (more than " |
196 | 0 | << total_bytes_limit_ |
197 | 0 | << " bytes). To increase the limit (or to disable these " |
198 | 0 | "warnings), see CodedInputStream::SetTotalBytesLimit() " |
199 | 0 | "in third_party/protobuf/src/google/protobuf/io/coded_stream.h."; |
200 | 0 | } |
201 | | |
202 | 0 | bool CodedInputStream::SkipFallback(int count, int original_buffer_size) { |
203 | 0 | if (buffer_size_after_limit_ > 0) { |
204 | | // We hit a limit inside this buffer. Advance to the limit and fail. |
205 | 0 | Advance(original_buffer_size); |
206 | 0 | return false; |
207 | 0 | } |
208 | | |
209 | 0 | count -= original_buffer_size; |
210 | 0 | buffer_ = NULL; |
211 | 0 | buffer_end_ = buffer_; |
212 | | |
213 | | // Make sure this skip doesn't try to skip past the current limit. |
214 | 0 | int closest_limit = std::min(current_limit_, total_bytes_limit_); |
215 | 0 | int bytes_until_limit = closest_limit - total_bytes_read_; |
216 | 0 | if (bytes_until_limit < count) { |
217 | | // We hit the limit. Skip up to it then fail. |
218 | 0 | if (bytes_until_limit > 0) { |
219 | 0 | total_bytes_read_ = closest_limit; |
220 | 0 | input_->Skip(bytes_until_limit); |
221 | 0 | } |
222 | 0 | return false; |
223 | 0 | } |
224 | | |
225 | 0 | if (!input_->Skip(count)) { |
226 | 0 | total_bytes_read_ = input_->ByteCount(); |
227 | 0 | return false; |
228 | 0 | } |
229 | 0 | total_bytes_read_ += count; |
230 | 0 | return true; |
231 | 0 | } |
232 | | |
233 | 0 | bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) { |
234 | 0 | if (BufferSize() == 0 && !Refresh()) return false; |
235 | | |
236 | 0 | *data = buffer_; |
237 | 0 | *size = BufferSize(); |
238 | 0 | return true; |
239 | 0 | } |
240 | | |
241 | 0 | bool CodedInputStream::ReadRaw(void* buffer, int size) { |
242 | 0 | int current_buffer_size; |
243 | 0 | while ((current_buffer_size = BufferSize()) < size) { |
244 | | // Reading past end of buffer. Copy what we have, then refresh. |
245 | 0 | memcpy(buffer, buffer_, current_buffer_size); |
246 | 0 | buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size; |
247 | 0 | size -= current_buffer_size; |
248 | 0 | Advance(current_buffer_size); |
249 | 0 | if (!Refresh()) return false; |
250 | 0 | } |
251 | | |
252 | 0 | memcpy(buffer, buffer_, size); |
253 | 0 | Advance(size); |
254 | |
|
255 | 0 | return true; |
256 | 0 | } |
257 | | |
258 | 0 | bool CodedInputStream::ReadString(std::string* buffer, int size) { |
259 | 0 | if (size < 0) return false; // security: size is often user-supplied |
260 | | |
261 | 0 | if (BufferSize() >= size) { |
262 | 0 | STLStringResizeUninitialized(buffer, size); |
263 | 0 | std::pair<char*, bool> z = as_string_data(buffer); |
264 | 0 | if (z.second) { |
265 | | // Oddly enough, memcpy() requires its first two args to be non-NULL even |
266 | | // if we copy 0 bytes. So, we have ensured that z.first is non-NULL here. |
267 | 0 | GOOGLE_DCHECK(z.first != NULL); |
268 | 0 | memcpy(z.first, buffer_, size); |
269 | 0 | Advance(size); |
270 | 0 | } |
271 | 0 | return true; |
272 | 0 | } |
273 | | |
274 | 0 | return ReadStringFallback(buffer, size); |
275 | 0 | } |
276 | | |
277 | 0 | bool CodedInputStream::ReadStringFallback(std::string* buffer, int size) { |
278 | 0 | if (!buffer->empty()) { |
279 | 0 | buffer->clear(); |
280 | 0 | } |
281 | |
|
282 | 0 | int closest_limit = std::min(current_limit_, total_bytes_limit_); |
283 | 0 | if (closest_limit != INT_MAX) { |
284 | 0 | int bytes_to_limit = closest_limit - CurrentPosition(); |
285 | 0 | if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) { |
286 | 0 | buffer->reserve(size); |
287 | 0 | } |
288 | 0 | } |
289 | |
|
290 | 0 | int current_buffer_size; |
291 | 0 | while ((current_buffer_size = BufferSize()) < size) { |
292 | | // Some STL implementations "helpfully" crash on buffer->append(NULL, 0). |
293 | 0 | if (current_buffer_size != 0) { |
294 | | // Note: string1.append(string2) is O(string2.size()) (as opposed to |
295 | | // O(string1.size() + string2.size()), which would be bad). |
296 | 0 | buffer->append(reinterpret_cast<const char*>(buffer_), |
297 | 0 | current_buffer_size); |
298 | 0 | } |
299 | 0 | size -= current_buffer_size; |
300 | 0 | Advance(current_buffer_size); |
301 | 0 | if (!Refresh()) return false; |
302 | 0 | } |
303 | | |
304 | 0 | buffer->append(reinterpret_cast<const char*>(buffer_), size); |
305 | 0 | Advance(size); |
306 | |
|
307 | 0 | return true; |
308 | 0 | } |
309 | | |
310 | | |
311 | 0 | bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) { |
312 | 0 | uint8 bytes[sizeof(*value)]; |
313 | |
|
314 | 0 | const uint8* ptr; |
315 | 0 | if (BufferSize() >= sizeof(*value)) { |
316 | | // Fast path: Enough bytes in the buffer to read directly. |
317 | 0 | ptr = buffer_; |
318 | 0 | Advance(sizeof(*value)); |
319 | 0 | } else { |
320 | | // Slow path: Had to read past the end of the buffer. |
321 | 0 | if (!ReadRaw(bytes, sizeof(*value))) return false; |
322 | 0 | ptr = bytes; |
323 | 0 | } |
324 | 0 | ReadLittleEndian32FromArray(ptr, value); |
325 | 0 | return true; |
326 | 0 | } |
327 | | |
328 | 0 | bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) { |
329 | 0 | uint8 bytes[sizeof(*value)]; |
330 | |
|
331 | 0 | const uint8* ptr; |
332 | 0 | if (BufferSize() >= sizeof(*value)) { |
333 | | // Fast path: Enough bytes in the buffer to read directly. |
334 | 0 | ptr = buffer_; |
335 | 0 | Advance(sizeof(*value)); |
336 | 0 | } else { |
337 | | // Slow path: Had to read past the end of the buffer. |
338 | 0 | if (!ReadRaw(bytes, sizeof(*value))) return false; |
339 | 0 | ptr = bytes; |
340 | 0 | } |
341 | 0 | ReadLittleEndian64FromArray(ptr, value); |
342 | 0 | return true; |
343 | 0 | } |
344 | | |
345 | | namespace { |
346 | | |
347 | | // Decodes varint64 with known size, N, and returns next pointer. Knowing N at |
348 | | // compile time, compiler can generate optimal code. For example, instead of |
349 | | // subtracting 0x80 at each iteration, it subtracts properly shifted mask once. |
350 | | template <size_t N> |
351 | 0 | const uint8* DecodeVarint64KnownSize(const uint8* buffer, uint64* value) { |
352 | 0 | GOOGLE_DCHECK_GT(N, 0); |
353 | 0 | uint64 result = static_cast<uint64>(buffer[N - 1]) << (7 * (N - 1)); |
354 | 0 | for (int i = 0, offset = 0; i < N - 1; i++, offset += 7) { |
355 | 0 | result += static_cast<uint64>(buffer[i] - 0x80) << offset; |
356 | 0 | } |
357 | 0 | *value = result; |
358 | 0 | return buffer + N; |
359 | 0 | } Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<2ul>(unsigned char const*, unsigned long*) Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<3ul>(unsigned char const*, unsigned long*) Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<4ul>(unsigned char const*, unsigned long*) Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<5ul>(unsigned char const*, unsigned long*) Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<6ul>(unsigned char const*, unsigned long*) Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<7ul>(unsigned char const*, unsigned long*) Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<8ul>(unsigned char const*, unsigned long*) Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<9ul>(unsigned char const*, unsigned long*) Unexecuted instantiation: coded_stream.cc:unsigned char const* google::protobuf::io::(anonymous namespace)::DecodeVarint64KnownSize<10ul>(unsigned char const*, unsigned long*) |
360 | | |
361 | | // Read a varint from the given buffer, write it to *value, and return a pair. |
362 | | // The first part of the pair is true iff the read was successful. The second |
363 | | // part is buffer + (number of bytes read). This function is always inlined, |
364 | | // so returning a pair is costless. |
365 | | PROTOBUF_ALWAYS_INLINE |
366 | | ::std::pair<bool, const uint8*> ReadVarint32FromArray(uint32 first_byte, |
367 | | const uint8* buffer, |
368 | | uint32* value); |
369 | | inline ::std::pair<bool, const uint8*> ReadVarint32FromArray( |
370 | 0 | uint32 first_byte, const uint8* buffer, uint32* value) { |
371 | | // Fast path: We have enough bytes left in the buffer to guarantee that |
372 | | // this read won't cross the end, so we can skip the checks. |
373 | 0 | GOOGLE_DCHECK_EQ(*buffer, first_byte); |
374 | 0 | GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte; |
375 | 0 | const uint8* ptr = buffer; |
376 | 0 | uint32 b; |
377 | 0 | uint32 result = first_byte - 0x80; |
378 | 0 | ++ptr; // We just processed the first byte. Move on to the second. |
379 | 0 | b = *(ptr++); |
380 | 0 | result += b << 7; |
381 | 0 | if (!(b & 0x80)) goto done; |
382 | 0 | result -= 0x80 << 7; |
383 | 0 | b = *(ptr++); |
384 | 0 | result += b << 14; |
385 | 0 | if (!(b & 0x80)) goto done; |
386 | 0 | result -= 0x80 << 14; |
387 | 0 | b = *(ptr++); |
388 | 0 | result += b << 21; |
389 | 0 | if (!(b & 0x80)) goto done; |
390 | 0 | result -= 0x80 << 21; |
391 | 0 | b = *(ptr++); |
392 | 0 | result += b << 28; |
393 | 0 | if (!(b & 0x80)) goto done; |
394 | | // "result -= 0x80 << 28" is irrevelant. |
395 | | |
396 | | // If the input is larger than 32 bits, we still need to read it all |
397 | | // and discard the high-order bits. |
398 | 0 | for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) { |
399 | 0 | b = *(ptr++); |
400 | 0 | if (!(b & 0x80)) goto done; |
401 | 0 | } |
402 | | |
403 | | // We have overrun the maximum size of a varint (10 bytes). Assume |
404 | | // the data is corrupt. |
405 | 0 | return std::make_pair(false, ptr); |
406 | | |
407 | 0 | done: |
408 | 0 | *value = result; |
409 | 0 | return std::make_pair(true, ptr); |
410 | 0 | } |
411 | | |
412 | | PROTOBUF_ALWAYS_INLINE::std::pair<bool, const uint8*> ReadVarint64FromArray( |
413 | | const uint8* buffer, uint64* value); |
414 | | inline ::std::pair<bool, const uint8*> ReadVarint64FromArray( |
415 | 0 | const uint8* buffer, uint64* value) { |
416 | | // Assumes varint64 is at least 2 bytes. |
417 | 0 | GOOGLE_DCHECK_GE(buffer[0], 128); |
418 | |
|
419 | 0 | const uint8* next; |
420 | 0 | if (buffer[1] < 128) { |
421 | 0 | next = DecodeVarint64KnownSize<2>(buffer, value); |
422 | 0 | } else if (buffer[2] < 128) { |
423 | 0 | next = DecodeVarint64KnownSize<3>(buffer, value); |
424 | 0 | } else if (buffer[3] < 128) { |
425 | 0 | next = DecodeVarint64KnownSize<4>(buffer, value); |
426 | 0 | } else if (buffer[4] < 128) { |
427 | 0 | next = DecodeVarint64KnownSize<5>(buffer, value); |
428 | 0 | } else if (buffer[5] < 128) { |
429 | 0 | next = DecodeVarint64KnownSize<6>(buffer, value); |
430 | 0 | } else if (buffer[6] < 128) { |
431 | 0 | next = DecodeVarint64KnownSize<7>(buffer, value); |
432 | 0 | } else if (buffer[7] < 128) { |
433 | 0 | next = DecodeVarint64KnownSize<8>(buffer, value); |
434 | 0 | } else if (buffer[8] < 128) { |
435 | 0 | next = DecodeVarint64KnownSize<9>(buffer, value); |
436 | 0 | } else if (buffer[9] < 128) { |
437 | 0 | next = DecodeVarint64KnownSize<10>(buffer, value); |
438 | 0 | } else { |
439 | | // We have overrun the maximum size of a varint (10 bytes). Assume |
440 | | // the data is corrupt. |
441 | 0 | return std::make_pair(false, buffer + 11); |
442 | 0 | } |
443 | | |
444 | 0 | return std::make_pair(true, next); |
445 | 0 | } |
446 | | |
447 | | } // namespace |
448 | | |
449 | 0 | bool CodedInputStream::ReadVarint32Slow(uint32* value) { |
450 | | // Directly invoke ReadVarint64Fallback, since we already tried to optimize |
451 | | // for one-byte varints. |
452 | 0 | std::pair<uint64, bool> p = ReadVarint64Fallback(); |
453 | 0 | *value = static_cast<uint32>(p.first); |
454 | 0 | return p.second; |
455 | 0 | } |
456 | | |
457 | 0 | int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) { |
458 | 0 | if (BufferSize() >= kMaxVarintBytes || |
459 | | // Optimization: We're also safe if the buffer is non-empty and it ends |
460 | | // with a byte that would terminate a varint. |
461 | 0 | (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { |
462 | 0 | GOOGLE_DCHECK_NE(first_byte_or_zero, 0) |
463 | 0 | << "Caller should provide us with *buffer_ when buffer is non-empty"; |
464 | 0 | uint32 temp; |
465 | 0 | ::std::pair<bool, const uint8*> p = |
466 | 0 | ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp); |
467 | 0 | if (!p.first) return -1; |
468 | 0 | buffer_ = p.second; |
469 | 0 | return temp; |
470 | 0 | } else { |
471 | | // Really slow case: we will incur the cost of an extra function call here, |
472 | | // but moving this out of line reduces the size of this function, which |
473 | | // improves the common case. In micro benchmarks, this is worth about 10-15% |
474 | 0 | uint32 temp; |
475 | 0 | return ReadVarint32Slow(&temp) ? static_cast<int64>(temp) : -1; |
476 | 0 | } |
477 | 0 | } |
478 | | |
479 | 0 | int CodedInputStream::ReadVarintSizeAsIntSlow() { |
480 | | // Directly invoke ReadVarint64Fallback, since we already tried to optimize |
481 | | // for one-byte varints. |
482 | 0 | std::pair<uint64, bool> p = ReadVarint64Fallback(); |
483 | 0 | if (!p.second || p.first > static_cast<uint64>(INT_MAX)) return -1; |
484 | 0 | return p.first; |
485 | 0 | } |
486 | | |
487 | 0 | int CodedInputStream::ReadVarintSizeAsIntFallback() { |
488 | 0 | if (BufferSize() >= kMaxVarintBytes || |
489 | | // Optimization: We're also safe if the buffer is non-empty and it ends |
490 | | // with a byte that would terminate a varint. |
491 | 0 | (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { |
492 | 0 | uint64 temp; |
493 | 0 | ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp); |
494 | 0 | if (!p.first || temp > static_cast<uint64>(INT_MAX)) return -1; |
495 | 0 | buffer_ = p.second; |
496 | 0 | return temp; |
497 | 0 | } else { |
498 | | // Really slow case: we will incur the cost of an extra function call here, |
499 | | // but moving this out of line reduces the size of this function, which |
500 | | // improves the common case. In micro benchmarks, this is worth about 10-15% |
501 | 0 | return ReadVarintSizeAsIntSlow(); |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | 0 | uint32 CodedInputStream::ReadTagSlow() { |
506 | 0 | if (buffer_ == buffer_end_) { |
507 | | // Call refresh. |
508 | 0 | if (!Refresh()) { |
509 | | // Refresh failed. Make sure that it failed due to EOF, not because |
510 | | // we hit total_bytes_limit_, which, unlike normal limits, is not a |
511 | | // valid place to end a message. |
512 | 0 | int current_position = total_bytes_read_ - buffer_size_after_limit_; |
513 | 0 | if (current_position >= total_bytes_limit_) { |
514 | | // Hit total_bytes_limit_. But if we also hit the normal limit, |
515 | | // we're still OK. |
516 | 0 | legitimate_message_end_ = current_limit_ == total_bytes_limit_; |
517 | 0 | } else { |
518 | 0 | legitimate_message_end_ = true; |
519 | 0 | } |
520 | 0 | return 0; |
521 | 0 | } |
522 | 0 | } |
523 | | |
524 | | // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags |
525 | | // again, since we have now refreshed the buffer. |
526 | 0 | uint64 result = 0; |
527 | 0 | if (!ReadVarint64(&result)) return 0; |
528 | 0 | return static_cast<uint32>(result); |
529 | 0 | } |
530 | | |
531 | 0 | uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) { |
532 | 0 | const int buf_size = BufferSize(); |
533 | 0 | if (buf_size >= kMaxVarintBytes || |
534 | | // Optimization: We're also safe if the buffer is non-empty and it ends |
535 | | // with a byte that would terminate a varint. |
536 | 0 | (buf_size > 0 && !(buffer_end_[-1] & 0x80))) { |
537 | 0 | GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]); |
538 | 0 | if (first_byte_or_zero == 0) { |
539 | 0 | ++buffer_; |
540 | 0 | return 0; |
541 | 0 | } |
542 | 0 | uint32 tag; |
543 | 0 | ::std::pair<bool, const uint8*> p = |
544 | 0 | ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag); |
545 | 0 | if (!p.first) { |
546 | 0 | return 0; |
547 | 0 | } |
548 | 0 | buffer_ = p.second; |
549 | 0 | return tag; |
550 | 0 | } else { |
551 | | // We are commonly at a limit when attempting to read tags. Try to quickly |
552 | | // detect this case without making another function call. |
553 | 0 | if ((buf_size == 0) && |
554 | 0 | ((buffer_size_after_limit_ > 0) || |
555 | 0 | (total_bytes_read_ == current_limit_)) && |
556 | | // Make sure that the limit we hit is not total_bytes_limit_, since |
557 | | // in that case we still need to call Refresh() so that it prints an |
558 | | // error. |
559 | 0 | total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) { |
560 | | // We hit a byte limit. |
561 | 0 | legitimate_message_end_ = true; |
562 | 0 | return 0; |
563 | 0 | } |
564 | 0 | return ReadTagSlow(); |
565 | 0 | } |
566 | 0 | } |
567 | | |
568 | 0 | bool CodedInputStream::ReadVarint64Slow(uint64* value) { |
569 | | // Slow path: This read might cross the end of the buffer, so we |
570 | | // need to check and refresh the buffer if and when it does. |
571 | |
|
572 | 0 | uint64 result = 0; |
573 | 0 | int count = 0; |
574 | 0 | uint32 b; |
575 | |
|
576 | 0 | do { |
577 | 0 | if (count == kMaxVarintBytes) { |
578 | 0 | *value = 0; |
579 | 0 | return false; |
580 | 0 | } |
581 | 0 | while (buffer_ == buffer_end_) { |
582 | 0 | if (!Refresh()) { |
583 | 0 | *value = 0; |
584 | 0 | return false; |
585 | 0 | } |
586 | 0 | } |
587 | 0 | b = *buffer_; |
588 | 0 | result |= static_cast<uint64>(b & 0x7F) << (7 * count); |
589 | 0 | Advance(1); |
590 | 0 | ++count; |
591 | 0 | } while (b & 0x80); |
592 | | |
593 | 0 | *value = result; |
594 | 0 | return true; |
595 | 0 | } |
596 | | |
597 | 0 | std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() { |
598 | 0 | if (BufferSize() >= kMaxVarintBytes || |
599 | | // Optimization: We're also safe if the buffer is non-empty and it ends |
600 | | // with a byte that would terminate a varint. |
601 | 0 | (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { |
602 | 0 | uint64 temp; |
603 | 0 | ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp); |
604 | 0 | if (!p.first) { |
605 | 0 | return std::make_pair(0, false); |
606 | 0 | } |
607 | 0 | buffer_ = p.second; |
608 | 0 | return std::make_pair(temp, true); |
609 | 0 | } else { |
610 | 0 | uint64 temp; |
611 | 0 | bool success = ReadVarint64Slow(&temp); |
612 | 0 | return std::make_pair(temp, success); |
613 | 0 | } |
614 | 0 | } |
615 | | |
616 | 0 | bool CodedInputStream::Refresh() { |
617 | 0 | GOOGLE_DCHECK_EQ(0, BufferSize()); |
618 | |
|
619 | 0 | if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 || |
620 | 0 | total_bytes_read_ == current_limit_) { |
621 | | // We've hit a limit. Stop. |
622 | 0 | int current_position = total_bytes_read_ - buffer_size_after_limit_; |
623 | |
|
624 | 0 | if (current_position >= total_bytes_limit_ && |
625 | 0 | total_bytes_limit_ != current_limit_) { |
626 | | // Hit total_bytes_limit_. |
627 | 0 | PrintTotalBytesLimitError(); |
628 | 0 | } |
629 | |
|
630 | 0 | return false; |
631 | 0 | } |
632 | | |
633 | 0 | const void* void_buffer; |
634 | 0 | int buffer_size; |
635 | 0 | if (NextNonEmpty(input_, &void_buffer, &buffer_size)) { |
636 | 0 | buffer_ = reinterpret_cast<const uint8*>(void_buffer); |
637 | 0 | buffer_end_ = buffer_ + buffer_size; |
638 | 0 | GOOGLE_CHECK_GE(buffer_size, 0); |
639 | |
|
640 | 0 | if (total_bytes_read_ <= INT_MAX - buffer_size) { |
641 | 0 | total_bytes_read_ += buffer_size; |
642 | 0 | } else { |
643 | | // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX. |
644 | | // We can't get that far anyway, because total_bytes_limit_ is guaranteed |
645 | | // to be less than it. We need to keep track of the number of bytes |
646 | | // we discarded, though, so that we can call input_->BackUp() to back |
647 | | // up over them on destruction. |
648 | | |
649 | | // The following line is equivalent to: |
650 | | // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX; |
651 | | // except that it avoids overflows. Signed integer overflow has |
652 | | // undefined results according to the C standard. |
653 | 0 | overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size); |
654 | 0 | buffer_end_ -= overflow_bytes_; |
655 | 0 | total_bytes_read_ = INT_MAX; |
656 | 0 | } |
657 | |
|
658 | 0 | RecomputeBufferLimits(); |
659 | 0 | return true; |
660 | 0 | } else { |
661 | 0 | buffer_ = NULL; |
662 | 0 | buffer_end_ = NULL; |
663 | 0 | return false; |
664 | 0 | } |
665 | 0 | } |
666 | | |
667 | | // CodedOutputStream ================================================= |
668 | | |
669 | 0 | void EpsCopyOutputStream::EnableAliasing(bool enabled) { |
670 | 0 | aliasing_enabled_ = enabled && stream_->AllowsAliasing(); |
671 | 0 | } |
672 | | |
673 | 0 | int64 EpsCopyOutputStream::ByteCount(uint8* ptr) const { |
674 | | // Calculate the current offset relative to the end of the stream buffer. |
675 | 0 | int delta = (end_ - ptr) + (buffer_end_ ? 0 : kSlopBytes); |
676 | 0 | return stream_->ByteCount() - delta; |
677 | 0 | } |
678 | | |
679 | | // Flushes what's written out to the underlying ZeroCopyOutputStream buffers. |
680 | | // Returns the size remaining in the buffer and sets buffer_end_ to the start |
681 | | // of the remaining buffer, ie. [buffer_end_, buffer_end_ + return value) |
682 | 0 | int EpsCopyOutputStream::Flush(uint8* ptr) { |
683 | 0 | while (buffer_end_ && ptr > end_) { |
684 | 0 | int overrun = ptr - end_; |
685 | 0 | GOOGLE_DCHECK(!had_error_); |
686 | 0 | GOOGLE_DCHECK(overrun <= kSlopBytes); // NOLINT |
687 | 0 | ptr = Next() + overrun; |
688 | 0 | if (had_error_) return 0; |
689 | 0 | } |
690 | 0 | int s; |
691 | 0 | if (buffer_end_) { |
692 | 0 | std::memcpy(buffer_end_, buffer_, ptr - buffer_); |
693 | 0 | buffer_end_ += ptr - buffer_; |
694 | 0 | s = end_ - ptr; |
695 | 0 | } else { |
696 | | // The stream is writing directly in the ZeroCopyOutputStream buffer. |
697 | 0 | s = end_ + kSlopBytes - ptr; |
698 | 0 | buffer_end_ = ptr; |
699 | 0 | } |
700 | 0 | GOOGLE_DCHECK(s >= 0); // NOLINT |
701 | 0 | return s; |
702 | 0 | } |
703 | | |
704 | 0 | uint8* EpsCopyOutputStream::Trim(uint8* ptr) { |
705 | 0 | if (had_error_) return ptr; |
706 | 0 | int s = Flush(ptr); |
707 | 0 | if (s) stream_->BackUp(s); |
708 | | // Reset to initial state (expecting new buffer) |
709 | 0 | buffer_end_ = end_ = buffer_; |
710 | 0 | return buffer_; |
711 | 0 | } |
712 | | |
713 | | |
714 | 0 | uint8* EpsCopyOutputStream::FlushAndResetBuffer(uint8* ptr) { |
715 | 0 | if (had_error_) return buffer_; |
716 | 0 | int s = Flush(ptr); |
717 | 0 | if (had_error_) return buffer_; |
718 | 0 | return SetInitialBuffer(buffer_end_, s); |
719 | 0 | } |
720 | | |
721 | 0 | bool EpsCopyOutputStream::Skip(int count, uint8** pp) { |
722 | 0 | if (count < 0) return false; |
723 | 0 | if (had_error_) { |
724 | 0 | *pp = buffer_; |
725 | 0 | return false; |
726 | 0 | } |
727 | 0 | int size = Flush(*pp); |
728 | 0 | if (had_error_) { |
729 | 0 | *pp = buffer_; |
730 | 0 | return false; |
731 | 0 | } |
732 | 0 | void* data = buffer_end_; |
733 | 0 | while (count > size) { |
734 | 0 | count -= size; |
735 | 0 | if (!stream_->Next(&data, &size)) { |
736 | 0 | *pp = Error(); |
737 | 0 | return false; |
738 | 0 | } |
739 | 0 | } |
740 | 0 | *pp = SetInitialBuffer(static_cast<uint8*>(data) + count, size - count); |
741 | 0 | return true; |
742 | 0 | } |
743 | | |
744 | | bool EpsCopyOutputStream::GetDirectBufferPointer(void** data, int* size, |
745 | 0 | uint8** pp) { |
746 | 0 | if (had_error_) { |
747 | 0 | *pp = buffer_; |
748 | 0 | return false; |
749 | 0 | } |
750 | 0 | *size = Flush(*pp); |
751 | 0 | if (had_error_) { |
752 | 0 | *pp = buffer_; |
753 | 0 | return false; |
754 | 0 | } |
755 | 0 | *data = buffer_end_; |
756 | 0 | while (*size == 0) { |
757 | 0 | if (!stream_->Next(data, size)) { |
758 | 0 | *pp = Error(); |
759 | 0 | return false; |
760 | 0 | } |
761 | 0 | } |
762 | 0 | *pp = SetInitialBuffer(*data, *size); |
763 | 0 | return true; |
764 | 0 | } |
765 | | |
766 | | uint8* EpsCopyOutputStream::GetDirectBufferForNBytesAndAdvance(int size, |
767 | 0 | uint8** pp) { |
768 | 0 | if (had_error_) { |
769 | 0 | *pp = buffer_; |
770 | 0 | return nullptr; |
771 | 0 | } |
772 | 0 | int s = Flush(*pp); |
773 | 0 | if (had_error_) { |
774 | 0 | *pp = buffer_; |
775 | 0 | return nullptr; |
776 | 0 | } |
777 | 0 | if (s >= size) { |
778 | 0 | auto res = buffer_end_; |
779 | 0 | *pp = SetInitialBuffer(buffer_end_ + size, s - size); |
780 | 0 | return res; |
781 | 0 | } else { |
782 | 0 | *pp = SetInitialBuffer(buffer_end_, s); |
783 | 0 | return nullptr; |
784 | 0 | } |
785 | 0 | } |
786 | | |
787 | 0 | uint8* EpsCopyOutputStream::Next() { |
788 | 0 | GOOGLE_DCHECK(!had_error_); // NOLINT |
789 | 0 | if (PROTOBUF_PREDICT_FALSE(stream_ == nullptr)) return Error(); |
790 | 0 | if (buffer_end_) { |
791 | | // We're in the patch buffer and need to fill up the previous buffer. |
792 | 0 | std::memcpy(buffer_end_, buffer_, end_ - buffer_); |
793 | 0 | uint8* ptr; |
794 | 0 | int size; |
795 | 0 | do { |
796 | 0 | void* data; |
797 | 0 | if (PROTOBUF_PREDICT_FALSE(!stream_->Next(&data, &size))) { |
798 | | // Stream has an error, we use the patch buffer to continue to be |
799 | | // able to write. |
800 | 0 | return Error(); |
801 | 0 | } |
802 | 0 | ptr = static_cast<uint8*>(data); |
803 | 0 | } while (size == 0); |
804 | 0 | if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) { |
805 | 0 | std::memcpy(ptr, end_, kSlopBytes); |
806 | 0 | end_ = ptr + size - kSlopBytes; |
807 | 0 | buffer_end_ = nullptr; |
808 | 0 | return ptr; |
809 | 0 | } else { |
810 | 0 | GOOGLE_DCHECK(size > 0); // NOLINT |
811 | | // Buffer to small |
812 | 0 | std::memmove(buffer_, end_, kSlopBytes); |
813 | 0 | buffer_end_ = ptr; |
814 | 0 | end_ = buffer_ + size; |
815 | 0 | return buffer_; |
816 | 0 | } |
817 | 0 | } else { |
818 | 0 | std::memcpy(buffer_, end_, kSlopBytes); |
819 | 0 | buffer_end_ = end_; |
820 | 0 | end_ = buffer_ + kSlopBytes; |
821 | 0 | return buffer_; |
822 | 0 | } |
823 | 0 | } |
824 | | |
825 | 0 | uint8* EpsCopyOutputStream::EnsureSpaceFallback(uint8* ptr) { |
826 | 0 | do { |
827 | 0 | if (PROTOBUF_PREDICT_FALSE(had_error_)) return buffer_; |
828 | 0 | int overrun = ptr - end_; |
829 | 0 | GOOGLE_DCHECK(overrun >= 0); // NOLINT |
830 | 0 | GOOGLE_DCHECK(overrun <= kSlopBytes); // NOLINT |
831 | 0 | ptr = Next() + overrun; |
832 | 0 | } while (ptr >= end_); |
833 | 0 | GOOGLE_DCHECK(ptr < end_); // NOLINT |
834 | 0 | return ptr; |
835 | 0 | } |
836 | | |
837 | | uint8* EpsCopyOutputStream::WriteRawFallback(const void* data, int size, |
838 | 0 | uint8* ptr) { |
839 | 0 | int s = GetSize(ptr); |
840 | 0 | while (s < size) { |
841 | 0 | std::memcpy(ptr, data, s); |
842 | 0 | size -= s; |
843 | 0 | data = static_cast<const uint8*>(data) + s; |
844 | 0 | ptr = EnsureSpaceFallback(ptr + s); |
845 | 0 | s = GetSize(ptr); |
846 | 0 | } |
847 | 0 | std::memcpy(ptr, data, size); |
848 | 0 | return ptr + size; |
849 | 0 | } |
850 | | |
851 | | uint8* EpsCopyOutputStream::WriteAliasedRaw(const void* data, int size, |
852 | 0 | uint8* ptr) { |
853 | 0 | if (size < GetSize(ptr) |
854 | 0 | ) { |
855 | 0 | return WriteRaw(data, size, ptr); |
856 | 0 | } else { |
857 | 0 | ptr = Trim(ptr); |
858 | 0 | if (stream_->WriteAliasedRaw(data, size)) return ptr; |
859 | 0 | return Error(); |
860 | 0 | } |
861 | 0 | } |
862 | | |
863 | | #ifndef PROTOBUF_LITTLE_ENDIAN |
864 | | uint8* EpsCopyOutputStream::WriteRawLittleEndian32(const void* data, int size, |
865 | | uint8* ptr) { |
866 | | auto p = static_cast<const uint8*>(data); |
867 | | auto end = p + size; |
868 | | while (end - p >= kSlopBytes) { |
869 | | ptr = EnsureSpace(ptr); |
870 | | uint32 buffer[4]; |
871 | | static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes"); |
872 | | std::memcpy(buffer, p, kSlopBytes); |
873 | | p += kSlopBytes; |
874 | | for (auto x : buffer) |
875 | | ptr = CodedOutputStream::WriteLittleEndian32ToArray(x, ptr); |
876 | | } |
877 | | while (p < end) { |
878 | | ptr = EnsureSpace(ptr); |
879 | | uint32 buffer; |
880 | | std::memcpy(&buffer, p, 4); |
881 | | p += 4; |
882 | | ptr = CodedOutputStream::WriteLittleEndian32ToArray(buffer, ptr); |
883 | | } |
884 | | return ptr; |
885 | | } |
886 | | |
887 | | uint8* EpsCopyOutputStream::WriteRawLittleEndian64(const void* data, int size, |
888 | | uint8* ptr) { |
889 | | auto p = static_cast<const uint8*>(data); |
890 | | auto end = p + size; |
891 | | while (end - p >= kSlopBytes) { |
892 | | ptr = EnsureSpace(ptr); |
893 | | uint64 buffer[2]; |
894 | | static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes"); |
895 | | std::memcpy(buffer, p, kSlopBytes); |
896 | | p += kSlopBytes; |
897 | | for (auto x : buffer) |
898 | | ptr = CodedOutputStream::WriteLittleEndian64ToArray(x, ptr); |
899 | | } |
900 | | while (p < end) { |
901 | | ptr = EnsureSpace(ptr); |
902 | | uint64 buffer; |
903 | | std::memcpy(&buffer, p, 8); |
904 | | p += 8; |
905 | | ptr = CodedOutputStream::WriteLittleEndian64ToArray(buffer, ptr); |
906 | | } |
907 | | return ptr; |
908 | | } |
909 | | #endif |
910 | | |
911 | | |
912 | | uint8* EpsCopyOutputStream::WriteStringMaybeAliasedOutline(uint32 num, |
913 | | const std::string& s, |
914 | 0 | uint8* ptr) { |
915 | 0 | ptr = EnsureSpace(ptr); |
916 | 0 | uint32 size = s.size(); |
917 | 0 | ptr = WriteLengthDelim(num, size, ptr); |
918 | 0 | return WriteRawMaybeAliased(s.data(), size, ptr); |
919 | 0 | } |
920 | | |
921 | | uint8* EpsCopyOutputStream::WriteStringOutline(uint32 num, const std::string& s, |
922 | 0 | uint8* ptr) { |
923 | 0 | ptr = EnsureSpace(ptr); |
924 | 0 | uint32 size = s.size(); |
925 | 0 | ptr = WriteLengthDelim(num, size, ptr); |
926 | 0 | return WriteRaw(s.data(), size, ptr); |
927 | 0 | } |
928 | | |
929 | | std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{ |
930 | | false}; |
931 | | |
932 | | CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* stream, |
933 | | bool do_eager_refresh) |
934 | 0 | : impl_(stream, IsDefaultSerializationDeterministic(), &cur_), |
935 | 0 | start_count_(stream->ByteCount()) { |
936 | 0 | if (do_eager_refresh) { |
937 | 0 | void* data; |
938 | 0 | int size; |
939 | 0 | if (!stream->Next(&data, &size) || size == 0) return; |
940 | 0 | cur_ = impl_.SetInitialBuffer(data, size); |
941 | 0 | } |
942 | 0 | } |
943 | | |
944 | 0 | CodedOutputStream::~CodedOutputStream() { Trim(); } |
945 | | |
946 | | |
947 | | uint8* CodedOutputStream::WriteStringWithSizeToArray(const std::string& str, |
948 | 0 | uint8* target) { |
949 | 0 | GOOGLE_DCHECK_LE(str.size(), kuint32max); |
950 | 0 | target = WriteVarint32ToArray(str.size(), target); |
951 | 0 | return WriteStringToArray(str, target); |
952 | 0 | } |
953 | | |
954 | | } // namespace io |
955 | | } // namespace protobuf |
956 | | } // namespace google |