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