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