Open arapelle opened 11 months ago
#include <span>
#include <algorithm>
#include <numeric>
#include <ranges>
#include <vector>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <unordered_map>
void check_input_args(int argc)
{
if (argc < 3)
{
std::cerr << "ERROR: arguments are missing. Please provide : output_file input_file ..." << std::endl;
exit(EXIT_FAILURE);
}
}
void check_input_file(const std::filesystem::path& input_file_path)
{
if (!std::filesystem::exists(input_file_path))
{
std::cerr << "ERROR: Input file does not exist : " << input_file_path << "." << std::endl;
exit(EXIT_FAILURE);
}
}
void check_input_file(std::ifstream& input_file)
{
if (!input_file)
{
std::cerr << "ERROR: Error while reading input file." << std::endl;
exit(EXIT_FAILURE);
}
}
void check_output_file(std::ofstream& output_file)
{
if (!output_file)
{
std::cerr << "ERROR: Error while writing output file." << std::endl;
exit(EXIT_FAILURE);
}
}
class Input_file
{
public:
Input_file(std::filesystem::path path)
: path_(path), fstream_(path, std::ios::binary|std::ios::ate), size_(fstream_.tellg())
{}
const std::filesystem::path& path() const { return path_; }
std::size_t size() const { return size_; }
void write_to_ofstream(std::ofstream& ofs) const
{
fstream_.seekg(0, std::ios::beg);
constexpr std::size_t buffer_size = 1024;
std::array<char, buffer_size> bytes;
for (std::size_t file_size = size(); file_size > 0;)
{
std::size_t byte_count = std::min<std::size_t>(bytes.size(), file_size);
fstream_.read(bytes.data(), byte_count);
check_input_file(fstream_);
ofs.write(bytes.data(), byte_count);
check_output_file(ofs);
file_size -= byte_count;
}
fstream_.seekg(0, std::ios::beg);
}
private:
std::filesystem::path path_;
mutable std::ifstream fstream_;
std::size_t size_;
};
template <class RequestTypeTag, class Type, class ResponseType>
struct define_requested_type
{
using type = ResponseType;
};
template <class RequestTag, class Type>
struct requested_type;
template <class RequestTag, class Type>
using requested_type_t = typename requested_type<RequestTag, Type>::type;
template <class RequestTag, class Type, class OrType>
struct requested_type_or { using type = OrType; };
template <class RequestTag, class Type, class OrType>
requires requires
{
typename requested_type_t<RequestTag, Type>;
}
struct requested_type_or<RequestTag, Type, OrType> { using type = requested_type_t<RequestTag, Type>; };
template <class RequestTag, class Type, class OrType>
using requested_type_or_t = typename requested_type_or<RequestTag, Type, OrType>::type;
// ---
class resource_ifstream_tag { ~resource_ifstream_tag() = delete; };
template <>
struct requested_type<resource_ifstream_tag, int>
: public define_requested_type<resource_ifstream_tag, int, void> {};
// #define ARBA_CORE_DEFINE_REQUESTED_TYPE(tag, type, vtype) !
// e.g. ARBA_CORE_DEFINE_REQUESTED_TYPE(resource_ifstream_tag, sf::Texture, sf::InputFileStream)
class resource_pack
{
public:
struct resource_info
{
uint64_t index;
uint64_t size;
void read_binary(std::istream& stream)
{
// seri::read_binary(stream, index);
// seri::read_binary(stream, size);
}
};
public:
resource_pack(const std::filesystem::path& rscp_fpath)
: rscp_fpath_(rscp_fpath)
{
load_index_();
}
inline const std::filesystem::path& path() const { return rscp_fpath_; }
const resource_info* resource_info_ptr(std::string_view rsc_path) const
{
if (auto iter = index_.find(std::string(rsc_path)); iter != index_.end()) [[likely]]
return &iter->second;
return nullptr;
}
bool open_input_file_stream(std::string_view rsc_path, std::ifstream& input_fstream, uint64_t& rsc_size) const
{
if (const resource_info* rsc_info_ptr = resource_info_ptr(rsc_path); rsc_info_ptr)
{
rsc_size = rsc_info_ptr->size;
input_fstream.open(rscp_fpath_);
input_fstream.seekg(rsc_info_ptr->index);
return static_cast<bool>(input_fstream);
}
return false;
}
inline bool open_input_file_stream(std::string_view rsc_path, std::ifstream& input_fstream) const
{
std::size_t unused;
return open_input_file_stream(rsc_path, input_fstream, unused);
}
template <class Resource>
std::shared_ptr<Resource> get_rsc(std::string_view rsc_path) const
{
if (const resource_info* rsc_info_ptr = resource_info_ptr(rsc_path); rsc_info_ptr)
{
// using input_fstream_t = typename resource_types<Resource>::input_file_stream;
using input_fstream_t = requested_type_or_t<resource_ifstream_tag, Resource, std::ifstream>;
input_fstream_t rscp_fstream(rscp_fpath_);
rscp_fstream.seekg(rsc_info_ptr->index);
Resource rsc;
// if (seri::read_binary(rscp_fstream, rsc))
return std::make_shared(std::move(rsc));
}
return nullptr;
}
private:
void load_index_()
{
std::ifstream rscp_fstream(rscp_fpath_);
uint64_t offset = 0;
// seri::read_binary(rscp_fstream, offset);
rscp_fstream.seekg(offset, std::ifstream::cur);
// seri::write_binary(rscp_fstream, index_);
}
private:
std::filesystem::path rscp_fpath_;
std::unordered_map<std::string, resource_info> index_;
};
void make_rscpack(int argc, char** argv)
{
check_input_args(argc);
std::filesystem::path output_fpath(argv[1]);
std::ofstream output_fstream(output_fpath.string(), std::ios::binary);
check_output_file(output_fstream);
std::vector<Input_file> input_files;
input_files.reserve(argc - 2);
for (std::filesystem::path input_fpath : std::ranges::subrange(argv + 2, argv + argc))
{
check_input_file(input_fpath);
input_files.emplace_back(input_fpath);
std::cout << input_fpath << std::endl;
}
uint64_t input_files_size = 0;
std::ranges::for_each(input_files, [&](const auto& arg){ input_files_size += arg.size(); });
output_fstream << input_files_size;
std::unordered_map<std::filesystem::path, uint64_t> resource_index;
resource_index.reserve(input_files.size());
for (const Input_file& input_file : input_files)
{
resource_index.emplace(input_file.path(), output_fstream.tellp());
input_file.write_to_ofstream(output_fstream);
}
output_fstream << resource_index.size();
for (const auto& entry : resource_index)
output_fstream << entry.first.generic_string() << entry.second;
}
int main(int argc, char** argv)
{
std::cout << "EXIT SUCCESS" << std::endl;
return EXIT_SUCCESS;
}
rscpack
project.