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