Archived
1
Fork 0

Add exl parser, make exd category configurable

Now you can easily parse EXL files, and this commit includes changes
to GameData to easily extract a EXH from just an excel sheet name
like "Item" or "Map". However this still doesn't work for language
seperated excel sheets yet.
This commit is contained in:
Joshua Goins 2022-04-11 10:18:29 -04:00
parent 851ae281e6
commit 7006cc4662
7 changed files with 109 additions and 6 deletions

View file

@ -70,7 +70,8 @@ add_library(libxiv STATIC
src/exhparser.cpp src/exhparser.cpp
src/exdparser.cpp src/exdparser.cpp
src/installextract.cpp src/installextract.cpp
src/patch.cpp) src/patch.cpp
src/exlparser.cpp)
target_include_directories(libxiv PUBLIC include PRIVATE src) target_include_directories(libxiv PUBLIC include PRIVATE src)
target_link_libraries(libxiv PUBLIC ${LIBRARIES}) target_link_libraries(libxiv PUBLIC ${LIBRARIES})
target_link_directories(libxiv PUBLIC ${LIB_DIRS}) target_link_directories(libxiv PUBLIC ${LIB_DIRS})

View file

@ -19,4 +19,6 @@ struct EXD {
std::vector<Row> rows; std::vector<Row> rows;
}; };
EXD readEXD(EXH& exh, ExcelDataPagination& page); std::string getEXDFilename(EXH& exh, std::string_view name, ExcelDataPagination& page);
EXD readEXD(EXH& exh, std::string_view path, ExcelDataPagination& page);

16
include/exlparser.h Normal file
View file

@ -0,0 +1,16 @@
#pragma once
#include <string_view>
#include <vector>
#include <string>
struct EXLRow {
std::string name;
int id;
};
struct EXL {
std::vector<EXLRow> rows;
};
EXL readEXL(std::string_view path);

View file

