Add source code for ctrtool

This commit is contained in:
jakcron
2022-03-12 16:00:33 +08:00
parent 6ad2f13c50
commit 800f5776bc
681 changed files with 219734 additions and 0 deletions
@@ -0,0 +1,222 @@
#include <tc/cli/FormatUtil.h>
#include <fmt/core.h>
inline int charToByte(char chr)
{
if (chr >= 'a' && chr <= 'f')
return (chr - 'a') + 0xa;
else if (chr >= 'A' && chr <= 'F')
return (chr - 'A') + 0xa;
else if (chr >= '0' && chr <= '9')
return chr - '0';
return -1;
}
tc::ByteData tc::cli::FormatUtil::hexStringToBytes(const std::string& str)
{
size_t size = str.size();
if ((size % 2))
{
return tc::ByteData();
}
auto bytes = tc::ByteData(size/2);
for (size_t i = 0; i < bytes.size(); i++)
{
int byte = 0;
byte = charToByte(str[i * 2]);
if (byte == -1)
return tc::ByteData();
bytes.data()[i] = byte_t((byte & 0xf) << 4);
byte = charToByte(str[(i * 2) + 1]);
if (byte == -1)
return tc::ByteData();
bytes.data()[i] |= byte_t((byte & 0xf) << 0);
}
return bytes;
}
std::string tc::cli::FormatUtil::formatBytesAsStringWithLineLimit(const byte_t* data, size_t len, bool upper_case, const std::string& delimiter, size_t row_len, size_t indent_len, bool print_first_indent)
{
// create indentation string
std::string indent_str = "";
for (size_t i = 0; i < indent_len; i++)
{
indent_str += " ";
}
const byte_t* original_data = data;
// create output string
std::string output_str = "";
for (size_t print_len = 0; len > 0; len -= print_len, data += print_len)
{
if (data != original_data || print_first_indent)
{
output_str += indent_str;
}
print_len = std::min<size_t>(len, row_len);
output_str += formatBytesAsString(data, print_len, upper_case, delimiter);
output_str += fmt::format("\n");
}
return output_str;
}
std::string tc::cli::FormatUtil::formatBytesAsString(const byte_t* data, size_t size, bool upper_case, const std::string& delimiter)
{
// create output string
std::string output_str;
for (size_t i = 0; i < size; i++)
{
output_str += fmt::format((upper_case ? "{:02X}" : "{:02x}"), data[i]);
if (i+1 < size)
{
output_str += delimiter;
}
}
return output_str;
}
std::string tc::cli::FormatUtil::formatBytesAsString(const tc::ByteData& data, bool upper_case, const std::string& delimiter)
{
return formatBytesAsString(data.data(), data.size(), upper_case, delimiter);
}
std::string tc::cli::FormatUtil::formatListWithLineLimit(const std::vector<std::string>& str_list, size_t row_len, size_t indent_len, bool print_first_indent)
{
if (str_list.size() == 0)
{
return "";
}
// create output string
std::string output_str = "";
// create indentation string
std::string indent_str = "";
for (size_t i = 0; i < indent_len; i++)
{
indent_str += " ";
}
// create delimiter string
std::string delimiter_str = ", ";
size_t printed_len = 0;
for (auto itr = str_list.begin(); itr != str_list.end(); itr++)
{
// format the strings
// wrap the line after row_len multples
if (printed_len > row_len || printed_len == 0)
{
// don't print the new line if this is the first string
if (itr != str_list.begin())
{
output_str += fmt::format("{:s}\n", delimiter_str);
}
// print indent if this isn't the first string or the user has opted into printing the indent regardless
if (itr != str_list.begin() || print_first_indent)
{
output_str += indent_str;
}
// reset printed_len
printed_len = 0;
}
// within a line we want to separate the next string from the last one with a comma and a space
else
{
//ss << delimiter_str;
output_str += delimiter_str;
}
// print string
output_str += *itr;
// note the length of the string printed
printed_len += itr->size() + delimiter_str.size();
}
output_str += fmt::format("\n");
return output_str;
}
std::string tc::cli::FormatUtil::formatBytesAsHxdHexString(const byte_t* data, size_t size, size_t bytes_per_row, size_t byte_group_size)
{
if (size == 0 || bytes_per_row == 0 || byte_group_size == 0)
{
return "";
}
// create output string
std::string output_str = "";
// iterate over blocks
for (size_t i = 0; size > 0; i++)
{
size_t row_print_len = std::min<size_t>(size, bytes_per_row);
output_str += fmt::format("{:08x} | ", uint64_t(i) * uint64_t(bytes_per_row));
// for block i print each byte
for (size_t j = 0; j < bytes_per_row; j++)
{
if (j < row_print_len)
{
output_str += fmt::format("{:02X}", data[(i * bytes_per_row) + j]);
}
else
{
output_str += " ";
}
if (((j+1) % byte_group_size) == 0)
{
output_str += " ";
}
}
output_str += " ";
for (size_t j = 0; j < bytes_per_row; j++)
{
if (j < row_print_len)
{
byte_t byte = data[(i * bytes_per_row) + j];
output_str += fmt::format("{:c}", (iscntrl(byte) == 0 && byte < 0x7f) ? (char)byte : '.');
}
else
{
output_str += " ";
}
}
output_str += fmt::format("\n");
size -= row_print_len;
}
return output_str;
}
std::string tc::cli::FormatUtil::formatBytesAsHxdHexString(const byte_t* data, size_t size)
{
return formatBytesAsHxdHexString(data, size, 0x10, 1);
}
@@ -0,0 +1,185 @@
#include <tc/cli/OptionParser.h>
#include <fmt/core.h>
const std::string tc::cli::OptionParser::kClassName = "tc::cli::OptionParser";
tc::cli::OptionParser::OptionParser() :
mOptionaAliasMap(),
mUnkOptHandler(nullptr)
{
}
void tc::cli::OptionParser::registerOptionHandler(const std::shared_ptr<IOptionHandler>& handler)
{
if (handler == nullptr)
{
// throw exception
throw tc::ArgumentNullException(kClassName, "OptionHandler was null.");
}
if (handler->getOptionStrings().empty() && handler->getOptionRegexPatterns().empty())
{
throw tc::ArgumentOutOfRangeException(kClassName, "OptionHandler had no option strings or regex patterns.");
}
for (auto itr = handler->getOptionStrings().begin(); itr != handler->getOptionStrings().end(); itr++)
{
mOptionaAliasMap.insert(std::pair<std::string, std::shared_ptr<IOptionHandler>>(*itr, handler));
}
for (auto itr = handler->getOptionRegexPatterns().begin(); itr != handler->getOptionRegexPatterns().end(); itr++)
{
mOptionRegexList.push_back(std::pair<std::regex, std::shared_ptr<IOptionHandler>>(std::regex(*itr), handler));
}
}
void tc::cli::OptionParser::registerUnrecognisedOptionHandler(const std::shared_ptr<IOptionHandler>& handler)
{
if (handler == nullptr)
{
// throw exception
throw tc::ArgumentNullException(kClassName, "OptionHandler was null.");
}
mUnkOptHandler = handler;
}
void tc::cli::OptionParser::processOptions(const std::vector<std::string>& args)
{
/*
fmt::print("OptionParser\n");
fmt::print(" args:\n");
for (auto itr = args.begin(); itr != args.end(); itr++)
{
fmt::print(" #{:s}#\n", *itr);
}
*/
//fmt::print("Begin parsing options\n");
std::string opt = std::string();
std::vector<std::string> params = std::vector<std::string>();
for (auto itr = args.begin(); itr != args.end(); itr++)
{
//fmt::print("itr={:s}\n", *itr);
// (1) parse the current string
std::string tmp_opt = std::string();
std::string tmp_param = std::string();
bool is_compound = false;
// if the string begins with '-' then it is an option (which may be compound)
if (itr->compare(0,1,"-") == 0)
{
//fmt::print("looks like an option\n");
// if there is an "=" in this, then this is a compound option & paramter
size_t equalsign_pos = itr->find('=');
if (equalsign_pos == std::string::npos)
{
//fmt::print("the option looks like a solo option\n");
tmp_opt = *itr;
}
else
{
//fmt::print("the option looks like a compound opt=param\n");
tmp_opt = itr->substr(0, equalsign_pos);
tmp_param = itr->substr(equalsign_pos + 1, std::string::npos);
//fmt::print(" > opt : {:s}\n", tmp_opt);
//fmt::print(" > param : {:s}\n", tmp_param);
// --path=here
// 0123456789a
// --path : pos=0, size = 6 = equalsign_pos
// here : pos = 7 = eqialsign_pos + 1, size = 4 = 11 - 7 = itr->length() -(equalsign_pos+1)
is_compound = true;
}
}
// otherwise it is a param
else
{
tmp_param = *itr;
}
// (2) interprete it in the context of the current state
// the user has indicated the end of the current option
// hand off to option handler and clear state
if (opt.empty() == false && tmp_opt.empty() == false)
{
handleOption(opt, params);
opt = std::string();
params = std::vector<std::string>();
}
// if tmp_opt isn't empty then make it the option
if (tmp_opt.empty() == false)
{
opt = tmp_opt;
}
// if tmp_param isn't empty then add it to the param list
if (tmp_param.empty() == false)
{
// if there is no option set, then this is a head-less parameter, throw exception
if (opt.empty() == true)
{
throw tc::ArgumentException(kClassName, "Option parameter was provided without an option.");
}
params.push_back(tmp_param);
}
// compound options only accept one parameter
if (is_compound)
{
handleOption(opt, params);
opt = std::string();
params = std::vector<std::string>();
}
}
// process dangling opt/params
if (opt.empty() == false)
{
handleOption(opt, params);
}
}
void tc::cli::OptionParser::processOptions(const std::vector<std::string>& args, size_t pos, size_t num)
{
processOptions({args.begin()+pos, args.begin()+pos+num});
}
void tc::cli::OptionParser::handleOption(const std::string& opt, const std::vector<std::string>& params)
{
// attempt to locate a literal alias
auto aliasItr = mOptionaAliasMap.find(opt);
if (aliasItr != mOptionaAliasMap.end())
{
aliasItr->second->processOption(opt, params);
return;
}
// attempt to pattern match
for (auto regexItr = mOptionRegexList.begin(); regexItr != mOptionRegexList.end(); regexItr++)
{
if (std::regex_match(opt, regexItr->first))
{
regexItr->second->processOption(opt, params);
return;
}
}
// attempt to use unknown option handler
if (mUnkOptHandler != nullptr)
{
mUnkOptHandler->processOption(opt, params);
return;
}
// if no handler is located, throw exception
throw tc::ArgumentException(kClassName, fmt::format("Option \"{}\" is not recognised.", opt));
}