From abea66d6f0443c5f7a6b087c69929a5ef9f16e01 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Sat, 30 Sep 2023 14:24:37 +0800 Subject: [PATCH] fix including file error in CKFile. update reader -> writer method --- LibCmo/CK2/CKFile.hpp | 40 +++++--- LibCmo/CK2/CKFileOthers.cpp | 154 ++++++++++++++++++++---------- LibCmo/CK2/CKFileReader.cpp | 2 +- LibCmo/CK2/CKFileWriter.cpp | 28 +++--- LibCmo/CK2/ObjImpls/CKTexture.cpp | 4 +- Unvirt/StructFormatter.cpp | 2 +- Unvirt/UnvirtContext.cpp | 7 +- Unvirt/UnvirtContext.hpp | 1 + 8 files changed, 153 insertions(+), 85 deletions(-) diff --git a/LibCmo/CK2/CKFile.hpp b/LibCmo/CK2/CKFile.hpp index 29a2a90..43ed04c 100644 --- a/LibCmo/CK2/CKFile.hpp +++ b/LibCmo/CK2/CKFile.hpp @@ -107,7 +107,7 @@ namespace LibCmo::CK2 { CKDWORD FileSize; /**< Size of file in bytes. */ CKDWORD ObjectCount; /**< Number of objects stored in the file. */ CKDWORD ManagerCount; /**< Number of managers which saved data in the file. */ - CKDWORD MaxIDSaved; /**< Maximum Object identifier saved */ + CK_ID MaxIDSaved; /**< Maximum Object identifier saved */ CKDWORD Crc; /**< Crc of data */ CKDWORD Hdr1PackSize; /**< The compressed size of Header section. */ CKDWORD Hdr1UnPackSize; /**< The uncompressed size of Header section. */ @@ -195,7 +195,7 @@ namespace LibCmo::CK2 { CKERROR DeepLoad(CKSTRING u8_filename); // ========== Loading Result ========== - CKINT GetSaveIdMax(); + CK_ID GetSaveIdMax(); const XContainer::XArray& GetFileObjects(); const XContainer::XArray& GetManagersData(); const XContainer::XArray& GetPluginsDep(); @@ -204,12 +204,16 @@ namespace LibCmo::CK2 { protected: bool m_Done; - CKINT m_SaveIDMax; /**< Maximum CK_ID found when saving or loading objects */ + CK_ID m_SaveIDMax; /**< Maximum CK_ID found when saving or loading objects */ XContainer::XArray m_FileObjects; /**< List of objects being saved / loaded */ XContainer::XArray m_ManagersData; /**< Manager Data loaded */ XContainer::XArray m_PluginsDep; /**< Plugins dependencies for this file */ // XContainer::XClassArray m_IndexByClassId; /**< List of index in the m_FileObjects table sorted by ClassID */ - XContainer::XArray m_IncludedFiles; /**< List of files that should be inserted in the CMO file. */ + /** + * @brief List of files that should be inserted in the CMO file. + * @remark Each item is just file name, not the full path to file. + */ + XContainer::XArray m_IncludedFiles; CKFileInfo m_FileInfo; /**< Headers summary */ CKERROR ReadFileHeader(CKBufferParser* ParserPtr); @@ -223,7 +227,7 @@ namespace LibCmo::CK2 { friend class CKFileVisitor; public: CKFileWriter(CKContext* ctx); - CKFileWriter(CKContext* ctx, CKFileReader* reader); + CKFileWriter(CKContext* ctx, CKFileReader* reader, bool is_shallow); ~CKFileWriter(); LIBCMO_DISABLE_COPY_MOVE(CKFileWriter); @@ -238,19 +242,29 @@ namespace LibCmo::CK2 { protected: bool m_Done; /** - * True if this writer is copy from reader. - * The data copied from reader mean that calling just only do some small modification. - * So we don't need try getting some managers or save file options from CKContext. - * Just apply the data coming from reader. - * Also, Add object functions is not allowed when writer copying from reader. + * @brief True if this writer is not allowed to add objects. + * @remark + * + This field should be false in default. + * + This field usually be set when importing from reader. */ - bool m_IsCopyFromReader; + bool m_DisableAddingObject; + /** + * @brief True if this writer is not allowed to add files. + * @remark + * + This field should be false in default. + * + This field usually be set when importing from reader. + */ + bool m_DisableAddingFile; - CKINT m_SaveIDMax; /**< Maximum CK_ID found when saving or loading objects */ + CK_ID m_SaveIDMax; /**< Maximum CK_ID found when saving or loading objects */ XContainer::XArray m_FileObjects; /**< List of objects being saved / loaded */ XContainer::XArray m_ManagersData; /**< Manager Data loaded */ XContainer::XArray m_PluginsDep; /**< Plugins dependencies for this file */ - XContainer::XArray m_IncludedFiles; /**< List of files that should be inserted in the CMO file. */ + /** + * @brief List of files that should be inserted in the CMO file. + * @remark Each item is the full path to file. + */ + XContainer::XArray m_IncludedFiles; XContainer::XHashTable m_ObjectsHashTable; /**< A Object ID to save index hash table. */ XContainer::XBitArray m_AlreadySavedMask; /**< Field recording saved object id. If this object is saved, set m_AlreadySavedMask[id] to true. Also used to check whether object already is in save list. */ CKFileInfo m_FileInfo; /**< Headers summary */ diff --git a/LibCmo/CK2/CKFileOthers.cpp b/LibCmo/CK2/CKFileOthers.cpp index e1e9b6f..5330a24 100644 --- a/LibCmo/CK2/CKFileOthers.cpp +++ b/LibCmo/CK2/CKFileOthers.cpp @@ -1,5 +1,7 @@ #include "CKFile.hpp" #include "CKStateChunk.hpp" +#include "CKContext.hpp" +#include "MgrImpls/CKPathManager.hpp" #include "ObjImpls/CKObject.hpp" #include @@ -132,7 +134,7 @@ namespace LibCmo::CK2 { CKFileReader::~CKFileReader() {} - CKINT CKFileReader::GetSaveIdMax() { + CK_ID CKFileReader::GetSaveIdMax() { return m_SaveIDMax; } @@ -162,78 +164,124 @@ namespace LibCmo::CK2 { CKFileWriter::CKFileWriter(CKContext* ctx) : m_Ctx(ctx), m_Visitor(this), - m_Done(false), m_IsCopyFromReader(false), + m_Done(false), + m_DisableAddingObject(false), m_DisableAddingFile(false), m_SaveIDMax(0), m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(), m_FileInfo() {} - CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader) : + CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader, bool is_shallow) : m_Ctx(ctx), m_Visitor(this), - m_Done(false), m_IsCopyFromReader(true), + m_Done(false), + m_DisableAddingObject(true), m_DisableAddingFile(!is_shallow), // only disable adding file in shallow mode. but disable adding object in all mode. m_SaveIDMax(0), m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(), m_FileInfo() { - // sync save id max - this->m_SaveIDMax = reader->GetSaveIdMax(); + if (is_shallow) { - // copy objects - for (const auto& item : reader->GetFileObjects()) { - CKFileObject obj; - // copy CKObject pointer - obj.ObjPtr = item.ObjPtr; - // and use ctor to copy CKStateChunk - if (item.Data == nullptr) { - obj.Data = nullptr; - } else { - obj.Data = new CKStateChunk(*item.Data); +#pragma region Shallow Assign + + // sync save id max + this->m_SaveIDMax = reader->GetSaveIdMax(); + + // copy statechunk + for (const auto& item : reader->GetFileObjects()) { + CKFileObject obj; + + // use ctor to copy CKStateChunk + if (item.Data == nullptr) { + obj.Data = nullptr; + } else { + obj.Data = new CKStateChunk(*item.Data); + } + + // set other data + obj.ObjectId = item.ObjectId; + obj.CreatedObjectId = 0; + obj.ObjectCid = item.ObjectCid; + obj.ObjPtr = nullptr; // set zero for obj + obj.Name = item.Name; + obj.SaveFlags = item.SaveFlags; + + // insert + m_FileObjects.emplace_back(std::move(obj)); } - // copy other data - obj.ObjectId = item.ObjectId; - obj.ObjectCid = item.ObjectCid; - obj.SaveFlags = item.SaveFlags; - obj.Name = item.Name; + // copy managers + for (const auto& item : reader->GetManagersData()) { + CKFileManagerData mgr; + // copy guid + mgr.Manager = item.Manager; + // copy chunk + if (item.Data == nullptr) { + mgr.Data = nullptr; + } else { + mgr.Data = new CKStateChunk(*item.Data); + } - // insert - m_FileObjects.emplace_back(std::move(obj)); - } - - // copy managers - for (const auto& item : reader->GetManagersData()) { - CKFileManagerData mgr; - // copy guid - mgr.Manager = item.Manager; - // copy chunk - if (item.Data == nullptr) { - mgr.Data = nullptr; - } else { - mgr.Data = new CKStateChunk(*item.Data); + // insert + m_ManagersData.emplace_back(std::move(mgr)); } - // insert - m_ManagersData.emplace_back(std::move(mgr)); - } + // copy plugin dep + for (const auto& item : reader->GetPluginsDep()) { + // direct copy + m_PluginsDep.emplace_back(item); + } - // copy plugin dep - for (const auto& item : reader->GetPluginsDep()) { - // direct copy - m_PluginsDep.emplace_back(item); - } + // copy included file + for (const auto& item : reader->GetIncludedFiles()) { + // resolve it to temp folder + // and add it + m_IncludedFiles.emplace_back(m_Ctx->GetPathManager()->GetTempFilePath(item.c_str())); + } - // copy included file - for (const auto& item : reader->GetIncludedFiles()) { - // direct copy - m_IncludedFiles.emplace_back(item); - } +#pragma endregion + } else { + +#pragma region Deep Assign + + // copy object and calc max id + CK_ID maxid = 0; + for (const auto& item : reader->GetFileObjects()) { + CKFileObject obj; + + // skip if invalid + if (item.ObjPtr == nullptr) continue; + + // set obj ptr + obj.ObjPtr = item.ObjPtr; + + // set other data + obj.ObjectId = obj.ObjPtr->GetID(); + obj.ObjectCid = obj.ObjPtr->GetClassID(); + obj.Data = nullptr; // blank statechunk + obj.SaveFlags = CK_STATESAVE_ALL; + XContainer::NSXString::FromCKSTRING(obj.Name, obj.ObjPtr->GetName()); + + // update max id + maxid = std::max(maxid, obj.ObjectId); + + // insert + m_FileObjects.emplace_back(std::move(obj)); + + } + + // set max id + m_SaveIDMax = maxid; + +#pragma endregion + + } } CKFileWriter::~CKFileWriter() {} bool CKFileWriter::AddSavedObject(ObjImpls::CKObject* obj, CKDWORD flags) { - if (m_Done || m_IsCopyFromReader) return false; + if (m_Done || m_DisableAddingObject) return false; if (obj == nullptr) return false; // check whether is saved. @@ -242,9 +290,11 @@ namespace LibCmo::CK2 { // ok, insert this value m_ObjectsHashTable.try_emplace(objid, static_cast(m_FileObjects.size())); - XContainer::NSXBitArray::Set(m_AlreadySavedMask, static_cast(objid)); + // update max id + m_SaveIDMax = std::max(m_SaveIDMax, objid); + // add entry CKFileObject fobj; fobj.ObjectId = objid; fobj.ObjPtr = obj; @@ -257,7 +307,7 @@ namespace LibCmo::CK2 { } bool CKFileWriter::AddSavedObjects(const XContainer::XObjectPointerArray& objarray, CKDWORD flags) { - if (m_Done || m_IsCopyFromReader) return false; + if (m_Done || m_DisableAddingObject) return false; bool ret = true; for (auto obj : objarray) { @@ -270,7 +320,7 @@ namespace LibCmo::CK2 { } bool CKFileWriter::AddSavedFile(CKSTRING u8FileName) { - if (m_Done || m_IsCopyFromReader) return false; + if (m_Done || m_DisableAddingFile) return false; if (u8FileName == nullptr) return false; m_IncludedFiles.emplace_back(u8FileName); diff --git a/LibCmo/CK2/CKFileReader.cpp b/LibCmo/CK2/CKFileReader.cpp index 8d2f235..79f6a18 100644 --- a/LibCmo/CK2/CKFileReader.cpp +++ b/LibCmo/CK2/CKFileReader.cpp @@ -72,7 +72,7 @@ namespace LibCmo::CK2 { this->m_FileInfo.FileSize = parser->GetSize(); this->m_FileInfo.ManagerCount = rawHeader.ManagerCount; this->m_FileInfo.ObjectCount = rawHeader.ObjectCount; - this->m_FileInfo.MaxIDSaved = rawHeader.MaxIDSaved; + this->m_FileInfo.MaxIDSaved = static_cast(rawHeader.MaxIDSaved); this->m_FileInfo.Hdr1PackSize = rawHeader.FileVersion >= 8 ? rawHeader.Hdr1PackSize : 0u; this->m_FileInfo.Hdr1UnPackSize = rawHeader.FileVersion >= 8 ? rawHeader.Hdr1UnPackSize : 0u; this->m_FileInfo.DataPackSize = rawHeader.DataPackSize; diff --git a/LibCmo/CK2/CKFileWriter.cpp b/LibCmo/CK2/CKFileWriter.cpp index afb41d8..1ef99f6 100644 --- a/LibCmo/CK2/CKFileWriter.cpp +++ b/LibCmo/CK2/CKFileWriter.cpp @@ -46,8 +46,8 @@ namespace LibCmo::CK2 { } // iterate manager - // if copied from reader. skip - if (!m_IsCopyFromReader) { + // if object adding is disabled, skip. because in that mode, no need to query manager data. + if (!m_DisableAddingObject) { CKINT mgrcount = m_Ctx->GetManagerCount(); CKINT availablemgr = 0; @@ -75,14 +75,11 @@ namespace LibCmo::CK2 { } - // if copied from reader, skip plugin dep - if (!m_IsCopyFromReader) { + // if object adding is disabled, skip plugin dep. same reason with manager iteration. + if (!m_DisableAddingObject) { // todo: finish plugin dep filling } - // MARK: skip include file filling. - // we order user manually fill it. - // ========== Size Calc ========== // iterate 3 list to get each parts' size CKDWORD sumDataObjSize = 0, @@ -161,7 +158,7 @@ namespace LibCmo::CK2 { rawHeader.DataPackSize = sumDataSize; rawHeader.ProductVersion = DEVVERSION; rawHeader.ProductBuild = DEVBUILD; - rawHeader.MaxIDSaved = m_SaveIDMax; + rawHeader.MaxIDSaved = static_cast(m_SaveIDMax); // crc will filled later // ========== Write header ========== @@ -289,7 +286,7 @@ namespace LibCmo::CK2 { this->m_FileInfo.DataUnPackSize = rawHeader.DataUnPackSize; this->m_FileInfo.ManagerCount = rawHeader.ManagerCount; this->m_FileInfo.ObjectCount = rawHeader.ObjectCount; - this->m_FileInfo.MaxIDSaved = rawHeader.MaxIDSaved; + this->m_FileInfo.MaxIDSaved = static_cast(rawHeader.MaxIDSaved); // fill file size and crc this->m_FileInfo.FileSize = CKSizeof(CKRawFileInfo) + rawHeader.DataPackSize + rawHeader.Hdr1PackSize; this->m_FileInfo.Crc = computedcrc; @@ -308,16 +305,19 @@ namespace LibCmo::CK2 { datparser.reset(); // ========== Included Files ========== - for (auto& fentry : m_IncludedFiles) { + for (const auto& fentry : m_IncludedFiles) { + // get file name from full path + XContainer::XString filename(fentry); + m_Ctx->GetPathManager()->GetFileName(filename); + // write filename - m_Ctx->GetNativeString(fentry, name_conv); + m_Ctx->GetNativeString(filename, name_conv); CKDWORD filenamelen = static_cast(name_conv.size()); std::fwrite(&filenamelen, sizeof(CKDWORD), 1, fs); std::fwrite(name_conv.data(), sizeof(CKBYTE), filenamelen, fs); // try mapping file. - XContainer::XString tempfilename = m_Ctx->GetPathManager()->GetTempFilePath(fentry.c_str()); - std::unique_ptr mappedFile(new VxMath::VxMemoryMappedFile(tempfilename.c_str())); + std::unique_ptr mappedFile(new VxMath::VxMemoryMappedFile(fentry.c_str())); if (mappedFile->IsValid()) { // write file length CKDWORD filebodylen = mappedFile->GetFileSize(); @@ -331,7 +331,7 @@ namespace LibCmo::CK2 { std::fwrite(&filebodylen, sizeof(CKDWORD), 1, fs); // report error - m_Ctx->OutputToConsoleEx("Fail to open temp file: %s", tempfilename.c_str()); + m_Ctx->OutputToConsoleEx("Fail to open temp file: %" PRI_CKSTRING, fentry.c_str()); } // release mapped file diff --git a/LibCmo/CK2/ObjImpls/CKTexture.cpp b/LibCmo/CK2/ObjImpls/CKTexture.cpp index 21062f8..d53ef8f 100644 --- a/LibCmo/CK2/ObjImpls/CKTexture.cpp +++ b/LibCmo/CK2/ObjImpls/CKTexture.cpp @@ -158,14 +158,14 @@ namespace LibCmo::CK2::ObjImpls { // setup fake self props.m_Size = CKSizeof(props); - props.m_Data = 6172; + props.m_Data = 0; // setup fake VxImageDescEx props.m_Format.Size = CKSizeof(props.m_Format); props.m_Format.Flags = static_cast(VxMath::VX_PIXELFORMAT::_32_ARGB8888); props.m_Format.Width = m_ImageHost.GetWidth(); props.m_Format.Height = m_ImageHost.GetHeight(); - props.m_Format.BytesPerLine = VxMath::VxImageDescEx::PixelSize * props.m_Format.Height * props.m_Format.Width; + props.m_Format.BytesPerLine = VxMath::VxImageDescEx::PixelSize * props.m_Format.Width; props.m_Format.BitsPerPixel = 32; props.m_Format.RedMask = 0x00FF0000; diff --git a/Unvirt/StructFormatter.cpp b/Unvirt/StructFormatter.cpp index c85b95f..a6e07ec 100644 --- a/Unvirt/StructFormatter.cpp +++ b/Unvirt/StructFormatter.cpp @@ -399,7 +399,7 @@ namespace Unvirt::StructFormatter { fputc('\n', stdout); - fprintf(stdout, "Manager Count: %" PRIuCKDWORD "\nObject Count: %" PRIuCKDWORD "\nMax ID Saved: %" PRIuCKDWORD "\n", + fprintf(stdout, "Manager Count: %" PRIuCKDWORD "\nObject Count: %" PRIuCKDWORD "\nMax ID Saved: %" PRIuCKID "\n", fileinfo.ManagerCount, fileinfo.ObjectCount, fileinfo.MaxIDSaved ); diff --git a/Unvirt/UnvirtContext.cpp b/Unvirt/UnvirtContext.cpp index 5248c45..4d980c0 100644 --- a/Unvirt/UnvirtContext.cpp +++ b/Unvirt/UnvirtContext.cpp @@ -9,7 +9,7 @@ namespace Unvirt::Context { UnvirtContext::UnvirtContext() : m_Root(), m_Splitter(), m_Help(nullptr), m_PageLen(10u), m_OrderExit(false), - m_Ctx(nullptr), m_FileReader(nullptr) { + m_Ctx(nullptr), m_FileReader(nullptr), m_IsShallowRead(true) { // create command root CmdHelper::CommandRoot* root = &m_Root; @@ -175,6 +175,7 @@ namespace Unvirt::Context { // delete reader delete m_FileReader; m_FileReader = nullptr; + m_IsShallowRead = true; // clear context m_Ctx->ClearAll(); } @@ -242,8 +243,10 @@ namespace Unvirt::Context { LibCmo::CK2::CKERROR err; if (is_deep) { err = m_FileReader->DeepLoad(filepath.c_str()); + m_IsShallowRead = false; } else { err = m_FileReader->ShallowLoad(filepath.c_str()); + m_IsShallowRead = true; } if (err != LibCmo::CK2::CKERROR::CKERR_OK) { // fail to load. release all. @@ -277,7 +280,7 @@ namespace Unvirt::Context { std::string filepath = *amap->Get("filepath"); // construct writer from reader - LibCmo::CK2::CKFileWriter writer(m_Ctx, m_FileReader); + LibCmo::CK2::CKFileWriter writer(m_Ctx, m_FileReader, m_IsShallowRead); // backup current file write mode // and replace it with reader diff --git a/Unvirt/UnvirtContext.hpp b/Unvirt/UnvirtContext.hpp index ed05126..9d1337a 100644 --- a/Unvirt/UnvirtContext.hpp +++ b/Unvirt/UnvirtContext.hpp @@ -55,6 +55,7 @@ namespace Unvirt::Context { bool m_OrderExit; LibCmo::CK2::CKContext* m_Ctx; LibCmo::CK2::CKFileReader* m_FileReader; + bool m_IsShallowRead; };