123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- // Copyright 2021 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/web_package/web_bundle_chunked_buffer.h"
- #include <algorithm>
- #include "base/check.h"
- #include "base/memory/ptr_util.h"
- #include "base/numerics/checked_math.h"
- namespace web_package {
- namespace {
- class ChunkedBufferDataSource : public mojo::DataPipeProducer::DataSource {
- public:
- ChunkedBufferDataSource(std::unique_ptr<const WebBundleChunkedBuffer> buffer,
- uint64_t offset,
- uint64_t length)
- : buffer_(std::move(buffer)), offset_(offset), length_(length) {
- DCHECK(buffer_);
- }
- ~ChunkedBufferDataSource() override = default;
- // Disallow copy and assign.
- ChunkedBufferDataSource(const ChunkedBufferDataSource&) = delete;
- ChunkedBufferDataSource& operator=(const ChunkedBufferDataSource&) = delete;
- uint64_t GetLength() const override { return length_; }
- ReadResult Read(uint64_t offset, base::span<char> buffer) override {
- ReadResult result;
- if (offset >= length_) {
- result.result = MOJO_RESULT_OUT_OF_RANGE;
- return result;
- }
- uint64_t read_start = offset_ + offset;
- uint64_t out_size = buffer.size();
- uint64_t len = std::min(length_ - offset, out_size);
- buffer_->ReadData(read_start, len,
- reinterpret_cast<uint8_t*>(buffer.data()));
- result.bytes_read = len;
- return result;
- }
- private:
- const std::unique_ptr<const WebBundleChunkedBuffer> buffer_;
- const uint64_t offset_;
- const uint64_t length_;
- };
- } // namespace
- WebBundleChunkedBuffer::Chunk::Chunk(
- uint64_t start_pos,
- scoped_refptr<const base::RefCountedBytes> bytes)
- : start_pos_(start_pos), bytes_(std::move(bytes)) {
- DCHECK(bytes_);
- DCHECK(bytes_->size() != 0);
- DCHECK(base::CheckAdd<uint64_t>(start_pos_, bytes_->size()).IsValid());
- }
- WebBundleChunkedBuffer::Chunk::~Chunk() = default;
- WebBundleChunkedBuffer::Chunk::Chunk(const WebBundleChunkedBuffer::Chunk&) =
- default;
- WebBundleChunkedBuffer::Chunk::Chunk(WebBundleChunkedBuffer::Chunk&&) = default;
- uint64_t WebBundleChunkedBuffer::Chunk::start_pos() const {
- return start_pos_;
- }
- uint64_t WebBundleChunkedBuffer::Chunk::end_pos() const {
- return start_pos_ + bytes_->size();
- }
- uint64_t WebBundleChunkedBuffer::Chunk::size() const {
- return bytes_->size();
- }
- const uint8_t* WebBundleChunkedBuffer::Chunk::data() const {
- return bytes_->data().data();
- }
- WebBundleChunkedBuffer::WebBundleChunkedBuffer() = default;
- WebBundleChunkedBuffer::WebBundleChunkedBuffer(ChunkVector chunks)
- : chunks_(std::move(chunks)) {}
- WebBundleChunkedBuffer::~WebBundleChunkedBuffer() = default;
- void WebBundleChunkedBuffer::Append(const uint8_t* data, size_t num_bytes) {
- DCHECK(base::CheckAdd<uint64_t>(end_pos(), num_bytes).IsValid());
- if (num_bytes == 0)
- return;
- auto bytes = base::MakeRefCounted<base::RefCountedBytes>(data, num_bytes);
- chunks_.push_back(Chunk(end_pos(), std::move(bytes)));
- }
- bool WebBundleChunkedBuffer::ContainsAll(uint64_t offset,
- uint64_t length) const {
- DCHECK(base::CheckAdd<uint64_t>(offset, length).IsValid());
- if (length == 0)
- return true;
- if (offset < start_pos())
- return false;
- if (offset + length > end_pos())
- return false;
- return true;
- }
- std::unique_ptr<mojo::DataPipeProducer::DataSource>
- WebBundleChunkedBuffer::CreateDataSource(uint64_t offset,
- uint64_t max_length) const {
- uint64_t length = GetAvailableLength(offset, max_length);
- if (length == 0)
- return nullptr;
- return std::make_unique<ChunkedBufferDataSource>(
- CreatePartialBuffer(offset, length), offset, length);
- }
- uint64_t WebBundleChunkedBuffer::size() const {
- DCHECK_GE(end_pos(), start_pos());
- return end_pos() - start_pos();
- }
- WebBundleChunkedBuffer::ChunkVector::const_iterator
- WebBundleChunkedBuffer::FindChunk(uint64_t pos) const {
- if (empty())
- return chunks_.end();
- // |pos| ls before everything
- if (pos < chunks_.begin()->start_pos())
- return chunks_.end();
- // As an optimization, check the last region first
- if (chunks_.back().start_pos() <= pos) {
- if (chunks_.back().end_pos() <= pos)
- return chunks_.end();
- return chunks_.end() - 1;
- }
- // Binary search
- return std::partition_point(
- chunks_.begin(), chunks_.end(),
- [pos](const Chunk& chunk) { return chunk.end_pos() <= pos; });
- }
- std::unique_ptr<const WebBundleChunkedBuffer>
- WebBundleChunkedBuffer::CreatePartialBuffer(uint64_t offset,
- uint64_t length) const {
- DCHECK(ContainsAll(offset, length));
- ChunkVector::const_iterator it = FindChunk(offset);
- CHECK(it != chunks_.end());
- ChunkVector new_chunks;
- while (it != chunks_.end() && it->start_pos() < offset + length) {
- new_chunks.push_back(*it);
- ++it;
- }
- return base::WrapUnique(new WebBundleChunkedBuffer(std::move(new_chunks)));
- }
- bool WebBundleChunkedBuffer::empty() const {
- return chunks_.empty();
- }
- uint64_t WebBundleChunkedBuffer::start_pos() const {
- if (empty())
- return 0;
- return chunks_.front().start_pos();
- }
- uint64_t WebBundleChunkedBuffer::end_pos() const {
- if (empty())
- return 0;
- return chunks_.back().end_pos();
- }
- uint64_t WebBundleChunkedBuffer::GetAvailableLength(uint64_t offset,
- uint64_t max_length) const {
- if (offset < start_pos())
- return 0;
- if (end_pos() <= offset)
- return 0;
- return std::min(max_length, end_pos() - offset);
- }
- uint64_t WebBundleChunkedBuffer::ReadData(uint64_t offset,
- uint64_t max_length,
- uint8_t* out) const {
- uint64_t length = GetAvailableLength(offset, max_length);
- if (length == 0)
- return 0;
- ChunkVector::const_iterator it = FindChunk(offset);
- DCHECK(it != chunks_.end());
- uint64_t written = 0;
- while (length > written) {
- DCHECK(it != chunks_.end());
- uint64_t offset_in_chunk = offset + written - it->start_pos();
- uint64_t length_in_chunk =
- std::min(it->size() - offset_in_chunk, length - written);
- memcpy(out + written, it->data() + offset_in_chunk, length_in_chunk);
- written += length_in_chunk;
- ++it;
- }
- return written;
- }
- } // namespace web_package
|