Files
cKit/Foundation/c_Hex.c
T

279 lines
10 KiB
C
Raw Normal View History

2026-08-31 22:49:42 +08:00
#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;
}