2023-02-25 17:39:39 +08:00
# include "CKFile.hpp"
2023-02-26 21:48:03 +08:00
# include "CKStateChunk.hpp"
2023-08-26 16:37:26 +08:00
# include "ObjImpls/CKObject.hpp"
2023-09-06 10:42:23 +08:00
# include "MgrImpls/CKPathManager.hpp"
2023-08-25 17:35:45 +08:00
# include "../VxMath/VxMemoryMappedFile.hpp"
# include "CKContext.hpp"
2023-02-25 17:39:39 +08:00
# include <memory>
2023-02-26 21:48:03 +08:00
namespace LibCmo : : CK2 {
2023-02-25 17:39:39 +08:00
/*
* NOTE :
* We onlt support read Virtools file with FileVersion > = 7.
* The file with FileVersion < 7 is older than NeMo 1.0 ( CK 1.1 ) .
* No need to support them .
*/
2023-08-25 21:57:22 +08:00
CKERROR CKFileReader : : ShallowLoad ( CKSTRING u8_filename ) {
// check document status
2023-09-26 12:07:13 +08:00
if ( this - > m_Done ) return CKERROR : : CKERR_CANCELLED ;
2024-08-23 17:38:45 +08:00
// check CKContext encoding sequence
if ( ! this - > m_Ctx - > IsValidEncoding ( ) ) return CKERROR : : CKERR_CANCELLED ;
2023-02-25 22:58:28 +08:00
// check file and open memory
if ( u8_filename = = nullptr ) return CKERROR : : CKERR_INVALIDPARAMETER ;
2023-08-25 21:57:22 +08:00
std : : unique_ptr < VxMath : : VxMemoryMappedFile > mappedFile ( new VxMath : : VxMemoryMappedFile ( u8_filename ) ) ;
2023-02-25 22:58:28 +08:00
if ( ! mappedFile - > IsValid ( ) ) {
2024-08-23 11:28:49 +08:00
this - > m_Ctx - > OutputToConsoleEx ( u8 " Fail to create Memory File for \" %s \" . " , u8_filename ) ;
2023-02-25 17:39:39 +08:00
return CKERROR : : CKERR_INVALIDFILE ;
}
// create buffer and start loading
2023-08-25 21:57:22 +08:00
std : : unique_ptr < CKBufferParser > parser ( new CKBufferParser ( mappedFile - > GetBase ( ) , mappedFile - > GetFileSize ( ) , false ) ) ;
CKERROR err = this - > ReadFileHeader ( parser . get ( ) ) ;
2023-02-25 17:39:39 +08:00
if ( err ! = CKERROR : : CKERR_OK ) return err ;
2023-08-25 21:57:22 +08:00
err = this - > ReadFileData ( parser . get ( ) ) ;
2023-02-25 17:39:39 +08:00
if ( err ! = CKERROR : : CKERR_OK ) return err ;
2023-02-25 22:58:28 +08:00
// other data will be free automatically
2024-08-23 17:38:45 +08:00
// set done flag and return
this - > m_Done = true ;
2023-02-25 17:39:39 +08:00
return CKERROR : : CKERR_OK ;
}
2023-08-25 21:57:22 +08:00
CKERROR CKFileReader : : ReadFileHeader ( CKBufferParser * ParserPtr ) {
std : : unique_ptr < CKBufferParser > parser ( new CKBufferParser ( ParserPtr - > GetBase ( ) , ParserPtr - > GetSize ( ) , false ) ) ;
2023-02-25 22:58:28 +08:00
parser - > SetCursor ( ParserPtr - > GetCursor ( ) ) ;
2024-08-23 11:28:49 +08:00
std : : string name_conv ;
2023-02-25 17:39:39 +08:00
// ========== read header ==========
// check header size
2023-08-29 14:00:34 +08:00
if ( parser - > GetSize ( ) < CKSizeof ( CKRawFileInfo ) ) return CKERROR : : CKERR_INVALIDFILE ;
2023-08-28 17:04:28 +08:00
if ( std : : memcmp ( parser - > GetPtr ( ) , CKNEMOFI , sizeof ( CKRawFileInfo : : NeMo ) ) ) return CKERROR : : CKERR_INVALIDFILE ;
2023-02-25 17:39:39 +08:00
// read header
CKRawFileInfo rawHeader ;
2023-09-17 10:38:46 +08:00
parser - > Read ( & rawHeader ) ;
2023-02-25 17:39:39 +08:00
// ========== header checker ==========
// check zero flag?
if ( rawHeader . Zero ) return CKERROR : : CKERR_INVALIDFILE ;
// check file version
if ( rawHeader . FileVersion > 9 | | rawHeader . FileVersion < 7 ) return CKERROR : : CKERR_OBSOLETEVIRTOOLS ;
// force reset too big product ver?
if ( rawHeader . ProductVersion > = 12u ) {
rawHeader . ProductVersion = 0u ;
2023-02-28 14:04:38 +08:00
rawHeader . ProductBuild = 0x01010000u ;
2023-02-25 17:39:39 +08:00
}
// ========== assign value ==========
2023-08-25 21:57:22 +08:00
this - > m_FileInfo . ProductVersion = rawHeader . ProductVersion ;
this - > m_FileInfo . ProductBuild = rawHeader . ProductBuild ;
this - > m_FileInfo . FileWriteMode = static_cast < CK_FILE_WRITEMODE > ( rawHeader . FileWriteMode ) ;
this - > m_FileInfo . CKVersion = rawHeader . CKVersion ;
this - > m_FileInfo . FileVersion = rawHeader . FileVersion ;
2023-08-30 10:03:02 +08:00
this - > m_FileInfo . FileSize = parser - > GetSize ( ) ;
2023-08-25 21:57:22 +08:00
this - > m_FileInfo . ManagerCount = rawHeader . ManagerCount ;
this - > m_FileInfo . ObjectCount = rawHeader . ObjectCount ;
2023-09-30 14:24:37 +08:00
this - > m_FileInfo . MaxIDSaved = static_cast < CK_ID > ( rawHeader . MaxIDSaved ) ;
2023-08-25 21:57:22 +08:00
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 ;
this - > m_FileInfo . DataUnPackSize = rawHeader . DataUnPackSize ;
this - > m_FileInfo . Crc = rawHeader . Crc ;
2023-02-25 17:39:39 +08:00
// ========== crc and body unpacker ==========
2023-08-25 21:57:22 +08:00
if ( this - > m_FileInfo . FileVersion > = 8 ) {
2023-02-25 17:39:39 +08:00
// crc checker for file ver >= 8
// reset crc field of header
rawHeader . Crc = 0u ;
2024-12-28 16:29:35 +08:00
// Compute and check CRC in theory (< Virtools 4.0)
2023-08-29 14:00:34 +08:00
CKDWORD gotten_crc = CKComputeDataCRC ( & rawHeader , CKSizeof ( CKRawFileInfo ) , 0u ) ;
2024-12-28 16:29:35 +08:00
parser - > SetCursor ( CKSizeof ( CKRawFileInfo ) ) ;
2023-08-25 21:57:22 +08:00
gotten_crc = CKComputeDataCRC ( parser - > GetPtr ( ) , this - > m_FileInfo . Hdr1PackSize , gotten_crc ) ;
parser - > MoveCursor ( this - > m_FileInfo . Hdr1PackSize ) ;
gotten_crc = CKComputeDataCRC ( parser - > GetPtr ( ) , this - > m_FileInfo . DataPackSize , gotten_crc ) ;
2023-02-25 17:39:39 +08:00
2023-08-25 21:57:22 +08:00
if ( gotten_crc ! = this - > m_FileInfo . Crc ) {
2024-12-28 16:29:35 +08:00
// MARK:
// If the CRC check failed, there is another way to compute CRC. (>= Virtools 4.0)
// This is a patch for Dassault stupid programmer.
//
// After Virtools 4.0, Dassault use a new way to compute the CRC of file.
2024-12-31 17:43:39 +08:00
// Dassault introduces a new class called CKMemoryBufferWriter which use file and memory map to handle big file properly.
// This algorithm splits the whole data body into 8 MB chunks and calculate them one by one to avoid instantaneous memory occupation.
2024-12-28 16:29:35 +08:00
// However, there is a bug in virtual function CKMemoryBufferWriter::ComputeCRC.
2024-12-31 17:43:39 +08:00
// It takes `PreviousCRC` as argument but never use it in function.
// In this function, the start value of CRC compution is hardcoded 0.
2024-12-28 16:29:35 +08:00
// So, although Dassault programmer try to compute CRC for file header, header part and daat part in code, it actually only compute CRC for data part!
2024-12-31 17:43:39 +08:00
// I 100% sure this is the mistake of Dassault stupid programmer and this bug cause more horrible result.
2024-12-28 16:29:35 +08:00
//
// In Virtools 2.1, engine will check CRC of file first. If no matched CRC, engine will reject loading file.
// So the obvious result is that we can not load file saved by Virtools 4.0 in Virtools 2.1.
// But this is not the point which makes me indignant.
2024-12-31 17:43:39 +08:00
// The real weird point is that we can use Virtools 3.5 to open file saved by Virtools 4.0, but why?
// After some researches, I found that the programmer of Dassault totally removed CRC check when loading file, since some version which I don't know, to suppress this bug!
2024-12-28 16:29:35 +08:00
// This is totally cheat and commercial-oriented behavior!
2024-12-31 17:43:39 +08:00
// I guess Dassault programmer also found that they can not load new created file in old Virtools.
// But they didn't find out what cause this bug, and just directly remove the whole of CRC checker to resolve this bug!
// I can't believe that this thing happens on such official software.
// This is the point which makes me indignant.
2024-12-28 16:29:35 +08:00
gotten_crc = CKComputeDataCRC ( parser - > GetPtr ( ) , this - > m_FileInfo . DataPackSize , 0u ) ;
2024-12-31 17:43:39 +08:00
// Both CRC compute methods are failed. This file may be really broken.
2024-12-28 16:29:35 +08:00
// Report exception directly.
if ( gotten_crc ! = this - > m_FileInfo . Crc ) {
this - > m_Ctx - > OutputToConsole ( u8 " Virtools file CRC error. " ) ;
return CKERROR : : CKERR_FILECRCERROR ;
}
2023-02-25 22:58:28 +08:00
}
2023-02-25 17:39:39 +08:00
// reset cursor
2024-12-28 16:29:35 +08:00
parser - > SetCursor ( CKSizeof ( CKRawFileInfo ) ) ;
2023-02-25 17:39:39 +08:00
// compare size to decide wheher use compress feature
2023-08-28 21:21:40 +08:00
if ( this - > m_FileInfo . Hdr1PackSize ! = this - > m_FileInfo . Hdr1UnPackSize ) {
void * decomp_buffer = CKUnPackData ( this - > m_FileInfo . Hdr1UnPackSize , parser - > GetPtr ( ) , this - > m_FileInfo . Hdr1PackSize ) ;
if ( decomp_buffer ! = nullptr ) {
parser = std : : unique_ptr < CKBufferParser > ( new CKBufferParser ( decomp_buffer , this - > m_FileInfo . Hdr1UnPackSize , true ) ) ;
}
2023-02-25 17:39:39 +08:00
}
}
// ========== object list read ==========
// file ver >= 7 have this features
2023-02-25 22:58:28 +08:00
{
2023-02-25 17:39:39 +08:00
// apply max id saved
2023-08-25 21:57:22 +08:00
this - > m_SaveIDMax = this - > m_FileInfo . MaxIDSaved ;
2023-02-25 17:39:39 +08:00
// resize
2023-08-25 21:57:22 +08:00
this - > m_FileObjects . resize ( this - > m_FileInfo . ObjectCount ) ;
2023-02-25 17:39:39 +08:00
// read data
2023-08-25 21:57:22 +08:00
for ( auto & fileobj : this - > m_FileObjects ) {
2023-02-25 17:39:39 +08:00
// read basic fields
2023-09-17 10:38:46 +08:00
parser - > Read ( & fileobj . ObjectId ) ;
parser - > Read ( & fileobj . ObjectCid ) ;
parser - > Read ( & fileobj . FileIndex ) ;
2023-02-25 17:39:39 +08:00
CKDWORD namelen ;
2023-09-17 10:38:46 +08:00
parser - > Read ( & namelen ) ;
2023-02-25 17:39:39 +08:00
if ( namelen ! = 0 ) {
2023-02-25 22:58:28 +08:00
name_conv . resize ( namelen ) ;
parser - > Read ( name_conv . data ( ) , namelen ) ;
2024-08-27 11:25:53 +08:00
if ( ! m_Ctx - > GetUTF8String ( name_conv , fileobj . Name ) )
m_Ctx - > OutputToConsole ( u8 " Fail to get UTF8 name for CKObject when reading file header. Some objects name will leave to blank. " ) ;
2023-09-16 18:31:25 +08:00
} else {
2023-11-30 22:48:40 +08:00
XContainer : : NSXString : : FromCKSTRING ( fileobj . Name , nullptr ) ;
2023-02-25 17:39:39 +08:00
}
}
}
// ========== dep list read ==========
// file ver >= 8 have this feature
2023-08-25 21:57:22 +08:00
if ( this - > m_FileInfo . FileVersion > = 8 ) {
2023-02-25 17:39:39 +08:00
// get size and resize
CKDWORD depSize ;
2023-09-17 10:38:46 +08:00
parser - > Read ( & depSize ) ;
2023-08-25 21:57:22 +08:00
this - > m_PluginsDep . resize ( depSize ) ;
2023-02-25 17:39:39 +08:00
CKDWORD guid_size ;
2023-08-25 21:57:22 +08:00
for ( auto & dep : this - > m_PluginsDep ) {
2023-02-25 17:39:39 +08:00
// read category
2023-09-17 10:38:46 +08:00
parser - > Read ( & dep . m_PluginCategory ) ;
2023-02-25 17:39:39 +08:00
// get size and resize
2023-09-17 10:38:46 +08:00
parser - > Read ( & guid_size ) ;
2023-02-25 17:39:39 +08:00
dep . m_Guids . resize ( guid_size ) ;
// read data
if ( guid_size ! = 0 ) {
parser - > Read ( dep . m_Guids . data ( ) , sizeof ( CKGUID ) * guid_size ) ;
}
}
}
// ========== included file list read ==========
// file ver >= 8 have this feature
2023-08-25 21:57:22 +08:00
if ( this - > m_FileInfo . FileVersion > = 8 ) {
2023-02-25 17:39:39 +08:00
// MARK: i don't knwo what is this!
2023-09-17 10:38:46 +08:00
CKINT hasIncludedFile ;
parser - > Read ( & hasIncludedFile ) ;
2023-02-25 17:39:39 +08:00
if ( hasIncludedFile > 0 ) {
// read included file size and resize
CKDWORD includedFileCount ;
2023-09-17 10:38:46 +08:00
parser - > Read ( & includedFileCount ) ;
2023-08-25 21:57:22 +08:00
this - > m_IncludedFiles . resize ( includedFileCount ) ;
2023-02-25 17:39:39 +08:00
2023-09-17 10:38:46 +08:00
hasIncludedFile - = static_cast < CKINT > ( sizeof ( CKDWORD ) ) ;
2023-02-25 17:39:39 +08:00
}
2023-02-25 22:58:28 +08:00
// MARK: backward pos
// backward with 0?
parser - > MoveCursor ( hasIncludedFile ) ;
}
// ========== sync main parser ==========
2023-08-25 21:57:22 +08:00
if ( this - > m_FileInfo . FileVersion > = 8 ) {
2023-02-25 22:58:28 +08:00
// file ver >= 8, use header offset
// because it have compress feature
2024-12-28 16:29:35 +08:00
ParserPtr - > SetCursor ( this - > m_FileInfo . Hdr1PackSize + CKSizeof ( CKRawFileInfo ) ) ;
2023-02-25 22:58:28 +08:00
} else {
// otherwise, sync with current parser.
ParserPtr - > SetCursor ( parser - > GetCursor ( ) ) ;
2023-02-25 17:39:39 +08:00
}
return CKERROR : : CKERR_OK ;
}
2023-08-25 21:57:22 +08:00
CKERROR CKFileReader : : ReadFileData ( CKBufferParser * ParserPtr ) {
2023-08-26 16:37:26 +08:00
std : : unique_ptr < CKBufferParser > parser ( new CKBufferParser ( ParserPtr - > GetBase ( ) , ParserPtr - > GetSize ( ) , false ) ) ;
2023-02-25 22:58:28 +08:00
parser - > SetCursor ( ParserPtr - > GetCursor ( ) ) ;
2024-08-23 11:28:49 +08:00
std : : string name_conv ;
2023-02-25 22:58:28 +08:00
// ========== compress feature process ==========
2024-11-03 19:05:27 +08:00
if ( YYCC : : EnumHelper : : Has ( this - > m_FileInfo . FileWriteMode , CK_FILE_WRITEMODE : : CKFILE_CHUNKCOMPRESSED_OLD ) | |
YYCC : : EnumHelper : : Has ( this - > m_FileInfo . FileWriteMode , CK_FILE_WRITEMODE : : CKFILE_WHOLECOMPRESSED ) ) {
2023-02-25 22:58:28 +08:00
2023-08-25 21:57:22 +08:00
void * decomp_buffer = CKUnPackData ( this - > m_FileInfo . DataUnPackSize , parser - > GetPtr ( ) , this - > m_FileInfo . DataPackSize ) ;
2023-02-25 22:58:28 +08:00
if ( decomp_buffer ! = nullptr ) {
2023-08-25 21:57:22 +08:00
parser = std : : unique_ptr < CKBufferParser > ( new CKBufferParser ( decomp_buffer , this - > m_FileInfo . DataUnPackSize , true ) ) ;
2023-02-25 22:58:28 +08:00
}
}
// ========== old file crc and obj list read ==========
// only file ver < 8 run this
2023-08-25 21:57:22 +08:00
if ( this - > m_FileInfo . FileVersion < 8 ) {
2023-02-25 22:58:28 +08:00
// check crc
CKDWORD gotten_crc = CKComputeDataCRC (
parser - > GetPtr ( ) ,
parser - > GetSize ( ) - parser - > GetCursor ( ) ,
0u
) ;
2023-08-25 21:57:22 +08:00
if ( gotten_crc ! = this - > m_FileInfo . Crc ) {
2024-08-23 11:28:49 +08:00
this - > m_Ctx - > OutputToConsole ( u8 " Virtools file CRC error. " ) ;
2023-02-25 22:58:28 +08:00
return CKERROR : : CKERR_FILECRCERROR ;
}
// MARK: why read again? especially for file ver == 7.
// get save id max
2023-09-17 10:38:46 +08:00
parser - > Read ( & this - > m_SaveIDMax ) ;
2023-02-25 22:58:28 +08:00
// get object count and resize
2023-09-17 10:38:46 +08:00
parser - > Read ( & this - > m_FileInfo . ObjectCount ) ;
2023-08-25 21:57:22 +08:00
if ( this - > m_FileObjects . empty ( ) ) {
this - > m_FileObjects . resize ( this - > m_FileInfo . ObjectCount ) ;
2023-02-25 22:58:28 +08:00
}
}
// ========== manager read ==========
// only file ver >= 6 have this
2023-08-25 21:57:22 +08:00
if ( this - > m_FileInfo . ManagerCount ! = 0 ) {
this - > m_ManagersData . resize ( this - > m_FileInfo . ManagerCount ) ;
2023-02-25 22:58:28 +08:00
CKDWORD stateChunkLen = 0u ;
bool stateChkParseSuccess = false ;
2023-08-25 21:57:22 +08:00
for ( auto & mgr : this - > m_ManagersData ) {
2023-02-25 22:58:28 +08:00
// read guid
2023-09-17 10:38:46 +08:00
parser - > Read ( & mgr . Manager ) ;
2023-02-25 22:58:28 +08:00
// read statechunk len
2023-09-17 10:38:46 +08:00
parser - > Read ( & stateChunkLen ) ;
2023-02-25 22:58:28 +08:00
// check len
if ( stateChunkLen = = 0 ) {
mgr . Data = nullptr ;
continue ;
}
// read statechunk
2023-08-25 21:57:22 +08:00
mgr . Data = new CKStateChunk ( & this - > m_Visitor , this - > m_Ctx ) ;
stateChkParseSuccess = mgr . Data - > ConvertFromBuffer ( parser - > GetPtr ( ) ) ;
if ( ! stateChkParseSuccess ) {
delete mgr . Data ;
mgr . Data = nullptr ;
2023-02-25 22:58:28 +08:00
}
parser - > MoveCursor ( stateChunkLen ) ;
}
}
// ========== object read ==========
// only works file version >= 4. < 4 section has been removed.
2023-08-25 21:57:22 +08:00
if ( this - > m_FileInfo . ObjectCount ! = 0 ) {
2023-02-25 22:58:28 +08:00
// new file reader section
bool stateChkParseSuccess = false ;
2023-08-25 21:57:22 +08:00
for ( auto & obj : this - > m_FileObjects ) {
2023-02-25 22:58:28 +08:00
// get statechunk len
2023-09-17 10:38:46 +08:00
parser - > Read ( & obj . PackSize ) ;
2023-02-25 22:58:28 +08:00
// check state chunk len
2023-08-28 17:04:28 +08:00
if ( obj . PackSize = = 0 ) {
2023-02-25 22:58:28 +08:00
obj . Data = nullptr ;
continue ;
}
// read state chunk
2023-08-25 21:57:22 +08:00
obj . Data = new CKStateChunk ( & this - > m_Visitor , this - > m_Ctx ) ;
stateChkParseSuccess = obj . Data - > ConvertFromBuffer ( parser - > GetPtr ( ) ) ;
if ( ! stateChkParseSuccess ) {
delete obj . Data ;
obj . Data = nullptr ;
2023-02-25 22:58:28 +08:00
}
2023-08-28 17:04:28 +08:00
parser - > MoveCursor ( obj . PackSize ) ;
2023-02-25 22:58:28 +08:00
}
}
// ========== included file get ==========
// before reading, we need switch back to original parser.
// and skip data chunk size
2023-08-26 16:37:26 +08:00
parser = std : : unique_ptr < CKBufferParser > ( new CKBufferParser ( ParserPtr - > GetBase ( ) , ParserPtr - > GetSize ( ) , false ) ) ;
2023-08-30 10:03:02 +08:00
parser - > SetCursor ( ParserPtr - > GetCursor ( ) ) ;
2023-08-25 21:57:22 +08:00
parser - > MoveCursor ( this - > m_FileInfo . DataPackSize ) ;
2023-02-25 22:58:28 +08:00
// then we can read it.
2023-08-25 21:57:22 +08:00
if ( this - > m_IncludedFiles . size ( ) ! = 0 ) {
for ( auto & file : this - > m_IncludedFiles ) {
2023-02-25 22:58:28 +08:00
// get file name length and resize it
CKDWORD filenamelen = 0u ;
2023-09-17 10:38:46 +08:00
parser - > Read ( & filenamelen ) ;
2023-02-25 22:58:28 +08:00
name_conv . resize ( filenamelen ) ;
// read filename
if ( filenamelen ! = 0 ) {
parser - > Read ( name_conv . data ( ) , filenamelen ) ;
2024-08-27 11:25:53 +08:00
if ( ! m_Ctx - > GetUTF8String ( name_conv , file ) )
m_Ctx - > OutputToConsole ( u8 " Fail to get UTF8 name for included file when reading file body. Some included files may be stripped. " ) ;
2023-02-25 22:58:28 +08:00
}
// read file body length
CKDWORD filebodylen = 0u ;
2023-09-17 10:38:46 +08:00
parser - > Read ( & filebodylen ) ;
2023-02-25 22:58:28 +08:00
// read file body
2023-09-16 18:31:25 +08:00
XContainer : : XString tempfilename = m_Ctx - > GetPathManager ( ) - > GetTempFilePath ( file . c_str ( ) ) ;
2024-08-23 11:28:49 +08:00
FILE * fp = YYCC : : IOHelper : : UTF8FOpen ( tempfilename . c_str ( ) , u8 " wb " ) ;
2023-02-25 22:58:28 +08:00
if ( fp ! = nullptr ) {
2023-09-17 10:38:46 +08:00
std : : fwrite ( parser - > GetPtr ( ) , sizeof ( CKBYTE ) , filebodylen , fp ) ;
2023-08-29 14:00:34 +08:00
std : : fclose ( fp ) ;
2023-08-30 10:03:02 +08:00
} else {
2024-08-23 11:28:49 +08:00
m_Ctx - > OutputToConsoleEx ( u8 " Fail to open temp file: %s " , tempfilename . c_str ( ) ) ;
2023-02-25 22:58:28 +08:00
}
// move to next
parser - > MoveCursor ( filebodylen ) ;
}
}
return CKERROR : : CKERR_OK ;
2023-02-25 17:39:39 +08:00
}
2023-08-25 21:57:22 +08:00
CKERROR CKFileReader : : DeepLoad ( CKSTRING u8_filename ) {
2023-08-28 17:04:28 +08:00
// check document status
2023-09-26 12:07:13 +08:00
if ( this - > m_Done ) return CKERROR : : CKERR_CANCELLED ;
2024-08-23 17:38:45 +08:00
// check CKContext encoding sequence
if ( ! this - > m_Ctx - > IsValidEncoding ( ) ) return CKERROR : : CKERR_CANCELLED ;
2023-08-28 17:04:28 +08:00
2023-02-28 11:35:54 +08:00
// ========== prepare work ==========
2023-03-03 11:06:26 +08:00
CKERROR err = CKERROR : : CKERR_OK ;
2023-02-28 11:35:54 +08:00
// get shallow document first
2023-08-25 21:57:22 +08:00
err = this - > ShallowLoad ( u8_filename ) ;
2023-02-28 11:35:54 +08:00
if ( err ! = CKERROR : : CKERR_OK ) return err ;
2024-08-23 17:38:45 +08:00
// reset done flag because we need further processing
this - > m_Done = false ;
2023-02-28 11:35:54 +08:00
// ========== create object first ==========
2023-08-25 21:57:22 +08:00
for ( auto & obj : this - > m_FileObjects ) {
2023-02-28 11:35:54 +08:00
// todo: skip CK_LEVEL
// todo: resolve references
if ( obj . Data = = nullptr ) continue ;
2023-03-08 15:45:06 +08:00
// create object and assign created obj ckid
2023-09-16 18:31:25 +08:00
obj . ObjPtr = m_Ctx - > CreateObject ( obj . ObjectCid , XContainer : : NSXString : : ToCKSTRING ( obj . Name ) ) ;
2023-03-08 15:45:06 +08:00
if ( obj . ObjPtr = = nullptr ) {
2023-08-25 21:57:22 +08:00
obj . CreatedObjectId = 0u ;
2023-03-08 15:45:06 +08:00
} else {
2023-08-25 21:57:22 +08:00
obj . CreatedObjectId = obj . ObjPtr - > GetID ( ) ;
2023-03-08 15:45:06 +08:00
}
2023-02-28 11:35:54 +08:00
}
// ========== CKStateChunk remap ==========
// todo: remap
// todo: CK_LEVEL special proc
// ========== consume Managers ==========
// todo...
// ========== analyze objects CKStateChunk ==========
2023-08-25 21:57:22 +08:00
for ( auto & obj : this - > m_FileObjects ) {
2023-03-03 11:06:26 +08:00
if ( obj . Data = = nullptr | | obj . ObjPtr = = nullptr ) continue ;
2023-02-28 11:35:54 +08:00
// todo: special treat for CK_LEVEL
// try parsing data
2023-02-28 14:04:38 +08:00
obj . Data - > StartRead ( ) ;
2023-08-25 21:57:22 +08:00
bool success = obj . ObjPtr - > Load ( obj . Data , & this - > m_Visitor ) ;
2023-02-28 14:04:38 +08:00
obj . Data - > StopRead ( ) ;
2023-03-05 22:31:11 +08:00
if ( success ) {
2023-03-03 11:06:26 +08:00
// if success, clear CKStateChunk*
delete obj . Data ;
obj . Data = nullptr ;
2023-03-05 22:31:11 +08:00
} else {
// if failed, delete it
2023-09-01 13:27:46 +08:00
m_Ctx - > DestroyObject ( obj . ObjectId ) ;
2023-03-05 22:31:11 +08:00
obj . ObjPtr = nullptr ;
2023-08-25 21:57:22 +08:00
obj . CreatedObjectId = 0u ;
2023-02-28 11:35:54 +08:00
}
}
// ========== finalize work ==========
2024-12-28 16:29:35 +08:00
2024-08-23 17:38:45 +08:00
// set done flag and return
this - > m_Done = true ;
2023-02-26 13:57:32 +08:00
return CKERROR : : CKERR_OK ;
}
2023-02-25 17:39:39 +08:00
}