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