107 lines
3.1 KiB
C++
107 lines
3.1 KiB
C++
#include "encoding.hpp"
|
|
|
|
#include <array>
|
|
#include <cctype>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
|
|
namespace connector {
|
|
|
|
std::vector<std::uint8_t> decode_base64(const std::string& value) {
|
|
static const std::string alphabet =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
std::array<int, 256> table{};
|
|
table.fill(-1);
|
|
for (std::size_t index = 0; index < alphabet.size(); ++index) {
|
|
table[static_cast<unsigned char>(alphabet[index])] = static_cast<int>(index);
|
|
}
|
|
if (value.size() % 4 != 0) throw std::runtime_error("图片数据格式无效");
|
|
std::vector<std::uint8_t> output;
|
|
output.reserve(value.size() / 4 * 3);
|
|
int accumulator = 0;
|
|
int bits = -8;
|
|
bool padding = false;
|
|
for (const unsigned char c : value) {
|
|
if (c == '=') {
|
|
padding = true;
|
|
continue;
|
|
}
|
|
if (padding || table[c] < 0) throw std::runtime_error("图片数据格式无效");
|
|
accumulator = (accumulator << 6) | table[c];
|
|
bits += 6;
|
|
if (bits >= 0) {
|
|
output.push_back(static_cast<std::uint8_t>((accumulator >> bits) & 0xff));
|
|
bits -= 8;
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
namespace {
|
|
int hex_value(char c) {
|
|
if (c >= '0' && c <= '9') return c - '0';
|
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
|
return -1;
|
|
}
|
|
} // namespace
|
|
|
|
std::string url_decode(const std::string& value) {
|
|
std::string output;
|
|
output.reserve(value.size());
|
|
for (std::size_t index = 0; index < value.size(); ++index) {
|
|
if (value[index] == '+') {
|
|
output.push_back(' ');
|
|
} else if (value[index] == '%' && index + 2 < value.size()) {
|
|
const int high = hex_value(value[index + 1]);
|
|
const int low = hex_value(value[index + 2]);
|
|
if (high < 0 || low < 0) throw std::runtime_error("URL 编码无效");
|
|
output.push_back(static_cast<char>((high << 4) | low));
|
|
index += 2;
|
|
} else {
|
|
output.push_back(value[index]);
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
std::string url_encode(const std::string& value) {
|
|
std::ostringstream output;
|
|
output << std::uppercase << std::hex;
|
|
for (const unsigned char c : value) {
|
|
if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
|
|
output << static_cast<char>(c);
|
|
} else {
|
|
output << '%' << std::setw(2) << std::setfill('0') << static_cast<int>(c);
|
|
}
|
|
}
|
|
return output.str();
|
|
}
|
|
|
|
std::string html_escape(const std::string& value) {
|
|
std::string output;
|
|
output.reserve(value.size());
|
|
for (const char c : value) {
|
|
switch (c) {
|
|
case '&': output += "&"; break;
|
|
case '<': output += "<"; break;
|
|
case '>': output += ">"; break;
|
|
case '"': output += """; break;
|
|
case '\'': output += "'"; break;
|
|
default: output.push_back(c);
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
std::string trim(const std::string& value) {
|
|
std::size_t start = 0;
|
|
while (start < value.size() && std::isspace(static_cast<unsigned char>(value[start]))) ++start;
|
|
std::size_t end = value.size();
|
|
while (end > start && std::isspace(static_cast<unsigned char>(value[end - 1]))) --end;
|
|
return value.substr(start, end - start);
|
|
}
|
|
|
|
} // namespace connector
|