Files
2026-08-31 22:49:42 +08:00

279 lines
10 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "c_Hex.h"
#include <assert.h>
#include <stdio.h>
#include <ctype.h>
#include <c_Memory.h>
/* -------------------------------------------------------------------------------------------------------------- */
/* */
#define BYTE_AT(A, I) (*(((unsigned char*)(A))+(I)))
/* ================================================================================ */
void c_Hex_DumpBin(const void* data, c_size_t size, int line_size){
for(c_size_t i=0; i<size; i++){
unsigned char b = BYTE_AT(data, i);
for(int8_t d=7; d>=0; d--){
putchar((b & (1<<d))?'1':'0');
}
if(((i+1)*8)%line_size==0 || (i+1)==size){
putchar('\n');
}
}
}
void c_Hex_Dump(const void *data, c_size_t size) {
c_Hex_DumpTo(data, size, (void (*)(const char *, ...)) printf);
}
void c_Hex_DumpTo(const void *data, c_size_t size, void (*dump)(const char*, ...)) {
char ascii[17];
size_t i, j;
ascii[16] = '\0';
for (i = 0; i < size; ++i) {
if (i % 16 == 0) {
dump("%08"C_PRIx" ", i);
}
dump("%02X ", ((unsigned char*)data)[i]);
if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
ascii[i % 16] = ((unsigned char*)data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
dump(" ");
if ((i+1) % 16 == 0) {
dump("| %s \n", ascii);
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
dump(" ");
}
for (j = (i+1) % 16; j < 16; ++j) {
dump(" ");
}
dump("| %s \n", ascii);
}
}
}
}
/* ================================================================================ */
//
// static const uint8_t LOOKUP_TABLE_LOWER[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
// static const uint8_t LOOKUP_TABLE_UPPER[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
//
// char* c_Hex_BinToHex(const uint8_t *data
// , c_size_t data_size
// , const bool isUpperCase
// , const c_ByteOrder_t byteOrder)
// {
//
// assert(data);
// assert(data_size > 0);
//
// c_size_t i;
// const c_size_t buffer_size = (data_size << 1 ) + 1;
//
// char* buffer = C_ALLOC(buffer_size);
// if (!buffer) {
// return NULL;
// }
// assert(buffer);
//
// const uint8_t* lookup = isUpperCase?LOOKUP_TABLE_UPPER:LOOKUP_TABLE_LOWER;
//
// for(i =0; i<data_size; i++){
// const c_size_t index = (byteOrder == kByteOrder_BigEndian) ? i : (data_size - i - 1);
// buffer[(i<<1)] = (char)lookup[(data[index] >> 4) & 0x0F];
// buffer[(i<<1) + 1] = (char)lookup[(data[index] & 0x0F)];
// }
//
// buffer[buffer_size] = '\0';
//
// return buffer;
// }
/* ================================================================================ */
#if 0
static const unsigned char TBL[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 58, 59, 60, 61,
62, 63, 64, 10, 11, 12, 13, 14, 15, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 10, 11, 12, 13, 14, 15
};
static const unsigned char *LOOKUP = TBL - 48;
uint8_t* c_Hex_HexToBin(const char* hex, const c_size_t hex_size, c_size_t* returnSize){
uint8_t b1, b2;
c_size_t bin_size = hex_size >> 1;
uint8_t* buffer = C_ALLOC(bin_size);
if (!buffer) {
return NULL;
}
assert(buffer);
const char* in = hex;
const char* end = in + hex_size;
while(in < end){
b1 = LOOKUP[(uint8_t)*(in++)];
b2 = LOOKUP[(uint8_t)*(in++)];
*(buffer) = ( b1 << 4) | b2;
buffer++;
}
if (returnSize) {
*returnSize = bin_size;
}
return buffer - bin_size;
}
void c_Hex_Free(void* ptr) {
C_FREE(ptr);
}
#endif
/**
* @brief 内部私有:将单个十六进制字符转换为合规的 4 位无符号半字节(Nibble)
*
* 🌟【高吞吐无损硬容错】:完美兼容大小写,一旦遭遇非法杂质字符立刻返回 -1 触发拦截
*/
C_STATIC_FORCE_INLINE
int c_Hex_CharToNibble(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; // 捕获到非法十六进制元素
}
/**
* @brief 工业级二进制安全:十六进制文本字符串逆向解析还原为真实二进制字节流
*
* @param hex_str 待解析的标准十六进制文本字符串(以 '\0' 截止,如 "4A00FE"
* @param out_bin 由外部声明传入、用于承接导出的二进制字节流物理缓冲区首地址
* @param bin_max_cap 外部缓冲区 out_bin 的最大物理插槽配额上限限制(防缓冲区溢出踩踏)
* @param out_size 🌟【物理边界锁】:成功转化后,通过此二级指针强行传出实际生成的【真实字节总个数 (N)】
*/
c_err_t c_Hex_HexToBin(const char* hex_str, void* out_bin, c_size_t bin_max_cap, c_size_t* out_size) {
// 1. 前置毒入参非法强拦截
if (!hex_str || !out_bin || !out_size || bin_max_cap == 0) {
return C_ERR_PARAM;
}
c_size_t hex_len = strlen(hex_str);
if (hex_len == 0) {
*out_size = 0;
return C_ERR_EMPTY;
}
// 🌟【硬核格式契约 1】:十六进制字符串每 2 个可显示字符拼接成 1 个完整字节。
// 如果总字符长度为奇数,说明控制流发生非对称残缺,属于恶意或不合规输入,立刻原地熔断!
if ((hex_len & 1) != 0) {
*out_size = 0;
return C_ERR_PARAM;
}
// 计算出本次还原所期望开辟生成的精确二进制字节体量
c_size_t required_bin_size = hex_len >> 1;
// 🌟【硬核格式契约 2】:前置上界高位拦截。
// 若外部承接缓冲区的物理最大上限 capacity 根本吃不下这批数据,强行抛出越界异常,物理粉碎堆溢出!
if (required_bin_size > bin_max_cap) {
*out_size = 0;
return C_ERR_OUTOFBOUND;
}
unsigned char* bin_buf = (unsigned char*)out_bin;
// 2. 启动双字高频滑窗位移状态机
for (c_size_t i = 0; i < required_bin_size; i++) {
// 每轮循环,密集抓取 2 个相邻的十六进制可显示字符
char high_char = hex_str[i << 1];
char low_char = hex_str[(i << 1) + 1];
int high_nibble = c_Hex_CharToNibble(high_char);
int low_nibble = c_Hex_CharToNibble(low_char);
// 🌟【硬核格式契约 3】:如果沿途解包走查发现夹杂了任何非十六进制可打印杂质字符(如 G),
// 判定该报文已被严重污染,立刻启动自毁灭机制清空已生成数据,严肃报错退出!
if (high_nibble < 0 || low_nibble < 0) {
memset(out_bin, 0, bin_max_cap); // 洗净泄露
*out_size = 0;
return C_ERR_PARAM;
}
// 3. 高低位半字节(Nibble)按位执行物理高位填补拼接:(High << 4) | Low
bin_buf[i] = (unsigned char)((high_nibble << 4) | low_nibble);
}
// 4. 锁定物理绝对边界传出,不依附任何文本 \0 截断
*out_size = required_bin_size;
return C_ERR_OK;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
/**
* @brief 工业级二进制安全:二进制字节流正向解析还原为标准十六进制文本字符串
*
* @param in_bin 待转化的二进制字节流物理缓冲区首地址(二进制安全,支持 \0 内置流)
* @param bin_size 二进制字节流的绝对有效物理字节总大小 (N)
* @param uppercase 控制开关:true 导出为大写十六进制字符串(如 "4A00FE");false 导出为小写(如 "4a00fe"
* @param out_hex_str 由外部声明传入、用于承接导出的十六进制可写文本缓冲区起始地址
* @param hex_max_cap 外部文本缓冲区的最大物理插槽配额上限限制(防缓冲区溢出踩踏)
*/
c_err_t c_Hex_BinToHex(const void* in_bin, c_size_t bin_size, bool uppercase, char* out_hex_str, c_size_t hex_max_cap) {
// 1. 前置毒入参非法强拦截
if (!in_bin || !out_hex_str || hex_max_cap == 0) {
return C_ERR_PARAM;
}
if (bin_size == 0) {
if (hex_max_cap > 0) {
out_hex_str[0] = '\0';
}
return C_ERR_EMPTY;
}
// 🌟【硬核算术加固】:前置逆向除法与乘位溢出防御审计
// 计算出本次还原所期望生成的文本矩阵绝对字节体量:N * 2 + 1 (含末尾 \0 终止符)
if (((c_size_t)-1 - 1) / 2 < bin_size) {
return C_ERR_NOMEM;
}
c_size_t required_hex_size = (bin_size << 1) + 1;
// 🌟【硬核格式契约】:前置上界高位拦截。
// 若外部承接缓冲区的物理最大上限 capacity 根本吃不下这批数据,强行抛出越界异常,物理粉碎堆溢出!
if (required_hex_size > hex_max_cap) {
return C_ERR_OUTOFBOUND;
}
const unsigned char* bin_buf = (const unsigned char*)in_bin;
// 弹性选择十六进制多态高速查找字母表
const char* hex_digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
// 2. 启动单向滑窗转换状态机
for (c_size_t i = 0; i < bin_size; i++) {
unsigned char byte_val = bin_buf[i];
// 分离高、低位半字节(Nibble)按位定位至字母表矩阵
out_hex_str[i << 1] = hex_digits[(byte_val >> 4) & 0x0F]; // 提取高 4 位
out_hex_str[(i << 1) + 1] = hex_digits[byte_val & 0x0F]; // 提取低 4 位
}
// 3. 完美格式化合拢:在尾端强制安全截断注入标准 C 风格 '\0' 终止符
out_hex_str[bin_size << 1] = '\0';
return C_ERR_OK;
}