blob: 032d3f8655b9d70e44d1626cb14bfcc6ef66028e [file] [log] [blame]
David Ghandehari878ef3e2016-11-13 21:06:36 -08001// 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.
4
5#include "content/browser/speech/chunked_byte_buffer.h"
6
7#include <algorithm>
8#include <utility>
9
Andrew Top0d1858f2019-05-15 22:01:47 -070010#include "base/big_endian.h"
11#include "base/lazy_instance.h"
David Ghandehari878ef3e2016-11-13 21:06:36 -080012#include "base/logging.h"
13
14namespace {
15
16static const size_t kHeaderLength = sizeof(uint32_t);
17
Andrew Top0d1858f2019-05-15 22:01:47 -070018static_assert(sizeof(size_t) >= kHeaderLength,
19 "chunked byte buffer not supported on this architecture");
David Ghandehari878ef3e2016-11-13 21:06:36 -080020
21} // namespace
22
23namespace content {
24
25ChunkedByteBuffer::ChunkedByteBuffer()
Kaido Kerte51ce0a2023-08-12 21:43:21 -070026 : partial_chunk_(new Chunk()), total_bytes_stored_(0) {}
David Ghandehari878ef3e2016-11-13 21:06:36 -080027
28ChunkedByteBuffer::~ChunkedByteBuffer() {
29 Clear();
30}
31
32void ChunkedByteBuffer::Append(const uint8_t* start, size_t length) {
33 size_t remaining_bytes = length;
34 const uint8_t* next_data = start;
35
36 while (remaining_bytes > 0) {
Andrew Top0d1858f2019-05-15 22:01:47 -070037 DCHECK(partial_chunk_ != nullptr);
David Ghandehari878ef3e2016-11-13 21:06:36 -080038 size_t insert_length = 0;
39 bool header_completed = false;
40 bool content_completed = false;
41 std::vector<uint8_t>* insert_target;
42
43 if (partial_chunk_->header.size() < kHeaderLength) {
44 const size_t bytes_to_complete_header =
45 kHeaderLength - partial_chunk_->header.size();
46 insert_length = std::min(bytes_to_complete_header, remaining_bytes);
47 insert_target = &partial_chunk_->header;
48 header_completed = (remaining_bytes >= bytes_to_complete_header);
49 } else {
50 DCHECK_LT(partial_chunk_->content->size(),
51 partial_chunk_->ExpectedContentLength());
52 const size_t bytes_to_complete_chunk =
53 partial_chunk_->ExpectedContentLength() -
54 partial_chunk_->content->size();
55 insert_length = std::min(bytes_to_complete_chunk, remaining_bytes);
56 insert_target = partial_chunk_->content.get();
57 content_completed = (remaining_bytes >= bytes_to_complete_chunk);
58 }
59
60 DCHECK_GT(insert_length, 0U);
61 DCHECK_LE(insert_length, remaining_bytes);
62 DCHECK_LE(next_data + insert_length, start + length);
Kaido Kerte51ce0a2023-08-12 21:43:21 -070063 insert_target->insert(insert_target->end(), next_data,
David Ghandehari878ef3e2016-11-13 21:06:36 -080064 next_data + insert_length);
65 next_data += insert_length;
66 remaining_bytes -= insert_length;
67
68 if (header_completed) {
69 DCHECK_EQ(partial_chunk_->header.size(), kHeaderLength);
70 if (partial_chunk_->ExpectedContentLength() == 0) {
71 // Handle zero-byte chunks.
Andrew Top0d1858f2019-05-15 22:01:47 -070072 chunks_.push_back(std::move(partial_chunk_));
David Ghandehari878ef3e2016-11-13 21:06:36 -080073 partial_chunk_.reset(new Chunk());
74 } else {
75 partial_chunk_->content->reserve(
76 partial_chunk_->ExpectedContentLength());
77 }
78 } else if (content_completed) {
79 DCHECK_EQ(partial_chunk_->content->size(),
80 partial_chunk_->ExpectedContentLength());
Andrew Top0d1858f2019-05-15 22:01:47 -070081 chunks_.push_back(std::move(partial_chunk_));
David Ghandehari878ef3e2016-11-13 21:06:36 -080082 partial_chunk_.reset(new Chunk());
83 }
84 }
85 DCHECK_EQ(next_data, start + length);
86 total_bytes_stored_ += length;
87}
88
Andrew Top0d1858f2019-05-15 22:01:47 -070089void ChunkedByteBuffer::Append(base::StringPiece string) {
David Ghandehari878ef3e2016-11-13 21:06:36 -080090 Append(reinterpret_cast<const uint8_t*>(string.data()), string.size());
91}
92
93bool ChunkedByteBuffer::HasChunks() const {
94 return !chunks_.empty();
95}
96
Andrew Top0d1858f2019-05-15 22:01:47 -070097std::unique_ptr<std::vector<uint8_t>> ChunkedByteBuffer::PopChunk() {
David Ghandehari878ef3e2016-11-13 21:06:36 -080098 if (chunks_.empty())
Andrew Top0d1858f2019-05-15 22:01:47 -070099 return std::unique_ptr<std::vector<uint8_t>>();
100 std::unique_ptr<Chunk> chunk = std::move(*chunks_.begin());
101 chunks_.erase(chunks_.begin());
David Ghandehari878ef3e2016-11-13 21:06:36 -0800102 DCHECK_EQ(chunk->header.size(), kHeaderLength);
103 DCHECK_EQ(chunk->content->size(), chunk->ExpectedContentLength());
104 total_bytes_stored_ -= chunk->content->size();
105 total_bytes_stored_ -= kHeaderLength;
Andrew Top0d1858f2019-05-15 22:01:47 -0700106 return std::move(chunk->content);
David Ghandehari878ef3e2016-11-13 21:06:36 -0800107}
108
109void ChunkedByteBuffer::Clear() {
110 chunks_.clear();
111 partial_chunk_.reset(new Chunk());
112 total_bytes_stored_ = 0;
113}
114
115ChunkedByteBuffer::Chunk::Chunk() : content(new std::vector<uint8_t>()) {}
116
Kaido Kerte51ce0a2023-08-12 21:43:21 -0700117ChunkedByteBuffer::Chunk::~Chunk() {}
David Ghandehari878ef3e2016-11-13 21:06:36 -0800118
119size_t ChunkedByteBuffer::Chunk::ExpectedContentLength() const {
120 DCHECK_EQ(header.size(), kHeaderLength);
Andrew Top0d1858f2019-05-15 22:01:47 -0700121 uint32_t content_length = 0;
122 base::ReadBigEndian(reinterpret_cast<const char*>(&header[0]),
123 &content_length);
124 return static_cast<size_t>(content_length);
David Ghandehari878ef3e2016-11-13 21:06:36 -0800125}
126
127} // namespace content