Try to optimize things a bit
PakReader won't read everything in ReadData(), it now only reads the header and TOC. Files now need to be read in separately. Adds progress bar to europa_pack_extractor. Moved code around.
This commit is contained in:
parent
5d03f49e21
commit
fae513fdfe
|
@ -1,3 +1,6 @@
|
||||||
[submodule "third_party/libpixel"]
|
[submodule "third_party/libpixel"]
|
||||||
path = third_party/libpixel
|
path = third_party/libpixel
|
||||||
url = https://github.com/modeco80/libpixel.git
|
url = https://github.com/modeco80/libpixel.git
|
||||||
|
[submodule "third_party/indicators"]
|
||||||
|
path = third_party/indicators
|
||||||
|
url = https://github.com/p-ranav/indicators
|
||||||
|
|
|
@ -10,6 +10,7 @@ include(cmake/Policies.cmake)
|
||||||
project(EuropaTools)
|
project(EuropaTools)
|
||||||
|
|
||||||
add_subdirectory(third_party/libpixel)
|
add_subdirectory(third_party/libpixel)
|
||||||
|
add_subdirectory(third_party/indicators)
|
||||||
|
|
||||||
add_subdirectory(src/libeuropa)
|
add_subdirectory(src/libeuropa)
|
||||||
add_subdirectory(src/tools)
|
add_subdirectory(src/tools)
|
||||||
|
|
|
@ -10,9 +10,9 @@ Provides archive IO utilities and the structures.
|
||||||
|
|
||||||
## The Tools
|
## The Tools
|
||||||
|
|
||||||
### `europa_pak_extractor`
|
### `eupak`
|
||||||
|
|
||||||
Extractor for .pak and .pmdl (they use 1:1 the same format) files.
|
Swiss army knife for Europa packfiles.
|
||||||
|
|
||||||
TODO: this will be one `eupak` utility later, probably.
|
Can create, extract, and show info on them.
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma endian little
|
#pragma endian little
|
||||||
|
// Big archives need a big pattern limit
|
||||||
|
#pragma max_patterns 0x40000
|
||||||
|
|
||||||
namespace europa {
|
namespace europa {
|
||||||
|
|
||||||
|
@ -56,7 +58,7 @@ namespace europa {
|
||||||
|
|
||||||
struct PakFile {
|
struct PakFile {
|
||||||
PakHeader header;
|
PakHeader header;
|
||||||
//PakTocEntry toc[header.fileCount] @ header.tocOffset;
|
PakTocEntry toc[header.fileCount] @ header.tocOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace europa
|
} // namespace europa
|
||||||
|
|
|
@ -9,18 +9,17 @@
|
||||||
#ifndef EUROPA_IO_PAKFILE_H
|
#ifndef EUROPA_IO_PAKFILE_H
|
||||||
#define EUROPA_IO_PAKFILE_H
|
#define EUROPA_IO_PAKFILE_H
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include <europa/structs/Pak.h>
|
#include <europa/structs/Pak.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace europa::io {
|
namespace europa::io {
|
||||||
|
|
||||||
struct PakReader;
|
struct PakReader;
|
||||||
struct PakWriter;
|
struct PakWriter;
|
||||||
|
|
||||||
struct PakFile {
|
struct PakFile {
|
||||||
|
|
||||||
using DataType = std::vector<std::uint8_t>;
|
using DataType = std::vector<std::uint8_t>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,13 +42,10 @@ namespace europa::io {
|
||||||
friend PakReader;
|
friend PakReader;
|
||||||
friend PakWriter;
|
friend PakWriter;
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> data;
|
std::vector<std::uint8_t> data;
|
||||||
structs::PakTocEntry tocData;
|
structs::PakTocEntry tocData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace europa::io
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // EUROPA_IO_PAKFILE_H
|
#endif // EUROPA_IO_PAKFILE_H
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#define EUROPA_IO_PAKREADER_H
|
#define EUROPA_IO_PAKREADER_H
|
||||||
|
|
||||||
#include <europa/io/PakFile.h>
|
#include <europa/io/PakFile.h>
|
||||||
|
|
||||||
#include <europa/structs/Pak.h>
|
#include <europa/structs/Pak.h>
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
@ -20,16 +19,25 @@
|
||||||
namespace europa::io {
|
namespace europa::io {
|
||||||
|
|
||||||
struct PakReader {
|
struct PakReader {
|
||||||
|
using MapType = std::unordered_map<std::string, PakFile>;
|
||||||
|
|
||||||
explicit PakReader(std::istream& is);
|
explicit PakReader(std::istream& is);
|
||||||
|
|
||||||
void ReadData();
|
void ReadData();
|
||||||
|
|
||||||
|
void ReadFiles();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read in a specific file.
|
||||||
|
*/
|
||||||
|
void ReadFile(const std::string& file);
|
||||||
|
|
||||||
bool Invalid() const {
|
bool Invalid() const {
|
||||||
return invalid;
|
return invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, PakFile>& GetFiles() const;
|
MapType& GetFiles();
|
||||||
|
const MapType& GetFiles() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::istream& stream;
|
std::istream& stream;
|
||||||
|
@ -37,7 +45,7 @@ namespace europa::io {
|
||||||
|
|
||||||
structs::PakHeader header {};
|
structs::PakHeader header {};
|
||||||
|
|
||||||
std::unordered_map<std::string, PakFile> files;
|
MapType files;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace europa::io
|
} // namespace europa::io
|
||||||
|
|
|
@ -9,12 +9,9 @@
|
||||||
#ifndef EUROPA_IO_PAKWRITER_H
|
#ifndef EUROPA_IO_PAKWRITER_H
|
||||||
#define EUROPA_IO_PAKWRITER_H
|
#define EUROPA_IO_PAKWRITER_H
|
||||||
|
|
||||||
|
|
||||||
#include <europa/io/PakFile.h>
|
#include <europa/io/PakFile.h>
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
@ -24,12 +21,9 @@ namespace europa::io {
|
||||||
* Writer for package files.
|
* Writer for package files.
|
||||||
*/
|
*/
|
||||||
struct PakWriter {
|
struct PakWriter {
|
||||||
|
void Init(structs::PakVersion version);
|
||||||
|
|
||||||
void Init();
|
std::unordered_map<std::string, PakFile>& GetFiles();
|
||||||
|
|
||||||
void AddFile(const std::string& path, const PakFile& data);
|
|
||||||
|
|
||||||
void RemoveFile(const std::string& path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the resulting archive to the given output stream.
|
* Write the resulting archive to the given output stream.
|
||||||
|
@ -41,7 +35,6 @@ namespace europa::io {
|
||||||
std::unordered_map<std::string, PakFile> archiveFiles;
|
std::unordered_map<std::string, PakFile> archiveFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace europa::io
|
||||||
}
|
|
||||||
|
|
||||||
#endif // EUROPA_IO_PAKWRITER_H
|
#endif // EUROPA_IO_PAKWRITER_H
|
||||||
|
|
|
@ -53,20 +53,47 @@ namespace europa::structs {
|
||||||
return sizeof(magic) + static_cast<std::size_t>(headerSize);
|
return sizeof(magic) + static_cast<std::size_t>(headerSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init(PakVersion ver) {
|
/**
|
||||||
|
* Initialize this header (used when writing).
|
||||||
|
*/
|
||||||
|
void Init(PakVersion ver) noexcept {
|
||||||
// clear any junk
|
// clear any junk
|
||||||
memset(this, 0, sizeof(PakHeader));
|
memset(this, 0, sizeof(PakHeader));
|
||||||
|
|
||||||
// Copy important things.
|
// Copy important things.
|
||||||
std::memcpy(&magic[0], &VALID_MAGIC[0], sizeof(VALID_MAGIC));
|
std::memcpy(&magic[0], &VALID_MAGIC[0], sizeof(VALID_MAGIC));
|
||||||
|
|
||||||
|
// Set proper header size.
|
||||||
headerSize = sizeof(PakHeader) - (sizeof(PakHeader::VALID_MAGIC) - 1);
|
headerSize = sizeof(PakHeader) - (sizeof(PakHeader::VALID_MAGIC) - 1);
|
||||||
|
|
||||||
// Set archive version
|
// Set archive version
|
||||||
version = ver;
|
version = ver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool Valid() const noexcept {
|
||||||
|
// Magic must match.
|
||||||
|
if(std::strcmp(magic, VALID_MAGIC) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
using enum PakVersion;
|
||||||
|
|
||||||
|
// Version must match ones we support,
|
||||||
|
// otherwise it's invalid.
|
||||||
|
switch(version) {
|
||||||
|
case Starfighter:
|
||||||
|
case Ver2:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header is okay.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A Toc entry (without string. Needs to be read in seperately)
|
// A Toc entry (without string. Needs to be read in separately)
|
||||||
struct [[gnu::packed]] PakTocEntry {
|
struct [[gnu::packed]] PakTocEntry {
|
||||||
u32 offset;
|
u32 offset;
|
||||||
u32 size;
|
u32 size;
|
||||||
|
@ -77,7 +104,7 @@ namespace europa::structs {
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(PakHeader) == 0x29, "PakHeader wrong size!!");
|
static_assert(sizeof(PakHeader) == 0x29, "PakHeader wrong size!!");
|
||||||
static_assert(sizeof(PakHeader) - (sizeof(PakHeader::VALID_MAGIC) - 1) == 0x1a, "PakHeader::headerSize will be invalid");
|
static_assert(sizeof(PakHeader) - (sizeof(PakHeader::VALID_MAGIC) - 1) == 0x1a, "PakHeader::headerSize will be invalid when writing archives.");
|
||||||
static_assert(sizeof(PakTocEntry) == 0xc, "PakTocEntry wrong size!");
|
static_assert(sizeof(PakTocEntry) == 0xc, "PakTocEntry wrong size!");
|
||||||
|
|
||||||
} // namespace europa::structs
|
} // namespace europa::structs
|
||||||
|
|
|
@ -37,6 +37,6 @@ namespace europa::util {
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
FixedString(char const (&)[N]) -> FixedString<N - 1>;
|
FixedString(char const (&)[N]) -> FixedString<N - 1>;
|
||||||
|
|
||||||
}
|
} // namespace europa::util
|
||||||
|
|
||||||
#endif // EUROPA_UTIL_FIXEDSTRING_H
|
#endif // EUROPA_UTIL_FIXEDSTRING_H
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
#ifndef EUROPA_FOURCC_H
|
#ifndef EUROPA_FOURCC_H
|
||||||
#define EUROPA_FOURCC_H
|
#define EUROPA_FOURCC_H
|
||||||
|
|
||||||
#include <bit>
|
|
||||||
|
|
||||||
#include <europa/util/FixedString.h>
|
#include <europa/util/FixedString.h>
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
|
||||||
namespace europa::util {
|
namespace europa::util {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,6 +36,6 @@ namespace europa::util {
|
||||||
return 0xffffffff;
|
return 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace europa::util
|
||||||
|
|
||||||
#endif // EUROPA_FOURCC_H
|
#endif // EUROPA_FOURCC_H
|
||||||
|
|
|
@ -18,7 +18,6 @@ namespace europa::io {
|
||||||
return tocData;
|
return tocData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
structs::PakTocEntry& PakFile::GetTOCEntry() {
|
structs::PakTocEntry& PakFile::GetTOCEntry() {
|
||||||
return tocData;
|
return tocData;
|
||||||
}
|
}
|
||||||
|
@ -31,4 +30,4 @@ namespace europa::io {
|
||||||
tocData.size = static_cast<std::uint32_t>(data.size());
|
tocData.size = static_cast<std::uint32_t>(data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace europa::io
|
|
@ -20,57 +20,51 @@ namespace europa::io {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PakReader::ReadData() {
|
void PakReader::ReadData() {
|
||||||
auto ReadHeader = [&]() {
|
|
||||||
header = impl::ReadStreamType<structs::PakHeader>(stream);
|
header = impl::ReadStreamType<structs::PakHeader>(stream);
|
||||||
};
|
|
||||||
|
|
||||||
auto ReadTocEntry = [&]() {
|
if(!header.Valid()) {
|
||||||
|
invalid = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the archive TOC
|
||||||
|
stream.seekg(header.tocOffset, std::istream::beg);
|
||||||
|
for(auto i = 0; i < header.fileCount; ++i) {
|
||||||
// The first part of the TOC entry is a VLE string,
|
// The first part of the TOC entry is a VLE string,
|
||||||
// which we don't store inside the type (because we can't)
|
// which we don't store inside the type (because we can't)
|
||||||
//
|
//
|
||||||
// Read this in first.
|
// Read this in first.
|
||||||
auto filename = impl::ReadPString(stream);
|
auto filename = impl::ReadPString(stream);
|
||||||
|
|
||||||
files[filename].GetTOCEntry() = impl::ReadStreamType<structs::PakTocEntry>(stream);
|
files[filename].GetTOCEntry() = impl::ReadStreamType<structs::PakTocEntry>(stream);
|
||||||
};
|
}
|
||||||
|
|
||||||
ReadHeader();
|
|
||||||
|
|
||||||
// Validate the archive header
|
|
||||||
if(std::strcmp(header.magic, structs::PakHeader::VALID_MAGIC) != 0) {
|
|
||||||
invalid = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(header.version) {
|
void PakReader::ReadFiles() {
|
||||||
case structs::PakVersion::Starfighter:
|
for(auto& [filename, file] : files)
|
||||||
case structs::PakVersion::Ver2:
|
ReadFile(filename);
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
invalid = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.seekg(header.tocOffset, std::istream::beg);
|
void PakReader::ReadFile(const std::string& file) {
|
||||||
|
auto& fileObject = files[file];
|
||||||
|
|
||||||
// Read the archive TOC
|
// This file was already read in, or has data
|
||||||
for(auto i = 0; i < header.fileCount; ++i)
|
// the user may not want to overwrite.
|
||||||
ReadTocEntry();
|
if(!fileObject.data.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
// Read all file data in
|
auto& toc = fileObject.GetTOCEntry();
|
||||||
for(auto& [filename, file] : files) {
|
fileObject.data.resize(toc.size);
|
||||||
auto& toc = file.GetTOCEntry();
|
|
||||||
file.data.resize(toc.size);
|
|
||||||
|
|
||||||
stream.seekg(toc.offset, std::istream::beg);
|
stream.seekg(toc.offset, std::istream::beg);
|
||||||
stream.read(reinterpret_cast<char*>(&file.data[0]), toc.size);
|
stream.read(reinterpret_cast<char*>(&fileObject.data[0]), toc.size);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, PakFile>& PakReader::GetFiles() const {
|
PakReader::MapType& PakReader::GetFiles() {
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PakReader::MapType& PakReader::GetFiles() const {
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace europa::io
|
} // namespace europa::io
|
|
@ -7,24 +7,20 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <europa/io/PakWriter.h>
|
#include <europa/io/PakWriter.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "StreamUtils.h"
|
#include "StreamUtils.h"
|
||||||
|
|
||||||
namespace europa::io {
|
namespace europa::io {
|
||||||
|
|
||||||
|
void PakWriter::Init(structs::PakVersion version) {
|
||||||
void PakWriter::Init() {
|
|
||||||
// for now.
|
// for now.
|
||||||
pakHeader.Init(structs::PakVersion::Starfighter);
|
pakHeader.Init(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PakWriter::AddFile(const std::string &path, const PakFile& data) {
|
std::unordered_map<std::string, PakFile>& PakWriter::GetFiles() {
|
||||||
archiveFiles[path] = data;
|
return archiveFiles;
|
||||||
}
|
|
||||||
|
|
||||||
void PakWriter::RemoveFile(const std::string &path) {
|
|
||||||
archiveFiles.erase(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PakWriter::Write(std::ostream& os) {
|
void PakWriter::Write(std::ostream& os) {
|
||||||
|
@ -34,6 +30,12 @@ namespace europa::io {
|
||||||
// Leave space for the header
|
// Leave space for the header
|
||||||
os.seekp(sizeof(structs::PakHeader), std::ostream::beg);
|
os.seekp(sizeof(structs::PakHeader), std::ostream::beg);
|
||||||
|
|
||||||
|
// Seek forwards for version 2 PAKs, as the only
|
||||||
|
// difference seems to be
|
||||||
|
if(pakHeader.version == structs::PakVersion::Ver2) {
|
||||||
|
os.seekp(6, std::ostream::cur);
|
||||||
|
}
|
||||||
|
|
||||||
// Write file data
|
// Write file data
|
||||||
for(auto& [filename, file] : archiveFiles) {
|
for(auto& [filename, file] : archiveFiles) {
|
||||||
file.GetTOCEntry().offset = os.tellp();
|
file.GetTOCEntry().offset = os.tellp();
|
||||||
|
@ -59,4 +61,4 @@ namespace europa::io {
|
||||||
impl::WriteStreamType(os, pakHeader);
|
impl::WriteStreamType(os, pakHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace europa::io
|
|
@ -19,7 +19,6 @@ namespace europa::io::impl {
|
||||||
is.read(&buffer[0], size);
|
is.read(&buffer[0], size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WriteStreamTypeImpl(std::ostream& os, const char* buffer, std::size_t buffer_size) {
|
void WriteStreamTypeImpl(std::ostream& os, const char* buffer, std::size_t buffer_size) {
|
||||||
os.write(&buffer[0], buffer_size);
|
os.write(&buffer[0], buffer_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace europa::io::impl {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
void ReadStreamTypeImpl(std::istream& is, char* buffer, std::size_t size);
|
void ReadStreamTypeImpl(std::istream& is, char* buffer, std::size_t size);
|
||||||
void WriteStreamTypeImpl(std::ostream& os, const char* buffer, std::size_t buffer_size);
|
void WriteStreamTypeImpl(std::ostream& os, const char* buffer, std::size_t buffer_size);
|
||||||
}
|
} // namespace detail
|
||||||
|
|
||||||
// This is lame. But it works :)
|
// This is lame. But it works :)
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|
|
@ -7,10 +7,11 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <europa/io/YatfReader.h>
|
#include <europa/io/YatfReader.h>
|
||||||
#include "StreamUtils.h"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "StreamUtils.h"
|
||||||
|
|
||||||
namespace europa::io {
|
namespace europa::io {
|
||||||
|
|
||||||
YatfReader::YatfReader(std::istream& is)
|
YatfReader::YatfReader(std::istream& is)
|
||||||
|
@ -56,6 +57,4 @@ namespace europa::io {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace europa::io
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,8 @@
|
||||||
add_executable(europa_pack_extractor europa_pack_extractor.cpp)
|
add_executable(europa_pack_extractor europa_pack_extractor.cpp)
|
||||||
|
|
||||||
target_link_libraries(europa_pack_extractor PUBLIC libeuropa)
|
target_link_libraries(europa_pack_extractor PUBLIC libeuropa
|
||||||
|
indicators::indicators
|
||||||
|
)
|
||||||
|
|
||||||
set_target_properties(europa_pack_extractor PROPERTIES
|
set_target_properties(europa_pack_extractor PROPERTIES
|
||||||
CXX_STANDARD 20
|
CXX_STANDARD 20
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <indicators/cursor_control.hpp>
|
||||||
|
#include <indicators/progress_bar.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
@ -38,6 +40,19 @@ int main(int argc, char** argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indicators::ProgressBar progress {
|
||||||
|
indicators::option::BarWidth { 50 },
|
||||||
|
indicators::option::ForegroundColor { indicators::Color::green },
|
||||||
|
indicators::option::MaxProgress { reader.GetFiles().size() },
|
||||||
|
indicators::option::ShowPercentage { true },
|
||||||
|
indicators::option::ShowElapsedTime { true },
|
||||||
|
indicators::option::ShowRemainingTime { true },
|
||||||
|
|
||||||
|
indicators::option::PrefixText { "Extracting archive " }
|
||||||
|
};
|
||||||
|
|
||||||
|
indicators::show_console_cursor(false);
|
||||||
|
|
||||||
for(auto& [filename, file] : reader.GetFiles()) {
|
for(auto& [filename, file] : reader.GetFiles()) {
|
||||||
auto nameCopy = filename;
|
auto nameCopy = filename;
|
||||||
|
|
||||||
|
@ -50,11 +65,15 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
progress.set_option(indicators::option::PostfixText { filename });
|
||||||
|
|
||||||
auto outpath = (baseDirectory / nameCopy);
|
auto outpath = (baseDirectory / nameCopy);
|
||||||
|
|
||||||
if(!fs::exists(outpath.parent_path()))
|
if(!fs::exists(outpath.parent_path()))
|
||||||
fs::create_directories(outpath.parent_path());
|
fs::create_directories(outpath.parent_path());
|
||||||
|
|
||||||
|
reader.ReadFile(filename);
|
||||||
|
|
||||||
std::ofstream ofs(outpath.string(), std::ofstream::binary);
|
std::ofstream ofs(outpath.string(), std::ofstream::binary);
|
||||||
|
|
||||||
if(!ofs) {
|
if(!ofs) {
|
||||||
|
@ -63,10 +82,9 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ofs.write(reinterpret_cast<const char*>(file.GetData().data()), static_cast<std::streampos>(file.GetTOCEntry().size));
|
ofs.write(reinterpret_cast<const char*>(file.GetData().data()), static_cast<std::streampos>(file.GetTOCEntry().size));
|
||||||
ofs.close();
|
progress.tick();
|
||||||
|
|
||||||
std::cout << "Wrote \"" << outpath.string() << "\" to disk.\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indicators::show_console_cursor(true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -11,8 +11,8 @@
|
||||||
#include <europa/io/PakReader.h>
|
#include <europa/io/PakReader.h>
|
||||||
#include <europa/io/PakWriter.h>
|
#include <europa/io/PakWriter.h>
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
std::ifstream ifs(argv[1], std::ifstream::binary);
|
std::ifstream ifs(argv[1], std::ifstream::binary);
|
||||||
|
@ -20,7 +20,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
europa::io::PakWriter writer;
|
europa::io::PakWriter writer;
|
||||||
|
|
||||||
writer.Init();
|
writer.Init(europa::structs::PakVersion::Ver2);
|
||||||
|
|
||||||
// Read pak data and vomit it into the writer.
|
// Read pak data and vomit it into the writer.
|
||||||
// This will temporarily consume 2x the memory (so about 240mb for the biggest paks I've seen),
|
// This will temporarily consume 2x the memory (so about 240mb for the biggest paks I've seen),
|
||||||
|
|
Loading…
Reference in New Issue