1 // Copyright (c) 2012 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.
5 #include "content/browser/speech/chunked_byte_buffer.h"
9 #include "base/basictypes.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
15 static const size_t kHeaderLength
= sizeof(uint32
);
17 static_assert(sizeof(size_t) >= kHeaderLength
,
18 "chunked byte buffer not supported on this architecture");
20 uint32
ReadBigEndian32(const uint8
* buffer
) {
21 return (static_cast<uint32
>(buffer
[3])) |
22 (static_cast<uint32
>(buffer
[2]) << 8) |
23 (static_cast<uint32
>(buffer
[1]) << 16) |
24 (static_cast<uint32
>(buffer
[0]) << 24);
31 ChunkedByteBuffer::ChunkedByteBuffer()
32 : partial_chunk_(new Chunk()),
33 total_bytes_stored_(0) {
36 ChunkedByteBuffer::~ChunkedByteBuffer() {
40 void ChunkedByteBuffer::Append(const uint8
* start
, size_t length
) {
41 size_t remaining_bytes
= length
;
42 const uint8
* next_data
= start
;
44 while (remaining_bytes
> 0) {
45 DCHECK(partial_chunk_
!= NULL
);
46 size_t insert_length
= 0;
47 bool header_completed
= false;
48 bool content_completed
= false;
49 std::vector
<uint8
>* insert_target
;
51 if (partial_chunk_
->header
.size() < kHeaderLength
) {
52 const size_t bytes_to_complete_header
=
53 kHeaderLength
- partial_chunk_
->header
.size();
54 insert_length
= std::min(bytes_to_complete_header
, remaining_bytes
);
55 insert_target
= &partial_chunk_
->header
;
56 header_completed
= (remaining_bytes
>= bytes_to_complete_header
);
58 DCHECK_LT(partial_chunk_
->content
->size(),
59 partial_chunk_
->ExpectedContentLength());
60 const size_t bytes_to_complete_chunk
=
61 partial_chunk_
->ExpectedContentLength() -
62 partial_chunk_
->content
->size();
63 insert_length
= std::min(bytes_to_complete_chunk
, remaining_bytes
);
64 insert_target
= partial_chunk_
->content
.get();
65 content_completed
= (remaining_bytes
>= bytes_to_complete_chunk
);
68 DCHECK_GT(insert_length
, 0U);
69 DCHECK_LE(insert_length
, remaining_bytes
);
70 DCHECK_LE(next_data
+ insert_length
, start
+ length
);
71 insert_target
->insert(insert_target
->end(),
73 next_data
+ insert_length
);
74 next_data
+= insert_length
;
75 remaining_bytes
-= insert_length
;
77 if (header_completed
) {
78 DCHECK_EQ(partial_chunk_
->header
.size(), kHeaderLength
);
79 if (partial_chunk_
->ExpectedContentLength() == 0) {
80 // Handle zero-byte chunks.
81 chunks_
.push_back(partial_chunk_
.release());
82 partial_chunk_
.reset(new Chunk());
84 partial_chunk_
->content
->reserve(
85 partial_chunk_
->ExpectedContentLength());
87 } else if (content_completed
) {
88 DCHECK_EQ(partial_chunk_
->content
->size(),
89 partial_chunk_
->ExpectedContentLength());
90 chunks_
.push_back(partial_chunk_
.release());
91 partial_chunk_
.reset(new Chunk());
94 DCHECK_EQ(next_data
, start
+ length
);
95 total_bytes_stored_
+= length
;
98 void ChunkedByteBuffer::Append(const std::string
& string
) {
99 Append(reinterpret_cast<const uint8
*>(string
.data()), string
.size());
102 bool ChunkedByteBuffer::HasChunks() const {
103 return !chunks_
.empty();
106 scoped_ptr
< std::vector
<uint8
> > ChunkedByteBuffer::PopChunk() {
108 return scoped_ptr
< std::vector
<uint8
> >();
109 scoped_ptr
<Chunk
> chunk(*chunks_
.begin());
110 chunks_
.weak_erase(chunks_
.begin());
111 DCHECK_EQ(chunk
->header
.size(), kHeaderLength
);
112 DCHECK_EQ(chunk
->content
->size(), chunk
->ExpectedContentLength());
113 total_bytes_stored_
-= chunk
->content
->size();
114 total_bytes_stored_
-= kHeaderLength
;
115 return chunk
->content
.Pass();
118 void ChunkedByteBuffer::Clear() {
120 partial_chunk_
.reset(new Chunk());
121 total_bytes_stored_
= 0;
124 ChunkedByteBuffer::Chunk::Chunk()
125 : content(new std::vector
<uint8
>()) {
128 ChunkedByteBuffer::Chunk::~Chunk() {
131 size_t ChunkedByteBuffer::Chunk::ExpectedContentLength() const {
132 DCHECK_EQ(header
.size(), kHeaderLength
);
133 return static_cast<size_t>(ReadBigEndian32(&header
[0]));
136 } // namespace content