fix saving issue

- fix CKStateChunk resize memory error.
- fix wrong CKBitmapHandler free position in CKBitmapData writer.
- fix init value error of CKFileWriter::m_DisableAddingFile when copying from reader.
- fix ReadString, WriteString error in CKStateChunk (forget NULL terminal)
- change CKPathManager resolve path order. Resolve temp path first, then resources folder.
- fix mixdata combine error when writing CKTexture.
This commit is contained in:
yyc12345 2023-09-30 16:01:39 +08:00
parent abea66d6f0
commit ee4b621cac
10 changed files with 62 additions and 36 deletions

View File

@ -138,7 +138,6 @@ namespace LibCmo::CK2 {
CKDWORD expectedSize = reader->SaveMemory(nullptr, slot, *savefmt); CKDWORD expectedSize = reader->SaveMemory(nullptr, slot, *savefmt);
std::unique_ptr<CKBYTE[]> filebuf(new CKBYTE[expectedSize]); std::unique_ptr<CKBYTE[]> filebuf(new CKBYTE[expectedSize]);
reader->SaveMemory(filebuf.get(), slot, *savefmt); reader->SaveMemory(filebuf.get(), slot, *savefmt);
reader.reset();
// in original Virtools design, only save alpha data when raw data can not represent alpha data // in original Virtools design, only save alpha data when raw data can not represent alpha data
bool canSaveAlpha = reader->CanSaveAlpha(); bool canSaveAlpha = reader->CanSaveAlpha();
@ -201,6 +200,9 @@ namespace LibCmo::CK2 {
} }
// free reader
reader.reset();
// explicitly return to skip fallback // explicitly return to skip fallback
return; return;
} }

View File

@ -174,7 +174,7 @@ namespace LibCmo::CK2 {
CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader, bool is_shallow) : CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader, bool is_shallow) :
m_Ctx(ctx), m_Visitor(this), m_Ctx(ctx), m_Visitor(this),
m_Done(false), 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_SaveIDMax(0),
m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(), m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(),
m_FileInfo() m_FileInfo()

View File

@ -104,6 +104,10 @@ namespace LibCmo::CK2 {
struct ChunkParser { struct ChunkParser {
CKStateChunkStatus m_Status; CKStateChunkStatus m_Status;
CKDWORD m_CurrentPos; 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_DataSize;
CKDWORD m_PrevIdentifierPos; CKDWORD m_PrevIdentifierPos;
}; };

View File

@ -261,18 +261,26 @@ namespace LibCmo::CK2 {
delete[] this->m_pData; delete[] this->m_pData;
this->m_pData = nullptr; this->m_pData = nullptr;
} }
// set buf size
this->m_Parser.m_DataSize = 0u;
} else { } else {
// otherwise, we create a new buffer instead it // otherwise, we create a new buffer instead it
CKDWORD* newbuf = new CKDWORD[new_dwsize]; 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) { 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; delete[] this->m_pData;
} }
// assign new buffer // assign new buffer
this->m_pData = newbuf; this->m_pData = newbuf;
// set buf size
this->m_Parser.m_DataSize = new_dwsize;
} }
return true; return true;
@ -290,9 +298,6 @@ namespace LibCmo::CK2 {
// try resizing it // try resizing it
if (!this->ResizeBuffer(needed)) return false; if (!this->ResizeBuffer(needed)) return false;
// update size
this->m_Parser.m_DataSize = needed;
} }
return true; return true;

View File

