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