String
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
#ifndef INCLUDED_C_HEX_H
|
||||
#define INCLUDED_C_HEX_H
|
||||
|
||||
#ifndef INCLUDED_C_TYPES_H
|
||||
#include <c_Types.h>
|
||||
#endif /*INCLUDED_C_TYPES_H*/
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------------------- */
|
||||
/* */
|
||||
|
||||
|
||||
void c_Hex_DumpBin(const void* data, c_size_t size, int line_size);
|
||||
|
||||
void c_Hex_Dump(const void *data, c_size_t size);
|
||||
|
||||
void c_Hex_DumpTo(const void *data, c_size_t size, void (*dump)(const char*, ...));
|
||||
|
||||
c_err_t c_Hex_HexToBin(const char* hex_str, void* out_bin, c_size_t bin_max_cap, c_size_t* out_size);
|
||||
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
|
||||
/* ================================================================================ */
|
||||
#define C_HEX_SET_UINT8(array, idx, u8v) ((array)[(idx)]=(u8v)&0xFF)
|
||||
|
||||
#define C_HEX_SET_UINT16_BE(array, idx, u16v) \
|
||||
do{ \
|
||||
(array)[(idx)] = ((u16v) >> 8) & 0xFF; \
|
||||
(array)[(idx)+1] = ((u16v)) & 0xFF; \
|
||||
}while(0)
|
||||
|
||||
#define C_HEX_SET_UINT16_LE(array, idx, u16v) \
|
||||
do{ \
|
||||
(array)[(idx)] = ((u16v)) & 0xFF; \
|
||||
(array)[(idx)+1] = ((u16v) >> 8) & 0xFF; \
|
||||
}while(0)
|
||||
|
||||
#define C_HEX_SET_UINT24_BE(array, idx, u24v) \
|
||||
do{ \
|
||||
(array)[(idx)] = ((u24v) >> 16) & 0xFF; \
|
||||
(array)[(idx)+1] = ((u24v) >> 8) & 0xFF; \
|
||||
(array)[(idx)+2] = ((u24v)) & 0xFF; \
|
||||
}while(0)
|
||||
|
||||
#define C_HEX_SET_UINT24_LE(array, idx, u24v) \
|
||||
do{ \
|
||||
(array)[(idx)] = ((u24v)) & 0xFF; \
|
||||
(array)[(idx)+1] = ((u24v) >> 8) & 0xFF; \
|
||||
(array)[(idx)+2] = ((u24v) >> 16) & 0xFF; \
|
||||
}while(0)
|
||||
|
||||
#define C_HEX_SET_UINT32_BE(array, idx, u32v) \
|
||||
do{ \
|
||||
(array)[(idx)] = ((u32v) >> 24) & 0xFF; \
|
||||
(array)[(idx)+1] = ((u32v) >> 16) & 0xFF; \
|
||||
(array)[(idx)+2] = ((u32v) >> 8) & 0xFF; \
|
||||
(array)[(idx)+3] = ((u32v)) & 0xFF; \
|
||||
}while(0)
|
||||
|
||||
#define C_HEX_SET_UINT32_LE(array, idx, u32v) \
|
||||
do{ \
|
||||
(array)[(idx)] = ((u32v)) & 0xFF; \
|
||||
(array)[(idx)+1] = ((u32v) >> 8) & 0xFF; \
|
||||
(array)[(idx)+2] = ((u32v) >> 16) & 0xFF; \
|
||||
(array)[(idx)+3] = ((u32v) >> 24) & 0xFF; \
|
||||
}while(0)
|
||||
|
||||
#define C_HEX_SET_UINT64_BE(array, idx, u64v) \
|
||||
do{ \
|
||||
(array)[(idx)] = ((u64v) >> 56) & 0xFF; \
|
||||
(array)[(idx)+1] = ((u64v) >> 48) & 0xFF; \
|
||||
(array)[(idx)+2] = ((u64v) >> 40) & 0xFF; \
|
||||
(array)[(idx)+3] = ((u64v) >> 32) & 0xFF; \
|
||||
(array)[(idx)+4] = ((u64v) >> 24) & 0xFF; \
|
||||
(array)[(idx)+5] = ((u64v) >> 16) & 0xFF; \
|
||||
(array)[(idx)+6] = ((u64v) >> 8) & 0xFF; \
|
||||
(array)[(idx)+7] = ((u64v)) & 0xFF; \
|
||||
}while(0)
|
||||
|
||||
#define C_HEX_SET_UINT64_LE(array, idx, u64v) \
|
||||
do{ \
|
||||
(array)[(idx)] = ((u64v)) & 0xFF; \
|
||||
(array)[(idx)+1] = ((u64v) >> 8) & 0xFF; \
|
||||
(array)[(idx)+2] = ((u64v) >> 16) & 0xFF; \
|
||||
(array)[(idx)+3] = ((u64v) >> 24) & 0xFF; \
|
||||
(array)[(idx)+4] = ((u64v) >> 32) & 0xFF; \
|
||||
(array)[(idx)+5] = ((u64v) >> 40) & 0xFF; \
|
||||
(array)[(idx)+6] = ((u64v) >> 48) & 0xFF; \
|
||||
(array)[(idx)+7] = ((u64v) >> 56) & 0xFF; \
|
||||
}while(0)
|
||||
|
||||
#define C_HEX_GET_UINT8(array, idx) (((array)[(idx)])&0xFF)
|
||||
|
||||
#define C_HEX_GET_UINT16_BE(array, idx) ((((array)[(idx)]&0xFF)<<8) | ((array)[(idx)+1] & 0xFF))
|
||||
#define C_HEX_GET_UINT16_LE(array, idx) (((array)[(idx)]&0xFF) | (((array)[(idx)+1] & 0xFF)<<8) )
|
||||
|
||||
#define C_HEX_GET_UINT24_BE(array, idx) ( (((array)[(idx)]&0xFF)<<16) | (((array)[(idx)+1]&0xFF)<<8) | ((array)[(idx)+2] & 0xFF) )
|
||||
#define C_HEX_GET_UINT24_LE(array, idx) ( ((array)[(idx)]&0xFF) | (((array)[(idx)+1]&0xFF)<<8) | (((array)[(idx)+2]&0xFF)<<16) )
|
||||
|
||||
#define C_HEX_GET_UINT32_BE(array, idx) ( \
|
||||
(((array)[(idx)]&0xFF)<<24) \
|
||||
| (((array)[(idx)+1]&0xFF)<<16) \
|
||||
| (((array)[(idx)+2]&0xFF)<<8) \
|
||||
| ((array)[(idx)+3] & 0xFF) )
|
||||
|
||||
#define C_HEX_GET_UINT32_LE(array, idx) ( \
|
||||
((array)[(idx)]&0xFF) \
|
||||
| (((array)[(idx)+1]&0xFF)<<8) \
|
||||
| (((array)[(idx)+2]&0xFF)<<16) \
|
||||
| (((array)[(idx)+3]&0xFF)<<24) )
|
||||
|
||||
|
||||
#define C_HEX_GET_UINT64_BE(array, idx) ( \
|
||||
((uint64_t)((array)[(idx)]&0xFF)<<56) \
|
||||
| ((uint64_t)((array)[(idx)+1]&0xFF)<<48) \
|
||||
| ((uint64_t)((array)[(idx)+2]&0xFF)<<40) \
|
||||
| ((uint64_t)((array)[(idx)+3]&0xFF)<<32) \
|
||||
| ((uint64_t)((array)[(idx)+4]&0xFF)<<24) \
|
||||
| ((uint64_t)((array)[(idx)+5]&0xFF)<<16) \
|
||||
| ((uint64_t)((array)[(idx)+6]&0xFF)<<8) \
|
||||
| ((uint64_t)(array)[(idx)+7] & 0xFF) )
|
||||
|
||||
#define C_HEX_GET_UINT64_LE(array, idx) ( \
|
||||
((uint64_t)(array)[(idx)]&0xFF) \
|
||||
| ((uint64_t)((array)[(idx)+1]&0xFF)<<8) \
|
||||
| ((uint64_t)((array)[(idx)+2]&0xFF)<<16) \
|
||||
| ((uint64_t)((array)[(idx)+3]&0xFF)<<24) ) \
|
||||
| ((uint64_t)((array)[(idx)+4]&0xFF)<<32) ) \
|
||||
| ((uint64_t)((array)[(idx)+5]&0xFF)<<40) ) \
|
||||
| ((uint64_t)((array)[(idx)+6]&0xFF)<<48) ) \
|
||||
| ((uint64_t)((array)[(idx)+7]&0xFF)<<56) )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /*INCLUDED_C_HEX_H*/
|
||||
@@ -0,0 +1,90 @@
|
||||
#include "c_Hex.h"
|
||||
#include "c_Test.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
TEST_CASE(test_c_Hex_BinToHex_A) {
|
||||
// 🌟【场景 A】:输入包含 0x00 中途截断干扰项的二进制数据密钥流
|
||||
// 预期转化为大写十六进制字符串后必须为:"4A00FE1B"
|
||||
const unsigned char raw_bin_stream[] = { 0x4A, 0x00, 0xFE, 0x1B };
|
||||
c_size_t bin_len = sizeof(raw_bin_stream);
|
||||
|
||||
char hex_output_buffer[16];
|
||||
|
||||
// 1. 验证大写形式正向导出
|
||||
c_err_t err = c_Hex_BinToHex(raw_bin_stream, bin_len, true, hex_output_buffer, 16);
|
||||
ASSERT_INT_EQ(C_ERR_OK, err);
|
||||
ASSERT_TRUE(strcmp("4A00FE1B", hex_output_buffer) == 0); // 完美跨越 00 截断并成功输出大写文本
|
||||
|
||||
// 2. 验证小写形式正向导出
|
||||
err = c_Hex_BinToHex(raw_bin_stream, bin_len, false, hex_output_buffer, 16);
|
||||
ASSERT_INT_EQ(C_ERR_OK, err);
|
||||
ASSERT_TRUE(strcmp("4a00fe1b", hex_output_buffer) == 0); // 成功输出小写文本
|
||||
}
|
||||
|
||||
TEST_CASE(test_c_Hex_BinToHex_B) {
|
||||
const unsigned char dummy_bin[] = { 0xAA, 0xBB, 0xCC };
|
||||
char dummy_hex_out[16];
|
||||
|
||||
// 🌟【场景 B】:外部承接缓冲区分配空间配额严重不足(仅给 5 字节,但 3 字节输入需要 3*2+1=7 字节空间)
|
||||
// 预期控制流必须前置高位拦截,原地拒绝并抛出越界异常状态码 C_ERR_OUTOFBOUND,粉碎缓冲区踩踏溢出!
|
||||
ASSERT_INT_EQ(C_ERR_OUTOFBOUND, c_Hex_BinToHex(dummy_bin, 3, true, dummy_hex_out, 5));
|
||||
|
||||
// 🌟【场景 C】:验证空仓异常状态码拦截返回
|
||||
ASSERT_INT_EQ(C_ERR_EMPTY, c_Hex_BinToHex(dummy_bin, 0, true, dummy_hex_out, 16));
|
||||
ASSERT_TRUE(dummy_hex_out[0] == '\0'); // 确保空输入时尾端完好写入空截止符
|
||||
|
||||
// 🌟【场景 D】:验证毒参数非合规强拦截线
|
||||
ASSERT_INT_EQ(C_ERR_PARAM, c_Hex_BinToHex(NULL, 5, true, dummy_hex_out, 16));
|
||||
ASSERT_INT_EQ(C_ERR_PARAM, c_Hex_BinToHex(dummy_bin, 5, true, NULL, 16));
|
||||
}
|
||||
|
||||
TEST_CASE(test_c_Hex_HexToBin_A) {
|
||||
// 🌟【场景 A】:输入一个大小写变长混合、且正中央故意包含 00 以便生成二进制 \0 数据的十六进制文本
|
||||
// 预期对应的物理二进制内容: 0x4A, 0x00, 0xFE, 0x1B
|
||||
const char* mixed_hex_string = "4a00FE1b";
|
||||
|
||||
unsigned char bin_output_buffer[16];
|
||||
c_size_t actual_generated_size = 0;
|
||||
|
||||
c_err_t err = c_Hex_HexToBin(mixed_hex_string, bin_output_buffer, 16, &actual_generated_size);
|
||||
ASSERT_INT_EQ(C_ERR_OK, err);
|
||||
|
||||
// 绝对物理长度必须精准卡死导出为 4 字节,不被 00 干扰斩断
|
||||
ASSERT_INT_EQ(4, (int)actual_generated_size);
|
||||
|
||||
// 逐字节穿透核验真实的十六进制数字指纹内容
|
||||
ASSERT_INT_EQ(0x4A, bin_output_buffer[0]);
|
||||
ASSERT_INT_EQ(0x00, bin_output_buffer[1]); // 验证 \0 无损存储
|
||||
ASSERT_INT_EQ(0xFE, bin_output_buffer[2]);
|
||||
ASSERT_INT_EQ(0x1B, bin_output_buffer[3]);
|
||||
}
|
||||
|
||||
TEST_CASE(test_c_Hex_HexToBin_B) {
|
||||
unsigned char dummy_buf[16];
|
||||
c_size_t dummy_size = 0;
|
||||
|
||||
// 🌟【场景 B】:输入奇数位残缺字面量(长度 5),无法配对,预期必须爆发 C_ERR_PARAM 拦截
|
||||
ASSERT_INT_EQ(C_ERR_PARAM, c_Hex_HexToBin("A0F1B", dummy_buf, 16, &dummy_size));
|
||||
|
||||
// 🌟【场景 C】:注入了非十六进制字母表上限的污染杂质字符 'G',预期必须原地自毁熔断报错
|
||||
ASSERT_INT_EQ(C_ERR_PARAM, c_Hex_HexToBin("A0F1G2", dummy_buf, 16, &dummy_size));
|
||||
ASSERT_INT_EQ(0, (int)dummy_size);
|
||||
|
||||
// 🌟【场景 D】:外部缓冲区承接上限过低(仅给 2 字节容量,但需要 3 字节),预期触发越界保护锁
|
||||
ASSERT_INT_EQ(C_ERR_OUTOFBOUND, c_Hex_HexToBin("4A00FE", dummy_buf, 2, &dummy_size));
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 5. 主集成入口
|
||||
// ==========================================
|
||||
int main(void) {
|
||||
TEST_START(C_Hex_BinToHex_TestSuite);
|
||||
RUN_TEST(test_c_Hex_BinToHex_A);
|
||||
RUN_TEST(test_c_Hex_BinToHex_B);
|
||||
|
||||
RUN_TEST(test_c_Hex_HexToBin_A);
|
||||
RUN_TEST(test_c_Hex_HexToBin_B);
|
||||
TEST_REPORT();
|
||||
return (g_test_registry.failed_count > 0 ? 1 : 0);
|
||||
}
|
||||
@@ -145,6 +145,17 @@ void c_StringBuffer_Clear(c_StringBuffer_t* self) {
|
||||
|
||||
/* --- Explicit String-Wrapper Interfaces --- */
|
||||
|
||||
c_err_t c_StringBuffer_PopBack(c_StringBuffer_t* self) {
|
||||
if (!self) return C_ERR_PARAM;
|
||||
if (self->size == 0) return C_ERR_EMPTY;
|
||||
return c_StringBuffer_RemoveAt(self, self->size-1, 1);
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_AppendChar(c_StringBuffer_t* self, char ch) {
|
||||
if (!self || !self->buffer) return C_ERR_PARAM;
|
||||
return c_StringBuffer_Append(self, (char*)&ch, 1);
|
||||
}
|
||||
|
||||
c_err_t c_StringBuffer_AppendStr(c_StringBuffer_t* self, const char* string) {
|
||||
if (!string) return C_ERR_PARAM;
|
||||
return c_StringBuffer_Append(self, string, strlen(string));
|
||||
|
||||
@@ -60,6 +60,7 @@ c_err_t c_StringBuffer_RemoveAt(c_StringBuffer_t* self, c_size_t index, c_size_t
|
||||
|
||||
void c_StringBuffer_Clear(c_StringBuffer_t* self);
|
||||
|
||||
c_err_t c_StringBuffer_AppendChar(c_StringBuffer_t* self, char ch);
|
||||
c_err_t c_StringBuffer_AppendStr(c_StringBuffer_t* self, const char* string);
|
||||
c_err_t c_StringBuffer_PrependStr(c_StringBuffer_t* self, const char* string);
|
||||
c_err_t c_StringBuffer_InsertStrAt(c_StringBuffer_t* self, const char* string, c_size_t index);
|
||||
@@ -135,4 +136,7 @@ c_err_t c_StringBuffer_strtoul(const c_StringBuffer_t* self, c_size_t start_inde
|
||||
*/
|
||||
c_err_t c_StringBuffer_SetLength(c_StringBuffer_t* sb, c_size_t new_length);
|
||||
|
||||
|
||||
c_err_t c_StringBuffer_PopBack(c_StringBuffer_t* self);
|
||||
|
||||
#endif /*INCLUDED_C_STRINGBUFFER_H*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <c_StringList.h>
|
||||
|
||||
c_err_t c_StringList_Init(c_StringList* self, c_size_t capacity, c_Allocator_t* allocator) {
|
||||
c_err_t c_StringList_Init(c_StringList_t* self, c_size_t capacity, c_Allocator_t* allocator) {
|
||||
if (!self) return C_ERR_PARAM;
|
||||
|
||||
self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator;
|
||||
@@ -19,7 +19,7 @@ c_err_t c_StringList_Init(c_StringList* self, c_size_t capacity, c_Allocator_t*
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
void c_StringList_Clear(c_StringList* self) {
|
||||
void c_StringList_Clear(c_StringList_t* self) {
|
||||
if (!self || !self->strings) return;
|
||||
|
||||
// 【核心深清算】:必须先顺着槽位将当前持有的每一个独占字符串物理火化,退还给内置分配器
|
||||
@@ -32,7 +32,7 @@ void c_StringList_Clear(c_StringList* self) {
|
||||
self->size = 0;
|
||||
}
|
||||
|
||||
void c_StringList_Destroy(c_StringList* self) {
|
||||
void c_StringList_Destroy(c_StringList_t* self) {
|
||||
if (!self) return;
|
||||
|
||||
if (self->strings) {
|
||||
@@ -48,7 +48,7 @@ void c_StringList_Destroy(c_StringList* self) {
|
||||
* @note 强异常安全性:若分配器因碎片满或爆仓返回 NULL,原有数据指针及老矩阵原样完整留存,绝不发生物理跑飞
|
||||
*/
|
||||
C_STATIC_FORCE_INLINE
|
||||
bool c_StringList_EnsureCapacity(c_StringList* self) {
|
||||
bool c_StringList_EnsureCapacity(c_StringList_t* self) {
|
||||
if (self->size < self->capacity) return true;
|
||||
|
||||
c_size_t old_bytes = self->capacity * sizeof(char*);
|
||||
@@ -73,7 +73,7 @@ bool c_StringList_EnsureCapacity(c_StringList* self) {
|
||||
// 2. 核心深度值复制增删控制操作 API
|
||||
// ==================================================================================================================
|
||||
|
||||
c_err_t c_StringList_InsertAt(c_StringList* self, c_size_t index, const char* str) {
|
||||
c_err_t c_StringList_InsertAt(c_StringList_t* self, c_size_t index, const char* str) {
|
||||
if (!self || !str || index > self->size) return C_ERR_PARAM;
|
||||
if (!c_StringList_EnsureCapacity(self)) return C_ERR_NOMEM;
|
||||
|
||||
@@ -93,11 +93,11 @@ c_err_t c_StringList_InsertAt(c_StringList* self, c_size_t index, const char* st
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
c_err_t c_StringList_Add(c_StringList* self, const char* str) {
|
||||
c_err_t c_StringList_Add(c_StringList_t* self, const char* str) {
|
||||
return c_StringList_InsertAt(self, self->size, str); // 末尾追加
|
||||
}
|
||||
|
||||
c_err_t c_StringList_RemoveAt(c_StringList* self, c_size_t index) {
|
||||
c_err_t c_StringList_RemoveAt(c_StringList_t* self, c_size_t index) {
|
||||
if (!self || index >= self->size || !self->strings) return C_ERR_PARAM;
|
||||
|
||||
// ① 定点火化销毁当前槽位持有的独占堆字符串,归还空间
|
||||
@@ -118,7 +118,7 @@ c_err_t c_StringList_RemoveAt(c_StringList* self, c_size_t index) {
|
||||
// 3. 高级功能:链表深克隆与高速去重
|
||||
// ==================================================================================================================
|
||||
|
||||
c_err_t c_StringList_Clone(c_StringList* dest, const c_StringList* src) {
|
||||
c_err_t c_StringList_Clone(c_StringList_t* dest, const c_StringList_t* src) {
|
||||
if (!dest || !src || dest == src || !src->strings) return C_ERR_PARAM;
|
||||
|
||||
// 清算 dest 先前绑定的生命线
|
||||
@@ -139,7 +139,7 @@ c_err_t c_StringList_Clone(c_StringList* dest, const c_StringList* src) {
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
c_err_t c_StringList_Deduplicate(c_StringList* self) {
|
||||
c_err_t c_StringList_Deduplicate(c_StringList_t* self) {
|
||||
if (!self || self->size <= 1 || !self->strings) return C_ERR_OK;
|
||||
|
||||
// O(N^2) 经典原位原地重排去重流
|
||||
|
||||
+11
-11
@@ -18,32 +18,32 @@ typedef struct {
|
||||
c_size_t size; // Current active string rows stored
|
||||
c_size_t capacity; // Max allocated capacity bounds of the internal pointer matrix
|
||||
c_Allocator_t allocator;
|
||||
} c_StringList;
|
||||
} c_StringList_t;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
c_err_t c_StringList_Init(c_StringList* self, c_size_t capacity, c_Allocator_t* allocator);
|
||||
void c_StringList_Destroy(c_StringList* self);
|
||||
c_err_t c_StringList_Init(c_StringList_t* self, c_size_t capacity, c_Allocator_t* allocator);
|
||||
void c_StringList_Destroy(c_StringList_t* self);
|
||||
|
||||
// 核心操作 API (安全深拷贝值复制模式)
|
||||
c_err_t c_StringList_Add(c_StringList* self, const char* str);
|
||||
c_err_t c_StringList_InsertAt(c_StringList* self, c_size_t index, const char* str);
|
||||
c_err_t c_StringList_RemoveAt(c_StringList* self, c_size_t index);
|
||||
void c_StringList_Clear(c_StringList* self);
|
||||
c_err_t c_StringList_Add(c_StringList_t* self, const char* str);
|
||||
c_err_t c_StringList_InsertAt(c_StringList_t* self, c_size_t index, const char* str);
|
||||
c_err_t c_StringList_RemoveAt(c_StringList_t* self, c_size_t index);
|
||||
void c_StringList_Clear(c_StringList_t* self);
|
||||
|
||||
// 高级功能接口
|
||||
c_err_t c_StringList_Clone(c_StringList* dest, const c_StringList* src);
|
||||
c_err_t c_StringList_Deduplicate(c_StringList* self);
|
||||
c_err_t c_StringList_Clone(c_StringList_t* dest, const c_StringList_t* src);
|
||||
c_err_t c_StringList_Deduplicate(c_StringList_t* self);
|
||||
|
||||
// 极致高频内联只读窥探接口
|
||||
C_STATIC_FORCE_INLINE
|
||||
c_size_t c_StringList_Size(const c_StringList* self) {
|
||||
c_size_t c_StringList_Size(const c_StringList_t* self) {
|
||||
return self ? self->size : 0; // O(1) 实时读取
|
||||
}
|
||||
|
||||
C_STATIC_FORCE_INLINE
|
||||
const char* c_StringList_Get(const c_StringList* self, c_size_t index) {
|
||||
const char* c_StringList_Get(const c_StringList_t* self, c_size_t index) {
|
||||
if (!self || index >= self->size || !self->strings) return NULL;
|
||||
return self->strings[index]; // 零拷贝原位返回
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ TEST_CASE(test_string_list_polymorphic_deep_copy_closure) {
|
||||
.ud = NULL
|
||||
};
|
||||
|
||||
c_StringList list;
|
||||
c_StringList_t list;
|
||||
// 初始化容量为 2 的特化字符串链表,并注入分配器
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_StringList_Init(&list, 2, &my_pool));
|
||||
|
||||
@@ -76,7 +76,7 @@ TEST_CASE(test_string_list_polymorphic_deep_copy_closure) {
|
||||
ASSERT_INT_EQ(3, (int)g_list_pool_active_chunks); // 重复行的物理资源被内置分配器在底层连根拔起
|
||||
|
||||
// 7. 验证克隆体深拷贝承袭能力 (Clone)
|
||||
c_StringList clone_list;
|
||||
c_StringList_t clone_list;
|
||||
c_StringList_Init(&clone_list, 1, &my_pool); // 给个小容量 1
|
||||
ASSERT_INT_EQ(C_ERR_OK, c_StringList_Clone(&clone_list, &list));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user