2023-08-27 12:30:12 +08:00
|
|
|
#include "UnvirtContext.hpp"
|
2023-09-12 17:03:06 +08:00
|
|
|
#include <CK2/MgrImpls/CKPathManager.hpp>
|
2023-08-31 12:37:23 +08:00
|
|
|
#include <cstdarg>
|
2023-10-28 18:17:53 +08:00
|
|
|
#include <regex>
|
2023-08-27 12:30:12 +08:00
|
|
|
|
|
|
|
namespace Unvirt::Context {
|
|
|
|
|
|
|
|
#pragma region UnvirtContext Misc
|
|
|
|
|
|
|
|
UnvirtContext::UnvirtContext() :
|
|
|
|
m_Root(), m_Splitter(), m_Help(nullptr),
|
2023-10-28 18:17:53 +08:00
|
|
|
m_PageLen(10u), m_ListStyleIsFull(true), m_OrderExit(false),
|
|
|
|
m_SearchPart(SearchPart::None), m_SearchIdxResult(),
|
2023-09-30 14:24:37 +08:00
|
|
|
m_Ctx(nullptr), m_FileReader(nullptr), m_IsShallowRead(true) {
|
2023-08-27 12:30:12 +08:00
|
|
|
|
|
|
|
// create command root
|
|
|
|
CmdHelper::CommandRoot* root = &m_Root;
|
2023-08-27 14:21:44 +08:00
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
root
|
|
|
|
->Then((new CmdHelper::Literal("load"))
|
|
|
|
->Then((new CmdHelper::Choice("stage", { "deep", "shallow"}))
|
|
|
|
->Comment("The stage of loading. 'deep' will load to CKObject stage. 'shallow' will load to CKStateChunk stage.")
|
|
|
|
->Then((new CmdHelper::StringArgument("filepath"))
|
|
|
|
->Comment("The path to loading file.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcLoad, this, std::placeholders::_1),
|
2023-09-12 17:03:06 +08:00
|
|
|
"Load a Virtools composition."
|
2023-08-27 16:45:07 +08:00
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
->Then((new CmdHelper::Literal("unload"))
|
2023-08-27 14:21:44 +08:00
|
|
|
->Executes(
|
2023-08-27 16:45:07 +08:00
|
|
|
std::bind(&UnvirtContext::ProcUnLoad, this, std::placeholders::_1),
|
|
|
|
"Release loaded Virtools composition."
|
|
|
|
)
|
2023-08-27 12:30:12 +08:00
|
|
|
)
|
2023-08-28 22:20:46 +08:00
|
|
|
->Then((new CmdHelper::Literal("save"))
|
|
|
|
->Then((new CmdHelper::StringArgument("filepath"))
|
|
|
|
->Comment("The path to save file.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcSave, this, std::placeholders::_1),
|
|
|
|
"Save the loaded file into a new file."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 16:45:07 +08:00
|
|
|
->Then((new CmdHelper::Literal("info"))
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcInfo, this, std::placeholders::_1),
|
|
|
|
"Show the header info of loaded Virtools composition."
|
|
|
|
)
|
2023-08-27 12:30:12 +08:00
|
|
|
)
|
2023-08-27 16:45:07 +08:00
|
|
|
->Then((new CmdHelper::Literal("ls"))
|
2023-10-28 18:17:53 +08:00
|
|
|
->Then((new CmdHelper::Choice("part", { "obj", "mgr", "search"}))
|
2023-08-27 16:45:07 +08:00
|
|
|
->Comment("Which list you want to list.")
|
|
|
|
->Then((new CmdHelper::IntArgument("page", [](int32_t v) -> bool { return v > 0; }))
|
|
|
|
->Comment("The page index. Start with 1.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcLs, this, std::placeholders::_1),
|
|
|
|
"List something about loaded Virtools composition."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 12:30:12 +08:00
|
|
|
)
|
2023-08-27 16:45:07 +08:00
|
|
|
->Then((new CmdHelper::Literal("data"))
|
|
|
|
->Then((new CmdHelper::Choice("part", { "obj", "mgr"}))
|
|
|
|
->Comment("Which list you want to show data.")
|
|
|
|
->Then((new CmdHelper::IntArgument("index", [](int32_t v) -> bool { return v >= 0; }))
|
|
|
|
->Comment("The index. Start with 0.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcData, this, std::placeholders::_1),
|
|
|
|
"Show the specific CKObject / CKBaseManager data."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 12:30:12 +08:00
|
|
|
)
|
2023-08-27 16:45:07 +08:00
|
|
|
->Then((new CmdHelper::Literal("chunk"))
|
|
|
|
->Then((new CmdHelper::Choice("part", { "obj", "mgr"}))
|
|
|
|
->Comment("Which list you want to show chunk.")
|
|
|
|
->Then((new CmdHelper::IntArgument("index", [](int32_t v) -> bool { return v >= 0; }))
|
|
|
|
->Comment("The index. Start with 0.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcChunk, this, std::placeholders::_1),
|
|
|
|
"Show the specific CKStateChunk data."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 12:30:12 +08:00
|
|
|
)
|
2023-10-28 18:17:53 +08:00
|
|
|
->Then((new CmdHelper::Literal("search"))
|
|
|
|
->Then((new CmdHelper::Choice("part", { "obj", "mgr"}))
|
|
|
|
->Comment("Which list you want to search.")
|
|
|
|
->Then((new CmdHelper::Choice("mode", { "plain", "re"}))
|
|
|
|
->Comment("The search mode. `plain` will search by substring and `re` will do regex search.")
|
|
|
|
->Then((new CmdHelper::StringArgument("text"))
|
|
|
|
->Comment("The text or regex to search.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcSearch, this, std::placeholders::_1),
|
|
|
|
"Search object or manager by text or regex. Please note that the regex have limited UTF8 support and may cause undefined behavior."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 16:45:07 +08:00
|
|
|
->Then((new CmdHelper::Literal("items"))
|
|
|
|
->Then((new CmdHelper::IntArgument("count", [](int32_t v) -> bool { return v > 0; }))
|
|
|
|
->Comment("The count of items you want to show in one page.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcItems, this, std::placeholders::_1),
|
|
|
|
"Set up how many items should be listed in one page when using 'ls' command."
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 12:30:12 +08:00
|
|
|
)
|
2023-10-28 18:17:53 +08:00
|
|
|
->Then((new CmdHelper::Literal("style"))
|
|
|
|
->Then((new CmdHelper::Choice("level", { "full", "simple"}))
|
|
|
|
->Comment("The amount of showen content.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcStyle, this, std::placeholders::_1),
|
|
|
|
"Change the detail level of showen data in `ls` command."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 16:45:07 +08:00
|
|
|
->Then((new CmdHelper::Literal("encoding"))
|
|
|
|
->Then((new CmdHelper::EncodingArgument("enc"))
|
|
|
|
->Comment("CKContext used encoding splitted by ','. Support mutiple encoding.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcEncoding, this, std::placeholders::_1),
|
|
|
|
"Set the encoding series for CKContext."
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 14:21:44 +08:00
|
|
|
)
|
2023-08-27 16:45:07 +08:00
|
|
|
->Then((new CmdHelper::Literal("temp"))
|
|
|
|
->Then((new CmdHelper::StringArgument("temppath"))
|
|
|
|
->Comment("The path to Temp folder.")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcTemp, this, std::placeholders::_1),
|
|
|
|
"Set the Temp path for CKContext."
|
2023-08-27 14:21:44 +08:00
|
|
|
)
|
2023-08-27 16:45:07 +08:00
|
|
|
)
|
|
|
|
)
|
2023-09-12 17:03:06 +08:00
|
|
|
->Then((new CmdHelper::Literal("rsc"))
|
|
|
|
->Then((new CmdHelper::Literal("clear"))
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcRsc, this, std::placeholders::_1, true),
|
|
|
|
"Clear all data resources paths."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
->Then((new CmdHelper::Literal("add"))
|
|
|
|
->Then((new CmdHelper::StringArgument("datares"))
|
|
|
|
->Comment("The data resources path .")
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcRsc, this, std::placeholders::_1, false),
|
|
|
|
"Add a path to let Virtools find resources."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2023-09-20 20:44:03 +08:00
|
|
|
->Then((new CmdHelper::Literal("test"))
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcTest, this, std::placeholders::_1),
|
|
|
|
"Call custom debugging function (only available in Debug mode)."
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 22:14:02 +08:00
|
|
|
->Then((new CmdHelper::Literal("help"))
|
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcHelp, this, std::placeholders::_1),
|
|
|
|
"Output this help page."
|
|
|
|
)
|
|
|
|
)
|
2023-08-27 16:51:18 +08:00
|
|
|
->Then((new CmdHelper::Literal("exit"))
|
2023-08-27 16:45:07 +08:00
|
|
|
->Executes(
|
|
|
|
std::bind(&UnvirtContext::ProcExit, this, std::placeholders::_1),
|
|
|
|
"Exit program."
|
|
|
|
)
|
|
|
|
);
|
2023-08-27 14:21:44 +08:00
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
// create help
|
|
|
|
m_Help = root->RootHelp();
|
|
|
|
|
|
|
|
// create context
|
2023-09-01 12:19:06 +08:00
|
|
|
LibCmo::CK2::CKStartUp();
|
2023-08-27 16:45:07 +08:00
|
|
|
m_Ctx = new LibCmo::CK2::CKContext();
|
|
|
|
m_Ctx->SetOutputCallback(std::bind(&UnvirtContext::PrintContextMsg, this, std::placeholders::_1));
|
2023-10-02 17:45:59 +08:00
|
|
|
m_Ctx->SetGlobalImagesSaveOptions(LibCmo::CK2::CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_EXTERNAL);
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
UnvirtContext::~UnvirtContext() {
|
|
|
|
if (m_Help != nullptr)
|
|
|
|
delete m_Help;
|
2023-09-01 12:19:06 +08:00
|
|
|
|
|
|
|
// free context
|
|
|
|
ClearDocument();
|
|
|
|
delete m_Ctx;
|
|
|
|
LibCmo::CK2::CKShutdown();
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool UnvirtContext::HasOpenedFile() {
|
|
|
|
return m_FileReader != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnvirtContext::ClearDocument() {
|
|
|
|
if (m_FileReader == nullptr) return;
|
2023-10-28 18:17:53 +08:00
|
|
|
// clear search result
|
|
|
|
m_SearchPart = SearchPart::None;
|
|
|
|
m_SearchIdxResult.clear();
|
2023-08-27 22:14:02 +08:00
|
|
|
// delete reader
|
2023-08-27 12:30:12 +08:00
|
|
|
delete m_FileReader;
|
|
|
|
m_FileReader = nullptr;
|
2023-09-30 14:24:37 +08:00
|
|
|
m_IsShallowRead = true;
|
2023-08-27 22:14:02 +08:00
|
|
|
// clear context
|
2023-09-12 17:03:06 +08:00
|
|
|
m_Ctx->ClearAll();
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
2023-09-17 10:38:46 +08:00
|
|
|
void UnvirtContext::PrintContextMsg(LibCmo::CKSTRING msg) {
|
2023-08-27 12:30:12 +08:00
|
|
|
if (msg != nullptr) {
|
2023-08-27 22:14:02 +08:00
|
|
|
fprintf(stdout, UNVIRT_TERMCOL_LIGHT_YELLOW(("[CKContext] ")) "%s\n", msg);
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
}
|
2023-10-28 18:17:53 +08:00
|
|
|
|
|
|
|
void UnvirtContext::PrintCommonInfo(const char* u8_fmt, ...) {
|
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, u8_fmt);
|
|
|
|
std::vfprintf(stdout, u8_fmt, argptr);
|
|
|
|
va_end(argptr);
|
|
|
|
std::fputc('\n', stdout);
|
|
|
|
}
|
2023-08-27 12:30:12 +08:00
|
|
|
|
|
|
|
void UnvirtContext::PrintCommonError(const char* u8_fmt, ...) {
|
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, u8_fmt);
|
2023-08-27 22:14:02 +08:00
|
|
|
std::fputs(UNVIRT_TERMCOLHDR_LIGHT_RED, stdout);
|
|
|
|
std::vfprintf(stdout, u8_fmt, argptr);
|
|
|
|
std::fputs(UNVIRT_TERMCOLTAIL, stdout);
|
2023-08-27 12:30:12 +08:00
|
|
|
va_end(argptr);
|
2023-08-27 22:14:02 +08:00
|
|
|
std::fputc('\n', stdout);
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Main Run
|
|
|
|
|
|
|
|
void UnvirtContext::Run() {
|
|
|
|
Unvirt::TerminalHelper::EnsureTerminalColor();
|
|
|
|
Unvirt::TerminalHelper::EnsureTerminalEncoding();
|
|
|
|
std::string u8cmd;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
// get command
|
|
|
|
TerminalHelper::GetCmdLine(u8cmd);
|
|
|
|
|
|
|
|
// split cmd and parse it
|
|
|
|
auto cmds = m_Splitter.Convert(u8cmd);
|
2023-09-20 15:25:43 +08:00
|
|
|
if (cmds.empty()) continue;
|
2023-08-27 12:30:12 +08:00
|
|
|
|
|
|
|
// get sub command
|
|
|
|
if (!m_Root.RootConsume(cmds)) {
|
2023-08-27 22:14:02 +08:00
|
|
|
this->PrintCommonError("Syntax error \"%s\".\nType 'help' for usage.", u8cmd.c_str());
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_OrderExit) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Proc Detail
|
|
|
|
|
2023-08-27 14:21:44 +08:00
|
|
|
void UnvirtContext::ProcLoad(const CmdHelper::ArgumentsMap* amap) {
|
2023-08-27 12:30:12 +08:00
|
|
|
// check pre-requirement
|
|
|
|
if (HasOpenedFile()) {
|
2023-08-27 22:14:02 +08:00
|
|
|
PrintCommonError("Already have a opened file. Close it before calling 'load'.");
|
2023-08-27 12:30:12 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-27 14:21:44 +08:00
|
|
|
std::string filepath = *amap->Get<CmdHelper::StringArgument::vType>("filepath");
|
|
|
|
bool is_deep = *amap->Get<CmdHelper::Choice::vType>("stage") == 0;
|
2023-08-27 12:30:12 +08:00
|
|
|
|
|
|
|
// proc
|
|
|
|
m_FileReader = new LibCmo::CK2::CKFileReader(m_Ctx);
|
|
|
|
LibCmo::CK2::CKERROR err;
|
|
|
|
if (is_deep) {
|
|
|
|
err = m_FileReader->DeepLoad(filepath.c_str());
|
2023-09-30 14:24:37 +08:00
|
|
|
m_IsShallowRead = false;
|
2023-08-27 12:30:12 +08:00
|
|
|
} else {
|
|
|
|
err = m_FileReader->ShallowLoad(filepath.c_str());
|
2023-09-30 14:24:37 +08:00
|
|
|
m_IsShallowRead = true;
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
if (err != LibCmo::CK2::CKERROR::CKERR_OK) {
|
|
|
|
// fail to load. release all.
|
2023-08-28 22:20:46 +08:00
|
|
|
PrintCommonError("Fail to load file. Function return: %s\n\t%s",
|
2023-08-27 12:30:12 +08:00
|
|
|
Unvirt::AccessibleValue::GetCkErrorName(err).c_str(),
|
|
|
|
Unvirt::AccessibleValue::GetCkErrorDescription(err).c_str()
|
|
|
|
);
|
|
|
|
|
|
|
|
ClearDocument();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
void UnvirtContext::ProcUnLoad(const CmdHelper::ArgumentsMap*) {
|
2023-08-27 12:30:12 +08:00
|
|
|
// check pre-requirement
|
|
|
|
if (!HasOpenedFile()) {
|
|
|
|
this->PrintCommonError("No loaded file.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// free all
|
|
|
|
ClearDocument();
|
|
|
|
}
|
|
|
|
|
2023-08-28 22:20:46 +08:00
|
|
|
void Unvirt::Context::UnvirtContext::ProcSave(const CmdHelper::ArgumentsMap* amap) {
|
|
|
|
// check pre-requirement
|
|
|
|
if (!HasOpenedFile()) {
|
|
|
|
PrintCommonError("No loaded file.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string filepath = *amap->Get<CmdHelper::StringArgument::vType>("filepath");
|
|
|
|
|
|
|
|
// construct writer from reader
|
2023-09-30 14:24:37 +08:00
|
|
|
LibCmo::CK2::CKFileWriter writer(m_Ctx, m_FileReader, m_IsShallowRead);
|
2023-08-28 22:20:46 +08:00
|
|
|
|
|
|
|
// backup current file write mode
|
|
|
|
// and replace it with reader
|
|
|
|
LibCmo::CK2::CK_FILE_WRITEMODE backup = m_Ctx->GetFileWriteMode();
|
|
|
|
m_Ctx->SetFileWriteMode(m_FileReader->GetFileInfo().FileWriteMode);
|
|
|
|
|
|
|
|
// run writer
|
|
|
|
LibCmo::CK2::CKERROR err = writer.Save(filepath.c_str());
|
|
|
|
if (err != LibCmo::CK2::CKERROR::CKERR_OK) {
|
|
|
|
// fail to load. release all.
|
|
|
|
PrintCommonError("Fail to save file. Function return: %s\n\t%s",
|
|
|
|
Unvirt::AccessibleValue::GetCkErrorName(err).c_str(),
|
|
|
|
Unvirt::AccessibleValue::GetCkErrorDescription(err).c_str()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// restore file write mode
|
|
|
|
m_Ctx->SetFileWriteMode(backup);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
void UnvirtContext::ProcInfo(const CmdHelper::ArgumentsMap*) {
|
2023-08-27 12:30:12 +08:00
|
|
|
// check pre-requirement
|
|
|
|
if (!HasOpenedFile()) {
|
|
|
|
PrintCommonError("No loaded file.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// print
|
|
|
|
Unvirt::StructFormatter::PrintCKFileInfo(m_FileReader->GetFileInfo());
|
|
|
|
}
|
|
|
|
|
2023-08-27 14:21:44 +08:00
|
|
|
void UnvirtContext::ProcLs(const CmdHelper::ArgumentsMap* amap) {
|
2023-08-27 12:30:12 +08:00
|
|
|
// check pre-requirement
|
|
|
|
if (!HasOpenedFile()) {
|
2023-08-27 22:14:02 +08:00
|
|
|
PrintCommonError("No loaded file.");
|
2023-08-27 12:30:12 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-28 18:17:53 +08:00
|
|
|
// get 0 based page (-1)
|
2023-08-27 16:45:07 +08:00
|
|
|
size_t page = *amap->Get<CmdHelper::IntArgument::vType>("page") - 1;
|
2023-08-27 12:30:12 +08:00
|
|
|
|
|
|
|
// show list
|
2023-08-27 16:45:07 +08:00
|
|
|
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
|
|
|
|
case 0:
|
2023-08-27 12:30:12 +08:00
|
|
|
{
|
|
|
|
// obj list
|
2023-10-28 18:17:53 +08:00
|
|
|
Unvirt::StructFormatter::PrintObjectList(
|
|
|
|
m_FileReader->GetFileObjects(),
|
|
|
|
m_FileReader->GetFileInfo(),
|
|
|
|
page, this->m_PageLen,
|
|
|
|
m_ListStyleIsFull
|
|
|
|
);
|
2023-08-27 12:30:12 +08:00
|
|
|
break;
|
|
|
|
}
|
2023-08-27 16:45:07 +08:00
|
|
|
case 1:
|
2023-08-27 12:30:12 +08:00
|
|
|
{
|
|
|
|
// mgr list
|
2023-10-28 18:17:53 +08:00
|
|
|
Unvirt::StructFormatter::PrintManagerList(
|
|
|
|
m_FileReader->GetManagersData(),
|
|
|
|
page, this->m_PageLen,
|
|
|
|
m_ListStyleIsFull
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
// search list
|
|
|
|
switch (m_SearchPart) {
|
|
|
|
case SearchPart::None:
|
|
|
|
{
|
|
|
|
PrintCommonError("No search result to list.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SearchPart::Object:
|
|
|
|
{
|
|
|
|
Unvirt::StructFormatter::PrintSearchedObjectList(
|
|
|
|
m_SearchIdxResult,
|
|
|
|
m_FileReader->GetFileObjects(),
|
|
|
|
m_FileReader->GetFileInfo(),
|
|
|
|
page, this->m_PageLen,
|
|
|
|
m_ListStyleIsFull
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SearchPart::Manager:
|
|
|
|
{
|
|
|
|
Unvirt::StructFormatter::PrintSearchedManagerList(
|
|
|
|
m_SearchIdxResult,
|
|
|
|
m_FileReader->GetManagersData(),
|
|
|
|
page, this->m_PageLen,
|
|
|
|
m_ListStyleIsFull
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-27 14:21:44 +08:00
|
|
|
void UnvirtContext::ProcData( const CmdHelper::ArgumentsMap* amap) {
|
2023-08-27 16:45:07 +08:00
|
|
|
// check pre-requirement
|
|
|
|
if (!HasOpenedFile()) {
|
2023-08-27 22:14:02 +08:00
|
|
|
PrintCommonError("No loaded file.");
|
2023-08-27 16:45:07 +08:00
|
|
|
return;
|
|
|
|
}
|
2023-08-27 12:30:12 +08:00
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
// get index
|
|
|
|
size_t index = *amap->Get<CmdHelper::IntArgument::vType>("index");
|
|
|
|
|
|
|
|
// show data
|
|
|
|
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
if (index >= m_FileReader->GetFileObjects().size()) {
|
|
|
|
PrintCommonError("Index out of range.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Unvirt::StructFormatter::PrintCKObject(m_FileReader->GetFileObjects()[index].ObjPtr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
if (index >= m_FileReader->GetManagersData().size()) {
|
|
|
|
PrintCommonError("Index out of range.");
|
|
|
|
return;
|
|
|
|
}
|
2023-10-28 18:17:53 +08:00
|
|
|
// todo: finish manager display
|
|
|
|
PrintCommonError("Not supported now.");
|
2023-08-27 16:45:07 +08:00
|
|
|
//Unvirt::StructFormatter::PrintCKBaseManager(m_FileReader->GetManagersData()[index].Data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
2023-08-27 14:21:44 +08:00
|
|
|
void UnvirtContext::ProcChunk(const CmdHelper::ArgumentsMap* amap) {
|
2023-08-27 16:45:07 +08:00
|
|
|
// check pre-requirement
|
|
|
|
if (!HasOpenedFile()) {
|
2023-08-27 22:14:02 +08:00
|
|
|
PrintCommonError("No loaded file.");
|
2023-08-27 16:45:07 +08:00
|
|
|
return;
|
|
|
|
}
|
2023-08-27 12:30:12 +08:00
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
// get index
|
|
|
|
size_t index = *amap->Get<CmdHelper::IntArgument::vType>("index");
|
2023-08-27 12:30:12 +08:00
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
// show data
|
|
|
|
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
if (index >= m_FileReader->GetFileObjects().size()) {
|
|
|
|
PrintCommonError("Index out of range.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Unvirt::StructFormatter::PrintCKStateChunk(m_FileReader->GetFileObjects()[index].Data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
if (index >= m_FileReader->GetManagersData().size()) {
|
|
|
|
PrintCommonError("Index out of range.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Unvirt::StructFormatter::PrintCKStateChunk(m_FileReader->GetManagersData()[index].Data);
|
|
|
|
break;
|
|
|
|
}
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
2023-08-27 16:45:07 +08:00
|
|
|
}
|
2023-08-27 12:30:12 +08:00
|
|
|
|
2023-10-28 18:17:53 +08:00
|
|
|
void UnvirtContext::ProcSearch(const CmdHelper::ArgumentsMap* amap) {
|
|
|
|
// check pre-requirement
|
|
|
|
if (!HasOpenedFile()) {
|
|
|
|
PrintCommonError("No loaded file.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get search text
|
|
|
|
std::string search_text(*amap->Get<CmdHelper::StringArgument::vType>("text"));
|
|
|
|
|
|
|
|
// analyse search mode
|
|
|
|
std::function<bool(const LibCmo::XContainer::XString&)> search_fct = [](const LibCmo::XContainer::XString&) -> bool { return false; };
|
|
|
|
switch (*amap->Get<CmdHelper::Choice::vType>("mode")) {
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
// plain mode
|
|
|
|
search_fct = [&search_text](const LibCmo::XContainer::XString& cmp) -> bool {
|
|
|
|
return cmp.find(search_text) != std::string::npos;
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
// regex mode
|
|
|
|
|
|
|
|
// try construct regex
|
|
|
|
std::regex re;
|
|
|
|
try {
|
|
|
|
re = std::regex(search_text, std::regex_constants::ECMAScript);
|
|
|
|
} catch (const std::regex_error& e) {
|
|
|
|
PrintCommonError("Invalid regular expressions: %s", e.what());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// use copy ctor capture to input regex
|
|
|
|
// because re will be freed when exiting this switch.
|
|
|
|
search_fct = [re](const LibCmo::XContainer::XString& cmp) -> bool {
|
|
|
|
return std::regex_search(cmp, re);
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// start search
|
|
|
|
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
// object
|
|
|
|
m_SearchPart = SearchPart::Object;
|
|
|
|
m_SearchIdxResult.clear();
|
|
|
|
|
|
|
|
size_t counter = 0;
|
|
|
|
for (const auto& obj : m_FileReader->GetFileObjects()) {
|
|
|
|
if (search_fct(obj.Name)) {
|
|
|
|
m_SearchIdxResult.emplace_back(counter);
|
|
|
|
}
|
|
|
|
++counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
// manager
|
|
|
|
m_SearchPart = SearchPart::Manager;
|
|
|
|
m_SearchIdxResult.clear();
|
|
|
|
PrintCommonError("Not supported now.");
|
|
|
|
// todo: remove this return when fixing manager searching.
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// report search result
|
|
|
|
if (m_SearchIdxResult.empty()) {
|
|
|
|
PrintCommonInfo("Search done, but no result.");
|
|
|
|
} else {
|
|
|
|
PrintCommonInfo("Search done with %" PRIuSIZET " results. Use `ls search` to check them.", m_SearchIdxResult.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
void UnvirtContext::ProcItems(const CmdHelper::ArgumentsMap* amap) {
|
2023-08-27 12:30:12 +08:00
|
|
|
// assign
|
2023-08-27 16:45:07 +08:00
|
|
|
m_PageLen = *amap->Get<CmdHelper::IntArgument::vType>("count");
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
2023-10-28 18:17:53 +08:00
|
|
|
void UnvirtContext::ProcStyle(const CmdHelper::ArgumentsMap* amap) {
|
|
|
|
// set list style level
|
|
|
|
switch (*amap->Get<CmdHelper::Choice::vType>("level")) {
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
// full level
|
|
|
|
m_ListStyleIsFull = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
// simple level
|
|
|
|
m_ListStyleIsFull = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-27 14:21:44 +08:00
|
|
|
void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap* amap) {
|
2023-08-27 16:45:07 +08:00
|
|
|
const auto& encodings = *amap->Get<CmdHelper::EncodingArgument::vType>("enc");
|
|
|
|
m_Ctx->SetEncoding(encodings);
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
2023-08-27 14:21:44 +08:00
|
|
|
void UnvirtContext::ProcTemp(const CmdHelper::ArgumentsMap* amap) {
|
2023-08-27 12:30:12 +08:00
|
|
|
// assign
|
2023-09-12 17:03:06 +08:00
|
|
|
if (!m_Ctx->GetPathManager()->SetTempFolder(amap->Get<CmdHelper::StringArgument::vType>("temppath")->c_str())) {
|
|
|
|
PrintCommonError("Set temp folder failed. Check your path first.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Unvirt::Context::UnvirtContext::ProcRsc(const CmdHelper::ArgumentsMap* amap, bool isClear) {
|
|
|
|
if (isClear) {
|
|
|
|
m_Ctx->GetPathManager()->ClearPath();
|
|
|
|
} else {
|
|
|
|
if (!m_Ctx->GetPathManager()->AddPath(amap->Get<CmdHelper::StringArgument::vType>("datares")->c_str())) {
|
|
|
|
PrintCommonError("Set data resource folder failed. Check your path first.");
|
|
|
|
}
|
|
|
|
}
|
2023-08-27 12:30:12 +08:00
|
|
|
}
|
|
|
|
|
2023-09-20 20:44:03 +08:00
|
|
|
void Unvirt::Context::UnvirtContext::ProcTest(const CmdHelper::ArgumentsMap* amap) {
|
|
|
|
#if defined(LIBCMO_BUILD_DEBUG)
|
|
|
|
// MARK: Add the debug code here.
|
2023-10-29 10:27:35 +08:00
|
|
|
|
|
|
|
// todo: temporaryly write Transparent Column Fixer code.
|
|
|
|
// move to independent app in future.
|
|
|
|
|
|
|
|
// check pre-requirement
|
|
|
|
if (!HasOpenedFile()) {
|
|
|
|
PrintCommonError("No loaded file.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!m_IsShallowRead) {
|
|
|
|
PrintCommonError("Transparent Column Fixer only accept shallow loaded file.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// iterate objects
|
|
|
|
LibCmo::CKDWORD expcode = static_cast<LibCmo::CKDWORD>(LibCmo::CK2::CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXONLY);
|
|
|
|
LibCmo::CKDWORD modcode = static_cast<LibCmo::CKDWORD>(LibCmo::CK2::CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_OLDTEXONLY);
|
|
|
|
for (const auto& cobj : m_FileReader->GetFileObjects()) {
|
|
|
|
if (cobj.ObjectCid == LibCmo::CK2::CK_CLASSID::CKCID_TEXTURE && cobj.Data != nullptr) {
|
|
|
|
LibCmo::CK2::CKFileObject& obj = const_cast<LibCmo::CK2::CKFileObject&>(cobj);
|
|
|
|
obj.Data->StartRead();
|
|
|
|
auto chunkinfo = obj.Data->GetIdentifiersProfile();
|
|
|
|
obj.Data->StopRead();
|
|
|
|
|
|
|
|
// find CK_STATESAVE_TEXONLY and change it to CK_STATESAVE_OLDTEXONLY
|
|
|
|
for (const auto& entry : chunkinfo) {
|
|
|
|
if (entry.m_Identifier == expcode) {
|
|
|
|
LibCmo::CKDWORD* p = static_cast<LibCmo::CKDWORD*>(entry.m_DataPtr);
|
|
|
|
p -= 2;
|
|
|
|
|
|
|
|
if (*p == expcode) {
|
|
|
|
*p = modcode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-20 20:44:03 +08:00
|
|
|
|
|
|
|
#else
|
|
|
|
PrintCommonError("Test command only available in Debug mode.");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-08-28 22:20:46 +08:00
|
|
|
void Unvirt::Context::UnvirtContext::ProcHelp(const CmdHelper::ArgumentsMap*) {
|
2023-08-27 22:14:02 +08:00
|
|
|
m_Help->Print();
|
|
|
|
}
|
|
|
|
|
2023-08-27 16:45:07 +08:00
|
|
|
void UnvirtContext::ProcExit(const CmdHelper::ArgumentsMap*) {
|
2023-08-27 12:30:12 +08:00
|
|
|
m_OrderExit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
}
|