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);
std::unique_ptr<CKBYTE[]> 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;
}

View File

@ -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()

View File

@ -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;
};

View File

@ -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;

View File

@ -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;

View File

@ -140,18 +140,25 @@ namespace LibCmo::CK2 {
XContainer::XString cache;
m_BindContext->GetNativeString(*strl, cache);
// get size
CKDWORD strByteSize = static_cast<CKDWORD>(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<CKDWORD>(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) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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.

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
CKDWORD mixdata = 0;
// save options
mixdata &= static_cast<CKDWORD>(m_ImageHost.GetSaveOptions()) & 0xFF;
mixdata |= static_cast<CKDWORD>(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);