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 43namespace google { 44namespace protobuf { 45namespace io { 46 47namespace { 48 49// Default block size for Copying{In,Out}putStreamAdaptor. 50static const int kDefaultBlockSize = 8192; 51 52} // namespace 53 54// =================================================================== 55 56ArrayInputStream::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 65ArrayInputStream::~ArrayInputStream() { 66} 67 68bool 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 82void 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 91bool 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 103int64 ArrayInputStream::ByteCount() const { 104 return position_; 105} 106 107 108// =================================================================== 109 110ArrayOutputStream::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 118ArrayOutputStream::~ArrayOutputStream() { 119} 120 121bool 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 135void 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 144int64 ArrayOutputStream::ByteCount() const { 145 return position_; 146} 147 148// =================================================================== 149 150StringOutputStream::StringOutputStream(string* target) 151 : target_(target) { 152} 153 154StringOutputStream::~StringOutputStream() { 155} 156 157bool 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 187void 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 193int64 StringOutputStream::ByteCount() const { 194 return target_->size(); 195} 196 197// =================================================================== 198 199CopyingInputStream::~CopyingInputStream() {} 200 201int 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 216CopyingInputStreamAdaptor::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 227CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() { 228 if (owns_copying_stream_) { 229 delete copying_stream_; 230 } 231} 232 233bool 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 267void 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 279bool 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 302int64 CopyingInputStreamAdaptor::ByteCount() const { 303 return position_ - backup_bytes_; 304} 305 306void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() { 307 if (buffer_.get() == NULL) { 308 buffer_.reset(new uint8[buffer_size_]); 309 } 310} 311 312void CopyingInputStreamAdaptor::FreeBuffer() { 313 GOOGLE_CHECK_EQ(backup_bytes_, 0); 314 buffer_used_ = 0; 315 buffer_.reset(); 316} 317 318// =================================================================== 319 320CopyingOutputStream::~CopyingOutputStream() {} 321 322CopyingOutputStreamAdaptor::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 332CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() { 333 WriteBuffer(); 334 if (owns_copying_stream_) { 335 delete copying_stream_; 336 } 337} 338 339bool CopyingOutputStreamAdaptor::Flush() { 340 return WriteBuffer(); 341} 342 343bool 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 356void 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 367int64 CopyingOutputStreamAdaptor::ByteCount() const { 368 return position_ + buffer_used_; 369} 370 371bool 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 390void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() { 391 if (buffer_ == NULL) { 392 buffer_.reset(new uint8[buffer_size_]); 393 } 394} 395 396void CopyingOutputStreamAdaptor::FreeBuffer() { 397 buffer_used_ = 0; 398 buffer_.reset(); 399} 400 401// =================================================================== 402 403} // namespace io 404} // namespace protobuf 405} // namespace google 406