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.h> 36#include <google/protobuf/stubs/common.h> 37#include <google/protobuf/stubs/stl_util-inl.h> 38 39namespace google { 40namespace protobuf { 41namespace io { 42 43namespace { 44 45// Default block size for Copying{In,Out}putStreamAdaptor. 46static const int kDefaultBlockSize = 8192; 47 48} // namespace 49 50// =================================================================== 51 52ArrayInputStream::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 61ArrayInputStream::~ArrayInputStream() { 62} 63 64bool 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 78void 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 87bool 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 99int64 ArrayInputStream::ByteCount() const { 100 return position_; 101} 102 103 104// =================================================================== 105 106ArrayOutputStream::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 114ArrayOutputStream::~ArrayOutputStream() { 115} 116 117bool 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 131void 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 140int64 ArrayOutputStream::ByteCount() const { 141 return position_; 142} 143 144// =================================================================== 145 146StringOutputStream::StringOutputStream(string* target) 147 : target_(target) { 148} 149 150StringOutputStream::~StringOutputStream() { 151} 152 153bool 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 175void 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 181int64 StringOutputStream::ByteCount() const { 182 return target_->size(); 183} 184 185// =================================================================== 186 187CopyingInputStream::~CopyingInputStream() {} 188 189int 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 204CopyingInputStreamAdaptor::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 215CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() { 216 if (owns_copying_stream_) { 217 delete copying_stream_; 218 } 219} 220 221bool 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 255void 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 267bool 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 290int64 CopyingInputStreamAdaptor::ByteCount() const { 291 return position_ - backup_bytes_; 292} 293 294void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() { 295 if (buffer_.get() == NULL) { 296 buffer_.reset(new uint8[buffer_size_]); 297 } 298} 299 300void CopyingInputStreamAdaptor::FreeBuffer() { 301 GOOGLE_CHECK_EQ(backup_bytes_, 0); 302 buffer_used_ = 0; 303 buffer_.reset(); 304} 305 306// =================================================================== 307 308CopyingOutputStream::~CopyingOutputStream() {} 309 310CopyingOutputStreamAdaptor::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 320CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() { 321 WriteBuffer(); 322 if (owns_copying_stream_) { 323 delete copying_stream_; 324 } 325} 326 327bool CopyingOutputStreamAdaptor::Flush() { 328 return WriteBuffer(); 329} 330 331bool 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 344void 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 355int64 CopyingOutputStreamAdaptor::ByteCount() const { 356 return position_ + buffer_used_; 357} 358 359bool 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 378void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() { 379 if (buffer_ == NULL) { 380 buffer_.reset(new uint8[buffer_size_]); 381 } 382} 383 384void CopyingOutputStreamAdaptor::FreeBuffer() { 385 buffer_used_ = 0; 386 buffer_.reset(); 387} 388 389// =================================================================== 390 391} // namespace io 392} // namespace protobuf 393} // namespace google 394