123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/speech/chunked_byte_buffer.h"
- #include <algorithm>
- #include <memory>
- #include <utility>
- #include "base/big_endian.h"
- #include "base/check_op.h"
- #include "base/lazy_instance.h"
- namespace {
- static const size_t kHeaderLength = sizeof(uint32_t);
- static_assert(sizeof(size_t) >= kHeaderLength,
- "chunked byte buffer not supported on this architecture");
- } // namespace
- namespace speech {
- ChunkedByteBuffer::ChunkedByteBuffer()
- : partial_chunk_(new Chunk()), total_bytes_stored_(0) {}
- ChunkedByteBuffer::~ChunkedByteBuffer() {
- Clear();
- }
- void ChunkedByteBuffer::Append(const uint8_t* start, size_t length) {
- size_t remaining_bytes = length;
- const uint8_t* next_data = start;
- while (remaining_bytes > 0) {
- DCHECK(partial_chunk_ != nullptr);
- size_t insert_length = 0;
- bool header_completed = false;
- bool content_completed = false;
- std::vector<uint8_t>* insert_target;
- if (partial_chunk_->header.size() < kHeaderLength) {
- const size_t bytes_to_complete_header =
- kHeaderLength - partial_chunk_->header.size();
- insert_length = std::min(bytes_to_complete_header, remaining_bytes);
- insert_target = &partial_chunk_->header;
- header_completed = (remaining_bytes >= bytes_to_complete_header);
- } else {
- DCHECK_LT(partial_chunk_->content->size(),
- partial_chunk_->ExpectedContentLength());
- const size_t bytes_to_complete_chunk =
- partial_chunk_->ExpectedContentLength() -
- partial_chunk_->content->size();
- insert_length = std::min(bytes_to_complete_chunk, remaining_bytes);
- insert_target = partial_chunk_->content.get();
- content_completed = (remaining_bytes >= bytes_to_complete_chunk);
- }
- DCHECK_GT(insert_length, 0U);
- DCHECK_LE(insert_length, remaining_bytes);
- DCHECK_LE(next_data + insert_length, start + length);
- insert_target->insert(insert_target->end(), next_data,
- next_data + insert_length);
- next_data += insert_length;
- remaining_bytes -= insert_length;
- if (header_completed) {
- DCHECK_EQ(partial_chunk_->header.size(), kHeaderLength);
- if (partial_chunk_->ExpectedContentLength() == 0) {
- // Handle zero-byte chunks.
- chunks_.push_back(std::move(partial_chunk_));
- partial_chunk_ = std::make_unique<Chunk>();
- } else {
- partial_chunk_->content->reserve(
- partial_chunk_->ExpectedContentLength());
- }
- } else if (content_completed) {
- DCHECK_EQ(partial_chunk_->content->size(),
- partial_chunk_->ExpectedContentLength());
- chunks_.push_back(std::move(partial_chunk_));
- partial_chunk_ = std::make_unique<Chunk>();
- }
- }
- DCHECK_EQ(next_data, start + length);
- total_bytes_stored_ += length;
- }
- void ChunkedByteBuffer::Append(base::StringPiece string) {
- Append(reinterpret_cast<const uint8_t*>(string.data()), string.size());
- }
- bool ChunkedByteBuffer::HasChunks() const {
- return !chunks_.empty();
- }
- std::unique_ptr<std::vector<uint8_t>> ChunkedByteBuffer::PopChunk() {
- if (chunks_.empty())
- return nullptr;
- std::unique_ptr<Chunk> chunk = std::move(*chunks_.begin());
- chunks_.erase(chunks_.begin());
- DCHECK_EQ(chunk->header.size(), kHeaderLength);
- DCHECK_EQ(chunk->content->size(), chunk->ExpectedContentLength());
- total_bytes_stored_ -= chunk->content->size();
- total_bytes_stored_ -= kHeaderLength;
- return std::move(chunk->content);
- }
- void ChunkedByteBuffer::Clear() {
- chunks_.clear();
- partial_chunk_ = std::make_unique<Chunk>();
- total_bytes_stored_ = 0;
- }
- ChunkedByteBuffer::Chunk::Chunk() : content(new std::vector<uint8_t>()) {}
- ChunkedByteBuffer::Chunk::~Chunk() {}
- size_t ChunkedByteBuffer::Chunk::ExpectedContentLength() const {
- DCHECK_EQ(header.size(), kHeaderLength);
- uint32_t content_length = 0;
- base::ReadBigEndian(&header[0], &content_length);
- return static_cast<size_t>(content_length);
- }
- } // namespace speech
|