1
// Protocol Buffers - Google's data interchange format
2
// Copyright 2008 Google Inc. All rights reserved.
3
// http://code.google.com/p/protobuf/
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are
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
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.
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.
31
// Author: kenton@google.com (Kenton Varda)
32
// Based on original Protocol Buffers design by
33
// Sanjay Ghemawat, Jeff Dean, and others.
35
#include <google/protobuf/io/zero_copy_stream_impl.h>
36
#include <google/protobuf/stubs/common.h>
37
#include <google/protobuf/stubs/stl_util-inl.h>
45
// Default block size for Copying{In,Out}putStreamAdaptor.
46
static const int kDefaultBlockSize = 8192;
50
// ===================================================================
52
ArrayInputStream::ArrayInputStream(const void* data, int size,
54
: data_(reinterpret_cast<const uint8*>(data)),
56
block_size_(block_size > 0 ? block_size : size),
58
last_returned_size_(0) {
61
ArrayInputStream::~ArrayInputStream() {
64
bool ArrayInputStream::Next(const void** data, int* size) {
65
if (position_ < size_) {
66
last_returned_size_ = min(block_size_, size_ - position_);
67
*data = data_ + position_;
68
*size = last_returned_size_;
69
position_ += last_returned_size_;
72
// We're at the end of the array.
73
last_returned_size_ = 0; // Don't let caller back up.
78
void ArrayInputStream::BackUp(int count) {
79
GOOGLE_CHECK_GT(last_returned_size_, 0)
80
<< "BackUp() can only be called after a successful Next().";
81
GOOGLE_CHECK_LE(count, last_returned_size_);
82
GOOGLE_CHECK_GE(count, 0);
84
last_returned_size_ = 0; // Don't let caller back up further.
87
bool ArrayInputStream::Skip(int count) {
88
GOOGLE_CHECK_GE(count, 0);
89
last_returned_size_ = 0; // Don't let caller back up.
90
if (count > size_ - position_) {
99
int64 ArrayInputStream::ByteCount() const {
104
// ===================================================================
106
ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
107
: data_(reinterpret_cast<uint8*>(data)),
109
block_size_(block_size > 0 ? block_size : size),
111
last_returned_size_(0) {
114
ArrayOutputStream::~ArrayOutputStream() {
117
bool ArrayOutputStream::Next(void** data, int* size) {
118
if (position_ < size_) {
119
last_returned_size_ = min(block_size_, size_ - position_);
120
*data = data_ + position_;
121
*size = last_returned_size_;
122
position_ += last_returned_size_;
125
// We're at the end of the array.
126
last_returned_size_ = 0; // Don't let caller back up.
131
void ArrayOutputStream::BackUp(int count) {
132
GOOGLE_CHECK_GT(last_returned_size_, 0)
133
<< "BackUp() can only be called after a successful Next().";
134
GOOGLE_CHECK_LE(count, last_returned_size_);
135
GOOGLE_CHECK_GE(count, 0);
137
last_returned_size_ = 0; // Don't let caller back up further.
140
int64 ArrayOutputStream::ByteCount() const {
144
// ===================================================================
146
StringOutputStream::StringOutputStream(string* target)
150
StringOutputStream::~StringOutputStream() {
153
bool StringOutputStream::Next(void** data, int* size) {
154
int old_size = target_->size();
157
if (old_size < target_->capacity()) {
158
// Resize the string to match its capacity, since we can get away
159
// without a memory allocation this way.
160
STLStringResizeUninitialized(target_, target_->capacity());
162
// Size has reached capacity, so double the size. Also make sure
163
// that the new size is at least kMinimumSize.
164
STLStringResizeUninitialized(
167
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
170
*data = string_as_array(target_) + old_size;
171
*size = target_->size() - old_size;
175
void StringOutputStream::BackUp(int count) {
176
GOOGLE_CHECK_GE(count, 0);
177
GOOGLE_CHECK_LE(count, target_->size());
178
target_->resize(target_->size() - count);
181
int64 StringOutputStream::ByteCount() const {
182
return target_->size();
185
// ===================================================================
187
CopyingInputStream::~CopyingInputStream() {}
189
int CopyingInputStream::Skip(int count) {
192
while (skipped < count) {
193
int bytes = Read(junk, min(count - skipped,
194
implicit_cast<int>(sizeof(junk))));
196
// EOF or read error.
204
CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
205
CopyingInputStream* copying_stream, int block_size)
206
: copying_stream_(copying_stream),
207
owns_copying_stream_(false),
210
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
215
CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
216
if (owns_copying_stream_) {
217
delete copying_stream_;
221
bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
223
// Already failed on a previous read.
227
AllocateBufferIfNeeded();
229
if (backup_bytes_ > 0) {
230
// We have data left over from a previous BackUp(), so just return that.
231
*data = buffer_.get() + buffer_used_ - backup_bytes_;
232
*size = backup_bytes_;
237
// Read new data into the buffer.
238
buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
239
if (buffer_used_ <= 0) {
240
// EOF or read error. We don't need the buffer anymore.
241
if (buffer_used_ < 0) {
242
// Read error (not EOF).
248
position_ += buffer_used_;
250
*size = buffer_used_;
251
*data = buffer_.get();
255
void CopyingInputStreamAdaptor::BackUp(int count) {
256
GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
257
<< " BackUp() can only be called after Next().";
258
GOOGLE_CHECK_LE(count, buffer_used_)
259
<< " Can't back up over more bytes than were returned by the last call"
261
GOOGLE_CHECK_GE(count, 0)
262
<< " Parameter to BackUp() can't be negative.";
264
backup_bytes_ = count;
267
bool CopyingInputStreamAdaptor::Skip(int count) {
268
GOOGLE_CHECK_GE(count, 0);
271
// Already failed on a previous read.
275
// First skip any bytes left over from a previous BackUp().
276
if (backup_bytes_ >= count) {
277
// We have more data left over than we're trying to skip. Just chop it.
278
backup_bytes_ -= count;
282
count -= backup_bytes_;
285
int skipped = copying_stream_->Skip(count);
286
position_ += skipped;
287
return skipped == count;
290
int64 CopyingInputStreamAdaptor::ByteCount() const {
291
return position_ - backup_bytes_;
294
void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
295
if (buffer_.get() == NULL) {
296
buffer_.reset(new uint8[buffer_size_]);
300
void CopyingInputStreamAdaptor::FreeBuffer() {
301
GOOGLE_CHECK_EQ(backup_bytes_, 0);
306
// ===================================================================
308
CopyingOutputStream::~CopyingOutputStream() {}
310
CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
311
CopyingOutputStream* copying_stream, int block_size)
312
: copying_stream_(copying_stream),
313
owns_copying_stream_(false),
316
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
320
CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
322
if (owns_copying_stream_) {
323
delete copying_stream_;
327
bool CopyingOutputStreamAdaptor::Flush() {
328
return WriteBuffer();
331
bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
332
if (buffer_used_ == buffer_size_) {
333
if (!WriteBuffer()) return false;
336
AllocateBufferIfNeeded();
338
*data = buffer_.get() + buffer_used_;
339
*size = buffer_size_ - buffer_used_;
340
buffer_used_ = buffer_size_;
344
void CopyingOutputStreamAdaptor::BackUp(int count) {
345
GOOGLE_CHECK_GE(count, 0);
346
GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
347
<< " BackUp() can only be called after Next().";
348
GOOGLE_CHECK_LE(count, buffer_used_)
349
<< " Can't back up over more bytes than were returned by the last call"
352
buffer_used_ -= count;
355
int64 CopyingOutputStreamAdaptor::ByteCount() const {
356
return position_ + buffer_used_;
359
bool CopyingOutputStreamAdaptor::WriteBuffer() {
361
// Already failed on a previous write.
365
if (buffer_used_ == 0) return true;
367
if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
368
position_ += buffer_used_;
378
void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
379
if (buffer_ == NULL) {
380
buffer_.reset(new uint8[buffer_size_]);
384
void CopyingOutputStreamAdaptor::FreeBuffer() {
389
// ===================================================================
392
} // namespace protobuf
393
} // namespace google