Home | History | Annotate | Download | only in io
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      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 (at) 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.h>
     36 #include <google/protobuf/stubs/common.h>
     37 #include <google/protobuf/stubs/stl_util-inl.h>
     38 
     39 namespace google {
     40 namespace protobuf {
     41 namespace io {
     42 
     43 namespace {
     44 
     45 // Default block size for Copying{In,Out}putStreamAdaptor.
     46 static const int kDefaultBlockSize = 8192;
     47 
     48 }  // namespace
     49 
     50 // ===================================================================
     51 
     52 ArrayInputStream::ArrayInputStream(const void* data, int size,
     53                                    int block_size)
     54   : data_(reinterpret_cast<const uint8*>(data)),
     55     size_(size),
     56     block_size_(block_size > 0 ? block_size : size),
     57     position_(0),
     58     last_returned_size_(0) {
     59 }
     60 
     61 ArrayInputStream::~ArrayInputStream() {
     62 }
     63 
     64 bool ArrayInputStream::Next(const void** data, int* size) {
     65   if (position_ < size_) {
     66     last_returned_size_ = min(block_size_, size_ - position_);
     67     *data = data_ + position_;
     68     *size = last_returned_size_;
     69     position_ += last_returned_size_;
     70     return true;
     71   } else {
     72     // We're at the end of the array.
     73     last_returned_size_ = 0;   // Don't let caller back up.
     74     return false;
     75   }
     76 }
     77 
     78 void ArrayInputStream::BackUp(int count) {
     79   GOOGLE_CHECK_GT(last_returned_size_, 0)
     80       << "BackUp() can only be called after a successful Next().";
     81   GOOGLE_CHECK_LE(count, last_returned_size_);
     82   GOOGLE_CHECK_GE(count, 0);
     83   position_ -= count;
     84   last_returned_size_ = 0;  // Don't let caller back up further.
     85 }
     86 
     87 bool ArrayInputStream::Skip(int count) {
     88   GOOGLE_CHECK_GE(count, 0);
     89   last_returned_size_ = 0;   // Don't let caller back up.
     90   if (count > size_ - position_) {
     91     position_ = size_;
     92     return false;
     93   } else {
     94     position_ += count;
     95     return true;
     96   }
     97 }
     98 
     99 int64 ArrayInputStream::ByteCount() const {
    100   return position_;
    101 }
    102 
    103 
    104 // ===================================================================
    105 
    106 ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
    107   : data_(reinterpret_cast<uint8*>(data)),
    108     size_(size),
    109     block_size_(block_size > 0 ? block_size : size),
    110     position_(0),
    111     last_returned_size_(0) {
    112 }
    113 
    114 ArrayOutputStream::~ArrayOutputStream() {
    115 }
    116 
    117 bool ArrayOutputStream::Next(void** data, int* size) {
    118   if (position_ < size_) {
    119     last_returned_size_ = min(block_size_, size_ - position_);
    120     *data = data_ + position_;
    121     *size = last_returned_size_;
    122     position_ += last_returned_size_;
    123     return true;
    124   } else {
    125     // We're at the end of the array.
    126     last_returned_size_ = 0;   // Don't let caller back up.
    127     return false;
    128   }
    129 }
    130 
    131 void ArrayOutputStream::BackUp(int count) {
    132   GOOGLE_CHECK_GT(last_returned_size_, 0)
    133       << "BackUp() can only be called after a successful Next().";
    134   GOOGLE_CHECK_LE(count, last_returned_size_);
    135   GOOGLE_CHECK_GE(count, 0);
    136   position_ -= count;
    137   last_returned_size_ = 0;  // Don't let caller back up further.
    138 }
    139 
    140 int64 ArrayOutputStream::ByteCount() const {
    141   return position_;
    142 }
    143 
    144 // ===================================================================
    145 
    146 StringOutputStream::StringOutputStream(string* target)
    147   : target_(target) {
    148 }
    149 
    150 StringOutputStream::~StringOutputStream() {
    151 }
    152 
    153 bool StringOutputStream::Next(void** data, int* size) {
    154   int old_size = target_->size();
    155 
    156   // Grow the string.
    157   if (old_size < target_->capacity()) {
    158     // Resize the string to match its capacity, since we can get away
    159     // without a memory allocation this way.
    160     STLStringResizeUninitialized(target_, target_->capacity());
    161   } else {
    162     // Size has reached capacity, so double the size.  Also make sure
    163     // that the new size is at least kMinimumSize.
    164     STLStringResizeUninitialized(
    165       target_,
    166       max(old_size * 2,
    167           kMinimumSize + 0));  // "+ 0" works around GCC4 weirdness.
    168   }
    169 
    170   *data = string_as_array(target_) + old_size;
    171   *size = target_->size() - old_size;
    172   return true;
    173 }
    174 
    175 void StringOutputStream::BackUp(int count) {
    176   GOOGLE_CHECK_GE(count, 0);
    177   GOOGLE_CHECK_LE(count, target_->size());
    178   target_->resize(target_->size() - count);
    179 }
    180 
    181 int64 StringOutputStream::ByteCount() const {
    182   return target_->size();
    183 }
    184 
    185 // ===================================================================
    186 
    187 CopyingInputStream::~CopyingInputStream() {}
    188 
    189 int CopyingInputStream::Skip(int count) {
    190   char junk[4096];
    191   int skipped = 0;
    192   while (skipped < count) {
    193     int bytes = Read(junk, min(count - skipped,
    194                                implicit_cast<int>(sizeof(junk))));
    195     if (bytes <= 0) {
    196       // EOF or read error.
    197       return skipped;
    198     }
    199     skipped += bytes;
    200   }
    201   return skipped;
    202 }
    203 
    204 CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
    205     CopyingInputStream* copying_stream, int block_size)
    206   : copying_stream_(copying_stream),
    207     owns_copying_stream_(false),
    208     failed_(false),
    209     position_(0),
    210     buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
    211     buffer_used_(0),
    212     backup_bytes_(0) {
    213 }
    214 
    215 CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
    216   if (owns_copying_stream_) {
    217     delete copying_stream_;
    218   }
    219 }
    220 
    221 bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
    222   if (failed_) {
    223     // Already failed on a previous read.
    224     return false;
    225   }
    226 
    227   AllocateBufferIfNeeded();
    228 
    229   if (backup_bytes_ > 0) {
    230     // We have data left over from a previous BackUp(), so just return that.
    231     *data = buffer_.get() + buffer_used_ - backup_bytes_;
    232     *size = backup_bytes_;
    233     backup_bytes_ = 0;
    234     return true;
    235   }
    236 
    237   // Read new data into the buffer.
    238   buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
    239   if (buffer_used_ <= 0) {
    240     // EOF or read error.  We don't need the buffer anymore.
    241     if (buffer_used_ < 0) {
    242       // Read error (not EOF).
    243       failed_ = true;
    244     }
    245     FreeBuffer();
    246     return false;
    247   }
    248   position_ += buffer_used_;
    249 
    250   *size = buffer_used_;
    251   *data = buffer_.get();
    252   return true;
    253 }
    254 
    255 void CopyingInputStreamAdaptor::BackUp(int count) {
    256   GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
    257     << " BackUp() can only be called after Next().";
    258   GOOGLE_CHECK_LE(count, buffer_used_)
    259     << " Can't back up over more bytes than were returned by the last call"
    260        " to Next().";
    261   GOOGLE_CHECK_GE(count, 0)
    262     << " Parameter to BackUp() can't be negative.";
    263 
    264   backup_bytes_ = count;
    265 }
    266 
    267 bool CopyingInputStreamAdaptor::Skip(int count) {
    268   GOOGLE_CHECK_GE(count, 0);
    269 
    270   if (failed_) {
    271     // Already failed on a previous read.
    272     return false;
    273   }
    274 
    275   // First skip any bytes left over from a previous BackUp().
    276   if (backup_bytes_ >= count) {
    277     // We have more data left over than we're trying to skip.  Just chop it.
    278     backup_bytes_ -= count;
    279     return true;
    280   }
    281 
    282   count -= backup_bytes_;
    283   backup_bytes_ = 0;
    284 
    285   int skipped = copying_stream_->Skip(count);
    286   position_ += skipped;
    287   return skipped == count;
    288 }
    289 
    290 int64 CopyingInputStreamAdaptor::ByteCount() const {
    291   return position_ - backup_bytes_;
    292 }
    293 
    294 void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
    295   if (buffer_.get() == NULL) {
    296     buffer_.reset(new uint8[buffer_size_]);
    297   }
    298 }
    299 
    300 void CopyingInputStreamAdaptor::FreeBuffer() {
    301   GOOGLE_CHECK_EQ(backup_bytes_, 0);
    302   buffer_used_ = 0;
    303   buffer_.reset();
    304 }
    305 
    306 // ===================================================================
    307 
    308 CopyingOutputStream::~CopyingOutputStream() {}
    309 
    310 CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
    311     CopyingOutputStream* copying_stream, int block_size)
    312   : copying_stream_(copying_stream),
    313     owns_copying_stream_(false),
    314     failed_(false),
    315     position_(0),
    316     buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
    317     buffer_used_(0) {
    318 }
    319 
    320 CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
    321   WriteBuffer();
    322   if (owns_copying_stream_) {
    323     delete copying_stream_;
    324   }
    325 }
    326 
    327 bool CopyingOutputStreamAdaptor::Flush() {
    328   return WriteBuffer();
    329 }
    330 
    331 bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
    332   if (buffer_used_ == buffer_size_) {
    333     if (!WriteBuffer()) return false;
    334   }
    335 
    336   AllocateBufferIfNeeded();
    337 
    338   *data = buffer_.get() + buffer_used_;
    339   *size = buffer_size_ - buffer_used_;
    340   buffer_used_ = buffer_size_;
    341   return true;
    342 }
    343 
    344 void CopyingOutputStreamAdaptor::BackUp(int count) {
    345   GOOGLE_CHECK_GE(count, 0);
    346   GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
    347     << " BackUp() can only be called after Next().";
    348   GOOGLE_CHECK_LE(count, buffer_used_)
    349     << " Can't back up over more bytes than were returned by the last call"
    350        " to Next().";
    351 
    352   buffer_used_ -= count;
    353 }
    354 
    355 int64 CopyingOutputStreamAdaptor::ByteCount() const {
    356   return position_ + buffer_used_;
    357 }
    358 
    359 bool CopyingOutputStreamAdaptor::WriteBuffer() {
    360   if (failed_) {
    361     // Already failed on a previous write.
    362     return false;
    363   }
    364 
    365   if (buffer_used_ == 0) return true;
    366 
    367   if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
    368     position_ += buffer_used_;
    369     buffer_used_ = 0;
    370     return true;
    371   } else {
    372     failed_ = true;
    373     FreeBuffer();
    374     return false;
    375   }
    376 }
    377 
    378 void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
    379   if (buffer_ == NULL) {
    380     buffer_.reset(new uint8[buffer_size_]);
    381   }
    382 }
    383 
    384 void CopyingOutputStreamAdaptor::FreeBuffer() {
    385   buffer_used_ = 0;
    386   buffer_.reset();
    387 }
    388 
    389 // ===================================================================
    390 
    391 }  // namespace io
    392 }  // namespace protobuf
    393 }  // namespace google
    394