I was busy typing a reply at the same time And
nom
is the first thing I thought of too -- it's really fun to use, but there's a bit of a learning curve if you're not used to parser-combinators. Knowing how to use it is extremely useful, though, so it might be worth the time.
What I was playing around with was using the bytes
to do the parsing directly. It's an easy way to read parts out of a slice/array sequentially, so it's quite easy to build a parser with it. The example below shows how you could use it (link Rust Playground)
use bytes::{Buf, Bytes};
fn main() {
let bytes = b"this is a name\0 this is another name\0 \x01\x01\x00\x00 --and so on---";
println!("{:?}",bytes);
let mut buf = Bytes::from(&bytes[..]);
// extract fields
let first = buf.copy_to_bytes(40);
let second = buf.copy_to_bytes(40);
// WORD is probably 32-bits, signed, little endian,
// but you may need to do some experimenting to get this
// right.
let word = buf.get_i32_le();
// string conversion
let first_str = convert_string_stop_null(&first).expect("string");
let second_str = convert_string_stop_null(&second).expect("string");
println!("first: {}.", first_str);
println!("second: {}.", second_str);
println!("word: {}.", word);
// remaining buffer
println!("remaining buffer {:?}", buf);
}
// String conversion, assuming there's a null terminator somewhere.
// Find the null and extract everything before it.
fn convert_string_stop_null(raw: &[u8]) -> Option<String> {
let v = raw.split(|b| *b == 0).nth(0)?;
Some(String::from_utf8_lossy(v).to_string())
}
You'll need to play around with it a bit. I'm not sure what the assumed WORD size is, and the strings may or may not be null-terminated. Having a look at the file with hexdump -C
or a hex editor is probably a good way to verify these things.