You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.8 KiB
93 lines
2.8 KiB
use std::fmt;
|
|
use std::io;
|
|
|
|
use encoding_rs::SHIFT_JIS;
|
|
use nom::IResult;
|
|
use nom::bytes::complete::take_while;
|
|
|
|
/// Trait for structs that are easy to pack to bytes.
|
|
pub trait Pack {
|
|
/// Write the entirety of `self` as bytes to the write buffer `f`.
|
|
fn write(&self, f: &mut dyn io::Write) -> io::Result<usize>;
|
|
}
|
|
|
|
/// Parse a zero-terminated string from the slice.
|
|
pub fn take_cstring(i: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
take_while(|c| c != b'\0')(i)
|
|
}
|
|
|
|
/// Parse a zero-terminated string from the slice, discarding the rest.
|
|
///
|
|
/// The cstring will be parsed from the first max_length bytes of the
|
|
/// slice, and on success the parser will discard exactly max_length
|
|
/// bytes from the input, regardless of the parsed string length.
|
|
pub fn take_cstring_from(i: &[u8], max_length: usize) -> IResult<&[u8], &[u8]> {
|
|
take_cstring(i).map(|(_, s)| Ok((&i[max_length..], s)) )?
|
|
}
|
|
|
|
/// Decode a Shift JIS encoded byte slice.
|
|
pub fn sjis_to_string(i: &[u8]) -> Option<String> {
|
|
let (cow, _, has_errors) = SHIFT_JIS.decode(i);
|
|
if has_errors {
|
|
return None
|
|
}
|
|
Some(cow.to_string())
|
|
}
|
|
|
|
/// Decode a Shift JIS encoded byte slice or hex representation.
|
|
pub fn sjis_to_string_lossy(i: &[u8]) -> String {
|
|
sjis_to_string(i).unwrap_or(format!("{:x?}", i))
|
|
}
|
|
|
|
/// Represent an integer that can be 32 or 64 bits,
|
|
/// depending on the platform and flags used.
|
|
pub union VarSizeInt {
|
|
pub vu32: u32,
|
|
pub vu64: u64,
|
|
}
|
|
|
|
impl VarSizeInt {
|
|
/// Set u64 value if condition is true, else the u32 as u64.
|
|
pub fn u64_if(&self, c: bool) -> u64 {
|
|
if c { unsafe { self.vu64 } } else { unsafe { self.vu32 as u64 } }
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for VarSizeInt {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "VarSizeInt: {{ {}: u32, {}: u64 }}", unsafe { self.vu32 }, unsafe { self.vu64 })
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_take_cstring() {
|
|
assert_eq!(take_cstring(b"ABC\0\xFF"), Ok((b"\0\xFF".as_ref(), b"ABC".as_ref())));
|
|
assert_eq!(take_cstring(b"\0"), Ok((b"\0".as_ref(), b"".as_ref())));
|
|
}
|
|
|
|
#[test]
|
|
fn test_take_cstring_from() {
|
|
// Take cstring from the whole slice; nothing remains.
|
|
assert_eq!(
|
|
take_cstring_from(
|
|
b"ABC\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20", // 0x10 bytes
|
|
0x10,
|
|
),
|
|
Ok((b"".as_ref(), b"ABC".as_ref()))
|
|
);
|
|
|
|
// Take cstring from the first half of the slice; the second half remains.
|
|
assert_eq!(
|
|
take_cstring_from(
|
|
b"ABC\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20", // 0x10 bytes
|
|
0x8,
|
|
),
|
|
Ok((b"\x20\x20\x20\x20\x20\x20\x20\x20".as_ref(), b"ABC".as_ref()))
|
|
);
|
|
}
|
|
}
|