Archived
1
Fork 0

Add support for excel sheets with subrows

This also fixes strings not loading past another string
column
This commit is contained in:
Joshua Goins 2022-04-12 14:39:33 -04:00
parent cd6033a77b
commit fa8fa9093a
3 changed files with 108 additions and 88 deletions

View file

@ -8,7 +8,7 @@
// taken from https://xiv.dev/game-data/file-formats/excel
struct ExhHeader {
char magic[0x4];
uint16_t unknown;
uint16_t version;
uint16_t dataOffset;
uint16_t columnCount;
uint16_t pageCount;

View file

@ -9,11 +9,11 @@
#include "utility.h"
struct ExcelDataHeader {
char magic[0x4];
char magic[4];
uint16_t version;
uint16_t unknown1;
uint32_t indexSize;
uint32_t unknown2[5];
uint16_t unknown2[10];
};
struct ExcelDataOffset {
@ -63,7 +63,7 @@ EXD readEXD(EXH& exh, std::string_view path, ExcelDataPagination& page) {
endianSwap(&header.indexSize);
std::vector<ExcelDataOffset> dataOffsets;
dataOffsets.resize(header.indexSize / sizeof( ExcelDataOffset ));
dataOffsets.resize(header.indexSize / sizeof(ExcelDataOffset));
fread(dataOffsets.data(), sizeof(ExcelDataOffset) * dataOffsets.size(), 1, file);
@ -72,106 +72,124 @@ EXD readEXD(EXH& exh, std::string_view path, ExcelDataPagination& page) {
endianSwap(&offset.rowId);
}
for(auto& offset : dataOffsets) {
Row row;
for(int i = 0; i < exh.header.rowCount; i++) {
for(auto& offset : dataOffsets) {
if (offset.rowId == i) {
fseek(file, offset.offset, SEEK_SET);
fseek(file, exh.header.dataOffset + offset.offset, SEEK_SET);
ExcelDataRowHeader rowHeader;
fread(&rowHeader, sizeof(ExcelDataRowHeader), 1, file);
ExcelDataRowHeader rowHeader;
fread(&rowHeader, sizeof(ExcelDataRowHeader), 1, file);
endianSwap(&rowHeader.dataSize);
endianSwap(&rowHeader.rowCount);
endianSwap(&rowHeader.dataSize);
endianSwap(&rowHeader.rowCount);
const int headerOffset = offset.offset + 6;
const int rowOffset = offset.offset + 6;
const auto readRow = [&exd, &exh, file, rowHeader](int offset) {
Row row;
for(auto column : exh.columnDefinitions) {
Column c;
for (auto column: exh.columnDefinitions) {
Column c;
switch(column.type) {
case String:
{
fseek(file, rowOffset + column.offset, SEEK_SET);
switch (column.type) {
case String: {
fseek(file, offset + column.offset, SEEK_SET);
uint32_t stringLength;
fread(&stringLength, sizeof(uint32_t), 1, file);
uint32_t stringLength = 0; // this is actually offset?
fread(&stringLength, sizeof(uint32_t), 1, file);
fseek(file, rowOffset + exh.header.dataOffset + stringLength, SEEK_SET);
endianSwap(&stringLength);
std::string string;
fseek(file, offset + exh.header.dataOffset + stringLength, SEEK_SET);
int ch;
while ((ch = fgetc(file)) != '\0' && ch != '\377') {
string.push_back((char)ch);
std::string string;
uint8_t byte;
fread(&byte, sizeof(uint8_t), 1, file);
while(byte != 0) {
string.push_back(byte);
fread(&byte, sizeof(uint8_t), 1, file);
}
fmt::print("read {}\n", string);
c.data = string;
c.type = "String";
}
break;
case Int8:
c.data = readData<int8_t>(file, offset + column.offset);
c.type = "Int";
break;
case UInt8:
c.data = readData<uint8_t>(file, offset + column.offset);
c.type = "Unsigned Int";
break;
case Int16:
c.data = readData<int16_t>(file, offset + column.offset);
c.type = "Int";
break;
case UInt16:
c.data = readData<uint16_t>(file, offset + column.offset);
c.type = "Unsigned Int";
break;
case Int32:
c.data = readData<int32_t>(file, offset + column.offset);
c.type = "Int";
break;
case UInt32:
c.data = readData<uint32_t>(file, offset + column.offset);
c.type = "Unsigned Int";
break;
case Float32:
c.data = readData<float>(file, offset + column.offset);
c.type = "Float";
break;
case Int64:
c.data = readData<int64_t>(file, offset + column.offset);
c.type = "Int";
break;
case UInt64:
c.data = readData<uint64_t>(file, offset + column.offset);
c.type = "Unsigned Int";
break;
case PackedBool0:
case PackedBool1:
case PackedBool2:
case PackedBool3:
case PackedBool4:
case PackedBool5:
case PackedBool6:
case PackedBool7: {
int shift = (int) column.type - (int) PackedBool0;
int bit = 1 << shift;
int32_t data = readDataRaw<int32_t>(file, offset + column.offset);
c.data = std::to_string((data & bit) == bit);
c.type = "Boolean";
}
break;
default:
c.data = "undefined";
c.type = "Unknown";
break;
}
row.data.push_back(c);
}
fmt::print("{}\n", string.data());
exd.rows.push_back(row);
};
c.data = string;
c.type = "String";
if (rowHeader.rowCount > 1) {
for (int i = 0; i < rowHeader.rowCount; i++) {
int subrowOffset = headerOffset + (i * exh.header.dataOffset + 2 * (i + 1));
readRow(subrowOffset);
}
} else {
readRow(headerOffset);
}
break;
case Int8:
c.data = readData<int8_t>(file, rowOffset + column.offset);
c.type = "Int";
break;
case UInt8:
c.data = readData<uint8_t>(file, rowOffset + column.offset);
c.type = "Unsigned Int";
break;
case Int16:
c.data = readData<int16_t>(file, rowOffset + column.offset);
c.type = "Int";
break;
case UInt16:
c.data = readData<uint16_t>(file, rowOffset + column.offset);
c.type = "Unsigned Int";
break;
case Int32:
c.data = readData<int32_t>(file, rowOffset + column.offset);
c.type = "Int";
break;
case UInt32:
c.data = readData<uint32_t>(file, rowOffset + column.offset);
c.type = "Unsigned Int";
break;
case Float32:
c.data = readData<float>(file, rowOffset + column.offset);
c.type = "Float";
break;
case Int64:
c.data = readData<int64_t>(file, rowOffset + column.offset);
c.type = "Int";
break;
case UInt64:
c.data = readData<uint64_t>(file, rowOffset + column.offset);
c.type = "Unsigned Int";
break;
case PackedBool0:
case PackedBool1:
case PackedBool2:
case PackedBool3:
case PackedBool4:
case PackedBool5:
case PackedBool6:
case PackedBool7: {
int shift = (int)column.type - (int)PackedBool0;
int bit = 1 << shift;
int32_t data = readDataRaw<int32_t>(file, rowOffset + column.offset);
c.data = std::to_string((data & bit) == bit);
c.type = "Boolean";
}
break;
default:
c.data = "undefined";
c.type = "Unknown";
break;
}
row.data.push_back(c);
}
exd.rows.push_back(row);
}
return exd;

View file

@ -17,6 +17,8 @@ EXH readEXH(const std::string_view path) {
fread(&exh.header, sizeof(ExhHeader), 1, file);
fseek(file, 0x20, SEEK_SET);
endianSwap(&exh.header.dataOffset);
endianSwap(&exh.header.columnCount);
endianSwap(&exh.header.pageCount);