279 lines
10 KiB
C
279 lines
10 KiB
C
#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;
|
||
}
|
||
|