1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/logging.h"
8 #include "net/base/io_buffer.h"
9 #include "remoting/base/compound_buffer.h"
13 CompoundBuffer::DataChunk::DataChunk(
14 net::IOBuffer
* buffer_value
, const char* start_value
, int size_value
)
15 : buffer(buffer_value
),
20 CompoundBuffer::DataChunk::~DataChunk() {}
22 CompoundBuffer::CompoundBuffer()
27 CompoundBuffer::~CompoundBuffer() {
30 void CompoundBuffer::Clear() {
36 void CompoundBuffer::Append(net::IOBuffer
* buffer
,
37 const char* start
, int size
) {
38 // A weak check that the |start| is within |buffer|.
39 DCHECK_GE(start
, buffer
->data());
44 chunks_
.push_back(DataChunk(buffer
, start
, size
));
48 void CompoundBuffer::Append(net::IOBuffer
* buffer
, int size
) {
49 Append(buffer
, buffer
->data(), size
);
52 void CompoundBuffer::Append(const CompoundBuffer
& buffer
) {
53 for (DataChunkList::const_iterator it
= buffer
.chunks_
.begin();
54 it
!= buffer
.chunks_
.end(); ++it
) {
55 Append(it
->buffer
.get(), it
->start
, it
->size
);
59 void CompoundBuffer::Prepend(net::IOBuffer
* buffer
,
60 const char* start
, int size
) {
61 // A weak check that the |start| is within |buffer|.
62 DCHECK_GE(start
, buffer
->data());
67 chunks_
.push_front(DataChunk(buffer
, start
, size
));
71 void CompoundBuffer::Prepend(net::IOBuffer
* buffer
, int size
) {
72 Prepend(buffer
, buffer
->data(), size
);
75 void CompoundBuffer::Prepend(const CompoundBuffer
& buffer
) {
76 for (DataChunkList::const_iterator it
= buffer
.chunks_
.begin();
77 it
!= buffer
.chunks_
.end(); ++it
) {
78 Prepend(it
->buffer
.get(), it
->start
, it
->size
);
81 void CompoundBuffer::AppendCopyOf(const char* data
, int size
) {
82 net::IOBuffer
* buffer
= new net::IOBuffer(size
);
83 memcpy(buffer
->data(), data
, size
);
87 void CompoundBuffer::PrependCopyOf(const char* data
, int size
) {
88 net::IOBuffer
* buffer
= new net::IOBuffer(size
);
89 memcpy(buffer
->data(), data
, size
);
90 Prepend(buffer
, size
);
93 void CompoundBuffer::CropFront(int bytes
) {
96 if (total_bytes_
<= bytes
) {
101 total_bytes_
-= bytes
;
102 while (!chunks_
.empty() && chunks_
.front().size
<= bytes
) {
103 bytes
-= chunks_
.front().size
;
106 if (!chunks_
.empty() && bytes
> 0) {
107 chunks_
.front().start
+= bytes
;
108 chunks_
.front().size
-= bytes
;
109 DCHECK_GT(chunks_
.front().size
, 0);
115 void CompoundBuffer::CropBack(int bytes
) {
118 if (total_bytes_
<= bytes
) {
123 total_bytes_
-= bytes
;
124 while (!chunks_
.empty() && chunks_
.back().size
<= bytes
) {
125 bytes
-= chunks_
.back().size
;
128 if (!chunks_
.empty() && bytes
> 0) {
129 chunks_
.back().size
-= bytes
;
130 DCHECK_GT(chunks_
.back().size
, 0);
136 void CompoundBuffer::Lock() {
140 net::IOBufferWithSize
* CompoundBuffer::ToIOBufferWithSize() const {
141 net::IOBufferWithSize
* result
= new net::IOBufferWithSize(total_bytes_
);
142 CopyTo(result
->data(), total_bytes_
);
146 void CompoundBuffer::CopyTo(char* data
, int size
) const {
148 for (DataChunkList::const_iterator it
= chunks_
.begin();
149 it
!= chunks_
.end(); ++it
) {
150 CHECK_LE(pos
+ it
->size
, data
+ size
);
151 memcpy(pos
, it
->start
, it
->size
);
156 void CompoundBuffer::CopyFrom(const CompoundBuffer
& source
,
157 int start
, int end
) {
158 // Check that 0 <= |start| <= |end| <= |total_bytes_|.
160 DCHECK_LE(start
, end
);
161 DCHECK_LE(end
, source
.total_bytes());
169 // Iterate over chunks in the |source| and add those that we need.
171 for (DataChunkList::const_iterator it
= source
.chunks_
.begin();
172 it
!= source
.chunks_
.end(); ++it
) {
174 // Add data from the current chunk only if it is in the specified interval.
175 if (pos
+ it
->size
> start
&& pos
< end
) {
176 int relative_start
= std::max(0, start
- pos
);
177 int relative_end
= std::min(it
->size
, end
- pos
);
178 DCHECK_LE(0, relative_start
);
179 DCHECK_LT(relative_start
, relative_end
);
180 DCHECK_LE(relative_end
, it
->size
);
181 Append(it
->buffer
.get(), it
->start
+ relative_start
,
182 relative_end
- relative_start
);
187 // We've got all the data we need.
192 DCHECK_EQ(total_bytes_
, end
- start
);
195 CompoundBufferInputStream::CompoundBufferInputStream(
196 const CompoundBuffer
* buffer
)
199 current_chunk_position_(0),
201 last_returned_size_(0) {
202 DCHECK(buffer_
->locked());
205 CompoundBufferInputStream::~CompoundBufferInputStream() {
208 bool CompoundBufferInputStream::Next(const void** data
, int* size
) {
209 if (current_chunk_
< buffer_
->chunks_
.size()) {
210 // Reply with the number of bytes remaining in the current buffer.
211 const CompoundBuffer::DataChunk
& chunk
= buffer_
->chunks_
[current_chunk_
];
212 int read_size
= chunk
.size
- current_chunk_position_
;
213 *data
= chunk
.start
+ current_chunk_position_
;
218 current_chunk_position_
= 0;
219 position_
+= read_size
;
221 last_returned_size_
= read_size
;
225 DCHECK_EQ(position_
, buffer_
->total_bytes());
227 // We've reached the end of the stream. So reset |last_returned_size_|
228 // to zero to prevent any backup request.
229 // This is the same as in ArrayInputStream.
230 // See google/protobuf/io/zero_copy_stream_impl_lite.cc.
231 last_returned_size_
= 0;
235 void CompoundBufferInputStream::BackUp(int count
) {
236 DCHECK_LE(count
, last_returned_size_
);
237 DCHECK_GT(current_chunk_
, 0u);
239 // Rewind one buffer and rewind data offset by |count| bytes.
241 const CompoundBuffer::DataChunk
& chunk
= buffer_
->chunks_
[current_chunk_
];
242 current_chunk_position_
= chunk
.size
- count
;
244 DCHECK_GE(position_
, 0);
246 // Prevent additional backups.
247 last_returned_size_
= 0;
250 bool CompoundBufferInputStream::Skip(int count
) {
252 last_returned_size_
= 0;
254 while (count
> 0 && current_chunk_
< buffer_
->chunks_
.size()) {
255 const CompoundBuffer::DataChunk
& chunk
= buffer_
->chunks_
[current_chunk_
];
256 int read
= std::min(count
, chunk
.size
- current_chunk_position_
);
258 // Advance the current buffer offset and position.
259 current_chunk_position_
+= read
;
263 // If the current buffer is fully read, then advance to the next buffer.
264 if (current_chunk_position_
== chunk
.size
) {
266 current_chunk_position_
= 0;
273 int64
CompoundBufferInputStream::ByteCount() const {
277 } // namespace remoting