• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
41 namespace google {
42 namespace protobuf {
43 namespace io {
44 
45 namespace {
46 
47 // Default block size for Copying{In,Out}putStreamAdaptor.
48 static const int kDefaultBlockSize = 8192;
49 
50 }  // namespace
51 
52 // ===================================================================
53 
ArrayInputStream(const void * data,int size,int block_size)54 ArrayInputStream::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 
~ArrayInputStream()63 ArrayInputStream::~ArrayInputStream() {
64 }
65 
Next(const void ** data,int * size)66 bool 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 
BackUp(int count)80 void 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 
Skip(int count)89 bool 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 
ByteCount() const101 int64 ArrayInputStream::ByteCount() const {
102   return position_;
103 }
104 
105 
106 // ===================================================================
107 
ArrayOutputStream(void * data,int size,int block_size)108 ArrayOutputStream::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 
~ArrayOutputStream()116 ArrayOutputStream::~ArrayOutputStream() {
117 }
118 
Next(void ** data,int * size)119 bool 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 
BackUp(int count)133 void 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 
ByteCount() const142 int64 ArrayOutputStream::ByteCount() const {
143   return position_;
144 }
145 
146 // ===================================================================
147 
StringOutputStream(string * target)148 StringOutputStream::StringOutputStream(string* target)
149   : target_(target) {
150 }
151 
~StringOutputStream()152 StringOutputStream::~StringOutputStream() {
153 }
154 
Next(void ** data,int * size)155 bool 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 
BackUp(int count)177 void 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 
ByteCount() const183 int64 StringOutputStream::ByteCount() const {
184   return target_->size();
185 }
186 
187 // ===================================================================
188 
~CopyingInputStream()189 CopyingInputStream::~CopyingInputStream() {}
190 
Skip(int count)191 int 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 
CopyingInputStreamAdaptor(CopyingInputStream * copying_stream,int block_size)206 CopyingInputStreamAdaptor::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 
~CopyingInputStreamAdaptor()217 CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
218   if (owns_copying_stream_) {
219     delete copying_stream_;
220   }
221 }
222 
Next(const void ** data,int * size)223 bool 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 
BackUp(int count)257 void 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 
Skip(int count)269 bool 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 
ByteCount() const292 int64 CopyingInputStreamAdaptor::ByteCount() const {
293   return position_ - backup_bytes_;
294 }
295 
AllocateBufferIfNeeded()296 void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
297   if (buffer_.get() == NULL) {
298     buffer_.reset(new uint8[buffer_size_]);
299   }
300 }
301 
FreeBuffer()302 void CopyingInputStreamAdaptor::FreeBuffer() {
303   GOOGLE_CHECK_EQ(backup_bytes_, 0);
304   buffer_used_ = 0;
305   buffer_.reset();
306 }
307 
308 // ===================================================================
309 
~CopyingOutputStream()310 CopyingOutputStream::~CopyingOutputStream() {}
311 
CopyingOutputStreamAdaptor(CopyingOutputStream * copying_stream,int block_size)312 CopyingOutputStreamAdaptor::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 
~CopyingOutputStreamAdaptor()322 CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
323   WriteBuffer();
324   if (owns_copying_stream_) {
325     delete copying_stream_;
326   }
327 }
328 
Flush()329 bool CopyingOutputStreamAdaptor::Flush() {
330   return WriteBuffer();
331 }
332 
Next(void ** data,int * size)333 bool 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 
BackUp(int count)346 void 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 
ByteCount() const357 int64 CopyingOutputStreamAdaptor::ByteCount() const {
358   return position_ + buffer_used_;
359 }
360 
WriteBuffer()361 bool 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 
AllocateBufferIfNeeded()380 void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
381   if (buffer_ == NULL) {
382     buffer_.reset(new uint8[buffer_size_]);
383   }
384 }
385 
FreeBuffer()386 void CopyingOutputStreamAdaptor::FreeBuffer() {
387   buffer_used_ = 0;
388   buffer_.reset();
389 }
390 
391 // ===================================================================
392 
393 }  // namespace io
394 }  // namespace protobuf
395 }  // namespace google
396