Разбор двоичного файла с помощью имени 5.0 - PullRequest
1 голос
/ 04 октября 2019

Проблема

Есть файл с несколькими заголовками внутри, но для меня это имеет значение только один и данные после него. Этот заголовок повторяется несколько раз в файле.

Его магическое число: A3046 в ASCII или 0x65 0x51 0x48 0x54 0x52 в HEX. После нахождения первого байта анализатор должен занять все байты до 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);

Я объявляю магические числа с помощью: pub static QT_MAGIC: &[u8; 5] = b"A3046"; И в качестве теста я написал следующую функцию, чтобы попытаться найти первый заголовок.

fn parse_block(input: &[u8]) -> IResult<&[u8], &[u8]> {
    tag(QT_MAGIC)(input)
}

Однако когдатестовые прогоны, Ok имеет значение None. Это определенно должно было что-то найти. Что я делаю не так?

Я не нашел примеров разбора байтов с использованием nom5, а также то, что новичок по ржавчине не помогает. Как я могу разобрать все блоки с этими правилами?

1 Ответ

1 голос
/ 04 октября 2019

nom версия

Во-первых, извинения за это, игровая площадка имеет только 4.0, и, как следствие, код на этом хранилище github .

Чтобы разобрать что-то подобное, нам нужно объединить два разных анализатора:

  • take_until, чтобы принимать байты долибо преамбула, либо EOF
  • tag, чтобы выделить преамбулу

и комбинатор, preceded, поэтому мыможет отбросить первый элемент последовательности парсеров.

// 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)
    })
}

Код должен быть достаточно хорошо аннотирован, чтобы следовать. Это отбрасывает любые байты до тех пор, пока не найдет байты преамбулы, затем отбрасывает их и сохраняет все, пока не найдет последовательность байтов EOF ([0xff]).

Затем возвращает обратное nomрезультат, потому что это был пример. Вы можете отменить его, чтобы объединить с другими парсерами, если хотите. Первый элемент - это содержимое последовательности, второй - то, что было после EOF. Это означает, что вы можете выполнять итерации с помощью этой функции (я сделал это в тесте в репозитории, который я поставил на github).

...