#include "STRG.hpp" #include "DNAMP1.hpp" namespace Retro { namespace DNAMP1 { void STRG::_read(Athena::io::IStreamReader& reader) { atUint32 langCount = reader.readUint32(); atUint32 strCount = reader.readUint32(); std::vector<FourCC> readLangs; readLangs.reserve(langCount); for (atUint32 l=0 ; l<langCount ; ++l) { FourCC lang; lang.read(reader); readLangs.emplace_back(lang); reader.seek(4); } langs.clear(); langs.reserve(langCount); for (FourCC& lang : readLangs) { std::vector<std::wstring> strs; reader.seek(strCount * 4 + 4); for (atUint32 s=0 ; s<strCount ; ++s) strs.emplace_back(reader.readWString()); langs.emplace_back(lang, strs); } langMap.clear(); langMap.reserve(langCount); for (std::pair<FourCC, std::vector<std::wstring>>& item : langs) langMap.emplace(item.first, &item.second); } void STRG::read(Athena::io::IStreamReader& reader) { reader.setEndian(Athena::BigEndian); atUint32 magic = reader.readUint32(); if (magic != 0x87654321) Log.report(LogVisor::Error, "invalid STRG magic"); atUint32 version = reader.readUint32(); if (version != 0) Log.report(LogVisor::Error, "invalid STRG version"); _read(reader); } void STRG::write(Athena::io::IStreamWriter& writer) const { writer.setEndian(Athena::BigEndian); writer.writeUint32(0x87654321); writer.writeUint32(0); writer.writeUint32(langs.size()); atUint32 strCount = STRG::count(); writer.writeUint32(strCount); atUint32 offset = 0; for (const std::pair<FourCC, std::vector<std::wstring>>& lang : langs) { lang.first.write(writer); writer.writeUint32(offset); offset += strCount * 4 + 4; atUint32 langStrCount = lang.second.size(); for (atUint32 s=0 ; s<strCount ; ++s) { atUint32 chCount = lang.second[s].size(); if (s < langStrCount) offset += chCount * 2 + 1; else offset += 1; } } for (const std::pair<FourCC, std::vector<std::wstring>>& lang : langs) { atUint32 langStrCount = lang.second.size(); atUint32 tableSz = strCount * 4; for (atUint32 s=0 ; s<strCount ; ++s) { if (s < langStrCount) tableSz += lang.second[s].size() * 2 + 1; else tableSz += 1; } writer.writeUint32(tableSz); offset = strCount * 4; for (atUint32 s=0 ; s<strCount ; ++s) { writer.writeUint32(offset); if (s < langStrCount) offset += lang.second[s].size() * 2 + 1; else offset += 1; } for (atUint32 s=0 ; s<strCount ; ++s) { if (s < langStrCount) writer.writeWString(lang.second[s]); else writer.writeUByte(0); } } } bool STRG::readAngelScript(const AngelScript::asIScriptModule& in) { std::wstring_convert<std::codecvt_utf8<wchar_t>> wconv; /* Validate pass */ for (AngelScript::asUINT i=0 ; i<in.GetGlobalVarCount() ; ++i) { const char* name; int typeId; if (in.GetGlobalVar(i, &name, 0, &typeId) < 0) continue; if (typeId == ASTYPE_STRGLanguage.getTypeID()) { if (strlen(name) != 4) { Log.report(LogVisor::Error, "STRG language string '%s' from %s must be exactly 4 characters", name, in.GetName()); return false; } } } /* Read pass */ langs.clear(); for (AngelScript::asUINT i=0 ; i<in.GetGlobalVarCount() ; ++i) { const char* name; int typeId; if (in.GetGlobalVar(i, &name, 0, &typeId) < 0) continue; if (typeId == ASTYPE_STRGLanguage.getTypeID()) { const std::vector<std::string*>& strsin = ASTYPE_STRGLanguage.vectorCast(in.GetAddressOfGlobalVar(i)); std::vector<std::wstring> strs; for (const std::string* str : strsin) strs.emplace_back(wconv.from_bytes(*str)); langs.emplace_back(FourCC(name), strs); } } langMap.clear(); langMap.reserve(langs.size()); for (std::pair<FourCC, std::vector<std::wstring>>& item : langs) langMap.emplace(item.first, &item.second); return true; } void STRG::writeAngelScript(std::ofstream& out) const { std::wstring_convert<std::codecvt_utf8<wchar_t>> wconv; for (const std::pair<FourCC, std::vector<std::wstring>>& lang : langs) { out << "STRG::Language " << lang.first.toString() << "({"; bool comma = false; unsigned idx = 0; for (const std::wstring& str : lang.second) { if (comma) out << ","; out << "\n/* " << idx++ << " */ \""; out << wconv.to_bytes(str); out << "\""; comma = true; } out << "\n});\n"; } } } }