Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions include/zarchive/zarchivereader.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#pragma once

#include <cstdint>
#include <memory>
#include <vector>
#include <string_view>
#include <unordered_map>
#include <mutex>

#include <filesystem>
#include <fstream>
#include <istream>

#include "zarchivecommon.h"

Expand All @@ -27,6 +28,7 @@ class ZArchiveReader
};

static ZArchiveReader* OpenFromFile(const std::filesystem::path& path);
static ZArchiveReader* OpenFromStream(std::unique_ptr<std::istream>&& stream);

~ZArchiveReader();

Expand Down Expand Up @@ -60,7 +62,7 @@ class ZArchiveReader
CacheBlock* m_lruChainLast;
std::unordered_map<uint64_t, CacheBlock*> m_blockLookup;

ZArchiveReader(std::ifstream&& file, std::vector<_ZARCHIVE::CompressionOffsetRecord>&& offsetRecords, std::vector<uint8_t>&& nameTable, std::vector<_ZARCHIVE::FileDirectoryEntry>&& fileTree, uint64_t compressedDataOffset, uint64_t compressedDataSize);
ZArchiveReader(std::unique_ptr<std::istream>&& stream, std::vector<_ZARCHIVE::CompressionOffsetRecord>&& offsetRecords, std::vector<uint8_t>&& nameTable, std::vector<_ZARCHIVE::FileDirectoryEntry>&& fileTree, uint64_t compressedDataOffset, uint64_t compressedDataSize);

CacheBlock* GetCachedBlock(uint64_t blockIndex);
CacheBlock* RecycleLRUBlock(uint64_t newBlockIndex);
Expand All @@ -72,7 +74,7 @@ class ZArchiveReader

static std::string_view GetName(const std::vector<uint8_t>& nameTable, uint32_t nameOffset);

std::ifstream m_file;
std::unique_ptr<std::istream> m_stream;
std::vector<_ZARCHIVE::CompressionOffsetRecord> m_offsetRecords;
std::vector<uint8_t> m_nameTable;
std::vector<_ZARCHIVE::FileDirectoryEntry> m_fileTree;
Expand Down
48 changes: 28 additions & 20 deletions src/zarchivereader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
#include <zstd.h>
#include <cassert>

static uint64_t _ifstream_getFileSize(std::ifstream& file)
static uint64_t _istream_getFileSize(std::istream& stream)
{
file.seekg(0, std::ios_base::end);
return (uint64_t)file.tellg();
stream.seekg(0, std::ios_base::end);
return (uint64_t)stream.tellg();
}

static bool _ifstream_readBytes(std::ifstream& file, uint64_t offset, void* buffer, uint32_t size)
static bool _istream_readBytes(std::istream& stream, uint64_t offset, void* buffer, uint32_t size)
{
file.seekg(offset, std::ios_base::beg);
file.read((char*)buffer, size);
return file.gcount() == size;
stream.seekg(offset, std::ios_base::beg);
stream.read((char*)buffer, size);
return stream.gcount() == size;
}

static uint64_t _getValidElementCount(uint64_t size, uint64_t elementSize)
Expand All @@ -28,16 +28,24 @@ static uint64_t _getValidElementCount(uint64_t size, uint64_t elementSize)

ZArchiveReader* ZArchiveReader::OpenFromFile(const std::filesystem::path& path)
{
std::ifstream file;
file.open(path, std::ios_base::in | std::ios_base::binary);
if (!file.is_open())
auto file = std::make_unique<std::ifstream>(path, std::ios_base::in | std::ios_base::binary);
if (!file->is_open())
return nullptr;
uint64_t fileSize = _ifstream_getFileSize(file);

return ZArchiveReader::OpenFromStream(std::move(file));
}

