#include "exdparser.h" #include #include #include #include #include "exhparser.h" #include "utility.h" struct ExcelDataHeader { char magic[4]; uint16_t version; uint16_t unknown1; uint32_t indexSize; uint16_t unknown2[10]; }; struct ExcelDataOffset { uint32_t rowId; uint32_t offset; }; struct ExcelDataRowHeader { uint32_t dataSize; uint16_t rowCount; }; template T readDataRaw(MemorySpan& span, int offset) { span.seek(offset, Seek::Set); T value; span.read(&value); endianSwap(&value); return value; } template std::string readData(MemorySpan& span, int offset) { return std::to_string(readDataRaw(span, offset)); } std::string getEXDFilename(EXH& exh, std::string_view name, std::string_view lang, ExcelDataPagination& page) { if(lang.empty()) { return fmt::format("{}_{}.exd", name, page.startId); } else { return fmt::format("{}_{}_{}.exd", name, page.startId, lang); } } EXD readEXD(EXH& exh, MemorySpan data, ExcelDataPagination& page) { EXD exd; ExcelDataHeader header; data.read(&header); endianSwap(&header.indexSize); std::vector dataOffsets; data.read_structures(&dataOffsets, header.indexSize / sizeof(ExcelDataOffset)); for(auto& offset : dataOffsets) { endianSwap(&offset.offset); endianSwap(&offset.rowId); } for(int i = 0; i < exh.header.rowCount; i++) { for(auto& offset : dataOffsets) { if (offset.rowId == i) { data.seek(offset.offset, Seek::Set); ExcelDataRowHeader rowHeader; data.read(&rowHeader); endianSwap(&rowHeader.dataSize); endianSwap(&rowHeader.rowCount); const int headerOffset = offset.offset + 6; const auto readRow = [&exd, &exh, &data, rowHeader](int offset) { Row row; for (auto column: exh.columnDefinitions) { Column c; switch (column.type) { case String: { data.seek(offset + column.offset, Seek::Set); uint32_t stringLength = 0; // this is actually offset? data.read(&stringLength); endianSwap(&stringLength); data.seek(offset + exh.header.dataOffset + stringLength, Seek::Set); std::string string; uint8_t byte; data.read(&byte); while(byte != 0) { string.push_back(byte); data.read(&byte); } c.data = string; c.type = "String"; } break; case Int8: c.data = readData(data, offset + column.offset); c.type = "Int"; c.uint64Data = readDataRaw(data, offset + column.offset); break; case UInt8: c.data = readData(data, offset + column.offset); c.type = "Unsigned Int"; c.uint64Data = readDataRaw(data, offset + column.offset); break; case Int16: c.data = readData(data, offset + column.offset); c.type = "Int"; c.uint64Data = readDataRaw(data, offset + column.offset); break; case UInt16: c.data = readData(data, offset + column.offset); c.type = "Unsigned Int"; break; case Int32: c.data = readData(data, offset + column.offset); c.type = "Int"; c.uint64Data = readDataRaw(data, offset + column.offset); break; case UInt32: c.data = readData(data, offset + column.offset); c.type = "Unsigned Int"; break; case Float32: c.data = readData(data, offset + column.offset); c.type = "Float"; break; case Int64: c.data = readData(data, offset + column.offset); c.type = "Int"; c.uint64Data = readDataRaw(data, offset + column.offset); break; case UInt64: c.data = readData(data, offset + column.offset); c.type = "Unsigned Int"; c.uint64Data = readDataRaw(data, offset + column.offset); 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 boolData = readDataRaw(data, offset + column.offset); c.data = std::to_string((boolData & bit) == bit); c.type = "Boolean"; } break; default: c.data = "undefined"; c.type = "Unknown"; break; } row.data.push_back(c); } exd.rows.push_back(row); }; 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); } } } } return exd; }