BinHex是上世纪80年代为Mac平台设计的带校验和与资源分支信息的ASCII编码格式,C++标准库无现成解析器,需手动处理头部跳过、:分隔行解析、CRCC校验及数据/资源分支分离。

BinHex是什么,为什么C++里没有现成解析器
BinHex是上世纪80年代为Mac平台设计的二进制编码格式,把二进制数据转成ASCII(主要是0-9、A-Z、a-z、:),还带校验和和资源分支信息。现代C++标准库完全不支持它——std::base64_decode不存在,std::hex也对不上它的字符集和分块规则。
这意味着你得自己处理三件事:跳过头部(如(This file must be converted with BinHex 4.0))、按行解析:分隔的十六进制块、验证CRCC校验和。别指望boost::archive或zlib能帮上忙,它们根本不认这个格式。
手动解析BinHex 4.0的三个关键步骤
BinHex 4.0(最常见版本)文件结构固定:起始标记、数据区(每行以:开头)、结尾校验行(如CRCC: 12345678)。解析必须严格按顺序来:
- 先用
std::getline逐行读取,跳过所有非:开头的行,直到遇到第一个:行 - 每个数据行去掉开头
:,然后把剩余字符串按两个字符一组拆开,用std::stoi(x.substr(i,2), nullptr, 16)转成字节 - 遇到
CRCC:行时,提取后面8位十六进制数,用BinHex CRC算法(非标准CRC32)校验前面所有解码字节;错误时直接返回失败
注意:有些老文件用Mac换行符\r,std::getline默认按\n切会出错,得手动处理\r残留。
立即学习“C++免费学习笔记(深入)”;
用std::stringstream还是std::from_chars?性能差很多
对每个两字符十六进制段,别用std::stringstream——它构造开销大,且在嵌入式或高频解析场景下明显拖慢。实测1MB文件,std::from_chars比std::stoi快2.3倍,比std::stringstream快5倍以上:
char buf[3] = {hex_pair[0], hex_pair[1], '\0'};
int val;
std::from_chars(buf, buf + 2, val, 16);
但std::from_chars要求输入严格是两位十六进制字符,不能有空格或换行残留——所以解析前必须确保已去除行尾\r、\n和空格。否则ec == std::errc::invalid_argument,你就得退回到std::stoi兜底。
真实文件里最常踩的坑:头部偏移和资源分支干扰
很多BinHex文件实际包含两个数据段:数据分支(Data)和资源分支(Resource),头信息里会写data-fork bytes: 1234和resource-fork bytes: 567。如果你只解:之后的内容,会把两个分支混在一起解,结果文件损坏。
正确做法是:
- 先扫描全文,找到
data-fork bytes:和resource-fork bytes:对应的数值 - 计算数据分支应占多少字节,解码时只取前N个字节,剩下的留给资源分支(或丢弃,取决于需求)
- 不要依赖行数判断——有的文件每行16字节,有的32字节,甚至末尾行不满额
另外,某些老Mac备份工具生成的BinHex会在末尾补零凑整,但CRC只算有效字节,多出来的零不能参与校验。
BinHex不是“换个编码方式读出来就行”的格式,头部语义、分支长度、CRC算法全得抠细节;漏掉任意一项,解出来的文件就打不开。


















