mirror of
https://github.com/rwengine/openrw.git
synced 2024-10-06 09:07:19 +02:00
rwcore/LoaderIMG: Switch to fstream and avoid case-insensitive string comparision.
This commit is contained in:
parent
edaab68525
commit
77b348f1f4
@ -1,53 +1,87 @@
|
||||
#include "loaders/LoaderIMG.hpp"
|
||||
#include <loaders/LoaderIMG.hpp>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rw/debug.hpp"
|
||||
#include <rw/debug.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t kAssetRecordSize{2048};
|
||||
|
||||
void to_lowercase_inplace(char* name) {
|
||||
size_t len = std::strlen(name);
|
||||
|
||||
std::transform(
|
||||
name, name+len, name,
|
||||
[](char ch) -> char { return std::tolower(ch); }
|
||||
);
|
||||
} // namespace
|
||||
|
||||
}
|
||||
|
||||
bool LoaderIMG::load(const rwfs::path& filepath) {
|
||||
assert(m_archive.empty());
|
||||
m_archive = filepath;
|
||||
|
||||
auto dirPath = filepath;
|
||||
dirPath.replace_extension(".dir");
|
||||
|
||||
FILE* fp = fopen(dirPath.string().c_str(), "rb");
|
||||
if (fp) {
|
||||
fseek(fp, 0, SEEK_END);
|
||||
unsigned long fileSize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
std::ifstream file(dirPath.string(), std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
RW_ERROR("Failed to open " + dirPath.string());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t expectedCount = fileSize / 32;
|
||||
file.seekg(0, std::ios::end);
|
||||
auto fileSize = file.tellg();
|
||||
file.seekg(0);
|
||||
|
||||
std::size_t expectedCount = fileSize / sizeof(LoaderIMGFile);
|
||||
m_assets.resize(expectedCount);
|
||||
std::size_t actualCount = fread(&m_assets[0], sizeof(LoaderIMGFile),
|
||||
expectedCount, fp);
|
||||
|
||||
if (expectedCount != actualCount) {
|
||||
m_assets.resize(actualCount);
|
||||
file.read(reinterpret_cast<char*>(m_assets.data()), expectedCount * sizeof(LoaderIMGFile));
|
||||
|
||||
if (file.fail() || file.gcount() != fileSize) {\
|
||||
m_assets.resize(file.gcount() / sizeof(LoaderIMGFile));
|
||||
RW_ERROR("Error reading records in IMG archive");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
for (auto& asset : m_assets) {
|
||||
to_lowercase_inplace(asset.name);
|
||||
}
|
||||
|
||||
auto imgPath = filepath;
|
||||
imgPath.replace_extension(".img");
|
||||
m_archive = imgPath;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
m_archive_stream.open(imgPath.string(), std::ios::binary);
|
||||
if (!m_archive_stream.is_open()) {
|
||||
RW_ERROR("Failed to open " << imgPath.string());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Get the information of a asset in the examining archive
|
||||
bool LoaderIMG::findAssetInfo(const std::string& assetname,
|
||||
LoaderIMGFile& out) {
|
||||
for (auto &asset : m_assets) {
|
||||
if (boost::iequals(asset.name, assetname)) {
|
||||
for (const auto& asset : m_assets) {
|
||||
if (assetname.compare(asset.name) == 0) {
|
||||
out = asset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> LoaderIMG::loadToMemory(const std::string& assetname) {
|
||||
if (!m_archive_stream.is_open()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LoaderIMGFile assetInfo;
|
||||
bool found = findAssetInfo(assetname, assetInfo);
|
||||
|
||||
@ -56,50 +90,38 @@ std::unique_ptr<char[]> LoaderIMG::loadToMemory(const std::string& assetname) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto imgName = m_archive;
|
||||
std::streamsize asset_size = assetInfo.size * kAssetRecordSize;
|
||||
auto raw_data = std::make_unique<char[]>(asset_size);
|
||||
m_archive_stream.seekg(assetInfo.offset * kAssetRecordSize);
|
||||
m_archive_stream.read(raw_data.get(), asset_size);
|
||||
|
||||
FILE* fp = fopen(imgName.string().c_str(), "rb");
|
||||
if (fp) {
|
||||
auto raw_data = std::make_unique<char[]>(assetInfo.size * 2048);
|
||||
|
||||
fseek(fp, assetInfo.offset * 2048, SEEK_SET);
|
||||
if (fread(raw_data.get(), 2048, assetInfo.size, fp) != assetInfo.size) {
|
||||
if (m_archive_stream.gcount() != asset_size) {
|
||||
RW_ERROR("Error reading asset " << assetInfo.name);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return raw_data;
|
||||
} else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Writes the contents of assetname to filename
|
||||
bool LoaderIMG::saveAsset(const std::string& assetname,
|
||||
const std::string& filename) {
|
||||
auto raw_data = loadToMemory(assetname);
|
||||
if (!raw_data) return false;
|
||||
|
||||
FILE* dumpFile = fopen(filename.c_str(), "wb");
|
||||
if (dumpFile) {
|
||||
LoaderIMGFile asset;
|
||||
if (findAssetInfo(assetname, asset)) {
|
||||
fwrite(raw_data.get(), 2048, asset.size, dumpFile);
|
||||
printf("=> IMG: Saved %s to disk with filename %s\n",
|
||||
assetname.c_str(), filename.c_str());
|
||||
}
|
||||
fclose(dumpFile);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (!raw_data) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the information of an asset by its index
|
||||
const LoaderIMGFile& LoaderIMG::getAssetInfoByIndex(size_t index) const {
|
||||
return m_assets[index];
|
||||
}
|
||||
LoaderIMGFile asset;
|
||||
if (!findAssetInfo(assetname, asset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t LoaderIMG::getAssetCount() const {
|
||||
return m_assets.size();
|
||||
std::ofstream dump_file(filename, std::ios::binary);
|
||||
if (!dump_file.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dump_file.write(raw_data.get(), kAssetRecordSize * asset.size);
|
||||
RW_MESSAGE("Saved " << assetname << " to disk with filename " << filename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2,9 +2,10 @@
|
||||
#define _LIBRW_LOADERIMG_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
|
||||
#include <rw/filesystem.hpp>
|
||||
|
||||
@ -32,11 +33,13 @@ public:
|
||||
|
||||
/// Construct
|
||||
LoaderIMG() = default;
|
||||
LoaderIMG(const LoaderIMG&) = delete;
|
||||
LoaderIMG(LoaderIMG&&) noexcept = default;
|
||||
|
||||
/// Load the structure of the archive
|
||||
/// Omit the extension in filename so both .dir and .img are loaded when
|
||||
/// appropriate
|
||||
bool load(const rwfs::path& filename);
|
||||
bool load(const rwfs::path& filepath);
|
||||
|
||||
/// Load a file from the archive to memory and pass a pointer to it
|
||||
/// Warning: Returns nullptr if by any reason it can't load the file
|
||||
@ -49,10 +52,14 @@ public:
|
||||
bool findAssetInfo(const std::string& assetname, LoaderIMGFile& out);
|
||||
|
||||
/// Get the information of an asset by its index
|
||||
const LoaderIMGFile& getAssetInfoByIndex(size_t index) const;
|
||||
const LoaderIMGFile& getAssetInfoByIndex(size_t index) const {
|
||||
return m_assets[index];
|
||||
}
|
||||
|
||||
/// Returns the number of asset files in the archive
|
||||
std::size_t getAssetCount() const;
|
||||
std::size_t getAssetCount() const {
|
||||
return m_assets.size();
|
||||
}
|
||||
|
||||
Version getVersion() const {
|
||||
return m_version;
|
||||
@ -61,6 +68,7 @@ public:
|
||||
private:
|
||||
Version m_version = GTAIIIVC; ///< Version of this IMG archive
|
||||
rwfs::path m_archive; ///< Path to the archive being used (no extension)
|
||||
std::ifstream m_archive_stream; ///< File stream for archive
|
||||
|
||||
std::vector<LoaderIMGFile> m_assets; ///< Asset info of the archive
|
||||
};
|
||||
|
@ -3,12 +3,9 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
#include "platform/FileHandle.hpp"
|
||||
#include "loaders/LoaderIMG.hpp"
|
||||
|
||||
#include "rw/debug.hpp"
|
||||
|
||||
std::string FileIndex::normalizeFilePath(const std::string &filePath) {
|
||||
@ -75,7 +72,7 @@ FileContentsInfo FileIndex::openFileRaw(const std::string &filePath) const {
|
||||
void FileIndex::indexArchive(const std::string &archive) {
|
||||
rwfs::path path = findFilePath(archive);
|
||||
|
||||
LoaderIMG img;
|
||||
LoaderIMG& img = loaders_[path.string()];
|
||||
if (!img.load(path.string())) {
|
||||
throw std::runtime_error("Failed to load IMG archive: " + path.string());
|
||||
}
|
||||
@ -105,17 +102,17 @@ FileContentsInfo FileIndex::openFile(const std::string &filePath) {
|
||||
size_t length = 0;
|
||||
|
||||
if (indexedData.type == IndexedDataType::ARCHIVE) {
|
||||
LoaderIMG img;
|
||||
|
||||
if (!img.load(indexedData.path)) {
|
||||
throw std::runtime_error("Failed to load IMG archive: " + indexedData.path);
|
||||
auto loaderPos = loaders_.find(indexedData.path);
|
||||
if (loaderPos == loaders_.end()) {
|
||||
throw std::runtime_error("IMG archive not indexed: " + indexedData.path);
|
||||
}
|
||||
|
||||
auto& loader = loaderPos->second;
|
||||
LoaderIMGFile file;
|
||||
auto filename = rwfs::path(indexedData.assetData).filename().string();
|
||||
if (img.findAssetInfo(filename, file)) {
|
||||
if (loader.findAssetInfo(filename, file)) {
|
||||
length = file.size * 2048;
|
||||
data = img.loadToMemory(filename);
|
||||
data = loader.loadToMemory(filename);
|
||||
}
|
||||
} else {
|
||||
std::ifstream dfile(indexedData.path, std::ios::binary);
|
||||
|
@ -1,10 +1,13 @@
|
||||
#ifndef _LIBRW_FILEINDEX_HPP_
|
||||
#define _LIBRW_FILEINDEX_HPP_
|
||||
|
||||
#include "rw/filesystem.hpp"
|
||||
#include "rw/forward.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
#include <loaders/LoaderIMG.hpp>
|
||||
#include <rw/filesystem.hpp>
|
||||
#include <rw/forward.hpp>
|
||||
|
||||
|
||||
class FileIndex {
|
||||
public:
|
||||
@ -91,6 +94,11 @@ private:
|
||||
* @throws If this FileIndex has not indexed filePath
|
||||
*/
|
||||
const IndexedData *getIndexedDataAt(const std::string &filePath) const;
|
||||
|
||||
/**
|
||||
* @brief loaders_ Maps .img filepaths to its respective loader
|
||||
*/
|
||||
std::unordered_map<std::string, LoaderIMG> loaders_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -6,7 +6,7 @@
|
||||
class IMGArchiveModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
||||
LoaderIMG archive;
|
||||
const LoaderIMG& archive;
|
||||
|
||||
public:
|
||||
IMGArchiveModel(const LoaderIMG& archive, QObject* parent = 0)
|
||||
|
Loading…
Reference in New Issue
Block a user