ZArchiveReader* ZArchiveReader::OpenFromStream(std::unique_ptr<std::istream>&& stream)
{
if(stream == nullptr)
return nullptr;

uint64_t fileSize = _istream_getFileSize(*stream);
if (fileSize <= sizeof(_ZARCHIVE::Footer))
return nullptr;
// read footer
_ZARCHIVE::Footer footer;
if (!_ifstream_readBytes(file, fileSize - sizeof(_ZARCHIVE::Footer), &footer, sizeof(_ZARCHIVE::Footer)))
if (!_istream_readBytes(*stream, fileSize - sizeof(_ZARCHIVE::Footer), &footer, sizeof(_ZARCHIVE::Footer)))
return nullptr;
_ZARCHIVE::Footer::Deserialize(&footer, &footer);
// validate footer
Expand All @@ -63,18 +71,18 @@ ZArchiveReader* ZArchiveReader::OpenFromFile(const std::filesystem::path& path)
// read offset records
std::vector<_ZARCHIVE::CompressionOffsetRecord> offsetRecords;
offsetRecords.resize(_getValidElementCount(footer.sectionOffsetRecords.size, sizeof(_ZARCHIVE::CompressionOffsetRecord)));
if (offsetRecords.empty() || !_ifstream_readBytes(file, footer.sectionOffsetRecords.offset, offsetRecords.data(), (uint32_t)(offsetRecords.size() * sizeof(_ZARCHIVE::CompressionOffsetRecord))))
if (offsetRecords.empty() || !_istream_readBytes(*stream, footer.sectionOffsetRecords.offset, offsetRecords.data(), (uint32_t)(offsetRecords.size() * sizeof(_ZARCHIVE::CompressionOffsetRecord))))
return nullptr;
_ZARCHIVE::CompressionOffsetRecord::Deserialize(offsetRecords.data(), offsetRecords.size(), offsetRecords.data());
// read name table
std::vector<uint8_t> nameTable;
nameTable.resize(footer.sectionNames.size);
if (!_ifstream_readBytes(file, footer.sectionNames.offset, nameTable.data(), (uint32_t)(nameTable.size() * sizeof(uint8_t))))
if (!_istream_readBytes(*stream, footer.sectionNames.offset, nameTable.data(), (uint32_t)(nameTable.size() * sizeof(uint8_t))))
return nullptr;
// read file tree
std::vector<_ZARCHIVE::FileDirectoryEntry> fileTree;
fileTree.resize(_getValidElementCount(footer.sectionFileTree.size, sizeof(_ZARCHIVE::FileDirectoryEntry)));
if (fileTree.empty() || !_ifstream_readBytes(file, footer.sectionFileTree.offset, fileTree.data(), (uint32_t)(fileTree.size() * sizeof(_ZARCHIVE::FileDirectoryEntry))))
if (fileTree.empty() || !_istream_readBytes(*stream, footer.sectionFileTree.offset, fileTree.data(), (uint32_t)(fileTree.size() * sizeof(_ZARCHIVE::FileDirectoryEntry))))
return nullptr;
_ZARCHIVE::FileDirectoryEntry::Deserialize(fileTree.data(), fileTree.size(), fileTree.data());
// verify file tree
Expand All @@ -86,12 +94,12 @@ ZArchiveReader* ZArchiveReader::OpenFromFile(const std::filesystem::path& path)
// read meta data
// todo

ZArchiveReader* cfs = new ZArchiveReader(std::move(file), std::move(offsetRecords), std::move(nameTable), std::move(fileTree), footer.sectionCompressedData.offset, footer.sectionCompressedData.size);
ZArchiveReader* cfs = new ZArchiveReader(std::move(stream), std::move(offsetRecords), std::move(nameTable), std::move(fileTree), footer.sectionCompressedData.offset, footer.sectionCompressedData.size);
return cfs;
}

ZArchiveReader::ZArchiveReader(std::ifstream&& file, std::vector<_ZARCHIVE::CompressionOffsetRecord>&& offsetRecords, std::vector<uint8_t>&& nameTable, std::vector<_ZARCHIVE::FileDirectoryEntry>&& fileTree, uint64_t compressedDataOffset, uint64_t compressedDataSize) :
m_file(std::move(file)), m_offsetRecords(std::move(offsetRecords)), m_nameTable(std::move(nameTable)), m_fileTree(std::move(fileTree)),
ZArchiveReader::ZArchiveReader(std::unique_ptr<std::istream>&& stream, std::vector<_ZARCHIVE::CompressionOffsetRecord>&& offsetRecords, std::vector<uint8_t>&& nameTable, std::vector<_ZARCHIVE::FileDirectoryEntry>&& fileTree, uint64_t compressedDataOffset, uint64_t compressedDataSize) :
m_stream(std::move(stream)), m_offsetRecords(std::move(offsetRecords)), m_nameTable(std::move(nameTable)), m_fileTree(std::move(fileTree)),
m_compressedDataOffset(compressedDataOffset), m_compressedDataSize(compressedDataSize)
{
m_blockCount = (uint64_t)m_offsetRecords.size() * _ZARCHIVE::ENTRIES_PER_OFFSETRECORD;
Expand Down Expand Up @@ -338,9 +346,9 @@ bool ZArchiveReader::LoadBlock(CacheBlock* block)
if (compressedSize == _ZARCHIVE::COMPRESSED_BLOCK_SIZE)
{
// uncompressed block, read directly into cached block
return _ifstream_readBytes(m_file, offset, block->data, compressedSize);
return _istream_readBytes(*m_stream, offset, block->data, compressedSize);
}
if (!_ifstream_readBytes(m_file, offset, m_blockDecompressionBuffer.data(), compressedSize))
if (!_istream_readBytes(*m_stream, offset, m_blockDecompressionBuffer.data(), compressedSize))
return false;
// decompress
size_t outputSize = ZSTD_decompress(block->data, _ZARCHIVE::COMPRESSED_BLOCK_SIZE, m_blockDecompressionBuffer.data(), compressedSize);
Expand Down
Loading