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