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