2023-08-25 17:35:45 +08:00
|
|
|
#include "CKFile.hpp"
|
|
|
|
#include "CKStateChunk.hpp"
|
2023-08-28 17:04:28 +08:00
|
|
|
#include "ObjImpls/CKObject.hpp"
|
2023-08-25 17:35:45 +08:00
|
|
|
#include <cstdarg>
|
|
|
|
|
|
|
|
namespace LibCmo::CK2 {
|
|
|
|
|
|
|
|
#pragma region CKFileObject
|
|
|
|
|
|
|
|
// CKObject is managed by CKMinContext,
|
|
|
|
// so we do not considering its memory leak
|
|
|
|
// however, we need process CKStateChunk.
|
|
|
|
|
|
|
|
CKFileObject::CKFileObject() :
|
|
|
|
ObjectId(0u), CreatedObjectId(0u), ObjectCid(CK_CLASSID::CKCID_OBJECT),
|
|
|
|
ObjPtr(nullptr), Name(), Data(nullptr), Options(CK_FO_OPTIONS::CK_FO_DEFAULT),
|
2023-08-28 17:04:28 +08:00
|
|
|
FileIndex(0u), SaveFlags(CK_STATESAVE_ALL), PackSize(0u) {}
|
2023-08-25 17:35:45 +08:00
|
|
|
|
|
|
|
CKFileObject::CKFileObject(const CKFileObject& rhs) :
|
|
|
|
ObjectId(rhs.ObjectId), CreatedObjectId(rhs.CreatedObjectId), ObjectCid(rhs.ObjectCid),
|
|
|
|
ObjPtr(rhs.ObjPtr), Name(rhs.Name), Data(rhs.Data), Options(rhs.Options),
|
2023-08-28 17:04:28 +08:00
|
|
|
FileIndex(rhs.FileIndex), SaveFlags(rhs.SaveFlags), PackSize(rhs.PackSize) {
|
2023-08-25 17:35:45 +08:00
|
|
|
if (this->Data != nullptr) {
|
|
|
|
this->Data = new CKStateChunk(*(rhs.Data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CKFileObject::CKFileObject(CKFileObject&& rhs) :
|
|
|
|
ObjectId(rhs.ObjectId), CreatedObjectId(rhs.CreatedObjectId), ObjectCid(rhs.ObjectCid),
|
|
|
|
ObjPtr(rhs.ObjPtr), Name(rhs.Name), Data(rhs.Data), Options(rhs.Options),
|
2023-08-28 17:04:28 +08:00
|
|
|
FileIndex(rhs.FileIndex), SaveFlags(rhs.SaveFlags), PackSize(rhs.PackSize) {
|
2023-08-25 17:35:45 +08:00
|
|
|
rhs.Data = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
CKFileObject& CKFileObject::operator=(const CKFileObject& rhs) {
|
|
|
|
this->ObjectId = rhs.ObjectId;
|
|
|
|
this->CreatedObjectId = rhs.CreatedObjectId;
|
|
|
|
this->ObjectCid = rhs.ObjectCid;
|
|
|
|
this->ObjPtr = rhs.ObjPtr;
|
|
|
|
this->Name = rhs.Name;
|
|
|
|
|
|
|
|
this->Data = rhs.Data;
|
|
|
|
if (this->Data != nullptr) {
|
|
|
|
this->Data = new CKStateChunk(*(rhs.Data));
|
|
|
|
}
|
|
|
|
|
2023-08-28 17:04:28 +08:00
|
|
|
this->PackSize = rhs.PackSize;
|
2023-08-25 17:35:45 +08:00
|
|
|
this->Options = rhs.Options;
|
|
|
|
this->FileIndex = rhs.FileIndex;
|
|
|
|
this->SaveFlags = rhs.SaveFlags;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
CKFileObject& CKFileObject::operator=(CKFileObject&& rhs) {
|
|
|
|
this->ObjectId = rhs.ObjectId;
|
|
|
|
this->CreatedObjectId = rhs.CreatedObjectId;
|
|
|
|
this->ObjectCid = rhs.ObjectCid;
|
|
|
|
this->ObjPtr = rhs.ObjPtr;
|
|
|
|
this->Name = rhs.Name;
|
|
|
|
|
|
|
|
this->Data = rhs.Data;
|
|
|
|
rhs.Data = nullptr;
|
2023-08-28 17:04:28 +08:00
|
|
|
|
|
|
|
this->PackSize = rhs.PackSize;
|
2023-08-25 17:35:45 +08:00
|
|
|
this->Options = rhs.Options;
|
|
|
|
this->FileIndex = rhs.FileIndex;
|
|
|
|
this->SaveFlags = rhs.SaveFlags;
|
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
return *this;
|
2023-08-25 17:35:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CKFileObject::~CKFileObject() {
|
|
|
|
if (Data != nullptr) delete Data;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region CKFileManagerData
|
|
|
|
|
|
|
|
CKFileManagerData::CKFileManagerData() :
|
|
|
|
Data(nullptr), Manager(0u, 0u) {}
|
|
|
|
|
|
|
|
CKFileManagerData::CKFileManagerData(const CKFileManagerData& rhs) :
|
|
|
|
Data(rhs.Data), Manager(rhs.Manager) {
|
|
|
|
|
|
|
|
if (this->Data != nullptr) {
|
|
|
|
this->Data = new CKStateChunk(*(rhs.Data));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CKFileManagerData::CKFileManagerData(CKFileManagerData&& rhs) :
|
|
|
|
Data(rhs.Data), Manager(rhs.Manager) {
|
|
|
|
rhs.Data = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
CKFileManagerData& CKFileManagerData::operator=(const CKFileManagerData& rhs) {
|
|
|
|
this->Manager = rhs.Manager;
|
|
|
|
|
|
|
|
this->Data = rhs.Data;
|
|
|
|
if (this->Data != nullptr) {
|
|
|
|
this->Data = new CKStateChunk(*(rhs.Data));
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
CKFileManagerData& CKFileManagerData::operator=(CKFileManagerData&& rhs) {
|
|
|
|
this->Manager = rhs.Manager;
|
|
|
|
|
|
|
|
this->Data = rhs.Data;
|
|
|
|
rhs.Data = nullptr;
|
2023-08-25 21:57:22 +08:00
|
|
|
|
|
|
|
return *this;
|
2023-08-25 17:35:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CKFileManagerData::~CKFileManagerData() {
|
|
|
|
if (Data != nullptr) delete Data;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
#pragma region CKFileReader
|
2023-08-25 17:35:45 +08:00
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
CKFileReader::CKFileReader(CKContext* ctx) :
|
|
|
|
m_Ctx(ctx), m_Visitor(this),
|
|
|
|
m_Done(false),
|
|
|
|
m_SaveIDMax(0),
|
|
|
|
m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(),
|
|
|
|
m_FileInfo() {}
|
2023-08-25 17:35:45 +08:00
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
CKFileReader::~CKFileReader() {}
|
2023-08-25 17:35:45 +08:00
|
|
|
|
2023-08-26 20:34:51 +08:00
|
|
|
CKINT CKFileReader::GetSaveIdMax() {
|
|
|
|
return m_SaveIDMax;
|
|
|
|
}
|
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
const XContainer::XArray<CKFileObject>& CKFileReader::GetFileObjects() {
|
|
|
|
return m_FileObjects;
|
2023-08-25 17:35:45 +08:00
|
|
|
}
|
|
|
|
|
2023-08-26 20:34:51 +08:00
|
|
|
const XContainer::XArray<CKFileManagerData>& CKFileReader::GetManagersData() {
|
|
|
|
return m_ManagersData;
|
|
|
|
}
|
|
|
|
|
|
|
|
const XContainer::XArray<CKFilePluginDependencies>& CKFileReader::GetPluginsDep() {
|
|
|
|
return m_PluginsDep;
|
|
|
|
}
|
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
const XContainer::XArray<XContainer::XString>& CKFileReader::GetIncludedFiles() {
|
|
|
|
return m_IncludedFiles;
|
|
|
|
}
|
2023-08-25 17:35:45 +08:00
|
|
|
|
2023-08-26 20:34:51 +08:00
|
|
|
const CKFileInfo CKFileReader::GetFileInfo() {
|
|
|
|
return m_FileInfo;
|
|
|
|
}
|
|
|
|
|
2023-08-25 17:35:45 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
#pragma region CKFileWriter
|
|
|
|
|
|
|
|
CKFileWriter::CKFileWriter(CKContext* ctx) :
|
2023-08-28 14:18:58 +08:00
|
|
|
m_Ctx(ctx), m_Visitor(this),
|
|
|
|
m_Done(false), m_IsCopyFromReader(false),
|
2023-08-28 17:04:28 +08:00
|
|
|
m_SaveIDMax(0),
|
2023-08-28 21:21:40 +08:00
|
|
|
m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(),
|
|
|
|
m_FileInfo()
|
2023-08-28 14:18:58 +08:00
|
|
|
{}
|
2023-08-25 21:57:22 +08:00
|
|
|
|
|
|
|
CKFileWriter::CKFileWriter(CKContext* ctx, CKFileReader* reader) :
|
2023-08-28 14:18:58 +08:00
|
|
|
m_Ctx(ctx), m_Visitor(this),
|
|
|
|
m_Done(false), m_IsCopyFromReader(true),
|
2023-08-28 17:04:28 +08:00
|
|
|
m_SaveIDMax(0),
|
2023-08-28 21:21:40 +08:00
|
|
|
m_FileObjects(), m_ManagersData(), m_PluginsDep(), m_IncludedFiles(),
|
|
|
|
m_FileInfo()
|
2023-08-28 14:18:58 +08:00
|
|
|
{
|
2023-08-28 17:04:28 +08:00
|
|
|
// sync save id max
|
|
|
|
this->m_SaveIDMax = reader->GetSaveIdMax();
|
|
|
|
|
2023-08-28 14:18:58 +08:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2023-08-28 17:04:28 +08:00
|
|
|
// copy other data
|
|
|
|
obj.ObjectId = item.ObjectId;
|
|
|
|
obj.ObjectCid = item.ObjectCid;
|
2023-08-28 14:18:58 +08:00
|
|
|
obj.SaveFlags = item.SaveFlags;
|
2023-08-28 17:04:28 +08:00
|
|
|
obj.Name = item.Name;
|
2023-08-28 14:18:58 +08:00
|
|
|
|
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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()) {
|
|
|
|
// direct copy
|
|
|
|
m_IncludedFiles.emplace_back(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-08-25 17:35:45 +08:00
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
CKFileWriter::~CKFileWriter() {}
|
|
|
|
|
2023-08-29 14:00:34 +08:00
|
|
|
bool CKFileWriter::AddSavedObject(ObjImpls::CKObject* obj, CKDWORD flags) {
|
|
|
|
if (m_Done || m_IsCopyFromReader) return false;
|
2023-09-24 12:21:33 +08:00
|
|
|
if (obj == nullptr) return false;
|
|
|
|
|
|
|
|
// check whether is saved.
|
|
|
|
CK_ID objid = obj->GetID();
|
|
|
|
if (XContainer::NSXBitArray::IsSet(m_AlreadySavedMask, static_cast<CKDWORD>(objid))) return false;
|
|
|
|
|
|
|
|
// ok, insert this value
|
|
|
|
m_ObjectsHashTable.try_emplace(objid, static_cast<CKDWORD>(m_FileObjects.size()));
|
|
|
|
|
|
|
|
XContainer::NSXBitArray::Set(m_AlreadySavedMask, static_cast<CKDWORD>(objid));
|
|
|
|
|
|
|
|
CKFileObject fobj;
|
|
|
|
fobj.ObjectId = objid;
|
|
|
|
fobj.ObjPtr = obj;
|
|
|
|
fobj.ObjectCid = obj->GetClassID();
|
|
|
|
fobj.SaveFlags = flags;
|
|
|
|
XContainer::NSXString::FromCKSTRING(fobj.Name, obj->GetName());
|
|
|
|
m_FileObjects.emplace_back(std::move(fobj));
|
|
|
|
|
|
|
|
return true;
|
2023-08-25 17:35:45 +08:00
|
|
|
}
|
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
bool CKFileWriter::AddSavedObjects(const XContainer::XObjectPointerArray& objarray, CKDWORD flags) {
|
2023-08-29 14:00:34 +08:00
|
|
|
if (m_Done || m_IsCopyFromReader) return false;
|
2023-09-24 12:21:33 +08:00
|
|
|
|
|
|
|
bool ret = true;
|
|
|
|
for (auto obj : objarray) {
|
|
|
|
if (!AddSavedObject(obj, flags)) {
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2023-08-25 21:57:22 +08:00
|
|
|
}
|
2023-08-25 17:35:45 +08:00
|
|
|
|
2023-08-29 14:00:34 +08:00
|
|
|
bool CKFileWriter::AddSavedFile(CKSTRING u8FileName) {
|
|
|
|
if (m_Done || m_IsCopyFromReader) return false;
|
2023-09-24 12:21:33 +08:00
|
|
|
if (u8FileName == nullptr) return false;
|
|
|
|
|
|
|
|
m_IncludedFiles.emplace_back(u8FileName);
|
|
|
|
return true;
|
2023-08-25 21:57:22 +08:00
|
|
|
}
|
2023-08-25 17:35:45 +08:00
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
#pragma region CKFileVisitor
|
|
|
|
|
|
|
|
CKFileVisitor::CKFileVisitor(CKFileReader* reader) :
|
2023-08-29 14:00:34 +08:00
|
|
|
m_IsReader(true), m_Reader(reader), m_Writer(nullptr), m_Ctx(reader->m_Ctx) {
|
2023-09-24 20:56:23 +08:00
|
|
|
if (reader == nullptr) LIBCMO_PANIC("Reader is nullptr.");
|
2023-08-25 21:57:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CKFileVisitor::CKFileVisitor(CKFileWriter* writer) :
|
2023-08-29 10:42:13 +08:00
|
|
|
m_IsReader(false), m_Reader(nullptr), m_Writer(writer), m_Ctx(writer->m_Ctx) {
|
2023-09-24 20:56:23 +08:00
|
|
|
if (writer == nullptr) LIBCMO_PANIC("Writer is nullptr.");
|
2023-08-25 21:57:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CKFileVisitor::CKFileVisitor(const CKFileVisitor& rhs) :
|
2023-08-29 10:42:13 +08:00
|
|
|
m_IsReader(rhs.m_IsReader), m_Reader(rhs.m_Reader), m_Writer(rhs.m_Writer), m_Ctx(rhs.m_Ctx) {}
|
2023-08-25 21:57:22 +08:00
|
|
|
|
|
|
|
CKFileVisitor::CKFileVisitor(CKFileVisitor&& rhs) :
|
2023-08-29 10:42:13 +08:00
|
|
|
m_IsReader(rhs.m_IsReader), m_Reader(rhs.m_Reader), m_Writer(rhs.m_Writer), m_Ctx(rhs.m_Ctx) {}
|
2023-08-25 21:57:22 +08:00
|
|
|
|
|
|
|
CKFileVisitor& CKFileVisitor::operator=(const CKFileVisitor& rhs) {
|
|
|
|
this->m_IsReader = rhs.m_IsReader;
|
|
|
|
this->m_Reader = rhs.m_Reader;
|
|
|
|
this->m_Writer = rhs.m_Writer;
|
2023-08-29 10:42:13 +08:00
|
|
|
this->m_Ctx = rhs.m_Ctx;
|
2023-08-25 21:57:22 +08:00
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
CKFileVisitor& CKFileVisitor::operator=(CKFileVisitor&& rhs) {
|
|
|
|
this->m_IsReader = rhs.m_IsReader;
|
|
|
|
this->m_Reader = rhs.m_Reader;
|
|
|
|
this->m_Writer = rhs.m_Writer;
|
2023-08-29 10:42:13 +08:00
|
|
|
this->m_Ctx = rhs.m_Ctx;
|
2023-08-25 21:57:22 +08:00
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2023-09-24 20:56:23 +08:00
|
|
|
const CKFileObject* CKFileVisitor::GetFileObjectByIndex(CKDWORD index) {
|
2023-08-25 21:57:22 +08:00
|
|
|
if (m_IsReader) {
|
|
|
|
return &m_Reader->m_FileObjects[index];
|
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-24 12:21:33 +08:00
|
|
|
CKDWORD CKFileVisitor::GetIndexByObjectID(CK_ID objid) {
|
|
|
|
// see CKFile::SaveFindObjectIndex in IDA
|
2023-09-24 13:55:41 +08:00
|
|
|
CKDWORD idx = static_cast<CKDWORD>(-1);
|
2023-09-24 12:21:33 +08:00
|
|
|
if (m_IsReader) return idx;
|
|
|
|
|
|
|
|
auto finder = m_Writer->m_ObjectsHashTable.find(objid);
|
|
|
|
if (finder == m_Writer->m_ObjectsHashTable.end()) return idx;
|
|
|
|
return finder->second;
|
|
|
|
}
|
|
|
|
|
2023-08-25 21:57:22 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
2023-08-25 17:35:45 +08:00
|
|
|
}
|