blob: 083beca43deeb3c02d628aac8a91ca2bf7eefce7 [file] [log] [blame]
kenton@google.com80b1d622009-07-29 01:13:20 +00001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
kenton@google.com80b1d622009-07-29 01:13:20 +00004//
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
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000035#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
kenton@google.com80b1d622009-07-29 01:13:20 +000036
xiaofeng@google.com172019c2013-09-17 21:00:11 +000037#include <algorithm>
jieluo@google.com4de8f552014-07-18 00:47:59 +000038#include <limits>
39
Feng Xiao6ef984a2014-11-10 17:34:54 -080040#include <google/protobuf/stubs/casts.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000041#include <google/protobuf/stubs/common.h>
Feng Xiaoeee38b02015-08-22 18:25:48 -070042#include <google/protobuf/stubs/logging.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000043#include <google/protobuf/stubs/stl_util.h>
xiaofeng@google.com172019c2013-09-17 21:00:11 +000044
kenton@google.com80b1d622009-07-29 01:13:20 +000045namespace google {
46namespace protobuf {
47namespace io {
48
49namespace {
50
51// Default block size for Copying{In,Out}putStreamAdaptor.
52static const int kDefaultBlockSize = 8192;
53
54} // namespace
55
56// ===================================================================
57
58ArrayInputStream::ArrayInputStream(const void* data, int size,
59 int block_size)
60 : data_(reinterpret_cast<const uint8*>(data)),
61 size_(size),
62 block_size_(block_size > 0 ? block_size : size),
63 position_(0),
64 last_returned_size_(0) {
65}
66
67ArrayInputStream::~ArrayInputStream() {
68}
69
70bool ArrayInputStream::Next(const void** data, int* size) {
71 if (position_ < size_) {
72 last_returned_size_ = min(block_size_, size_ - position_);
73 *data = data_ + position_;
74 *size = last_returned_size_;
75 position_ += last_returned_size_;
76 return true;
77 } else {
78 // We're at the end of the array.
79 last_returned_size_ = 0; // Don't let caller back up.
80 return false;
81 }
82}
83
84void ArrayInputStream::BackUp(int count) {
85 GOOGLE_CHECK_GT(last_returned_size_, 0)
86 << "BackUp() can only be called after a successful Next().";
87 GOOGLE_CHECK_LE(count, last_returned_size_);
88 GOOGLE_CHECK_GE(count, 0);
89 position_ -= count;
90 last_returned_size_ = 0; // Don't let caller back up further.
91}
92
93bool ArrayInputStream::Skip(int count) {
94 GOOGLE_CHECK_GE(count, 0);
95 last_returned_size_ = 0; // Don't let caller back up.
96 if (count > size_ - position_) {
97 position_ = size_;
98 return false;
99 } else {
100 position_ += count;
101 return true;
102 }
103}
104
105int64 ArrayInputStream::ByteCount() const {
106 return position_;
107}
108
109
110// ===================================================================
111
112ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
113 : data_(reinterpret_cast<uint8*>(data)),
114 size_(size),
115 block_size_(block_size > 0 ? block_size : size),
116 position_(0),
117 last_returned_size_(0) {
118}
119
120ArrayOutputStream::~ArrayOutputStream() {
121}
122
123bool ArrayOutputStream::Next(void** data, int* size) {
124 if (position_ < size_) {
125 last_returned_size_ = min(block_size_, size_ - position_);
126 *data = data_ + position_;
127 *size = last_returned_size_;
128 position_ += last_returned_size_;
129 return true;
130 } else {
131 // We're at the end of the array.
132 last_returned_size_ = 0; // Don't let caller back up.
133 return false;
134 }
135}
136
137void ArrayOutputStream::BackUp(int count) {
138 GOOGLE_CHECK_GT(last_returned_size_, 0)
139 << "BackUp() can only be called after a successful Next().";
140 GOOGLE_CHECK_LE(count, last_returned_size_);
141 GOOGLE_CHECK_GE(count, 0);
142 position_ -= count;
143 last_returned_size_ = 0; // Don't let caller back up further.
144}
145
146int64 ArrayOutputStream::ByteCount() const {
147 return position_;
148}
149
150// ===================================================================
151
152StringOutputStream::StringOutputStream(string* target)
153 : target_(target) {
154}
155
156StringOutputStream::~StringOutputStream() {
157}
158
159bool StringOutputStream::Next(void** data, int* size) {
Feng Xiao76195052016-01-06 18:06:43 -0800160 GOOGLE_CHECK_NE(NULL, target_);
kenton@google.com80b1d622009-07-29 01:13:20 +0000161 int old_size = target_->size();
162
163 // Grow the string.
164 if (old_size < target_->capacity()) {
165 // Resize the string to match its capacity, since we can get away
166 // without a memory allocation this way.
167 STLStringResizeUninitialized(target_, target_->capacity());
168 } else {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000169 // Size has reached capacity, try to double the size.
170 if (old_size > std::numeric_limits<int>::max() / 2) {
171 // Can not double the size otherwise it is going to cause integer
172 // overflow in the expression below: old_size * 2 ";
173 GOOGLE_LOG(ERROR) << "Cannot allocate buffer larger than kint32max for "
174 << "StringOutputStream.";
175 return false;
176 }
177 // Double the size, also make sure that the new size is at least
178 // kMinimumSize.
kenton@google.com80b1d622009-07-29 01:13:20 +0000179 STLStringResizeUninitialized(
180 target_,
181 max(old_size * 2,
182 kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
183 }
184
jieluo@google.com4de8f552014-07-18 00:47:59 +0000185 *data = mutable_string_data(target_) + old_size;
kenton@google.com80b1d622009-07-29 01:13:20 +0000186 *size = target_->size() - old_size;
187 return true;
188}
189
190void StringOutputStream::BackUp(int count) {
191 GOOGLE_CHECK_GE(count, 0);
Feng Xiao76195052016-01-06 18:06:43 -0800192 GOOGLE_CHECK_NE(NULL, target_);
kenton@google.com80b1d622009-07-29 01:13:20 +0000193 GOOGLE_CHECK_LE(count, target_->size());
194 target_->resize(target_->size() - count);
195}
196
197int64 StringOutputStream::ByteCount() const {
Feng Xiao76195052016-01-06 18:06:43 -0800198 GOOGLE_CHECK_NE(NULL, target_);
kenton@google.com80b1d622009-07-29 01:13:20 +0000199 return target_->size();
200}
201
Feng Xiao76195052016-01-06 18:06:43 -0800202void StringOutputStream::SetString(string* target) {
203 target_ = target;
204}
205
206// ===================================================================
207
208LazyStringOutputStream::LazyStringOutputStream(
209 ResultCallback<string*>* callback)
210 : StringOutputStream(NULL),
211 callback_(GOOGLE_CHECK_NOTNULL(callback)),
212 string_is_set_(false) {
213}
214
215LazyStringOutputStream::~LazyStringOutputStream() {
216}
217
218bool LazyStringOutputStream::Next(void** data, int* size) {
219 if (!string_is_set_) {
220 SetString(callback_->Run());
221 string_is_set_ = true;
222 }
223 return StringOutputStream::Next(data, size);
224}
225
226int64 LazyStringOutputStream::ByteCount() const {
227 return string_is_set_ ? StringOutputStream::ByteCount() : 0;
228}
229
kenton@google.com80b1d622009-07-29 01:13:20 +0000230// ===================================================================
231
232CopyingInputStream::~CopyingInputStream() {}
233
234int CopyingInputStream::Skip(int count) {
235 char junk[4096];
236 int skipped = 0;
237 while (skipped < count) {
238 int bytes = Read(junk, min(count - skipped,
239 implicit_cast<int>(sizeof(junk))));
240 if (bytes <= 0) {
241 // EOF or read error.
242 return skipped;
243 }
244 skipped += bytes;
245 }
246 return skipped;
247}
248
249CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
250 CopyingInputStream* copying_stream, int block_size)
251 : copying_stream_(copying_stream),
252 owns_copying_stream_(false),
253 failed_(false),
254 position_(0),
255 buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
256 buffer_used_(0),
257 backup_bytes_(0) {
258}
259
260CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
261 if (owns_copying_stream_) {
262 delete copying_stream_;
263 }
264}
265
266bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
267 if (failed_) {
268 // Already failed on a previous read.
269 return false;
270 }
271
272 AllocateBufferIfNeeded();
273
274 if (backup_bytes_ > 0) {
275 // We have data left over from a previous BackUp(), so just return that.
276 *data = buffer_.get() + buffer_used_ - backup_bytes_;
277 *size = backup_bytes_;
278 backup_bytes_ = 0;
279 return true;
280 }
281
282 // Read new data into the buffer.
283 buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
284 if (buffer_used_ <= 0) {
285 // EOF or read error. We don't need the buffer anymore.
286 if (buffer_used_ < 0) {
287 // Read error (not EOF).
288 failed_ = true;
289 }
290 FreeBuffer();
291 return false;
292 }
293 position_ += buffer_used_;
294
295 *size = buffer_used_;
296 *data = buffer_.get();
297 return true;
298}
299
300void CopyingInputStreamAdaptor::BackUp(int count) {
301 GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
302 << " BackUp() can only be called after Next().";
303 GOOGLE_CHECK_LE(count, buffer_used_)
304 << " Can't back up over more bytes than were returned by the last call"
305 " to Next().";
306 GOOGLE_CHECK_GE(count, 0)
307 << " Parameter to BackUp() can't be negative.";
308
309 backup_bytes_ = count;
310}
311
312bool CopyingInputStreamAdaptor::Skip(int count) {
313 GOOGLE_CHECK_GE(count, 0);
314
315 if (failed_) {
316 // Already failed on a previous read.
317 return false;
318 }
319
320 // First skip any bytes left over from a previous BackUp().
321 if (backup_bytes_ >= count) {
322 // We have more data left over than we're trying to skip. Just chop it.
323 backup_bytes_ -= count;
324 return true;
325 }
326
327 count -= backup_bytes_;
328 backup_bytes_ = 0;
329
330 int skipped = copying_stream_->Skip(count);
331 position_ += skipped;
332 return skipped == count;
333}
334
335int64 CopyingInputStreamAdaptor::ByteCount() const {
336 return position_ - backup_bytes_;
337}
338
339void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
340 if (buffer_.get() == NULL) {
341 buffer_.reset(new uint8[buffer_size_]);
342 }
343}
344
345void CopyingInputStreamAdaptor::FreeBuffer() {
346 GOOGLE_CHECK_EQ(backup_bytes_, 0);
347 buffer_used_ = 0;
348 buffer_.reset();
349}
350
351// ===================================================================
352
353CopyingOutputStream::~CopyingOutputStream() {}
354
355CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
356 CopyingOutputStream* copying_stream, int block_size)
357 : copying_stream_(copying_stream),
358 owns_copying_stream_(false),
359 failed_(false),
360 position_(0),
361 buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
362 buffer_used_(0) {
363}
364
365CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
366 WriteBuffer();
367 if (owns_copying_stream_) {
368 delete copying_stream_;
369 }
370}
371
372bool CopyingOutputStreamAdaptor::Flush() {
373 return WriteBuffer();
374}
375
376bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
377 if (buffer_used_ == buffer_size_) {
378 if (!WriteBuffer()) return false;
379 }
380
381 AllocateBufferIfNeeded();
382
383 *data = buffer_.get() + buffer_used_;
384 *size = buffer_size_ - buffer_used_;
385 buffer_used_ = buffer_size_;
386 return true;
387}
388
389void CopyingOutputStreamAdaptor::BackUp(int count) {
390 GOOGLE_CHECK_GE(count, 0);
391 GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
392 << " BackUp() can only be called after Next().";
393 GOOGLE_CHECK_LE(count, buffer_used_)
394 << " Can't back up over more bytes than were returned by the last call"
395 " to Next().";
396
397 buffer_used_ -= count;
398}
399
400int64 CopyingOutputStreamAdaptor::ByteCount() const {
401 return position_ + buffer_used_;
402}
403
404bool CopyingOutputStreamAdaptor::WriteBuffer() {
405 if (failed_) {
406 // Already failed on a previous write.
407 return false;
408 }
409
410 if (buffer_used_ == 0) return true;
411
412 if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
413 position_ += buffer_used_;
414 buffer_used_ = 0;
415 return true;
416 } else {
417 failed_ = true;
418 FreeBuffer();
419 return false;
420 }
421}
422
423void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
424 if (buffer_ == NULL) {
425 buffer_.reset(new uint8[buffer_size_]);
426 }
427}
428
429void CopyingOutputStreamAdaptor::FreeBuffer() {
430 buffer_used_ = 0;
431 buffer_.reset();
432}
433
434// ===================================================================
435
436} // namespace io
437} // namespace protobuf
438} // namespace google