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