use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write, Cursor};
use encoding_rs;
pub fn read_u8(cursor: &mut Cursor<&[u8]>) -> Result<u8, std::io::Error> {
cursor.read_u8()
}
pub fn read_u16(cursor: &mut Cursor<&[u8]>) -> Result<u16, std::io::Error> {
cursor.read_u16::<LittleEndian>()
}
pub fn read_u32(cursor: &mut Cursor<&[u8]>) -> Result<u32, std::io::Error> {
cursor.read_u32::<LittleEndian>()
}
pub fn read_i32(cursor: &mut Cursor<&[u8]>) -> Result<i32, std::io::Error> {
cursor.read_i32::<LittleEndian>()
}
pub fn write_u8(writer: &mut dyn Write, value: u8) -> Result<(), std::io::Error> {
writer.write_u8(value)
}
pub fn write_u16(writer: &mut dyn Write, value: u16) -> Result<(), std::io::Error> {
writer.write_u16::<LittleEndian>(value)
}
pub fn write_u32(writer: &mut dyn Write, value: u32) -> Result<(), std::io::Error> {
writer.write_u32::<LittleEndian>(value)
}
pub fn write_i32(writer: &mut dyn Write, value: i32) -> Result<(), std::io::Error> {
writer.write_i32::<LittleEndian>(value)
}
const SUPPORTED_ENCODINGS: &[&str] = &["utf-8", "windows-1252", "windows-1250", "windows-1251"];
#[derive(Debug, Clone)]
pub struct RawString {
pub content: String,
pub encoding: String,
}
impl RawString {
pub fn decode(data: &[u8]) -> Self {
for encoding_name in SUPPORTED_ENCODINGS {
if let Some(encoding) = encoding_rs::Encoding::for_label(encoding_name.as_bytes()) {
let (decoded, _, had_errors) = encoding.decode(data);
if !had_errors {
return RawString {
content: decoded.into_owned(),
encoding: encoding_name.to_string(),
};
}
}
}
RawString {
content: String::from_utf8_lossy(data).into_owned(),
encoding: "utf-8".to_string(),
}
}
pub fn parse_zstring(data: &[u8]) -> Self {
let null_pos = data.iter().position(|&b| b == 0).unwrap_or(data.len());
Self::decode(&data[..null_pos])
}
pub fn parse_bstring(cursor: &mut Cursor<&[u8]>) -> Result<Self, std::io::Error> {
let length = read_u8(cursor)? as usize;
let mut buffer = vec![0u8; length];
cursor.read_exact(&mut buffer)?;
if let Some(null_pos) = buffer.iter().position(|&b| b == 0) {
buffer.truncate(null_pos);
}
Ok(Self::decode(&buffer))
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy)]
pub struct RecordFlags: u32 {
const MASTER_FILE = 0x00000001; const UNKNOWN_02 = 0x00000002; const UNKNOWN_04 = 0x00000004; const UNKNOWN_08 = 0x00000008; const UNKNOWN_10 = 0x00000010; const DELETED = 0x00000020; const UNKNOWN_40 = 0x00000040; const LOCALIZED = 0x00000080; const UNKNOWN_100 = 0x00000100; const LIGHT_MASTER = 0x00000200; const PERSISTENT = 0x00000400; const DISABLED = 0x00000800; const UNKNOWN_1000 = 0x00001000; const UNKNOWN_2000 = 0x00002000; const UNKNOWN_4000 = 0x00004000; const VISIBLE_DISTANT = 0x00008000; const UNKNOWN_10000 = 0x00010000; const UNKNOWN_20000 = 0x00020000; const COMPRESSED = 0x00040000; const UNKNOWN_80000 = 0x00080000; const UNKNOWN_100000 = 0x00100000; const UNKNOWN_200000 = 0x00200000; const UNKNOWN_400000 = 0x00400000; const UNKNOWN_800000 = 0x00800000; const UNKNOWN_1000000 = 0x01000000; const UNKNOWN_2000000 = 0x02000000; const UNKNOWN_4000000 = 0x04000000; const UNKNOWN_8000000 = 0x08000000; const UNKNOWN_10000000 = 0x10000000; const UNKNOWN_20000000 = 0x20000000; const UNKNOWN_40000000 = 0x40000000; const UNKNOWN_80000000 = 0x80000000; }
}