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 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
36
37 #include <algorithm>
38 #include <limits>
39
40 #include <google/protobuf/stubs/casts.h>
41 #include <google/protobuf/stubs/common.h>
42 #include <google/protobuf/stubs/logging.h>
43 #include <google/protobuf/stubs/stl_util.h>
44
45 namespace google {
46 namespace protobuf {
47 namespace io {
48
49 namespace {
50
51 // Default block size for Copying{In,Out}putStreamAdaptor.
52 static const int kDefaultBlockSize = 8192;
53
54 } // namespace
55
56 // ===================================================================
57
ArrayInputStream(const void * data,int size,int block_size)58 ArrayInputStream::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
~ArrayInputStream()67 ArrayInputStream::~ArrayInputStream() {
68 }
69
Next(const void ** data,int * size)70 bool ArrayInputStream::Next(const void** data, int* size) {
71 if (position_ < size_) {
72 last_returned_size_ = std::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
BackUp(int count)84 void 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
Skip(int count)93 bool 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
ByteCount() const105 int64 ArrayInputStream::ByteCount() const {
106 return position_;
107 }
108
109
110 // ===================================================================
111
ArrayOutputStream(void * data,int size,int block_size)112 ArrayOutputStream::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
~ArrayOutputStream()120 ArrayOutputStream::~ArrayOutputStream() {
121 }
122
Next(void ** data,int * size)123 bool ArrayOutputStream::Next(void** data, int* size) {
124 if (position_ < size_) {
125 last_returned_size_ = std::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
BackUp(int count)137 void 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
ByteCount() const146 int64 ArrayOutputStream::ByteCount() const {
147 return position_;
148 }
149
150 // ===================================================================
151
StringOutputStream(string * target)152 StringOutputStream::StringOutputStream(string* target)
153 : target_(target) {
154 }
155
~StringOutputStream()156 StringOutputStream::~StringOutputStream() {
157 }
158
Next(void ** data,int * size)159 bool StringOutputStream::Next(void** data, int* size) {
160 GOOGLE_CHECK(target_ != NULL);
161 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 {
169 // 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.
179 STLStringResizeUninitialized(
180 target_,
181 std::max(old_size * 2,
182 kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
183 }
184
185 *data = mutable_string_data(target_) + old_size;
186 *size = target_->size() - old_size;
187 return true;
188 }
189
BackUp(int count)190 void StringOutputStream::BackUp(int count) {
191 GOOGLE_CHECK_GE(count, 0);
192 GOOGLE_CHECK(target_ != NULL);
193 GOOGLE_CHECK_LE(count, target_->size());
194 target_->resize(target_->size() - count);
195 }
196
ByteCount() const197 int64 StringOutputStream::ByteCount() const {
198 GOOGLE_CHECK(target_ != NULL);
199 return target_->size();
200 }
201
SetString(string * target)202 void StringOutputStream::SetString(string* target) {
203 target_ = target;
204 }
205
206 // ===================================================================
207
LazyStringOutputStream(ResultCallback<string * > * callback)208 LazyStringOutputStream::LazyStringOutputStream(
209 ResultCallback<string*>* callback)
210 : StringOutputStream(NULL),
211 callback_(GOOGLE_CHECK_NOTNULL(callback)),
212 string_is_set_(false) {
213 }
214
~LazyStringOutputStream()215 LazyStringOutputStream::~LazyStringOutputStream() {
216 }
217
Next(void ** data,int * size)218 bool 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
ByteCount() const226 int64 LazyStringOutputStream::ByteCount() const {
227 return string_is_set_ ? StringOutputStream::ByteCount() : 0;
228 }
229
230 // ===================================================================
231
~CopyingInputStream()232 CopyingInputStream::~CopyingInputStream() {}
233
Skip(int count)234 int CopyingInputStream::Skip(int count) {
235 char junk[4096];
236 int skipped = 0;
237 while (skipped < count) {
238 int bytes =
239 Read(junk, std::min(count - skipped, 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
CopyingInputStreamAdaptor(CopyingInputStream * copying_stream,int block_size)249 CopyingInputStreamAdaptor::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
~CopyingInputStreamAdaptor()260 CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
261 if (owns_copying_stream_) {
262 delete copying_stream_;
263 }
264 }
265
Next(const void ** data,int * size)266 bool 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
BackUp(int count)300 void 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
Skip(int count)312 bool 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
ByteCount() const335 int64 CopyingInputStreamAdaptor::ByteCount() const {
336 return position_ - backup_bytes_;
337 }
338
AllocateBufferIfNeeded()339 void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
340 if (buffer_.get() == NULL) {
341 buffer_.reset(new uint8[buffer_size_]);
342 }
343 }
344
FreeBuffer()345 void CopyingInputStreamAdaptor::FreeBuffer() {
346 GOOGLE_CHECK_EQ(backup_bytes_, 0);
347 buffer_used_ = 0;
348 buffer_.reset();
349 }
350
351 // ===================================================================
352
~CopyingOutputStream()353 CopyingOutputStream::~CopyingOutputStream() {}
354
CopyingOutputStreamAdaptor(CopyingOutputStream * copying_stream,int block_size)355 CopyingOutputStreamAdaptor::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
~CopyingOutputStreamAdaptor()365 CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
366 WriteBuffer();
367 if (owns_copying_stream_) {
368 delete copying_stream_;
369 }
370 }
371
Flush()372 bool CopyingOutputStreamAdaptor::Flush() {
373 return WriteBuffer();
374 }
375
Next(void ** data,int * size)376 bool 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
BackUp(int count)389 void 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
ByteCount() const400 int64 CopyingOutputStreamAdaptor::ByteCount() const {
401 return position_ + buffer_used_;
402 }
403
WriteBuffer()404 bool 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
AllocateBufferIfNeeded()423 void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
424 if (buffer_ == NULL) {
425 buffer_.reset(new uint8[buffer_size_]);
426 }
427 }
428
FreeBuffer()429 void CopyingOutputStreamAdaptor::FreeBuffer() {
430 buffer_used_ = 0;
431 buffer_.reset();
432 }
433
434 // ===================================================================
435
436 } // namespace io
437 } // namespace protobuf
438 } // namespace google
439