Move hex-related functions into their own file

This commit is contained in:
blankie 2023-12-08 18:15:28 +11:00
parent 9b6f6a4bcc
commit d1711a040b
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
4 changed files with 102 additions and 45 deletions

View File

@ -29,7 +29,7 @@ list(APPEND FLAGS -Werror -Wall -Wextra -Wshadow -Wpedantic -Wno-gnu-anonymous-s
add_link_options(${FLAGS}) add_link_options(${FLAGS})
add_executable(${PROJECT_NAME} main.cpp numberhelper.cpp config.cpp settings.cpp models.cpp client.cpp servehelper.cpp timeutils.cpp hiredis_wrapper.cpp add_executable(${PROJECT_NAME} main.cpp numberhelper.cpp hex.cpp config.cpp settings.cpp models.cpp client.cpp servehelper.cpp timeutils.cpp hiredis_wrapper.cpp
routes/home.cpp routes/css.cpp routes/user.cpp routes/status.cpp routes/tags.cpp routes/about.cpp routes/user_settings.cpp routes/home.cpp routes/css.cpp routes/user.cpp routes/status.cpp routes/tags.cpp routes/about.cpp routes/user_settings.cpp
blankie/serializer.cpp blankie/escape.cpp) blankie/serializer.cpp blankie/escape.cpp)
set_target_properties(${PROJECT_NAME} set_target_properties(${PROJECT_NAME}

View File

@ -2,6 +2,7 @@
#include <stdexcept> #include <stdexcept>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "hex.h"
#include "client.h" #include "client.h"
#include "models.h" #include "models.h"
#include "curlu_wrapper.h" #include "curlu_wrapper.h"
@ -11,8 +12,6 @@ MastodonClient mastodon_client;
static void lowercase(std::string& str); static void lowercase(std::string& str);
static void handle_post_server(Post& post, const std::string& host); static void handle_post_server(Post& post, const std::string& host);
static std::string url_encode(const std::string& in);
static inline void hexencode(char c, char out[2]);
static void share_lock(CURL* curl, curl_lock_data data, curl_lock_access access, void* clientp); static void share_lock(CURL* curl, curl_lock_data data, curl_lock_access access, void* clientp);
static void share_unlock(CURL* curl, curl_lock_data data, void* clientp); static void share_unlock(CURL* curl, curl_lock_data data, void* clientp);
@ -90,7 +89,7 @@ std::optional<Account> MastodonClient::get_account_by_username(std::string host,
url.set(CURLUPART_SCHEME, "https"); url.set(CURLUPART_SCHEME, "https");
url.set(CURLUPART_HOST, host); url.set(CURLUPART_HOST, host);
url.set(CURLUPART_PATH, "/api/v1/accounts/lookup"); url.set(CURLUPART_PATH, "/api/v1/accounts/lookup");
url.set(CURLUPART_QUERY, "acct="s + url_encode(username)); url.set(CURLUPART_QUERY, "acct="s + percent_encode(username));
try { try {
Account account = this->_send_request("coyote:"s + host + ":@" + username, url); Account account = this->_send_request("coyote:"s + host + ":@" + username, url);
account.same_server = host == account.server; account.same_server = host == account.server;
@ -111,7 +110,7 @@ std::vector<Post> MastodonClient::get_pinned_posts(std::string host, const std::
CurlUrl url; CurlUrl url;
url.set(CURLUPART_SCHEME, "https"); url.set(CURLUPART_SCHEME, "https");
url.set(CURLUPART_HOST, host); url.set(CURLUPART_HOST, host);
url.set(CURLUPART_PATH, "/api/v1/accounts/"s + url_encode(account_id) + "/statuses"); url.set(CURLUPART_PATH, "/api/v1/accounts/"s + percent_encode(account_id) + "/statuses");
url.set(CURLUPART_QUERY, "pinned=true"); url.set(CURLUPART_QUERY, "pinned=true");
std::vector<Post> posts = this->_send_request("coyote:"s + host + ':' + account_id + ":pinned", url); std::vector<Post> posts = this->_send_request("coyote:"s + host + ':' + account_id + ":pinned", url);
@ -129,7 +128,7 @@ std::vector<Post> MastodonClient::get_posts(const std::string& host, const std::
CurlUrl url; CurlUrl url;
url.set(CURLUPART_SCHEME, "https"); url.set(CURLUPART_SCHEME, "https");
url.set(CURLUPART_HOST, host); url.set(CURLUPART_HOST, host);
url.set(CURLUPART_PATH, "/api/v1/accounts/"s + url_encode(account_id) + "/statuses"); url.set(CURLUPART_PATH, "/api/v1/accounts/"s + percent_encode(account_id) + "/statuses");
url.set(CURLUPART_QUERY, sorting_parameters[sorting_method]); url.set(CURLUPART_QUERY, sorting_parameters[sorting_method]);
if (max_id) { if (max_id) {
url.set(CURLUPART_QUERY, "max_id="s + std::move(*max_id), CURLU_URLENCODE | CURLU_APPENDQUERY); url.set(CURLUPART_QUERY, "max_id="s + std::move(*max_id), CURLU_URLENCODE | CURLU_APPENDQUERY);
@ -150,7 +149,7 @@ std::optional<Post> MastodonClient::get_post(const std::string& host, std::strin
CurlUrl url; CurlUrl url;
url.set(CURLUPART_SCHEME, "https"); url.set(CURLUPART_SCHEME, "https");
url.set(CURLUPART_HOST, host); url.set(CURLUPART_HOST, host);
url.set(CURLUPART_PATH, "/api/v1/statuses/"s + url_encode(std::move(id))); url.set(CURLUPART_PATH, "/api/v1/statuses/"s + percent_encode(std::move(id)));
try { try {
Post post = this->_send_request(std::nullopt, url); Post post = this->_send_request(std::nullopt, url);
handle_post_server(post, host); handle_post_server(post, host);
@ -170,7 +169,7 @@ PostContext MastodonClient::get_post_context(const std::string& host, std::strin
CurlUrl url; CurlUrl url;
url.set(CURLUPART_SCHEME, "https"); url.set(CURLUPART_SCHEME, "https");
url.set(CURLUPART_HOST, host); url.set(CURLUPART_HOST, host);
url.set(CURLUPART_PATH, "/api/v1/statuses/"s + url_encode(std::move(id)) + "/context"); url.set(CURLUPART_PATH, "/api/v1/statuses/"s + percent_encode(std::move(id)) + "/context");
PostContext context = this->_send_request(std::nullopt, url); PostContext context = this->_send_request(std::nullopt, url);
for (Post& post : context.ancestors) { for (Post& post : context.ancestors) {
@ -189,7 +188,7 @@ std::vector<Post> MastodonClient::get_tag_timeline(const std::string& host, cons
CurlUrl url; CurlUrl url;
url.set(CURLUPART_SCHEME, "https"); url.set(CURLUPART_SCHEME, "https");
url.set(CURLUPART_HOST, host); url.set(CURLUPART_HOST, host);
url.set(CURLUPART_PATH, "/api/v1/timelines/tag/"s + url_encode(tag)); url.set(CURLUPART_PATH, "/api/v1/timelines/tag/"s + percent_encode(tag));
if (max_id) { if (max_id) {
url.set(CURLUPART_QUERY, "max_id="s + std::move(*max_id), CURLU_URLENCODE | CURLU_APPENDQUERY); url.set(CURLUPART_QUERY, "max_id="s + std::move(*max_id), CURLU_URLENCODE | CURLU_APPENDQUERY);
} }
@ -313,42 +312,6 @@ static void handle_post_server(Post& post, const std::string& host) {
} }
} }
static std::string url_encode(const std::string& in) {
std::string out;
char encoded[2];
size_t pos = 0;
size_t last_pos = 0;
out.reserve(in.size());
while ((pos = in.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", pos)) != std::string::npos) {
out.append(in, last_pos, pos - last_pos);
hexencode(in[pos], encoded);
out += '%';
out.append(encoded, 2);
pos++;
last_pos = pos;
}
if (in.size() > last_pos) {
out.append(in, last_pos);
}
return out;
}
static inline void hexencode(char c, char out[2]) {
char nibble1 = (c >> 4) & 0xF;
char nibble2 = c & 0xF;
auto hexencode = [](char nibble) {
return static_cast<char>(nibble < 10
? '0' + nibble
: 'A' + nibble - 10);
};
out[0] = hexencode(nibble1);
out[1] = hexencode(nibble2);
}
static void share_lock(CURL* curl, curl_lock_data data, curl_lock_access access, void* clientp) { static void share_lock(CURL* curl, curl_lock_data data, curl_lock_access access, void* clientp) {
(void)curl; (void)curl;
(void)access; (void)access;

82
hex.cpp Normal file
View File

@ -0,0 +1,82 @@
#include <stdexcept>
#include "hex.h"
static void hex_encode(char c, char out[2]);
static inline char hex_decode(char nibble1, char nibble2);
std::string hex_encode(const char* in, size_t in_size) {
std::string out;
out.reserve(in_size * 2);
for (size_t i = 0; i < in_size; i++) {
char encoded[2];
hex_encode(in[i], encoded);
out.append(encoded, 2);
}
return out;
}
std::string percent_encode(std::string_view in) {
std::string out;
char encoded[2];
size_t pos = 0;
size_t last_pos = 0;
out.reserve(in.size());
while ((pos = in.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", pos)) != std::string::npos) {
out.append(in, last_pos, pos - last_pos);
hex_encode(in[pos], encoded);
out += '%';
out.append(encoded, 2);
pos++;
last_pos = pos;
}
if (in.size() > last_pos) {
out.append(in, last_pos);
}
return out;
}
std::vector<char> hex_decode(std::string_view in) {
if (in.size() % 2 != 0) {
throw std::invalid_argument("hex_decode(): hex string with an odd size passed");
}
std::vector<char> out;
out.reserve(in.size() / 2);
for (size_t i = 0; i < in.size(); i += 2) {
out.push_back(hex_decode(in[i], in[i + 1]));
}
return out;
}
static void hex_encode(char c, char out[2]) {
char nibble1 = (c >> 4) & 0xF;
char nibble2 = c & 0xF;
auto hex_encode = [](char nibble) {
return static_cast<char>(nibble < 10
? '0' + nibble
: 'A' + nibble - 10);
};
out[0] = hex_encode(nibble1);
out[1] = hex_encode(nibble2);
}
static inline char hex_decode(char nibble1, char nibble2) {
auto hex_decode = [](char nibble) {
if (nibble >= '0' && nibble <= '9') return nibble - '0';
if (nibble >= 'a' && nibble <= 'f') return nibble - 'a' + 10;
if (nibble >= 'A' && nibble <= 'F') return nibble - 'A' + 10;
throw std::invalid_argument("hex_decode(): invalid nibble");
};
return static_cast<char>((hex_decode(nibble1) << 4) | hex_decode(nibble2));
}

12
hex.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <string>
#include <vector>
std::string hex_encode(const char* in, size_t in_size);
inline std::string hex_encode(const std::vector<char>& in) {
return hex_encode(in.data(), in.size());
}
std::string percent_encode(std::string_view in);
std::vector<char> hex_decode(std::string_view in);