add ZipFileDevice (WIP)
This commit is contained in:
@@ -0,0 +1,175 @@
|
|||||||
|
#include "ZipFileDevice.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "debug/Logger.hpp"
|
||||||
|
#include "util/data_io.hpp"
|
||||||
|
|
||||||
|
static debug::Logger logger("zip-file");
|
||||||
|
|
||||||
|
using namespace io;
|
||||||
|
|
||||||
|
static constexpr uint32_t EOCD_SIGNATURE = 0x06054b50;
|
||||||
|
static constexpr uint32_t CENTRAL_DIR_SIGNATURE = 0x02014b50;
|
||||||
|
static constexpr uint32_t LOCAL_FILE_SIGNATURE = 0x04034b50;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static T read_int(std::unique_ptr<std::istream>& file) {
|
||||||
|
T value = 0;
|
||||||
|
file->read(reinterpret_cast<char*>(&value), sizeof(value));
|
||||||
|
return dataio::le2h(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void read_int(std::unique_ptr<std::istream>& file, T& value) {
|
||||||
|
file->read(reinterpret_cast<char*>(&value), sizeof(value));
|
||||||
|
value = dataio::le2h(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipFileDevice::Entry ZipFileDevice::readEntry() {
|
||||||
|
// Read entry info
|
||||||
|
Entry entry {};
|
||||||
|
read_int(file, entry.versionMadeBy);
|
||||||
|
read_int(file, entry.versionNeeded);
|
||||||
|
read_int(file, entry.flags);
|
||||||
|
read_int(file, entry.compressionMethod);
|
||||||
|
read_int(file, entry.modTime);
|
||||||
|
read_int(file, entry.modDate);
|
||||||
|
read_int(file, entry.crc32);
|
||||||
|
read_int(file, entry.compressedSize);
|
||||||
|
read_int(file, entry.uncompressedSize);
|
||||||
|
auto fileNameLength = read_int<uint16_t>(file);
|
||||||
|
auto extraFieldLength = read_int<uint16_t>(file);
|
||||||
|
auto fileCommentLength = read_int<uint16_t>(file);
|
||||||
|
read_int(file, entry.diskNumberStart);
|
||||||
|
read_int(file, entry.internalAttributes);
|
||||||
|
read_int(file, entry.externalAttributes);
|
||||||
|
read_int(file, entry.localHeaderOffset);
|
||||||
|
|
||||||
|
entry.fileName.resize(fileNameLength, '\0');
|
||||||
|
file->read(entry.fileName.data(), fileNameLength);
|
||||||
|
|
||||||
|
// Skip extra field and file comment
|
||||||
|
file->seekg(extraFieldLength + fileCommentLength, std::ios::cur);
|
||||||
|
|
||||||
|
if (entry.diskNumberStart == 0xFF) {
|
||||||
|
throw std::runtime_error("zip64 is not supported");
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZipFileDevice::findBlob(Entry& entry) {
|
||||||
|
file->seekg(entry.localHeaderOffset);
|
||||||
|
if (read_int<uint32_t>(file) != LOCAL_FILE_SIGNATURE) {
|
||||||
|
throw std::runtime_error("invalid local file signature");
|
||||||
|
}
|
||||||
|
read_int<uint16_t>(file); // version
|
||||||
|
read_int<uint16_t>(file); // flags
|
||||||
|
read_int<uint16_t>(file); // compression method
|
||||||
|
read_int<uint16_t>(file); // last modification time
|
||||||
|
read_int<uint16_t>(file); // last modification date
|
||||||
|
read_int<uint32_t>(file); // crc32
|
||||||
|
read_int<uint32_t>(file); // compressed size
|
||||||
|
read_int<uint32_t>(file); // uncompressed size
|
||||||
|
auto nameLength = read_int<uint16_t>(file);
|
||||||
|
auto extraFieldLength = read_int<uint16_t>(file);
|
||||||
|
|
||||||
|
// Skip extra field and file comment
|
||||||
|
file->seekg(nameLength + extraFieldLength, std::ios::cur);
|
||||||
|
entry.blobOffset = file->tellg();
|
||||||
|
|
||||||
|
std::cout << entry.fileName << ": " << entry.blobOffset << " " << entry.compressionMethod << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipFileDevice::ZipFileDevice(std::unique_ptr<std::istream> filePtr)
|
||||||
|
: file(std::move(filePtr)) {
|
||||||
|
|
||||||
|
// Searching for EOCD
|
||||||
|
file->seekg(0, std::ios::end);
|
||||||
|
std::streampos fileSize = file->tellg();
|
||||||
|
|
||||||
|
bool foundEOCD = false;
|
||||||
|
for (int pos = static_cast<int>(fileSize)-4; pos >= 0; --pos) {
|
||||||
|
file->seekg(pos);
|
||||||
|
if (read_int<uint32_t>(file) == EOCD_SIGNATURE) {
|
||||||
|
foundEOCD = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundEOCD) {
|
||||||
|
throw std::runtime_error("EOCD not found, ZIP file is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading EOCD
|
||||||
|
read_int<uint16_t>(file); // diskNumber
|
||||||
|
read_int<uint16_t>(file); // centralDirDisk
|
||||||
|
read_int<uint16_t>(file); // numEntriesThisDisk
|
||||||
|
auto totalEntries = read_int<uint16_t>(file);
|
||||||
|
read_int<uint32_t>(file); // centralDirSize
|
||||||
|
auto centralDirOffset = read_int<uint32_t>(file);
|
||||||
|
read_int<uint16_t>(file); // commentLength
|
||||||
|
|
||||||
|
file->seekg(centralDirOffset);
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < totalEntries; i++) {
|
||||||
|
if (read_int<uint32_t>(file) != CENTRAL_DIR_SIGNATURE) {
|
||||||
|
logger.error() << "invalid central directory entry";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Read entry info
|
||||||
|
Entry entry = readEntry();
|
||||||
|
entries[entry.fileName] = std::move(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [_, entry] : entries) {
|
||||||
|
findBlob(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::filesystem::path ZipFileDevice::resolve(std::string_view path) {
|
||||||
|
throw std::runtime_error("unable to resolve filesystem path");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<std::ostream> ZipFileDevice::write(std::string_view path) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<std::istream> ZipFileDevice::read(std::string_view path) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZipFileDevice::size(std::string_view path) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipFileDevice::exists(std::string_view path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipFileDevice::isdir(std::string_view path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipFileDevice::isfile(std::string_view path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipFileDevice::mkdir(std::string_view path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipFileDevice::mkdirs(std::string_view path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipFileDevice::remove(std::string_view path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ZipFileDevice::removeAll(std::string_view path) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<PathsGenerator> ZipFileDevice::list(std::string_view path) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "Device.hpp"
|
||||||
|
|
||||||
|
namespace io {
|
||||||
|
class ZipFileDevice : public Device {
|
||||||
|
struct Entry {
|
||||||
|
uint16_t versionMadeBy;
|
||||||
|
uint16_t versionNeeded;
|
||||||
|
uint16_t flags;
|
||||||
|
uint16_t compressionMethod;
|
||||||
|
uint16_t modTime;
|
||||||
|
uint16_t modDate;
|
||||||
|
uint32_t crc32;
|
||||||
|
uint32_t compressedSize;
|
||||||
|
uint32_t uncompressedSize;
|
||||||
|
uint16_t diskNumberStart;
|
||||||
|
uint16_t internalAttributes;
|
||||||
|
uint32_t externalAttributes;
|
||||||
|
uint32_t localHeaderOffset;
|
||||||
|
std::string fileName;
|
||||||
|
size_t blobOffset = 0;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
ZipFileDevice(std::unique_ptr<std::istream> file);
|
||||||
|
|
||||||
|
std::filesystem::path resolve(std::string_view path) override;
|
||||||
|
std::unique_ptr<std::ostream> write(std::string_view path) override;
|
||||||
|
std::unique_ptr<std::istream> read(std::string_view path) override;
|
||||||
|
size_t size(std::string_view path) override;
|
||||||
|
bool exists(std::string_view path) override;
|
||||||
|
bool isdir(std::string_view path) override;
|
||||||
|
bool isfile(std::string_view path) override;
|
||||||
|
bool mkdir(std::string_view path) override;
|
||||||
|
bool mkdirs(std::string_view path) override;
|
||||||
|
bool remove(std::string_view path) override;
|
||||||
|
uint64_t removeAll(std::string_view path) override;
|
||||||
|
std::unique_ptr<PathsGenerator> list(std::string_view path) override;
|
||||||
|
private:
|
||||||
|
std::unique_ptr<std::istream> file;
|
||||||
|
std::unordered_map<std::string, Entry> entries;
|
||||||
|
|
||||||
|
Entry readEntry();
|
||||||
|
void findBlob(Entry& entry);
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user