diff --git a/Unvirt/AccessibleValue.cpp b/Unvirt/AccessibleValue.cpp index 131c492..64f7d3c 100644 --- a/Unvirt/AccessibleValue.cpp +++ b/Unvirt/AccessibleValue.cpp @@ -8,8 +8,6 @@ namespace Unvirt { #pragma region universal enum name - const char c_InvalidEnumName[] = "[undefined]"; - namespace EnumDesc { const EnumDescPairArray CK_FILE_WRITEMODE{ { LibCmo::CK2::CK_FILE_WRITEMODE::CKFILE_UNCOMPRESSED, "CKFILE_UNCOMPRESSED" }, @@ -115,7 +113,8 @@ namespace Unvirt { { LibCmo::CK2::CKERROR::CKERR_INVALIDANIMATION, {"CKERR_INVALIDANIMATION", "the animation is invalid (no entity associated or zero length)"} } }; - void GetCkErrorName(std::string& strl, LibCmo::CK2::CKERROR err) { + std::string GetCkErrorName(LibCmo::CK2::CKERROR err) { + std::string strl; const std::array* pErrDesc = GetEnumData>( _CkErrorData, err ); @@ -125,9 +124,11 @@ namespace Unvirt { } else { strl = c_InvalidEnumName; } + return strl; } - void GetCkErrorDescription(std::string& strl, LibCmo::CK2::CKERROR err) { + std::string GetCkErrorDescription( LibCmo::CK2::CKERROR err) { + std::string strl; const std::array* pErrDesc = GetEnumData>( _CkErrorData, err ); @@ -137,6 +138,7 @@ namespace Unvirt { } else { strl = c_InvalidEnumName; } + return strl; } static const std::vector>> _CkClassHierarchy{ @@ -209,7 +211,8 @@ namespace Unvirt { { LibCmo::CK2::CK_CLASSID::CKCID_MAXMAXCLASSID, {"CKCID_MAXMAXCLASSID"} } }; - void GetClassIdName(std::string& strl, LibCmo::CK2::CK_CLASSID cls) { + std::string GetClassIdName(LibCmo::CK2::CK_CLASSID cls) { + std::string strl; const std::vector* pHierarchy = GetEnumData>( _CkClassHierarchy, cls ); @@ -219,9 +222,11 @@ namespace Unvirt { } else { strl = c_InvalidEnumName; } + return strl; } - void GetClassIdHierarchy(std::string& strl, LibCmo::CK2::CK_CLASSID cls) { + std::string GetClassIdHierarchy(LibCmo::CK2::CK_CLASSID cls) { + std::string strl; const std::vector* pHierarchy = GetEnumData>( _CkClassHierarchy, cls ); @@ -235,38 +240,41 @@ namespace Unvirt { } else { strl = c_InvalidEnumName; } + + return strl; } #pragma endregion - void GetAccessibleFileSize(std::string& strl, uint64_t size) { + std::string GetAccessibleFileSize(uint64_t size) { + std::string strl; static double denominator = (double)0b1111111111; uint64_t probe = size; // check bytes if ((probe >> 10) == UINT64_C(0)) { StringHelper::StdstringPrintf(strl, "%" PRIu64 "Bytes", probe); - return; + return strl; } probe >>= 10; // check kb if ((probe >> 10) == UINT64_C(0)) { StringHelper::StdstringPrintf(strl, "%.2lfKiB", size / static_cast(UINT64_C(1) << 10)); - return; + return strl; } probe >>= 10; // check mb if ((probe >> 10) == UINT64_C(0)) { StringHelper::StdstringPrintf(strl, "%.2lfMiB", size / static_cast(UINT64_C(1) << 20)); - return; + return strl; } probe >>= 10; // otherwise gb StringHelper::StdstringPrintf(strl, "%.2lfGiB", size / static_cast(UINT64_C(1) << 30)); - return; + return strl; } diff --git a/Unvirt/AccessibleValue.hpp b/Unvirt/AccessibleValue.hpp index 8e1599b..cc5a1c4 100644 --- a/Unvirt/AccessibleValue.hpp +++ b/Unvirt/AccessibleValue.hpp @@ -8,7 +8,7 @@ namespace Unvirt { namespace AccessibleValue { - extern const char c_InvalidEnumName[]; + constexpr const char c_InvalidEnumName[] = "[undefined]"; #pragma region universal enum name @@ -23,23 +23,25 @@ namespace Unvirt { } template - void GetEnumName(const EnumDescPairArray& desc, std::string& strl, TEnum val) { + std::string GetEnumName(const EnumDescPairArray& desc, TEnum val) { + std::string strl; for (auto it = desc.begin(); it != desc.end(); ++it) { if ((*it).first == val) { strl = (*it).second; - return; + return strl; } } strl = c_InvalidEnumName; + return strl; } template - void GetFlagEnumName(const EnumDescPairArray& desc, std::string& strl, TEnum val) { - strl.clear(); + std::string GetFlagEnumName(const EnumDescPairArray& desc, TEnum val) { + std::string strl; for (auto it = desc.begin(); it != desc.end(); ++it) { // if it have exacelt same entry, return directly if ((*it).first == val) { strl = (*it).second; - return; + return strl; } // check flag match @@ -54,16 +56,17 @@ namespace Unvirt { // nothing was gotten. set to undefined strl = c_InvalidEnumName; } // otherwise return directly + return strl; } #pragma endregion - void GetClassIdName(std::string& strl, LibCmo::CK2::CK_CLASSID cls); - void GetCkErrorName(std::string& strl, LibCmo::CK2::CKERROR err); - void GetClassIdHierarchy(std::string& strl, LibCmo::CK2::CK_CLASSID cls); - void GetCkErrorDescription(std::string& strl, LibCmo::CK2::CKERROR err); + std::string GetClassIdName(LibCmo::CK2::CK_CLASSID cls); + std::string GetCkErrorName(LibCmo::CK2::CKERROR err); + std::string GetClassIdHierarchy(LibCmo::CK2::CK_CLASSID cls); + std::string GetCkErrorDescription(LibCmo::CK2::CKERROR err); - void GetAccessibleFileSize(std::string& strl, uint64_t size); + std::string GetAccessibleFileSize(uint64_t size); } } diff --git a/Unvirt/CmdHelper.cpp b/Unvirt/CmdHelper.cpp index 864a9c1..3f7ec79 100644 --- a/Unvirt/CmdHelper.cpp +++ b/Unvirt/CmdHelper.cpp @@ -1,5 +1,7 @@ #include "CmdHelper.hpp" #include "TerminalHelper.hpp" +#include "StructFormatter.hpp" +#include "AccessibleValue.hpp" #include #include @@ -8,6 +10,11 @@ #include #include +/* TODO: +do not re-allocated ctx and file for each loading in future. +this will be implemented by free all objects within doc. +*/ + namespace Unvirt::CmdHelper { #pragma region CmdSplitter @@ -76,7 +83,7 @@ namespace Unvirt::CmdHelper { #pragma region ArgParser - bool ArgParser::ParseInt(const std::vector& cmd, const size_t expected_index, int32_t& result) { + bool ArgParser::ParseInt(const std::deque& cmd, const size_t expected_index, int32_t& result) { if (expected_index >= cmd.size()) { result = 0; return false; @@ -95,7 +102,7 @@ namespace Unvirt::CmdHelper { return true; } - bool ArgParser::ParseString(const std::vector& cmd, const size_t expected_index, std::string& result) { + bool ArgParser::ParseString(const std::deque& cmd, const size_t expected_index, std::string& result) { if (expected_index >= cmd.size()) { result.clear(); return false; @@ -105,7 +112,7 @@ namespace Unvirt::CmdHelper { } } - bool ArgParser::ParseSwitch(const std::vector& cmd, const size_t expected_index, const std::vector& switches, std::string& gotten) { + bool ArgParser::ParseSwitch(const std::deque& cmd, const size_t expected_index, const std::vector& switches, std::string& gotten) { if (expected_index >= cmd.size()) { gotten.clear(); return false; @@ -127,21 +134,21 @@ namespace Unvirt::CmdHelper { #pragma region InteractiveCmd InteractiveCmd::InteractiveCmd() : - m_CmdSplitter(), m_ExitRunFlag(false), - m_Ctx(nullptr), m_Doc(nullptr) { + m_CmdSplitter(), m_PageLen(10), + m_Ctx(nullptr), m_File(nullptr), m_Doc(nullptr) { } InteractiveCmd::~InteractiveCmd() { if (m_Doc != nullptr) delete m_Doc; + if (m_File != nullptr) delete m_File; if (m_Ctx != nullptr) delete m_Ctx; } void InteractiveCmd::Run(void) { std::string u8cmd; - m_ExitRunFlag = false; - while (!m_ExitRunFlag) { + while (true) { // get command GetCmdLine(u8cmd); @@ -158,21 +165,23 @@ namespace Unvirt::CmdHelper { cmds.pop_front(); // dispatch command - bool success = true; - if (subcmd == "load") success = this->ProcLoad(cmds); - else if (subcmd == "unload") success = this->ProcUnLoad(cmds); - else if (subcmd == "info") success = this->ProcInfo(cmds); - else if (subcmd == "ls") success = this->ProcLs(cmds); + if (subcmd == "load") this->ProcLoad(cmds); + 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 == "help") this->PrintHelp(); + else if (subcmd == "exit") break; else { this->PrintCommonError("No such command \"\".", subcmd.c_str()); this->PrintHelp(); } - if (!success) this->PrintHelp(); } } void InteractiveCmd::GetCmdLine(std::string& u8cmd) { + fputs("Unvirt> ", stdout); #if defined(LIBCMO_OS_WIN32) std::wstring wcmd; std::getline(std::wcin, wcmd); @@ -183,12 +192,37 @@ namespace Unvirt::CmdHelper { } bool InteractiveCmd::HasOpenedFile(void) { - return (m_Ctx != nullptr || m_Doc != nullptr); + return (m_Ctx != nullptr || m_File == nullptr || m_Doc != nullptr); } void InteractiveCmd::PrintHelp(void) { FILE* f = stdout; fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Allowed Subcommands: \n")), f); + + fputs("load\n", f); + fputs("\tDescription: Load a Virtools composition.\n", f); + fputs("\tSyntax: load [encoding] [temp path]\n", f); + + fputs("unload\n", f); + fputs("\tDescription: Release loaded Virtools composition.\n", f); + fputs("\tSyntax: unload\n", f); + + fputs("info\n", f); + fputs("\tDescription: Show the header info of loaded Virtools composition.\n", f); + fputs("\tSyntax: info\n", f); + + fputs("ls\n", f); + fputs("\tDescription: List something about loaded Virtools composition.\n", f); + fputs("\tSyntax: ls [page]\n", f); + + fputs("page\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("exit\n", f); + fputs("\tDescription: Exit program\n", f); + fputs("\tSyntax: exit\n", f); + } void InteractiveCmd::PrintArgParseError(const std::deque& cmd, size_t pos) { @@ -216,23 +250,99 @@ namespace Unvirt::CmdHelper { #pragma region Command Processors - bool InteractiveCmd::ProcLoad(const std::deque& cmd) { + void InteractiveCmd::ProcLoad(const std::deque& cmd) { + // check pre-requirement + if (HasOpenedFile()) { + this->PrintCommonError("Already have a opened file. Close it before calling \"load\"."); + return; + } + + // check requirement + size_t pos = 0u; + std::string filepath; + if (!ArgParser::ParseString(cmd, pos, filepath)) { + this->PrintArgParseError(cmd, pos); + return; + } + ++pos; + std::string encoding; + if (!ArgParser::ParseString(cmd, pos, encoding)) { + this->PrintArgParseError(cmd, pos); + return; + } + ++pos; + std::string temppath; + if (!ArgParser::ParseString(cmd, pos, temppath)) { + this->PrintArgParseError(cmd, pos); + return; + } + + // proc + m_Ctx = new LibCmo::CK2::CKMinContext(); + m_Ctx->SetEncoding(encoding.c_str()); + m_Ctx->SetTempPath(temppath.c_str()); + + m_File = new LibCmo::CK2::CKFile(m_Ctx); + m_Doc = new LibCmo::CK2::CKFileDocument(); + LibCmo::CK2::CKERROR err = m_File->DeepLoad(filepath.c_str(), &m_Doc); + 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) + ); + + if (m_Doc != nullptr) delete m_Doc; + if (m_File != nullptr) delete m_File; + if (m_Ctx != nullptr) delete m_Ctx; + } } - bool InteractiveCmd::ProcUnLoad(const std::deque& cmd) { + void InteractiveCmd::ProcUnLoad(const std::deque& cmd) { + // check pre-requirement + if (!HasOpenedFile()) { + this->PrintCommonError("No loaded file."); + return; + } + + // free all + if (m_Doc != nullptr) delete m_Doc; + if (m_File != nullptr) delete m_File; + if (m_Ctx != nullptr) delete m_Ctx; } - bool InteractiveCmd::ProcInfo(const std::deque& cmd) { + void InteractiveCmd::ProcInfo(const std::deque& cmd) { + // check pre-requirement + if (!HasOpenedFile()) { + this->PrintCommonError("No loaded file."); + return; + } + + // print + Unvirt::StructFormatter::PrintCKFileInfo(m_Doc->m_FileInfo); } - bool InteractiveCmd::ProcLs(const std::deque& cmd) { - static const std::vector c_AllowedSwitches { + void InteractiveCmd::ProcLs(const std::deque& cmd) { + static const std::vector c_AllowedSwitches{ "obj", "mgr" }; } + void InteractiveCmd::ProcPage(const std::deque& cmd) { + // check requirement + size_t pos = 0u; + int32_t count; + if (!ArgParser::ParseInt(cmd, pos, count) || count <= 0) { + this->PrintArgParseError(cmd, pos); + return; + } + + // assign + m_PageLen = static_cast(count); + } + #pragma endregion diff --git a/Unvirt/CmdHelper.hpp b/Unvirt/CmdHelper.hpp index 17fb641..0fd0b1e 100644 --- a/Unvirt/CmdHelper.hpp +++ b/Unvirt/CmdHelper.hpp @@ -127,9 +127,9 @@ namespace Unvirt::CmdHelper { ArgParser& operator=(const ArgParser&) = delete; ~ArgParser() {} - static bool ParseInt(const std::vector& cmd, const size_t expected_index, int32_t& result); - static bool ParseString(const std::vector& cmd, const size_t expected_index, std::string& result); - static bool ParseSwitch(const std::vector& cmd, const size_t expected_index, const std::vector& switches, std::string& gotten); + static bool ParseInt(const std::deque& cmd, const size_t expected_index, int32_t& result); + static bool ParseString(const std::deque& cmd, const size_t expected_index, std::string& result); + static bool ParseSwitch(const std::deque& cmd, const size_t expected_index, const std::vector& switches, std::string& gotten); }; class InteractiveCmd { @@ -148,14 +148,16 @@ namespace Unvirt::CmdHelper { void PrintArgParseError(const std::deque& cmd, size_t pos); void PrintCommonError(const char* u8_fmt, ...); - bool ProcLoad(const std::deque& cmd); - bool ProcUnLoad(const std::deque& cmd); - bool ProcInfo(const std::deque& cmd); - bool ProcLs(const std::deque& cmd); + void ProcLoad(const std::deque& cmd); + void ProcUnLoad(const std::deque& cmd); + void ProcInfo(const std::deque& cmd); + void ProcLs(const std::deque& cmd); + void ProcPage(const std::deque& cmd); - bool m_ExitRunFlag; CmdSplitter m_CmdSplitter; + size_t m_PageLen; LibCmo::CK2::CKMinContext* m_Ctx; + LibCmo::CK2::CKFile* m_File; LibCmo::CK2::CKFileDocument* m_Doc; }; diff --git a/Unvirt/StructFormatter.cpp b/Unvirt/StructFormatter.cpp index 06da5d7..61be984 100644 --- a/Unvirt/StructFormatter.cpp +++ b/Unvirt/StructFormatter.cpp @@ -8,7 +8,6 @@ namespace Unvirt { static FILE* fout = stdout; void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo) { - std::string container; fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileInfo\n")), fout); fprintf(fout, "FileVersion: %" PRIu32 "\n", fileinfo.FileVersion); @@ -28,29 +27,23 @@ namespace Unvirt { fileinfo.ProductVersion, product_series[0], product_series[1], product_series[2], product_series[3] ); - Unvirt::AccessibleValue::GetFlagEnumName( - Unvirt::AccessibleValue::EnumDesc::CK_FILE_WRITEMODE, container, fileinfo.FileWriteMode - ); - fprintf(fout, "Save Flags: %s\n", container.c_str()); + fprintf(fout, "Save Flags: %s\n", Unvirt::AccessibleValue::GetFlagEnumName( + Unvirt::AccessibleValue::EnumDesc::CK_FILE_WRITEMODE, fileinfo.FileWriteMode + ).c_str()); - Unvirt::AccessibleValue::GetAccessibleFileSize(container, fileinfo.FileSize); - fprintf(fout, "File Size: %s\n", container.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); fputs("Hdr1 (Pack / UnPack): ", fout); - Unvirt::AccessibleValue::GetAccessibleFileSize(container, fileinfo.Hdr1PackSize); - fprintf(fout, "%s / ", container.c_str()); - Unvirt::AccessibleValue::GetAccessibleFileSize(container, fileinfo.Hdr1UnPackSize); - fprintf(fout, "%s\n", container.c_str()); + 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); - Unvirt::AccessibleValue::GetAccessibleFileSize(container, fileinfo.DataPackSize); - fprintf(fout, "%s / ", container.c_str()); - Unvirt::AccessibleValue::GetAccessibleFileSize(container, fileinfo.DataUnPackSize); - fprintf(fout, "%s\n", container.c_str()); + fprintf(fout, "%s / ", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.DataPackSize).c_str()); + fprintf(fout, "%s\n", Unvirt::AccessibleValue::GetAccessibleFileSize(fileinfo.DataUnPackSize).c_str()); fputc('\n', fout);