// Copyright (c) 2010 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. #ifndef PDF_CHUNK_STREAM_H_ #define PDF_CHUNK_STREAM_H_ #include #include #include #include #include #include #include #include "pdf/range_set.h" namespace chrome_pdf { // This class collects a chunks of data into one data stream. Client can check // if data in certain range is available, and get missing chunks of data. template class ChunkStream { public: static constexpr uint32_t kChunkSize = N; using ChunkData = typename std::array; ChunkStream() {} ~ChunkStream() {} void SetChunkData(uint32_t chunk_index, std::unique_ptr data) { if (!data) return; if (chunk_index >= data_.size()) data_.resize(chunk_index + 1); if (!data_[chunk_index]) ++filled_chunks_count_; data_[chunk_index] = std::move(data); filled_chunks_.Union(gfx::Range(chunk_index, chunk_index + 1)); } bool ReadData(const gfx::Range& range, void* buffer) const { if (!IsRangeAvailable(range)) return false; unsigned char* data_buffer = static_cast(buffer); uint32_t start = range.start(); while (start != range.end()) { const uint32_t chunk_index = GetChunkIndex(start); const uint32_t chunk_start = start % kChunkSize; const uint32_t len = std::min(kChunkSize - chunk_start, range.end() - start); memcpy(data_buffer, data_[chunk_index]->data() + chunk_start, len); data_buffer += len; start += len; } return true; } uint32_t GetChunkIndex(uint32_t offset) const { return offset / kChunkSize; } gfx::Range GetChunksRange(uint32_t offset, uint32_t size) const { return gfx::Range(GetChunkIndex(offset), GetChunkEnd(offset + size)); } bool IsRangeAvailable(const gfx::Range& range) const { if (!range.IsValid() || range.is_reversed() || (eof_pos_ > 0 && eof_pos_ < range.end())) { return false; } if (range.is_empty()) return true; const gfx::Range chunks_range(GetChunkIndex(range.start()), GetChunkEnd(range.end())); return filled_chunks_.Contains(chunks_range); } bool IsChunkAvailable(uint32_t chunk_index) const { return filled_chunks_.Contains(chunk_index); } void set_eof_pos(uint32_t eof_pos) { eof_pos_ = eof_pos; } uint32_t eof_pos() const { return eof_pos_; } const RangeSet& filled_chunks() const { return filled_chunks_; } bool IsComplete() const { return eof_pos_ > 0 && IsRangeAvailable(gfx::Range(0, eof_pos_)); } bool IsValidChunkIndex(uint32_t chunk_index) const { return !eof_pos_ || (chunk_index <= GetChunkIndex(eof_pos_ - 1)); } void Clear() { data_.clear(); eof_pos_ = 0; filled_chunks_.Clear(); filled_chunks_count_ = 0; } uint32_t filled_chunks_count() const { return filled_chunks_count_; } uint32_t total_chunks_count() const { return GetChunkEnd(eof_pos_); } private: uint32_t GetChunkEnd(uint32_t offset) const { return (offset + kChunkSize - 1) / kChunkSize; } std::vector> data_; uint32_t eof_pos_ = 0; RangeSet filled_chunks_; uint32_t filled_chunks_count_ = 0; }; } // namespace chrome_pdf #endif // PDF_CHUNK_STREAM_H_