mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-15 05:55:09 -05:00
176 lines
5.3 KiB
Rust
176 lines
5.3 KiB
Rust
use std::io::{Seek, SeekFrom};
|
|
|
|
use byteorder::{BigEndian, ReadBytesExt};
|
|
use failure::ResultExt;
|
|
|
|
use byte_buffer::ByteBufferRead;
|
|
use compression::Compression;
|
|
use encoding_type::EncodingType;
|
|
use error::{KbinErrorKind, Result};
|
|
use node_types::StandardType;
|
|
use sixbit::Sixbit;
|
|
use super::{ARRAY_MASK, SIGNATURE, SIG_COMPRESSED};
|
|
|
|
pub struct Reader<'buf> {
|
|
encoding: EncodingType,
|
|
|
|
pub(crate) node_buf: ByteBufferRead<'buf>,
|
|
pub(crate) data_buf: ByteBufferRead<'buf>,
|
|
|
|
data_buf_start: u64,
|
|
|
|
last_node_type: Option<(StandardType, bool)>,
|
|
last_node_identifier: Option<String>,
|
|
}
|
|
|
|
impl<'buf> Reader<'buf> {
|
|
pub fn new(input: &'buf [u8]) -> Result<Self> {
|
|
// Node buffer starts from the beginning.
|
|
// Data buffer starts later after reading `len_data`.
|
|
let mut node_buf = ByteBufferRead::new(&input[..]);
|
|
|
|
let signature = node_buf.read_u8().context(KbinErrorKind::HeaderRead("signature"))?;
|
|
if signature != SIGNATURE {
|
|
return Err(KbinErrorKind::HeaderValue("signature").into());
|
|
}
|
|
|
|
// TODO: support uncompressed
|
|
let compress_byte = node_buf.read_u8().context(KbinErrorKind::HeaderRead("compression"))?;
|
|
if compress_byte != SIG_COMPRESSED {
|
|
return Err(KbinErrorKind::HeaderValue("compression").into());
|
|
}
|
|
|
|
let compressed = Compression::from_byte(compress_byte)?;
|
|
|
|
let encoding_byte = node_buf.read_u8().context(KbinErrorKind::HeaderRead("encoding"))?;
|
|
let encoding_negation = node_buf.read_u8().context(KbinErrorKind::HeaderRead("encoding negation"))?;
|
|
let encoding = EncodingType::from_byte(encoding_byte)?;
|
|
if encoding_negation != !encoding_byte {
|
|
return Err(KbinErrorKind::HeaderValue("encoding negation").into());
|
|
}
|
|
|
|
info!("signature: 0x{:X}, compression: 0x{:X} ({:?}), encoding: 0x{:X} ({:?})", signature, compress_byte, compressed, encoding_byte, encoding);
|
|
|
|
let len_node = node_buf.read_u32::<BigEndian>().context(KbinErrorKind::LenNodeRead)?;
|
|
info!("len_node: {0} (0x{0:x})", len_node);
|
|
|
|
// We have read 8 bytes so far, so offset the start of the data buffer from
|
|
// the start of the input data.
|
|
let data_buf_start = len_node + 8;
|
|
let mut data_buf = ByteBufferRead::new(&input[(data_buf_start as usize)..]);
|
|
|
|
let len_data = data_buf.read_u32::<BigEndian>().context(KbinErrorKind::LenDataRead)?;
|
|
info!("len_data: {0} (0x{0:x})", len_data);
|
|
|
|
//let node_buf_end = data_buf_start.into();
|
|
|
|
Ok(Self {
|
|
encoding,
|
|
//read_mode: ReadMode::Single,
|
|
//first_struct: true,
|
|
//node_buf_end,
|
|
node_buf,
|
|
data_buf,
|
|
|
|
data_buf_start: data_buf_start as u64,
|
|
|
|
last_node_type: None,
|
|
last_node_identifier: None,
|
|
})
|
|
}
|
|
|
|
fn parse_node_type(raw_node_type: u8) -> Result<(StandardType, bool)> {
|
|
let is_array = raw_node_type & ARRAY_MASK == ARRAY_MASK;
|
|
let node_type = raw_node_type & !ARRAY_MASK;
|
|
|
|
let xml_type = StandardType::from_u8(node_type);
|
|
debug!("Reader::parse_node_type() => raw_node_type: {}, node_type: {:?} ({}), is_array: {}",
|
|
raw_node_type,
|
|
xml_type,
|
|
node_type,
|
|
is_array);
|
|
|
|
Ok((xml_type, is_array))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn encoding(&self) -> EncodingType {
|
|
self.encoding
|
|
}
|
|
|
|
#[inline]
|
|
pub fn data_buf_start(&self) -> u64 {
|
|
self.data_buf_start
|
|
}
|
|
|
|
#[inline]
|
|
pub fn last_node_type(&self) -> Option<(StandardType, bool)> {
|
|
self.last_node_type
|
|
}
|
|
|
|
#[inline]
|
|
pub fn last_identifier(&self) -> Option<&str> {
|
|
self.last_node_identifier.as_ref().map(String::as_str)
|
|
}
|
|
|
|
pub fn peek_node_type(&self) -> Result<(StandardType, bool)> {
|
|
let pos = self.node_buf.position();
|
|
let raw_node_type = self.node_buf.get_ref()[pos as usize];
|
|
Self::parse_node_type(raw_node_type)
|
|
}
|
|
|
|
pub fn peek_node_identifier(&mut self) -> Result<String> {
|
|
let old_pos = self.node_buf.position();
|
|
let _raw_node_type = self.node_buf.read_u8().context(KbinErrorKind::NodeTypeRead)?;
|
|
let value = Sixbit::unpack(&mut *self.node_buf)?;
|
|
|
|
let size = self.node_buf.position() - old_pos;
|
|
self.node_buf.seek(SeekFrom::Start(old_pos)).context(KbinErrorKind::DataRead(size as usize))?;
|
|
|
|
Ok(value)
|
|
}
|
|
|
|
pub fn read_node_type(&mut self) -> Result<(StandardType, bool)> {
|
|
let raw_node_type = self.node_buf.read_u8().context(KbinErrorKind::NodeTypeRead)?;
|
|
let value = Self::parse_node_type(raw_node_type)?;
|
|
self.last_node_type = Some(value);
|
|
|
|
Ok(value)
|
|
}
|
|
|
|
pub fn read_node_identifier(&mut self) -> Result<String> {
|
|
let value = Sixbit::unpack(&mut *self.node_buf)?;
|
|
debug!("Reader::read_node_identifier() => value: {:?}", value);
|
|
|
|
self.last_node_identifier = Some(value.clone());
|
|
|
|
Ok(value)
|
|
}
|
|
|
|
pub fn read_string(&mut self) -> Result<String> {
|
|
let value = self.data_buf.read_str(self.encoding)?;
|
|
debug!("Reader::read_string() => value: {:?}", value);
|
|
|
|
Ok(value)
|
|
}
|
|
|
|
pub fn read_u8(&mut self) -> Result<u8> {
|
|
let value = self.data_buf.read_u8().context(KbinErrorKind::DataReadOneByte)?;
|
|
debug!("Reader::read_u8() => value: {}", value);
|
|
|
|
Ok(value)
|
|
}
|
|
|
|
pub fn read_u32(&mut self) -> Result<u32> {
|
|
let value = self.data_buf.read_u32::<BigEndian>().context(KbinErrorKind::DataRead(4))?;
|
|
debug!("Reader::read_u32() => result: {}", value);
|
|
|
|
Ok(value)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn read_bytes(&mut self) -> Result<&'buf [u8]> {
|
|
self.data_buf.buf_read()
|
|
}
|
|
}
|