Decompose utils from duox-related code

This commit is contained in:
kormax
2026-05-05 18:27:19 +03:00
parent ab4eda6ce5
commit 1167bd9701
7 changed files with 304 additions and 283 deletions
+12 -195
View File
@@ -18,12 +18,9 @@
#include "crypto/duoxcrypto.h"
#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <mbedtls/asn1.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/ecp.h>
@@ -40,6 +37,7 @@
#include "x509_crt.h"
#define DUOX_CERTIFICATE_ANCHOR_INPUT_LEN 8192
#define DUOX_CERTIFICATE_ANCHOR_SEARCH_DEPTH 4
static int duox_cert_info_from_x509_crt(const mbedtls_x509_crt *cert, duox_cert_info_t *out);
@@ -55,189 +53,6 @@ const char *duox_certificate_format_name(duox_certificate_format_t format) {
}
}
const char *duox_cert_info_format_name(const duox_cert_info_t *cert) {
if (cert == NULL) {
return duox_certificate_format_name(DUOX_CERTIFICATE_FORMAT_UNKNOWN);
}
return duox_certificate_format_name(cert->format);
}
static void duox_trim_ascii_inplace(char *text) {
if (text == NULL) {
return;
}
size_t start = 0;
size_t len = strlen(text);
while (start < len && isspace((unsigned char)text[start])) {
start++;
}
while (len > start && isspace((unsigned char)text[len - 1])) {
len--;
}
if (start > 0) {
memmove(text, text + start, len - start);
}
text[len - start] = '\0';
}
static int duox_copy_without_whitespace(const char *src, char *dst, size_t dst_size, size_t *dst_len) {
if (src == NULL || dst == NULL || dst_len == NULL || dst_size == 0) {
return PM3_EINVARG;
}
size_t out = 0;
for (size_t i = 0; src[i] != '\0'; i++) {
if (isspace((unsigned char)src[i])) {
continue;
}
if ((out + 1) >= dst_size) {
return PM3_EOVFLOW;
}
dst[out++] = src[i];
}
dst[out] = '\0';
*dst_len = out;
return PM3_SUCCESS;
}
static bool duox_path_is_directory(const char *path) {
if (path == NULL) {
return false;
}
struct stat st;
if (stat(path, &st) != 0) {
return false;
}
return S_ISDIR(st.st_mode) != 0;
}
static bool duox_path_is_regular_file(const char *path) {
if (path == NULL) {
return false;
}
struct stat st;
if (stat(path, &st) != 0) {
return false;
}
return S_ISREG(st.st_mode) != 0;
}
static const char *duox_path_basename(const char *path) {
if (path == NULL) {
return "";
}
const char *base = strrchr(path, '/');
const char *base_win = strrchr(path, '\\');
if (base == NULL || (base_win != NULL && base_win > base)) {
base = base_win;
}
return (base == NULL) ? path : (base + 1);
}
static void duox_path_basename_without_ext(const char *path, char *out, size_t out_len) {
if (out == NULL || out_len == 0) {
return;
}
out[0] = '\0';
const char *base = duox_path_basename(path);
if (base[0] == '\0') {
return;
}
snprintf(out, out_len, "%s", base);
char *dot = strrchr(out, '.');
if (dot != NULL && dot != out) {
*dot = '\0';
}
}
static int duox_qsort_path_cmp(const void *a, const void *b) {
const char *pa = (const char *)a;
const char *pb = (const char *)b;
return strcmp(pa, pb);
}
static int duox_collect_certificate_anchor_paths_recursive(const char *dirpath,
char paths[][DUOX_CERTIFICATE_ANCHOR_PATH_LEN],
size_t max_paths, size_t *count) {
if (dirpath == NULL || paths == NULL || count == NULL) {
return PM3_EINVARG;
}
DIR *dir = opendir(dirpath);
if (dir == NULL) {
return PM3_EFILE;
}
struct dirent *entry = NULL;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 || entry->d_name[0] == '.') {
continue;
}
char fullpath[DUOX_CERTIFICATE_ANCHOR_PATH_LEN] = {0};
if (snprintf(fullpath, sizeof(fullpath), "%s/%s", dirpath, entry->d_name) >= (int)sizeof(fullpath)) {
continue;
}
if (duox_path_is_directory(fullpath)) {
int res = duox_collect_certificate_anchor_paths_recursive(fullpath, paths, max_paths, count);
if (res != PM3_SUCCESS) {
closedir(dir);
return res;
}
continue;
}
if (!duox_path_is_regular_file(fullpath)) {
continue;
}
if (*count >= max_paths) {
closedir(dir);
return PM3_EOVFLOW;
}
snprintf(paths[*count], DUOX_CERTIFICATE_ANCHOR_PATH_LEN, "%s", fullpath);
(*count)++;
}
closedir(dir);
return PM3_SUCCESS;
}
static int duox_collect_certificate_anchor_paths(const char *anchor_store_dir,
char paths[][DUOX_CERTIFICATE_ANCHOR_PATH_LEN],
size_t max_paths, size_t *count) {
if (anchor_store_dir == NULL || anchor_store_dir[0] == '\0' || paths == NULL || count == NULL) {
return PM3_EINVARG;
}
char *rootdir = NULL;
int res = searchFile(&rootdir, RESOURCES_SUBDIR, anchor_store_dir, "", true);
if (res != PM3_SUCCESS) {
return res;
}
if (!duox_path_is_directory(rootdir)) {
free(rootdir);
return PM3_EFILE;
}
*count = 0;
res = duox_collect_certificate_anchor_paths_recursive(rootdir, paths, max_paths, count);
free(rootdir);
if (res != PM3_SUCCESS) {
return res;
}
qsort(paths, *count, sizeof(paths[0]), duox_qsort_path_cmp);
return PM3_SUCCESS;
}
int duox_certificate_anchor_public_key(const duox_certificate_anchor_t *anchor,
mbedtls_ecp_group_id *curveid,
const uint8_t **pubkey, size_t *pubkey_len) {
@@ -299,7 +114,7 @@ static int duox_load_x509_certificate_input(const char *input, mbedtls_x509_crt
return PM3_EOVFLOW;
}
memcpy(normalized, input, input_len + 1);
duox_trim_ascii_inplace(normalized);
str_trim_ascii_inplace(normalized);
if (normalized[0] == '\0') {
return PM3_EINVARG;
}
@@ -319,7 +134,7 @@ static int duox_load_x509_certificate_input(const char *input, mbedtls_x509_crt
char compact[DUOX_CERTIFICATE_ANCHOR_INPUT_LEN] = {0};
size_t compact_len = 0;
if (duox_copy_without_whitespace(normalized, compact, sizeof(compact), &compact_len) != PM3_SUCCESS || compact_len == 0) {
if (str_copy_without_whitespace(normalized, compact, sizeof(compact), &compact_len) != PM3_SUCCESS || compact_len == 0) {
return PM3_EINVARG;
}
@@ -425,7 +240,7 @@ static int duox_load_certificate_anchor_from_file_path(const char *filepath, duo
}
char filename_anchor_name[DUOX_CERTIFICATE_ANCHOR_NAME_LEN] = {0};
duox_path_basename_without_ext(filepath, filename_anchor_name, sizeof(filename_anchor_name));
path_basename_without_ext(filepath, filename_anchor_name, sizeof(filename_anchor_name));
if (filename_anchor_name[0] == '\0') {
return PM3_EINVARG;
}
@@ -446,14 +261,15 @@ static int duox_load_named_certificate_anchor_from_store(const char *token, cons
char paths[DUOX_CERTIFICATE_ANCHOR_MAX_PATHS][DUOX_CERTIFICATE_ANCHOR_PATH_LEN] = {{0}};
size_t path_count = 0;
int res = duox_collect_certificate_anchor_paths(anchor_store_dir, paths, ARRAYLEN(paths), &path_count);
int res = collect_resource_file_paths(anchor_store_dir, (char *)paths, sizeof(paths[0]), ARRAYLEN(paths), &path_count,
false, DUOX_CERTIFICATE_ANCHOR_SEARCH_DEPTH);
if (res != PM3_SUCCESS) {
return res;
}
for (size_t i = 0; i < path_count; i++) {
char filename_anchor_name[DUOX_CERTIFICATE_ANCHOR_NAME_LEN] = {0};
duox_path_basename_without_ext(paths[i], filename_anchor_name, sizeof(filename_anchor_name));
path_basename_without_ext(paths[i], filename_anchor_name, sizeof(filename_anchor_name));
if (filename_anchor_name[0] == '\0') {
continue;
}
@@ -466,7 +282,7 @@ static int duox_load_named_certificate_anchor_from_store(const char *token, cons
const char *matched_path = NULL;
for (size_t i = 0; i < path_count; i++) {
char filename_anchor_name[DUOX_CERTIFICATE_ANCHOR_NAME_LEN] = {0};
duox_path_basename_without_ext(paths[i], filename_anchor_name, sizeof(filename_anchor_name));
path_basename_without_ext(paths[i], filename_anchor_name, sizeof(filename_anchor_name));
if (filename_anchor_name[0] == '\0' || !str_startswith_case_insensitive(filename_anchor_name, token)) {
continue;
}
@@ -491,7 +307,7 @@ int duox_load_certificate_anchor_from_input(const char *input, const char *ancho
char normalized[DUOX_CERTIFICATE_ANCHOR_INPUT_LEN] = {0};
snprintf(normalized, sizeof(normalized), "%s", input);
duox_trim_ascii_inplace(normalized);
str_trim_ascii_inplace(normalized);
if (normalized[0] == '\0') {
return PM3_EINVARG;
}
@@ -499,7 +315,7 @@ int duox_load_certificate_anchor_from_input(const char *input, const char *ancho
char *resolved_path = NULL;
if (searchFile(&resolved_path, RESOURCES_SUBDIR, normalized, "", true) == PM3_SUCCESS) {
int res = PM3_EINVARG;
if (duox_path_is_regular_file(resolved_path)) {
if (path_is_regular_file(resolved_path)) {
res = duox_load_certificate_anchor_from_file_path(resolved_path, anchor);
}
free(resolved_path);
@@ -532,7 +348,8 @@ int duox_load_certificate_anchors_from_store(const char *anchor_store_dir,
char paths[DUOX_CERTIFICATE_ANCHOR_MAX_PATHS][DUOX_CERTIFICATE_ANCHOR_PATH_LEN] = {{0}};
size_t path_count = 0;
int res = duox_collect_certificate_anchor_paths(anchor_store_dir, paths, ARRAYLEN(paths), &path_count);
int res = collect_resource_file_paths(anchor_store_dir, (char *)paths, sizeof(paths[0]), ARRAYLEN(paths), &path_count,
false, DUOX_CERTIFICATE_ANCHOR_SEARCH_DEPTH);
if (res != PM3_SUCCESS) {
return res;
}
-1
View File
@@ -76,7 +76,6 @@ typedef struct {
} duox_certificate_anchor_t;
const char *duox_certificate_format_name(duox_certificate_format_t format);
const char *duox_cert_info_format_name(const duox_cert_info_t *cert);
int duox_certificate_anchor_public_key(const duox_certificate_anchor_t *anchor,
mbedtls_ecp_group_id *curveid,
const uint8_t **pubkey, size_t *pubkey_len);
+8 -81
View File
@@ -22,7 +22,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <mbedtls/asn1.h>
#include <mbedtls/des.h>
#include <mbedtls/aes.h>
@@ -106,78 +105,6 @@ int pcrypto_rng_fill_oneshot(uint8_t *out, size_t out_len, const char *personali
return res;
}
static void pcrypto_trim_ascii_inplace(char *text) {
if (text == NULL) {
return;
}
size_t start = 0;
size_t len = strlen(text);
while (start < len && isspace((unsigned char)text[start])) {
start++;
}
while (len > start && isspace((unsigned char)text[len - 1])) {
len--;
}
if (start > 0) {
memmove(text, text + start, len - start);
}
text[len - start] = '\0';
}
static void pcrypto_unescape_newlines_inplace(char *text) {
if (text == NULL) {
return;
}
size_t read_pos = 0;
size_t write_pos = 0;
size_t len = strlen(text);
while (read_pos < len) {
if (text[read_pos] == '\\' && (read_pos + 1) < len) {
char esc = text[read_pos + 1];
if (esc == 'n') {
text[write_pos++] = '\n';
read_pos += 2;
continue;
}
if (esc == 'r') {
text[write_pos++] = '\r';
read_pos += 2;
continue;
}
if (esc == 't') {
text[write_pos++] = '\t';
read_pos += 2;
continue;
}
}
text[write_pos++] = text[read_pos++];
}
text[write_pos] = '\0';
}
static int pcrypto_copy_without_whitespace(const char *src, char *dst, size_t dst_size, size_t *dst_len) {
if (src == NULL || dst == NULL || dst_len == NULL || dst_size == 0) {
return PM3_EINVARG;
}
size_t out = 0;
for (size_t i = 0; src[i] != '\0'; i++) {
if (isspace((unsigned char)src[i])) {
continue;
}
if ((out + 1) >= dst_size) {
return PM3_EOVFLOW;
}
dst[out++] = src[i];
}
dst[out] = '\0';
*dst_len = out;
return PM3_SUCCESS;
}
static int pcrypto_extract_priv_scalar_from_pk(const mbedtls_pk_context *pkctx,
mbedtls_ecp_group_id curveid,
uint8_t *out_priv, size_t out_priv_len) {
@@ -265,7 +192,7 @@ static int pcrypto_parse_ec_private_base64(const char *input,
char compact[PCRYPTO_MAX_KEY_INPUT] = {0};
size_t compact_len = 0;
int res = pcrypto_copy_without_whitespace(input, compact, sizeof(compact), &compact_len);
int res = str_copy_without_whitespace(input, compact, sizeof(compact), &compact_len);
if (res != PM3_SUCCESS || compact_len == 0) {
return PM3_EINVARG;
}
@@ -399,7 +326,7 @@ static int pcrypto_parse_ec_private_text(const char *input, bool allow_file_path
return PM3_EOVFLOW;
}
memcpy(normalized, input, input_len + 1);
pcrypto_trim_ascii_inplace(normalized);
str_trim_ascii_inplace(normalized);
if (normalized[0] == '\0') {
return PM3_EINVARG;
@@ -416,13 +343,13 @@ static int pcrypto_parse_ec_private_text(const char *input, bool allow_file_path
// Only unescape after path resolution fails, to avoid mutating valid paths
// (for example Windows paths containing '\t', '\n' or '\r').
pcrypto_unescape_newlines_inplace(normalized);
str_unescape_newlines_inplace(normalized);
uint8_t decoded[PCRYPTO_MAX_KEY_INPUT] = {0};
int decoded_len = -1;
char compact[PCRYPTO_MAX_KEY_INPUT] = {0};
size_t compact_len = 0;
if (pcrypto_copy_without_whitespace(normalized, compact, sizeof(compact), &compact_len) == PM3_SUCCESS &&
if (str_copy_without_whitespace(normalized, compact, sizeof(compact), &compact_len) == PM3_SUCCESS &&
compact_len > 0) {
decoded_len = hex_to_bytes(compact, decoded, sizeof(decoded));
}
@@ -740,7 +667,7 @@ static int pcrypto_parse_ec_public_base64(const char *input,
char compact[PCRYPTO_MAX_KEY_INPUT] = {0};
size_t compact_len = 0;
int res = pcrypto_copy_without_whitespace(input, compact, sizeof(compact), &compact_len);
int res = str_copy_without_whitespace(input, compact, sizeof(compact), &compact_len);
if (res != PM3_SUCCESS || compact_len == 0) {
return PM3_EINVARG;
}
@@ -777,7 +704,7 @@ static int pcrypto_parse_ec_public_text(const char *input, bool allow_file_path,
return PM3_EOVFLOW;
}
memcpy(normalized, input, input_len + 1);
pcrypto_trim_ascii_inplace(normalized);
str_trim_ascii_inplace(normalized);
if (normalized[0] == '\0') {
return PM3_EINVARG;
@@ -793,14 +720,14 @@ static int pcrypto_parse_ec_public_text(const char *input, bool allow_file_path,
}
// Only unescape after path resolution fails
pcrypto_unescape_newlines_inplace(normalized);
str_unescape_newlines_inplace(normalized);
// Try as hex string
uint8_t decoded[PCRYPTO_MAX_KEY_INPUT] = {0};
int decoded_len = -1;
char compact[PCRYPTO_MAX_KEY_INPUT] = {0};
size_t compact_len = 0;
if (pcrypto_copy_without_whitespace(normalized, compact, sizeof(compact), &compact_len) == PM3_SUCCESS &&
if (str_copy_without_whitespace(normalized, compact, sizeof(compact), &compact_len) == PM3_SUCCESS &&
compact_len > 0) {
decoded_len = hex_to_bytes(compact, decoded, sizeof(decoded));
}
+161 -6
View File
@@ -127,20 +127,176 @@ int fileExists(const char *filename) {
* @param filename
* @return
*/
static bool is_directory(const char *filename) {
bool path_is_directory(const char *path) {
if (path == NULL) {
return false;
}
#ifdef _WIN32
struct _stat st;
if (_stat(filename, &st) == -1)
if (_stat(path, &st) == -1)
return false;
#else
struct stat st;
// stat(filename, &st);
if (lstat(filename, &st) == -1)
if (lstat(path, &st) == -1)
return false;
#endif
return S_ISDIR(st.st_mode) != 0;
}
bool path_is_regular_file(const char *path) {
if (path == NULL) {
return false;
}
#ifdef _WIN32
struct _stat st;
if (_stat(path, &st) == -1)
return false;
#else
struct stat st;
if (stat(path, &st) == -1)
return false;
#endif
return S_ISREG(st.st_mode) != 0;
}
const char *path_basename(const char *path) {
if (path == NULL) {
return "";
}
const char *base = strrchr(path, '/');
const char *base_win = strrchr(path, '\\');
if (base == NULL || (base_win != NULL && base_win > base)) {
base = base_win;
}
return (base == NULL) ? path : (base + 1);
}
void path_basename_without_ext(const char *path, char *out, size_t out_len) {
if (out == NULL || out_len == 0) {
return;
}
out[0] = '\0';
const char *base = path_basename(path);
if (base[0] == '\0') {
return;
}
snprintf(out, out_len, "%s", base);
char *dot = strrchr(out, '.');
if (dot != NULL && dot != out) {
*dot = '\0';
}
}
static int qsort_path_cmp(const void *a, const void *b) {
const char *pa = (const char *)a;
const char *pb = (const char *)b;
return strcmp(pa, pb);
}
static char *path_list_slot(char *paths, size_t path_len, size_t index) {
return paths + (index * path_len);
}
int collect_file_paths_recursive(const char *dirpath, char *paths, size_t path_len,
size_t max_paths, size_t *count, bool include_hidden, size_t max_depth) {
if (dirpath == NULL || paths == NULL || path_len == 0 || count == NULL) {
return PM3_EINVARG;
}
DIR *dir = opendir(dirpath);
if (dir == NULL) {
return PM3_EFILE;
}
struct dirent *entry = NULL;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 ||
(include_hidden == false && entry->d_name[0] == '.')) {
continue;
}
char *fullpath = calloc(path_len, sizeof(char));
if (fullpath == NULL) {
closedir(dir);
return PM3_EMALLOC;
}
const char *sep = "";
size_t dir_len = strlen(dirpath);
if (dir_len > 0 && dirpath[dir_len - 1] != '/' && dirpath[dir_len - 1] != '\\') {
sep = PATHSEP;
}
if (snprintf(fullpath, path_len, "%s%s%s", dirpath, sep, entry->d_name) >= (int)path_len) {
free(fullpath);
continue;
}
if (path_is_directory(fullpath)) {
if (max_depth == 0) {
free(fullpath);
continue;
}
int res = collect_file_paths_recursive(fullpath, paths, path_len, max_paths, count, include_hidden, max_depth - 1);
free(fullpath);
if (res != PM3_SUCCESS) {
closedir(dir);
return res;
}
continue;
}
if (!path_is_regular_file(fullpath)) {
free(fullpath);
continue;
}
if (*count >= max_paths) {
free(fullpath);
closedir(dir);
return PM3_EOVFLOW;
}
if (snprintf(path_list_slot(paths, path_len, *count), path_len, "%s", fullpath) >= (int)path_len) {
free(fullpath);
continue;
}
free(fullpath);
(*count)++;
}
closedir(dir);
return PM3_SUCCESS;
}
int collect_resource_file_paths(const char *resource_dir, char *paths, size_t path_len,
size_t max_paths, size_t *count, bool include_hidden, size_t max_depth) {
if (resource_dir == NULL || resource_dir[0] == '\0' || paths == NULL || path_len == 0 || count == NULL) {
return PM3_EINVARG;
}
char *rootdir = NULL;
int res = searchFile(&rootdir, RESOURCES_SUBDIR, resource_dir, "", true);
if (res != PM3_SUCCESS) {
return res;
}
if (!path_is_directory(rootdir)) {
free(rootdir);
return PM3_EFILE;
}
*count = 0;
res = collect_file_paths_recursive(rootdir, paths, path_len, max_paths, count, include_hidden, max_depth);
free(rootdir);
if (res != PM3_SUCCESS) {
return res;
}
qsort(paths, *count, path_len, qsort_path_cmp);
return PM3_SUCCESS;
}
bool setDefaultPath(savePaths_t pathIndex, const char *path) {
if (pathIndex < spItemCount) {
@@ -2884,7 +3040,7 @@ static int filelist(const char *path, const char *ext, uint8_t last, bool tentat
tmp_fullpath[1023] = 0x00;
strncat(tmp_fullpath, namelist[i]->d_name, strlen(tmp_fullpath) - 1);
if (is_directory(tmp_fullpath)) {
if (path_is_directory(tmp_fullpath)) {
char newpath[1024];
if (strcmp(namelist[i]->d_name, ".") == 0 || strcmp(namelist[i]->d_name, "..") == 0)
@@ -3144,7 +3300,7 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con
return PM3_EINVARG;
}
if (is_directory(searchname)) {
if (path_is_directory(searchname)) {
return PM3_EINVARG;
}
@@ -3397,4 +3553,3 @@ int pm3_save_fm11rf08s_nonces(const char *fn, iso14a_fm11rf08s_nonces_with_data_
}
return PM3_SUCCESS;
}
+36
View File
@@ -114,6 +114,42 @@ typedef enum {
int fileExists(const char *filename);
/**
* @brief Check whether a path exists and is a directory.
*/
bool path_is_directory(const char *path);
/**
* @brief Check whether a path exists and is a regular file.
*/
bool path_is_regular_file(const char *path);
/**
* @brief Return the final path component, or an empty string for NULL input.
*/
const char *path_basename(const char *path);
/**
* @brief Copy the final path component without its last file extension.
*/
void path_basename_without_ext(const char *path, char *out, size_t out_len);
/**
* @brief Recursively collect regular file paths under a directory into fixed-size slots.
*
* A max_depth of 0 scans only dirpath and does not descend into subdirectories.
*/
int collect_file_paths_recursive(const char *dirpath, char *paths, size_t path_len,
size_t max_paths, size_t *count, bool include_hidden, size_t max_depth);
/**
* @brief Resolve a resources subdirectory and recursively collect regular file paths from it.
*
* A max_depth of 0 scans only the resolved resource_dir and does not descend into subdirectories.
*/
int collect_resource_file_paths(const char *resource_dir, char *paths, size_t path_len,
size_t max_paths, size_t *count, bool include_hidden, size_t max_depth);
// set a path in the path list g_session.defaultPaths
bool setDefaultPath(savePaths_t pathIndex, const char *path);
+72
View File
@@ -1944,3 +1944,75 @@ size_t unduplicate(uint8_t *d, size_t n, const uint8_t item_n) {
return write_index;
}
void str_trim_ascii_inplace(char *s) {
if (s == NULL) {
return;
}
size_t start = 0;
size_t len = strlen(s);
while (start < len && isspace((unsigned char)s[start])) {
start++;
}
while (len > start && isspace((unsigned char)s[len - 1])) {
len--;
}
if (start > 0) {
memmove(s, s + start, len - start);
}
s[len - start] = '\0';
}
void str_unescape_newlines_inplace(char *s) {
if (s == NULL) {
return;
}
size_t read_pos = 0;
size_t write_pos = 0;
size_t len = strlen(s);
while (read_pos < len) {
if (s[read_pos] == '\\' && (read_pos + 1) < len) {
char esc = s[read_pos + 1];
if (esc == 'n') {
s[write_pos++] = '\n';
read_pos += 2;
continue;
}
if (esc == 'r') {
s[write_pos++] = '\r';
read_pos += 2;
continue;
}
if (esc == 't') {
s[write_pos++] = '\t';
read_pos += 2;
continue;
}
}
s[write_pos++] = s[read_pos++];
}
s[write_pos] = '\0';
}
int str_copy_without_whitespace(const char *src, char *dst, size_t dst_size, size_t *dst_len) {
if (src == NULL || dst == NULL || dst_len == NULL || dst_size == 0) {
return PM3_EINVARG;
}
size_t out = 0;
for (size_t i = 0; src[i] != '\0'; i++) {
if (isspace((unsigned char)src[i])) {
continue;
}
if ((out + 1) >= dst_size) {
return PM3_EOVFLOW;
}
dst[out++] = src[i];
}
dst[out] = '\0';
*dst_len = out;
return PM3_SUCCESS;
}
+15
View File
@@ -215,4 +215,19 @@ uint8_t get_highest_frequency(const uint8_t *d, uint8_t n);
size_t unduplicate(uint8_t *d, size_t n, const uint8_t item_n);
/**
* @brief Trim leading and trailing ASCII whitespace from a mutable string.
*/
void str_trim_ascii_inplace(char *s);
/**
* @brief Replace escaped \n, \r, and \t sequences with their control characters in-place.
*/
void str_unescape_newlines_inplace(char *s);
/**
* @brief Copy a string while dropping all ASCII whitespace characters.
*/
int str_copy_without_whitespace(const char *src, char *dst, size_t dst_size, size_t *dst_len);
#endif