chunked_byte_buffer.cc 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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.
  4. #include "components/speech/chunked_byte_buffer.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/big_endian.h"
  9. #include "base/check_op.h"
  10. #include "base/lazy_instance.h"
  11. namespace {
  12. static const size_t kHeaderLength = sizeof(uint32_t);
  13. static_assert(sizeof(size_t) >= kHeaderLength,
  14. "chunked byte buffer not supported on this architecture");
  15. } // namespace
  16. namespace speech {
  17. ChunkedByteBuffer::ChunkedByteBuffer()
  18. : partial_chunk_(new Chunk()), total_bytes_stored_(0) {}
  19. ChunkedByteBuffer::~ChunkedByteBuffer() {
  20. Clear();
  21. }
  22. void ChunkedByteBuffer::Append(const uint8_t* start, size_t length) {
  23. size_t remaining_bytes = length;
  24. const uint8_t* next_data = start;
  25. while (remaining_bytes > 0) {
  26. DCHECK(partial_chunk_ != nullptr);
  27. size_t insert_length = 0;
  28. bool header_completed = false;
  29. bool content_completed = false;
  30. std::vector<uint8_t>* insert_target;
  31. if (partial_chunk_->header.size() < kHeaderLength) {
  32. const size_t bytes_to_complete_header =
  33. kHeaderLength - partial_chunk_->header.size();
  34. insert_length = std::min(bytes_to_complete_header, remaining_bytes);
  35. insert_target = &partial_chunk_->header;
  36. header_completed = (remaining_bytes >= bytes_to_complete_header);
  37. } else {
  38. DCHECK_LT(partial_chunk_->content->size(),
  39. partial_chunk_->ExpectedContentLength());
  40. const size_t bytes_to_complete_chunk =
  41. partial_chunk_->ExpectedContentLength() -
  42. partial_chunk_->content->size();
  43. insert_length = std::min(bytes_to_complete_chunk, remaining_bytes);
  44. insert_target = partial_chunk_->content.get();
  45. content_completed = (remaining_bytes >= bytes_to_complete_chunk);
  46. }
  47. DCHECK_GT(insert_length, 0U);
  48. DCHECK_LE(insert_length, remaining_bytes);
  49. DCHECK_LE(next_data + insert_length, start + length);
  50. insert_target->insert(insert_target->end(), next_data,
  51. next_data + insert_length);
  52. next_data += insert_length;
  53. remaining_bytes -= insert_length;
  54. if (header_completed) {
  55. DCHECK_EQ(partial_chunk_->header.size(), kHeaderLength);
  56. if (partial_chunk_->ExpectedContentLength() == 0) {
  57. // Handle zero-byte chunks.
  58. chunks_.push_back(std::move(partial_chunk_));
  59. partial_chunk_ = std::make_unique<Chunk>();
  60. } else {
  61. partial_chunk_->content->reserve(
  62. partial_chunk_->ExpectedContentLength());
  63. }
  64. } else if (content_completed) {
  65. DCHECK_EQ(partial_chunk_->content->size(),
  66. partial_chunk_->ExpectedContentLength());
  67. chunks_.push_back(std::move(partial_chunk_));
  68. partial_chunk_ = std::make_unique<Chunk>();
  69. }
  70. }
  71. DCHECK_EQ(next_data, start + length);
  72. total_bytes_stored_ += length;
  73. }
  74. void ChunkedByteBuffer::Append(base::StringPiece string) {
  75. Append(reinterpret_cast<const uint8_t*>(string.data()), string.size());
  76. }
  77. bool ChunkedByteBuffer::HasChunks() const {
  78. return !chunks_.empty();
  79. }
  80. std::unique_ptr<std::vector<uint8_t>> ChunkedByteBuffer::PopChunk() {
  81. if (chunks_.empty())
  82. return nullptr;
  83. std::unique_ptr<Chunk> chunk = std::move(*chunks_.begin());
  84. chunks_.erase(chunks_.begin());
  85. DCHECK_EQ(chunk->header.size(), kHeaderLength);
  86. DCHECK_EQ(chunk->content->size(), chunk->ExpectedContentLength());
  87. total_bytes_stored_ -= chunk->content->size();
  88. total_bytes_stored_ -= kHeaderLength;
  89. return std::move(chunk->content);
  90. }
  91. void ChunkedByteBuffer::Clear() {
  92. chunks_.clear();
  93. partial_chunk_ = std::make_unique<Chunk>();
  94. total_bytes_stored_ = 0;
  95. }
  96. ChunkedByteBuffer::Chunk::Chunk() : content(new std::vector<uint8_t>()) {}
  97. ChunkedByteBuffer::Chunk::~Chunk() {}
  98. size_t ChunkedByteBuffer::Chunk::ExpectedContentLength() const {
  99. DCHECK_EQ(header.size(), kHeaderLength);
  100. uint32_t content_length = 0;
  101. base::ReadBigEndian(&header[0], &content_length);
  102. return static_cast<size_t>(content_length);
  103. }
  104. } // namespace speech