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