Initial commit

This commit is contained in:
zhangshun
2026-06-01 15:55:59 +08:00
commit 40f9bdb590
1799 changed files with 362227 additions and 0 deletions

461
src/utils.cpp Normal file
View 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