diff --git a/code/nel/tools/pipeline/max/builtin/app_data.cpp b/code/nel/tools/pipeline/max/builtin/app_data.cpp index f30b3fd8e..68f9cff71 100644 --- a/code/nel/tools/pipeline/max/builtin/app_data.cpp +++ b/code/nel/tools/pipeline/max/builtin/app_data.cpp @@ -151,6 +151,9 @@ void CAppData::parse(uint16 version, TParseLevel level) { if (level & PARSE_BUILTIN) { + // Cannot be parsed yet + if (!m_ChunksOwnsPointers) { nlerror("Already parsed"); return; } + // First parse all the child nodes CStorageContainer::parse(version, level); @@ -183,8 +186,8 @@ void CAppData::parse(uint16 version, TParseLevel level) void CAppData::clean() { - if (m_ChunksOwnsPointers) { nldebug("Not parsed"); return; } // Must have local ownership - if (m_Chunks.size() == 0) { nlwarning("Bad container size"); return; } // Already cleaned + if (m_ChunksOwnsPointers) { nldebug("Not parsed, or disowned"); return; } // Must have local ownership + if (m_Chunks.size() == 0) { nlwarning("Already cleaned (or did not build due to coding error)"); return; } // Already cleaned if (m_Chunks.begin()->first != NLMAXFILE_APP_DATA_HEADER_CHUNK_ID) { nlerror("Bad id %x, expected %x", (uint32)m_Chunks.begin()->first, NLMAXFILE_APP_DATA_HEADER_CHUNK_ID); return; } // Cannot happen, because we won't have local ownership if parsing failed delete m_Chunks.begin()->second; // Delete the header chunk, since we own it m_Chunks.clear(); // Clear the remaining chunks @@ -194,7 +197,7 @@ void CAppData::build(uint16 version) { // Must be clean first if (!m_ChunksOwnsPointers && m_Chunks.size() != 0) { nlerror("Not cleaned"); return; } - if (m_Chunks.size() != 0) { nldebug("Not parsed"); return; } + if (m_Chunks.size() != 0) { nldebug("Not parsed, or disowned"); return; } // Set up the header in the chunks container CStorageValue *headerSize = new CStorageValue(); // Owned locally, not by m_Chunks @@ -211,12 +214,15 @@ void CAppData::disown() if (m_ChunksOwnsPointers) { nldebug("Not parsed"); } if (!m_ChunksOwnsPointers && (m_Chunks.size() != (m_Entries.size() + 1))) { nlerror("Not built"); return; } // If chunks is not the owner, built chunks must match the parsed data // NOTE: m_Chunks must be valid at this point! - // Disown all the child chunks - CStorageContainer::disown(); + // Disown locally m_Entries.clear(); + // Give ownership back m_ChunksOwnsPointers = true; + + // Disown all the child chunks + CStorageContainer::disown(); } void CAppData::init() diff --git a/code/nel/tools/pipeline/max/scene_class.cpp b/code/nel/tools/pipeline/max/scene_class.cpp index 5d0f80b00..224d025e9 100644 --- a/code/nel/tools/pipeline/max/scene_class.cpp +++ b/code/nel/tools/pipeline/max/scene_class.cpp @@ -29,6 +29,7 @@ #include "scene_class.h" // STL includes +#include // NeL includes // #include @@ -65,29 +66,96 @@ std::string CSceneClass::getClassName() void CSceneClass::toString(std::ostream &ostream, const std::string &pad) { - CStorageContainer::toString(ostream, pad); + if (m_ChunksOwnsPointers) + { + CStorageContainer::toString(ostream, pad); + } + else + { + ostream << "(" << getClassName() << ": " << ucstring(getClassDesc()->displayName()).toUtf8() << ", " << getClassDesc()->classId().toString() << ", " << ucstring(getClassDesc()->dllPluginDesc()->internalName()).toUtf8() << ") [" << m_Chunks.size() << "] { "; + toStringLocal(ostream, pad); + ostream << "} "; + } } void CSceneClass::parse(uint16 version, TParseLevel level) { + // Cannot be parsed yet + if (!m_ChunksOwnsPointers) { nlerror("Already parsed"); return; } // Already parsed, illegal to call twice + + // Parse all child chunks CStorageContainer::parse(version, level); + + // Orphanize all child chunk + m_OrphanedChunks.insert(m_OrphanedChunks.end(), m_Chunks.begin(), m_Chunks.end()); + + // Take ownership + m_ChunksOwnsPointers = false; + + // Inheriting classes take control from here on, they should check + // m_ChunksOwnsPointers to be false before taking action, in case + // a subclass called disown due to failure. } void CSceneClass::clean() { - CStorageContainer::clean(); + if (m_ChunksOwnsPointers) { nldebug("Not parsed, or disowned"); return; } // Must have local ownership, parsing may have failed + if (m_Chunks.size() == 0 && m_OrphanedChunks.size() != 0) { nlwarning("Already cleaned"); return; } // Already cleaned, should not call twice, not reliable because not all chunks have child chunks + + // Clear unneeded references from the parent + m_Chunks.clear(); + + // Clean owned child chunks + for (TStorageObjectContainer::const_iterator it = m_OrphanedChunks.begin(), end = m_OrphanedChunks.end(); it != end; ++it) + { + if (it->second->isContainer()) + { + nldebug("Cleaning orphan child"); + static_cast(it->second)->clean(); + } + } } void CSceneClass::build(uint16 version) { + // Must be clean first + if (!m_ChunksOwnsPointers && m_Chunks.size() != 0) { nlerror("Not cleaned"); return; } // Cannot call twice, illegal call + if (m_Chunks.size() != 0) { nldebug("Not parsed, or disowned"); return; } // Don't have local ownership, parsing may have failed, the built version is implicitly up to date + + // Store orphan chunks + m_Chunks.insert(m_Chunks.end(), m_OrphanedChunks.begin(), m_OrphanedChunks.end()); + + // Build the orphan chunks (this is a little trick to do it this + // way here, don't do this from subclasses) CStorageContainer::build(version); + + // Set the insertion pointer before the orphans + m_PutChunkInsert = m_Chunks.begin(); + + // Inheriting classes take control from here on, so the build is + // called to owned subclasses from the putChunk function. } void CSceneClass::disown() { + if (m_ChunksOwnsPointers) { nldebug("Not parsed"); } + if (!m_ChunksOwnsPointers && (m_Chunks.size() < m_OrphanedChunks.size())) { nlerror("Not built"); return; } // If chunks is not the owner, built chunks must match the parsed data. This check is not fully reliable + + // Clear local references + m_OrphanedChunks.clear(); + + // Return ownership + m_ChunksOwnsPointers = true; + + // Disown children CStorageContainer::disown(); } +void CSceneClass::init() +{ + // Nothing to do here! +} + IStorageObject *CSceneClass::createChunkById(uint16 id, bool container) { // Temporary @@ -113,6 +181,26 @@ const ISceneClassDesc *CSceneClass::getClassDesc() return static_cast(&SceneClassDesc); } +void CSceneClass::toStringLocal(std::ostream &ostream, const std::string &pad) const +{ + std::string padpad = pad + "\t"; + sint i = 0; + for (TStorageObjectContainer::const_iterator it = m_OrphanedChunks.begin(), end = m_OrphanedChunks.end(); it != end; ++it) + { + std::stringstream ss; + ss << std::hex << std::setfill('0'); + ss << std::setw(4) << it->first; + ostream << "\n" << pad << i << " 0x" << ss.str() << ": "; + it->second->toString(ostream, padpad); + ++i; + } +} + +IStorageObject *CSceneClass::getChunk(uint16 id) +{ + return NULL; +} + //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// diff --git a/code/nel/tools/pipeline/max/scene_class.h b/code/nel/tools/pipeline/max/scene_class.h index fd1bf3874..78e1a433e 100644 --- a/code/nel/tools/pipeline/max/scene_class.h +++ b/code/nel/tools/pipeline/max/scene_class.h @@ -90,7 +90,7 @@ public: /// Return the class description of the inheriting class virtual const ISceneClassDesc *getClassDesc(); /// Create a readable representation of this class - virtual void toStringLocal(std::ostream &ostream, const std::string &pad = ""); + virtual void toStringLocal(std::ostream &ostream, const std::string &pad = "") const; //@} public: @@ -105,7 +105,7 @@ protected: /// Use during parsing. Gets the chunk with specified id. Warnings when chunks are skipped may be elevated to errors. Remaining orphaned chunks will be appended after chunks that are written by the classes. Returns NULL when the chunk does not exist. Empty chunks are often not written by classes. You have ownership over the chunk until it is disowned. In case that the chunk cannot be parsed, call disown and abort parsing. If this function returns NULL it is also possible that the parsing has been aborted when m_ChunksOwnsPointers is true IStorageObject *getChunk(uint16 id); /// Use during file build. Adds a chunk to the chunks that will be written to the file. Build is called when a chunk is passed through - void putChunk(uint16 id, IStorageObject *storageObject) + void putChunk(uint16 id, IStorageObject *storageObject); //@} protected: diff --git a/code/nel/tools/pipeline/max/scene_class_unknown.cpp b/code/nel/tools/pipeline/max/scene_class_unknown.cpp index 36cfdcd4c..99bacb434 100644 --- a/code/nel/tools/pipeline/max/scene_class_unknown.cpp +++ b/code/nel/tools/pipeline/max/scene_class_unknown.cpp @@ -29,7 +29,6 @@ #include "scene_class_unknown.h" // STL includes -#include // NeL includes // #include @@ -121,7 +120,7 @@ CSceneClassUnknown::~CSceneClassUnknown() void CSceneClassUnknown::toString(std::ostream &ostream, const std::string &pad) { - nlassert(m_ChunksOwnsPointers); + /*nlassert(m_ChunksOwnsPointers); ostream << "(" << getClassName() << ": " << ucstring(getClassDesc()->displayName()).toUtf8() << ", " << getClassDesc()->classId().toString() << ", " << ucstring(getClassDesc()->dllPluginDesc()->internalName()).toUtf8() << ") [" << m_Chunks.size() << "] { "; std::string padpad = pad + "\t"; sint i = 0; @@ -134,7 +133,8 @@ void CSceneClassUnknown::toString(std::ostream &ostream, const std::string &pad) it->second->toString(ostream, padpad); ++i; } - ostream << "} "; + ostream << "} ";*/ + CSceneClass::toString(ostream, pad); } void CSceneClassUnknown::parse(uint16 version, TParseLevel level) diff --git a/code/nel/tools/pipeline/max/storage_object.cpp b/code/nel/tools/pipeline/max/storage_object.cpp index 4c30a709c..47d189aef 100644 --- a/code/nel/tools/pipeline/max/storage_object.cpp +++ b/code/nel/tools/pipeline/max/storage_object.cpp @@ -196,6 +196,7 @@ void CStorageContainer::toString(std::ostream &ostream, const std::string &pad) void CStorageContainer::parse(uint16 version, TParseLevel level) { + nlassert(m_ChunksOwnsPointers); // Can only use this when m_Chunks still has ownership. for (TStorageObjectContainer::const_iterator it = m_Chunks.begin(), end = m_Chunks.end(); it != end; ++it) { if (it->second->isContainer()) @@ -230,6 +231,7 @@ void CStorageContainer::build(uint16 version) void CStorageContainer::disown() { + nlassert(m_ChunksOwnsPointers); // Can only use this when m_Chunks has been given ownership. for (TStorageObjectContainer::const_iterator it = m_Chunks.begin(), end = m_Chunks.end(); it != end; ++it) { if (it->second->isContainer())