Add support for excel sheets with subrows
This also fixes strings not loading past another string column
This commit is contained in:
parent
cd6033a77b
commit
fa8fa9093a
3 changed files with 108 additions and 88 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Reference in a new issue