control文件位于.deb包的control.tar.*归档内,是遵循rfc 822格式的纯文本:字段名后接“: ”和值,字段间空行分隔,支持缩进续行,无引号/转义,需按行状态机解析并处理bom。

control文件在Debian包里的位置和格式特点
Debian包(.deb)本质是ar归档,内部包含debian-binary、control.tar.<em></em>(通常是control.tar.gz或control.tar.xz)、data.tar.三部分。真正要解析的control文件就藏在control.tar.*里,且是纯文本,遵循RFC 822风格:字段名后跟冒号、空格、值,字段间用空行分隔,支持多行值(后续行需以空格缩进)。
注意:control不是JSON/YAML,没有引号包裹、不转义特殊字符,也不强制要求字段顺序;值末尾的换行和缩进空格有语义,不能简单用std::getline按行切分后trim了事。
用C++解压并读取control内容(不依赖libapt)
核心步骤是:打开.deb → 定位并解压control.tar.* → 解压出control文件 → 按RFC 822规则解析字段。
-
ar头固定为8字节签名,之后是按“文件名+大小+填充”的固定格式条目;可手动跳过debian-binary,找到以control.tar.开头的条目(注意它可能叫control.tar.gz或control.tar.xz) - 推荐用
libarchive(archive_read_open_memory+archive_read_next_header)处理嵌套压缩,比手写ar解析+调用zlib/liblzma更稳 - 若坚持零外部依赖,可用
miniz(仅.gz)或lzma-sdk(仅.xz),但需先识别压缩类型——看control.tar.*扩展名不够可靠,应检查魔数:1f 8b(gzip)、fd 37 7a 58 5a 00(xz)
示例片段(用libarchive):
struct archive *a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_tar(a); archive_read_open_filename(a, "package.deb", 10240); // ……跳过前两个条目,找到 control.tar.* archive_read_open_memory(a, control_tar_data, control_tar_size); // 然后遍历,找名为 "control" 的entry
安全解析control字段(避免split(':')陷阱)
直接按冒号分割字段会崩在这些地方:
- 字段值本身含冒号(如
Description: A C++ lib: fast & safe) - 多行值(如
Description跨三行,第二行以空格开头) - 字段名含空格?不会,但值开头有空格是合法的(表示续行)
正确做法是逐行扫描,维护当前字段名和累积值:
- 遇到
"\n\n"或EOF,结束一个段落(一个Package块) - 行以字母开头 → 新字段:
name: value,冒号后第一个非空格位置开始是值 - 行以空格或制表符开头 → 当前字段续行,把前导空白去掉,拼到上一行值末尾(保留内部空格)
- 值末尾的换行需保留(某些工具依赖它做格式化)
别用std::regex匹配整行——性能差,且无法处理续行逻辑。
字段值里的换行和空格怎么处理才符合dpkg行为
dpkg-deb -I输出的Description会把续行合并成单行(用空格连接),但原始control文件中换行是语义的一部分。是否折叠取决于你的用途:
- 如果做元数据比对(如校验
Version),直接取首行值即可,忽略续行(只有Description、Homepage等少数字段允许多行) - 如果生成人类可读报告,按
dpkg逻辑折叠:把续行前导空白替换成单空格,再trim首尾,最后用单空格连接所有行 - 注意
Depends字段虽允许多行,但每行实际是独立的依赖项列表,不能简单拼接——得按逗号分割后再trim
最易被忽略的一点:control文件可能含UTF-8 BOM(虽然Debian政策不鼓励),但很多真实包存在;读取时若没跳过EF BB BF,会导致Package:字段名前面多三个乱码字节——解析直接失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











