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/common.h>
41 #include <google/protobuf/stubs/stl_util.h>
42
43 namespace google {
44 namespace protobuf {
45 namespace io {
46
47 namespace {
48
49 // Default block size for Copying{In,Out}putStreamAdaptor.
50 static const int kDefaultBlockSize = 8192;
51
52 } // namespace
53
54 // ===================================================================
55
ArrayInputStream(const void * data,int size,int block_size)56 ArrayInputStream::ArrayInputStream(const void* data, int size,
57 int block_size)
58 : data_(reinterpret_cast<const uint8*>(data)),
59 size_(size),
60 block_size_(block_size > 0 ? block_size : size),
61 position_(0),
62 last_returned_size_(0) {
63 }
64
~ArrayInputStream()65 ArrayInputStream::~ArrayInputStream() {
66 }
67
Next(const void ** data,int * size)68 bool ArrayInputStream::Next(const void** data, int* size) {
69 if (position_ < size_) {
70 last_returned_size_ = min(block_size_, size_ - position_);
71 *data = data_ + position_;
72 *size = last_returned_size_;
73 position_ += last_returned_size_;
74 return true;
75 } else {
76 // We're at the end of the array.
77 last_returned_size_ = 0; // Don't let caller back up.
78 return false;
79 }
80 }
81
BackUp(int count)82 void ArrayInputStream::BackUp(int count) {
83 GOOGLE_CHECK_GT(last_returned_size_, 0)
84 << "BackUp() can only be called after a successful Next().";
85 GOOGLE_CHECK_LE(count, last_returned_size_);
86 GOOGLE_CHECK_GE(count, 0);
87 position_ -= count;
88 last_returned_size_ = 0; // Don't let caller back up further.
89 }
90
Skip(int count)91 bool ArrayInputStream::Skip(int count) {
92 GOOGLE_CHECK_GE(count, 0);
93 last_returned_size_ = 0; // Don't let caller back up.
94 if (count > size_ - position_) {
95 position_ = size_;
96 return false;
97 } else {
98 position_ += count;
99 return true;
100 }
101 }
102
ByteCount() const103 int64 ArrayInputStream::ByteCount() const {
104 return position_;
105 }
106
107
108 // ===================================================================
109
ArrayOutputStream(void * data,int size,int block_size)110 ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
111 : data_(reinterpret_cast<uint8*>(data)),
112 size_(size),
113 block_size_(block_size > 0 ? block_size : size),
114 position_(0),
115 last_returned_size_(0) {
116 }
117
~ArrayOutputStream()118 ArrayOutputStream::~ArrayOutputStream() {
119 }
120
Next(void ** data,int * size)121 bool ArrayOutputStream::Next(void** data, int* size) {
122 if (position_ < size_) {
123 last_returned_size_ = min(block_size_, size_ - position_);
124 *data = data_ + position_;
125 *size = last_returned_size_;
126 position_ += last_returned_size_;
127 return true;
128 } else {
129 // We're at the end of the array.
130 last_returned_size_ = 0; // Don't let caller back up.
131 return false;
132 }
133 }
134
BackUp(int count)135 void ArrayOutputStream::BackUp(int count) {
136 GOOGLE_CHECK_GT(last_returned_size_, 0)
137 << "BackUp() can only be called after a successful Next().";
138 GOOGLE_CHECK_LE(count, last_returned_size_);
139 GOOGLE_CHECK_GE(count, 0);
140 position_ -= count;
141 last_returned_size_ = 0; // Don't let caller back up further.
142 }
143
ByteCount() const144 int64 ArrayOutputStream::ByteCount() const {
145 return position_;
146 }
147
148 // ===================================================================
149
StringOutputStream(string * target)150 StringOutputStream::StringOutputStream(string* target)
151 : target_(target) {
152 }
153
~StringOutputStream()154 StringOutputStream::~StringOutputStream() {
155 }
156
Next(void ** data,int * size)157 bool StringOutputStream::Next(void** data, int* size) {
158 int old_size = target_->size();
159
160 // Grow the string.
161 if (old_size < target_->capacity()) {
162 // Resize the string to match its capacity, since we can get away
163 // without a memory allocation this way.
164 STLStringResizeUninitialized(target_, target_->capacity());
165 } else {
166 // Size has reached capacity, try to double the size.
167 if (old_size > std::numeric_limits<int>::max() / 2) {
168 // Can not double the size otherwise it is going to cause integer
169 // overflow in the expression below: old_size * 2 ";
170 GOOGLE_LOG(ERROR) << "Cannot allocate buffer larger than kint32max for "
171 << "StringOutputStream.";
172 return false;
173 }
174 // Double the size, also make sure that the new size is at least
175 // kMinimumSize.
176 STLStringResizeUninitialized(
177 target_,
178 max(old_size * 2,
179 kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
180 }
181
182 *data = mutable_string_data(target_) + old_size;
183 *size = target_->size() - old_size;
184 return true;
185 }
186
BackUp(int count)187 void StringOutputStream::BackUp(int count) {
188 GOOGLE_CHECK_GE(count, 0);
189 GOOGLE_CHECK_LE(count, target_->size());
190 target_->resize(target_->size() - count);
191 }
192
ByteCount() const193 int64 StringOutputStream::ByteCount() const {
194 return target_->size();
195 }
196
197 // ===================================================================
198
~CopyingInputStream()199 CopyingInputStream::~CopyingInputStream() {}
200
Skip(int count)201 int CopyingInputStream::Skip(int count) {
202 char junk[4096];
203 int skipped = 0;
204 while (skipped < count) {
205 int bytes = Read(junk, min(count - skipped,
206 implicit_cast<int>(sizeof(junk))));
207 if (bytes <= 0) {
208 // EOF or read error.
209 return skipped;
210 }
211 skipped += bytes;
212 }
213 return skipped;
214 }
215
CopyingInputStreamAdaptor(CopyingInputStream * copying_stream,int block_size)216 CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
217 CopyingInputStream* copying_stream, int block_size)
218 : copying_stream_(copying_stream),
219 owns_copying_stream_(false),
220 failed_(false),
221 position_(0),
222 buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
223 buffer_used_(0),
224 backup_bytes_(0) {
225 }
226
~CopyingInputStreamAdaptor()227 CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
228 if (owns_copying_stream_) {
229 delete copying_stream_;
230 }
231 }
232
Next(const void ** data,int * size)233 bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
234 if (failed_) {
235 // Already failed on a previous read.
236 return false;
237 }
238
239 AllocateBufferIfNeeded();
240
241 if (backup_bytes_ > 0) {
242 // We have data left over from a previous BackUp(), so just return that.
243 *data = buffer_.get() + buffer_used_ - backup_bytes_;
244 *size = backup_bytes_;
245 backup_bytes_ = 0;
246 return true;
247 }
248
249 // Read new data into the buffer.
250 buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
251 if (buffer_used_ <= 0) {
252 // EOF or read error. We don't need the buffer anymore.
253 if (buffer_used_ < 0) {
254 // Read error (not EOF).
255 failed_ = true;
256 }
257 FreeBuffer();
258 return false;
259 }
260 position_ += buffer_used_;
261
262 *size = buffer_used_;
263 *data = buffer_.get();
264 return true;
265 }
266
BackUp(int count)267 void CopyingInputStreamAdaptor::BackUp(int count) {
268 GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
269 << " BackUp() can only be called after Next().";
270 GOOGLE_CHECK_LE(count, buffer_used_)
271 << " Can't back up over more bytes than were returned by the last call"
272 " to Next().";
273 GOOGLE_CHECK_GE(count, 0)
274 << " Parameter to BackUp() can't be negative.";
275
276 backup_bytes_ = count;
277 }
278
Skip(int count)279 bool CopyingInputStreamAdaptor::Skip(int count) {
280 GOOGLE_CHECK_GE(count, 0);
281
282 if (failed_) {
283 // Already failed on a previous read.
284 return false;
285 }
286
287 // First skip any bytes left over from a previous BackUp().
288 if (backup_bytes_ >= count) {
289 // We have more data left over than we're trying to skip. Just chop it.
290 backup_bytes_ -= count;
291 return true;
292 }
293
294 count -= backup_bytes_;
295 backup_bytes_ = 0;
296
297 int skipped = copying_stream_->Skip(count);
298 position_ += skipped;
299 return skipped == count;
300 }
301
ByteCount() const302 int64 CopyingInputStreamAdaptor::ByteCount() const {
303 return position_ - backup_bytes_;
304 }
305
AllocateBufferIfNeeded()306 void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
307 if (buffer_.get() == NULL) {
308 buffer_.reset(new uint8[buffer_size_]);
309 }
310 }
311
FreeBuffer()312 void CopyingInputStreamAdaptor::FreeBuffer() {
313 GOOGLE_CHECK_EQ(backup_bytes_, 0);
314 buffer_used_ = 0;
315 buffer_.reset();
316 }
317
318 // ===================================================================
319
~CopyingOutputStream()320 CopyingOutputStream::~CopyingOutputStream() {}
321
CopyingOutputStreamAdaptor(CopyingOutputStream * copying_stream,int block_size)322 CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
323 CopyingOutputStream* copying_stream, int block_size)
324 : copying_stream_(copying_stream),
325 owns_copying_stream_(false),
326 failed_(false),
327 position_(0),
328 buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
329 buffer_used_(0) {
330 }
331
~CopyingOutputStreamAdaptor()332 CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
333 WriteBuffer();
334 if (owns_copying_stream_) {
335 delete copying_stream_;
336 }
337 }
338
Flush()339 bool CopyingOutputStreamAdaptor::Flush() {
340 return WriteBuffer();
341 }
342
Next(void ** data,int * size)343 bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
344 if (buffer_used_ == buffer_size_) {
345 if (!WriteBuffer()) return false;
346 }
347
348 AllocateBufferIfNeeded();
349
350 *data = buffer_.get() + buffer_used_;
351 *size = buffer_size_ - buffer_used_;
352 buffer_used_ = buffer_size_;
353 return true;
354 }
355
BackUp(int count)356 void CopyingOutputStreamAdaptor::BackUp(int count) {
357 GOOGLE_CHECK_GE(count, 0);
358 GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
359 << " BackUp() can only be called after Next().";
360 GOOGLE_CHECK_LE(count, buffer_used_)
361 << " Can't back up over more bytes than were returned by the last call"
362 " to Next().";
363
364 buffer_used_ -= count;
365 }
366
ByteCount() const367 int64 CopyingOutputStreamAdaptor::ByteCount() const {
368 return position_ + buffer_used_;
369 }
370
WriteBuffer()371 bool CopyingOutputStreamAdaptor::WriteBuffer() {
372 if (failed_) {
373 // Already failed on a previous write.
374 return false;
375 }
376
377 if (buffer_used_ == 0) return true;
378
379 if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
380 position_ += buffer_used_;
381 buffer_used_ = 0;
382 return true;
383 } else {
384 failed_ = true;
385 FreeBuffer();
386 return false;
387 }
388 }
389
AllocateBufferIfNeeded()390 void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
391 if (buffer_ == NULL) {
392 buffer_.reset(new uint8[buffer_size_]);
393 }
394 }
395
FreeBuffer()396 void CopyingOutputStreamAdaptor::FreeBuffer() {
397 buffer_used_ = 0;
398 buffer_.reset();
399 }
400
401 // ===================================================================
402
403 } // namespace io
404 } // namespace protobuf
405 } // namespace google
406