diff --git a/src/io/devices/ZipFileDevice.cpp b/src/io/devices/ZipFileDevice.cpp index eb87844f..1e237a3f 100644 --- a/src/io/devices/ZipFileDevice.cpp +++ b/src/io/devices/ZipFileDevice.cpp @@ -94,9 +94,10 @@ void ZipFileDevice::findBlob(Entry& entry) { } } -ZipFileDevice::ZipFileDevice(std::unique_ptr filePtr) - : file(std::move(filePtr)) { - +ZipFileDevice::ZipFileDevice( + std::unique_ptr filePtr, FileSeparateFunc separateFunc +) + : file(std::move(filePtr)), separateFunc(std::move(separateFunc)) { // Searching for EOCD file->seekg(0, std::ios::end); std::streampos fileSize = file->tellg(); @@ -139,7 +140,6 @@ ZipFileDevice::ZipFileDevice(std::unique_ptr filePtr) } } - std::filesystem::path ZipFileDevice::resolve(std::string_view path) { throw std::runtime_error("unable to resolve filesystem path"); } @@ -160,17 +160,27 @@ std::unique_ptr ZipFileDevice::read(std::string_view path) { if (entry.blobOffset == 0) { findBlob(entry); } - file->seekg(entry.blobOffset); - - util::Buffer buffer(entry.compressedSize); - file->read(buffer.data(), buffer.size()); - auto memoryStream = std::make_unique(std::move(buffer)); - if (entry.compressionMethod == COMPRESSION_NONE) { - return memoryStream; - } else if (entry.compressionMethod == COMPRESSION_DEFLATE) { - return std::make_unique(std::move(memoryStream)); + std::unique_ptr srcStream; + if (separateFunc) { + // Create new istream for concurrent data reading + srcStream = separateFunc(); + srcStream->seekg(entry.blobOffset); } else { - throw std::runtime_error("unsupported compression method"); + // Read compressed data to memory if istream cannot be separated + file->seekg(entry.blobOffset); + util::Buffer buffer(entry.compressedSize); + file->read(buffer.data(), buffer.size()); + srcStream = std::make_unique(std::move(buffer)); + } + if (entry.compressionMethod == COMPRESSION_NONE) { + return srcStream; + } else if (entry.compressionMethod == COMPRESSION_DEFLATE) { + return std::make_unique(std::move(srcStream)); + } else { + throw std::runtime_error( + "unsupported compression method [" + + std::to_string(entry.compressionMethod) + "]" + ); } } diff --git a/src/io/devices/ZipFileDevice.hpp b/src/io/devices/ZipFileDevice.hpp index 88d2213c..2598c750 100644 --- a/src/io/devices/ZipFileDevice.hpp +++ b/src/io/devices/ZipFileDevice.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "Device.hpp" @@ -25,7 +26,15 @@ namespace io { bool isDirectory = false; }; public: - ZipFileDevice(std::unique_ptr file); + using FileSeparateFunc = std::function()>; + + /// @param file ZIP file seekable istream + /// @param separateFunc Optional function that creates new seekable + /// istream for the ZIP file. + ZipFileDevice( + std::unique_ptr file, + FileSeparateFunc separateFunc = nullptr + ); std::filesystem::path resolve(std::string_view path) override; std::unique_ptr write(std::string_view path) override; @@ -41,6 +50,7 @@ namespace io { std::unique_ptr list(std::string_view path) override; private: std::unique_ptr file; + FileSeparateFunc separateFunc; std::unordered_map entries; Entry readEntry();