Line data Source code
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/casts.h>
41 : #include <google/protobuf/stubs/common.h>
42 : #include <google/protobuf/stubs/logging.h>
43 : #include <google/protobuf/stubs/stl_util.h>
44 :
45 : namespace google {
46 : namespace protobuf {
47 : namespace io {
48 :
49 : namespace {
50 :
51 : // Default block size for Copying{In,Out}putStreamAdaptor.
52 : static const int kDefaultBlockSize = 8192;
53 :
54 : } // namespace
55 :
56 : // ===================================================================
57 :
58 55 : ArrayInputStream::ArrayInputStream(const void* data, int size,
59 : int block_size)
60 : : data_(reinterpret_cast<const uint8*>(data)),
61 : size_(size),
62 : block_size_(block_size > 0 ? block_size : size),
63 : position_(0),
64 110 : last_returned_size_(0) {
65 55 : }
66 :
67 55 : ArrayInputStream::~ArrayInputStream() {
68 55 : }
69 :
70 110 : bool ArrayInputStream::Next(const void** data, int* size) {
71 110 : if (position_ < size_) {
72 110 : last_returned_size_ = min(block_size_, size_ - position_);
73 55 : *data = data_ + position_;
74 55 : *size = last_returned_size_;
75 55 : position_ += last_returned_size_;
76 55 : return true;
77 : } else {
78 : // We're at the end of the array.
79 55 : last_returned_size_ = 0; // Don't let caller back up.
80 55 : return false;
81 : }
82 : }
83 :
84 0 : void ArrayInputStream::BackUp(int count) {
85 0 : GOOGLE_CHECK_GT(last_returned_size_, 0)
86 0 : << "BackUp() can only be called after a successful Next().";
87 0 : GOOGLE_CHECK_LE(count, last_returned_size_);
88 0 : GOOGLE_CHECK_GE(count, 0);
89 0 : position_ -= count;
90 0 : last_returned_size_ = 0; // Don't let caller back up further.
91 0 : }
92 :
93 0 : bool ArrayInputStream::Skip(int count) {
94 0 : GOOGLE_CHECK_GE(count, 0);
95 0 : last_returned_size_ = 0; // Don't let caller back up.
96 0 : if (count > size_ - position_) {
97 0 : position_ = size_;
98 0 : return false;
99 : } else {
100 0 : position_ += count;
101 0 : return true;
102 : }
103 : }
104 :
105 0 : int64 ArrayInputStream::ByteCount() const {
106 0 : return position_;
107 : }
108 :
109 :
110 : // ===================================================================
111 :
112 9 : ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
113 : : data_(reinterpret_cast<uint8*>(data)),
114 : size_(size),
115 : block_size_(block_size > 0 ? block_size : size),
116 : position_(0),
117 18 : last_returned_size_(0) {
118 9 : }
119 :
120 9 : ArrayOutputStream::~ArrayOutputStream() {
121 9 : }
122 :
123 9 : bool ArrayOutputStream::Next(void** data, int* size) {
124 9 : if (position_ < size_) {
125 18 : last_returned_size_ = min(block_size_, size_ - position_);
126 9 : *data = data_ + position_;
127 9 : *size = last_returned_size_;
128 9 : position_ += last_returned_size_;
129 9 : return true;
130 : } else {
131 : // We're at the end of the array.
132 0 : last_returned_size_ = 0; // Don't let caller back up.
133 0 : return false;
134 : }
135 : }
136 :
137 0 : void ArrayOutputStream::BackUp(int count) {
138 0 : GOOGLE_CHECK_GT(last_returned_size_, 0)
139 0 : << "BackUp() can only be called after a successful Next().";
140 0 : GOOGLE_CHECK_LE(count, last_returned_size_);
141 0 : GOOGLE_CHECK_GE(count, 0);
142 0 : position_ -= count;
143 0 : last_returned_size_ = 0; // Don't let caller back up further.
144 0 : }
145 :
146 0 : int64 ArrayOutputStream::ByteCount() const {
147 0 : return position_;
148 : }
149 :
150 : // ===================================================================
151 :
152 1227 : StringOutputStream::StringOutputStream(string* target)
153 2454 : : target_(target) {
154 1227 : }
155 :
156 1357 : StringOutputStream::~StringOutputStream() {
157 1357 : }
158 :
159 3066 : bool StringOutputStream::Next(void** data, int* size) {
160 6132 : int old_size = target_->size();
161 :
162 : // Grow the string.
163 6132 : if (old_size < target_->capacity()) {
164 : // Resize the string to match its capacity, since we can get away
165 : // without a memory allocation this way.
166 313 : STLStringResizeUninitialized(target_, target_->capacity());
167 : } else {
168 : // Size has reached capacity, try to double the size.
169 2753 : if (old_size > std::numeric_limits<int>::max() / 2) {
170 : // Can not double the size otherwise it is going to cause integer
171 : // overflow in the expression below: old_size * 2 ";
172 0 : GOOGLE_LOG(ERROR) << "Cannot allocate buffer larger than kint32max for "
173 0 : << "StringOutputStream.";
174 0 : return false;
175 : }
176 : // Double the size, also make sure that the new size is at least
177 : // kMinimumSize.
178 : STLStringResizeUninitialized(
179 : target_,
180 2753 : max(old_size * 2,
181 11012 : kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
182 : }
183 :
184 6132 : *data = mutable_string_data(target_) + old_size;
185 6132 : *size = target_->size() - old_size;
186 3066 : return true;
187 : }
188 :
189 1221 : void StringOutputStream::BackUp(int count) {
190 1221 : GOOGLE_CHECK_GE(count, 0);
191 2442 : GOOGLE_CHECK_LE(count, target_->size());
192 2442 : target_->resize(target_->size() - count);
193 1221 : }
194 :
195 0 : int64 StringOutputStream::ByteCount() const {
196 0 : return target_->size();
197 : }
198 :
199 : // ===================================================================
200 :
201 143 : CopyingInputStream::~CopyingInputStream() {}
202 :
203 0 : int CopyingInputStream::Skip(int count) {
204 : char junk[4096];
205 0 : int skipped = 0;
206 0 : while (skipped < count) {
207 0 : int bytes = Read(junk, min(count - skipped,
208 0 : implicit_cast<int>(sizeof(junk))));
209 0 : if (bytes <= 0) {
210 : // EOF or read error.
211 : return skipped;
212 : }
213 0 : skipped += bytes;
214 : }
215 : return skipped;
216 : }
217 :
218 143 : CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
219 : CopyingInputStream* copying_stream, int block_size)
220 : : copying_stream_(copying_stream),
221 : owns_copying_stream_(false),
222 : failed_(false),
223 : position_(0),
224 : buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
225 : buffer_used_(0),
226 429 : backup_bytes_(0) {
227 143 : }
228 :
229 429 : CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
230 143 : if (owns_copying_stream_) {
231 0 : delete copying_stream_;
232 : }
233 143 : }
234 :
235 214 : bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
236 214 : if (failed_) {
237 : // Already failed on a previous read.
238 : return false;
239 : }
240 :
241 214 : AllocateBufferIfNeeded();
242 :
243 214 : if (backup_bytes_ > 0) {
244 : // We have data left over from a previous BackUp(), so just return that.
245 0 : *data = buffer_.get() + buffer_used_ - backup_bytes_;
246 0 : *size = backup_bytes_;
247 0 : backup_bytes_ = 0;
248 0 : return true;
249 : }
250 :
251 : // Read new data into the buffer.
252 428 : buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
253 214 : if (buffer_used_ <= 0) {
254 : // EOF or read error. We don't need the buffer anymore.
255 86 : if (buffer_used_ < 0) {
256 : // Read error (not EOF).
257 0 : failed_ = true;
258 : }
259 86 : FreeBuffer();
260 86 : return false;
261 : }
262 128 : position_ += buffer_used_;
263 :
264 128 : *size = buffer_used_;
265 256 : *data = buffer_.get();
266 128 : return true;
267 : }
268 :
269 0 : void CopyingInputStreamAdaptor::BackUp(int count) {
270 0 : GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
271 0 : << " BackUp() can only be called after Next().";
272 0 : GOOGLE_CHECK_LE(count, buffer_used_)
273 : << " Can't back up over more bytes than were returned by the last call"
274 0 : " to Next().";
275 0 : GOOGLE_CHECK_GE(count, 0)
276 0 : << " Parameter to BackUp() can't be negative.";
277 :
278 0 : backup_bytes_ = count;
279 0 : }
280 :
281 0 : bool CopyingInputStreamAdaptor::Skip(int count) {
282 0 : GOOGLE_CHECK_GE(count, 0);
283 :
284 0 : if (failed_) {
285 : // Already failed on a previous read.
286 : return false;
287 : }
288 :
289 : // First skip any bytes left over from a previous BackUp().
290 0 : if (backup_bytes_ >= count) {
291 : // We have more data left over than we're trying to skip. Just chop it.
292 0 : backup_bytes_ -= count;
293 0 : return true;
294 : }
295 :
296 0 : count -= backup_bytes_;
297 0 : backup_bytes_ = 0;
298 :
299 0 : int skipped = copying_stream_->Skip(count);
300 0 : position_ += skipped;
301 0 : return skipped == count;
302 : }
303 :
304 0 : int64 CopyingInputStreamAdaptor::ByteCount() const {
305 0 : return position_ - backup_bytes_;
306 : }
307 :
308 214 : void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
309 428 : if (buffer_.get() == NULL) {
310 86 : buffer_.reset(new uint8[buffer_size_]);
311 : }
312 214 : }
313 :
314 86 : void CopyingInputStreamAdaptor::FreeBuffer() {
315 86 : GOOGLE_CHECK_EQ(backup_bytes_, 0);
316 86 : buffer_used_ = 0;
317 86 : buffer_.reset();
318 86 : }
319 :
320 : // ===================================================================
321 :
322 8 : CopyingOutputStream::~CopyingOutputStream() {}
323 :
324 8 : CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
325 : CopyingOutputStream* copying_stream, int block_size)
326 : : copying_stream_(copying_stream),
327 : owns_copying_stream_(false),
328 : failed_(false),
329 : position_(0),
330 : buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
331 24 : buffer_used_(0) {
332 8 : }
333 :
334 24 : CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
335 8 : WriteBuffer();
336 8 : if (owns_copying_stream_) {
337 0 : delete copying_stream_;
338 : }
339 8 : }
340 :
341 8 : bool CopyingOutputStreamAdaptor::Flush() {
342 8 : return WriteBuffer();
343 : }
344 :
345 18 : bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
346 18 : if (buffer_used_ == buffer_size_) {
347 10 : if (!WriteBuffer()) return false;
348 : }
349 :
350 18 : AllocateBufferIfNeeded();
351 :
352 36 : *data = buffer_.get() + buffer_used_;
353 18 : *size = buffer_size_ - buffer_used_;
354 18 : buffer_used_ = buffer_size_;
355 18 : return true;
356 : }
357 :
358 8 : void CopyingOutputStreamAdaptor::BackUp(int count) {
359 8 : GOOGLE_CHECK_GE(count, 0);
360 8 : GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
361 16 : << " BackUp() can only be called after Next().";
362 8 : GOOGLE_CHECK_LE(count, buffer_used_)
363 : << " Can't back up over more bytes than were returned by the last call"
364 16 : " to Next().";
365 :
366 8 : buffer_used_ -= count;
367 8 : }
368 :
369 0 : int64 CopyingOutputStreamAdaptor::ByteCount() const {
370 0 : return position_ + buffer_used_;
371 : }
372 :
373 26 : bool CopyingOutputStreamAdaptor::WriteBuffer() {
374 26 : if (failed_) {
375 : // Already failed on a previous write.
376 : return false;
377 : }
378 :
379 26 : if (buffer_used_ == 0) return true;
380 :
381 36 : if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
382 18 : position_ += buffer_used_;
383 18 : buffer_used_ = 0;
384 18 : return true;
385 : } else {
386 0 : failed_ = true;
387 0 : FreeBuffer();
388 0 : return false;
389 : }
390 : }
391 :
392 18 : void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
393 36 : if (buffer_ == NULL) {
394 8 : buffer_.reset(new uint8[buffer_size_]);
395 : }
396 18 : }
397 :
398 0 : void CopyingOutputStreamAdaptor::FreeBuffer() {
399 0 : buffer_used_ = 0;
400 0 : buffer_.reset();
401 0 : }
402 :
403 : // ===================================================================
404 :
405 : } // namespace io
406 : } // namespace protobuf
407 : } // namespace google
|