Initial commit
This commit is contained in:
461
src/utils.cpp
Normal file
461
src/utils.cpp
Normal file
@@ -0,0 +1,461 @@
|
||||
#include "utils.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
// 实现 splitByDelimiter 方法
|
||||
std::pair<std::string, std::string> StringUtils::splitByDelimiter(
|
||||
const std::string &str,
|
||||
char delimiter)
|
||||
{
|
||||
size_t pos = str.find(delimiter);
|
||||
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
// 找到分隔符,拆分字符串
|
||||
std::string first = str.substr(0, pos);
|
||||
std::string second = str.substr(pos + 1);
|
||||
return std::make_pair(first, second);
|
||||
}
|
||||
|
||||
// 未找到分隔符,返回原始字符串和空字符串
|
||||
return std::make_pair(str, "");
|
||||
}
|
||||
|
||||
// 实现 splitA_B 方法
|
||||
std::pair<std::string, std::string> StringUtils::splitA_B(const std::string &str)
|
||||
{
|
||||
return splitByDelimiter(str, '_');
|
||||
}
|
||||
|
||||
// 实现 splitToTwoParts 方法
|
||||
bool StringUtils::splitToTwoParts(
|
||||
const std::string &str,
|
||||
std::string &part1,
|
||||
std::string &part2,
|
||||
char delimiter)
|
||||
{
|
||||
size_t pos = str.find(delimiter);
|
||||
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
part1 = str.substr(0, pos);
|
||||
part2 = str.substr(pos + 1);
|
||||
return true; // 成功拆分
|
||||
}
|
||||
|
||||
// 未找到分隔符
|
||||
part1 = str;
|
||||
part2 = "";
|
||||
return false; // 拆分失败
|
||||
}
|
||||
|
||||
// 实现 splitStrict 方法
|
||||
std::pair<std::string, std::string> StringUtils::splitStrict(
|
||||
const std::string &str,
|
||||
char delimiter)
|
||||
{
|
||||
size_t pos = str.find(delimiter);
|
||||
|
||||
// 检查是否找到分隔符
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
throw std::invalid_argument("Delimiter '" + std::string(1, delimiter) +
|
||||
"' not found in string: \"" + str + "\"");
|
||||
}
|
||||
|
||||
// 检查是否有多于一个分隔符
|
||||
size_t nextPos = str.find(delimiter, pos + 1);
|
||||
if (nextPos != std::string::npos)
|
||||
{
|
||||
throw std::invalid_argument("Multiple delimiters '" + std::string(1, delimiter) +
|
||||
"' found in string: \"" + str + "\"");
|
||||
}
|
||||
|
||||
std::string first = str.substr(0, pos);
|
||||
std::string second = str.substr(pos + 1);
|
||||
|
||||
return std::make_pair(first, second);
|
||||
}
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
// Base64<36>ַ<EFBFBD><D6B7><EFBFBD>
|
||||
const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>Ƿ<EFBFBD>Ϊ<EFBFBD><CEAA>Ч<EFBFBD><D0A7>base64<36>ַ<EFBFBD>
|
||||
static bool is_base64(unsigned char c)
|
||||
{
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
std::string get_current_time()
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now.time_since_epoch()) %
|
||||
1000;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(std::gmtime(&in_time_t), "%Y-%m-%dT%H:%M:%S");
|
||||
ss << "." << std::setfill('0') << std::setw(3) << ms.count() << "Z";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string get_current_timestamp()
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now.time_since_epoch()) %
|
||||
1000;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M:%S");
|
||||
ss << '.' << std::setfill('0') << std::setw(3) << milliseconds.count();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// void setup_cors_headers(httplib::Response &res)
|
||||
// {
|
||||
// res.set_header("Access-Control-Allow-Origin", "*");
|
||||
// res.set_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH");
|
||||
// res.set_header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With, X-API-Key, Accept, Origin");
|
||||
// res.set_header("Access-Control-Expose-Headers", "Content-Length, Content-Type, X-Request-Id");
|
||||
// res.set_header("Access-Control-Max-Age", "86400"); // 24Сʱ
|
||||
// res.set_header("Vary", "Origin");
|
||||
// }
|
||||
|
||||
json create_error_response(int code, const std::string &message, const std::string &details)
|
||||
{
|
||||
json response = {
|
||||
{"success", false},
|
||||
{"code", code},
|
||||
{"message", message},
|
||||
{"timestamp", get_current_time()}};
|
||||
|
||||
if (!details.empty())
|
||||
{
|
||||
response["details"] = details;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
json create_success_response(const json &data, const std::string &message)
|
||||
{
|
||||
return {
|
||||
{"success", true},
|
||||
{"code", 0},
|
||||
{"message", message},
|
||||
{"data", data},
|
||||
{"timestamp", get_current_time()}};
|
||||
}
|
||||
|
||||
bool is_valid_utf8(const std::string &str)
|
||||
{
|
||||
for (size_t i = 0; i < str.size(); ++i)
|
||||
{
|
||||
unsigned char c = str[i];
|
||||
if (c <= 0x7F)
|
||||
{
|
||||
continue; // ASCII<49>ַ<EFBFBD>
|
||||
}
|
||||
else if ((c & 0xE0) == 0xC0)
|
||||
{
|
||||
// 2<>ֽ<EFBFBD>UTF-8
|
||||
if (i + 1 >= str.size() || (str[i + 1] & 0xC0) != 0x80)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
else if ((c & 0xF0) == 0xE0)
|
||||
{
|
||||
// 3<>ֽ<EFBFBD>UTF-8
|
||||
if (i + 2 >= str.size() || (str[i + 1] & 0xC0) != 0x80 || (str[i + 2] & 0xC0) != 0x80)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
else if ((c & 0xF8) == 0xF0)
|
||||
{
|
||||
// 4<>ֽ<EFBFBD>UTF-8
|
||||
if (i + 3 >= str.size() || (str[i + 1] & 0xC0) != 0x80 ||
|
||||
(str[i + 2] & 0xC0) != 0x80 || (str[i + 3] & 0xC0) != 0x80)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
i += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // <20><>Ч<EFBFBD><D0A7>UTF-8<>ֽ<EFBFBD>
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string sanitize_utf8(const std::string &str)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve(str.size());
|
||||
|
||||
for (size_t i = 0; i < str.size(); ++i)
|
||||
{
|
||||
unsigned char c = str[i];
|
||||
if (c <= 0x7F)
|
||||
{
|
||||
result += c; // ASCII<49>ַ<EFBFBD>
|
||||
}
|
||||
else if ((c & 0xE0) == 0xC0)
|
||||
{
|
||||
// 2<>ֽ<EFBFBD>UTF-8
|
||||
if (i + 1 < str.size() && (str[i + 1] & 0xC0) == 0x80)
|
||||
{
|
||||
result += c;
|
||||
result += str[i + 1];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
else if ((c & 0xF0) == 0xE0)
|
||||
{
|
||||
// 3<>ֽ<EFBFBD>UTF-8
|
||||
if (i + 2 < str.size() && (str[i + 1] & 0xC0) == 0x80 && (str[i + 2] & 0xC0) == 0x80)
|
||||
{
|
||||
result += c;
|
||||
result += str[i + 1];
|
||||
result += str[i + 2];
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
else if ((c & 0xF8) == 0xF0)
|
||||
{
|
||||
// 4<>ֽ<EFBFBD>UTF-8
|
||||
if (i + 3 < str.size() && (str[i + 1] & 0xC0) == 0x80 &&
|
||||
(str[i + 2] & 0xC0) == 0x80 && (str[i + 3] & 0xC0) == 0x80)
|
||||
{
|
||||
result += c;
|
||||
result += str[i + 1];
|
||||
result += str[i + 2];
|
||||
result += str[i + 3];
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>UTF-8<>ֽ<EFBFBD>
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
json create_api_response(bool success, int code, const std::string &msg,
|
||||
const std::string &req_code, const std::string &req_from,
|
||||
const std::string &req_cmd, const json &res_data)
|
||||
{
|
||||
json response;
|
||||
response["success"] = success;
|
||||
response["code"] = code;
|
||||
response["msg"] = msg;
|
||||
response["req_code"] = req_code;
|
||||
response["req_from"] = req_from;
|
||||
response["req_cmd"] = req_cmd;
|
||||
response["timestamp"] = std::time(nullptr);
|
||||
|
||||
if (!res_data.is_null())
|
||||
{
|
||||
response["res_data"] = res_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
response["res_data"] = json::object();
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
// Base64<36><34><EFBFBD>뺯<EFBFBD><EBBAAF>
|
||||
std::string base64_decode(const std::string &encoded_string)
|
||||
{
|
||||
int in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
// <20>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD>ܵĻ<DCB5><C4BB>з<EFBFBD><D0B7>Ϳո<CDBF>
|
||||
std::string clean_encoded;
|
||||
for (char c : encoded_string)
|
||||
{
|
||||
if (c != '\n' && c != '\r' && c != ' ')
|
||||
{
|
||||
clean_encoded += c;
|
||||
}
|
||||
}
|
||||
in_len = clean_encoded.size();
|
||||
|
||||
while (in_len-- && (clean_encoded[in_] != '=') && is_base64(clean_encoded[in_]))
|
||||
{
|
||||
char_array_4[i++] = clean_encoded[in_];
|
||||
in_++;
|
||||
if (i == 4)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
size_t pos = base64_chars.find(char_array_4[i]);
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Invalid base64 character");
|
||||
}
|
||||
char_array_4[i] = pos;
|
||||
}
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
ret += char_array_3[i];
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for (j = i; j < 4; j++)
|
||||
{
|
||||
char_array_4[j] = 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
size_t pos = base64_chars.find(char_array_4[j]);
|
||||
if (pos == std::string::npos && j >= i)
|
||||
{
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>λ<EFBFBD><CEBB>Ϊ0
|
||||
char_array_4[j] = 0;
|
||||
}
|
||||
else if (pos != std::string::npos)
|
||||
{
|
||||
char_array_4[j] = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Invalid base64 character");
|
||||
}
|
||||
}
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; j < i - 1; j++)
|
||||
{
|
||||
ret += char_array_3[j];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// <20><>base64<36><34><EFBFBD><EFBFBD><EFBFBD>URDFת<46><D7AA>Ϊ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
|
||||
std::string base64_to_urdf(const std::string &base64_urdf)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string urdf_content = base64_decode(base64_urdf);
|
||||
|
||||
// <20><>֤<EFBFBD><D6A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>URDF/XML
|
||||
if (urdf_content.find("<?xml") != std::string::npos ||
|
||||
urdf_content.find("<robot") != std::string::npos)
|
||||
{
|
||||
return urdf_content;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Decoded content does not appear to be a valid URDF file");
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw std::runtime_error(std::string("Failed to decode URDF: ") + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
// <20><>base64<36><34><EFBFBD><EFBFBD><EFBFBD>URDF<44><46><EFBFBD>浽<EFBFBD>ļ<EFBFBD>
|
||||
bool save_base64_urdf_to_file(const std::string &base64_urdf, const std::string &filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string urdf_content = base64_to_urdf(base64_urdf);
|
||||
return save_urdf_string_to_file(urdf_content, filename);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error saving base64 URDF to file: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// <20><>URDF<44>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>浽<EFBFBD>ļ<EFBFBD>
|
||||
bool save_urdf_string_to_file(const std::string &urdf_content, const std::string &filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ofstream out_file(filename);
|
||||
if (!out_file)
|
||||
{
|
||||
throw std::runtime_error("Cannot create output file: " + filename);
|
||||
}
|
||||
|
||||
out_file << urdf_content;
|
||||
out_file.close();
|
||||
|
||||
std::cout << "URDF file successfully saved to: " << filename << std::endl;
|
||||
std::cout << "File size: " << urdf_content.size() << " bytes" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error saving URDF to file: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// <20><>֤base64<36>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>URDF
|
||||
bool validate_urdf_base64(const std::string &base64_urdf)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string urdf_content = base64_to_urdf(base64_urdf);
|
||||
|
||||
// <20><EFBFBD>URDF<44><46>֤
|
||||
bool has_xml_decl = urdf_content.find("<?xml") != std::string::npos;
|
||||
bool has_robot_tag = urdf_content.find("<robot") != std::string::npos;
|
||||
bool has_link_tag = urdf_content.find("<link") != std::string::npos;
|
||||
bool has_joint_tag = urdf_content.find("<joint") != std::string::npos;
|
||||
|
||||
return has_robot_tag && (has_link_tag || has_joint_tag);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
Reference in New Issue
Block a user