diff --git a/LibCmo/CK2/CKBitmapData.cpp b/LibCmo/CK2/CKBitmapData.cpp index 4d9eef0..876c3b9 100644 --- a/LibCmo/CK2/CKBitmapData.cpp +++ b/LibCmo/CK2/CKBitmapData.cpp @@ -138,7 +138,6 @@ namespace LibCmo::CK2 { CKDWORD expectedSize = reader->SaveMemory(nullptr, slot, *savefmt); std::unique_ptr filebuf(new CKBYTE[expectedSize]); reader->SaveMemory(filebuf.get(), slot, *savefmt); - reader.reset(); // in original Virtools design, only save alpha data when raw data can not represent alpha data bool canSaveAlpha = reader->CanSaveAlpha(); @@ -201,6 +200,9 @@ namespace LibCmo::CK2 { } + // free reader + reader.reset(); + // explicitly return to skip fallback return; } diff --git a/LibCmo/CK2/CKFileOthers.cpp b/LibCmo/CK2/CKFileOthers.cpp index 5330a24..edd1d15 100644 --- a/LibCmo/CK2/CKFileOthers.cpp +++ b/LibCmo/CK2/CKFileOthers.cpp @@ -174,7 +174,7 @@ namespace LibCmo::CK2 { CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader, bool is_shallow) : m_Ctx(ctx), m_Visitor(this), 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_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() diff --git a/LibCmo/CK2/CKStateChunk.hpp b/LibCmo/CK2/CKStateChunk.hpp index 8079a73..2dc7ea8 100644 --- a/LibCmo/CK2/CKStateChunk.hpp +++ b/LibCmo/CK2/CKStateChunk.hpp @@ -104,6 +104,10 @@ namespace LibCmo::CK2 { struct ChunkParser { CKStateChunkStatus m_Status; CKDWORD m_CurrentPos; + /** + * @brief The runtime size of CKStateChunk internal buf in DWORD unit. + * Usually be used and changed when resizing buffer in writing mode. + */ CKDWORD m_DataSize; CKDWORD m_PrevIdentifierPos; }; diff --git a/LibCmo/CK2/CKStateChunkOthers.cpp b/LibCmo/CK2/CKStateChunkOthers.cpp index e494d28..f588371 100644 --- a/LibCmo/CK2/CKStateChunkOthers.cpp +++ b/LibCmo/CK2/CKStateChunkOthers.cpp @@ -261,18 +261,26 @@ namespace LibCmo::CK2 { delete[] this->m_pData; this->m_pData = nullptr; } + + // set buf size + this->m_Parser.m_DataSize = 0u; } else { // otherwise, we create a new buffer instead it CKDWORD* newbuf = new CKDWORD[new_dwsize]; - // if no original data, we do not need copy it and free it + // we copy original data only when it has. if (this->m_pData != nullptr) { - std::memcpy(newbuf, this->m_pData, sizeof(CKDWORD) * new_dwsize); + // MARK: use std::min to copy for the minilist one + // otherwise, EnsureWriteSpace or StopWrite will crash. + std::memcpy(newbuf, this->m_pData, sizeof(CKDWORD) * std::min(this->m_Parser.m_DataSize, new_dwsize)); delete[] this->m_pData; } // assign new buffer this->m_pData = newbuf; + + // set buf size + this->m_Parser.m_DataSize = new_dwsize; } return true; @@ -290,9 +298,6 @@ namespace LibCmo::CK2 { // try resizing it if (!this->ResizeBuffer(needed)) return false; - - // update size - this->m_Parser.m_DataSize = needed; } return true; diff --git a/LibCmo/CK2/CKStateChunkReader.cpp b/LibCmo/CK2/CKStateChunkReader.cpp index 9c18bf2..98aca0f 100644 --- a/LibCmo/CK2/CKStateChunkReader.cpp +++ b/LibCmo/CK2/CKStateChunkReader.cpp @@ -130,9 +130,18 @@ namespace LibCmo::CK2 { return false; } + // check blank string + if (strByteSize == 0) { + strl->clear(); + return true; + } + // read data + // MARK: the written string has NULL terminal. + // strByteSize also include NULL terminal, + // so we need minus 1 when resizing (not ReadByteData, because we still need read NULL terminal to skip it.) XContainer::XString cache; - cache.resize(strByteSize); + cache.resize(strByteSize - 1); if (!this->ReadByteData(cache.data(), strByteSize)) { strl->clear(); return false; diff --git a/LibCmo/CK2/CKStateChunkWriter.cpp b/LibCmo/CK2/CKStateChunkWriter.cpp index ee4aafc..e179954 100644 --- a/LibCmo/CK2/CKStateChunkWriter.cpp +++ b/LibCmo/CK2/CKStateChunkWriter.cpp @@ -140,18 +140,25 @@ namespace LibCmo::CK2 { XContainer::XString cache; m_BindContext->GetNativeString(*strl, cache); - // get size - CKDWORD strByteSize = static_cast(cache.size()); - if (!this->WriteStruct(strByteSize)) { - return false; - } + if (cache.empty()) { + // write zero string + return this->WriteStruct(0); + } else { + // write string with NULL terminal - // write data - if (!this->WriteByteData(cache.c_str(), strByteSize)) { - return false; - } + // write size + CKDWORD strByteSize = static_cast(cache.size()) + 1; + if (!this->WriteStruct(strByteSize)) { + return false; + } - return true; + // write data with NULL terminal + if (!this->WriteByteData(cache.c_str(), strByteSize)) { + return false; + } + + return true; + } } bool CKStateChunk::WriteObjectID(const CK_ID* id) { diff --git a/LibCmo/CK2/MgrImpls/CKPathManager.cpp b/LibCmo/CK2/MgrImpls/CKPathManager.cpp index 5779c02..fbc9353 100644 --- a/LibCmo/CK2/MgrImpls/CKPathManager.cpp +++ b/LibCmo/CK2/MgrImpls/CKPathManager.cpp @@ -78,6 +78,13 @@ namespace LibCmo::CK2::MgrImpls { return true; } + // test in temp folder + auto tempfile = m_TempFolder / filepath; + if (std::filesystem::is_regular_file(tempfile)) { + EncodingHelper::StdPathToU8Path(u8_filename, tempfile); + return true; + } + // otherwise check it in extra path for (const auto& extrapath : m_ExtraPathes) { auto combinedpath = extrapath / filepath; @@ -88,13 +95,6 @@ namespace LibCmo::CK2::MgrImpls { } } - // test in temp folder - auto tempfile = m_TempFolder / filepath; - if (std::filesystem::is_regular_file(tempfile)) { - EncodingHelper::StdPathToU8Path(u8_filename, tempfile); - return true; - } - // failed return false; } diff --git a/LibCmo/CK2/MgrImpls/CKPathManager.hpp b/LibCmo/CK2/MgrImpls/CKPathManager.hpp index 0d43857..b2d857e 100644 --- a/LibCmo/CK2/MgrImpls/CKPathManager.hpp +++ b/LibCmo/CK2/MgrImpls/CKPathManager.hpp @@ -47,8 +47,8 @@ namespace LibCmo::CK2::MgrImpls { * @remark * We match file in following order. * + Whether given file is absolute path. return if true. - * + User provided extra path. * + Virtools temp folder. + * + User provided extra path. * @return true if success */ bool ResolveFileName(XContainer::XString& u8_filename); diff --git a/LibCmo/CK2/ObjImpls/CK3dEntity.cpp b/LibCmo/CK2/ObjImpls/CK3dEntity.cpp index 6f0dd8d..c782db6 100644 --- a/LibCmo/CK2/ObjImpls/CK3dEntity.cpp +++ b/LibCmo/CK2/ObjImpls/CK3dEntity.cpp @@ -164,10 +164,9 @@ namespace LibCmo::CK2::ObjImpls { chunk->ReadStruct(m_ZOrder); } - } else { - // MARK: compatibility code removed because I don't need them - return false; - } + } + // MARK: compatibility alternative core data read code removed because I don't need them + // MARK: skin and bone are skipped. diff --git a/LibCmo/CK2/ObjImpls/CKTexture.cpp b/LibCmo/CK2/ObjImpls/CKTexture.cpp index d53ef8f..ea7f9cd 100644 --- a/LibCmo/CK2/ObjImpls/CKTexture.cpp +++ b/LibCmo/CK2/ObjImpls/CKTexture.cpp @@ -87,23 +87,23 @@ namespace LibCmo::CK2::ObjImpls { // prepare mix data. see Read for more info about the struct of this mix data CKDWORD mixdata = 0; // save options - mixdata &= static_cast(m_ImageHost.GetSaveOptions()) & 0xFF; + mixdata |= static_cast(m_ImageHost.GetSaveOptions()) & 0xFF; mixdata <<= 8; // mix flags CKDWORD mixflags = 0; if (m_ImageHost.IsTransparent()) { - mixflags &= 0x1; + mixflags |= 0x1; } if (m_VideoFormat != VxMath::VX_PIXELFORMAT::UNKNOWN_PF) { - mixflags &= 0x2; + mixflags |= 0x2; } if (m_ImageHost.IsCubeMap()) { - mixflags &= 0x4; + mixflags |= 0x4; } - mixdata &= mixflags & 0xFF; + mixdata |= mixflags & 0xFF; mixdata <<= 8; // mipmap - mixdata &= (IsUseMipmap() ? 0xFF : 0); + mixdata |= (IsUseMipmap() ? 0xFF : 0); // write mix data chunk->WriteStruct(mixdata);