From e166b8ec5b5a8ce579f0d9d6eb1960d56e55d41b Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Sat, 4 Mar 2023 00:13:03 +0800 Subject: [PATCH] finish cmd --- Unvirt/CmdHelper.cpp | 71 +++++++++++++++--- Unvirt/CmdHelper.hpp | 4 +- Unvirt/StructFormatter.cpp | 144 +++++++++++++++++++++++++++---------- Unvirt/StructFormatter.hpp | 8 +-- Unvirt/Unvirt.cpp | 20 +++--- 5 files changed, 186 insertions(+), 61 deletions(-) diff --git a/Unvirt/CmdHelper.cpp b/Unvirt/CmdHelper.cpp index 3f7ec79..afe74bc 100644 --- a/Unvirt/CmdHelper.cpp +++ b/Unvirt/CmdHelper.cpp @@ -13,6 +13,9 @@ /* TODO: do not re-allocated ctx and file for each loading in future. this will be implemented by free all objects within doc. + +split encoding and temp folder setting +and load command only have file name arg. */ namespace Unvirt::CmdHelper { @@ -39,6 +42,7 @@ namespace Unvirt::CmdHelper { // split for (auto it = u8cmd.begin(); it != u8cmd.end(); ++it) { mCmdChar = (*it); + if (!std::isprint(mCmdChar)) continue; // skip all invalid characters switch (mState) { case StateType::SPACE: @@ -169,14 +173,14 @@ namespace Unvirt::CmdHelper { else if (subcmd == "unload") this->ProcUnLoad(cmds); else if (subcmd == "info") this->ProcInfo(cmds); else if (subcmd == "ls") this->ProcLs(cmds); - else if (subcmd == "page") this->ProcPage(cmds); + else if (subcmd == "items") this->ProcItems(cmds); else if (subcmd == "help") this->PrintHelp(); else if (subcmd == "exit") break; else { - this->PrintCommonError("No such command \"\".", subcmd.c_str()); + this->PrintCommonError("No such command \"%s\".", subcmd.c_str()); this->PrintHelp(); } - + } } @@ -192,7 +196,7 @@ namespace Unvirt::CmdHelper { } bool InteractiveCmd::HasOpenedFile(void) { - return (m_Ctx != nullptr || m_File == nullptr || m_Doc != nullptr); + return (m_Ctx != nullptr || m_File != nullptr || m_Doc != nullptr); } void InteractiveCmd::PrintHelp(void) { @@ -215,9 +219,9 @@ namespace Unvirt::CmdHelper { fputs("\tDescription: List something about loaded Virtools composition.\n", f); fputs("\tSyntax: ls [page]\n", f); - fputs("page\n", f); + fputs("items\n", f); fputs("\tDescription: Set up how many items should be listed in one page when using \"ls\" command.\n", f); - fputs("\tSyntax: page \n", f); + fputs("\tSyntax: items \n", f); fputs("exit\n", f); fputs("\tDescription: Exit program\n", f); @@ -243,6 +247,7 @@ namespace Unvirt::CmdHelper { std::vfprintf(stdout, u8_fmt, argptr); std::fputs(UNVIRT_TERMCOLTAIL, stdout); va_end(argptr); + std::fputc('\n', stdout); } @@ -288,13 +293,17 @@ namespace Unvirt::CmdHelper { if (err != LibCmo::CK2::CKERROR::CKERR_OK) { // fail to load. release all. this->PrintCommonError("Fail to open file. Function return: %s\n%s", - Unvirt::AccessibleValue::GetCkErrorName(err), - Unvirt::AccessibleValue::GetCkErrorDescription(err) + Unvirt::AccessibleValue::GetCkErrorName(err).c_str(), + Unvirt::AccessibleValue::GetCkErrorDescription(err).c_str() ); if (m_Doc != nullptr) delete m_Doc; if (m_File != nullptr) delete m_File; if (m_Ctx != nullptr) delete m_Ctx; + + m_Doc = nullptr; + m_File = nullptr; + m_Ctx = nullptr; } } @@ -309,6 +318,10 @@ namespace Unvirt::CmdHelper { if (m_Doc != nullptr) delete m_Doc; if (m_File != nullptr) delete m_File; if (m_Ctx != nullptr) delete m_Ctx; + + m_Doc = nullptr; + m_File = nullptr; + m_Ctx = nullptr; } void InteractiveCmd::ProcInfo(const std::deque& cmd) { @@ -323,14 +336,54 @@ namespace Unvirt::CmdHelper { } void InteractiveCmd::ProcLs(const std::deque& cmd) { + // static values of switches static const std::vector c_AllowedSwitches{ "obj", "mgr" }; + // check pre-requirement + if (!HasOpenedFile()) { + this->PrintCommonError("No loaded file."); + return; + } + + // check requirement + size_t pos = 0u; + std::string sw; + if (!ArgParser::ParseSwitch(cmd, pos, c_AllowedSwitches, sw)) { + this->PrintArgParseError(cmd, pos); + return; + } + ++pos; + int32_t gotten_page; + if (!ArgParser::ParseInt(cmd, pos, gotten_page) || gotten_page <= 0) { + gotten_page = 0; // asssume as zero + } + size_t page = static_cast(gotten_page); + + // show list + if (sw == c_AllowedSwitches[0]) { + // obj list + if (page * this->m_PageLen >= m_Doc->m_FileObjects.size()) { + this->PrintCommonError("Page out of range."); + return; + } + + Unvirt::StructFormatter::PrintObjectList(this->m_Doc->m_FileObjects, page, this->m_PageLen); + + } else { + // mgr list + if (page * this->m_PageLen >= m_Doc->m_FileManagersData.size()) { + this->PrintCommonError("Page out of range."); + return; + } + + Unvirt::StructFormatter::PrintManagerList(this->m_Doc->m_FileManagersData, page, this->m_PageLen); + } } - void InteractiveCmd::ProcPage(const std::deque& cmd) { + void InteractiveCmd::ProcItems(const std::deque& cmd) { // check requirement size_t pos = 0u; int32_t count; diff --git a/Unvirt/CmdHelper.hpp b/Unvirt/CmdHelper.hpp index 0fd0b1e..4133fb1 100644 --- a/Unvirt/CmdHelper.hpp +++ b/Unvirt/CmdHelper.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include @@ -152,7 +152,7 @@ namespace Unvirt::CmdHelper { void ProcUnLoad(const std::deque& cmd); void ProcInfo(const std::deque& cmd); void ProcLs(const std::deque& cmd); - void ProcPage(const std::deque& cmd); + void ProcItems(const std::deque& cmd); CmdSplitter m_CmdSplitter; size_t m_PageLen; diff --git a/Unvirt/StructFormatter.cpp b/Unvirt/StructFormatter.cpp index 61be984..2ad56ab 100644 --- a/Unvirt/StructFormatter.cpp +++ b/Unvirt/StructFormatter.cpp @@ -2,56 +2,124 @@ #include "AccessibleValue.hpp" #include "TerminalHelper.hpp" -namespace Unvirt { - namespace StructFormatter { +namespace Unvirt::StructFormatter { - static FILE* fout = stdout; + static FILE* fout = stdout; - void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo) { + void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo) { - fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileInfo\n")), fout); - fprintf(fout, "FileVersion: %" PRIu32 "\n", fileinfo.FileVersion); - fprintf(fout, "CKVersion: %02" PRIX32 "/%02" PRIX32 "/%04" PRIX32 "\n", - (fileinfo.CKVersion >> 24) & 0xFF, - (fileinfo.CKVersion >> 16) & 0xFF, - (fileinfo.CKVersion >> 0) & 0xFFFF - ); + fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileInfo\n")), fout); + fprintf(fout, "FileVersion: %" PRIu32 "\n", fileinfo.FileVersion); + fprintf(fout, "CKVersion: %02" PRIX32 "/%02" PRIX32 "/%04" PRIX32 "\n", + (fileinfo.CKVersion >> 24) & 0xFF, + (fileinfo.CKVersion >> 16) & 0xFF, + (fileinfo.CKVersion >> 0) & 0xFFFF + ); - LibCmo::CK2::CKDWORD product_series[4]{ - (fileinfo.ProductBuild >> 24) & 0xFF, - (fileinfo.ProductBuild >> 16) & 0xFF, - (fileinfo.ProductBuild >> 8) & 0xFF, - (fileinfo.ProductBuild >> 0) & 0xFF, - }; - fprintf(fout, "Product (Version / Build): %" PRIu32 " / %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 "\n", - fileinfo.ProductVersion, product_series[0], product_series[1], product_series[2], product_series[3] - ); + LibCmo::CK2::CKDWORD product_series[4]{ + (fileinfo.ProductBuild >> 24) & 0xFF, + (fileinfo.ProductBuild >> 16) & 0xFF, + (fileinfo.ProductBuild >> 8) & 0xFF, + (fileinfo.ProductBuild >> 0) & 0xFF, + }; + fprintf(fout, "Product (Version / Build): %" PRIu32 " / %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 "\n", + fileinfo.ProductVersion, product_series[0], product_series[1], product_series[2], product_series[3] + ); - fprintf(fout, "Save Flags: %s\n", Unvirt::AccessibleValue::GetFlagEnumName( - Unvirt::AccessibleValue::EnumDesc::CK_FILE_WRITEMODE, fileinfo.FileWriteMode - ).c_str()); + fprintf(fout, "Save Flags: %s\n", Unvirt::AccessibleValue::GetFlagEnumName( + Unvirt::AccessibleValue::EnumDesc::CK_FILE_WRITEMODE, fileinfo.FileWriteMode + ).c_str()); - fprintf(fout, "File Size: %s\n", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.FileSize).c_str()); + fprintf(fout, "File Size: %s\n", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.FileSize).c_str()); - fprintf(fout, "Crc: 0x%" PRIX32 "\n", fileinfo.Crc); - fputc('\n', fout); + fprintf(fout, "Crc: 0x%" PRIX32 "\n", fileinfo.Crc); + fputc('\n', fout); - fputs("Hdr1 (Pack / UnPack): ", fout); - fprintf(fout, "%s / ", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.Hdr1PackSize).c_str()); - fprintf(fout, "%s\n", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.Hdr1UnPackSize).c_str()); + fputs("Hdr1 (Pack / UnPack): ", fout); + fprintf(fout, "%s / ", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.Hdr1PackSize).c_str()); + fprintf(fout, "%s\n", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.Hdr1UnPackSize).c_str()); - fputs("Data (Pack / UnPack): ", fout); - fprintf(fout, "%s / ", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.DataPackSize).c_str()); - fprintf(fout, "%s\n", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.DataUnPackSize).c_str()); - fputc('\n', fout); + fputs("Data (Pack / UnPack): ", fout); + fprintf(fout, "%s / ", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.DataPackSize).c_str()); + fprintf(fout, "%s\n", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.DataUnPackSize).c_str()); + fputc('\n', fout); - fprintf(fout, "Manager Count: %" PRIu32 "\nObject Count: %" PRIu32 "\nMax ID Saved: %" PRIu32 "\n", - fileinfo.ManagerCount, fileinfo.ObjectCount, fileinfo.MaxIDSaved - ); - - } + fprintf(fout, "Manager Count: %" PRIu32 "\nObject Count: %" PRIu32 "\nMax ID Saved: %" PRIu32 "\n", + fileinfo.ManagerCount, fileinfo.ObjectCount, fileinfo.MaxIDSaved + ); } + + static void PrintCKSTRING(const std::string& name) { + if (name.empty()) { + fputs(UNVIRT_TERMCOL_LIGHT_MAGENTA(("")), fout); + } else { + fputs(name.c_str(), fout); + } + } + static void PrintPointer(const void* ptr) { + if (ptr == nullptr) { + fputs(UNVIRT_TERMCOL_LIGHT_CYAN(("")), fout); + } else { + fprintf(fout, "<0x%08zX>", reinterpret_cast(ptr)); + } + } + static void PrintCKGUID(const LibCmo::CK2::CKGUID& guid) { + fprintf(stdout, "<0x%08" PRIx32 ", 0x%08" PRIx32 ">", guid.d1, guid.d2); + } + + void PrintObjectList(const LibCmo::CK2::XArray& ls, size_t page, size_t pageitems) { + + fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileObject\n")), fout); + size_t fulllen = ls.size(), + startpos = page * pageitems, + fullpage = fulllen / pageitems; + + // print header + fputs("Index\tCK ID\tCKObject\tCKStateChunk\tName\n", fout); + + // print body + for (size_t counter = startpos; counter < fulllen && (counter - startpos) < pageitems; ++counter) { + const auto& obj = ls[counter]; + + fprintf(stdout, "%zu\t%" PRIu32 "\t", counter, obj.ObjectId); + PrintPointer(obj.ObjPtr); + fputc('\t', fout); + PrintPointer(obj.Data); + fputc('\t', fout); + PrintCKSTRING(obj.Name); + fputc('\n', fout); + } + + fprintf(fout, "Page %zu of %zu\n", page, fullpage); + } + + void PrintManagerList(const LibCmo::CK2::XArray& ls, size_t page, size_t pageitems) { + + fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileManager\n")), fout); + size_t fulllen = ls.size(), + startpos = page * pageitems, + fullpage = fulllen / pageitems; + + // print header + fputs("Index\tCKGUID\tCKBaseManager\tCKStateChunk\n", fout); + + // print body + for (size_t counter = startpos; counter < fulllen && (counter - startpos) < pageitems; ++counter) { + const auto& mgr = ls[counter]; + + fprintf(stdout, "%zu\t", counter); + PrintCKGUID(mgr.Manager); + fputc('\t', fout); + PrintPointer(mgr.MgrPtr); + fputc('\t', fout); + PrintPointer(mgr.Data); + fputc('\n', fout); + } + + fprintf(fout, "Page %zu of %zu\n", page, fullpage); + } + } diff --git a/Unvirt/StructFormatter.hpp b/Unvirt/StructFormatter.hpp index b05af1d..2cf1ee3 100644 --- a/Unvirt/StructFormatter.hpp +++ b/Unvirt/StructFormatter.hpp @@ -2,10 +2,10 @@ #include -namespace Unvirt { - namespace StructFormatter { +namespace Unvirt::StructFormatter { - void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo); + void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo); + void PrintObjectList(const LibCmo::CK2::XArray& ls, size_t page, size_t pageitems); + void PrintManagerList(const LibCmo::CK2::XArray& ls, size_t page, size_t pageitems); - } } diff --git a/Unvirt/Unvirt.cpp b/Unvirt/Unvirt.cpp index 92d72c9..c9c2f61 100644 --- a/Unvirt/Unvirt.cpp +++ b/Unvirt/Unvirt.cpp @@ -1,6 +1,7 @@ #include "AccessibleValue.hpp" #include "TerminalHelper.hpp" #include "StructFormatter.hpp" +#include "CmdHelper.hpp" #include "CKMinContext.hpp" #include "CKFile.hpp" @@ -12,16 +13,19 @@ int main(int argc, char* argv[]) { Unvirt::TerminalHelper::EnsureTerminalColor(); Unvirt::TerminalHelper::EnsureTerminalEncoding(); - LibCmo::CK2::CKMinContext vtctx; - vtctx.SetTempPath("Temp"); - vtctx.SetEncoding("850"); + //LibCmo::CK2::CKMinContext vtctx; + //vtctx.SetTempPath("Temp"); + //vtctx.SetEncoding("850"); - LibCmo::CK2::CKFile vtfile(&vtctx); - LibCmo::CK2::CKFileDocument* doc; - LibCmo::CK2::CKERROR err = vtfile.DeepLoad("Level_02.NMO", &doc); + //LibCmo::CK2::CKFile vtfile(&vtctx); + //LibCmo::CK2::CKFileDocument* doc; + //LibCmo::CK2::CKERROR err = vtfile.DeepLoad("Level_02.NMO", &doc); - if (doc) - Unvirt::StructFormatter::PrintCKFileInfo(doc->m_FileInfo); + //if (doc) + // Unvirt::StructFormatter::PrintCKFileInfo(doc->m_FileInfo); + auto cmd = new Unvirt::CmdHelper::InteractiveCmd(); + cmd->Run(); + delete cmd; return 0; }