xref: /aosp_15_r20/external/cronet/third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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: [email protected] (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/logging.h>
42 #include <google/protobuf/stubs/casts.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 
ArrayInputStream(const void * data,int size,int block_size)58 ArrayInputStream::ArrayInputStream(const void* data, int size, int block_size)
59     : data_(reinterpret_cast<const uint8_t*>(data)),
60       size_(size),
61       block_size_(block_size > 0 ? block_size : size),
62       position_(0),
63       last_returned_size_(0) {}
64 
Next(const void ** data,int * size)65 bool ArrayInputStream::Next(const void** data, int* size) {
66   if (position_ < size_) {
67     last_returned_size_ = std::min(block_size_, size_ - position_);
68     *data = data_ + position_;
69     *size = last_returned_size_;
70     position_ += last_returned_size_;
71     return true;
72   } else {
73     // We're at the end of the array.
74     last_returned_size_ = 0;  // Don't let caller back up.
75     return false;
76   }
77 }
78 
BackUp(int count)79 void ArrayInputStream::BackUp(int count) {
80   GOOGLE_CHECK_GT(last_returned_size_, 0)
81       << "BackUp() can only be called after a successful Next().";
82   GOOGLE_CHECK_LE(count, last_returned_size_);
83   GOOGLE_CHECK_GE(count, 0);
84   position_ -= count;
85   last_returned_size_ = 0;  // Don't let caller back up further.
86 }
87 
Skip(int count)88 bool ArrayInputStream::Skip(int count) {
89   GOOGLE_CHECK_GE(count, 0);
90   last_returned_size_ = 0;  // Don't let caller back up.
91   if (count > size_ - position_) {
92     position_ = size_;
93     return false;
94   } else {
95     position_ += count;
96     return true;
97   }
98 }
99 
ByteCount() const100 int64_t ArrayInputStream::ByteCount() const { return position_; }
101 
102 
103 // ===================================================================
104 
ArrayOutputStream(void * data,int size,int block_size)105 ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
106     : data_(reinterpret_cast<uint8_t*>(data)),
107       size_(size),
108       block_size_(block_size > 0 ? block_size : size),
109       position_(0),
110       last_returned_size_(0) {}
111 
Next(void ** data,int * size)112 bool ArrayOutputStream::Next(void** data, int* size) {
113   if (position_ < size_) {
114     last_returned_size_ = std::min(block_size_, size_ - position_);
115     *data = data_ + position_;
116     *size = last_returned_size_;
117     position_ += last_returned_size_;
118     return true;
119   } else {
120     // We're at the end of the array.
121     last_returned_size_ = 0;  // Don't let caller back up.
122     return false;
123   }
124 }
125 
BackUp(int count)126 void ArrayOutputStream::BackUp(int count) {
127   GOOGLE_CHECK_LE(count, last_returned_size_)
128       << "BackUp() can not exceed the size of the last Next() call.";
129   GOOGLE_CHECK_GE(count, 0);
130   position_ -= count;
131   last_returned_size_ -= count;
132 }
133 
ByteCount() const134 int64_t ArrayOutputStream::ByteCount() const { return position_; }
135 
136 // ===================================================================
137 
StringOutputStream(std::string * target)138 StringOutputStream::StringOutputStream(std::string* target) : target_(target) {}
139 
Next(void ** data,int * size)140 bool StringOutputStream::Next(void** data, int* size) {
141   GOOGLE_CHECK(target_ != NULL);
142   size_t old_size = target_->size();
143 
144   // Grow the string.
145   size_t new_size;
146   if (old_size < target_->capacity()) {
147     // Resize the string to match its capacity, since we can get away
148     // without a memory allocation this way.
149     new_size = target_->capacity();
150   } else {
151     // Size has reached capacity, try to double it.
152     new_size = old_size * 2;
153   }
154   // Avoid integer overflow in returned '*size'.
155   new_size = std::min(new_size, old_size + std::numeric_limits<int>::max());
156   // Increase the size, also make sure that it is at least kMinimumSize.
157   STLStringResizeUninitialized(
158       target_,
159       std::max(new_size,
160                kMinimumSize + 0));  // "+ 0" works around GCC4 weirdness.
161 
162   *data = mutable_string_data(target_) + old_size;
163   *size = target_->size() - old_size;
164   return true;
165 }
166 
BackUp(int count)167 void StringOutputStream::BackUp(int count) {
168   GOOGLE_CHECK_GE(count, 0);
169   GOOGLE_CHECK(target_ != NULL);
170   GOOGLE_CHECK_LE(static_cast<size_t>(count), target_->size());
171   target_->resize(target_->size() - count);
172 }
173 
ByteCount() const174 int64_t StringOutputStream::ByteCount() const {
175   GOOGLE_CHECK(target_ != NULL);
176   return target_->size();
177 }
178 
179 // ===================================================================
180 
Skip(int count)181 int CopyingInputStream::Skip(int count) {
182   char junk[4096];
183   int skipped = 0;
184   while (skipped < count) {
185     int bytes = Read(junk, std::min(count - skipped,
186                                     implicit_cast<int>(sizeof(junk))));
187     if (bytes <= 0) {
188       // EOF or read error.
189       return skipped;
190     }
191     skipped += bytes;
192   }
193   return skipped;
194 }
195 
CopyingInputStreamAdaptor(CopyingInputStream * copying_stream,int block_size)196 CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
197     CopyingInputStream* copying_stream, int block_size)
198     : copying_stream_(copying_stream),
199       owns_copying_stream_(false),
200       failed_(false),
201       position_(0),
202       buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
203       buffer_used_(0),
204       backup_bytes_(0) {}
205 
~CopyingInputStreamAdaptor()206 CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
207   if (owns_copying_stream_) {
208     delete copying_stream_;
209   }
210 }
211 
Next(const void ** data,int * size)212 bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
213   if (failed_) {
214     // Already failed on a previous read.
215     return false;
216   }
217 
218   AllocateBufferIfNeeded();
219 
220   if (backup_bytes_ > 0) {
221     // We have data left over from a previous BackUp(), so just return that.
222     *data = buffer_.get() + buffer_used_ - backup_bytes_;
223     *size = backup_bytes_;
224     backup_bytes_ = 0;
225     return true;
226   }
227 
228   // Read new data into the buffer.
229   buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
230   if (buffer_used_ <= 0) {
231     // EOF or read error.  We don't need the buffer anymore.
232     if (buffer_used_ < 0) {
233       // Read error (not EOF).
234       failed_ = true;
235     }
236     FreeBuffer();
237     return false;
238   }
239   position_ += buffer_used_;
240 
241   *size = buffer_used_;
242   *data = buffer_.get();
243   return true;
244 }
245 
BackUp(int count)246 void CopyingInputStreamAdaptor::BackUp(int count) {
247   GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
248       << " BackUp() can only be called after Next().";
249   GOOGLE_CHECK_LE(count, buffer_used_)
250       << " Can't back up over more bytes than were returned by the last call"
251          " to Next().";
252   GOOGLE_CHECK_GE(count, 0) << " Parameter to BackUp() can't be negative.";
253 
254   backup_bytes_ = count;
255 }
256 
Skip(int count)257 bool CopyingInputStreamAdaptor::Skip(int count) {
258   GOOGLE_CHECK_GE(count, 0);
259 
260   if (failed_) {
261     // Already failed on a previous read.
262     return false;
263   }
264 
265   // First skip any bytes left over from a previous BackUp().
266   if (backup_bytes_ >= count) {
267     // We have more data left over than we're trying to skip.  Just chop it.
268     backup_bytes_ -= count;
269     return true;
270   }
271 
272   count -= backup_bytes_;
273   backup_bytes_ = 0;
274 
275   int skipped = copying_stream_->Skip(count);
276   position_ += skipped;
277   return skipped == count;
278 }
279 
ByteCount() const280 int64_t CopyingInputStreamAdaptor::ByteCount() const {
281   return position_ - backup_bytes_;
282 }
283 
AllocateBufferIfNeeded()284 void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
285   if (buffer_.get() == NULL) {
286     buffer_.reset(new uint8_t[buffer_size_]);
287   }
288 }
289 
FreeBuffer()290 void CopyingInputStreamAdaptor::FreeBuffer() {
291   GOOGLE_CHECK_EQ(backup_bytes_, 0);
292   buffer_used_ = 0;
293   buffer_.reset();
294 }
295 
296 // ===================================================================
297 
CopyingOutputStreamAdaptor(CopyingOutputStream * copying_stream,int block_size)298 CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
299     CopyingOutputStream* copying_stream, int block_size)
300     : copying_stream_(copying_stream),
301       owns_copying_stream_(false),
302       failed_(false),
303       position_(0),
304       buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
305       buffer_used_(0) {}
306 
~CopyingOutputStreamAdaptor()307 CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
308   WriteBuffer();
309   if (owns_copying_stream_) {
310     delete copying_stream_;
311   }
312 }
313 
Flush()314 bool CopyingOutputStreamAdaptor::Flush() { return WriteBuffer(); }
315 
Next(void ** data,int * size)316 bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
317   if (buffer_used_ == buffer_size_) {
318     if (!WriteBuffer()) return false;
319   }
320 
321   AllocateBufferIfNeeded();
322 
323   *data = buffer_.get() + buffer_used_;
324   *size = buffer_size_ - buffer_used_;
325   buffer_used_ = buffer_size_;
326   return true;
327 }
328 
BackUp(int count)329 void CopyingOutputStreamAdaptor::BackUp(int count) {
330   if (count == 0) {
331     Flush();
332     return;
333   }
334   GOOGLE_CHECK_GE(count, 0);
335   GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
336       << " BackUp() can only be called after Next().";
337   GOOGLE_CHECK_LE(count, buffer_used_)
338       << " Can't back up over more bytes than were returned by the last call"
339          " to Next().";
340 
341   buffer_used_ -= count;
342 }
343 
ByteCount() const344 int64_t CopyingOutputStreamAdaptor::ByteCount() const {
345   return position_ + buffer_used_;
346 }
347 
WriteAliasedRaw(const void * data,int size)348 bool CopyingOutputStreamAdaptor::WriteAliasedRaw(const void* data, int size) {
349   if (size >= buffer_size_) {
350     if (!Flush() || !copying_stream_->Write(data, size)) {
351       return false;
352     }
353     GOOGLE_DCHECK_EQ(buffer_used_, 0);
354     position_ += size;
355     return true;
356   }
357 
358   void* out;
359   int out_size;
360   while (true) {
361     if (!Next(&out, &out_size)) {
362       return false;
363     }
364 
365     if (size <= out_size) {
366       std::memcpy(out, data, size);
367       BackUp(out_size - size);
368       return true;
369     }
370 
371     std::memcpy(out, data, out_size);
372     data = static_cast<const char*>(data) + out_size;
373     size -= out_size;
374   }
375   return true;
376 }
377 
378 
WriteBuffer()379 bool CopyingOutputStreamAdaptor::WriteBuffer() {
380   if (failed_) {
381     // Already failed on a previous write.
382     return false;
383   }
384 
385   if (buffer_used_ == 0) return true;
386 
387   if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
388     position_ += buffer_used_;
389     buffer_used_ = 0;
390     return true;
391   } else {
392     failed_ = true;
393     FreeBuffer();
394     return false;
395   }
396 }
397 
AllocateBufferIfNeeded()398 void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
399   if (buffer_ == NULL) {
400     buffer_.reset(new uint8_t[buffer_size_]);
401   }
402 }
403 
FreeBuffer()404 void CopyingOutputStreamAdaptor::FreeBuffer() {
405   buffer_used_ = 0;
406   buffer_.reset();
407 }
408 
409 // ===================================================================
410 
LimitingInputStream(ZeroCopyInputStream * input,int64_t limit)411 LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
412                                          int64_t limit)
413     : input_(input), limit_(limit) {
414   prior_bytes_read_ = input_->ByteCount();
415 }
416 
~LimitingInputStream()417 LimitingInputStream::~LimitingInputStream() {
418   // If we overshot the limit, back up.
419   if (limit_ < 0) input_->BackUp(-limit_);
420 }
421 
Next(const void ** data,int * size)422 bool LimitingInputStream::Next(const void** data, int* size) {
423   if (limit_ <= 0) return false;
424   if (!input_->Next(data, size)) return false;
425 
426   limit_ -= *size;
427   if (limit_ < 0) {
428     // We overshot the limit.  Reduce *size to hide the rest of the buffer.
429     *size += limit_;
430   }
431   return true;
432 }
433 
BackUp(int count)434 void LimitingInputStream::BackUp(int count) {
435   if (limit_ < 0) {
436     input_->BackUp(count - limit_);
437     limit_ = count;
438   } else {
439     input_->BackUp(count);
440     limit_ += count;
441   }
442 }
443 
Skip(int count)444 bool LimitingInputStream::Skip(int count) {
445   if (count > limit_) {
446     if (limit_ < 0) return false;
447     input_->Skip(limit_);
448     limit_ = 0;
449     return false;
450   } else {
451     if (!input_->Skip(count)) return false;
452     limit_ -= count;
453     return true;
454   }
455 }
456 
ByteCount() const457 int64_t LimitingInputStream::ByteCount() const {
458   if (limit_ < 0) {
459     return input_->ByteCount() + limit_ - prior_bytes_read_;
460   } else {
461     return input_->ByteCount() - prior_bytes_read_;
462   }
463 }
464 
465 
466 // ===================================================================
467 
468 }  // namespace io
469 }  // namespace protobuf
470 }  // namespace google
471