Files
smart_wasm/src/utils.cpp
2026-06-01 17:59:51 +08:00

460 lines
14 KiB
C++

#include "utils.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <ctime>
#include <fstream>
#include <algorithm>
#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 字符表
const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
// 判断字符是否为有效的 Base64 字符
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 字符
}
else if ((c & 0xE0) == 0xC0)
{
// 2 字节 UTF-8
if (i + 1 >= str.size() || (str[i + 1] & 0xC0) != 0x80)
{
return false;
}
i += 1;
}
else if ((c & 0xF0) == 0xE0)
{
// 3 字节 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 字节 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; // 非法 UTF-8 字节
}
}
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 字符
}
else if ((c & 0xE0) == 0xC0)
{
// 2 字节 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 字节 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 字节 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;
}
}
// 跳过非法 UTF-8 字节
}
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 解码函数
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;
// 去掉输入中的换行和空格
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)
{
// 补齐的占位字符按 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;
}
// 将 Base64 编码的 URDF 转成字符串
std::string base64_to_urdf(const std::string &base64_urdf)
{
try
{
std::string urdf_content = base64_decode(base64_urdf);
// 校验解码结果是否像合法的 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());
}
}
// 将 Base64 编码的 URDF 保存到文件
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;
}
}
// 将 URDF 字符串保存到文件
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;
}
}
// 校验 Base64 字符串是否可解析为合法 URDF
bool validate_urdf_base64(const std::string &base64_urdf)
{
try
{
std::string urdf_content = base64_to_urdf(base64_urdf);
// 基础 URDF 结构校验
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