you are right, derkunde, i used uint32 for id instead of uint64 so it was shifted 
The source i use:
Code:
struct LocalizedStringEntry
{
uint64 id;
wchar_t* enumName;
wchar_t* lang1, *lang2, *lang3, *lang4;
uint32 soundEventID, version;
wchar_t* string;
uint32 vrecv0, vrecv1, vrecv2, vrecv3;
uint32 unitVoiceType, stringContext;
};
DTableFile<LocalizedStringEntry> dtf(L"DB\\LocalizedStrings.tbl", L"lsssssuusuuuuuu");
auto titles = dtf.getColumnTitles();
std::ofstream out(L"LocalizedStrings.tbl.csv", std::ios::out);
bool first = true;
for(auto title : titles) {
if(first == false) {
out << ",";
} else {
first = false;
}
out << toAnsi(title);
}
out << std::endl;
for(auto rec : dtf.getRecords()) {
out << rec.id << ",";
writeString(out, rec.enumName);
out << ",";
writeString(out, rec.lang1);
out << ",";
writeString(out, rec.lang2);
out << ",";
writeString(out, rec.lang3);
out << ",";
writeString(out, rec.lang4);
out << "," << rec.soundEventID << "," << rec.version << ",";
writeString(out, rec.string);
out << "," << rec.vrecv0 << "," << rec.vrecv1 << "," << rec.vrecv2 << "," << rec.vrecv3 << ",";
out << rec.unitVoiceType << "," << rec.stringContext << std::endl;
}
with DTableFile like that:
Code:
template<typename T>
class DTableFile
{
struct DTBLHeader
{
uint32 magic;
uint32 version;
uint64 lenTableName;
uint64 unk1;
uint64 recordSize;
uint64 numRows;
uint64 ofsFieldDesc;
uint64 numEntries;
uint64 sizeEntryBlock;
uint64 ofsEntries;
uint64 maxEntry;
uint64 ofsIDLookup;
uint64 unk3Zero;
};
enum class FieldType : uint32
{
UInt32 = 3,
Float = 4,
StringTableOffset = 0x82,
ForceDword = 0xFFFFFFFF
};
struct FieldDescEntry
{
uint64 unk1;
uint64 ofsFieldTitleTable;
FieldType type;
uint32 unk6;
};
DTBLHeader mHeader;
std::vector<FieldDescEntry> mFieldDescs;
std::wstring mTableName;
std::vector<int32> mIDLookup;
std::vector<std::wstring> mColumnHeaders;
std::vector<T> mRecords;
std::wstring mFileName;
BinStreamPtr mStream;
public:
DTableFile(const std::wstring& fileName, const std::wstring& format);
const std::vector<T>& getRecords() const { return mRecords; }
const std::vector<std::wstring>& getColumnTitles() const { return mColumnHeaders; }
};
template<typename T>
DTableFile<T>::DTableFile(const std::wstring& fileName, const std::wstring& format) {
mFileName = fileName;
auto entry = CWildstarStudioDlg::getFile(fileName);
if(entry == nullptr) {
throw std::exception("File not found!");
}
std::vector<uint8> content;
CWildstarStudioDlg::getFileContent(entry, content);
mStream = std::make_shared<BinStream>(content);
mHeader = mStream->read<DTBLHeader>();
mStream->seek(mHeader.ofsFieldDesc + 0x60);
mFieldDescs.resize(mHeader.numRows);
mStream->read(mFieldDescs.data(), sizeof(FieldDescEntry) * mHeader.numRows);
std::vector<wchar_t> tableName(mHeader.lenTableName);
mStream->seek(0x60);
mStream->read(tableName.data(), tableName.size() * sizeof(wchar_t));
tableName.push_back((wchar_t)0);
mTableName = tableName.data();
uint32 offset = mFieldDescs.size() * sizeof(FieldDescEntry) + mHeader.ofsFieldDesc + 0x60;
if(offset % 16) {
offset += 16 - (offset % 16);
}
for(uint32 i = 0; i < mHeader.numRows; ++i) {
wchar_t* title = (wchar_t*)mStream->getPointer(offset + mFieldDescs[i].ofsFieldTitleTable);
mColumnHeaders.push_back(title);
}
mStream->seek(mHeader.ofsEntries + 0x60);
std::vector<uint8> buffer(mHeader.recordSize);
for(uint32 i = 0; i < mHeader.numEntries; ++i) {
T t;
uint8* tPtr = (uint8*)&t;
mStream->read(buffer.data(), buffer.size());
uint32 nextPos = mStream->tell();
uint32 bufferPos = 0;
for(uint32 j = 0; j < mHeader.numRows; ++j) {
switch(format.at(j)) {
case 'l':
{
*(uint64*)tPtr = *(uint64*)&buffer[bufferPos];
tPtr += 8;
bufferPos += 8;
}
break;
case 'u':
{
*(uint32*)tPtr = *(uint32*)&buffer[bufferPos];
tPtr += 4;
bufferPos += 4;
}
break;
case 'f':
{
*(float*)tPtr = *(float*)&buffer[bufferPos];
tPtr += 4;
bufferPos += 4;
}
break;
case 's':
{
uint64 offset = *(uint64*)&buffer[bufferPos] + mHeader.ofsEntries + 0x60;
bufferPos += 8;
LPBYTE strPtr = mStream->getPointer(offset);
wchar_t* str = _wcsdup((const wchar_t*)strPtr);
*(wchar_t**)tPtr = str;
tPtr += sizeof(wchar_t**);
}
break;
}
}
mRecords.push_back(t);
mStream->seek(nextPos);
}
}