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