Rust 使用nom 5.0解析二进制文件 问题
有一个文件里面有多个头,但对我来说,它只关心一个头和后面的数据。此头在文件中重复多次 它的幻数是:ASCII格式的A3046,或十六进制格式的Rust 使用nom 5.0解析二进制文件 问题,rust,nom,Rust,Nom,有一个文件里面有多个头,但对我来说,它只关心一个头和后面的数据。此头在文件中重复多次 它的幻数是:ASCII格式的A3046,或十六进制格式的0x65 0x51 0x48 0x54 0x52。 找到第一个字节后,解析器必须获取所有字节,直到0xff,然后对剩余的头重复,直到EOF 我的解决方案 首先,我加载了文件: let mut file = OpenOptions::new() .read(true) .open("../assets/sample&
0x65 0x51 0x48 0x54 0x52。
找到第一个字节后,解析器必须获取所有字节,直到0xff
,然后对剩余的头重复,直到EOF
我的解决方案
首先,我加载了文件:
let mut file = OpenOptions::new()
.read(true)
.open("../assets/sample")
.unwrap();
let mut full_file: Vec<u8> = Vec::new();
file.read_to_end(&mut full_file);
但是,当测试运行时,Ok具有None
值。它肯定应该找到一些东西。我做错了什么
我没有发现使用nom5解析字节的例子,而且作为一个新手也没有帮助。
如何用这些规则解析所有的块?nomversion
首先,对此表示歉意,游乐场只有nom 4.0,因此,代码为on
要解析类似的内容,我们需要组合两个不同的解析器:
- ,以获取字节,直到前导码或EOF
- ,以隔离序言
还有一个组合符,这样我们就可以去掉一系列解析器的第一个元素
// Our preamble
const MAGIC:&[u8] = &[0x65, 0x51, 0x48, 0x54, 0x52];
// Our EOF byte sequence
const EOF:&[u8] = &[0xff];
// Shorthand to catch EOF
fn match_to_eof(data: &[u8]) -> nom::IResult<&[u8], &[u8]> {
nom::bytes::complete::take_until(EOF)(data)
}
// Shorthand to catch the preamble
fn take_until_preamble(data: &[u8]) -> nom::IResult<&[u8], &[u8]> {
nom::bytes::complete::take_until(MAGIC)(data)
}
pub fn extract_from_data(data: &[u8]) -> Option<(&[u8], &[u8])> {
let preamble_parser = nom::sequence::preceded(
// Ditch anything before the preamble
take_until_preamble,
nom::sequence::preceded(
// Ditch the preamble
nom::bytes::complete::tag(MAGIC),
// And take until the EOF (0xff)
match_to_eof
)
);
// And we swap the elements because it's confusing AF
// as a return function
preamble_parser(data).ok().map(|r| {
(r.1, r.0)
})
}
//我们的序言
常量魔法:&[u8]=&[0x65、0x51、0x48、0x54、0x52];
//我们的EOF字节序列
常数EOF:&[u8]=&[0xff];
//抓住EOF的速记
fn匹配到eof(数据:&[u8])->nom::IResult{
nom::bytes::complete::take_直到(EOF)(数据)
}
//抓住序言的速记
fn直到前导(数据:&[u8])->nom::IResult{
nom::bytes::complete::take_直到(MAGIC)(数据)
}
pub fn从_数据中提取_(数据:&[u8])->选项{
让preamble_parser=nom::sequence::preferred(
//在序言之前放弃任何东西
直到序言,
名称::序列::前置(
//放弃序言
nom::bytes::complete::tag(魔术),
//并一直持续到EOF(0xff)
匹配
)
);
//我们交换元素是因为它让人困惑
//作为返回函数
序言|u解析器(data).ok().map(| r|{
(r.1,r.0)
})
}
代码应该有足够好的注释,以便遵循。这将丢弃所有字节,直到找到前导字节,然后丢弃这些字节并保留所有字节,直到找到EOF字节序列([0xff]
)
然后它返回一个反向的nom
结果,因为这是一个示例。如果愿意,您可以取消反转它,将其与其他解析器组合。第一个元素是序列的内容,第二个元素是EOF之后的内容。这意味着您可以使用这个函数进行迭代(我在我放在github上的repo中的一个测试中这样做了)。nom
需求是固定的吗?我认为,使用流式迭代器可以更有效地实现这一点。这绝对不是一个要求,只是我想我可以帮助更快地实现我的目标。我会给你们两个,这样你们就可以决定了,在这种情况下:-)
// Our preamble
const MAGIC:&[u8] = &[0x65, 0x51, 0x48, 0x54, 0x52];
// Our EOF byte sequence
const EOF:&[u8] = &[0xff];
// Shorthand to catch EOF
fn match_to_eof(data: &[u8]) -> nom::IResult<&[u8], &[u8]> {
nom::bytes::complete::take_until(EOF)(data)
}
// Shorthand to catch the preamble
fn take_until_preamble(data: &[u8]) -> nom::IResult<&[u8], &[u8]> {
nom::bytes::complete::take_until(MAGIC)(data)
}
pub fn extract_from_data(data: &[u8]) -> Option<(&[u8], &[u8])> {
let preamble_parser = nom::sequence::preceded(
// Ditch anything before the preamble
take_until_preamble,
nom::sequence::preceded(
// Ditch the preamble
nom::bytes::complete::tag(MAGIC),
// And take until the EOF (0xff)
match_to_eof
)
);
// And we swap the elements because it's confusing AF
// as a return function
preamble_parser(data).ok().map(|r| {
(r.1, r.0)
})
}