From 34dd24b2612777a01157c07814bff3e1a17cb2a7 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 26 Mar 2023 11:34:21 +0200 Subject: [PATCH 1/3] Initial changes to detect when context isn't usable --- apps/openmw/mwworld/cellstore.cpp | 63 +++++++++++++++++++------------ components/esm4/reader.cpp | 2 + 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index dd589e7fdb..31c73f8461 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -764,35 +765,49 @@ namespace MWWorld static void visitCell4References(const ESM4::Cell& cell, ESM::ReadersCache& readers, ReferenceInvocable&& invocable) { auto stream = Files::openBinaryInputFileStream(cell.mReaderContext.filename); + const ESM::Format format = ESM::readFormat(*stream); + assert(format == ESM::Tes4); + stream->seekg(0); + ESM4::Reader readerESM4( std::move(stream), cell.mReaderContext.filename, MWBase::Environment::get().getResourceSystem()->getVFS()); readerESM4.setEncoder(readers.getStatelessEncoder()); - readerESM4.restoreContext(cell.mReaderContext); - bool continueRead = true; - while (ESM::RefId::formIdRefId(readerESM4.getContext().currCell) == cell.mId && readerESM4.hasMoreRecs() - && continueRead) + bool contextValid = cell.mReaderContext.filePos != -1; + if (contextValid) + readerESM4.restoreContext(cell.mReaderContext); + + while ((ESM::RefId::formIdRefId(readerESM4.getContext().currCell) == cell.mId || !contextValid) + && readerESM4.hasMoreRecs()) { - continueRead = ESM4::ReaderUtils::readItem( - readerESM4, - [&](ESM4::Reader& reader) { - auto recordType = static_cast(reader.hdr().record.typeId); - ESM::RecNameInts esm4RecName = static_cast(ESM::esm4Recname(recordType)); - if (esm4RecName == ESM::RecNameInts::REC_REFR4) - { - ESM4::Reference ref; - ref.load(reader); - invocable(ref); - return true; - } - else if (esm4RecName == ESM::RecNameInts::REC_CELL4) - { - ESM4::Cell cellToLoad; - cellToLoad.load(reader); // This is necessary to exit - } - return false; - }, - [&](ESM4::Reader& reader) {}); + readerESM4.exitGroupCheck(); + if (!ESM4::ReaderUtils::readItem( + readerESM4, + [&](ESM4::Reader& reader) { + auto recordType = static_cast(reader.hdr().record.typeId); + ESM::RecNameInts esm4RecName = static_cast(ESM::esm4Recname(recordType)); + if (esm4RecName == ESM::RecNameInts::REC_REFR4 && contextValid) + { + ESM4::Reference ref; + ref.load(reader); + invocable(ref); + return true; + } + else if (esm4RecName == ESM::RecNameInts::REC_CELL4) + { + ESM4::Cell cellToLoad; + cellToLoad.load(reader); // This is necessary to exit or to find the correct cell + if (cellToLoad.mId == cell.mId) + contextValid = true; + return true; + } + + return false; + }, + [&](ESM4::Reader& reader) {})) + { + break; + } } } diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index faf9383fdc..d6168efdae 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -134,6 +134,8 @@ namespace ESM4 ReaderContext Reader::getContext() { mCtx.filePos = mStream->tellg(); + if (mCtx.filePos == -1) + return mCtx; mCtx.filePos -= mCtx.recHeaderSize; // update file position return mCtx; } From 464092e3238023a6c0a4dee9670f1276adc25515 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Sun, 26 Mar 2023 14:13:06 +0200 Subject: [PATCH 2/3] fix oblivion and skyrim --- apps/openmw/mwworld/cellstore.cpp | 9 ++++++--- components/esm4/reader.cpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 31c73f8461..0f5009400d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -766,21 +766,22 @@ namespace MWWorld { auto stream = Files::openBinaryInputFileStream(cell.mReaderContext.filename); const ESM::Format format = ESM::readFormat(*stream); - assert(format == ESM::Tes4); + assert(format == ESM::Format::Tes4); stream->seekg(0); ESM4::Reader readerESM4( std::move(stream), cell.mReaderContext.filename, MWBase::Environment::get().getResourceSystem()->getVFS()); readerESM4.setEncoder(readers.getStatelessEncoder()); - bool contextValid = cell.mReaderContext.filePos != -1; + bool contextValid = cell.mReaderContext.filePos != std::numeric_limits::max(); if (contextValid) readerESM4.restoreContext(cell.mReaderContext); while ((ESM::RefId::formIdRefId(readerESM4.getContext().currCell) == cell.mId || !contextValid) && readerESM4.hasMoreRecs()) { - readerESM4.exitGroupCheck(); + if (!contextValid) + readerESM4.exitGroupCheck(); if (!ESM4::ReaderUtils::readItem( readerESM4, [&](ESM4::Reader& reader) { @@ -788,6 +789,7 @@ namespace MWWorld ESM::RecNameInts esm4RecName = static_cast(ESM::esm4Recname(recordType)); if (esm4RecName == ESM::RecNameInts::REC_REFR4 && contextValid) { + reader.getRecordData(); ESM4::Reference ref; ref.load(reader); invocable(ref); @@ -795,6 +797,7 @@ namespace MWWorld } else if (esm4RecName == ESM::RecNameInts::REC_CELL4) { + reader.getRecordData(); ESM4::Cell cellToLoad; cellToLoad.load(reader); // This is necessary to exit or to find the correct cell if (cellToLoad.mId == cell.mId) diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index d6168efdae..e599034c8f 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -134,7 +134,7 @@ namespace ESM4 ReaderContext Reader::getContext() { mCtx.filePos = mStream->tellg(); - if (mCtx.filePos == -1) + if (mCtx.filePos == std::numeric_limits::max()) return mCtx; mCtx.filePos -= mCtx.recHeaderSize; // update file position return mCtx; From a3a77670933651950954a1457a8df8db42dc3540 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 27 Mar 2023 22:29:33 +0200 Subject: [PATCH 3/3] applies review changes filepos changed to an actual file pos moved lambda declaration out of function call --- apps/openmw/mwworld/cellstore.cpp | 62 +++++++++++++++---------------- components/esm4/reader.cpp | 2 +- components/esm4/reader.hpp | 2 +- 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 0f5009400d..bc99ba7d7d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -765,52 +765,48 @@ namespace MWWorld static void visitCell4References(const ESM4::Cell& cell, ESM::ReadersCache& readers, ReferenceInvocable&& invocable) { auto stream = Files::openBinaryInputFileStream(cell.mReaderContext.filename); - const ESM::Format format = ESM::readFormat(*stream); - assert(format == ESM::Format::Tes4); stream->seekg(0); ESM4::Reader readerESM4( std::move(stream), cell.mReaderContext.filename, MWBase::Environment::get().getResourceSystem()->getVFS()); readerESM4.setEncoder(readers.getStatelessEncoder()); - bool contextValid = cell.mReaderContext.filePos != std::numeric_limits::max(); + bool contextValid = cell.mReaderContext.filePos != std::streampos(-1); if (contextValid) readerESM4.restoreContext(cell.mReaderContext); - while ((ESM::RefId::formIdRefId(readerESM4.getContext().currCell) == cell.mId || !contextValid) - && readerESM4.hasMoreRecs()) + while ( + (ESM::RefId::formIdRefId(readerESM4.currCell()) == cell.mId || !contextValid) && readerESM4.hasMoreRecs()) { if (!contextValid) readerESM4.exitGroupCheck(); - if (!ESM4::ReaderUtils::readItem( - readerESM4, - [&](ESM4::Reader& reader) { - auto recordType = static_cast(reader.hdr().record.typeId); - ESM::RecNameInts esm4RecName = static_cast(ESM::esm4Recname(recordType)); - if (esm4RecName == ESM::RecNameInts::REC_REFR4 && contextValid) - { - reader.getRecordData(); - ESM4::Reference ref; - ref.load(reader); - invocable(ref); - return true; - } - else if (esm4RecName == ESM::RecNameInts::REC_CELL4) - { - reader.getRecordData(); - ESM4::Cell cellToLoad; - cellToLoad.load(reader); // This is necessary to exit or to find the correct cell - if (cellToLoad.mId == cell.mId) - contextValid = true; - return true; - } - - return false; - }, - [&](ESM4::Reader& reader) {})) - { + + auto onRecord = [&](ESM4::Reader& reader) { + auto recordType = static_cast(reader.hdr().record.typeId); + ESM::RecNameInts esm4RecName = static_cast(ESM::esm4Recname(recordType)); + if (esm4RecName == ESM::RecNameInts::REC_REFR4 && contextValid) + { + reader.getRecordData(); + ESM4::Reference ref; + ref.load(reader); + invocable(ref); + return true; + } + else if (esm4RecName == ESM::RecNameInts::REC_CELL4) + { + reader.getRecordData(); + ESM4::Cell cellToLoad; + cellToLoad.load(reader); // This is necessary to exit or to find the correct cell + if (cellToLoad.mId == cell.mId) + contextValid = true; + return true; + } + + return false; + }; + + if (!ESM4::ReaderUtils::readItem(readerESM4, onRecord, [&](ESM4::Reader& reader) {})) break; - } } } diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index e599034c8f..091df5abf1 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -134,7 +134,7 @@ namespace ESM4 ReaderContext Reader::getContext() { mCtx.filePos = mStream->tellg(); - if (mCtx.filePos == std::numeric_limits::max()) + if (mCtx.filePos == std::streampos(-1)) return mCtx; mCtx.filePos -= mCtx.recHeaderSize; // update file position return mCtx; diff --git a/components/esm4/reader.hpp b/components/esm4/reader.hpp index 0b792dcf28..91bd44a156 100644 --- a/components/esm4/reader.hpp +++ b/components/esm4/reader.hpp @@ -62,7 +62,7 @@ namespace ESM4 // case the file was re-opened. default = TES5 size, // can be reduced for TES4 by setRecHeaderSize() - std::size_t filePos; // assume that the record header will be re-read once + std::streampos filePos; // assume that the record header will be re-read once // the context is restored // for keeping track of things