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 #include <google/protobuf/stubs/bytestream.h> 32 33 #include <string.h> 34 #include <algorithm> 35 36 namespace google { 37 namespace protobuf { 38 namespace strings { 39 40 void ByteSource::CopyTo(ByteSink* sink, size_t n) { 41 while (n > 0) { 42 StringPiece fragment = Peek(); 43 if (fragment.empty()) { 44 GOOGLE_LOG(DFATAL) << "ByteSource::CopyTo() overran input."; 45 break; 46 } 47 std::size_t fragment_size = std::min<std::size_t>(n, fragment.size()); 48 sink->Append(fragment.data(), fragment_size); 49 Skip(fragment_size); 50 n -= fragment_size; 51 } 52 } 53 54 void ByteSink::Flush() {} 55 56 void UncheckedArrayByteSink::Append(const char* data, size_t n) { 57 if (data != dest_) { 58 // Catch cases where the pointer returned by GetAppendBuffer() was modified. 59 GOOGLE_DCHECK(!(dest_ <= data && data < (dest_ + n))) 60 << "Append() data[] overlaps with dest_[]"; 61 memcpy(dest_, data, n); 62 } 63 dest_ += n; 64 } 65 66 CheckedArrayByteSink::CheckedArrayByteSink(char* outbuf, size_t capacity) 67 : outbuf_(outbuf), capacity_(capacity), size_(0), overflowed_(false) { 68 } 69 70 void CheckedArrayByteSink::Append(const char* bytes, size_t n) { 71 size_t available = capacity_ - size_; 72 if (n > available) { 73 n = available; 74 overflowed_ = true; 75 } 76 if (n > 0 && bytes != (outbuf_ + size_)) { 77 // Catch cases where the pointer returned by GetAppendBuffer() was modified. 78 GOOGLE_DCHECK(!(outbuf_ <= bytes && bytes < (outbuf_ + capacity_))) 79 << "Append() bytes[] overlaps with outbuf_[]"; 80 memcpy(outbuf_ + size_, bytes, n); 81 } 82 size_ += n; 83 } 84 85 GrowingArrayByteSink::GrowingArrayByteSink(size_t estimated_size) 86 : capacity_(estimated_size), 87 buf_(new char[estimated_size]), 88 size_(0) { 89 } 90 91 GrowingArrayByteSink::~GrowingArrayByteSink() { 92 delete[] buf_; // Just in case the user didn't call GetBuffer. 93 } 94 95 void GrowingArrayByteSink::Append(const char* bytes, size_t n) { 96 size_t available = capacity_ - size_; 97 if (bytes != (buf_ + size_)) { 98 // Catch cases where the pointer returned by GetAppendBuffer() was modified. 99 // We need to test for this before calling Expand() which may reallocate. 100 GOOGLE_DCHECK(!(buf_ <= bytes && bytes < (buf_ + capacity_))) 101 << "Append() bytes[] overlaps with buf_[]"; 102 } 103 if (n > available) { 104 Expand(n - available); 105 } 106 if (n > 0 && bytes != (buf_ + size_)) { 107 memcpy(buf_ + size_, bytes, n); 108 } 109 size_ += n; 110 } 111 112 char* GrowingArrayByteSink::GetBuffer(size_t* nbytes) { 113 ShrinkToFit(); 114 char* b = buf_; 115 *nbytes = size_; 116 buf_ = NULL; 117 size_ = capacity_ = 0; 118 return b; 119 } 120 121 void GrowingArrayByteSink::Expand(size_t amount) { // Expand by at least 50%. 122 size_t new_capacity = std::max(capacity_ + amount, (3 * capacity_) / 2); 123 char* bigger = new char[new_capacity]; 124 memcpy(bigger, buf_, size_); 125 delete[] buf_; 126 buf_ = bigger; 127 capacity_ = new_capacity; 128 } 129 130 void GrowingArrayByteSink::ShrinkToFit() { 131 // Shrink only if the buffer is large and size_ is less than 3/4 132 // of capacity_. 133 if (capacity_ > 256 && size_ < (3 * capacity_) / 4) { 134 char* just_enough = new char[size_]; 135 memcpy(just_enough, buf_, size_); 136 delete[] buf_; 137 buf_ = just_enough; 138 capacity_ = size_; 139 } 140 } 141 142 void StringByteSink::Append(const char* data, size_t n) { 143 dest_->append(data, n); 144 } 145 146 size_t ArrayByteSource::Available() const { 147 return input_.size(); 148 } 149 150 StringPiece ArrayByteSource::Peek() { 151 return input_; 152 } 153 154 void ArrayByteSource::Skip(size_t n) { 155 GOOGLE_DCHECK_LE(n, input_.size()); 156 input_.remove_prefix(n); 157 } 158 159 LimitByteSource::LimitByteSource(ByteSource *source, size_t limit) 160 : source_(source), 161 limit_(limit) { 162 } 163 164 size_t LimitByteSource::Available() const { 165 size_t available = source_->Available(); 166 if (available > limit_) { 167 available = limit_; 168 } 169 170 return available; 171 } 172 173 StringPiece LimitByteSource::Peek() { 174 StringPiece piece(source_->Peek()); 175 if (piece.size() > limit_) { 176 piece.set(piece.data(), limit_); 177 } 178 179 return piece; 180 } 181 182 void LimitByteSource::Skip(size_t n) { 183 GOOGLE_DCHECK_LE(n, limit_); 184 source_->Skip(n); 185 limit_ -= n; 186 } 187 188 void LimitByteSource::CopyTo(ByteSink *sink, size_t n) { 189 GOOGLE_DCHECK_LE(n, limit_); 190 source_->CopyTo(sink, n); 191 limit_ -= n; 192 } 193 194 } // namespace strings 195 } // namespace protobuf 196 } // namespace google 197