#include "skyrimsavegame.h" #ifdef _WIN32 #include #else #include #include // SYSTEMTIME is _SYSTEMTIME (defined in gamebryosavegame.h for Linux) using SYSTEMTIME = _SYSTEMTIME; // Portable FileTimeToSystemTime: converts Windows FILETIME to SYSTEMTIME static void FileTimeToSystemTime(const FILETIME* ft, SYSTEMTIME* st) { const uint64_t ticks = (static_cast(ft->dwHighDateTime) << 32) | static_cast(ft->dwLowDateTime); const int64_t unixSecs = static_cast(ticks / 10000000ULL) - 11644473600LL; const uint64_t remainderHns = ticks % 10000000ULL; // leftover 100ns units const QDateTime dt = QDateTime::fromSecsSinceEpoch(unixSecs, QTimeZone::UTC); const QDate d = dt.date(); const QTime t = dt.time(); st->wYear = static_cast(d.year()); st->wMonth = static_cast(d.month()); st->wDayOfWeek = static_cast(d.dayOfWeek() % 7); // Qt Mon=1..Sun=7 -> Win Sun=0..Sat=6 st->wDay = static_cast(d.day()); st->wHour = static_cast(t.hour()); st->wMinute = static_cast(t.minute()); st->wSecond = static_cast(t.second()); st->wMilliseconds = static_cast(remainderHns / 10000); } #endif #include "gameskyrim.h" SkyrimSaveGame::SkyrimSaveGame(QString const& fileName, GameSkyrim const* game) : GamebryoSaveGame(fileName, game) { FileWrapper file(getFilepath(), "TESV_SAVEGAME"); FILETIME ftime; fetchInformationFields(file, m_SaveNumber, m_PCName, m_PCLevel, m_PCLocation, ftime); // A file time is a 64-bit value that represents the number of 100-nanosecond // intervals that have elapsed since 12:00 A.M. January 1, 1601 Coordinated Universal // Time (UTC). So we need to convert that to something useful SYSTEMTIME ctime; ::FileTimeToSystemTime(&ftime, &ctime); setCreationTime(ctime); } void SkyrimSaveGame::fetchInformationFields( FileWrapper& file, uint32_t& saveNumber, QString& playerName, unsigned short& playerLevel, QString& playerLocation, FILETIME& creationTime) const { file.skip(); // header size file.skip(); // header version file.read(saveNumber); file.read(playerName); uint32_t temp; file.read(temp); playerLevel = static_cast(temp); file.setPluginStringFormat(GamebryoSaveGame::StringFormat::LOCAL8BIT); file.read(playerLocation); file.setPluginStringFormat(GamebryoSaveGame::StringFormat::UTF8); QString timeOfDay; file.read(timeOfDay); QString race; file.read(race); // race name (i.e. BretonRace) file.skip(); // Player gender (0 = male) file.skip(2); // experience gathered, experience required file.read(creationTime); } std::unique_ptr SkyrimSaveGame::fetchDataFields() const { FileWrapper file(getFilepath(), "TESV_SAVEGAME"); std::unique_ptr fields = std::make_unique(); { QString dummyName, dummyLocation; unsigned short dummyLevel; uint32_t dummySaveNumber; FILETIME dummyTime; fetchInformationFields(file, dummySaveNumber, dummyName, dummyLevel, dummyLocation, dummyTime); } fields->Screenshot = file.readImage(); file.skip(); // form version file.skip(); // plugin info size fields->Plugins = file.readPlugins(); return fields; }