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