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_t 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_t 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 size_t old_size = target_->size();
144
145 // Grow the string.
146 size_t new_size;
147 if (old_size < target_->capacity()) {
148 // Resize the string to match its capacity, since we can get away
149 // without a memory allocation this way.
150 new_size = target_->capacity();
151 } else {
152 // Size has reached capacity, try to double it.
153 new_size = old_size * 2;
154 }
155 // Avoid integer overflow in returned '*size'.
156 new_size = std::min(new_size, old_size + std::numeric_limits<int>::max());
157 // Increase the size, also make sure that it is at least kMinimumSize.
158 STLStringResizeUninitialized(
159 target_,
160 std::max(new_size,
161 kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
162
163 *data = mutable_string_data(target_) + old_size;
164 *size = target_->size() - old_size;
165 return true;
166 }
167
BackUp(int count)168 void StringOutputStream::BackUp(int count) {
169 GOOGLE_CHECK_GE(count, 0);
170 GOOGLE_CHECK(target_ != NULL);
171 GOOGLE_CHECK_LE(static_cast<size_t>(count), target_->size());
172 target_->resize(target_->size() - count);
173 }
174
ByteCount() const175 int64_t StringOutputStream::ByteCount() const {
176 GOOGLE_CHECK(target_ != NULL);
177 return target_->size();
178 }
179
180 // ===================================================================
181
Skip(int count)182 int CopyingInputStream::Skip(int count) {
183 char junk[4096];
184 int skipped = 0;
185 while (skipped < count) {
186 int bytes = Read(junk, std::min(count - skipped,
187 implicit_cast<int>(sizeof(junk))));
188 if (bytes <= 0) {
189 // EOF or read error.
190 return skipped;
191 }
192 skipped += bytes;
193 }
194 return skipped;
195 }
196
CopyingInputStreamAdaptor(CopyingInputStream * copying_stream,int block_size)197 CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
198 CopyingInputStream* copying_stream, int block_size)
199 : copying_stream_(copying_stream),
200 owns_copying_stream_(false),
201 failed_(false),
202 position_(0),
203 buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
204 buffer_used_(0),
205 backup_bytes_(0) {}
206
~CopyingInputStreamAdaptor()207 CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
208 if (owns_copying_stream_) {
209 delete copying_stream_;
210 }
211 }
212
Next(const void ** data,int * size)213 bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
214 if (failed_) {
215 // Already failed on a previous read.
216 return false;
217 }
218
219 AllocateBufferIfNeeded();
220
221 if (backup_bytes_ > 0) {
222 // We have data left over from a previous BackUp(), so just return that.
223 *data = buffer_.get() + buffer_used_ - backup_bytes_;
224 *size = backup_bytes_;
225 backup_bytes_ = 0;
226 return true;
227 }
228
229 // Read new data into the buffer.
230 buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
231 if (buffer_used_ <= 0) {
232 // EOF or read error. We don't need the buffer anymore.
233 if (buffer_used_ < 0) {
234 // Read error (not EOF).
235 failed_ = true;
236 }
237 FreeBuffer();
238 return false;
239 }
240 position_ += buffer_used_;
241
242 *size = buffer_used_;
243 *data = buffer_.get();
244 return true;
245 }
246
BackUp(int count)247 void CopyingInputStreamAdaptor::BackUp(int count) {
248 GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
249 << " BackUp() can only be called after Next().";
250 GOOGLE_CHECK_LE(count, buffer_used_)
251 << " Can't back up over more bytes than were returned by the last call"
252 " to Next().";
253 GOOGLE_CHECK_GE(count, 0) << " Parameter to BackUp() can't be negative.";
254
255 backup_bytes_ = count;
256 }
257
Skip(int count)258 bool CopyingInputStreamAdaptor::Skip(int count) {
259 GOOGLE_CHECK_GE(count, 0);
260
261 if (failed_) {
262 // Already failed on a previous read.
263 return false;
264 }
265
266 // First skip any bytes left over from a previous BackUp().
267 if (backup_bytes_ >= count) {
268 // We have more data left over than we're trying to skip. Just chop it.
269 backup_bytes_ -= count;
270 return true;
271 }
272
273 count -= backup_bytes_;
274 backup_bytes_ = 0;
275
276 int skipped = copying_stream_->Skip(count);
277 position_ += skipped;
278 return skipped == count;
279 }
280
ByteCount() const281 int64_t CopyingInputStreamAdaptor::ByteCount() const {
282 return position_ - backup_bytes_;
283 }
284
AllocateBufferIfNeeded()285 void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
286 if (buffer_.get() == NULL) {
287 buffer_.reset(new uint8[buffer_size_]);
288 }
289 }
290
FreeBuffer()291 void CopyingInputStreamAdaptor::FreeBuffer() {
292 GOOGLE_CHECK_EQ(backup_bytes_, 0);
293 buffer_used_ = 0;
294 buffer_.reset();
295 }
296
297 // ===================================================================
298
CopyingOutputStreamAdaptor(CopyingOutputStream * copying_stream,int block_size)299 CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
300 CopyingOutputStream* copying_stream, int block_size)
301 : copying_stream_(copying_stream),
302 owns_copying_stream_(false),
303 failed_(false),
304 position_(0),
305 buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
306 buffer_used_(0) {}
307
~CopyingOutputStreamAdaptor()308 CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
309 WriteBuffer();
310 if (owns_copying_stream_) {
311 delete copying_stream_;
312 }
313 }
314
Flush()315 bool CopyingOutputStreamAdaptor::Flush() { return WriteBuffer(); }
316
Next(void ** data,int * size)317 bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
318 if (buffer_used_ == buffer_size_) {
319 if (!WriteBuffer()) return false;
320 }
321
322 AllocateBufferIfNeeded();
323
324 *data = buffer_.get() + buffer_used_;
325 *size = buffer_size_ - buffer_used_;
326 buffer_used_ = buffer_size_;
327 return true;
328 }
329
BackUp(int count)330 void CopyingOutputStreamAdaptor::BackUp(int count) {
331 GOOGLE_CHECK_GE(count, 0);
332 GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
333 << " BackUp() can only be called after Next().";
334 GOOGLE_CHECK_LE(count, buffer_used_)
335 << " Can't back up over more bytes than were returned by the last call"
336 " to Next().";
337
338 buffer_used_ -= count;
339 }
340
ByteCount() const341 int64_t CopyingOutputStreamAdaptor::ByteCount() const {
342 return position_ + buffer_used_;
343 }
344
WriteAliasedRaw(const void * data,int size)345 bool CopyingOutputStreamAdaptor::WriteAliasedRaw(const void* data, int size) {
346 if (size >= buffer_size_) {
347 if (!Flush() || !copying_stream_->Write(data, size)) {
348 return false;
349 }
350 GOOGLE_DCHECK_EQ(buffer_used_, 0);
351 position_ += size;
352 return true;
353 }
354
355 void* out;
356 int out_size;
357 while (true) {
358 if (!Next(&out, &out_size)) {
359 return false;
360 }
361
362 if (size <= out_size) {
363 std::memcpy(out, data, size);
364 BackUp(out_size - size);
365 return true;
366 }
367
368 std::memcpy(out, data, out_size);
369 data = static_cast<const char*>(data) + out_size;
370 size -= out_size;
371 }
372 return true;
373 }
374
375
WriteBuffer()376 bool CopyingOutputStreamAdaptor::WriteBuffer() {
377 if (failed_) {
378 // Already failed on a previous write.
379 return false;
380 }
381
382 if (buffer_used_ == 0) return true;
383
384 if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
385 position_ += buffer_used_;
386 buffer_used_ = 0;
387 return true;
388 } else {
389 failed_ = true;
390 FreeBuffer();
391 return false;
392 }
393 }
394
AllocateBufferIfNeeded()395 void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
396 if (buffer_ == NULL) {
397 buffer_.reset(new uint8[buffer_size_]);
398 }
399 }
400
FreeBuffer()401 void CopyingOutputStreamAdaptor::FreeBuffer() {
402 buffer_used_ = 0;
403 buffer_.reset();
404 }
405
406 // ===================================================================
407
LimitingInputStream(ZeroCopyInputStream * input,int64 limit)408 LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
409 int64 limit)
410 : input_(input), limit_(limit) {
411 prior_bytes_read_ = input_->ByteCount();
412 }
413
~LimitingInputStream()414 LimitingInputStream::~LimitingInputStream() {
415 // If we overshot the limit, back up.
416 if (limit_ < 0) input_->BackUp(-limit_);
417 }
418
Next(const void ** data,int * size)419 bool LimitingInputStream::Next(const void** data, int* size) {
420 if (limit_ <= 0) return false;
421 if (!input_->Next(data, size)) return false;
422
423 limit_ -= *size;
424 if (limit_ < 0) {
425 // We overshot the limit. Reduce *size to hide the rest of the buffer.
426 *size += limit_;
427 }
428 return true;
429 }
430
BackUp(int count)431 void LimitingInputStream::BackUp(int count) {
432 if (limit_ < 0) {
433 input_->BackUp(count - limit_);
434 limit_ = count;
435 } else {
436 input_->BackUp(count);
437 limit_ += count;
438 }
439 }
440
Skip(int count)441 bool LimitingInputStream::Skip(int count) {
442 if (count > limit_) {
443 if (limit_ < 0) return false;
444 input_->Skip(limit_);
445 limit_ = 0;
446 return false;
447 } else {
448 if (!input_->Skip(count)) return false;
449 limit_ -= count;
450 return true;
451 }
452 }
453
ByteCount() const454 int64_t LimitingInputStream::ByteCount() const {
455 if (limit_ < 0) {
456 return input_->ByteCount() + limit_ - prior_bytes_read_;
457 } else {
458 return input_->ByteCount() - prior_bytes_read_;
459 }
460 }
461
462
463 // ===================================================================
464
465 } // namespace io
466 } // namespace protobuf
467 } // namespace google
468