@ -2,6 +2,9 @@
#include <string_view> #include <string_view>
#include <string> #include <string>
#include <optional>
#include "exhparser.h"
#include "exlparser.h"
/* /*
* This handles reading/extracting the raw data from game data packs, such as dat0, index and index2 files. * This handles reading/extracting the raw data from game data packs, such as dat0, index and index2 files.
@ -23,6 +26,10 @@ public:
*/ */
void extractFile(std::string_view dataFilePath, std::string_view outPath); void extractFile(std::string_view dataFilePath, std::string_view outPath);
std::optional<EXH> readExcelSheet(std::string_view name);
std::vector<std::string> getAllSheetNames();
private: private:
/* /*
* This returns a proper SQEX-style filename for index, index2, and dat files. * This returns a proper SQEX-style filename for index, index2, and dat files.
@ -41,4 +48,6 @@ private:
uint64_t calculateHash(std::string_view path); uint64_t calculateHash(std::string_view path);
std::string dataDirectory; std::string dataDirectory;
EXL rootEXL;
}; };

View file

@ -36,10 +36,14 @@ std::string readData(FILE* file, int offset) {
return std::to_string(value); return std::to_string(value);
} }
EXD readEXD(EXH& exh, ExcelDataPagination& page) { std::string getEXDFilename(EXH& exh, std::string_view name, ExcelDataPagination& page) {
EXD exd; auto path = fmt::format("{}_{}.exd", name, page.startId);
auto path = fmt::format("{}_{}.exd", "map", page.startId); return path;
}
EXD readEXD(EXH& exh, std::string_view path, ExcelDataPagination& page) {
EXD exd;
FILE* file = fopen(path.data(), "rb"); FILE* file = fopen(path.data(), "rb");
if(file == nullptr) { if(file == nullptr) {
@ -90,7 +94,7 @@ EXD readEXD(EXH& exh, ExcelDataPagination& page) {
std::string string; std::string string;
int ch; int ch;
while ((ch = fgetc(file)) != '\0') { while ((ch = fgetc(file)) != '\0' && ch != '\377') {
string.push_back((char)ch); string.push_back((char)ch);
} }

27
src/exlparser.cpp Normal file
View file

@ -0,0 +1,27 @@
#include "exlparser.h"
#include <stdexcept>
EXL readEXL(std::string_view path) {
FILE* file = fopen(path.data(), "rb");
if(!file) {
throw std::runtime_error("Failed to read exl file from " + std::string(path.data()));
}
EXL exl;
char* data = nullptr;
size_t len = 0;
while ((getline(&data, &len, file)) != -1) {
std::string line = data;
const size_t comma = line.find_first_of(',');
std::string name = line.substr(0, comma);
std::string id = line.substr(comma + 1, line.length());
exl.rows.push_back({name, std::stoi(id)});
}
return exl;
}

View file

@ -3,6 +3,7 @@
#include "crc32checksum.h" #include "crc32checksum.h"
#include "compression.h" #include "compression.h"
#include "string_utils.h" #include "string_utils.h"
#include "exlparser.h"
#include <string> #include <string>
#include <algorithm> #include <algorithm>
@ -31,6 +32,20 @@ std::unordered_map<std::string_view, int> categoryToID = {
GameData::GameData(const std::string_view dataDirectory) { GameData::GameData(const std::string_view dataDirectory) {
this->dataDirectory = dataDirectory; this->dataDirectory = dataDirectory;
extractFile("exd/root.exl", "root.exl");
rootEXL = readEXL("root.exl");
}
std::vector<std::string> GameData::getAllSheetNames() {
std::vector<std::string> names;
for(auto row : rootEXL.rows) {
names.push_back(row.name);
}
return names;
} }
uint64_t GameData::calculateHash(const std::string_view path) { uint64_t GameData::calculateHash(const std::string_view path) {
@ -86,6 +101,8 @@ void GameData::extractFile(std::string_view dataFilePath, std::string_view outPa
// TODO: handle platforms other than win32 // TODO: handle platforms other than win32
auto indexFilename = calculateFilename(categoryToID[category], getExpansionID(repository), 0, "win32", "index"); auto indexFilename = calculateFilename(categoryToID[category], getExpansionID(repository), 0, "win32", "index");
fmt::print("calculated index filename: ");
// TODO: handle hashes in index2 files (we can read them but it's not setup yet.) // TODO: handle hashes in index2 files (we can read them but it's not setup yet.)
auto indexFile = readIndexFile(dataDirectory + "/" + repository + "/" + indexFilename); auto indexFile = readIndexFile(dataDirectory + "/" + repository + "/" + indexFilename);
@ -93,6 +110,8 @@ void GameData::extractFile(std::string_view dataFilePath, std::string_view outPa
if(entry.hash == hash) { if(entry.hash == hash) {
auto dataFilename = calculateFilename(categoryToID[category], getExpansionID(repository), entry.dataFileId, "win32", "dat0"); auto dataFilename = calculateFilename(categoryToID[category], getExpansionID(repository), entry.dataFileId, "win32", "dat0");
fmt::print("Opening data file {}...\n", dataFilename);
FILE* file = fopen((dataDirectory + "/" + repository + "/" + dataFilename).c_str(), "rb"); FILE* file = fopen((dataDirectory + "/" + repository + "/" + dataFilename).c_str(), "rb");
if(file == nullptr) { if(file == nullptr) {
throw std::runtime_error("Failed to open data file: " + dataFilename); throw std::runtime_error("Failed to open data file: " + dataFilename);
@ -187,3 +206,28 @@ void GameData::extractFile(std::string_view dataFilePath, std::string_view outPa
fmt::print("Extracted {} to {}\n", dataFilePath, outPath); fmt::print("Extracted {} to {}\n", dataFilePath, outPath);
} }
std::optional<EXH> GameData::readExcelSheet(std::string_view name) {
fmt::print("Beginning to read excel sheet {}...\n", name);
for(auto row : rootEXL.rows) {
if(row.name == name) {
fmt::print("Found row {} at id {}!\n", name, row.id);
// we want it as lowercase (Item -> item)
std::string newFilename = name.data();
std::transform(newFilename.begin(), newFilename.end(), newFilename.begin(),
[](unsigned char c){ return std::tolower(c); });
std::string exhFilename = "exd/" + newFilename + ".exh";
extractFile(exhFilename, newFilename + ".exh");
fmt::print("Done extracting files, now parsing...\n");
return readEXH(newFilename + ".exh");
}
}
return {};
}