2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-05-13 20:31:21 +00:00
Lioncash 972af7c537 assetnameparser: Amend transposed fwrite arguments
Existing code was using the size argument for the number of elements to
write and vice versa.

No behavior change, given this still results in the same number of bytes
being copied. This just makes corrects their usages.
2020-05-31 07:13:06 -04:00

282 lines
8.0 KiB
C++

#include <cstdint>
#include <iostream>
#include <memory>
#include <vector>
#include <logvisor/logvisor.hpp>
#include "tinyxml2/tinyxml2.h"
#ifndef _WIN32
#include <cstdlib>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/statvfs.h>
#include <cerrno>
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#include <cwchar>
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#if UNICODE
#define IS_UCS2 1
#endif
#endif
namespace {
logvisor::Module Log("AssetNameParser");
// TODO: Clean this up
#undef bswap16
#undef bswap32
#undef bswap64
/* Type-sensitive byte swappers */
template <typename T>
constexpr T bswap16(T val) {
#if __GNUC__
return __builtin_bswap16(val);
#elif _WIN32
return _byteswap_ushort(val);
#else
return (val = (val << 8) | ((val >> 8) & 0xFF));
#endif
}
template <typename T>
constexpr T bswap32(T val) {
#if __GNUC__
return __builtin_bswap32(val);
#elif _WIN32
return _byteswap_ulong(val);
#else
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
return val;
#endif
}
template <typename T>
constexpr T bswap64(T val) {
#if __GNUC__
return __builtin_bswap64(val);
#elif _WIN32
return _byteswap_uint64(val);
#else
return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) |
((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) |
((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56);
#endif
}
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
constexpr uint32_t SBig(uint32_t val) { return bswap32(val); }
constexpr uint64_t SBig(uint64_t val) { return bswap64(val); }
#ifndef SBIG
#define SBIG(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
#endif
#ifndef SLITTLE
#define SLITTLE(q) (q)
#endif
#else
#ifndef SLITTLE
#define SLITTLE(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
#endif
constexpr uint32_t SBig(uint32_t val) { return val; }
constexpr uint64_t SBig(uint64_t val) { return val; }
#ifndef SBIG
#define SBIG(q) (q)
#endif
#endif
class FourCC {
protected:
union {
char fcc[4];
uint32_t num;
};
public:
FourCC() /* Sentinel FourCC */
: num(0) {}
FourCC(const FourCC& other) { num = other.num; }
FourCC(const char* name) : num(*(uint32_t*)name) {}
FourCC(uint32_t n) : num(n) {}
bool operator==(const FourCC& other) const { return num == other.num; }
bool operator!=(const FourCC& other) const { return num != other.num; }
bool operator==(const char* other) const { return num == *(uint32_t*)other; }
bool operator!=(const char* other) const { return num != *(uint32_t*)other; }
bool operator==(int32_t other) const { return num == other; }
bool operator!=(int32_t other) const { return num != other; }
bool operator==(uint32_t other) const { return num == other; }
bool operator!=(uint32_t other) const { return num != other; }
std::string toString() const { return std::string(fcc, 4); }
uint32_t toUint32() const { return num; }
operator uint32_t() const { return num; }
};
struct SAsset {
FourCC type;
uint64_t id;
std::string name;
std::string dir;
};
enum class FileLockType { None = 0, Read, Write };
#if IS_UCS2
using SystemChar = wchar_t;
using SystemString = std::wstring;
#ifndef _SYS_STR
#define _SYS_STR(val) L##val
#endif
using Sstat = struct _stat;
#else
using SystemChar = char;
using SystemString = std::string;
#ifndef _SYS_STR
#define _SYS_STR(val) val
#endif
using Sstat = struct stat;
#endif
struct FILEDeleter {
void operator()(FILE* file) const { std::fclose(file); }
};
using FILEPtr = std::unique_ptr<FILE, FILEDeleter>;
FILEPtr Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock = FileLockType::None) {
#if IS_UCS2
FILEPtr fp{_wfopen(path, mode)};
if (!fp) {
return nullptr;
}
#else
FILEPtr fp{std::fopen(path, mode)};
if (!fp) {
return nullptr;
}
#endif
if (lock != FileLockType::None) {
#if _WIN32
OVERLAPPED ov = {};
LockFileEx((HANDLE)(uintptr_t)_fileno(fp.get()), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0,
1, &ov);
#else
if (flock(fileno(fp.get()), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB)) {
std::fprintf(stderr, "flock %s: %s", path, strerror(errno));
}
#endif
}
return fp;
}
} // Anonymous namespace
#if _WIN32
int wmain(int argc, const wchar_t* argv[])
#else
int main(int argc, const char* argv[])
#endif
{
logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger();
if (argc < 3) {
Log.report(logvisor::Error, FMT_STRING(_SYS_STR("Usage: {} <input> <output>")), argv[0]);
return 1;
}
SystemString inPath = argv[1];
SystemString outPath = argv[2];
tinyxml2::XMLDocument doc;
std::vector<SAsset> assets;
FILEPtr docF = Fopen(inPath.c_str(), _SYS_STR("rb"));
if (doc.LoadFile(docF.get()) == tinyxml2::XML_SUCCESS) {
const tinyxml2::XMLElement* elm = doc.RootElement();
if (strcmp(elm->Name(), "AssetNameMap") != 0) {
Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Invalid database supplied")));
return 1;
}
elm = elm->FirstChildElement("AssetNameMap");
if (elm == nullptr) {
Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Malformed AssetName database")));
return 1;
}
elm = elm->FirstChildElement("Asset");
while (elm != nullptr ) {
const tinyxml2::XMLElement* keyElm = elm->FirstChildElement("Key");
const tinyxml2::XMLElement* valueElm = elm->FirstChildElement("Value");
if (keyElm == nullptr || valueElm == nullptr) {
Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Malformed Asset entry, [Key,Value] required")));
return 0;
}
const tinyxml2::XMLElement* nameElm = valueElm->FirstChildElement("Name");
const tinyxml2::XMLElement* dirElm = valueElm->FirstChildElement("Directory");
const tinyxml2::XMLElement* typeElm = valueElm->FirstChildElement("Type");
const tinyxml2::XMLElement* autoGenNameElm = valueElm->FirstChildElement("AutoGenName");
const tinyxml2::XMLElement* autoGenDirElm = valueElm->FirstChildElement("AutoGenDir");
if (nameElm == nullptr || dirElm == nullptr || typeElm == nullptr) {
Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Malformed Value entry, [Name,Directory,Type] required")));
return 0;
}
assets.emplace_back();
bool autoGen = strncasecmp(autoGenNameElm->GetText(), "true", 4) == 0 && strncasecmp(autoGenDirElm->GetText(), "true", 4) == 0;
if (!autoGen) {
SAsset& asset = assets.back();
asset.type = typeElm->GetText();
asset.id = strtoull(keyElm->GetText(), nullptr, 16);
asset.name = nameElm->GetText();
asset.dir = dirElm->GetText();
}
elm = elm->NextSiblingElement("Asset");
}
FILEPtr f = Fopen(outPath.c_str(), _SYS_STR("wb"));
if (f == nullptr) {
Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("Unable to open destination")));
return 0;
}
uint32_t assetCount = SBig(uint32_t(assets.size()));
FourCC sentinel(SBIG('AIDM'));
fwrite(&sentinel, sizeof(sentinel), 1, f.get());
fwrite(&assetCount, sizeof(assetCount), 1, f.get());
for (const SAsset& asset : assets) {
fwrite(&asset.type, sizeof(asset.type), 1, f.get());
uint64_t id = SBig(asset.id);
fwrite(&id, sizeof(id), 1, f.get());
uint32_t tmp = SBig(uint32_t(asset.name.length()));
fwrite(&tmp, sizeof(tmp), 1, f.get());
fwrite(asset.name.c_str(), 1, SBig(tmp), f.get());
tmp = SBig(uint32_t(asset.dir.length()));
fwrite(&tmp, sizeof(tmp), 1, f.get());
fwrite(asset.dir.c_str(), SBig(tmp), 1, f.get());
}
fflush(f.get());
return 0;
}
Log.report(logvisor::Fatal, FMT_STRING(_SYS_STR("failed to load")));
return 1;
}