299 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			299 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | #include "UnvirtContext.hpp"
 | ||
|  | 
 | ||
|  | namespace Unvirt::Context { | ||
|  | 
 | ||
|  | 	static FILE* fout = stdout; | ||
|  | 
 | ||
|  | #pragma region Encoding Arg
 | ||
|  | 
 | ||
|  | 	// Copy from Gamepiaynmo/BallanceModLoader
 | ||
|  | 	std::vector<std::string> SplitString(const std::string& str, const std::string& de) { | ||
|  | 		size_t lpos, pos = 0; | ||
|  | 		std::vector<std::string> res; | ||
|  | 
 | ||
|  | 		lpos = str.find_first_not_of(de, pos); | ||
|  | 		while (lpos != std::string::npos) { | ||
|  | 			pos = str.find_first_of(de, lpos); | ||
|  | 			res.push_back(str.substr(lpos, pos - lpos)); | ||
|  | 			if (pos == std::string::npos) break; | ||
|  | 
 | ||
|  | 			lpos = str.find_first_not_of(de, pos); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (pos != std::string::npos) | ||
|  | 			res.push_back(""); | ||
|  | 
 | ||
|  | 		return res; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	bool EncodingArgument::BeginParse(const std::string& strl) { | ||
|  | 		// encoding always accept every text
 | ||
|  | 		m_ParsedData = new std::vector<std::string>(SplitString(strl, ",")); | ||
|  | 		return true; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void EncodingArgument::EndParse() { | ||
|  | 		delete reinterpret_cast<std::vector<std::string>*>(m_ParsedData); | ||
|  | 		m_ParsedData = nullptr; | ||
|  | 	} | ||
|  | 
 | ||
|  | #pragma endregion
 | ||
|  | 
 | ||
|  | #pragma region UnvirtContext Misc
 | ||
|  | 
 | ||
|  | 	UnvirtContext::UnvirtContext() : | ||
|  | 		m_Root(), m_Splitter(), m_Help(nullptr), | ||
|  | 		m_PageLen(10u), m_Ctx(nullptr), m_FileReader(nullptr) { | ||
|  | 
 | ||
|  | 		// create command root
 | ||
|  | 		CmdHelper::CommandRoot* root = &m_Root; | ||
|  | 		root->Then( | ||
|  | 			(new CmdHelper::Literal("deepload"))->Then( | ||
|  | 			(new CmdHelper::StringArgument("filepath", "The path to loading file."))->Executes( | ||
|  | 			std::bind(&UnvirtContext::ProcLoad, this, true, std::placeholders::_1), | ||
|  | 			"Load a Virtools composition deeply. Load file to CKObject stage." | ||
|  | 		) | ||
|  | 		) | ||
|  | 		); | ||
|  | 		root->Then( | ||
|  | 			(new CmdHelper::Literal("shallowload"))->Then( | ||
|  | 			(new CmdHelper::StringArgument("filepath", "The path to loading file."))->Executes( | ||
|  | 			std::bind(&UnvirtContext::ProcLoad, this, false, std::placeholders::_1), | ||
|  | 			"Load a Virtools composition shallowly. Load file to CKStateChunk stage." | ||
|  | 		) | ||
|  | 		) | ||
|  | 		); | ||
|  | 		root->Then( | ||
|  | 			(new CmdHelper::Literal("unload"))->Executes( | ||
|  | 			std::bind(&UnvirtContext::ProcUnLoad, this, std::placeholders::_1), | ||
|  | 			"Release loaded Virtools composition." | ||
|  | 		) | ||
|  | 		); | ||
|  | 		root->Then( | ||
|  | 			(new CmdHelper::Literal("info"))->Executes( | ||
|  | 			std::bind(&UnvirtContext::ProcInfo, this, std::placeholders::_1), | ||
|  | 			"Show the header info of loaded Virtools composition." | ||
|  | 		) | ||
|  | 		); | ||
|  | 
 | ||
|  | 
 | ||
|  | 		root->Then( | ||
|  | 				(new CmdHelper::Literal("foo"))->Then( | ||
|  | 				(new CmdHelper::Literal("bar"))->Executes([](const CmdHelper::ArgumentsMap& amap) -> void { | ||
|  | 					fprintf(stdout, "foobar!\n"); | ||
|  | 				}, "simple foobar") | ||
|  | 			)->Then( | ||
|  | 				(new CmdHelper::IntArgument("bar", "the calling target 1"))->Executes([](const CmdHelper::ArgumentsMap& amap) -> void { | ||
|  | 						fprintf(stdout, "foo%" PRIi32 "!\n", *(amap.Get("bar")->GetData<int32_t>())); | ||
|  | 					}, "specialized foo bar") | ||
|  | 			) | ||
|  | 		)->Then( | ||
|  | 			(new CmdHelper::Literal("call"))->Then( | ||
|  | 				(new CmdHelper::IntArgument("bar", "the calling taget 2"))->Executes([](const CmdHelper::ArgumentsMap& amap) -> void { | ||
|  | 					fprintf(stdout, "call%" PRIi32 "!\n", *(amap.Get("bar")->GetData<int32_t>())); | ||
|  | 				}, "calling someone") | ||
|  | 			) | ||
|  | 		); | ||
|  | 		// create help
 | ||
|  | 		m_Help = root->RootHelp(); | ||
|  | 
 | ||
|  | 		// create context
 | ||
|  | 		m_Ctx = new LibCmo::CK2::CKContext(); | ||
|  | 		m_Ctx->SetOutputCallback(std::bind(&UnvirtContext::PrintContextMsg, this, std::placeholders::_1)); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	UnvirtContext::~UnvirtContext() { | ||
|  | 		if (m_Help != nullptr) | ||
|  | 			delete m_Help; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	bool UnvirtContext::HasOpenedFile() { | ||
|  | 		return m_FileReader != nullptr; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ClearDocument() { | ||
|  | 		if (m_FileReader == nullptr) return; | ||
|  | 		delete m_FileReader; | ||
|  | 		m_FileReader = nullptr; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::PrintContextMsg(LibCmo::CK2::CKSTRING msg) { | ||
|  | 		if (msg != nullptr) { | ||
|  | 			fprintf(fout, UNVIRT_TERMCOL_LIGHT_YELLOW(("[CKContext] ")) "%s\n", msg); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::PrintCommonError(const char* u8_fmt, ...) { | ||
|  | 		va_list argptr; | ||
|  | 		va_start(argptr, u8_fmt); | ||
|  | 		std::fputs(UNVIRT_TERMCOLHDR_LIGHT_RED, fout); | ||
|  | 		std::vfprintf(fout, u8_fmt, argptr); | ||
|  | 		std::fputs(UNVIRT_TERMCOLTAIL, fout); | ||
|  | 		va_end(argptr); | ||
|  | 		std::fputc('\n', fout); | ||
|  | 	} | ||
|  | 
 | ||
|  | #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); | ||
|  | 
 | ||
|  | 			// get sub command
 | ||
|  | 			if (!m_Root.RootConsume(cmds)) { | ||
|  | 				this->PrintCommonError("Command syntax error \"%s\".", u8cmd.c_str()); | ||
|  | 				m_Help->Print(); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if (m_OrderExit) { | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | #pragma endregion
 | ||
|  | 
 | ||
|  | #pragma region Proc Detail
 | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcLoad(bool is_deep, const CmdHelper::ArgumentsMap& amap) { | ||
|  | 		// check pre-requirement
 | ||
|  | 		if (HasOpenedFile()) { | ||
|  | 			PrintCommonError("Already have a opened file. Close it before calling \"load\"."); | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		std::string filepath = *amap.Get("filepath")->GetData<std::string>(); | ||
|  | 
 | ||
|  | 		// proc
 | ||
|  | 		m_FileReader = new LibCmo::CK2::CKFileReader(m_Ctx); | ||
|  | 		LibCmo::CK2::CKERROR err; | ||
|  | 		if (is_deep) { | ||
|  | 			err = m_FileReader->DeepLoad(filepath.c_str()); | ||
|  | 		} else { | ||
|  | 			err = m_FileReader->ShallowLoad(filepath.c_str()); | ||
|  | 		} | ||
|  | 		if (err != LibCmo::CK2::CKERROR::CKERR_OK) { | ||
|  | 			// fail to load. release all.
 | ||
|  | 			PrintCommonError("Fail to open file. Function return: %s\n\t%s", | ||
|  | 				Unvirt::AccessibleValue::GetCkErrorName(err).c_str(), | ||
|  | 				Unvirt::AccessibleValue::GetCkErrorDescription(err).c_str() | ||
|  | 			); | ||
|  | 
 | ||
|  | 			ClearDocument(); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcUnLoad(const CmdHelper::ArgumentsMap& amap) { | ||
|  | 		// check pre-requirement
 | ||
|  | 		if (!HasOpenedFile()) { | ||
|  | 			this->PrintCommonError("No loaded file."); | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// free all
 | ||
|  | 		ClearDocument(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcInfo(const CmdHelper::ArgumentsMap& amap) { | ||
|  | 		// check pre-requirement
 | ||
|  | 		if (!HasOpenedFile()) { | ||
|  | 			PrintCommonError("No loaded file."); | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// print
 | ||
|  | 		Unvirt::StructFormatter::PrintCKFileInfo(m_FileReader->GetFileInfo()); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcLs(ViewPart parts, const CmdHelper::ArgumentsMap& amap) { | ||
|  | 		// check pre-requirement
 | ||
|  | 		if (!HasOpenedFile()) { | ||
|  | 			this->PrintCommonError("No loaded file."); | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// check requirement
 | ||
|  | 		int32_t gotten_page = *amap.Get("page")->GetData<int32_t>(); | ||
|  | 		if (gotten_page <= 0) { | ||
|  | 			PrintCommonError("Page out of range."); | ||
|  | 			return; | ||
|  | 		} | ||
|  | 		size_t page = static_cast<size_t>(gotten_page) - 1; | ||
|  | 
 | ||
|  | 		// show list
 | ||
|  | 		switch (parts) { | ||
|  | 			case ViewPart::Objects: | ||
|  | 			{ | ||
|  | 				// obj list
 | ||
|  | 				if (page * m_PageLen >= m_FileReader->GetFileObjects().size()) { | ||
|  | 					PrintCommonError("Page out of range."); | ||
|  | 					return; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				Unvirt::StructFormatter::PrintObjectList(m_FileReader->GetFileObjects(), page, this->m_PageLen); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			case ViewPart::Managers: | ||
|  | 			{ | ||
|  | 				// mgr list
 | ||
|  | 				if (page * m_PageLen >= m_FileReader->GetManagersData().size()) { | ||
|  | 					PrintCommonError("Page out of range."); | ||
|  | 					return; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				Unvirt::StructFormatter::PrintManagerList(m_FileReader->GetManagersData(), page, this->m_PageLen); | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcData(ViewPart parts, const CmdHelper::ArgumentsMap& amap) { | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcChunk(ViewPart parts, const CmdHelper::ArgumentsMap& amap) { | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcItems(const CmdHelper::ArgumentsMap& amap) { | ||
|  | 		// check requirement
 | ||
|  | 		int32_t count = *amap.Get("count")->GetData<int32_t>(); | ||
|  | 		if (count <= 0) { | ||
|  | 			PrintCommonError("Value out of range."); | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// assign
 | ||
|  | 		m_PageLen = static_cast<size_t>(count); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap& amap) { | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcTemp(const CmdHelper::ArgumentsMap& amap) { | ||
|  | 		// check requirement
 | ||
|  | 		std::string temppath = *amap.Get("temppath")->GetData<std::string>(); | ||
|  | 
 | ||
|  | 		// assign
 | ||
|  | 		m_Ctx->SetTempPath(temppath.c_str()); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	void UnvirtContext::ProcExit(const CmdHelper::ArgumentsMap& amap) { | ||
|  | 		m_OrderExit = true; | ||
|  | 	} | ||
|  | 
 | ||
|  | #pragma endregion
 | ||
|  | 
 | ||
|  | } |