@ -130,9 +130,18 @@ namespace LibCmo::CK2 {
return false; return false;
} }
// check blank string
if (strByteSize == 0) {
strl->clear();
return true;
}
// read data // 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; XContainer::XString cache;
cache.resize(strByteSize); cache.resize(strByteSize - 1);
if (!this->ReadByteData(cache.data(), strByteSize)) { if (!this->ReadByteData(cache.data(), strByteSize)) {
strl->clear(); strl->clear();
return false; return false;

View File

@ -140,19 +140,26 @@ namespace LibCmo::CK2 {
XContainer::XString cache; XContainer::XString cache;
m_BindContext->GetNativeString(*strl, cache); m_BindContext->GetNativeString(*strl, cache);
// get size if (cache.empty()) {
CKDWORD strByteSize = static_cast<CKDWORD>(cache.size()); // write zero string
return this->WriteStruct(0);
} else {
// write string with NULL terminal
// write size
CKDWORD strByteSize = static_cast<CKDWORD>(cache.size()) + 1;
if (!this->WriteStruct(strByteSize)) { if (!this->WriteStruct(strByteSize)) {
return false; return false;
} }
// write data // write data with NULL terminal
if (!this->WriteByteData(cache.c_str(), strByteSize)) { if (!this->WriteByteData(cache.c_str(), strByteSize)) {
return false; return false;
} }
return true; return true;
} }
}
bool CKStateChunk::WriteObjectID(const CK_ID* id) { bool CKStateChunk::WriteObjectID(const CK_ID* id) {
// if BindFile is not nullptr, // if BindFile is not nullptr,

View File

@ -78,6 +78,13 @@ namespace LibCmo::CK2::MgrImpls {
return true; 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 // otherwise check it in extra path
for (const auto& extrapath : m_ExtraPathes) { for (const auto& extrapath : m_ExtraPathes) {
auto combinedpath = extrapath / filepath; 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 // failed
return false; return false;
} }

View File

@ -47,8 +47,8 @@ namespace LibCmo::CK2::MgrImpls {
* @remark * @remark
* We match file in following order. * We match file in following order.
* + Whether given file is absolute path. return if true. * + Whether given file is absolute path. return if true.
* + User provided extra path.
* + Virtools temp folder. * + Virtools temp folder.
* + User provided extra path.
* @return true if success * @return true if success
*/ */
bool ResolveFileName(XContainer::XString& u8_filename); bool ResolveFileName(XContainer::XString& u8_filename);

View File

@ -164,10 +164,9 @@ namespace LibCmo::CK2::ObjImpls {
chunk->ReadStruct(m_ZOrder); 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. // MARK: skin and bone are skipped.

View File

@ -87,23 +87,23 @@ namespace LibCmo::CK2::ObjImpls {
// prepare mix data. see Read for more info about the struct of this mix data // prepare mix data. see Read for more info about the struct of this mix data
CKDWORD mixdata = 0; CKDWORD mixdata = 0;
// save options // save options
mixdata &= static_cast<CKDWORD>(m_ImageHost.GetSaveOptions()) & 0xFF; mixdata |= static_cast<CKDWORD>(m_ImageHost.GetSaveOptions()) & 0xFF;
mixdata <<= 8; mixdata <<= 8;
// mix flags // mix flags
CKDWORD mixflags = 0; CKDWORD mixflags = 0;
if (m_ImageHost.IsTransparent()) { if (m_ImageHost.IsTransparent()) {
mixflags &= 0x1; mixflags |= 0x1;
} }
if (m_VideoFormat != VxMath::VX_PIXELFORMAT::UNKNOWN_PF) { if (m_VideoFormat != VxMath::VX_PIXELFORMAT::UNKNOWN_PF) {
mixflags &= 0x2; mixflags |= 0x2;
} }
if (m_ImageHost.IsCubeMap()) { if (m_ImageHost.IsCubeMap()) {
mixflags &= 0x4; mixflags |= 0x4;
} }
mixdata &= mixflags & 0xFF; mixdata |= mixflags & 0xFF;
mixdata <<= 8; mixdata <<= 8;
// mipmap // mipmap
mixdata &= (IsUseMipmap() ? 0xFF : 0); mixdata |= (IsUseMipmap() ? 0xFF : 0);
// write mix data // write mix data
chunk->WriteStruct(mixdata); chunk->WriteStruct(mixdata);