1
0

fix: finish StructFmt refactor in Unvirt

This commit is contained in:
2026-01-29 13:30:27 +08:00
parent ca4fab4612
commit ada432fbe7
4 changed files with 365 additions and 205 deletions

View File

@@ -3,6 +3,7 @@ add_executable(Unvirt "")
# Setup sources # Setup sources
target_sources(Unvirt target_sources(Unvirt
PRIVATE PRIVATE
Utils.cpp
Docstring.cpp Docstring.cpp
StructFmt.cpp StructFmt.cpp
CmdHelper.cpp CmdHelper.cpp
@@ -14,6 +15,7 @@ target_sources(Unvirt
PRIVATE PRIVATE
FILE_SET HEADERS FILE_SET HEADERS
FILES FILES
Utils.hpp
Docstring.hpp Docstring.hpp
StructFmt.hpp StructFmt.hpp
CmdHelper.hpp CmdHelper.hpp

View File

@@ -1,5 +1,6 @@
#include "StructFmt.hpp" #include "StructFmt.hpp"
#include "Docstring.hpp" #include "Docstring.hpp"
#include "Utils.hpp"
#include <yycc/string/op.hpp> #include <yycc/string/op.hpp>
#include <yycc/carton/termcolor.hpp> #include <yycc/carton/termcolor.hpp>
#include <yycc/carton/tabulate.hpp> #include <yycc/carton/tabulate.hpp>
@@ -12,6 +13,8 @@ using namespace yycc::patch::stream;
namespace strop = yycc::string::op; namespace strop = yycc::string::op;
namespace termcolor = yycc::carton::termcolor; namespace termcolor = yycc::carton::termcolor;
namespace tabulate = yycc::carton::tabulate; namespace tabulate = yycc::carton::tabulate;
using termcolor::Color;
using Unvirt::Utils::PageBreaker;
namespace Unvirt::StructFmt { namespace Unvirt::StructFmt {
@@ -20,10 +23,10 @@ namespace Unvirt::StructFmt {
static std::u8string PrintCKSTRING(LibCmo::CKSTRING name) { static std::u8string PrintCKSTRING(LibCmo::CKSTRING name) {
std::u8string ret; std::u8string ret;
if (name == nullptr) { if (name == nullptr) {
ret = termcolor::colored(u8"<anonymous>", termcolor::Color::LightMagenta); ret = termcolor::colored(u8"<anonymous>", Color::LightMagenta);
} else { } else {
if (name[0] == u8'\0') { if (name[0] == u8'\0') {
ret = termcolor::colored(u8"<blank>", termcolor::Color::LightMagenta); ret = termcolor::colored(u8"<blank>", Color::LightMagenta);
} else { } else {
ret = name; ret = name;
} }
@@ -33,7 +36,7 @@ namespace Unvirt::StructFmt {
static std::u8string PrintPointer(const void* ptr) { static std::u8string PrintPointer(const void* ptr) {
std::u8string ret; std::u8string ret;
if (ptr == nullptr) { if (ptr == nullptr) {
ret = termcolor::colored(u8"<null>", termcolor::Color::LightCyan); ret = termcolor::colored(u8"<null>", Color::LightCyan);
} else { } else {
ret = strop::printf(u8"<0x%" PRIXPTR_LPAD PRIxPTR ">", reinterpret_cast<uintptr_t>(ptr)); ret = strop::printf(u8"<0x%" PRIXPTR_LPAD PRIxPTR ">", reinterpret_cast<uintptr_t>(ptr));
} }
@@ -46,7 +49,7 @@ namespace Unvirt::StructFmt {
return (v ? u8"true" : u8"false"); return (v ? u8"true" : u8"false");
} }
static std::u8string PrintColorfulBool(bool v) { static std::u8string PrintColorfulBool(bool v) {
return (v ? termcolor::colored(u8"Yes", termcolor::Color::LightGreen) : termcolor::colored(u8"No", termcolor::Color::LightRed)); return (v ? termcolor::colored(u8"Yes", Color::LightGreen) : termcolor::colored(u8"No", Color::LightRed));
} }
static std::u8string PrintColor(LibCmo::CKDWORD argb) { static std::u8string PrintColor(LibCmo::CKDWORD argb) {
LibCmo::CKDWORD a = (argb & 0xFF000000) >> 24, LibCmo::CKDWORD a = (argb & 0xFF000000) >> 24,
@@ -92,39 +95,57 @@ namespace Unvirt::StructFmt {
#pragma region Page Helper #pragma region Page Helper
template<class T> /**
static void GeneralPrintList( * @brief
const std::vector<T>& data, size_t page, size_t pageitems, * @param pager
std::function<void()> printHdrFct, std::function<void(size_t, const T&)> printEntryFct) { * @param page
* @return True if given page index is valid, otherwise false.
// check page overflow */
if (page * pageitems >= data.size()) { static bool CheckPageHeader(const PageBreaker& pager, size_t page) {
console::write_line(YYCC_COLOR_LIGHT_RED(u8"Page out of range.")); bool good_page = pager.IsValidPage(page);
return; if (!good_page) {
termcolor::cprint(u8"Page out of range.", Color::LightRed);
} }
return good_page;
// calc page data
size_t fulllen = data.size(),
startpos = page * pageitems,
fullpage = (fulllen + (pageitems - 1)) / pageitems; // to solve `fulllen / pageitems` empty page issue. like CKStateChunk::GetCeilDwordSize function (+3 /4 to get DWORD size).
// print header
printHdrFct();
// print body
for (size_t counter = startpos; counter < fulllen && (counter - startpos) < pageitems; ++counter) {
printEntryFct(counter, data[counter]);
}
console::format_line(u8"Page %" PRIuSIZET " of %" PRIuSIZET, page + 1, fullpage);
} }
static void WritePageFooter(const PageBreaker& pager, size_t page) {
std::cout << strop::printf(u8"Page %" PRIuSIZET " of %" PRIuSIZET, page + 1, pager.GetMaxPage() + 1) << std::endl;
}
//template<class T>
//static void GeneralPrintList(
// const std::vector<T>& data, size_t page, size_t pageitems,
// std::function<void()> printHdrFct, std::function<void(size_t, const T&)> printEntryFct) {
// // check page overflow
// if (page * pageitems >= data.size()) {
// console::write_line(YYCC_COLOR_LIGHT_RED(u8"Page out of range."));
// return;
// }
// // calc page data
// size_t fulllen = data.size(),
// startpos = page * pageitems,
// fullpage = (fulllen + (pageitems - 1)) / pageitems; // to solve `fulllen / pageitems` empty page issue. like CKStateChunk::GetCeilDwordSize function (+3 /4 to get DWORD size).
// // print header
// printHdrFct();
// // print body
// for (size_t counter = startpos; counter < fulllen && (counter - startpos) < pageitems; ++counter) {
// printEntryFct(counter, data[counter]);
// }
// console::format_line(u8"Page %" PRIuSIZET " of %" PRIuSIZET, page + 1, fullpage);
//}
#pragma endregion #pragma endregion
#pragma region Object Printer #pragma region Object Printer
static void PrintCKObjectDetail(LibCmo::CK2::ObjImpls::CKObject* obj) { static void PrintCKObjectDetail(LibCmo::CK2::ObjImpls::CKObject* obj) {
termcolor::cprintln(u8"CKObject", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKObject", Color::LightYellow);
// print name // print name
std::cout << strop::printf(u8"Name: %s", PrintCKSTRING(obj->GetName()).c_str()) << std::endl; std::cout << strop::printf(u8"Name: %s", PrintCKSTRING(obj->GetName()).c_str()) << std::endl;
// print id // print id
@@ -141,19 +162,19 @@ namespace Unvirt::StructFmt {
static void PrintCKSceneObjectDetail(LibCmo::CK2::ObjImpls::CKSceneObject* obj) { static void PrintCKSceneObjectDetail(LibCmo::CK2::ObjImpls::CKSceneObject* obj) {
PrintCKObjectDetail(obj); PrintCKObjectDetail(obj);
termcolor::cprintln(u8"CKSceneObject", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKSceneObject", Color::LightYellow);
termcolor::cprintln(u8"No Data", termcolor::Color::LightRed); termcolor::cprintln(u8"No Data", Color::LightRed);
} }
static void PrintCKBeObjectDetail(LibCmo::CK2::ObjImpls::CKBeObject* obj) { static void PrintCKBeObjectDetail(LibCmo::CK2::ObjImpls::CKBeObject* obj) {
PrintCKSceneObjectDetail(obj); PrintCKSceneObjectDetail(obj);
termcolor::cprintln(u8"CKBeObject", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKBeObject", Color::LightYellow);
termcolor::cprintln(u8"No Data", termcolor::Color::LightRed); termcolor::cprintln(u8"No Data", Color::LightRed);
} }
static void PrintCKGroupDetail(LibCmo::CK2::ObjImpls::CKGroup* obj) { static void PrintCKGroupDetail(LibCmo::CK2::ObjImpls::CKGroup* obj) {
PrintCKBeObjectDetail(obj); PrintCKBeObjectDetail(obj);
termcolor::cprintln(u8"CKGroup", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKGroup", Color::LightYellow);
LibCmo::CKDWORD count = obj->GetObjectCount(); LibCmo::CKDWORD count = obj->GetObjectCount();
std::cout << strop::printf(u8"Group Object Count: %" PRIuCKDWORD, count) << std::endl; std::cout << strop::printf(u8"Group Object Count: %" PRIuCKDWORD, count) << std::endl;
@@ -176,16 +197,16 @@ namespace Unvirt::StructFmt {
static void PrintCKRenderObjectDetail(LibCmo::CK2::ObjImpls::CKRenderObject* obj) { static void PrintCKRenderObjectDetail(LibCmo::CK2::ObjImpls::CKRenderObject* obj) {
PrintCKBeObjectDetail(obj); PrintCKBeObjectDetail(obj);
termcolor::cprintln(u8"CKRenderObject", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKRenderObject", Color::LightYellow);
termcolor::cprintln(u8"No Data", termcolor::Color::LightRed); termcolor::cprintln(u8"No Data", Color::LightRed);
} }
static void PrintCK3dEntityDetail(LibCmo::CK2::ObjImpls::CK3dEntity* obj) { static void PrintCK3dEntityDetail(LibCmo::CK2::ObjImpls::CK3dEntity* obj) {
PrintCKRenderObjectDetail(obj); PrintCKRenderObjectDetail(obj);
termcolor::cprintln(u8"CK3dEntity", termcolor::Color::LightYellow); termcolor::cprintln(u8"CK3dEntity", Color::LightYellow);
std::cout << u8"== World Matrix ==" << std::endl; std::cout << u8"== World Matrix ==" << std::endl;
auto mat = obj->GetWorldMatrix(); const auto& mat = obj->GetWorldMatrix();
auto matrix_table = CreateGridTable(4); auto matrix_table = CreateGridTable(4);
for (LibCmo::CKDWORD i = 0; i < 4; ++i) { for (LibCmo::CKDWORD i = 0; i < 4; ++i) {
matrix_table.add_row({ matrix_table.add_row({
@@ -227,7 +248,7 @@ namespace Unvirt::StructFmt {
static void PrintCKLightDetail(LibCmo::CK2::ObjImpls::CKLight* obj) { static void PrintCKLightDetail(LibCmo::CK2::ObjImpls::CKLight* obj) {
PrintCK3dEntityDetail(obj); PrintCK3dEntityDetail(obj);
termcolor::cprintln(u8"CKLight", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKLight", Color::LightYellow);
std::cout << u8"== Basics ==" << std::endl; std::cout << u8"== Basics ==" << std::endl;
std::cout << u8"Type: " << Docstring::GetEnumName(obj->GetType()) << std::endl; std::cout << u8"Type: " << Docstring::GetEnumName(obj->GetType()) << std::endl;
@@ -259,13 +280,13 @@ namespace Unvirt::StructFmt {
static void PrintCKTargetLightDetail(LibCmo::CK2::ObjImpls::CKTargetLight* obj) { static void PrintCKTargetLightDetail(LibCmo::CK2::ObjImpls::CKTargetLight* obj) {
PrintCKLightDetail(obj); PrintCKLightDetail(obj);
termcolor::cprintln(u8"CKTargetLight", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKTargetLight", Color::LightYellow);
termcolor::cprintln(u8"No Data", termcolor::Color::LightRed); termcolor::cprintln(u8"No Data", Color::LightRed);
} }
static void PrintCKCameraDetail(LibCmo::CK2::ObjImpls::CKCamera* obj) { static void PrintCKCameraDetail(LibCmo::CK2::ObjImpls::CKCamera* obj) {
PrintCK3dEntityDetail(obj); PrintCK3dEntityDetail(obj);
termcolor::cprintln(u8"CKCamera", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKCamera", Color::LightYellow);
std::cout << u8"== Basics ==" << std::endl; std::cout << u8"== Basics ==" << std::endl;
std::cout << u8"Projection Type: " << Docstring::GetEnumName(obj->GetProjectionType()) << std::endl; std::cout << u8"Projection Type: " << Docstring::GetEnumName(obj->GetProjectionType()) << std::endl;
@@ -287,19 +308,19 @@ namespace Unvirt::StructFmt {
static void PrintCKTargetCameraDetail(LibCmo::CK2::ObjImpls::CKTargetCamera* obj) { static void PrintCKTargetCameraDetail(LibCmo::CK2::ObjImpls::CKTargetCamera* obj) {
PrintCKCameraDetail(obj); PrintCKCameraDetail(obj);
termcolor::cprintln(u8"CKTargetCamera", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKTargetCamera", Color::LightYellow);
termcolor::cprintln(u8"No Data", termcolor::Color::LightRed); termcolor::cprintln(u8"No Data", Color::LightRed);
} }
static void PrintCK3dObjectDetail(LibCmo::CK2::ObjImpls::CK3dObject* obj) { static void PrintCK3dObjectDetail(LibCmo::CK2::ObjImpls::CK3dObject* obj) {
PrintCK3dEntityDetail(obj); PrintCK3dEntityDetail(obj);
termcolor::cprintln(u8"CK3dObject", termcolor::Color::LightYellow); termcolor::cprintln(u8"CK3dObject", Color::LightYellow);
termcolor::cprintln(u8"No Data", termcolor::Color::LightRed); termcolor::cprintln(u8"No Data", Color::LightRed);
} }
static void PrintCKTextureDetail(LibCmo::CK2::ObjImpls::CKTexture* obj) { static void PrintCKTextureDetail(LibCmo::CK2::ObjImpls::CKTexture* obj) {
PrintCKBeObjectDetail(obj); PrintCKBeObjectDetail(obj);
termcolor::cprintln(u8"CKTexture", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKTexture", Color::LightYellow);
// texture // texture
std::cout << u8"== Texture ==" << std::endl; std::cout << u8"== Texture ==" << std::endl;
@@ -344,7 +365,7 @@ namespace Unvirt::StructFmt {
static void PrintCKMaterialDetail(LibCmo::CK2::ObjImpls::CKMaterial* obj) { static void PrintCKMaterialDetail(LibCmo::CK2::ObjImpls::CKMaterial* obj) {
PrintCKBeObjectDetail(obj); PrintCKBeObjectDetail(obj);
termcolor::cprintln(u8"CKMaterial", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKMaterial", Color::LightYellow);
// color // color
std::cout << u8"== Color ==" << std::endl; std::cout << u8"== Color ==" << std::endl;
@@ -407,7 +428,7 @@ namespace Unvirt::StructFmt {
static void PrintCKMeshDetail(LibCmo::CK2::ObjImpls::CKMesh* obj) { static void PrintCKMeshDetail(LibCmo::CK2::ObjImpls::CKMesh* obj) {
PrintCKBeObjectDetail(obj); PrintCKBeObjectDetail(obj);
termcolor::cprintln(u8"CKMesh", termcolor::Color::LightYellow); termcolor::cprintln(u8"CKMesh", Color::LightYellow);
std::cout << u8"== Flags ==" << std::endl; std::cout << u8"== Flags ==" << std::endl;
std::cout << u8"Mesh Flags:" << std::endl; std::cout << u8"Mesh Flags:" << std::endl;
@@ -493,185 +514,229 @@ namespace Unvirt::StructFmt {
void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo) { void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo) {
termcolor::cprint(u8"CKFileInfo", Color::LightYellow);
console::write_line(YYCC_COLOR_LIGHT_YELLOW(u8"CKFileInfo")); std::cout << strop::printf(u8"FileVersion: %" PRIuCKDWORD, fileinfo.FileVersion) << std::endl;
console::format_line(u8"FileVersion: %" PRIuCKDWORD, fileinfo.FileVersion);
LibCmo::CKDWORD ck_series[3] { LibCmo::CKDWORD ck_series[3] {
(fileinfo.CKVersion >> 24) & 0xFF, (fileinfo.CKVersion >> 24) & 0xFF,
(fileinfo.CKVersion >> 16) & 0xFF, (fileinfo.CKVersion >> 16) & 0xFF,
(fileinfo.CKVersion >> 0) & 0xFFFF (fileinfo.CKVersion >> 0) & 0xFFFF
}; };
console::format_line(u8"CKVersion: %02" PRIxCKDWORD "/%02" PRIxCKDWORD "/%04" PRIxCKDWORD, std::cout << strop::printf(u8"CKVersion: %02" PRIxCKDWORD "/%02" PRIxCKDWORD "/%04" PRIxCKDWORD,
ck_series[0], ck_series[1], ck_series[2] ck_series[0],
); ck_series[1],
ck_series[2])
<< std::endl;
LibCmo::CKDWORD product_series[4] { LibCmo::CKDWORD product_series[4] {
(fileinfo.ProductBuild >> 24) & 0xFF, (fileinfo.ProductBuild >> 24) & 0xFF,
(fileinfo.ProductBuild >> 16) & 0xFF, (fileinfo.ProductBuild >> 16) & 0xFF,
(fileinfo.ProductBuild >> 8) & 0xFF, (fileinfo.ProductBuild >> 8) & 0xFF,
(fileinfo.ProductBuild >> 0) & 0xFF, (fileinfo.ProductBuild >> 0) & 0xFF,
}; };
console::format_line(u8"Product (Version / Build): %" PRIuCKDWORD " / %" PRIuCKDWORD ".%" PRIuCKDWORD ".%" PRIuCKDWORD ".%" PRIuCKDWORD, std::cout << strop::printf(u8"Product (Version / Build): %" PRIuCKDWORD " / %" PRIuCKDWORD ".%" PRIuCKDWORD ".%" PRIuCKDWORD ".%" PRIuCKDWORD,
fileinfo.ProductVersion, product_series[0], product_series[1], product_series[2], product_series[3] fileinfo.ProductVersion,
); product_series[0],
product_series[1],
product_series[2],
product_series[3])
<< std::endl;
console::format_line(u8"Save Flags: %s", std::cout << u8"Save Flags: " << Docstring::GetFlagEnumName(fileinfo.FileWriteMode, u8", ") << std::endl;
Docstring::GetFlagEnumName(fileinfo.FileWriteMode, u8", ").c_str()
);
console::format_line(u8"File Size: %s", Docstring::GetReadableFileSize(fileinfo.FileSize).c_str()); std::cout << u8"File Size: " << Docstring::GetReadableFileSize(fileinfo.FileSize) << std::endl;
console::format_line(u8"Crc: 0x%" PRIxCKDWORD, fileinfo.Crc); std::cout << strop::printf(u8"Crc: 0x%" PRIxCKDWORD, fileinfo.Crc) << std::endl << std::endl;
console::write_line(u8"");
std::cout << strop::printf(u8"Hdr1 (Pack / UnPack): %s / %s",
Docstring::GetReadableFileSize(fileinfo.Hdr1PackSize).c_str(),
Docstring::GetReadableFileSize(fileinfo.Hdr1UnPackSize).c_str())
<< std::endl;
std::cout << strop::printf(u8"Data (Pack / UnPack): %s / %s",
Docstring::GetReadableFileSize(fileinfo.DataPackSize).c_str(),
Docstring::GetReadableFileSize(fileinfo.DataUnPackSize).c_str())
<< std::endl
<< std::endl;
console::format_line(u8"Hdr1 (Pack / UnPack): %s / %s", std::cout << strop::printf(u8"Manager Count: %" PRIuCKDWORD, fileinfo.ManagerCount) << std::endl;
Docstring::GetReadableFileSize(fileinfo.Hdr1PackSize).c_str(), std::cout << strop::printf(u8"Object Count: %" PRIuCKDWORD, fileinfo.ObjectCount) << std::endl;
Docstring::GetReadableFileSize(fileinfo.Hdr1UnPackSize).c_str() std::cout << strop::printf(u8"Max ID Saved: %" PRIuCKID, fileinfo.MaxIDSaved) << std::endl;
);
console::format_line(u8"Data (Pack / UnPack): %s / %s",
Docstring::GetReadableFileSize(fileinfo.DataPackSize).c_str(),
Docstring::GetReadableFileSize(fileinfo.DataUnPackSize).c_str()
);
console::write_line(u8"");
console::format_line(u8"Manager Count: %" PRIuCKDWORD, fileinfo.ManagerCount);
console::format_line(u8"Object Count: %" PRIuCKDWORD, fileinfo.ObjectCount);
console::format_line(u8"Max ID Saved: %" PRIuCKID, fileinfo.MaxIDSaved);
} }
#pragma region Object List Printer #pragma region Object List Printer
static void PrintObjectListHeader(bool full_detail) { static tabulate::Tabulate CreateObjectListTable(bool full_detail) {
if (full_detail) { if (full_detail) {
console::write_line(u8"SaveFlags\tOptions\tCK ID\tFile CK ID\tFile Index\tPack Size\tIndex\tType\tCKObject\tCKStateChunk\tName"); return CreateStandardTable({
u8"SaveFlags",
u8"Options",
u8"CK ID",
u8"File CK ID",
u8"File Index",
u8"Pack Size",
u8"Index",
u8"Type",
u8"CKObject",
u8"CKStateChunk",
u8"Name",
});
} else { } else {
console::write_line(u8"Index\tType\tObject\tChunk\tName"); return CreateStandardTable({
u8"Index",
u8"Type",
u8"Object",
u8"Chunk",
u8"Name",
});
} }
} }
static void PrintObjectListEntry(const LibCmo::CK2::CKFileObject& obj, const LibCmo::CK2::CKFileInfo& fileinfo, size_t entry_index, bool full_detail) { static void FillObjectListTable(tabulate::Tabulate& table,
if (full_detail) { const LibCmo::CK2::CKFileObject& obj,
Console::Format(u8"0x%08" PRIxCKDWORD "\t", obj.SaveFlags); const LibCmo::CK2::CKFileInfo& fileinfo,
Console::Format(u8"%s\t", Docstring::GetEnumName(obj.Options).c_str()); size_t entry_index,
bool full_detail) {
// Prepare simple layout data first
auto col_index = strop::printf(u8"#%" PRIuSIZET, entry_index);
auto col_type = Docstring::GetClassIdName(obj.ObjectCid);
auto col_object = PrintColorfulBool(obj.ObjPtr != nullptr);
auto col_chunk = PrintColorfulBool(obj.Data != nullptr);
auto col_name = PrintCKSTRING(LibCmo::XContainer::NSXString::ToCKSTRING(obj.Name));
Console::Format(u8"%" PRIuCKID "\t%" PRIuCKID "\t", // Return first if we are simple layout
obj.CreatedObjectId, if (!full_detail) {
obj.ObjectId table.add_row({
); col_index,
col_type,
Console::Format(u8"0x%08" PRIxCKDWORD " (Rel: 0x%08" PRIxCKDWORD ")\t", col_object,
obj.FileIndex, col_chunk,
obj.FileIndex - CKSizeof(LibCmo::CK2::CKRawFileInfo) - fileinfo.Hdr1UnPackSize col_name,
); });
Console::Format(u8"0x%08" PRIxCKDWORD "\t", obj.PackSize); return;
} }
// following items are shared by full details and simple layout
console::format_line(u8"#%" PRIuSIZET "\t%s\t%s\t%s\t%s", // Prepare full detail data
entry_index, auto col_save_flag = strop::printf(u8"0x%08" PRIxCKDWORD, obj.SaveFlags);
Docstring::GetClassIdName(obj.ObjectCid).c_str(), auto col_options = Docstring::GetEnumName(obj.Options);
PrintColorfulBool(obj.ObjPtr != nullptr).c_str(), auto col_ckid = strop::printf(u8"%" PRIuCKID, obj.CreatedObjectId);
PrintColorfulBool(obj.Data != nullptr).c_str(), auto col_file_ckid = strop::printf(u8"%" PRIuCKID, obj.ObjectId);
PrintCKSTRING(LibCmo::XContainer::NSXString::ToCKSTRING(obj.Name)).c_str() auto col_file_index = strop::printf(u8"0x%08" PRIxCKDWORD " (RVA: 0x%08" PRIxCKDWORD ")",
); obj.FileIndex,
obj.FileIndex - CKSizeof(LibCmo::CK2::CKRawFileInfo) - fileinfo.Hdr1UnPackSize);
auto col_pack_size = strop::printf(u8"0x%08" PRIxCKDWORD, obj.PackSize);
// Return full info layout
table.add_row({
col_save_flag,
col_options,
col_ckid,
col_file_ckid,
col_file_index,
col_pack_size,
col_index,
col_type,
col_object,
col_chunk,
col_name,
});
} }
void PrintObjectList( void PrintObjectList(const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls,
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls, const LibCmo::CK2::CKFileInfo& fileinfo,
const LibCmo::CK2::CKFileInfo& fileinfo, size_t page,
size_t page, size_t pageitems, size_t pageitems,
bool full_detail) { bool full_detail) {
termcolor::cprint(u8"CKFileObject", Color::LightYellow);
console::write_line(YYCC_COLOR_LIGHT_YELLOW(u8"CKFileObject")); PageBreaker pager(ls.size(), pageitems);
GeneralPrintList<LibCmo::CK2::CKFileObject>(ls, page, pageitems, if (!CheckPageHeader(pager, page)) return;
[full_detail]() -> void {
PrintObjectListHeader(full_detail);
},
[&fileinfo, full_detail](size_t index, const LibCmo::CK2::CKFileObject& obj) -> void {
PrintObjectListEntry(obj, fileinfo, index, full_detail);
}
);
auto table = CreateObjectListTable(full_detail);
for (size_t i = pager.GetPageBeginIndex(page); i < pager.GetPageEndIndex(page); ++i) {
FillObjectListTable(table, ls[i], fileinfo, i, full_detail);
}
table.print();
WritePageFooter(pager, page);
} }
void PrintSearchedObjectList( void PrintSearchedObjectList(const LibCmo::XContainer::XArray<size_t>& idxls,
const LibCmo::XContainer::XArray<size_t>& idxls, const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls,
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls, const LibCmo::CK2::CKFileInfo& fileinfo,
const LibCmo::CK2::CKFileInfo& fileinfo, size_t page,
size_t page, size_t pageitems, size_t pageitems,
bool full_detail) { bool full_detail) {
termcolor::cprint(u8"CKFileObject Searching Result", Color::LightYellow);
console::write_line(YYCC_COLOR_LIGHT_YELLOW(u8"CKFileObject Searching Result")); PageBreaker pager(idxls.size(), pageitems);
GeneralPrintList<size_t>(idxls, page, pageitems, if (!pager.IsValidPage(page)) return;
[full_detail]() -> void {
PrintObjectListHeader(full_detail);
},
[&ls, &fileinfo, full_detail](size_t, const size_t& index_to_obj) -> void {
// resolve index to real item.
// and pass the entry index, not the page index.
PrintObjectListEntry(ls[index_to_obj], fileinfo, index_to_obj, full_detail);
}
);
auto table = CreateObjectListTable(full_detail);
for (size_t i = pager.GetPageBeginIndex(page); i < pager.GetPageEndIndex(page); ++i) {
FillObjectListTable(table, ls[idxls[i]], fileinfo, i, full_detail);
}
table.print();
WritePageFooter(pager, page);
} }
#pragma endregion #pragma endregion
#pragma region Manager List Printer #pragma region Manager List Printer
static void PrintManagerListHeader(bool full_detail) { static tabulate::Tabulate CreateManagerListTable(bool full_detail) {
// manager list now do not affected by list style because it is enough short // manager list now do not affected by list style because it is enough short
console::write_line(u8"Index\tCKGUID\tCKStateChunk"); return CreateStandardTable({
u8"Index",
u8"CKGUID",
u8"CKStateChunk",
});
} }
static void PrintManagerListEntry(const LibCmo::CK2::CKFileManagerData& mgr, size_t entry_index, bool full_detail) { static void FillManagerListTable(tabulate::Tabulate& table, const LibCmo::CK2::CKFileManagerData& mgr, size_t entry_index, bool full_detail) {
// not affected by list style. // not affected by list style.
console::format_line(u8"#%" PRIuSIZET "\t%s\t%s", auto col_index = strop::printf(u8"#%" PRIuSIZET, entry_index);
entry_index, auto col_ckguid = PrintCKGUID(mgr.Manager);
PrintCKGUID(mgr.Manager).c_str(), auto col_ckstatechunk = PrintPointer(mgr.Data);
PrintPointer(mgr.Data).c_str()
);
} }
void PrintManagerList( void PrintManagerList(const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls,
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls, size_t page,
size_t page, size_t pageitems, size_t pageitems,
bool full_detail) { bool full_detail) {
termcolor::cprint(u8"CKFileManager", Color::LightYellow);
console::write_line(YYCC_COLOR_LIGHT_YELLOW(u8"CKFileManager")); PageBreaker pager(ls.size(), pageitems);
GeneralPrintList<LibCmo::CK2::CKFileManagerData>(ls, page, pageitems, if (!pager.IsValidPage(page)) return;
[full_detail]() -> void {
// print header
PrintManagerListHeader(full_detail);
},
[full_detail](size_t index, const LibCmo::CK2::CKFileManagerData& mgr) -> void {
// print body
PrintManagerListEntry(mgr, index, full_detail);
}
);
auto table = CreateObjectListTable(full_detail);
for (size_t i = pager.GetPageBeginIndex(page); i < pager.GetPageEndIndex(page); ++i) {
FillManagerListTable(table, ls[i], i, full_detail);
}
table.print();
WritePageFooter(pager, page);
} }
void PrintSearchedManagerList( void PrintSearchedManagerList(const LibCmo::XContainer::XArray<size_t>& idxls,
const LibCmo::XContainer::XArray<size_t>& idxls, const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls,
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls, size_t page,
size_t page, size_t pageitems, size_t pageitems,
bool full_detail) { bool full_detail) {
termcolor::cprint(u8"CKFileManager Searching Result", Color::LightYellow);
console::write_line(YYCC_COLOR_LIGHT_YELLOW(u8"CKFileManager Searching Result")); PageBreaker pager(ls.size(), pageitems);
GeneralPrintList<size_t>(idxls, page, pageitems, if (!pager.IsValidPage(page)) return;
[full_detail]() -> void {
PrintManagerListHeader(full_detail);
},
[&ls, full_detail](size_t, const size_t& index_to_mgr) -> void {
// resolve index to real one
PrintManagerListEntry(ls[index_to_mgr], index_to_mgr, full_detail);
}
);
auto table = CreateObjectListTable(full_detail);
for (size_t i = pager.GetPageBeginIndex(page); i < pager.GetPageEndIndex(page); ++i) {
FillManagerListTable(table, ls[idxls[i]], i, full_detail);
}
table.print();
WritePageFooter(pager, page);
} }
#pragma endregion #pragma endregion
void PrintCKObject(const LibCmo::CK2::ObjImpls::CKObject* obj) { void PrintCKObject(const LibCmo::CK2::ObjImpls::CKObject* obj) {
if (obj == nullptr) { if (obj == nullptr) {
console::write_line(YYCC_COLOR_LIGHT_RED(u8"Null Object")); termcolor::cprint(u8"Null Object", Color::LightRed);
return; return;
} }
@@ -720,26 +785,26 @@ namespace Unvirt::StructFmt {
PrintCKMeshDetail(static_cast<LibCmo::CK2::ObjImpls::CKMesh*>(mobj)); PrintCKMeshDetail(static_cast<LibCmo::CK2::ObjImpls::CKMesh*>(mobj));
break; break;
default: default:
console::write_line(YYCC_COLOR_LIGHT_RED(u8"Not Implemented.")); termcolor::cprint(u8"Not Implemented.", Color::LightRed);
break; break;
} }
} }
void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager* mgr) { void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager* mgr) {
console::write_line(YYCC_COLOR_LIGHT_YELLOW(u8"CKBaseManager")); termcolor::cprint(u8"CKBaseManager", Color::LightYellow);
if (mgr == nullptr) { if (mgr == nullptr) {
console::write_line(YYCC_COLOR_LIGHT_RED(u8"Null Manager")); termcolor::cprint(u8"Null Manager", Color::LightRed);
return; return;
} }
console::write_line(YYCC_COLOR_LIGHT_RED(u8"Not Implemented.")); termcolor::cprint(u8"Not Implemented.", Color::LightRed);
} }
void PrintCKStateChunk(const LibCmo::CK2::CKStateChunk* chunk) { void PrintCKStateChunk(const LibCmo::CK2::CKStateChunk* chunk) {
console::write_line(YYCC_COLOR_LIGHT_YELLOW(u8"CKStateChunk")); termcolor::cprint(u8"CKStateChunk", Color::LightYellow);
if (chunk == nullptr) { if (chunk == nullptr) {
console::write_line(YYCC_COLOR_LIGHT_RED(u8"Null Chunk")); termcolor::cprint(u8"Null Chunk", Color::LightRed);
return; return;
} }
@@ -749,41 +814,47 @@ namespace Unvirt::StructFmt {
// write profile // write profile
const auto profile = operchunk->GetStateChunkProfile(); const auto profile = operchunk->GetStateChunkProfile();
console::format_line(u8"Type: %s", Docstring::GetClassIdName(profile.m_ClassId).c_str()); std::cout << u8"Type: " << Docstring::GetClassIdName(profile.m_ClassId) << std::endl;
console::format_line(u8"Version (Data / Chunk): %" PRIuCKDWORD " (%s) / %" PRIuCKDWORD " (%s)", std::cout << strop::printf(u8"Version (Data / Chunk): %" PRIuCKDWORD " (%s) / %" PRIuCKDWORD " (%s)",
static_cast<LibCmo::CKDWORD>(profile.m_DataVersion), Docstring::GetEnumName(profile.m_DataVersion).c_str(), static_cast<LibCmo::CKDWORD>(profile.m_DataVersion),
static_cast<LibCmo::CKDWORD>(profile.m_ChunkVersion), Docstring::GetEnumName(profile.m_ChunkVersion).c_str() Docstring::GetEnumName(profile.m_DataVersion).c_str(),
); static_cast<LibCmo::CKDWORD>(profile.m_ChunkVersion),
console::format_line(u8"List (Object / Chunk / Manager): %" PRIuCKDWORD " / %" PRIuCKDWORD " / %" PRIuCKDWORD, Docstring::GetEnumName(profile.m_ChunkVersion).c_str())
static_cast<LibCmo::CKDWORD>(profile.m_ObjectListSize), << std::endl;
static_cast<LibCmo::CKDWORD>(profile.m_ChunkListSize), std::cout << strop::printf(u8"List (Object / Chunk / Manager): %" PRIuCKDWORD " / %" PRIuCKDWORD " / %" PRIuCKDWORD,
static_cast<LibCmo::CKDWORD>(profile.m_ManagerListSize) static_cast<LibCmo::CKDWORD>(profile.m_ObjectListSize),
); static_cast<LibCmo::CKDWORD>(profile.m_ChunkListSize),
static_cast<LibCmo::CKDWORD>(profile.m_ManagerListSize))
<< std::endl;
console::format_line(u8"Data: %s (0x%" PRIxCKDWORD " DWORD)", std::cout << strop::printf(u8"Data: %s (0x%" PRIxCKDWORD " DWORD)", PrintPointer(profile.m_pData).c_str(), profile.m_DataDwSize)
PrintPointer(profile.m_pData).c_str(), << std::endl;
profile.m_DataDwSize
);
console::format_line(u8"Bind CKFile: %s", PrintPointer(profile.m_BindFile).c_str()); std::cout << u8"Bind CKFile: " << PrintPointer(profile.m_BindFile) << std::endl;
console::format_line(u8"Bind CKContext: %s", PrintPointer(profile.m_BindContext).c_str()); std::cout << u8"Bind CKContext: " << PrintPointer(profile.m_BindContext) << std::endl;
// write identifiers // write identifiers
operchunk->StartRead(); operchunk->StartRead();
const auto collection = operchunk->GetIdentifiersProfile(); const auto collection = operchunk->GetIdentifiersProfile();
operchunk->StopRead(); operchunk->StopRead();
console::write_line(YYCC_COLOR_LIGHT_YELLOW(u8"Identifiers")); termcolor::cprint(u8"Identifiers", Color::LightYellow);
console::write_line(u8"Identifier\tData Pointer\tData Size"); auto ident_table = CreateStandardTable({
u8"Identifier",
u8"Data Address",
u8"Data Size",
});
for (const auto& ident : collection) { for (const auto& ident : collection) {
console::format_line(u8"0x%08" PRIxCKDWORD "\t%s\t%" PRIuCKDWORD " (%" PRIuCKDWORD " DWORD + %" PRIuCKDWORD ")", ident_table.add_row({
ident.m_Identifier, strop::printf(u8"0x%08" PRIxCKDWORD, ident.m_Identifier),
PrintPointer(ident.m_DataPtr).c_str(), PrintPointer(ident.m_DataPtr),
ident.m_AreaSize, strop::printf(u8"%" PRIuCKDWORD " (%" PRIuCKDWORD " DWORD + %" PRIuCKDWORD ")",
ident.m_AreaSize / CKSizeof(LibCmo::CKDWORD), ident.m_AreaSize,
ident.m_AreaSize % CKSizeof(LibCmo::CKDWORD) ident.m_AreaSize / CKSizeof(LibCmo::CKDWORD),
); ident.m_AreaSize % CKSizeof(LibCmo::CKDWORD)),
});
} }
ident_table.print();
} }
} }

33
Unvirt/Utils.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "Utils.hpp"
#include <yycc/num/op.hpp>
#include <stdexcept>
namespace Unvirt::Utils {
PageBreaker::PageBreaker(size_t count, size_t count_per_page) : count(count), count_per_page(count_per_page) {
if (count_per_page == 0) throw std::logic_error("item count per page should not be zero");
}
PageBreaker::~PageBreaker() {}
bool PageBreaker::IsValidPage(size_t page) const {
if (page == 0) return true;
else return page < this->GetMaxPage();
}
size_t PageBreaker::GetMaxPage() const {
if (this->count == 0) return 0;
else return yycc::num::op::div_ceil(this->count, this->count_per_page) - 1;
}
size_t PageBreaker::GetPageBeginIndex(size_t page) const {
if (this->IsValidPage(page)) return page * this->count_per_page;
else throw std::runtime_error("invalid page index");
}
size_t PageBreaker::GetPageEndIndex(size_t page) const {
if (this->IsValidPage(page)) return std::min(this->count, (page + 1) * this->count_per_page);
else throw std::runtime_error("invalid page index");
}
} // namespace Unvirt::Utils

54
Unvirt/Utils.hpp Normal file
View File

@@ -0,0 +1,54 @@
#pragma once
#include <yycc/macro/class_copy_move.hpp>
namespace Unvirt::Utils {
class PageBreaker {
public:
/**
* @brief
* @param[in] count
* @param[in] count_per_page
* @exception std::logic_error if the count per page is zero.
*/
PageBreaker(size_t count, size_t count_per_page);
~PageBreaker();
YYCC_DEFAULT_COPY_MOVE(PageBreaker)
public:
/**
* @brief
* @param[in] page The page index (zero-based)
* @return
* @remarks Page zero is always valid because we at least have one page.
*/
bool IsValidPage(size_t page) const;
/**
* @brief
* @return The max page index (zero-based, inclusive)
* @remarks Zero count will produce at least one page.
*/
size_t GetMaxPage() const;
/**
* @brief
* @param[in] page The page index (zero-based)
* @return The start index of this page (inclusive).
* Is is usually used as the init statement `size_t i = pb.GetPageBeginIndex()` in "for" statement.
* @exception std::runtime_error if page index is out of range.
*/
size_t GetPageBeginIndex(size_t page) const;
/**
* @brief
* @param[in] page The page index (zero-based)
* @return The end index of this page (exclusive).
* Is is usually used as the stop statement `i < pb.GetPageEndIndex()` in "for" statement.
* @exception std::runtime_error if page index is out of range.
*/
size_t GetPageEndIndex(size_t page) const;
private:
size_t count;
size_t count_per_page;
};
}