cargo: rustfmt

This commit is contained in:
Matt Bilker
2019-11-08 20:04:49 +00:00
parent 972e9b0e56
commit f273d5b13e
24 changed files with 2993 additions and 2721 deletions

4
rustfmt.toml Normal file
View File

@@ -0,0 +1,4 @@
binop_separator = "Back"
edition = "2018"
match_block_trailing_comma = true
overflow_delimited_expr = true

View File

@@ -8,111 +8,124 @@ use encoding_rs::Encoding;
use kbinxml::{EncodingType, Options, Printer};
fn display_buf(buf: &[u8]) -> Result<(), IoError> {
io::stdout().write_all(&buf)?;
println!();
io::stdout().write_all(&buf)?;
println!();
Ok(())
Ok(())
}
fn compare_slice(left: &[u8], right: &[u8]) {
let node_buf_length = BigEndian::read_u32(&left[4..8]);
let data_buf_start = 8 + node_buf_length as usize;
let node_buf_length = BigEndian::read_u32(&left[4..8]);
let data_buf_start = 8 + node_buf_length as usize;
let mut i = 0;
let mut mismatches = Vec::new();
while i < left.len() && i < right.len() {
if left[i] != right[i] {
mismatches.push((i, left[i], right[i]));
}
i += 1;
}
if let Some(ref first) = mismatches.first() {
eprintln!("Left does not equal right at the following indexes:");
for (i, left, right) in &mismatches {
let (section, offset) = if *i < data_buf_start {
("node buffer", (*i as isize) - 8)
} else {
("data buffer", (*i as isize) - 4 - (data_buf_start as isize))
};
eprintln!("index {0} ({3}, offset: {4}), left: {1:3} (0x{1:x}),\tright: {2:3} (0x{2:x})", i, left, right, section, offset);
let mut i = 0;
let mut mismatches = Vec::new();
while i < left.len() && i < right.len() {
if left[i] != right[i] {
mismatches.push((i, left[i], right[i]));
}
i += 1;
}
let (i, _, _) = first;
eprintln!(r#" left: `0x{:02x?}`
right: `0x{:02x?}`"#, &left[*i..], &right[*i..]);
}
if let Some(ref first) = mismatches.first() {
eprintln!("Left does not equal right at the following indexes:");
for (i, left, right) in &mismatches {
let (section, offset) = if *i < data_buf_start {
("node buffer", (*i as isize) - 8)
} else {
("data buffer", (*i as isize) - 4 - (data_buf_start as isize))
};
eprintln!(
"index {0} ({3}, offset: {4}), left: {1:3} (0x{1:x}),\tright: {2:3} (0x{2:x})",
i, left, right, section, offset
);
}
let (i, _, _) = first;
eprintln!(
r#" left: `0x{:02x?}`
right: `0x{:02x?}`"#,
&left[*i..],
&right[*i..]
);
}
}
fn main() -> Result<(), anyhow::Error> {
pretty_env_logger::init();
pretty_env_logger::init();
let matches = App::new("kbinxml")
.about(env!("CARGO_PKG_DESCRIPTION"))
.version(env!("CARGO_PKG_VERSION"))
.author("Matt Bilker <me@mbilker.us>")
.arg(Arg::with_name("printer")
.help("Turn on the NodeCollection and NodeDefinition debug printer")
.short("p")
.long("printer"))
.arg(Arg::with_name("encoding")
.help("Set the encoding used when encoding kbin data")
.short("e")
.long("encoding")
.takes_value(true))
.arg(Arg::with_name("input")
.help("The file to convert")
.index(1)
.required(true))
.get_matches();
let matches = App::new("kbinxml")
.about(env!("CARGO_PKG_DESCRIPTION"))
.version(env!("CARGO_PKG_VERSION"))
.author("Matt Bilker <me@mbilker.us>")
.arg(
Arg::with_name("printer")
.help("Turn on the NodeCollection and NodeDefinition debug printer")
.short("p")
.long("printer"),
)
.arg(
Arg::with_name("encoding")
.help("Set the encoding used when encoding kbin data")
.short("e")
.long("encoding")
.takes_value(true),
)
.arg(
Arg::with_name("input")
.help("The file to convert")
.index(1)
.required(true),
)
.get_matches();
let printer_enabled = matches.is_present("printer");
let file_name = matches.value_of("input").unwrap();
let output_encoding = if let Some(label) = matches.value_of("encoding") {
let encoding = Encoding::for_label(label.as_bytes())
.with_context(|| "No encoding found for label")?;
let printer_enabled = matches.is_present("printer");
let file_name = matches.value_of("input").unwrap();
let output_encoding = if let Some(label) = matches.value_of("encoding") {
let encoding =
Encoding::for_label(label.as_bytes()).context("No encoding found for label")?;
Some(EncodingType::from_encoding(encoding)?)
} else {
None
};
Some(EncodingType::from_encoding(encoding)?)
} else {
None
};
eprintln!("file_name: {}", file_name);
eprintln!("file_name: {}", file_name);
// Read '-' as standard input.
let contents = if file_name == "-" {
let mut contents = Vec::new();
io::stdin().read_to_end(&mut contents)?;
// Read '-' as standard input.
let contents = if file_name == "-" {
let mut contents = Vec::new();
io::stdin().read_to_end(&mut contents)?;
contents
} else {
fs::read(file_name)?
};
contents
} else {
fs::read(file_name)?
};
if kbinxml::is_binary_xml(&contents) {
if printer_enabled {
Printer::run(&contents).unwrap();
if kbinxml::is_binary_xml(&contents) {
if printer_enabled {
Printer::run(&contents).unwrap();
}
let (collection, _encoding) = kbinxml::from_slice(&contents)?;
let text_original = kbinxml::to_text_xml(&collection)?;
display_buf(&text_original)?;
let (collection, encoding_original) = kbinxml::from_slice(&contents)?;
let options = Options::with_encoding(output_encoding.unwrap_or(encoding_original));
let buf = kbinxml::to_binary_with_options(options, &collection)?;
compare_slice(&buf, &contents);
} else {
let (collection, encoding) = kbinxml::from_text_xml(&contents)?;
let options = Options::with_encoding(output_encoding.unwrap_or(encoding));
let buf = kbinxml::to_binary_with_options(options, &collection)?;
if printer_enabled {
Printer::run(&buf)?;
}
io::stdout().write_all(&buf)?;
}
let (collection, _encoding) = kbinxml::from_slice(&contents)?;
let text_original = kbinxml::to_text_xml(&collection)?;
display_buf(&text_original)?;
let (collection, encoding_original) = kbinxml::from_slice(&contents)?;
let options = Options::with_encoding(output_encoding.unwrap_or(encoding_original));
let buf = kbinxml::to_binary_with_options(options, &collection)?;
compare_slice(&buf, &contents);
} else {
let (collection, encoding) = kbinxml::from_text_xml(&contents)?;
let options = Options::with_encoding(output_encoding.unwrap_or(encoding));
let buf = kbinxml::to_binary_with_options(options, &collection)?;
if printer_enabled {
Printer::run(&buf)?;
}
io::stdout().write_all(&buf)?;
}
Ok(())
Ok(())
}

View File

@@ -12,371 +12,439 @@ use crate::node_types::KbinType;
#[derive(Debug, Snafu)]
pub enum ByteBufferError {
#[snafu(display("Out-of-bounds read attempted at offset: {} with size: {}", offset, size))]
OutOfBounds {
offset: usize,
size: usize,
},
#[snafu(display(
"Out-of-bounds read attempted at offset: {} with size: {}",
offset,
size
))]
OutOfBounds { offset: usize, size: usize },
#[snafu(display("Failed to read {} byte(s) from data buffer", size))]
DataRead {
size: usize,
source: io::Error,
},
#[snafu(display("Failed to read {} byte(s) from data buffer", size))]
DataRead { size: usize, source: io::Error },
#[snafu(display("Failed to read aligned {} byte(s) from data buffer", size))]
ReadAligned {
size: usize,
source: Box<ByteBufferError>,
},
#[snafu(display("Failed to read aligned {} byte(s) from data buffer", size))]
ReadAligned {
size: usize,
source: Box<ByteBufferError>,
},
#[snafu(display("Failed to read data size from data buffer"))]
ReadSize {
source: io::Error,
},
#[snafu(display("Failed to read data size from data buffer"))]
ReadSize { source: io::Error },
#[snafu(display("Failed to seek forward {} byte(s) in data buffer after size read", size))]
ReadSizeSeek {
size: usize,
source: io::Error,
},
#[snafu(display(
"Failed to seek forward {} byte(s) in data buffer after size read",
size
))]
ReadSizeSeek { size: usize, source: io::Error },
#[snafu(display("Failed to write length to data buffer (len: {})", len))]
WriteLength {
len: usize,
source: io::Error,
},
#[snafu(display("Failed to write length to data buffer (len: {})", len))]
WriteLength { len: usize, source: io::Error },
#[snafu(display("Failed to write data byte {} to data buffer", offset))]
WriteDataByte {
offset: usize,
source: io::Error,
},
#[snafu(display("Failed to write data byte {} to data buffer", offset))]
WriteDataByte { offset: usize, source: io::Error },
#[snafu(display("Failed to write data block to data buffer"))]
WriteDataBlock {
source: io::Error,
},
#[snafu(display("Failed to write data block to data buffer"))]
WriteDataBlock { source: io::Error },
#[snafu(display("Failed to write padding {} byte(s) to data buffer", size))]
WritePadding {
size: usize,
source: io::Error,
},
#[snafu(display("Failed to write padding {} byte(s) to data buffer", size))]
WritePadding { size: usize, source: io::Error },
#[snafu(display("Failed to seek to {} in data buffer", offset))]
SeekOffset {
offset: usize,
source: io::Error,
},
#[snafu(display("Failed to seek to {} in data buffer", offset))]
SeekOffset { offset: usize, source: io::Error },
#[snafu(display("Failed to seek forward {} byte(s) in data buffer", size))]
SeekForward {
size: usize,
source: io::Error,
},
#[snafu(display("Failed to seek forward {} byte(s) in data buffer", size))]
SeekForward { size: usize, source: io::Error },
}
/// Remove trailing null bytes, used for the `String` type
pub(crate) fn strip_trailing_null_bytes<'a>(data: &'a [u8]) -> &'a [u8] {
let len = data.len();
let len = data.len();
if len == 0 {
return data;
}
if len == 0 {
return data;
}
let mut index = len - 1;
while index > 0 && index < len && data[index] == 0x00 {
index -= 1;
}
let mut index = len - 1;
while index > 0 && index < len && data[index] == 0x00 {
index -= 1;
}
// Handle case where the buffer is only a null byte
if index == 0 && data.len() == 1 && data[index] == 0x00 {
&[]
} else {
&data[..=index]
}
// Handle case where the buffer is only a null byte
if index == 0 && data.len() == 1 && data[index] == 0x00 {
&[]
} else {
&data[..=index]
}
}
pub struct ByteBufferRead {
cursor: Cursor<Bytes>,
buffer: Bytes,
offset_1: usize,
offset_2: usize,
cursor: Cursor<Bytes>,
buffer: Bytes,
offset_1: usize,
offset_2: usize,
}
pub struct ByteBufferWrite {
buffer: Cursor<Vec<u8>>,
offset_1: u64,
offset_2: u64,
buffer: Cursor<Vec<u8>>,
offset_1: u64,
offset_2: u64,
}
impl ByteBufferRead {
pub fn new(buffer: Bytes) -> Self {
Self {
cursor: Cursor::new(buffer.clone()),
buffer,
offset_1: 0,
offset_2: 0,
}
}
#[inline]
fn data_buf_offset(&self) -> usize {
// Position is not the index of the previously read byte, it is the current
// index (offset).
//
// This is so much fun to debug.
//data_buf.position() - 1
self.cursor.position() as usize
}
fn check_read_size(&self, start: usize, size: usize) -> Result<usize, ByteBufferError> {
let end = start + size;
if end > self.buffer.len() {
Err(ByteBufferError::OutOfBounds { offset: start, size })
} else {
Ok(end)
}
}
fn buf_read_size(&mut self, size: usize) -> Result<Bytes, ByteBufferError> {
// To avoid an allocation of a `Vec` here, the raw input byte array is used
let start = self.data_buf_offset();
let end = self.check_read_size(start, size)?;
let data = self.buffer.slice(start, end);
trace!("buf_read_size => index: {}, size: {}, data: 0x{:02x?}", self.cursor.position(), data.len(), &*data);
self.cursor.seek(SeekFrom::Current(size as i64)).context(ReadSizeSeek { size })?;
Ok(data)
}
pub fn buf_read(&mut self) -> Result<Bytes, ByteBufferError> {
let size = self.cursor.read_u32::<BigEndian>().context(ReadSize)?;
debug!("buf_read => index: {}, size: {}", self.cursor.position(), size);
let data = self.buf_read_size(size as usize)?;
self.realign_reads(None)?;
Ok(data)
}
pub fn get(&mut self, size: u32) -> Result<Bytes, ByteBufferError> {
let data = self.buf_read_size(size as usize)?;
trace!("get => size: {}, data: 0x{:02x?}", size, &*data);
Ok(data)
}
pub fn get_aligned(&mut self, data_type: KbinType) -> Result<Bytes, ByteBufferError> {
if self.offset_1 % 4 == 0 {
self.offset_1 = self.data_buf_offset();
}
if self.offset_2 % 4 == 0 {
self.offset_2 = self.data_buf_offset();
pub fn new(buffer: Bytes) -> Self {
Self {
cursor: Cursor::new(buffer.clone()),
buffer,
offset_1: 0,
offset_2: 0,
}
}
let old_pos = self.data_buf_offset();
let size = data_type.size * data_type.count;
trace!("get_aligned => old_pos: {}, size: {}", old_pos, size);
#[inline]
fn data_buf_offset(&self) -> usize {
// Position is not the index of the previously read byte, it is the current
// index (offset).
//
// This is so much fun to debug.
//data_buf.position() - 1
self.cursor.position() as usize
}
let (check_old, data) = match size {
1 => {
let end = self.check_read_size(self.offset_1, 1)?;
let data = self.buffer.slice(self.offset_1, end);
self.offset_1 += 1;
fn check_read_size(&self, start: usize, size: usize) -> Result<usize, ByteBufferError> {
let end = start + size;
if end > self.buffer.len() {
Err(ByteBufferError::OutOfBounds {
offset: start,
size,
})
} else {
Ok(end)
}
}
(true, data)
},
2 => {
let end = self.check_read_size(self.offset_2, 2)?;
let data = self.buffer.slice(self.offset_2, end);
self.offset_2 += 2;
fn buf_read_size(&mut self, size: usize) -> Result<Bytes, ByteBufferError> {
// To avoid an allocation of a `Vec` here, the raw input byte array is used
let start = self.data_buf_offset();
let end = self.check_read_size(start, size)?;
(true, data)
},
size => {
let data = self.buf_read_size(size as usize).map_err(Box::new).context(ReadAligned { size })?;
let data = self.buffer.slice(start, end);
trace!(
"buf_read_size => index: {}, size: {}, data: 0x{:02x?}",
self.cursor.position(),
data.len(),
&*data
);
self.cursor
.seek(SeekFrom::Current(size as i64))
.context(ReadSizeSeek { size })?;
Ok(data)
}
pub fn buf_read(&mut self) -> Result<Bytes, ByteBufferError> {
let size = self.cursor.read_u32::<BigEndian>().context(ReadSize)?;
debug!(
"buf_read => index: {}, size: {}",
self.cursor.position(),
size
);
let data = self.buf_read_size(size as usize)?;
self.realign_reads(None)?;
(false, data)
},
};
if check_old {
let trailing = max(self.offset_1, self.offset_2);
trace!("get_aligned => old_pos: {}, trailing: {}", old_pos, trailing);
if old_pos < trailing {
self.cursor.seek(SeekFrom::Start(trailing as u64)).context(SeekOffset { offset: trailing })?;
self.realign_reads(None)?;
}
Ok(data)
}
Ok(data)
}
pub fn get(&mut self, size: u32) -> Result<Bytes, ByteBufferError> {
let data = self.buf_read_size(size as usize)?;
trace!("get => size: {}, data: 0x{:02x?}", size, &*data);
pub fn realign_reads(&mut self, size: Option<u64>) -> Result<(), ByteBufferError> {
let size = size.unwrap_or(4);
trace!("realign_reads => position: {}, size: {}", self.cursor.position(), size);
while self.cursor.position() % size > 0 {
self.cursor.seek(SeekFrom::Current(1)).context(SeekForward { size: 1usize })?;
Ok(data)
}
trace!("realign_reads => realigned to: {}", self.cursor.position());
Ok(())
}
pub fn get_aligned(&mut self, data_type: KbinType) -> Result<Bytes, ByteBufferError> {
if self.offset_1 % 4 == 0 {
self.offset_1 = self.data_buf_offset();
}
if self.offset_2 % 4 == 0 {
self.offset_2 = self.data_buf_offset();
}
let old_pos = self.data_buf_offset();
let size = data_type.size * data_type.count;
trace!("get_aligned => old_pos: {}, size: {}", old_pos, size);
let (check_old, data) = match size {
1 => {
let end = self.check_read_size(self.offset_1, 1)?;
let data = self.buffer.slice(self.offset_1, end);
self.offset_1 += 1;
(true, data)
},
2 => {
let end = self.check_read_size(self.offset_2, 2)?;
let data = self.buffer.slice(self.offset_2, end);
self.offset_2 += 2;
(true, data)
},
size => {
let data = self
.buf_read_size(size as usize)
.map_err(Box::new)
.context(ReadAligned { size })?;
self.realign_reads(None)?;
(false, data)
},
};
if check_old {
let trailing = max(self.offset_1, self.offset_2);
trace!(
"get_aligned => old_pos: {}, trailing: {}",
old_pos,
trailing
);
if old_pos < trailing {
self.cursor
.seek(SeekFrom::Start(trailing as u64))
.context(SeekOffset { offset: trailing })?;
self.realign_reads(None)?;
}
}
Ok(data)
}
pub fn realign_reads(&mut self, size: Option<u64>) -> Result<(), ByteBufferError> {
let size = size.unwrap_or(4);
trace!(
"realign_reads => position: {}, size: {}",
self.cursor.position(),
size
);
while self.cursor.position() % size > 0 {
self.cursor
.seek(SeekFrom::Current(1))
.context(SeekForward { size: 1usize })?;
}
trace!("realign_reads => realigned to: {}", self.cursor.position());
Ok(())
}
}
impl ByteBufferWrite {
pub fn new(buffer: Vec<u8>) -> Self {
Self {
buffer: Cursor::new(buffer),
offset_1: 0,
offset_2: 0,
}
}
pub fn into_inner(self) -> Vec<u8> {
self.buffer.into_inner()
}
#[inline]
fn data_buf_offset(&self) -> u64 {
// Position is not the index of the previously read byte, it is the current
// index (offset).
//
// This is so much fun to debug.
//data_buf.position() - 1
self.buffer.position()
}
pub fn buf_write(&mut self, data: &[u8]) -> Result<(), ByteBufferError> {
self.buffer.write_u32::<BigEndian>(data.len() as u32).context(WriteLength { len: data.len() })?;
debug!("buf_write => index: {}, size: {}", self.buffer.position(), data.len());
self.buffer.write_all(data).context(WriteDataBlock)?;
trace!("buf_write => index: {}, size: {}, data: 0x{:02x?}", self.buffer.position(), data.len(), data);
self.realign_writes(None)?;
Ok(())
}
pub fn write_str(&mut self, encoding: EncodingType, data: &str) -> Result<(), KbinError> {
trace!("write_str => input: {}, data: 0x{:02x?}", data, data.as_bytes());
let bytes = encoding.encode_bytes(data)?;
self.buf_write(&bytes)?;
Ok(())
}
pub fn write_aligned(&mut self, data_type: KbinType, data: &[u8]) -> Result<(), KbinError> {
if self.offset_1 % 4 == 0 {
self.offset_1 = self.data_buf_offset();
}
if self.offset_2 % 4 == 0 {
self.offset_2 = self.data_buf_offset();
}
let old_pos = self.data_buf_offset();
let size = data_type.size * data_type.count;
trace!("write_aligned => old_pos: {}, size: {}, data: 0x{:02x?}", old_pos, size, data);
if size != data.len() {
return Err(KbinError::SizeMismatch { node_type: data_type.name, expected: size, actual: data.len() });
}
let check_old = match size {
1 => {
// Make room for new DWORD
if self.offset_1 % 4 == 0 {
self.buffer.write_u32::<BigEndian>(0).context(WritePadding { size: 4usize })?;
pub fn new(buffer: Vec<u8>) -> Self {
Self {
buffer: Cursor::new(buffer),
offset_1: 0,
offset_2: 0,
}
}
self.buffer.seek(SeekFrom::Start(self.offset_1)).context(SeekOffset { offset: self.offset_1 as usize })?;
self.buffer.write_u8(data[0]).context(WriteDataByte { offset: 1usize })?;
self.offset_1 += 1;
pub fn into_inner(self) -> Vec<u8> {
self.buffer.into_inner()
}
true
},
2 => {
// Make room for new DWORD
if self.offset_2 % 4 == 0 {
self.buffer.write_u32::<BigEndian>(0).context(WritePadding { size: 4usize })?;
}
#[inline]
fn data_buf_offset(&self) -> u64 {
// Position is not the index of the previously read byte, it is the current
// index (offset).
//
// This is so much fun to debug.
//data_buf.position() - 1
self.buffer.position()
}
self.buffer.seek(SeekFrom::Start(self.offset_2)).context(SeekOffset { offset: self.offset_2 as usize })?;
self.buffer.write_u8(data[0]).context(WriteDataByte { offset: 1usize })?;
self.buffer.write_u8(data[1]).context(WriteDataByte { offset: 2usize })?;
self.offset_2 += 2;
pub fn buf_write(&mut self, data: &[u8]) -> Result<(), ByteBufferError> {
self.buffer
.write_u32::<BigEndian>(data.len() as u32)
.context(WriteLength { len: data.len() })?;
debug!(
"buf_write => index: {}, size: {}",
self.buffer.position(),
data.len()
);
true
},
_ => {
self.buffer.write_all(data).context(WriteDataBlock)?;
trace!(
"buf_write => index: {}, size: {}, data: 0x{:02x?}",
self.buffer.position(),
data.len(),
data
);
self.realign_writes(None)?;
false
},
};
if check_old {
self.buffer.seek(SeekFrom::Start(old_pos)).context(SeekOffset { offset: old_pos as usize })?;
let trailing = max(self.offset_1, self.offset_2);
trace!("write_aligned => old_pos: {}, trailing: {}", old_pos, trailing);
if old_pos < trailing {
self.buffer.seek(SeekFrom::Start(trailing)).context(SeekOffset { offset: trailing as usize })?;
self.realign_writes(None)?;
}
Ok(())
}
Ok(())
}
pub fn write_str(&mut self, encoding: EncodingType, data: &str) -> Result<(), KbinError> {
trace!(
"write_str => input: {}, data: 0x{:02x?}",
data,
data.as_bytes()
);
pub fn realign_writes(&mut self, size: Option<u64>) -> Result<(), ByteBufferError> {
let size = size.unwrap_or(4);
trace!("realign_writes => position: {}, size: {}", self.buffer.position(), size);
let bytes = encoding.encode_bytes(data)?;
self.buf_write(&bytes)?;
while self.buffer.position() % size > 0 {
self.buffer.write_u8(0).context(WritePadding { size: 1usize })?;
Ok(())
}
trace!("realign_writes => realigned to: {}", self.buffer.position());
pub fn write_aligned(&mut self, data_type: KbinType, data: &[u8]) -> Result<(), KbinError> {
if self.offset_1 % 4 == 0 {
self.offset_1 = self.data_buf_offset();
}
if self.offset_2 % 4 == 0 {
self.offset_2 = self.data_buf_offset();
}
Ok(())
}
let old_pos = self.data_buf_offset();
let size = data_type.size * data_type.count;
trace!(
"write_aligned => old_pos: {}, size: {}, data: 0x{:02x?}",
old_pos,
size,
data
);
if size != data.len() {
return Err(KbinError::SizeMismatch {
node_type: data_type.name,
expected: size,
actual: data.len(),
});
}
let check_old = match size {
1 => {
// Make room for new DWORD
if self.offset_1 % 4 == 0 {
self.buffer
.write_u32::<BigEndian>(0)
.context(WritePadding { size: 4usize })?;
}
self.buffer
.seek(SeekFrom::Start(self.offset_1))
.context(SeekOffset {
offset: self.offset_1 as usize,
})?;
self.buffer
.write_u8(data[0])
.context(WriteDataByte { offset: 1usize })?;
self.offset_1 += 1;
true
},
2 => {
// Make room for new DWORD
if self.offset_2 % 4 == 0 {
self.buffer
.write_u32::<BigEndian>(0)
.context(WritePadding { size: 4usize })?;
}
self.buffer
.seek(SeekFrom::Start(self.offset_2))
.context(SeekOffset {
offset: self.offset_2 as usize,
})?;
self.buffer
.write_u8(data[0])
.context(WriteDataByte { offset: 1usize })?;
self.buffer
.write_u8(data[1])
.context(WriteDataByte { offset: 2usize })?;
self.offset_2 += 2;
true
},
_ => {
self.buffer.write_all(data).context(WriteDataBlock)?;
self.realign_writes(None)?;
false
},
};
if check_old {
self.buffer
.seek(SeekFrom::Start(old_pos))
.context(SeekOffset {
offset: old_pos as usize,
})?;
let trailing = max(self.offset_1, self.offset_2);
trace!(
"write_aligned => old_pos: {}, trailing: {}",
old_pos,
trailing
);
if old_pos < trailing {
self.buffer
.seek(SeekFrom::Start(trailing))
.context(SeekOffset {
offset: trailing as usize,
})?;
self.realign_writes(None)?;
}
}
Ok(())
}
pub fn realign_writes(&mut self, size: Option<u64>) -> Result<(), ByteBufferError> {
let size = size.unwrap_or(4);
trace!(
"realign_writes => position: {}, size: {}",
self.buffer.position(),
size
);
while self.buffer.position() % size > 0 {
self.buffer
.write_u8(0)
.context(WritePadding { size: 1usize })?;
}
trace!("realign_writes => realigned to: {}", self.buffer.position());
Ok(())
}
}
impl Deref for ByteBufferRead {
type Target = Cursor<Bytes>;
type Target = Cursor<Bytes>;
fn deref(&self) -> &Self::Target {
&self.cursor
}
fn deref(&self) -> &Self::Target {
&self.cursor
}
}
impl DerefMut for ByteBufferRead {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cursor
}
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cursor
}
}
impl Deref for ByteBufferWrite {
type Target = Cursor<Vec<u8>>;
type Target = Cursor<Vec<u8>>;
fn deref(&self) -> &Self::Target {
&self.buffer
}
fn deref(&self) -> &Self::Target {
&self.buffer
}
}
impl DerefMut for ByteBufferWrite {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer
}
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer
}
}

View File

@@ -1,31 +1,31 @@
use crate::error::KbinError;
use super::{SIG_COMPRESSED, SIG_UNCOMPRESSED};
use crate::error::KbinError;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Compression {
Compressed,
Uncompressed,
Compressed,
Uncompressed,
}
impl Compression {
pub fn from_byte(byte: u8) -> Result<Self, KbinError> {
match byte {
SIG_COMPRESSED => Ok(Compression::Compressed),
SIG_UNCOMPRESSED => Ok(Compression::Uncompressed),
_ => Err(KbinError::UnknownCompression),
pub fn from_byte(byte: u8) -> Result<Self, KbinError> {
match byte {
SIG_COMPRESSED => Ok(Compression::Compressed),
SIG_UNCOMPRESSED => Ok(Compression::Uncompressed),
_ => Err(KbinError::UnknownCompression),
}
}
}
pub fn to_byte(&self) -> u8 {
match *self {
Compression::Compressed => SIG_COMPRESSED,
Compression::Uncompressed => SIG_UNCOMPRESSED,
pub fn to_byte(&self) -> u8 {
match *self {
Compression::Compressed => SIG_COMPRESSED,
Compression::Uncompressed => SIG_UNCOMPRESSED,
}
}
}
}
impl Default for Compression {
fn default() -> Self {
Compression::Compressed
}
fn default() -> Self {
Compression::Compressed
}
}

View File

@@ -10,215 +10,205 @@ use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)]
pub enum EncodingError {
#[snafu(display("Unknown encoding"))]
UnknownEncoding,
#[snafu(display("Unknown encoding"))]
UnknownEncoding,
#[snafu(display("Another encoding was used to decode the input: {:?}", actual))]
MismatchedDecode {
actual: &'static Encoding,
},
#[snafu(display("Another encoding was used to decode the input: {:?}", actual))]
MismatchedDecode { actual: &'static Encoding },
#[snafu(display("Another encoding was used to encode the output: {:?}", actual))]
MismatchedEncode {
actual: &'static Encoding,
},
#[snafu(display("Another encoding was used to encode the output: {:?}", actual))]
MismatchedEncode { actual: &'static Encoding },
#[snafu(display("Unmappable characters found in input"))]
UnmappableCharacters,
#[snafu(display("Unmappable characters found in input"))]
UnmappableCharacters,
#[snafu(display("Invalid ASCII character at index: {}", index))]
InvalidAscii {
index: usize,
},
#[snafu(display("Invalid ASCII character at index: {}", index))]
InvalidAscii { index: usize },
#[snafu(display("Failed to interpret string as UTF-8"))]
InvalidUtf8 {
source: FromUtf8Error,
},
#[snafu(display("Failed to interpret string as UTF-8"))]
InvalidUtf8 { source: FromUtf8Error },
#[snafu(display("Failed to convert string to alternate encoding"))]
Convert,
#[snafu(display("Failed to convert string to alternate encoding"))]
Convert,
}
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EncodingType {
None,
ASCII,
ISO_8859_1,
EUC_JP,
SHIFT_JIS,
UTF_8,
None,
ASCII,
ISO_8859_1,
EUC_JP,
SHIFT_JIS,
UTF_8,
}
impl Default for EncodingType {
fn default() -> Self {
EncodingType::SHIFT_JIS
}
fn default() -> Self {
EncodingType::SHIFT_JIS
}
}
impl fmt::Display for EncodingType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let encoding = match *self {
EncodingType::None => "None",
EncodingType::ASCII => "ASCII",
EncodingType::ISO_8859_1 => "ISO-8859-1",
EncodingType::EUC_JP => "EUC-JP",
EncodingType::SHIFT_JIS => "SHIFT-JIS",
EncodingType::UTF_8 => "UTF-8",
};
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let encoding = match *self {
EncodingType::None => "None",
EncodingType::ASCII => "ASCII",
EncodingType::ISO_8859_1 => "ISO-8859-1",
EncodingType::EUC_JP => "EUC-JP",
EncodingType::SHIFT_JIS => "SHIFT-JIS",
EncodingType::UTF_8 => "UTF-8",
};
write!(f, "{}", encoding)
}
write!(f, "{}", encoding)
}
}
impl EncodingType {
pub fn from_byte(byte: u8) -> Result<Self, EncodingError> {
let val = match byte {
0x00 => EncodingType::None,
0x20 => EncodingType::ASCII,
0x40 => EncodingType::ISO_8859_1,
0x60 => EncodingType::EUC_JP,
0x80 => EncodingType::SHIFT_JIS,
0xA0 => EncodingType::UTF_8,
_ => return Err(EncodingError::UnknownEncoding),
};
pub fn from_byte(byte: u8) -> Result<Self, EncodingError> {
let val = match byte {
0x00 => EncodingType::None,
0x20 => EncodingType::ASCII,
0x40 => EncodingType::ISO_8859_1,
0x60 => EncodingType::EUC_JP,
0x80 => EncodingType::SHIFT_JIS,
0xA0 => EncodingType::UTF_8,
_ => return Err(EncodingError::UnknownEncoding),
};
Ok(val)
}
pub fn from_encoding(encoding: &'static Encoding) -> Result<Self, EncodingError> {
match encoding {
e if e == WINDOWS_1252 => Ok(EncodingType::ISO_8859_1),
e if e == EUC_JP => Ok(EncodingType::EUC_JP),
e if e == SHIFT_JIS => Ok(EncodingType::SHIFT_JIS),
e if e == UTF_8 => Ok(EncodingType::UTF_8),
_ => return Err(EncodingError::UnknownEncoding),
}
}
pub fn from_label(label: &[u8]) -> Result<Self, EncodingError> {
Encoding::for_label(label)
.ok_or(EncodingError::UnknownEncoding)
.and_then(Self::from_encoding)
}
pub fn to_byte(&self) -> u8 {
match *self {
EncodingType::None => 0x00, // 0x00 >> 5 = 0
EncodingType::ASCII => 0x20, // 0x20 >> 5 = 1
EncodingType::ISO_8859_1 => 0x40, // 0x40 >> 5 = 2
EncodingType::EUC_JP => 0x60, // 0x60 >> 5 = 3
EncodingType::SHIFT_JIS => 0x80, // 0x80 >> 5 = 4
EncodingType::UTF_8 => 0xA0, // 0xA0 >> 5 = 5
}
}
pub fn name(&self) -> Option<&'static str> {
match *self {
EncodingType::None => None,
EncodingType::ASCII => None,
EncodingType::ISO_8859_1 => Some(WINDOWS_1252.name()),
EncodingType::EUC_JP => Some(EUC_JP.name()),
EncodingType::SHIFT_JIS => Some(SHIFT_JIS.name()),
EncodingType::UTF_8 => Some(UTF_8.name()),
}
}
fn decode_ascii(input: &[u8]) -> Result<String, EncodingError> {
// ASCII only goes up to 0x7F
match input.iter().position(|&ch| ch >= 0x80) {
Some(index) => {
Err(EncodingError::InvalidAscii { index })
},
None => {
String::from_utf8(input.to_vec()).context(InvalidUtf8)
},
}
}
fn encode_ascii(input: &str) -> Result<Vec<u8>, EncodingError> {
// ASCII only goes up to 0x7F
match input.as_bytes().iter().position(|&ch| ch >= 0x80) {
Some(index) => {
Err(EncodingError::InvalidAscii { index })
},
None => {
Ok(input.as_bytes().to_vec())
},
}
}
fn decode_with_encoding(encoding: &'static Encoding, input: &[u8]) -> Result<String, EncodingError> {
let (output, actual, character_replaced) = encoding.decode(input);
//eprintln!("character replaced: {}", character_replaced);
if character_replaced {
warn!("Character replacement occured with: {:?}", output);
Ok(val)
}
// `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's
// implementation will include invalid characters.
if encoding != actual {
Err(EncodingError::MismatchedDecode { actual })
} else if !character_replaced || encoding == SHIFT_JIS {
Ok(output.into_owned())
} else {
Err(EncodingError::UnmappableCharacters)
pub fn from_encoding(encoding: &'static Encoding) -> Result<Self, EncodingError> {
match encoding {
e if e == WINDOWS_1252 => Ok(EncodingType::ISO_8859_1),
e if e == EUC_JP => Ok(EncodingType::EUC_JP),
e if e == SHIFT_JIS => Ok(EncodingType::SHIFT_JIS),
e if e == UTF_8 => Ok(EncodingType::UTF_8),
_ => return Err(EncodingError::UnknownEncoding),
}
}
}
fn encode_with_encoding(encoding: &'static Encoding, input: &str) -> Result<Vec<u8>, EncodingError> {
let (output, actual, had_unmappable_characters) = encoding.encode(input);
if encoding != actual {
Err(EncodingError::MismatchedEncode { actual })
} else if had_unmappable_characters {
Err(EncodingError::UnmappableCharacters)
} else {
Ok(output.into_owned())
pub fn from_label(label: &[u8]) -> Result<Self, EncodingError> {
Encoding::for_label(label)
.ok_or(EncodingError::UnknownEncoding)
.and_then(Self::from_encoding)
}
}
/// Decode bytes using the encoding definition from the `encoding` crate.
///
/// A `Some` value indicates an encoding should be used from the `encoding`
/// crate. A `None` value indicates Rust's own UTF-8 handling should be used.
///
/// `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's
/// implementation will include invalid characters.
pub fn decode_bytes(&self, input: &[u8]) -> Result<String, EncodingError> {
match *self {
EncodingType::None |
EncodingType::UTF_8 => String::from_utf8(input.to_vec()).context(InvalidUtf8),
EncodingType::ASCII => Self::decode_ascii(input),
EncodingType::ISO_8859_1 => Self::decode_with_encoding(WINDOWS_1252, input),
EncodingType::EUC_JP => Self::decode_with_encoding(EUC_JP, input),
EncodingType::SHIFT_JIS => Self::decode_with_encoding(SHIFT_JIS, input),
pub fn to_byte(&self) -> u8 {
match *self {
EncodingType::None => 0x00, // 0x00 >> 5 = 0
EncodingType::ASCII => 0x20, // 0x20 >> 5 = 1
EncodingType::ISO_8859_1 => 0x40, // 0x40 >> 5 = 2
EncodingType::EUC_JP => 0x60, // 0x60 >> 5 = 3
EncodingType::SHIFT_JIS => 0x80, // 0x80 >> 5 = 4
EncodingType::UTF_8 => 0xA0, // 0xA0 >> 5 = 5
}
}
}
/// Encode bytes using the encoding definition from the `encoding` crate.
///
/// A `Some` value indicates the encoding should be used from the `encoding`
/// crate. A `None` value indicates Rust's own UTF-8 handling should be used.
pub fn encode_bytes(&self, input: &str) -> Result<Vec<u8>, EncodingError> {
let mut result = match *self {
EncodingType::None |
EncodingType::UTF_8 => input.as_bytes().to_vec(),
pub fn name(&self) -> Option<&'static str> {
match *self {
EncodingType::None => None,
EncodingType::ASCII => None,
EncodingType::ISO_8859_1 => Some(WINDOWS_1252.name()),
EncodingType::EUC_JP => Some(EUC_JP.name()),
EncodingType::SHIFT_JIS => Some(SHIFT_JIS.name()),
EncodingType::UTF_8 => Some(UTF_8.name()),
}
}
EncodingType::ASCII => Self::encode_ascii(input)?,
EncodingType::ISO_8859_1 => Self::encode_with_encoding(WINDOWS_1252, input)?,
EncodingType::EUC_JP => Self::encode_with_encoding(EUC_JP, input)?,
EncodingType::SHIFT_JIS => Self::encode_with_encoding(SHIFT_JIS, input)?,
};
fn decode_ascii(input: &[u8]) -> Result<String, EncodingError> {
// ASCII only goes up to 0x7F
match input.iter().position(|&ch| ch >= 0x80) {
Some(index) => Err(EncodingError::InvalidAscii { index }),
None => String::from_utf8(input.to_vec()).context(InvalidUtf8),
}
}
// Add trailing null byte
result.reserve_exact(1);
result.push(0);
fn encode_ascii(input: &str) -> Result<Vec<u8>, EncodingError> {
// ASCII only goes up to 0x7F
match input.as_bytes().iter().position(|&ch| ch >= 0x80) {
Some(index) => Err(EncodingError::InvalidAscii { index }),
None => Ok(input.as_bytes().to_vec()),
}
}
Ok(result)
}
fn decode_with_encoding(
encoding: &'static Encoding,
input: &[u8],
) -> Result<String, EncodingError> {
let (output, actual, character_replaced) = encoding.decode(input);
//eprintln!("character replaced: {}", character_replaced);
if character_replaced {
warn!("Character replacement occured with: {:?}", output);
}
// `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's
// implementation will include invalid characters.
if encoding != actual {
Err(EncodingError::MismatchedDecode { actual })
} else if !character_replaced || encoding == SHIFT_JIS {
Ok(output.into_owned())
} else {
Err(EncodingError::UnmappableCharacters)
}
}
fn encode_with_encoding(
encoding: &'static Encoding,
input: &str,
) -> Result<Vec<u8>, EncodingError> {
let (output, actual, had_unmappable_characters) = encoding.encode(input);
if encoding != actual {
Err(EncodingError::MismatchedEncode { actual })
} else if had_unmappable_characters {
Err(EncodingError::UnmappableCharacters)
} else {
Ok(output.into_owned())
}
}
/// Decode bytes using the encoding definition from the `encoding` crate.
///
/// A `Some` value indicates an encoding should be used from the `encoding`
/// crate. A `None` value indicates Rust's own UTF-8 handling should be used.
///
/// `EncodingType::SHIFT_JIS` will ignore invalid characters because Konami's
/// implementation will include invalid characters.
pub fn decode_bytes(&self, input: &[u8]) -> Result<String, EncodingError> {
match *self {
EncodingType::None | EncodingType::UTF_8 => {
String::from_utf8(input.to_vec()).context(InvalidUtf8)
},
EncodingType::ASCII => Self::decode_ascii(input),
EncodingType::ISO_8859_1 => Self::decode_with_encoding(WINDOWS_1252, input),
EncodingType::EUC_JP => Self::decode_with_encoding(EUC_JP, input),
EncodingType::SHIFT_JIS => Self::decode_with_encoding(SHIFT_JIS, input),
}
}
/// Encode bytes using the encoding definition from the `encoding` crate.
///
/// A `Some` value indicates the encoding should be used from the `encoding`
/// crate. A `None` value indicates Rust's own UTF-8 handling should be used.
pub fn encode_bytes(&self, input: &str) -> Result<Vec<u8>, EncodingError> {
let mut result = match *self {
EncodingType::None | EncodingType::UTF_8 => input.as_bytes().to_vec(),
EncodingType::ASCII => Self::encode_ascii(input)?,
EncodingType::ISO_8859_1 => Self::encode_with_encoding(WINDOWS_1252, input)?,
EncodingType::EUC_JP => Self::encode_with_encoding(EUC_JP, input)?,
EncodingType::SHIFT_JIS => Self::encode_with_encoding(SHIFT_JIS, input)?,
};
// Add trailing null byte
result.reserve_exact(1);
result.push(0);
Ok(result)
}
}

View File

@@ -6,8 +6,8 @@ use std::result::Result as StdResult;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use rustc_hex::FromHexError;
use quick_xml::Error as QuickXmlError;
use rustc_hex::FromHexError;
use snafu::Snafu;
use crate::byte_buffer::ByteBufferError;
@@ -22,185 +22,169 @@ pub type Result<T> = StdResult<T, KbinError>;
#[derive(Debug, Snafu)]
#[snafu(visibility = "pub(crate)")]
pub enum KbinError {
#[snafu(display("Unable to write {} header field", field))]
HeaderWrite {
field: &'static str,
source: io::Error,
},
#[snafu(display("Unable to write {} header field", field))]
HeaderWrite {
field: &'static str,
source: io::Error,
},
#[snafu(display("Invalid byte value for {} header field", field))]
HeaderValue {
field: &'static str,
},
#[snafu(display("Invalid byte value for {} header field", field))]
HeaderValue { field: &'static str },
#[snafu(display("Unable to read {} bytes from data buffer", size))]
DataRead {
size: usize,
source: io::Error,
},
#[snafu(display("Unable to read {} bytes from data buffer", size))]
DataRead { size: usize, source: io::Error },
#[snafu(display("Unable to write a {} to data buffer", node_type))]
DataWrite {
node_type: &'static str,
source: io::Error,
},
#[snafu(display("Unable to write a {} to data buffer", node_type))]
DataWrite {
node_type: &'static str,
source: io::Error,
},
#[snafu(display("Unable to read bytes or not enough data read"))]
DataConvert {
source: io::Error,
},
#[snafu(display("Unable to read bytes or not enough data read"))]
DataConvert { source: io::Error },
#[snafu(display("No node collection found"))]
NoNodeCollection,
#[snafu(display("No node collection found"))]
NoNodeCollection,
#[snafu(display("Failed to interpret string as UTF-8"))]
Utf8 {
source: FromUtf8Error,
},
#[snafu(display("Failed to interpret string as UTF-8"))]
Utf8 { source: FromUtf8Error },
#[snafu(display("Failed to interpret slice as UTF-8"))]
Utf8Slice {
source: Utf8Error,
},
#[snafu(display("Failed to interpret slice as UTF-8"))]
Utf8Slice { source: Utf8Error },
#[snafu(display("Unknown compression value"))]
UnknownCompression,
#[snafu(display("Unknown compression value"))]
UnknownCompression,
#[snafu(display("Size Mismatch, type: {}, expected size: {}, actual size: {}", node_type, expected, actual))]
SizeMismatch {
node_type: &'static str,
expected: usize,
actual: usize,
},
#[snafu(display(
"Size Mismatch, type: {}, expected size: {}, actual size: {}",
node_type,
expected,
actual
))]
SizeMismatch {
node_type: &'static str,
expected: usize,
actual: usize,
},
#[snafu(display("Unable to interpret input as {}", node_type))]
StringParse {
node_type: &'static str,
source: Box<dyn Error + Send + Sync>,
},
#[snafu(display("Unable to interpret input as {}", node_type))]
StringParse {
node_type: &'static str,
source: Box<dyn Error + Send + Sync>,
},
#[snafu(display("Unable to interpret integer input as {}", node_type))]
StringParseInt {
node_type: &'static str,
source: ParseIntError,
},
#[snafu(display("Unable to interpret integer input as {}", node_type))]
StringParseInt {
node_type: &'static str,
source: ParseIntError,
},
#[snafu(display("Unable to interpret float input as {}", node_type))]
StringParseFloat {
node_type: &'static str,
source: ParseFloatError,
},
#[snafu(display("Unable to interpret float input as {}", node_type))]
StringParseFloat {
node_type: &'static str,
source: ParseFloatError,
},
#[snafu(display("Unable to convert from hexadecimal"))]
HexError {
source: FromHexError,
},
#[snafu(display("Unable to convert from hexadecimal"))]
HexError { source: FromHexError },
#[snafu(display("Type mismatch, expected: {}, found: {}", expected, found))]
TypeMismatch {
expected: StandardType,
found: StandardType,
},
#[snafu(display("Type mismatch, expected: {}, found: {}", expected, found))]
TypeMismatch {
expected: StandardType,
found: StandardType,
},
#[snafu(display("Value mismatch, expected {}, but found {:?}", node_type, value))]
ValueTypeMismatch {
node_type: StandardType,
value: Value,
},
#[snafu(display("Value mismatch, expected {}, but found {:?}", node_type, value))]
ValueTypeMismatch {
node_type: StandardType,
value: Value,
},
#[snafu(display("Value mismatch, expected an array, but found {:?}", value))]
ExpectedValueArray {
value: Value,
},
#[snafu(display("Value mismatch, expected an array, but found {:?}", value))]
ExpectedValueArray { value: Value },
#[snafu(display("Invalid input for boolean: {}", input))]
InvalidBooleanInput {
input: u8,
},
#[snafu(display("Invalid input for boolean: {}", input))]
InvalidBooleanInput { input: u8 },
#[snafu(display("Invalid node type for operation: {:?}", node_type))]
InvalidNodeType {
node_type: StandardType,
},
#[snafu(display("Invalid node type for operation: {:?}", node_type))]
InvalidNodeType { node_type: StandardType },
#[snafu(display("Invalid state"))]
InvalidState,
#[snafu(display("Invalid state"))]
InvalidState,
#[snafu(display("Failed to handle byte buffer operation"))]
ByteBuffer {
#[snafu(backtrace)]
source: ByteBufferError,
},
#[snafu(display("Failed to handle byte buffer operation"))]
ByteBuffer {
#[snafu(backtrace)]
source: ByteBufferError,
},
#[snafu(display("Failed to handle string encoding operation"))]
Encoding {
#[snafu(backtrace)]
source: EncodingError,
},
#[snafu(display("Failed to handle string encoding operation"))]
Encoding {
#[snafu(backtrace)]
source: EncodingError,
},
#[snafu(display("Failed to read binary XML"))]
Reader {
#[snafu(backtrace)]
source: ReaderError,
},
#[snafu(display("Failed to read binary XML"))]
Reader {
#[snafu(backtrace)]
source: ReaderError,
},
#[snafu(display("Failed to handle sixbit string operation"))]
Sixbit {
#[snafu(backtrace)]
source: SixbitError,
},
#[snafu(display("Failed to handle sixbit string operation"))]
Sixbit {
#[snafu(backtrace)]
source: SixbitError,
},
#[snafu(display("Error handling XML"))]
XmlError {
source: QuickXmlError,
},
#[snafu(display("Error handling XML"))]
XmlError { source: QuickXmlError },
}
impl From<FromUtf8Error> for KbinError {
#[inline]
fn from(source: FromUtf8Error) -> Self {
KbinError::Utf8 { source }
}
#[inline]
fn from(source: FromUtf8Error) -> Self {
KbinError::Utf8 { source }
}
}
impl From<Utf8Error> for KbinError {
#[inline]
fn from(source: Utf8Error) -> Self {
KbinError::Utf8Slice { source }
}
#[inline]
fn from(source: Utf8Error) -> Self {
KbinError::Utf8Slice { source }
}
}
impl From<ByteBufferError> for KbinError {
#[inline]
fn from(source: ByteBufferError) -> Self {
KbinError::ByteBuffer { source }
}
#[inline]
fn from(source: ByteBufferError) -> Self {
KbinError::ByteBuffer { source }
}
}
impl From<EncodingError> for KbinError {
#[inline]
fn from(source: EncodingError) -> Self {
KbinError::Encoding { source }
}
#[inline]
fn from(source: EncodingError) -> Self {
KbinError::Encoding { source }
}
}
impl From<ReaderError> for KbinError {
#[inline]
fn from(source: ReaderError) -> Self {
KbinError::Reader { source }
}
#[inline]
fn from(source: ReaderError) -> Self {
KbinError::Reader { source }
}
}
impl From<SixbitError> for KbinError {
#[inline]
fn from(source: SixbitError) -> Self {
KbinError::Sixbit { source }
}
#[inline]
fn from(source: SixbitError) -> Self {
KbinError::Sixbit { source }
}
}
impl From<QuickXmlError> for KbinError {
#[inline]
fn from(source: QuickXmlError) -> Self {
KbinError::XmlError { source }
}
#[inline]
fn from(source: QuickXmlError) -> Self {
KbinError::XmlError { source }
}
}

View File

@@ -1,7 +1,9 @@
#![cfg_attr(test, feature(test))]
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate log;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
use bytes::Bytes;
@@ -27,15 +29,15 @@ use crate::to_text_xml::TextXmlWriter;
// Public exports
pub use crate::compression::Compression;
pub use crate::encoding_type::EncodingType;
pub use crate::printer::Printer;
pub use crate::reader::Reader;
pub use crate::error::{KbinError, Result};
pub use crate::node::{Node, NodeCollection};
pub use crate::node_types::StandardType;
pub use crate::options::{Options, OptionsBuilder};
pub use crate::printer::Printer;
pub use crate::reader::Reader;
pub use crate::to_text_xml::ToTextXml;
pub use crate::value::{Value, ValueArray};
pub use crate::writer::{Writer, Writeable};
pub use crate::writer::{Writeable, Writer};
const SIGNATURE: u8 = 0xA0;
@@ -45,55 +47,62 @@ const SIG_UNCOMPRESSED: u8 = 0x45;
const ARRAY_MASK: u8 = 1 << 6; // 1 << 6 = 64
pub fn is_binary_xml(input: &[u8]) -> bool {
input.len() > 2 && input[0] == SIGNATURE && (input[1] == SIG_COMPRESSED || input[1] == SIG_UNCOMPRESSED)
input.len() > 2 &&
input[0] == SIGNATURE &&
(input[1] == SIG_COMPRESSED || input[1] == SIG_UNCOMPRESSED)
}
pub fn from_binary(input: Bytes) -> Result<(NodeCollection, EncodingType)> {
let mut reader = Reader::new(input)?;
let collection = NodeCollection::from_iter(&mut reader).ok_or(KbinError::NoNodeCollection)?;
let encoding = reader.encoding();
let mut reader = Reader::new(input)?;
let collection = NodeCollection::from_iter(&mut reader).ok_or(KbinError::NoNodeCollection)?;
let encoding = reader.encoding();
Ok((collection, encoding))
Ok((collection, encoding))
}
pub fn from_text_xml(input: &[u8]) -> Result<(NodeCollection, EncodingType)> {
let mut reader = TextXmlReader::new(input);
let collection = reader.as_node_collection()?.ok_or(KbinError::NoNodeCollection)?;
let encoding = reader.encoding();
let mut reader = TextXmlReader::new(input);
let collection = reader
.as_node_collection()?
.ok_or(KbinError::NoNodeCollection)?;
let encoding = reader.encoding();
Ok((collection, encoding))
Ok((collection, encoding))
}
pub fn from_bytes(input: Bytes) -> Result<(NodeCollection, EncodingType)> {
if is_binary_xml(&input) {
from_binary(input)
} else {
from_text_xml(&input)
}
if is_binary_xml(&input) {
from_binary(input)
} else {
from_text_xml(&input)
}
}
#[inline]
pub fn from_slice(input: &[u8]) -> Result<(NodeCollection, EncodingType)> {
from_binary(Bytes::from(input))
from_binary(Bytes::from(input))
}
pub fn to_binary<T>(input: &T) -> Result<Vec<u8>>
where T: Writeable
where
T: Writeable,
{
let mut writer = Writer::new();
writer.to_binary(input)
let mut writer = Writer::new();
writer.to_binary(input)
}
pub fn to_binary_with_options<T>(options: Options, input: &T) -> Result<Vec<u8>>
where T: Writeable
where
T: Writeable,
{
let mut writer = Writer::with_options(options);
writer.to_binary(input)
let mut writer = Writer::with_options(options);
writer.to_binary(input)
}
pub fn to_text_xml<T>(input: &T) -> Result<Vec<u8>>
where T: ToTextXml
where
T: ToTextXml,
{
let writer = TextXmlWriter::new();
writer.to_text_xml(input)
let writer = TextXmlWriter::new();
writer.to_text_xml(input)
}

View File

@@ -8,189 +8,201 @@ use crate::node_types::StandardType;
use crate::value::Value;
fn parse_index(s: &str) -> Option<usize> {
if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
return None;
}
s.parse().ok()
if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
return None;
}
s.parse().ok()
}
/// A collection of node definitions (`NodeDefinition`)
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NodeCollection {
base: NodeDefinition,
attributes: VecDeque<NodeDefinition>,
children: VecDeque<NodeCollection>,
base: NodeDefinition,
attributes: VecDeque<NodeDefinition>,
children: VecDeque<NodeCollection>,
}
impl NodeCollection {
pub fn new(base: NodeDefinition) -> Self {
Self {
base,
attributes: VecDeque::with_capacity(0),
children: VecDeque::with_capacity(0),
}
}
pub fn with_attributes(base: NodeDefinition, attributes: VecDeque<NodeDefinition>) -> Self {
Self {
base,
attributes,
children: VecDeque::with_capacity(0),
}
}
pub fn from_iter<I>(iter: &mut I) -> Option<NodeCollection>
where I: Iterator<Item = NodeDefinition>
{
let base = if let Some(def) = iter.next() {
def
} else {
return None;
};
NodeCollection::from_iter_base(base, iter)
}
fn from_iter_base<I>(base: NodeDefinition, iter: &mut I) -> Option<NodeCollection>
where I: Iterator<Item = NodeDefinition>
{
let mut attributes = VecDeque::new();
let mut children = VecDeque::new();
loop {
if let Some(def) = iter.next() {
match def.node_type {
StandardType::Attribute => attributes.push_back(def),
StandardType::NodeEnd |
StandardType::FileEnd => break,
_ => match NodeCollection::from_iter_base(def, iter) {
Some(child) => children.push_back(child),
None => return None,
},
pub fn new(base: NodeDefinition) -> Self {
Self {
base,
attributes: VecDeque::with_capacity(0),
children: VecDeque::with_capacity(0),
}
} else {
break;
}
}
Some(NodeCollection {
base,
attributes,
children,
})
}
#[inline]
pub fn base(&self) -> &NodeDefinition {
&self.base
}
#[inline]
pub fn base_mut(&mut self) -> &mut NodeDefinition {
&mut self.base
}
#[inline]
pub fn attributes(&self) -> &VecDeque<NodeDefinition> {
&self.attributes
}
#[inline]
pub fn attributes_mut(&mut self) -> &mut VecDeque<NodeDefinition> {
&mut self.attributes
}
#[inline]
pub fn children(&self) -> &VecDeque<NodeCollection> {
&self.children
}
#[inline]
pub fn children_mut(&mut self) -> &mut VecDeque<NodeCollection> {
&mut self.children
}
pub fn as_node(&self) -> Result<Node, KbinError> {
let mut node = self.base.as_node()?;
for attr in &self.attributes {
let key = attr.key()?.ok_or(KbinError::InvalidState)?;
if let Value::Attribute(value) = attr.value()? {
node.set_attr(key, value);
} else {
return Err(KbinError::InvalidState.into());
}
pub fn with_attributes(base: NodeDefinition, attributes: VecDeque<NodeDefinition>) -> Self {
Self {
base,
attributes,
children: VecDeque::with_capacity(0),
}
}
for child in &self.children {
node.append_child(child.as_node()?);
pub fn from_iter<I>(iter: &mut I) -> Option<NodeCollection>
where
I: Iterator<Item = NodeDefinition>,
{
let base = if let Some(def) = iter.next() {
def
} else {
return None;
};
NodeCollection::from_iter_base(base, iter)
}
Ok(node)
}
fn from_iter_base<I>(base: NodeDefinition, iter: &mut I) -> Option<NodeCollection>
where
I: Iterator<Item = NodeDefinition>,
{
let mut attributes = VecDeque::new();
let mut children = VecDeque::new();
pub fn pointer<'a>(&'a self, pointer: &[&str]) -> Option<&'a NodeCollection> {
if pointer.is_empty() {
return Some(self);
}
let mut target = self;
loop {
if let Some(def) = iter.next() {
match def.node_type {
StandardType::Attribute => attributes.push_back(def),
StandardType::NodeEnd | StandardType::FileEnd => break,
_ => match NodeCollection::from_iter_base(def, iter) {
Some(child) => children.push_back(child),
None => return None,
},
}
} else {
break;
}
}
for token in pointer {
let target_opt = if let Some(index) = parse_index(token) {
target.children().get(index)
} else {
target.children().iter().find(|ref child| {
child.base().key().ok().and_then(|x| x).expect("key not parseable") == *token
Some(NodeCollection {
base,
attributes,
children,
})
};
if let Some(t) = target_opt {
target = t;
} else {
return None;
}
}
Some(target)
}
#[inline]
pub fn base(&self) -> &NodeDefinition {
&self.base
}
#[inline]
pub fn base_mut(&mut self) -> &mut NodeDefinition {
&mut self.base
}
#[inline]
pub fn attributes(&self) -> &VecDeque<NodeDefinition> {
&self.attributes
}
#[inline]
pub fn attributes_mut(&mut self) -> &mut VecDeque<NodeDefinition> {
&mut self.attributes
}
#[inline]
pub fn children(&self) -> &VecDeque<NodeCollection> {
&self.children
}
#[inline]
pub fn children_mut(&mut self) -> &mut VecDeque<NodeCollection> {
&mut self.children
}
pub fn as_node(&self) -> Result<Node, KbinError> {
let mut node = self.base.as_node()?;
for attr in &self.attributes {
let key = attr.key()?.ok_or(KbinError::InvalidState)?;
if let Value::Attribute(value) = attr.value()? {
node.set_attr(key, value);
} else {
return Err(KbinError::InvalidState.into());
}
}
for child in &self.children {
node.append_child(child.as_node()?);
}
Ok(node)
}
pub fn pointer<'a>(&'a self, pointer: &[&str]) -> Option<&'a NodeCollection> {
if pointer.is_empty() {
return Some(self);
}
let mut target = self;
for token in pointer {
let target_opt = if let Some(index) = parse_index(token) {
target.children().get(index)
} else {
target.children().iter().find(|ref child| {
child
.base()
.key()
.ok()
.and_then(|x| x)
.expect("key not parseable") ==
*token
})
};
if let Some(t) = target_opt {
target = t;
} else {
return None;
}
}
Some(target)
}
}
struct DisplayDebugWrapper<'a, T: fmt::Display + 'a>(&'a T, bool);
impl<'a, T> fmt::Debug for DisplayDebugWrapper<'a, T>
where T: fmt::Display
where
T: fmt::Display,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.1 {
write!(f, "{:#}", self.0)
} else {
write!(f, "{}", self.0)
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.1 {
write!(f, "{:#}", self.0)
} else {
write!(f, "{}", self.0)
}
}
}
}
struct VecDisplayDebugWrapper<'a, T: fmt::Display + 'a>(&'a VecDeque<T>, bool);
impl<'a, T> fmt::Debug for VecDisplayDebugWrapper<'a, T>
where T: fmt::Display
where
T: fmt::Display,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut l = f.debug_list();
for entry in self.0 {
l.entry(&DisplayDebugWrapper(&entry, self.1));
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut l = f.debug_list();
for entry in self.0 {
l.entry(&DisplayDebugWrapper(&entry, self.1));
}
l.finish()
}
l.finish()
}
}
impl fmt::Display for NodeCollection {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut d = f.debug_struct("NodeCollection");
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut d = f.debug_struct("NodeCollection");
d.field("base", &DisplayDebugWrapper(&self.base, false));
d.field("attributes", &VecDisplayDebugWrapper(&self.attributes, false));
d.field("children", &VecDisplayDebugWrapper(&self.children, true));
d.field("base", &DisplayDebugWrapper(&self.base, false));
d.field(
"attributes",
&VecDisplayDebugWrapper(&self.attributes, false),
);
d.field("children", &VecDisplayDebugWrapper(&self.children, true));
d.finish()
}
d.finish()
}
}

View File

@@ -12,232 +12,217 @@ use crate::value::Value;
#[derive(Clone, Eq)]
pub enum Key {
Compressed {
size: SixbitSize,
data: Bytes,
},
Uncompressed {
encoding: EncodingType,
data: Bytes,
},
Compressed { size: SixbitSize, data: Bytes },
Uncompressed { encoding: EncodingType, data: Bytes },
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum NodeData {
Some {
key: Key,
value_data: Bytes,
},
None,
Some { key: Key, value_data: Bytes },
None,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NodeDefinition {
encoding: EncodingType,
pub node_type: StandardType,
pub is_array: bool,
encoding: EncodingType,
pub node_type: StandardType,
pub is_array: bool,
data: NodeData,
data: NodeData,
}
impl Key {
fn to_string(&self) -> Result<String, KbinError> {
match self {
Key::Compressed { ref size, ref data } => {
Sixbit::unpack(data, *size).map_err(Into::into)
},
Key::Uncompressed { encoding, ref data } => {
encoding.decode_bytes(data).map_err(Into::into)
},
fn to_string(&self) -> Result<String, KbinError> {
match self {
Key::Compressed { ref size, ref data } => {
Sixbit::unpack(data, *size).map_err(Into::into)
},
Key::Uncompressed { encoding, ref data } => {
encoding.decode_bytes(data).map_err(Into::into)
},
}
}
}
}
impl NodeDefinition {
pub fn new(encoding: EncodingType, node_type: (StandardType, bool)) -> Self {
let (node_type, is_array) = node_type;
pub fn new(encoding: EncodingType, node_type: (StandardType, bool)) -> Self {
let (node_type, is_array) = node_type;
Self {
encoding,
node_type,
is_array,
data: NodeData::None,
}
}
pub fn with_data(encoding: EncodingType, node_type: (StandardType, bool), data: NodeData) -> Self {
let (node_type, is_array) = node_type;
Self {
encoding,
node_type,
is_array,
data,
}
}
#[inline]
pub fn encoding(&self) -> EncodingType {
self.encoding
}
#[inline]
pub fn node_type_tuple(&self) -> (StandardType, bool) {
(self.node_type, self.is_array)
}
#[inline]
pub fn data<'a>(&'a self) -> &'a NodeData {
&self.data
}
#[inline]
pub fn data_mut<'a>(&'a mut self) -> &'a mut NodeData {
&mut self.data
}
pub fn key(&self) -> Result<Option<String>, KbinError> {
match self.data {
NodeData::Some { ref key, .. } => key.to_string().map(Some),
NodeData::None => Ok(None),
}
}
pub fn value(&self) -> Result<Value, KbinError> {
match (self.node_type, &self.data) {
(StandardType::Attribute, NodeData::Some { ref value_data, .. }) => {
let data = strip_trailing_null_bytes(value_data);
let value = self.encoding.decode_bytes(data)?;
Ok(Value::Attribute(value))
},
(StandardType::String, NodeData::Some { ref value_data, .. }) => {
let data = strip_trailing_null_bytes(value_data);
let value = self.encoding.decode_bytes(data)?;
Ok(Value::String(value))
},
(node_type, NodeData::Some { ref value_data, .. }) => {
let value = Value::from_standard_type(node_type, self.is_array, value_data)?;
match value {
Some(value) => Ok(value),
None => Err(KbinError::InvalidNodeType { node_type }),
Self {
encoding,
node_type,
is_array,
data: NodeData::None,
}
},
(node_type, NodeData::None) => {
Err(KbinError::InvalidNodeType { node_type })
},
}
}
pub fn value_bytes<'a>(&'a self) -> Option<&'a [u8]> {
match self.data {
NodeData::Some { ref value_data, .. } => Some(value_data),
NodeData::None => None,
}
}
pub fn with_data(
encoding: EncodingType,
node_type: (StandardType, bool),
data: NodeData,
) -> Self {
let (node_type, is_array) = node_type;
pub fn as_node(&self) -> Result<Node, KbinError> {
trace!("parsing definition: {:?}", self);
match (self.node_type, &self.data) {
(StandardType::NodeEnd, _) |
(StandardType::FileEnd, _) => {
Err(KbinError::InvalidNodeType { node_type: self.node_type })
},
(StandardType::NodeStart, NodeData::Some { key, .. }) => {
let key = key.to_string()?;
Ok(Node::new(key))
},
(_, NodeData::Some { key, .. }) => {
let key = key.to_string()?;
let value = self.value()?;
Ok(Node::with_value(key, value))
},
(node_type, NodeData::None) => {
Err(KbinError::InvalidNodeType { node_type })
},
Self {
encoding,
node_type,
is_array,
data,
}
}
#[inline]
pub fn encoding(&self) -> EncodingType {
self.encoding
}
#[inline]
pub fn node_type_tuple(&self) -> (StandardType, bool) {
(self.node_type, self.is_array)
}
#[inline]
pub fn data<'a>(&'a self) -> &'a NodeData {
&self.data
}
#[inline]
pub fn data_mut<'a>(&'a mut self) -> &'a mut NodeData {
&mut self.data
}
pub fn key(&self) -> Result<Option<String>, KbinError> {
match self.data {
NodeData::Some { ref key, .. } => key.to_string().map(Some),
NodeData::None => Ok(None),
}
}
pub fn value(&self) -> Result<Value, KbinError> {
match (self.node_type, &self.data) {
(StandardType::Attribute, NodeData::Some { ref value_data, .. }) => {
let data = strip_trailing_null_bytes(value_data);
let value = self.encoding.decode_bytes(data)?;
Ok(Value::Attribute(value))
},
(StandardType::String, NodeData::Some { ref value_data, .. }) => {
let data = strip_trailing_null_bytes(value_data);
let value = self.encoding.decode_bytes(data)?;
Ok(Value::String(value))
},
(node_type, NodeData::Some { ref value_data, .. }) => {
let value = Value::from_standard_type(node_type, self.is_array, value_data)?;
match value {
Some(value) => Ok(value),
None => Err(KbinError::InvalidNodeType { node_type }),
}
},
(node_type, NodeData::None) => Err(KbinError::InvalidNodeType { node_type }),
}
}
pub fn value_bytes<'a>(&'a self) -> Option<&'a [u8]> {
match self.data {
NodeData::Some { ref value_data, .. } => Some(value_data),
NodeData::None => None,
}
}
pub fn as_node(&self) -> Result<Node, KbinError> {
trace!("parsing definition: {:?}", self);
match (self.node_type, &self.data) {
(StandardType::NodeEnd, _) | (StandardType::FileEnd, _) => {
Err(KbinError::InvalidNodeType {
node_type: self.node_type,
})
},
(StandardType::NodeStart, NodeData::Some { key, .. }) => {
let key = key.to_string()?;
Ok(Node::new(key))
},
(_, NodeData::Some { key, .. }) => {
let key = key.to_string()?;
let value = self.value()?;
Ok(Node::with_value(key, value))
},
(node_type, NodeData::None) => Err(KbinError::InvalidNodeType { node_type }),
}
}
}
}
impl PartialEq for Key {
fn eq(&self, other: &Key) -> bool {
match (self.to_string(), other.to_string()) {
(Ok(key1), Ok(key2)) => {
key1 == key2
},
(_, _) => {
// If the conversion fails, check if they have the same enum variant
// to check if the inner data is equal.
match (self, other) {
(
Key::Compressed { data: data1, .. },
Key::Compressed { data: data2, .. },
) => {
data1 == data2
},
(
Key::Uncompressed { data: data1, .. },
Key::Uncompressed { data: data2, .. },
) => {
data1 == data2
},
(_, _) => false,
fn eq(&self, other: &Key) -> bool {
match (self.to_string(), other.to_string()) {
(Ok(key1), Ok(key2)) => key1 == key2,
(_, _) => {
// If the conversion fails, check if they have the same enum variant
// to check if the inner data is equal.
match (self, other) {
(Key::Compressed { data: data1, .. }, Key::Compressed { data: data2, .. }) => {
data1 == data2
},
(
Key::Uncompressed { data: data1, .. },
Key::Uncompressed { data: data2, .. },
) => data1 == data2,
(_, _) => false,
}
},
}
},
}
}
}
impl fmt::Debug for Key {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Ok(key) = self.to_string() {
let variant = match self {
Key::Compressed { .. } => "Compressed",
Key::Uncompressed { .. } => "Uncompressed",
};
write!(f, "{} {{ \"{}\" }}", variant, key)
} else {
match self {
Key::Compressed { ref size, ref data } => {
f.debug_struct("Compressed")
.field("size", &size)
.field("data", &data)
.finish()
},
Key::Uncompressed { encoding, ref data } => {
f.debug_struct("Uncompressed")
.field("encoding", &encoding)
.field("data", &data)
.finish()
},
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Ok(key) = self.to_string() {
let variant = match self {
Key::Compressed { .. } => "Compressed",
Key::Uncompressed { .. } => "Uncompressed",
};
write!(f, "{} {{ \"{}\" }}", variant, key)
} else {
match self {
Key::Compressed { ref size, ref data } => f
.debug_struct("Compressed")
.field("size", &size)
.field("data", &data)
.finish(),
Key::Uncompressed { encoding, ref data } => f
.debug_struct("Uncompressed")
.field("encoding", &encoding)
.field("data", &data)
.finish(),
}
}
}
}
}
impl fmt::Display for NodeDefinition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut d = f.debug_struct("NodeDefinition");
d.field("node_type", &self.node_type);
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut d = f.debug_struct("NodeDefinition");
d.field("node_type", &self.node_type);
match self.node_type {
StandardType::Attribute |
StandardType::String => {
d.field("encoding", &self.encoding);
},
_ => {},
};
match self.data {
NodeData::Some { ref key, ref value_data } => {
match key.to_string() {
Ok(key) => d.field("key", &key),
Err(e) => d.field("key", &e),
match self.node_type {
StandardType::Attribute | StandardType::String => {
d.field("encoding", &self.encoding);
},
_ => {},
};
d.field("value_data", &value_data);
},
NodeData::None => {},
};
d.finish()
}
match self.data {
NodeData::Some {
ref key,
ref value_data,
} => {
match key.to_string() {
Ok(key) => d.field("key", &key),
Err(e) => d.field("key", &e),
};
d.field("value_data", &value_data);
},
NodeData::None => {},
};
d.finish()
}
}

View File

@@ -14,343 +14,352 @@ pub use self::definition::{Key, NodeData, NodeDefinition};
// The attributes argument is very hard to generalize
fn convert_attributes(attrs: &[(&str, &str)]) -> IndexMap<String, String> {
attrs.iter()
.map(|(key, value)| (String::from(*key), String::from(*value)))
.collect()
attrs
.iter()
.map(|(key, value)| (String::from(*key), String::from(*value)))
.collect()
}
fn parse_index(s: &str) -> Option<usize> {
if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
return None;
}
s.parse().ok()
if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
return None;
}
s.parse().ok()
}
pub struct OptionIterator<T: IntoIterator> {
inner: Option<T::IntoIter>,
inner: Option<T::IntoIter>,
}
#[derive(Clone, Default, PartialEq)]
pub struct Node {
key: String,
attributes: Option<IndexMap<String, String>>,
children: Option<Vec<Node>>,
value: Option<Value>,
key: String,
attributes: Option<IndexMap<String, String>>,
children: Option<Vec<Node>>,
value: Option<Value>,
}
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut d = f.debug_struct("Node");
d.field("key", &self.key);
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut d = f.debug_struct("Node");
d.field("key", &self.key);
if let Some(ref attributes) = self.attributes {
d.field("attributes", attributes);
}
if let Some(ref children) = self.children {
d.field("children", children);
}
if let Some(ref value) = self.value {
d.field("value", value);
}
if let Some(ref attributes) = self.attributes {
d.field("attributes", attributes);
}
if let Some(ref children) = self.children {
d.field("children", children);
}
if let Some(ref value) = self.value {
d.field("value", value);
}
d.finish()
}
d.finish()
}
}
impl Node {
pub fn new<K>(key: K) -> Self
where K: Into<String>
{
Self {
key: key.into(),
attributes: None,
children: None,
value: None,
}
}
pub fn with_attrs<K>(key: K, attrs: &[(&str, &str)]) -> Self
where K: Into<String>
{
Self {
key: key.into(),
attributes: Some(convert_attributes(attrs)),
children: None,
value: None,
}
}
pub fn with_value<K>(key: K, value: Value) -> Self
where K: Into<String>
{
Self {
key: key.into(),
attributes: None,
children: None,
value: Some(value),
}
}
pub fn with_nodes<K, N>(key: K, nodes: N) -> Self
where K: Into<String>,
N: Into<Vec<Node>>
{
Self {
key: key.into(),
attributes: None,
children: Some(nodes.into()),
value: None,
}
}
pub fn with<K, N>(key: K, attrs: &[(&str, &str)], nodes: N) -> Self
where K: Into<String>,
N: Into<Vec<Node>>
{
Self {
key: key.into(),
attributes: Some(convert_attributes(attrs)),
children: Some(nodes.into()),
value: None,
}
}
pub fn with_attrs_value<K>(key: K, attrs: &[(&str, &str)], value: Value) -> Self
where K: Into<String>
{
Self {
key: key.into(),
attributes: Some(convert_attributes(attrs)),
children: None,
value: Some(value),
}
}
#[inline]
pub fn key(&self) -> &str {
&self.key
}
#[inline]
pub fn attributes(&self) -> Option<&IndexMap<String, String>> {
self.attributes.as_ref()
}
#[inline]
pub fn attributes_mut(&mut self) -> Option<&mut IndexMap<String, String>> {
self.attributes.as_mut()
}
#[inline]
pub fn children(&self) -> Option<&Vec<Node>> {
self.children.as_ref()
}
#[inline]
pub fn children_mut(&mut self) -> Option<&mut Vec<Node>> {
self.children.as_mut()
}
#[inline]
pub fn value(&self) -> Option<&Value> {
self.value.as_ref()
}
#[inline]
pub fn value_mut(&mut self) -> Option<&mut Value> {
self.value.as_mut()
}
#[inline]
pub fn children_iter(&self) -> OptionIterator<&Vec<Node>> {
OptionIterator::new(self.children())
}
#[inline]
pub fn children_iter_mut(&mut self) -> OptionIterator<&mut Vec<Node>> {
OptionIterator::new(self.children_mut())
}
pub fn attr(&self, key: &str) -> Option<&str> {
self.attributes().and_then(|attributes| {
attributes.get(key).map(String::as_str)
})
}
pub fn attr_mut(&mut self, key: &str) -> Option<&mut String> {
self.attributes_mut().and_then(|attributes| {
attributes.get_mut(key)
})
}
pub fn into_key_and_value(self) -> (String, Option<Value>) {
(self.key, self.value)
}
pub fn set_key(&mut self, key: String) {
self.key = key;
}
pub fn set_attr<K, V>(&mut self, key: K, value: V) -> Option<String>
where K: Into<String>,
V: Into<String>
{
let attributes = self.attributes.get_or_insert_with(Default::default);
attributes.insert(key.into(), value.into())
}
pub fn remove_attr(&mut self, key: &str) -> Option<String> {
self.attributes.as_mut().and_then(|attributes| attributes.swap_remove(key))
}
pub fn sort_attrs(&mut self) {
if let Some(ref mut attributes) = self.attributes {
attributes.sort_keys();
}
}
pub fn append_child(&mut self, value: Node) {
let children = self.children.get_or_insert_with(Default::default);
children.push(value);
}
pub fn set_value(&mut self, value: Option<Value>) -> Option<Value> {
mem::replace(&mut self.value, value)
}
pub fn has(&self, key: &str) -> bool {
if let Some(ref children) = self.children {
for node in children {
if node.key == key {
return true;
pub fn new<K>(key: K) -> Self
where
K: Into<String>,
{
Self {
key: key.into(),
attributes: None,
children: None,
value: None,
}
}
}
false
}
pub fn get_child(&self, key: &str) -> Option<&Node> {
if let Some(ref children) = self.children {
for node in children {
if node.key == key {
return Some(node);
pub fn with_attrs<K>(key: K, attrs: &[(&str, &str)]) -> Self
where
K: Into<String>,
{
Self {
key: key.into(),
attributes: Some(convert_attributes(attrs)),
children: None,
value: None,
}
}
}
None
}
pub fn get_child_mut(&mut self, key: &str) -> Option<&mut Node> {
if let Some(ref mut children) = self.children {
for node in children {
if node.key == key {
return Some(node);
pub fn with_value<K>(key: K, value: Value) -> Self
where
K: Into<String>,
{
Self {
key: key.into(),
attributes: None,
children: None,
value: Some(value),
}
}
}
None
}
pub fn remove_child(&mut self, key: &str) -> Option<Node> {
if let Some(ref mut children) = self.children {
let index = children.iter()
.enumerate()
.find(|(_, child)| child.key() == key)
.map(|(index, _)| index);
if let Some(index) = index {
return Some(children.remove(index));
}
pub fn with_nodes<K, N>(key: K, nodes: N) -> Self
where
K: Into<String>,
N: Into<Vec<Node>>,
{
Self {
key: key.into(),
attributes: None,
children: Some(nodes.into()),
value: None,
}
}
None
}
pub fn remove_child_at(&mut self, index: usize) -> Option<Node> {
self.children.as_mut().map(|children| children.remove(index))
}
pub fn pointer<'a>(&'a self, pointer: &[&str]) -> Option<&'a Node> {
if pointer.is_empty() {
return Some(self);
pub fn with<K, N>(key: K, attrs: &[(&str, &str)], nodes: N) -> Self
where
K: Into<String>,
N: Into<Vec<Node>>,
{
Self {
key: key.into(),
attributes: Some(convert_attributes(attrs)),
children: Some(nodes.into()),
value: None,
}
}
let mut target = self;
for token in pointer {
let children = match target.children {
Some(ref v) => v,
None => return None,
};
let target_opt = if let Some(index) = parse_index(token) {
children.get(index)
} else {
children.iter().find(|ref child| {
child.key() == *token
})
};
if let Some(t) = target_opt {
target = t;
} else {
return None;
}
pub fn with_attrs_value<K>(key: K, attrs: &[(&str, &str)], value: Value) -> Self
where
K: Into<String>,
{
Self {
key: key.into(),
attributes: Some(convert_attributes(attrs)),
children: None,
value: Some(value),
}
}
Some(target)
}
pub fn pointer_mut<'a>(&'a mut self, pointer: &[&str]) -> Option<&'a mut Node> {
if pointer.is_empty() {
return Some(self);
#[inline]
pub fn key(&self) -> &str {
&self.key
}
let mut target = self;
for token in pointer {
let children = match target.children {
Some(ref mut v) => v,
None => return None,
};
let target_opt = if let Some(index) = parse_index(token) {
children.get_mut(index)
} else {
children.iter_mut().find(|ref child| {
child.key() == *token
})
};
if let Some(t) = target_opt {
target = t;
} else {
return None;
}
#[inline]
pub fn attributes(&self) -> Option<&IndexMap<String, String>> {
self.attributes.as_ref()
}
#[inline]
pub fn attributes_mut(&mut self) -> Option<&mut IndexMap<String, String>> {
self.attributes.as_mut()
}
#[inline]
pub fn children(&self) -> Option<&Vec<Node>> {
self.children.as_ref()
}
#[inline]
pub fn children_mut(&mut self) -> Option<&mut Vec<Node>> {
self.children.as_mut()
}
#[inline]
pub fn value(&self) -> Option<&Value> {
self.value.as_ref()
}
#[inline]
pub fn value_mut(&mut self) -> Option<&mut Value> {
self.value.as_mut()
}
#[inline]
pub fn children_iter(&self) -> OptionIterator<&Vec<Node>> {
OptionIterator::new(self.children())
}
#[inline]
pub fn children_iter_mut(&mut self) -> OptionIterator<&mut Vec<Node>> {
OptionIterator::new(self.children_mut())
}
pub fn attr(&self, key: &str) -> Option<&str> {
self.attributes()
.and_then(|attributes| attributes.get(key).map(String::as_str))
}
pub fn attr_mut(&mut self, key: &str) -> Option<&mut String> {
self.attributes_mut()
.and_then(|attributes| attributes.get_mut(key))
}
pub fn into_key_and_value(self) -> (String, Option<Value>) {
(self.key, self.value)
}
pub fn set_key(&mut self, key: String) {
self.key = key;
}
pub fn set_attr<K, V>(&mut self, key: K, value: V) -> Option<String>
where
K: Into<String>,
V: Into<String>,
{
let attributes = self.attributes.get_or_insert_with(Default::default);
attributes.insert(key.into(), value.into())
}
pub fn remove_attr(&mut self, key: &str) -> Option<String> {
self.attributes
.as_mut()
.and_then(|attributes| attributes.swap_remove(key))
}
pub fn sort_attrs(&mut self) {
if let Some(ref mut attributes) = self.attributes {
attributes.sort_keys();
}
}
pub fn append_child(&mut self, value: Node) {
let children = self.children.get_or_insert_with(Default::default);
children.push(value);
}
pub fn set_value(&mut self, value: Option<Value>) -> Option<Value> {
mem::replace(&mut self.value, value)
}
pub fn has(&self, key: &str) -> bool {
if let Some(ref children) = self.children {
for node in children {
if node.key == key {
return true;
}
}
}
false
}
pub fn get_child(&self, key: &str) -> Option<&Node> {
if let Some(ref children) = self.children {
for node in children {
if node.key == key {
return Some(node);
}
}
}
None
}
pub fn get_child_mut(&mut self, key: &str) -> Option<&mut Node> {
if let Some(ref mut children) = self.children {
for node in children {
if node.key == key {
return Some(node);
}
}
}
None
}
pub fn remove_child(&mut self, key: &str) -> Option<Node> {
if let Some(ref mut children) = self.children {
let index = children
.iter()
.enumerate()
.find(|(_, child)| child.key() == key)
.map(|(index, _)| index);
if let Some(index) = index {
return Some(children.remove(index));
}
}
None
}
pub fn remove_child_at(&mut self, index: usize) -> Option<Node> {
self.children
.as_mut()
.map(|children| children.remove(index))
}
pub fn pointer<'a>(&'a self, pointer: &[&str]) -> Option<&'a Node> {
if pointer.is_empty() {
return Some(self);
}
let mut target = self;
for token in pointer {
let children = match target.children {
Some(ref v) => v,
None => return None,
};
let target_opt = if let Some(index) = parse_index(token) {
children.get(index)
} else {
children.iter().find(|ref child| child.key() == *token)
};
if let Some(t) = target_opt {
target = t;
} else {
return None;
}
}
Some(target)
}
pub fn pointer_mut<'a>(&'a mut self, pointer: &[&str]) -> Option<&'a mut Node> {
if pointer.is_empty() {
return Some(self);
}
let mut target = self;
for token in pointer {
let children = match target.children {
Some(ref mut v) => v,
None => return None,
};
let target_opt = if let Some(index) = parse_index(token) {
children.get_mut(index)
} else {
children.iter_mut().find(|ref child| child.key() == *token)
};
if let Some(t) = target_opt {
target = t;
} else {
return None;
}
}
Some(target)
}
Some(target)
}
}
impl<T> OptionIterator<T>
where T: IntoIterator
where
T: IntoIterator,
{
pub fn new(inner: Option<T>) -> Self {
OptionIterator {
inner: inner.map(|inner| inner.into_iter()),
pub fn new(inner: Option<T>) -> Self {
OptionIterator {
inner: inner.map(|inner| inner.into_iter()),
}
}
}
}
impl<T> Iterator for OptionIterator<T>
where T: IntoIterator
where
T: IntoIterator,
{
type Item = T::Item;
type Item = T::Item;
fn next(&mut self) -> Option<Self::Item> {
match self.inner {
Some(ref mut inner) => inner.next(),
None => None,
fn next(&mut self) -> Option<Self::Item> {
match self.inner {
Some(ref mut inner) => inner.next(),
None => None,
}
}
}
}

View File

@@ -3,18 +3,18 @@ use std::ops::Deref;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct KbinType {
pub id: u8,
pub konst: &'static str,
pub name: &'static str,
pub alt_name: Option<&'static str>,
pub size: usize,
pub count: usize
pub id: u8,
pub konst: &'static str,
pub name: &'static str,
pub alt_name: Option<&'static str>,
pub size: usize,
pub count: usize,
}
impl fmt::Display for KbinType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ({})", self.konst, self.name)
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ({})", self.konst, self.name)
}
}
macro_rules! construct_types {

View File

@@ -3,54 +3,51 @@ use crate::encoding_type::EncodingType;
#[derive(Clone, Debug, Default)]
pub struct Options {
pub(crate) compression: Compression,
pub(crate) encoding: EncodingType,
pub(crate) compression: Compression,
pub(crate) encoding: EncodingType,
}
#[derive(Default)]
pub struct OptionsBuilder {
compression: Compression,
encoding: EncodingType,
compression: Compression,
encoding: EncodingType,
}
impl Options {
pub fn new(
compression: Compression,
encoding: EncodingType,
) -> Self {
Self {
compression,
encoding,
pub fn new(compression: Compression, encoding: EncodingType) -> Self {
Self {
compression,
encoding,
}
}
}
pub fn builder() -> OptionsBuilder {
OptionsBuilder::default()
}
pub fn with_encoding(encoding: EncodingType) -> Self {
Self {
encoding,
..Default::default()
pub fn builder() -> OptionsBuilder {
OptionsBuilder::default()
}
pub fn with_encoding(encoding: EncodingType) -> Self {
Self {
encoding,
..Default::default()
}
}
}
}
impl OptionsBuilder {
pub fn compression(&mut self, compression: Compression) -> &mut Self {
self.compression = compression;
self
}
pub fn encoding(&mut self, encoding: EncodingType) -> &mut Self {
self.encoding = encoding;
self
}
pub fn build(self) -> Options {
Options {
compression: self.compression,
encoding: self.encoding,
pub fn compression(&mut self, compression: Compression) -> &mut Self {
self.compression = compression;
self
}
pub fn encoding(&mut self, encoding: EncodingType) -> &mut Self {
self.encoding = encoding;
self
}
pub fn build(self) -> Options {
Options {
compression: self.compression,
encoding: self.encoding,
}
}
}
}

View File

@@ -8,51 +8,57 @@ use crate::reader::Reader;
pub struct Printer;
impl Printer {
pub fn run(input: &[u8]) -> Result<()> {
let mut reader = Reader::new(Bytes::from(input))?;
let mut nodes = Vec::new();
let mut definitions = Vec::new();
pub fn run(input: &[u8]) -> Result<()> {
let mut reader = Reader::new(Bytes::from(input))?;
let mut nodes = Vec::new();
let mut definitions = Vec::new();
while let Ok(def) = reader.read_node_definition() {
trace!("definition: {:?}", def);
while let Ok(def) = reader.read_node_definition() {
trace!("definition: {:?}", def);
let node_type = def.node_type;
let key = match def.key() {
Ok(v) => v,
Err(e) => {
error!("error processing key for definition {:?}: {}", def, e);
None
},
};
nodes.push((node_type, def.is_array, key));
definitions.push(def);
let node_type = def.node_type;
let key = match def.key() {
Ok(v) => v,
Err(e) => {
error!("error processing key for definition {:?}: {}", def, e);
None
},
};
nodes.push((node_type, def.is_array, key));
definitions.push(def);
if node_type == StandardType::FileEnd {
break;
}
if node_type == StandardType::FileEnd {
break;
}
}
let mut indent = 0;
for (node_type, is_array, identifier) in nodes {
eprint!(
"{:indent$} - {:?} (is_array: {}",
"",
node_type,
is_array,
indent = indent
);
if let Some(identifier) = identifier {
eprint!(", identifier: {}", identifier);
}
eprintln!(")");
match node_type {
StandardType::Attribute => {},
StandardType::NodeEnd => indent -= 2,
_ => indent += 2,
};
}
let collection = NodeCollection::from_iter(&mut definitions.into_iter());
match collection {
Some(ref collection) => eprintln!("collection: {:#}", collection),
None => eprintln!("collection: {:?}", collection),
};
Ok(())
}
let mut indent = 0;
for (node_type, is_array, identifier) in nodes {
eprint!("{:indent$} - {:?} (is_array: {}", "", node_type, is_array, indent = indent);
if let Some(identifier) = identifier {
eprint!(", identifier: {}", identifier);
}
eprintln!(")");
match node_type {
StandardType::Attribute => {},
StandardType::NodeEnd => indent -= 2,
_ => indent += 2,
};
}
let collection = NodeCollection::from_iter(&mut definitions.into_iter());
match collection {
Some(ref collection) => eprintln!("collection: {:#}", collection),
None => eprintln!("collection: {:?}", collection),
};
Ok(())
}
}

View File

@@ -1,7 +1,7 @@
use std::io;
use bytes::Bytes;
use byteorder::{BigEndian, ReadBytesExt};
use bytes::Bytes;
use snafu::{ResultExt, Snafu};
use crate::byte_buffer::{ByteBufferError, ByteBufferRead};
@@ -16,230 +16,224 @@ use super::{ARRAY_MASK, SIGNATURE};
#[derive(Debug, Snafu)]
pub enum ReaderError {
#[snafu(display("Failed to read signature from header"))]
Signature {
source: io::Error,
},
#[snafu(display("Failed to read signature from header"))]
Signature { source: io::Error },
#[snafu(display("Failed to read compression type from header"))]
Compression {
source: io::Error,
},
#[snafu(display("Failed to read compression type from header"))]
Compression { source: io::Error },
#[snafu(display("Failed to read encoding type from header"))]
Encoding {
source: io::Error,
},
#[snafu(display("Failed to read encoding type from header"))]
Encoding { source: io::Error },
#[snafu(display("Failed to read encoding type inverted value from header"))]
EncodingNegate {
source: io::Error,
},
#[snafu(display("Failed to read encoding type inverted value from header"))]
EncodingNegate { source: io::Error },
#[snafu(display("Failed to read node buffer length"))]
NodeBufferLength {
source: io::Error,
},
#[snafu(display("Failed to read node buffer length"))]
NodeBufferLength { source: io::Error },
#[snafu(display("Failed to read data buffer length"))]
DataBufferLength {
source: io::Error,
},
#[snafu(display("Failed to read data buffer length"))]
DataBufferLength { source: io::Error },
#[snafu(display("Reached the end of the node buffer"))]
EndOfNodeBuffer,
#[snafu(display("Reached the end of the node buffer"))]
EndOfNodeBuffer,
#[snafu(display("Failed to read node type"))]
NodeType {
source: io::Error,
},
#[snafu(display("Failed to read node type"))]
NodeType { source: io::Error },
#[snafu(display("Failed to read array node length"))]
ArrayLength {
source: io::Error,
},
#[snafu(display("Failed to read array node length"))]
ArrayLength { source: io::Error },
#[snafu(display("Failed to read node name length"))]
NameLength {
source: io::Error,
},
#[snafu(display("Failed to read node name length"))]
NameLength { source: io::Error },
#[snafu(display("Failed to read {} bytes from data buffer", size))]
DataRead {
size: usize,
source: io::Error,
},
#[snafu(display("Failed to read {} bytes from data buffer", size))]
DataRead { size: usize, source: io::Error },
}
pub struct Reader {
compression: CompressionType,
encoding: EncodingType,
compression: CompressionType,
encoding: EncodingType,
pub(crate) node_buf: ByteBufferRead,
pub(crate) data_buf: ByteBufferRead,
pub(crate) node_buf: ByteBufferRead,
pub(crate) data_buf: ByteBufferRead,
data_buf_start: u64,
data_buf_start: u64,
}
impl Reader {
pub fn new(input: Bytes) -> Result<Self, KbinError> {
// Node buffer starts from the beginning.
// Data buffer starts later after reading `len_data`.
let mut node_buf = ByteBufferRead::new(input.clone());
pub fn new(input: Bytes) -> Result<Self, KbinError> {
// Node buffer starts from the beginning.
// Data buffer starts later after reading `len_data`.
let mut node_buf = ByteBufferRead::new(input.clone());
let signature = node_buf.read_u8().context(Signature)?;
if signature != SIGNATURE {
return Err(KbinError::HeaderValue { field: "signature" });
let signature = node_buf.read_u8().context(Signature)?;
if signature != SIGNATURE {
return Err(KbinError::HeaderValue { field: "signature" });
}
let compress_byte = node_buf.read_u8().context(Compression)?;
let compression = CompressionType::from_byte(compress_byte)?;
let encoding_byte = node_buf.read_u8().context(Encoding)?;
let encoding_negation = node_buf.read_u8().context(EncodingNegate)?;
let encoding = EncodingType::from_byte(encoding_byte)?;
if encoding_negation != !encoding_byte {
return Err(KbinError::HeaderValue {
field: "encoding negation",
});
}
info!(
"signature: 0x{:X}, compression: 0x{:X} ({:?}), encoding: 0x{:X} ({:?})",
signature, compress_byte, compression, encoding_byte, encoding
);
let len_node = node_buf.read_u32::<BigEndian>().context(NodeBufferLength)?;
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.slice_from(data_buf_start as usize));
let len_data = data_buf.read_u32::<BigEndian>().context(DataBufferLength)?;
info!("len_data: {0} (0x{0:x})", len_data);
Ok(Self {
compression,
encoding,
node_buf,
data_buf,
data_buf_start: data_buf_start as u64,
})
}
let compress_byte = node_buf.read_u8().context(Compression)?;
let compression = CompressionType::from_byte(compress_byte)?;
fn parse_node_type(raw_node_type: u8) -> Result<(StandardType, bool), KbinError> {
let is_array = raw_node_type & ARRAY_MASK == ARRAY_MASK;
let node_type = raw_node_type & !ARRAY_MASK;
let encoding_byte = node_buf.read_u8().context(Encoding)?;
let encoding_negation = node_buf.read_u8().context(EncodingNegate)?;
let encoding = EncodingType::from_byte(encoding_byte)?;
if encoding_negation != !encoding_byte {
return Err(KbinError::HeaderValue { field: "encoding negation" });
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))
}
info!("signature: 0x{:X}, compression: 0x{:X} ({:?}), encoding: 0x{:X} ({:?})", signature, compress_byte, compression, encoding_byte, encoding);
let len_node = node_buf.read_u32::<BigEndian>().context(NodeBufferLength)?;
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.slice_from(data_buf_start as usize));
let len_data = data_buf.read_u32::<BigEndian>().context(DataBufferLength)?;
info!("len_data: {0} (0x{0:x})", len_data);
Ok(Self {
compression,
encoding,
node_buf,
data_buf,
data_buf_start: data_buf_start as u64,
})
}
fn parse_node_type(raw_node_type: u8) -> Result<(StandardType, bool), KbinError> {
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
}
pub fn check_if_node_buffer_end(&self) -> Result<(), ReaderError> {
if self.node_buf.position() >= self.data_buf_start {
Err(ReaderError::EndOfNodeBuffer)
} else {
Ok(())
#[inline]
pub fn encoding(&self) -> EncodingType {
self.encoding
}
}
pub fn read_node_type(&mut self) -> Result<(StandardType, bool), KbinError> {
self.check_if_node_buffer_end()?;
pub fn check_if_node_buffer_end(&self) -> Result<(), ReaderError> {
if self.node_buf.position() >= self.data_buf_start {
Err(ReaderError::EndOfNodeBuffer)
} else {
Ok(())
}
}
let raw_node_type = self.node_buf.read_u8().context(NodeType)?;
let value = Self::parse_node_type(raw_node_type)?;
pub fn read_node_type(&mut self) -> Result<(StandardType, bool), KbinError> {
self.check_if_node_buffer_end()?;
Ok(value)
}
let raw_node_type = self.node_buf.read_u8().context(NodeType)?;
let value = Self::parse_node_type(raw_node_type)?;
pub fn read_node_data(&mut self, node_type: (StandardType, bool)) -> Result<Bytes, KbinError> {
let (node_type, is_array) = node_type;
trace!("Reader::read_node_data(node_type: {:?}, is_array: {})", node_type, is_array);
Ok(value)
}
let value = match node_type {
StandardType::Attribute |
StandardType::String => self.data_buf.buf_read()?,
StandardType::Binary => self.read_bytes()?,
pub fn read_node_data(&mut self, node_type: (StandardType, bool)) -> Result<Bytes, KbinError> {
let (node_type, is_array) = node_type;
trace!(
"Reader::read_node_data(node_type: {:?}, is_array: {})",
node_type,
is_array
);
StandardType::NodeStart |
StandardType::NodeEnd |
StandardType::FileEnd => Bytes::new(),
let value = match node_type {
StandardType::Attribute | StandardType::String => self.data_buf.buf_read()?,
StandardType::Binary => self.read_bytes()?,
_ if is_array => {
let arr_size = self.data_buf.read_u32::<BigEndian>().context(ArrayLength)?;
let data = self.data_buf.get(arr_size)?;
self.data_buf.realign_reads(None)?;
StandardType::NodeStart | StandardType::NodeEnd | StandardType::FileEnd => Bytes::new(),
data
},
node_type => self.data_buf.get_aligned(*node_type)?,
};
debug!("Reader::read_node_data(node_type: {:?}, is_array: {}) => value: 0x{:02x?}", node_type, is_array, value);
_ if is_array => {
let arr_size = self.data_buf.read_u32::<BigEndian>().context(ArrayLength)?;
let data = self.data_buf.get(arr_size)?;
self.data_buf.realign_reads(None)?;
Ok(value)
}
pub fn read_node_definition(&mut self) -> Result<NodeDefinition, KbinError> {
let node_type = self.read_node_type()?;
match node_type.0 {
StandardType::NodeEnd |
StandardType::FileEnd => {
Ok(NodeDefinition::new(self.encoding, node_type))
}
_ => {
let key = match self.compression {
CompressionType::Compressed => {
let size = Sixbit::size(&mut *self.node_buf)?;
let data = self.node_buf.get(size.real_len as u32)?;
Key::Compressed { size, data }
},
CompressionType::Uncompressed => {
let encoding = self.encoding;
let length = (self.node_buf.read_u8().context(NameLength)? & !ARRAY_MASK) + 1;
let data = self.node_buf.get(length as u32)?;
Key::Uncompressed { encoding, data }
},
data
},
node_type => self.data_buf.get_aligned(*node_type)?,
};
let value_data = self.read_node_data(node_type)?;
let node_data = NodeData::Some { key, value_data };
Ok(NodeDefinition::with_data(self.encoding, node_type, node_data))
},
debug!(
"Reader::read_node_data(node_type: {:?}, is_array: {}) => value: 0x{:02x?}",
node_type, is_array, value
);
Ok(value)
}
}
pub fn read_u32(&mut self) -> Result<u32, ReaderError> {
let value = self.data_buf.read_u32::<BigEndian>().context(DataRead { size: 4usize })?;
debug!("Reader::read_u32() => result: {}", value);
pub fn read_node_definition(&mut self) -> Result<NodeDefinition, KbinError> {
let node_type = self.read_node_type()?;
match node_type.0 {
StandardType::NodeEnd | StandardType::FileEnd => {
Ok(NodeDefinition::new(self.encoding, node_type))
},
_ => {
let key = match self.compression {
CompressionType::Compressed => {
let size = Sixbit::size(&mut *self.node_buf)?;
let data = self.node_buf.get(size.real_len as u32)?;
Key::Compressed { size, data }
},
CompressionType::Uncompressed => {
let encoding = self.encoding;
let length =
(self.node_buf.read_u8().context(NameLength)? & !ARRAY_MASK) + 1;
let data = self.node_buf.get(length as u32)?;
Key::Uncompressed { encoding, data }
},
};
let value_data = self.read_node_data(node_type)?;
let node_data = NodeData::Some { key, value_data };
Ok(NodeDefinition::with_data(
self.encoding,
node_type,
node_data,
))
},
}
}
Ok(value)
}
pub fn read_u32(&mut self) -> Result<u32, ReaderError> {
let value = self
.data_buf
.read_u32::<BigEndian>()
.context(DataRead { size: 4usize })?;
debug!("Reader::read_u32() => result: {}", value);
#[inline]
pub fn read_bytes(&mut self) -> Result<Bytes, ByteBufferError> {
self.data_buf.buf_read()
}
Ok(value)
}
#[inline]
pub fn read_bytes(&mut self) -> Result<Bytes, ByteBufferError> {
self.data_buf.buf_read()
}
}
impl Iterator for Reader {
type Item = NodeDefinition;
type Item = NodeDefinition;
fn next(&mut self) -> Option<NodeDefinition> {
match self.read_node_definition() {
Ok(v) => Some(v),
Err(e) => {
error!("Error reading node definition in `next()`: {}", e);
None
},
fn next(&mut self) -> Option<NodeDefinition> {
match self.read_node_definition() {
Ok(v) => Some(v),
Err(e) => {
error!("Error reading node definition in `next()`: {}", e);
None
},
}
}
}
}

View File

@@ -4,165 +4,174 @@ use std::io::{self, Read, Write};
use byteorder::{ReadBytesExt, WriteBytesExt};
use snafu::{ResultExt, Snafu};
static CHAR_MAP: &'static [u8] = b"0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
static CHAR_MAP: &'static [u8] =
b"0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
lazy_static! {
static ref BYTE_MAP: HashMap<u8, u8> = {
CHAR_MAP
.iter()
.enumerate()
.map(|(i, value)| {
(*value, i as u8)
})
.collect()
};
static ref BYTE_MAP: HashMap<u8, u8> = {
CHAR_MAP
.iter()
.enumerate()
.map(|(i, value)| (*value, i as u8))
.collect()
};
}
#[derive(Debug, Snafu)]
pub enum SixbitError {
#[snafu(display("Failed to read sixbit string length"))]
LengthRead {
source: io::Error,
},
#[snafu(display("Failed to read sixbit string length"))]
LengthRead { source: io::Error },
#[snafu(display("Failed to write sixbit string length"))]
LengthWrite {
source: io::Error,
},
#[snafu(display("Failed to write sixbit string length"))]
LengthWrite { source: io::Error },
#[snafu(display("Failed to read sixbit string data (expected: {} bytes, got: {} bytes)", expected, actual))]
DataRead {
expected: usize,
actual: usize,
},
#[snafu(display(
"Failed to read sixbit string data (expected: {} bytes, got: {} bytes)",
expected,
actual
))]
DataRead { expected: usize, actual: usize },
#[snafu(display("Failed to write sixbit string data"))]
DataWrite {
source: io::Error,
},
#[snafu(display("Failed to write sixbit string data"))]
DataWrite { source: io::Error },
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SixbitSize {
pub sixbit_len: u8,
pub real_len: usize,
pub sixbit_len: u8,
pub real_len: usize,
}
pub struct Sixbit;
impl Sixbit {
pub fn size<T>(reader: &mut T) -> Result<SixbitSize, SixbitError>
where T: Read,
{
let sixbit_len = reader.read_u8().context(LengthRead)?;
let real_len = (f32::from(sixbit_len * 6) / 8f32).ceil();
let real_len = (real_len as u32) as usize;
debug!("sixbit_len: {}, real_len: {}", sixbit_len, real_len);
pub fn size<T>(reader: &mut T) -> Result<SixbitSize, SixbitError>
where
T: Read,
{
let sixbit_len = reader.read_u8().context(LengthRead)?;
let real_len = (f32::from(sixbit_len * 6) / 8f32).ceil();
let real_len = (real_len as u32) as usize;
debug!("sixbit_len: {}, real_len: {}", sixbit_len, real_len);
Ok(SixbitSize { sixbit_len, real_len })
}
pub fn pack<T>(writer: &mut T, input: &str) -> Result<(), SixbitError>
where T: Write,
{
let sixbit_chars = input
.bytes()
.map(|ch| {
*BYTE_MAP.get(&ch).expect("Character must be a valid sixbit character")
});
let len = input.len();
let real_len = (f64::from(len as u32 * 6) / 8f64).ceil() as usize;
debug!("sixbit_len: {}, real_len: {}", len, real_len);
let mut i = 0;
let mut bytes = vec![0; real_len];
for ch in sixbit_chars {
for _ in 0..6 {
// Some crazy math that works on a single bit at a time, but
// it still performs better than a `BigUint` calculation
bytes[i / 8] |= (ch >> (5 - (i % 6)) & 1) << (7 - (i % 8));
i += 1;
}
Ok(SixbitSize {
sixbit_len,
real_len,
})
}
writer.write_u8(len as u8).context(LengthWrite)?;
writer.write_all(&bytes).context(DataWrite)?;
pub fn pack<T>(writer: &mut T, input: &str) -> Result<(), SixbitError>
where
T: Write,
{
let sixbit_chars = input.bytes().map(|ch| {
*BYTE_MAP
.get(&ch)
.expect("Character must be a valid sixbit character")
});
Ok(())
}
let len = input.len();
let real_len = (f64::from(len as u32 * 6) / 8f64).ceil() as usize;
debug!("sixbit_len: {}, real_len: {}", len, real_len);
pub fn unpack(buf: &[u8], size: SixbitSize) -> Result<String, SixbitError> {
let SixbitSize { sixbit_len, real_len } = size;
let mut i = 0;
let mut bytes = vec![0; real_len];
for ch in sixbit_chars {
for _ in 0..6 {
// Some crazy math that works on a single bit at a time, but
// it still performs better than a `BigUint` calculation
bytes[i / 8] |= (ch >> (5 - (i % 6)) & 1) << (7 - (i % 8));
i += 1;
}
}
if buf.len() < real_len {
return Err(SixbitError::DataRead { expected: real_len, actual: buf.len() });
writer.write_u8(len as u8).context(LengthWrite)?;
writer.write_all(&bytes).context(DataWrite)?;
Ok(())
}
let sixbit_len = sixbit_len as usize;
let mut result = String::with_capacity(sixbit_len);
for i in 0..sixbit_len {
let mut current = 0u8;
for j in 0..6 {
let k = (i * 6) + j;
current |= (buf[k / 8] >> (7 - (k % 8)) & 1) << (5 - (k % 6));
}
result.push(CHAR_MAP[current as usize] as char);
}
pub fn unpack(buf: &[u8], size: SixbitSize) -> Result<String, SixbitError> {
let SixbitSize {
sixbit_len,
real_len,
} = size;
Ok(result)
}
if buf.len() < real_len {
return Err(SixbitError::DataRead {
expected: real_len,
actual: buf.len(),
});
}
let sixbit_len = sixbit_len as usize;
let mut result = String::with_capacity(sixbit_len);
for i in 0..sixbit_len {
let mut current = 0u8;
for j in 0..6 {
let k = (i * 6) + j;
current |= (buf[k / 8] >> (7 - (k % 8)) & 1) << (5 - (k % 6));
}
result.push(CHAR_MAP[current as usize] as char);
}
Ok(result)
}
}
#[cfg(test)]
mod tests {
extern crate test;
extern crate test;
use std::io::{Cursor, Seek, SeekFrom};
use std::io::{Cursor, Seek, SeekFrom};
use test::{Bencher, black_box};
use test::{black_box, Bencher};
use super::Sixbit;
use super::Sixbit;
const TEST1_STR: &str = "hello";
const TEST1_BYTES: &[u8] = &[5,182,172,113,208];
const TEST1_STR: &str = "hello";
const TEST1_BYTES: &[u8] = &[5, 182, 172, 113, 208];
#[test]
fn test_pack() {
let mut data: Cursor<Vec<u8>> = Cursor::new(Vec::new());
Sixbit::pack(&mut data, TEST1_STR).expect("Failed to pack sixbit");
assert_eq!(data.into_inner(), TEST1_BYTES);
}
#[test]
fn test_pack() {
let mut data: Cursor<Vec<u8>> = Cursor::new(Vec::new());
Sixbit::pack(&mut data, TEST1_STR).expect("Failed to pack sixbit");
assert_eq!(data.into_inner(), TEST1_BYTES);
}
#[test]
fn test_unpack() {
let size = Sixbit::size(&mut Cursor::new(TEST1_BYTES)).expect("Failed to get size of sixbit string");
let result = Sixbit::unpack(&TEST1_BYTES[1..], size).expect("Failed to unpack sixbit string");
assert_eq!(result, TEST1_STR);
}
#[test]
fn test_unpack() {
let size = Sixbit::size(&mut Cursor::new(TEST1_BYTES))
.expect("Failed to get size of sixbit string");
let result =
Sixbit::unpack(&TEST1_BYTES[1..], size).expect("Failed to unpack sixbit string");
assert_eq!(result, TEST1_STR);
}
#[bench]
fn bench_pack(b: &mut Bencher) {
let mut data: Cursor<Vec<u8>> = Cursor::new(Vec::with_capacity(10));
#[bench]
fn bench_pack(b: &mut Bencher) {
let mut data: Cursor<Vec<u8>> = Cursor::new(Vec::with_capacity(10));
b.iter(|| {
for _ in 0..100 {
data.seek(SeekFrom::Start(0)).unwrap();
black_box(Sixbit::pack(&mut data, TEST1_STR).unwrap());
}
});
b.iter(|| {
for _ in 0..100 {
data.seek(SeekFrom::Start(0)).unwrap();
black_box(Sixbit::pack(&mut data, TEST1_STR).unwrap());
}
});
assert_eq!(data.into_inner(), TEST1_BYTES);
}
assert_eq!(data.into_inner(), TEST1_BYTES);
}
#[bench]
fn bench_unpack(b: &mut Bencher) {
b.iter(|| {
for _ in 0..100 {
let size = Sixbit::size(&mut Cursor::new(TEST1_BYTES)).expect("Failed to get size of sixbit string");
let result = Sixbit::unpack(&TEST1_BYTES[1..], size).expect("Failed to unpack sixbit string");
black_box(result);
}
});
}
#[bench]
fn bench_unpack(b: &mut Bencher) {
b.iter(|| {
for _ in 0..100 {
let size = Sixbit::size(&mut Cursor::new(TEST1_BYTES))
.expect("Failed to get size of sixbit string");
let result = Sixbit::unpack(&TEST1_BYTES[1..], size)
.expect("Failed to unpack sixbit string");
black_box(result);
}
});
}
}

View File

@@ -1,237 +1,257 @@
use std::str;
use bytes::{BufMut, Bytes, BytesMut};
use quick_xml::Reader;
use quick_xml::events::{BytesStart, BytesText, Event};
use quick_xml::events::attributes::Attributes;
use quick_xml::events::{BytesStart, BytesText, Event};
use quick_xml::Reader;
use snafu::ResultExt;
use crate::encoding_type::EncodingType;
use crate::error::*;
use crate::node::{Key, NodeData, NodeCollection, NodeDefinition};
use crate::node::{Key, NodeCollection, NodeData, NodeDefinition};
use crate::node_types::StandardType;
use crate::value::Value;
const EMPTY_STRING_DATA: &[u8] = &[0];
pub struct TextXmlReader<'a> {
xml_reader: Reader<&'a [u8]>,
encoding: EncodingType,
xml_reader: Reader<&'a [u8]>,
encoding: EncodingType,
stack: Vec<(NodeCollection, usize, Option<usize>)>,
stack: Vec<(NodeCollection, usize, Option<usize>)>,
}
impl<'a> TextXmlReader<'a> {
pub fn new(input: &'a [u8]) -> Self {
let mut xml_reader = Reader::from_reader(input);
xml_reader.trim_text(true);
pub fn new(input: &'a [u8]) -> Self {
let mut xml_reader = Reader::from_reader(input);
xml_reader.trim_text(true);
Self {
xml_reader,
encoding: EncodingType::UTF_8,
Self {
xml_reader,
encoding: EncodingType::UTF_8,
// Most kbinxml files that I have come across do not have too
// many inner layers.
stack: Vec::with_capacity(6),
}
}
#[inline]
pub fn encoding(&self) -> EncodingType {
self.encoding
}
fn parse_attribute(&self, key: &[u8], value: &[u8]) -> Result<NodeDefinition> {
let mut value = BytesMut::from(value.to_vec());
// Add the trailing null byte that kbin has at the end of strings
value.reserve(1);
value.put_u8(0);
// `Attribute` nodes do not have the `is_array` flag set
let node_type = (StandardType::Attribute, false);
let data = NodeData::Some {
key: Key::Uncompressed {
encoding: self.encoding,
data: Bytes::from(key),
},
value_data: value.freeze(),
};
Ok(NodeDefinition::with_data(self.encoding, node_type, data))
}
fn parse_attributes(&self, attrs: Attributes<'a>) -> Result<(StandardType, usize, Option<usize>, Vec<NodeDefinition>)> {
let mut node_type = None;
let mut count = 0;
let mut size = None;
let mut attributes = Vec::new();
for attr in attrs {
match attr {
Ok(attr) => {
let value = match attr.unescaped_value() {
Ok(v) => v,
Err(e) => {
error!("Error decoding attribute value: {:?}", e);
attr.value.clone()
},
};
if attr.key == b"__type" {
let value = str::from_utf8(&*value)?;
node_type = Some(StandardType::from_name(value));
} else if attr.key == b"__count" {
let value = str::from_utf8(&*value)?;
let num_count = value.parse::<u32>().context(StringParseInt { node_type: "array count" })?;
count = num_count as usize;
} else if attr.key == b"__size" {
let value = str::from_utf8(&*value)?
.parse::<usize>()
.context(StringParseInt { node_type: "binary size" })?;
size = Some(value);
} else {
let definition = self.parse_attribute(attr.key, &value)?;
attributes.push(definition);
}
},
Err(e) => {
error!("Error reading attribute: {:?}", e);
},
}
// Most kbinxml files that I have come across do not have too
// many inner layers.
stack: Vec::with_capacity(6),
}
}
let node_type = match node_type {
Some(node_type) => node_type,
None => {
// Default to `NodeStart`, set to `String` if there is a `Event::Text` event before
// the `Event::End` event.
StandardType::NodeStart
},
};
#[inline]
pub fn encoding(&self) -> EncodingType {
self.encoding
}
Ok((node_type, count, size, attributes))
}
fn handle_start(&self, e: BytesStart) -> Result<(NodeCollection, usize, Option<usize>)> {
let (node_type, count, size, attributes) = self.parse_attributes(e.attributes())?;
// Stub the value for now, handle with `Event::Text`.
let value_data = match node_type {
StandardType::String => Bytes::from(EMPTY_STRING_DATA),
_ => Bytes::new(),
};
let node_type = (node_type, count > 0);
let data = NodeData::Some {
key: Key::Uncompressed {
encoding: self.encoding,
data: Bytes::from(e.name()),
},
value_data,
};
let base = NodeDefinition::with_data(self.encoding, node_type, data);
let collection = NodeCollection::with_attributes(base, attributes.into());
Ok((collection, count, size))
}
fn handle_text(event: BytesText, definition: &mut NodeDefinition, count: usize, size: Option<usize>) -> Result<()> {
let data = event.unescaped()?;
let data = match definition.node_type {
StandardType::String |
StandardType::NodeStart => {
let mut data = BytesMut::from(data.into_owned());
fn parse_attribute(&self, key: &[u8], value: &[u8]) -> Result<NodeDefinition> {
let mut value = BytesMut::from(value.to_vec());
// Add the trailing null byte that kbin has at the end of strings
data.reserve(1);
data.put_u8(0);
value.reserve(1);
value.put_u8(0);
data.freeze()
},
_ => {
let text = str::from_utf8(&*data)?;
let value = Value::from_string(definition.node_type, text, definition.is_array, count)?;
// `Attribute` nodes do not have the `is_array` flag set
let node_type = (StandardType::Attribute, false);
let data = NodeData::Some {
key: Key::Uncompressed {
encoding: self.encoding,
data: Bytes::from(key),
},
value_data: value.freeze(),
};
if let Value::Binary(data) = &value {
// The read number of bytes must match the size attribute, if set
if let Some(size) = size {
if data.len() != size {
return Err(KbinError::InvalidState.into());
Ok(NodeDefinition::with_data(self.encoding, node_type, data))
}
fn parse_attributes(
&self,
attrs: Attributes<'a>,
) -> Result<(StandardType, usize, Option<usize>, Vec<NodeDefinition>)> {
let mut node_type = None;
let mut count = 0;
let mut size = None;
let mut attributes = Vec::new();
for attr in attrs {
match attr {
Ok(attr) => {
let value = match attr.unescaped_value() {
Ok(v) => v,
Err(e) => {
error!("Error decoding attribute value: {:?}", e);
attr.value.clone()
},
};
if attr.key == b"__type" {
let value = str::from_utf8(&*value)?;
node_type = Some(StandardType::from_name(value));
} else if attr.key == b"__count" {
let value = str::from_utf8(&*value)?;
let num_count = value.parse::<u32>().context(StringParseInt {
node_type: "array count",
})?;
count = num_count as usize;
} else if attr.key == b"__size" {
let value =
str::from_utf8(&*value)?
.parse::<usize>()
.context(StringParseInt {
node_type: "binary size",
})?;
size = Some(value);
} else {
let definition = self.parse_attribute(attr.key, &value)?;
attributes.push(definition);
}
},
Err(e) => {
error!("Error reading attribute: {:?}", e);
},
}
}
}
Bytes::from(value.to_bytes()?)
},
};
let node_type = match node_type {
Some(node_type) => node_type,
None => {
// Default to `NodeStart`, set to `String` if there is a `Event::Text` event before
// the `Event::End` event.
StandardType::NodeStart
},
};
if definition.node_type == StandardType::NodeStart {
definition.node_type = StandardType::String;
Ok((node_type, count, size, attributes))
}
if let NodeData::Some { ref mut value_data, .. } = definition.data_mut() {
*value_data = data;
} else {
// There should be a valid `NodeData` structure from the `Event::Start` handler
return Err(KbinError::InvalidState.into());
fn handle_start(&self, e: BytesStart) -> Result<(NodeCollection, usize, Option<usize>)> {
let (node_type, count, size, attributes) = self.parse_attributes(e.attributes())?;
// Stub the value for now, handle with `Event::Text`.
let value_data = match node_type {
StandardType::String => Bytes::from(EMPTY_STRING_DATA),
_ => Bytes::new(),
};
let node_type = (node_type, count > 0);
let data = NodeData::Some {
key: Key::Uncompressed {
encoding: self.encoding,
data: Bytes::from(e.name()),
},
value_data,
};
let base = NodeDefinition::with_data(self.encoding, node_type, data);
let collection = NodeCollection::with_attributes(base, attributes.into());
Ok((collection, count, size))
}
Ok(())
}
fn handle_text(
event: BytesText,
definition: &mut NodeDefinition,
count: usize,
size: Option<usize>,
) -> Result<()> {
let data = event.unescaped()?;
let data = match definition.node_type {
StandardType::String | StandardType::NodeStart => {
let mut data = BytesMut::from(data.into_owned());
pub fn as_node_collection(&mut self) -> Result<Option<NodeCollection>> {
// A buffer size for reading a `quick_xml::events::Event` that I pulled
// out of my head.
let mut buf = Vec::with_capacity(1024);
// Add the trailing null byte that kbin has at the end of strings
data.reserve(1);
data.put_u8(0);
loop {
match self.xml_reader.read_event(&mut buf)? {
Event::Start(e) => {
let start = self.handle_start(e)?;
self.stack.push(start);
},
Event::Text(e) => {
if let Some((ref mut collection, ref count, ref size)) = self.stack.last_mut() {
let base = collection.base_mut();
Self::handle_text(e, base, *count, *size)?;
}
},
Event::End(_) => {
if let Some((collection, _count, _size)) = self.stack.pop() {
if let Some((parent_collection, _count, _size)) = self.stack.last_mut() {
parent_collection.children_mut().push_back(collection);
} else {
// The end of the structure has been reached.
return Ok(Some(collection));
}
}
},
Event::Empty(e) => {
let (collection, count, size) = self.handle_start(e)?;
assert!(count == 0, "empty node should not signal an array");
assert!(size.is_none() || size == Some(0), "empty node should not signal binary data");
data.freeze()
},
_ => {
let text = str::from_utf8(&*data)?;
let value =
Value::from_string(definition.node_type, text, definition.is_array, count)?;
if let Some((ref mut parent_collection, _count, _size)) = self.stack.last_mut() {
parent_collection.children_mut().push_back(collection);
}
},
Event::Decl(e) => {
if let Some(encoding) = e.encoding() {
self.encoding = EncodingType::from_label(&encoding?)?;
}
},
Event::Eof => break,
_ => {},
};
if let Value::Binary(data) = &value {
// The read number of bytes must match the size attribute, if set
if let Some(size) = size {
if data.len() != size {
return Err(KbinError::InvalidState.into());
}
}
}
buf.clear();
Bytes::from(value.to_bytes()?)
},
};
if definition.node_type == StandardType::NodeStart {
definition.node_type = StandardType::String;
}
if let NodeData::Some {
ref mut value_data, ..
} = definition.data_mut()
{
*value_data = data;
} else {
// There should be a valid `NodeData` structure from the `Event::Start` handler
return Err(KbinError::InvalidState.into());
}
Ok(())
}
Ok(None)
}
pub fn as_node_collection(&mut self) -> Result<Option<NodeCollection>> {
// A buffer size for reading a `quick_xml::events::Event` that I pulled
// out of my head.
let mut buf = Vec::with_capacity(1024);
loop {
match self.xml_reader.read_event(&mut buf)? {
Event::Start(e) => {
let start = self.handle_start(e)?;
self.stack.push(start);
},
Event::Text(e) => {
if let Some((ref mut collection, ref count, ref size)) = self.stack.last_mut() {
let base = collection.base_mut();
Self::handle_text(e, base, *count, *size)?;
}
},
Event::End(_) => {
if let Some((collection, _count, _size)) = self.stack.pop() {
if let Some((parent_collection, _count, _size)) = self.stack.last_mut() {
parent_collection.children_mut().push_back(collection);
} else {
// The end of the structure has been reached.
return Ok(Some(collection));
}
}
},
Event::Empty(e) => {
let (collection, count, size) = self.handle_start(e)?;
assert!(count == 0, "empty node should not signal an array");
assert!(
size.is_none() || size == Some(0),
"empty node should not signal binary data"
);
if let Some((ref mut parent_collection, _count, _size)) = self.stack.last_mut()
{
parent_collection.children_mut().push_back(collection);
}
},
Event::Decl(e) => {
if let Some(encoding) = e.encoding() {
self.encoding = EncodingType::from_label(&encoding?)?;
}
},
Event::Eof => break,
_ => {},
};
buf.clear();
}
Ok(None)
}
}

View File

@@ -1,7 +1,7 @@
use std::io::{Cursor, Write};
use quick_xml::Writer;
use quick_xml::events::{BytesDecl, Event};
use quick_xml::Writer;
use crate::encoding_type::EncodingType;
use crate::error::KbinError;
@@ -10,35 +10,34 @@ mod node;
mod node_collection;
pub trait ToTextXml {
fn encoding(&self) -> EncodingType;
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError>;
fn encoding(&self) -> EncodingType;
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError>;
}
pub struct TextXmlWriter {
xml_writer: Writer<Cursor<Vec<u8>>>,
xml_writer: Writer<Cursor<Vec<u8>>>,
}
impl TextXmlWriter {
pub fn new() -> Self {
let inner = Cursor::new(Vec::new());
let xml_writer = Writer::new_with_indent(inner, b' ', 2);
pub fn new() -> Self {
let inner = Cursor::new(Vec::new());
let xml_writer = Writer::new_with_indent(inner, b' ', 2);
Self {
xml_writer,
}
}
pub fn to_text_xml<T>(mut self, value: &T) -> Result<Vec<u8>, KbinError>
where T: ToTextXml
{
if let Some(encoding) = value.encoding().name() {
let header = BytesDecl::new(b"1.0", Some(encoding.as_bytes()), None);
self.xml_writer.write_event(Event::Decl(header))?;
Self { xml_writer }
}
value.write(&mut self.xml_writer)?;
pub fn to_text_xml<T>(mut self, value: &T) -> Result<Vec<u8>, KbinError>
where
T: ToTextXml,
{
if let Some(encoding) = value.encoding().name() {
let header = BytesDecl::new(b"1.0", Some(encoding.as_bytes()), None);
Ok(self.xml_writer.into_inner().into_inner())
}
self.xml_writer.write_event(Event::Decl(header))?;
}
value.write(&mut self.xml_writer)?;
Ok(self.xml_writer.into_inner().into_inner())
}
}

View File

@@ -1,9 +1,9 @@
use std::borrow::Cow;
use std::io::Write;
use quick_xml::Writer;
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::events::attributes::Attribute;
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::Writer;
use crate::encoding_type::EncodingType;
use crate::error::KbinError;
@@ -13,94 +13,94 @@ use crate::to_text_xml::ToTextXml;
use crate::value::Value;
impl ToTextXml for Node {
/// At the moment, a `Node` will always contain UTF-8 data.
fn encoding(&self) -> EncodingType {
EncodingType::UTF_8
}
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError> {
let key = self.key();
let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len());
// Write the attributes for the value, but not the value contents.
if let Some(value) = self.value() {
let node_type = value.standard_type();
match value {
Value::Binary(ref data) => {
elem.push_attribute(Attribute {
key: b"__size",
value: Cow::Owned(data.len().to_string().into_bytes()),
});
},
Value::Array(ref values) => {
elem.push_attribute(Attribute {
key: b"__count",
value: Cow::Owned(values.len().to_string().into_bytes()),
});
},
_ => {},
};
// Only add a `__type` attribute if this is not a `NodeStart` node
if node_type != StandardType::NodeStart {
elem.push_attribute(Attribute {
key: b"__type",
value: Cow::Borrowed(node_type.name.as_bytes()),
});
}
/// At the moment, a `Node` will always contain UTF-8 data.
fn encoding(&self) -> EncodingType {
EncodingType::UTF_8
}
if let Some(attributes) = self.attributes() {
for (key, value) in attributes {
let value = BytesText::from_plain_str(&value);
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError> {
let key = self.key();
let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len());
elem.push_attribute(Attribute {
key: key.as_bytes(),
value: Cow::Borrowed(value.escaped()),
});
}
// Write the attributes for the value, but not the value contents.
if let Some(value) = self.value() {
let node_type = value.standard_type();
match value {
Value::Binary(ref data) => {
elem.push_attribute(Attribute {
key: b"__size",
value: Cow::Owned(data.len().to_string().into_bytes()),
});
},
Value::Array(ref values) => {
elem.push_attribute(Attribute {
key: b"__count",
value: Cow::Owned(values.len().to_string().into_bytes()),
});
},
_ => {},
};
// Only add a `__type` attribute if this is not a `NodeStart` node
if node_type != StandardType::NodeStart {
elem.push_attribute(Attribute {
key: b"__type",
value: Cow::Borrowed(node_type.name.as_bytes()),
});
}
}
if let Some(attributes) = self.attributes() {
for (key, value) in attributes {
let value = BytesText::from_plain_str(&value);
elem.push_attribute(Attribute {
key: key.as_bytes(),
value: Cow::Borrowed(value.escaped()),
});
}
}
// Now write the value contents.
let start_elem = if let Some(value) = self.value() {
writer.write_event(Event::Start(elem))?;
let value = value.to_string();
let elem = BytesText::from_plain_str(&value);
writer.write_event(Event::Text(elem))?;
None
} else {
Some(elem)
};
let has_value = start_elem.is_none();
let has_children = match self.children() {
Some(children) => !children.is_empty(),
None => false,
};
// A `Some` value here means the start element was not written
if let Some(start_elem) = start_elem {
if !has_children {
writer.write_event(Event::Empty(start_elem))?;
} else {
writer.write_event(Event::Start(start_elem))?;
}
}
if let Some(children) = self.children() {
for child in children {
child.write(writer)?;
}
}
if has_value || has_children {
let end_elem = BytesEnd::borrowed(key.as_bytes());
writer.write_event(Event::End(end_elem))?;
}
Ok(())
}
// Now write the value contents.
let start_elem = if let Some(value) = self.value() {
writer.write_event(Event::Start(elem))?;
let value = value.to_string();
let elem = BytesText::from_plain_str(&value);
writer.write_event(Event::Text(elem))?;
None
} else {
Some(elem)
};
let has_value = start_elem.is_none();
let has_children = match self.children() {
Some(children) => !children.is_empty(),
None => false,
};
// A `Some` value here means the start element was not written
if let Some(start_elem) = start_elem {
if !has_children {
writer.write_event(Event::Empty(start_elem))?;
} else {
writer.write_event(Event::Start(start_elem))?;
}
}
if let Some(children) = self.children() {
for child in children {
child.write(writer)?;
}
}
if has_value || has_children {
let end_elem = BytesEnd::borrowed(key.as_bytes());
writer.write_event(Event::End(end_elem))?;
}
Ok(())
}
}

View File

@@ -1,9 +1,9 @@
use std::borrow::Cow;
use std::io::Write;
use quick_xml::Writer;
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::events::attributes::Attribute;
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::Writer;
use crate::encoding_type::EncodingType;
use crate::error::KbinError;
@@ -12,96 +12,99 @@ use crate::node_types::StandardType;
use crate::to_text_xml::ToTextXml;
impl ToTextXml for NodeCollection {
/// At the moment, decoding the value of a `NodeDefinition` will decode
/// strings into UTF-8.
fn encoding(&self) -> EncodingType {
EncodingType::UTF_8
}
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError> {
let base = self.base();
let key = base.key()?.ok_or(KbinError::InvalidState)?;
let value = match base.value() {
Ok(value) => Some(value),
Err(e) => match e {
KbinError::InvalidNodeType { .. } => None,
_ => return Err(e),
},
};
let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len());
if base.is_array {
let values = value.as_ref().ok_or(KbinError::InvalidState)?.as_array()?;
elem.push_attribute(Attribute {
key: b"__count",
value: Cow::Owned(values.len().to_string().into_bytes()),
});
/// At the moment, decoding the value of a `NodeDefinition` will decode
/// strings into UTF-8.
fn encoding(&self) -> EncodingType {
EncodingType::UTF_8
}
if base.node_type == StandardType::Binary {
let value = value.as_ref().ok_or(KbinError::InvalidState)?.as_slice()?;
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError> {
let base = self.base();
let key = base.key()?.ok_or(KbinError::InvalidState)?;
let value = match base.value() {
Ok(value) => Some(value),
Err(e) => match e {
KbinError::InvalidNodeType { .. } => None,
_ => return Err(e),
},
};
elem.push_attribute(Attribute {
key: b"__size",
value: Cow::Owned(value.len().to_string().into_bytes()),
});
let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len());
if base.is_array {
let values = value.as_ref().ok_or(KbinError::InvalidState)?.as_array()?;
elem.push_attribute(Attribute {
key: b"__count",
value: Cow::Owned(values.len().to_string().into_bytes()),
});
}
if base.node_type == StandardType::Binary {
let value = value.as_ref().ok_or(KbinError::InvalidState)?.as_slice()?;
elem.push_attribute(Attribute {
key: b"__size",
value: Cow::Owned(value.len().to_string().into_bytes()),
});
}
// Only add a `__type` attribute if this is not a `NodeStart` node
if base.node_type != StandardType::NodeStart {
elem.push_attribute(Attribute {
key: b"__type",
value: Cow::Borrowed(base.node_type.name.as_bytes()),
});
}
for attribute in self.attributes() {
let key = attribute
.key()?
.ok_or(KbinError::InvalidState)?
.into_bytes();
let value = attribute.value()?.to_string();
let value = BytesText::from_plain_str(&value);
elem.push_attribute(Attribute {
key: &key,
value: Cow::Borrowed(value.escaped()),
});
}
let start_elem = match value {
Some(value) => {
writer.write_event(Event::Start(elem))?;
let value = value.to_string();
let elem = BytesText::from_plain_str(&value);
writer.write_event(Event::Text(elem))?;
None
},
None => Some(elem),
};
let has_value = start_elem.is_none();
let has_children = !self.children().is_empty();
// A `Some` value here means the start element was not written
if let Some(start_elem) = start_elem {
if !has_children {
writer.write_event(Event::Empty(start_elem))?;
} else {
writer.write_event(Event::Start(start_elem))?;
}
}
for child in self.children() {
child.write(writer)?;
}
if has_value || has_children {
let end_elem = BytesEnd::borrowed(key.as_bytes());
writer.write_event(Event::End(end_elem))?;
}
Ok(())
}
// Only add a `__type` attribute if this is not a `NodeStart` node
if base.node_type != StandardType::NodeStart {
elem.push_attribute(Attribute {
key: b"__type",
value: Cow::Borrowed(base.node_type.name.as_bytes()),
});
}
for attribute in self.attributes() {
let key = attribute.key()?.ok_or(KbinError::InvalidState)?.into_bytes();
let value = attribute.value()?.to_string();
let value = BytesText::from_plain_str(&value);
elem.push_attribute(Attribute {
key: &key,
value: Cow::Borrowed(value.escaped()),
});
}
let start_elem = match value {
Some(value) => {
writer.write_event(Event::Start(elem))?;
let value = value.to_string();
let elem = BytesText::from_plain_str(&value);
writer.write_event(Event::Text(elem))?;
None
},
None => Some(elem),
};
let has_value = start_elem.is_none();
let has_children = !self.children().is_empty();
// A `Some` value here means the start element was not written
if let Some(start_elem) = start_elem {
if !has_children {
writer.write_event(Event::Empty(start_elem))?;
} else {
writer.write_event(Event::Start(start_elem))?;
}
}
for child in self.children() {
child.write(writer)?;
}
if has_value || has_children {
let end_elem = BytesEnd::borrowed(key.as_bytes());
writer.write_event(Event::End(end_elem))?;
}
Ok(())
}
}

View File

@@ -8,74 +8,74 @@ use snafu::ResultExt;
use crate::error::*;
pub trait IntoKbinBytes {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B);
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B);
}
pub trait FromKbinBytes: Sized {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self>;
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self>;
}
impl IntoKbinBytes for i8 {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_i8(self);
}
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_i8(self);
}
}
impl FromKbinBytes for i8 {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
input.read_i8().context(DataConvert)
}
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
input.read_i8().context(DataConvert)
}
}
impl IntoKbinBytes for u8 {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_u8(self);
}
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_u8(self);
}
}
impl FromKbinBytes for u8 {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
input.read_u8().context(DataConvert)
}
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
input.read_u8().context(DataConvert)
}
}
impl IntoKbinBytes for bool {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_u8(if self { 0x01 } else { 0x00 })
}
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_u8(if self { 0x01 } else { 0x00 })
}
}
impl FromKbinBytes for bool {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
match u8::from_kbin_bytes(input)? {
0x00 => Ok(false),
0x01 => Ok(true),
input => Err(KbinError::InvalidBooleanInput { input }),
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
match u8::from_kbin_bytes(input)? {
0x00 => Ok(false),
0x01 => Ok(true),
input => Err(KbinError::InvalidBooleanInput { input }),
}
}
}
}
impl<'a> IntoKbinBytes for &'a [u8] {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put(self);
}
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put(self);
}
}
impl IntoKbinBytes for Ipv4Addr {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
let octets = self.octets();
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
let octets = self.octets();
buf.put(&octets[..])
}
buf.put(&octets[..])
}
}
impl FromKbinBytes for Ipv4Addr {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
let mut octets = [0; 4];
input.read_exact(&mut octets).context(DataConvert)?;
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self> {
let mut octets = [0; 4];
input.read_exact(&mut octets).context(DataConvert)?;
Ok(Ipv4Addr::from(octets))
}
Ok(Ipv4Addr::from(octets))
}
}
macro_rules! multibyte_impl {

View File

@@ -7,66 +7,78 @@ use snafu::ResultExt;
use crate::error::*;
pub trait FromKbinString: Sized {
fn from_kbin_string(input: &str) -> Result<Self>;
fn from_kbin_string(input: &str) -> Result<Self>;
}
fn space_check(input: &str) -> Result<()> {
// check for space character
if input.find(' ').is_some() {
return Err(KbinError::InvalidState.into());
}
// check for space character
if input.find(' ').is_some() {
return Err(KbinError::InvalidState.into());
}
Ok(())
Ok(())
}
fn parse_tuple<T>(node_type: &'static str, input: &str, output: &mut [T]) -> Result<()>
where T: FromStr,
T::Err: Error + Send + Sync + 'static,
where
T: FromStr,
T::Err: Error + Send + Sync + 'static,
{
let count = input.split(' ').count();
if count != output.len() {
return Err(KbinError::SizeMismatch { node_type, expected: output.len(), actual: count });
}
let count = input.split(' ').count();
if count != output.len() {
return Err(KbinError::SizeMismatch {
node_type,
expected: output.len(),
actual: count,
});
}
for (i, part) in input.split(' ').enumerate() {
output[i] = part.parse::<T>()
.map_err(|e| Box::new(e) as Box<(dyn Error + Send + Sync + 'static)>)
.context(StringParse { node_type })?;
}
for (i, part) in input.split(' ').enumerate() {
output[i] = part
.parse::<T>()
.map_err(|e| Box::new(e) as Box<(dyn Error + Send + Sync + 'static)>)
.context(StringParse { node_type })?;
}
Ok(())
Ok(())
}
impl FromKbinString for bool {
fn from_kbin_string(input: &str) -> Result<Self> {
match input {
"false" |
"0" => Ok(false),
"true" |
"1" => Ok(true),
input => Err(KbinError::InvalidBooleanInput { input: u8::from_kbin_string(input)? }),
fn from_kbin_string(input: &str) -> Result<Self> {
match input {
"false" | "0" => Ok(false),
"true" | "1" => Ok(true),
input => Err(KbinError::InvalidBooleanInput {
input: u8::from_kbin_string(input)?,
}),
}
}
}
}
impl FromKbinString for Ipv4Addr {
fn from_kbin_string(input: &str) -> Result<Self> {
space_check(input)?;
fn from_kbin_string(input: &str) -> Result<Self> {
space_check(input)?;
let count = input.split('.').count();
if count != 4 {
return Err(KbinError::SizeMismatch { node_type: "Ipv4Addr", expected: 4, actual: count });
let count = input.split('.').count();
if count != 4 {
return Err(KbinError::SizeMismatch {
node_type: "Ipv4Addr",
expected: 4,
actual: count,
});
}
let mut octets = [0; 4];
// IP addresses are split by a period, so do not use `parse_tuple`
for (i, part) in input.split('.').enumerate() {
octets[i] = part.parse::<u8>().context(StringParseInt {
node_type: "Ipv4Addr",
})?;
}
Ok(Ipv4Addr::from(octets))
}
let mut octets = [0; 4];
// IP addresses are split by a period, so do not use `parse_tuple`
for (i, part) in input.split('.').enumerate() {
octets[i] = part.parse::<u8>().context(StringParseInt { node_type: "Ipv4Addr" })?;
}
Ok(Ipv4Addr::from(octets))
}
}
macro_rules! basic_int_parse {

View File

@@ -4,61 +4,61 @@ use std::net::Ipv4Addr;
use crate::error::KbinError;
use crate::node_types::StandardType;
use crate::types::{FromKbinBytes, IntoKbinBytes};
use crate::types::FromKbinString;
use crate::types::{FromKbinBytes, IntoKbinBytes};
#[derive(Clone, Debug, PartialEq)]
pub enum ValueArray {
S8(Vec<i8>),
U8(Vec<u8>),
S16(Vec<i16>),
U16(Vec<u16>),
S32(Vec<i32>),
U32(Vec<u32>),
S64(Vec<i64>),
U64(Vec<u64>),
Ip4(Vec<Ipv4Addr>),
Float(Vec<f32>),
Double(Vec<f64>),
S8_2(Vec<[i8; 2]>),
U8_2(Vec<[u8; 2]>),
S16_2(Vec<[i16; 2]>),
U16_2(Vec<[u16; 2]>),
S32_2(Vec<[i32; 2]>),
U32_2(Vec<[u32; 2]>),
S64_2(Vec<[i64; 2]>),
U64_2(Vec<[u64; 2]>),
Float2(Vec<[f32; 2]>),
Double2(Vec<[f64; 2]>),
S8_3(Vec<[i8; 3]>),
U8_3(Vec<[u8; 3]>),
S16_3(Vec<[i16; 3]>),
U16_3(Vec<[u16; 3]>),
S32_3(Vec<[i32; 3]>),
U32_3(Vec<[u32; 3]>),
S64_3(Vec<[i64; 3]>),
U64_3(Vec<[u64; 3]>),
Float3(Vec<[f32; 3]>),
Double3(Vec<[f64; 3]>),
S8_4(Vec<[i8; 4]>),
U8_4(Vec<[u8; 4]>),
S16_4(Vec<[i16; 4]>),
U16_4(Vec<[u16; 4]>),
S32_4(Vec<[i32; 4]>),
U32_4(Vec<[u32; 4]>),
S64_4(Vec<[i64; 4]>),
U64_4(Vec<[u64; 4]>),
Float4(Vec<[f32; 4]>),
Double4(Vec<[f64; 4]>),
Vs8(Vec<[i8; 16]>),
Vu8(Vec<[u8; 16]>),
Vs16(Vec<[i16; 8]>),
Vu16(Vec<[u16; 8]>),
Boolean(Vec<bool>),
Boolean2(Vec<[bool; 2]>),
Boolean3(Vec<[bool; 3]>),
Boolean4(Vec<[bool; 4]>),
Vb(Vec<[bool; 16]>),
S8(Vec<i8>),
U8(Vec<u8>),
S16(Vec<i16>),
U16(Vec<u16>),
S32(Vec<i32>),
U32(Vec<u32>),
S64(Vec<i64>),
U64(Vec<u64>),
Ip4(Vec<Ipv4Addr>),
Float(Vec<f32>),
Double(Vec<f64>),
S8_2(Vec<[i8; 2]>),
U8_2(Vec<[u8; 2]>),
S16_2(Vec<[i16; 2]>),
U16_2(Vec<[u16; 2]>),
S32_2(Vec<[i32; 2]>),
U32_2(Vec<[u32; 2]>),
S64_2(Vec<[i64; 2]>),
U64_2(Vec<[u64; 2]>),
Float2(Vec<[f32; 2]>),
Double2(Vec<[f64; 2]>),
S8_3(Vec<[i8; 3]>),
U8_3(Vec<[u8; 3]>),
S16_3(Vec<[i16; 3]>),
U16_3(Vec<[u16; 3]>),
S32_3(Vec<[i32; 3]>),
U32_3(Vec<[u32; 3]>),
S64_3(Vec<[i64; 3]>),
U64_3(Vec<[u64; 3]>),
Float3(Vec<[f32; 3]>),
Double3(Vec<[f64; 3]>),
S8_4(Vec<[i8; 4]>),
U8_4(Vec<[u8; 4]>),
S16_4(Vec<[i16; 4]>),
U16_4(Vec<[u16; 4]>),
S32_4(Vec<[i32; 4]>),
U32_4(Vec<[u32; 4]>),
S64_4(Vec<[i64; 4]>),
U64_4(Vec<[u64; 4]>),
Float4(Vec<[f32; 4]>),
Double4(Vec<[f64; 4]>),
Vs8(Vec<[i8; 16]>),
Vu8(Vec<[u8; 16]>),
Vs16(Vec<[i16; 8]>),
Vu16(Vec<[u16; 8]>),
Boolean(Vec<bool>),
Boolean2(Vec<[bool; 2]>),
Boolean3(Vec<[bool; 3]>),
Boolean4(Vec<[bool; 4]>),
Vb(Vec<[bool; 16]>),
}
macro_rules! type_impl {
@@ -185,51 +185,51 @@ macro_rules! type_impl {
}
impl ValueArray {
type_impl! {
S8, U8,
S16, U16,
S32, U32,
S64, U64,
Ip4,
Float,
Double,
Boolean,
S8_2, S8_3, S8_4, Vs8,
U8_2, U8_3, U8_4, Vu8,
Boolean2, Boolean3, Boolean4, Vb,
S16_2, S16_3, S16_4, Vs16,
S32_2, S32_3, S32_4,
S64_2, S64_3, S64_4,
U16_2, U16_3, U16_4, Vu16,
U32_2, U32_3, U32_4,
U64_2, U64_3, U64_4,
Float2, Float3, Float4,
Double2, Double3, Double4,
}
type_impl! {
S8, U8,
S16, U16,
S32, U32,
S64, U64,
Ip4,
Float,
Double,
Boolean,
S8_2, S8_3, S8_4, Vs8,
U8_2, U8_3, U8_4, Vu8,
Boolean2, Boolean3, Boolean4, Vb,
S16_2, S16_3, S16_4, Vs16,
S32_2, S32_3, S32_4,
S64_2, S64_3, S64_4,
U16_2, U16_3, U16_4, Vu16,
U32_2, U32_3, U32_4,
U64_2, U64_3, U64_4,
Float2, Float3, Float4,
Double2, Double3, Double4,
}
}
fn write_values<T: fmt::Display>(f: &mut fmt::Formatter, values: &[T]) -> fmt::Result {
for (i, v) in values.iter().enumerate() {
if i > 0 {
f.write_str(" ")?;
for (i, v) in values.iter().enumerate() {
if i > 0 {
f.write_str(" ")?;
}
fmt::Display::fmt(v, f)?;
}
fmt::Display::fmt(v, f)?;
}
Ok(())
Ok(())
}
macro_rules! write_array {
($method:ident, $num:expr) => {
fn $method<T: fmt::Display>(f: &mut fmt::Formatter, values: &[[T; $num]]) -> fmt::Result {
for (i, v) in values.iter().flat_map(|v| v.into_iter()).enumerate() {
if i > 0 {
f.write_str(" ")?;
($method:ident, $num:expr) => {
fn $method<T: fmt::Display>(f: &mut fmt::Formatter, values: &[[T; $num]]) -> fmt::Result {
for (i, v) in values.iter().flat_map(|v| v.into_iter()).enumerate() {
if i > 0 {
f.write_str(" ")?;
}
fmt::Display::fmt(v, f)?;
}
Ok(())
}
fmt::Display::fmt(v, f)?;
}
Ok(())
}
};
};
}
write_array!(write_array_2, 2);
@@ -239,58 +239,58 @@ write_array!(write_array_8, 8);
write_array!(write_array_16, 16);
impl fmt::Display for ValueArray {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ValueArray::S8(v) => write_values(f, v),
ValueArray::U8(v) => write_values(f, v),
ValueArray::S16(v) => write_values(f, v),
ValueArray::U16(v) => write_values(f, v),
ValueArray::S32(v) => write_values(f, v),
ValueArray::U32(v) => write_values(f, v),
ValueArray::S64(v) => write_values(f, v),
ValueArray::U64(v) => write_values(f, v),
ValueArray::Ip4(v) => write_values(f, v),
ValueArray::Float(v) => write_values(f, v),
ValueArray::Double(v) => write_values(f, v),
ValueArray::S8_2(v) => write_array_2(f, v),
ValueArray::U8_2(v) => write_array_2(f, v),
ValueArray::S16_2(v) => write_array_2(f, v),
ValueArray::U16_2(v) => write_array_2(f, v),
ValueArray::S32_2(v) => write_array_2(f, v),
ValueArray::U32_2(v) => write_array_2(f, v),
ValueArray::S64_2(v) => write_array_2(f, v),
ValueArray::U64_2(v) => write_array_2(f, v),
ValueArray::Float2(v) => write_array_2(f, v),
ValueArray::Double2(v) => write_array_2(f, v),
ValueArray::S8_3(v) => write_array_3(f, v),
ValueArray::U8_3(v) => write_array_3(f, v),
ValueArray::S16_3(v) => write_array_3(f, v),
ValueArray::U16_3(v) => write_array_3(f, v),
ValueArray::S32_3(v) => write_array_3(f, v),
ValueArray::U32_3(v) => write_array_3(f, v),
ValueArray::S64_3(v) => write_array_3(f, v),
ValueArray::U64_3(v) => write_array_3(f, v),
ValueArray::Float3(v) => write_array_3(f, v),
ValueArray::Double3(v) => write_array_3(f, v),
ValueArray::S8_4(v) => write_array_4(f, v),
ValueArray::U8_4(v) => write_array_4(f, v),
ValueArray::S16_4(v) => write_array_4(f, v),
ValueArray::U16_4(v) => write_array_4(f, v),
ValueArray::S32_4(v) => write_array_4(f, v),
ValueArray::U32_4(v) => write_array_4(f, v),
ValueArray::S64_4(v) => write_array_4(f, v),
ValueArray::U64_4(v) => write_array_4(f, v),
ValueArray::Float4(v) => write_array_4(f, v),
ValueArray::Double4(v) => write_array_4(f, v),
ValueArray::Vs8(v) => write_array_16(f, v),
ValueArray::Vu8(v) => write_array_16(f, v),
ValueArray::Vs16(v) => write_array_8(f, v),
ValueArray::Vu16(v) => write_array_8(f, v),
ValueArray::Boolean(v) => write_values(f, &v),
ValueArray::Boolean2(v) => write_array_2(f, v),
ValueArray::Boolean3(v) => write_array_3(f, v),
ValueArray::Boolean4(v) => write_array_4(f, v),
ValueArray::Vb(v) => write_array_16(f, v),
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ValueArray::S8(v) => write_values(f, v),
ValueArray::U8(v) => write_values(f, v),
ValueArray::S16(v) => write_values(f, v),
ValueArray::U16(v) => write_values(f, v),
ValueArray::S32(v) => write_values(f, v),
ValueArray::U32(v) => write_values(f, v),
ValueArray::S64(v) => write_values(f, v),
ValueArray::U64(v) => write_values(f, v),
ValueArray::Ip4(v) => write_values(f, v),
ValueArray::Float(v) => write_values(f, v),
ValueArray::Double(v) => write_values(f, v),
ValueArray::S8_2(v) => write_array_2(f, v),
ValueArray::U8_2(v) => write_array_2(f, v),
ValueArray::S16_2(v) => write_array_2(f, v),
ValueArray::U16_2(v) => write_array_2(f, v),
ValueArray::S32_2(v) => write_array_2(f, v),
ValueArray::U32_2(v) => write_array_2(f, v),
ValueArray::S64_2(v) => write_array_2(f, v),
ValueArray::U64_2(v) => write_array_2(f, v),
ValueArray::Float2(v) => write_array_2(f, v),
ValueArray::Double2(v) => write_array_2(f, v),
ValueArray::S8_3(v) => write_array_3(f, v),
ValueArray::U8_3(v) => write_array_3(f, v),
ValueArray::S16_3(v) => write_array_3(f, v),
ValueArray::U16_3(v) => write_array_3(f, v),
ValueArray::S32_3(v) => write_array_3(f, v),
ValueArray::U32_3(v) => write_array_3(f, v),
ValueArray::S64_3(v) => write_array_3(f, v),
ValueArray::U64_3(v) => write_array_3(f, v),
ValueArray::Float3(v) => write_array_3(f, v),
ValueArray::Double3(v) => write_array_3(f, v),
ValueArray::S8_4(v) => write_array_4(f, v),
ValueArray::U8_4(v) => write_array_4(f, v),
ValueArray::S16_4(v) => write_array_4(f, v),
ValueArray::U16_4(v) => write_array_4(f, v),
ValueArray::S32_4(v) => write_array_4(f, v),
ValueArray::U32_4(v) => write_array_4(f, v),
ValueArray::S64_4(v) => write_array_4(f, v),
ValueArray::U64_4(v) => write_array_4(f, v),
ValueArray::Float4(v) => write_array_4(f, v),
ValueArray::Double4(v) => write_array_4(f, v),
ValueArray::Vs8(v) => write_array_16(f, v),
ValueArray::Vu8(v) => write_array_16(f, v),
ValueArray::Vs16(v) => write_array_8(f, v),
ValueArray::Vu16(v) => write_array_8(f, v),
ValueArray::Boolean(v) => write_values(f, &v),
ValueArray::Boolean2(v) => write_array_2(f, v),
ValueArray::Boolean3(v) => write_array_3(f, v),
ValueArray::Boolean4(v) => write_array_4(f, v),
ValueArray::Vb(v) => write_array_16(f, v),
}
}
}
}

View File

@@ -228,136 +228,180 @@ macro_rules! tuple {
}
impl Value {
tuple! {
S8_2, S8_3, S8_4, Vs8,
U8_2, U8_3, U8_4, Vu8,
Boolean2, Boolean3, Boolean4, Vb,
S16_2, S16_3, S16_4, Vs16,
S32_2, S32_3, S32_4,
S64_2, S64_3, S64_4,
U16_2, U16_3, U16_4, Vu16,
U32_2, U32_3, U32_4,
U64_2, U64_3, U64_4,
Float2, Float3, Float4,
Double2, Double3, Double4,
}
pub fn to_bytes(&self) -> Result<Vec<u8>> {
let mut output = Vec::new();
self.to_bytes_inner(&mut output)?;
Ok(output)
}
#[inline]
pub fn to_bytes_into(&self, output: &mut Vec<u8>) -> Result<()> {
self.to_bytes_inner(output)
}
pub fn as_i8(&self) -> Result<i8> {
match self {
Value::S8(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S8, value: value.clone() }),
tuple! {
S8_2, S8_3, S8_4, Vs8,
U8_2, U8_3, U8_4, Vu8,
Boolean2, Boolean3, Boolean4, Vb,
S16_2, S16_3, S16_4, Vs16,
S32_2, S32_3, S32_4,
S64_2, S64_3, S64_4,
U16_2, U16_3, U16_4, Vu16,
U32_2, U32_3, U32_4,
U64_2, U64_3, U64_4,
Float2, Float3, Float4,
Double2, Double3, Double4,
}
}
pub fn as_u8(&self) -> Result<u8> {
match self {
Value::U8(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: value.clone() }),
}
}
pub fn to_bytes(&self) -> Result<Vec<u8>> {
let mut output = Vec::new();
self.to_bytes_inner(&mut output)?;
pub fn as_i16(&self) -> Result<i16> {
match self {
Value::S16(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S16, value: value.clone() }),
Ok(output)
}
}
pub fn as_u16(&self) -> Result<u16> {
match self {
Value::U16(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U16, value: value.clone() }),
#[inline]
pub fn to_bytes_into(&self, output: &mut Vec<u8>) -> Result<()> {
self.to_bytes_inner(output)
}
}
pub fn as_i32(&self) -> Result<i32> {
match self {
Value::S32(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S32, value: value.clone() }),
pub fn as_i8(&self) -> Result<i8> {
match self {
Value::S8(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::S8,
value: value.clone(),
}),
}
}
}
pub fn as_u32(&self) -> Result<u32> {
match self {
Value::U32(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U32, value: value.clone() }),
pub fn as_u8(&self) -> Result<u8> {
match self {
Value::U8(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::U8,
value: value.clone(),
}),
}
}
}
pub fn as_i64(&self) -> Result<i64> {
match self {
Value::S64(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::S64, value: value.clone() }),
pub fn as_i16(&self) -> Result<i16> {
match self {
Value::S16(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::S16,
value: value.clone(),
}),
}
}
}
pub fn as_u64(&self) -> Result<u64> {
match self {
Value::U64(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U64, value: value.clone() }),
pub fn as_u16(&self) -> Result<u16> {
match self {
Value::U16(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::U16,
value: value.clone(),
}),
}
}
}
pub fn as_slice(&self) -> Result<&[u8]> {
match self {
Value::Binary(ref data) => Ok(data),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }),
pub fn as_i32(&self) -> Result<i32> {
match self {
Value::S32(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::S32,
value: value.clone(),
}),
}
}
}
pub fn as_str(&self) -> Result<&str> {
match self {
Value::String(ref s) => Ok(s),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::String, value: value.clone() }),
pub fn as_u32(&self) -> Result<u32> {
match self {
Value::U32(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::U32,
value: value.clone(),
}),
}
}
}
pub fn as_string(self) -> Result<String> {
match self {
Value::String(s) => Ok(s),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::String, value }),
pub fn as_i64(&self) -> Result<i64> {
match self {
Value::S64(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::S64,
value: value.clone(),
}),
}
}
}
pub fn as_attribute(self) -> Result<String> {
match self {
Value::Attribute(s) => Ok(s),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Attribute, value }),
pub fn as_u64(&self) -> Result<u64> {
match self {
Value::U64(ref n) => Ok(*n),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::U64,
value: value.clone(),
}),
}
}
}
pub fn as_binary(&self) -> Result<&[u8]> {
match self {
Value::Binary(ref data) => Ok(data),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }),
pub fn as_slice(&self) -> Result<&[u8]> {
match self {
Value::Binary(ref data) => Ok(data),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::Binary,
value: value.clone(),
}),
}
}
}
pub fn as_array(&self) -> Result<&ValueArray> {
match self {
Value::Array(ref values) => Ok(values),
value => Err(KbinError::ExpectedValueArray { value: value.clone() }),
pub fn as_str(&self) -> Result<&str> {
match self {
Value::String(ref s) => Ok(s),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::String,
value: value.clone(),
}),
}
}
}
pub fn into_binary(self) -> Result<Vec<u8>> {
match self {
Value::Binary(data) => Ok(data),
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value }),
pub fn as_string(self) -> Result<String> {
match self {
Value::String(s) => Ok(s),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::String,
value,
}),
}
}
pub fn as_attribute(self) -> Result<String> {
match self {
Value::Attribute(s) => Ok(s),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::Attribute,
value,
}),
}
}
pub fn as_binary(&self) -> Result<&[u8]> {
match self {
Value::Binary(ref data) => Ok(data),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::Binary,
value: value.clone(),
}),
}
}
pub fn as_array(&self) -> Result<&ValueArray> {
match self {
Value::Array(ref values) => Ok(values),
value => Err(KbinError::ExpectedValueArray {
value: value.clone(),
}),
}
}
pub fn into_binary(self) -> Result<Vec<u8>> {
match self {
Value::Binary(data) => Ok(data),
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::Binary,
value,
}),
}
}
}
}
/*
@@ -374,46 +418,58 @@ impl TryFrom<Value> for Vec<Value> {
*/
impl TryFrom<Value> for Vec<u8> {
type Error = KbinError;
type Error = KbinError;
fn try_from(value: Value) -> Result<Self> {
// An array of unsigned 8-bit integers can either be `Binary` or a literal
// array of unsigned 8-bit integers.
match value {
Value::Binary(data) => Ok(data),
Value::Array(values) => match values {
ValueArray::U8(values) => Ok(values),
values => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: Value::Array(values) }),
},
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value }),
fn try_from(value: Value) -> Result<Self> {
// An array of unsigned 8-bit integers can either be `Binary` or a literal
// array of unsigned 8-bit integers.
match value {
Value::Binary(data) => Ok(data),
Value::Array(values) => match values {
ValueArray::U8(values) => Ok(values),
values => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::U8,
value: Value::Array(values),
}),
},
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::Binary,
value,
}),
}
}
}
}
impl TryFrom<&Value> for Vec<u8> {
type Error = KbinError;
type Error = KbinError;
fn try_from(value: &Value) -> Result<Self> {
match value {
Value::Binary(ref data) => Ok(data.to_vec()),
Value::Array(ref values) => match values.clone() {
ValueArray::U8(values) => Ok(values),
values => Err(KbinError::ValueTypeMismatch { node_type: StandardType::U8, value: Value::Array(values) }),
},
value => Err(KbinError::ValueTypeMismatch { node_type: StandardType::Binary, value: value.clone() }),
fn try_from(value: &Value) -> Result<Self> {
match value {
Value::Binary(ref data) => Ok(data.to_vec()),
Value::Array(ref values) => match values.clone() {
ValueArray::U8(values) => Ok(values),
values => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::U8,
value: Value::Array(values),
}),
},
value => Err(KbinError::ValueTypeMismatch {
node_type: StandardType::Binary,
value: value.clone(),
}),
}
}
}
}
impl From<Vec<u8>> for Value {
fn from(value: Vec<u8>) -> Value {
Value::Binary(value)
}
fn from(value: Vec<u8>) -> Value {
Value::Binary(value)
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
macro_rules! field {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
macro_rules! field {
(
display: [$($konst_display:ident),*],
debug: [$($konst_debug:ident),*]
@@ -435,28 +491,28 @@ impl fmt::Debug for Value {
};
}
field! {
display: [
S8, S16, S32, S64,
U8, U16, U32, U64,
Float, Double, Boolean
],
debug: [
String, Time, Ip4,
Attribute,
S8_2, U8_2, S16_2, U16_2, S32_2, U32_2, S64_2, U64_2, Float2, Double2, Boolean2,
S8_3, U8_3, S16_3, U16_3, S32_3, U32_3, S64_3, U64_3, Float3, Double3, Boolean3,
S8_4, U8_4, S16_4, U16_4, S32_4, U32_4, S64_4, U64_4, Float4, Double4, Boolean4,
Vs16, Vu16,
Vs8, Vu8, Vb
]
field! {
display: [
S8, S16, S32, S64,
U8, U16, U32, U64,
Float, Double, Boolean
],
debug: [
String, Time, Ip4,
Attribute,
S8_2, U8_2, S16_2, U16_2, S32_2, U32_2, S64_2, U64_2, Float2, Double2, Boolean2,
S8_3, U8_3, S16_3, U16_3, S32_3, U32_3, S64_3, U64_3, Float3, Double3, Boolean3,
S8_4, U8_4, S16_4, U16_4, S32_4, U32_4, S64_4, U64_4, Float4, Double4, Boolean4,
Vs16, Vu16,
Vs8, Vu8, Vb
]
}
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
macro_rules! display_value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
macro_rules! display_value {
(
simple: [$($simple:ident),*],
tuple: [$($tuple:ident),*],
@@ -506,25 +562,25 @@ impl fmt::Display for Value {
};
}
display_value! {
simple: [
S8, U8, S16, U16, S32, U32, S64, U64,
String, Ip4, Time, Attribute,
Array
],
tuple: [
S8_2, U8_2, S16_2, U16_2, S32_2, U32_2, S64_2, U64_2,
S8_3, U8_3, S16_3, U16_3, S32_3, U32_3, S64_3, U64_3,
S8_4, U8_4, S16_4, U16_4, S32_4, U32_4, S64_4, U64_4,
Vs8, Vu8, Vs16, Vu16
],
value: [
Float => [Float2, Float3, Float4],
Double => [Double2, Double3, Double4],
Boolean => [Boolean2, Boolean3, Boolean4, Vb]
]
display_value! {
simple: [
S8, U8, S16, U16, S32, U32, S64, U64,
String, Ip4, Time, Attribute,
Array
],
tuple: [
S8_2, U8_2, S16_2, U16_2, S32_2, U32_2, S64_2, U64_2,
S8_3, U8_3, S16_3, U16_3, S32_3, U32_3, S64_3, U64_3,
S8_4, U8_4, S16_4, U16_4, S32_4, U32_4, S64_4, U64_4,
Vs8, Vu8, Vs16, Vu16
],
value: [
Float => [Float2, Float3, Float4],
Double => [Double2, Double3, Double4],
Boolean => [Boolean2, Boolean3, Boolean4, Vb]
]
}
}
}
}
construct_types! {

View File

@@ -14,223 +14,325 @@ use crate::value::Value;
use super::{ARRAY_MASK, SIGNATURE};
fn write_value(options: &Options, data_buf: &mut ByteBufferWrite, node_type: StandardType, is_array: bool, value: &Value) -> Result<()> {
match value {
Value::Binary(data) => {
trace!("data: 0x{:02x?}", data);
fn write_value(
options: &Options,
data_buf: &mut ByteBufferWrite,
node_type: StandardType,
is_array: bool,
value: &Value,
) -> Result<()> {
match value {
Value::Binary(data) => {
trace!("data: 0x{:02x?}", data);
let size = (data.len() as u32) * (node_type.size as u32);
data_buf.write_u32::<BigEndian>(size).context(DataWrite { node_type: "binary node size" })?;
data_buf.write_all(&data).context(DataWrite { node_type: "binary" })?;
data_buf.realign_writes(None)?;
},
Value::String(text) => {
data_buf.write_str(options.encoding, &text)?;
},
Value::Array(values) => {
if !is_array {
return Err(KbinError::InvalidState);
}
let size = (data.len() as u32) * (node_type.size as u32);
data_buf.write_u32::<BigEndian>(size).context(DataWrite {
node_type: "binary node size",
})?;
data_buf.write_all(&data).context(DataWrite {
node_type: "binary",
})?;
data_buf.realign_writes(None)?;
},
Value::String(text) => {
data_buf.write_str(options.encoding, &text)?;
},
Value::Array(values) => {
if !is_array {
return Err(KbinError::InvalidState);
}
let total_size = values.len() * node_type.count * node_type.size;
let total_size = values.len() * node_type.count * node_type.size;
let mut data = Vec::with_capacity(total_size);
values.to_bytes_into(&mut data)?;
let mut data = Vec::with_capacity(total_size);
values.to_bytes_into(&mut data)?;
data_buf.write_u32::<BigEndian>(total_size as u32).context(DataWrite { node_type: "node size" })?;
data_buf.write_all(&data).context(DataWrite { node_type: node_type.name })?;
data_buf.realign_writes(None)?;
},
value => {
if is_array {
return Err(KbinError::InvalidState);
} else {
let data = value.to_bytes()?;
data_buf.write_aligned(*node_type, &data)?;
}
},
};
data_buf
.write_u32::<BigEndian>(total_size as u32)
.context(DataWrite {
node_type: "node size",
})?;
data_buf.write_all(&data).context(DataWrite {
node_type: node_type.name,
})?;
data_buf.realign_writes(None)?;
},
value => {
if is_array {
return Err(KbinError::InvalidState);
} else {
let data = value.to_bytes()?;
data_buf.write_aligned(*node_type, &data)?;
}
},
};
Ok(())
Ok(())
}
pub trait Writeable {
fn write_node(&self, options: &Options, node_buf: &mut ByteBufferWrite, data_buf: &mut ByteBufferWrite) -> Result<()>;
fn write_node(
&self,
options: &Options,
node_buf: &mut ByteBufferWrite,
data_buf: &mut ByteBufferWrite,
) -> Result<()>;
}
impl Writeable for NodeCollection {
fn write_node(&self, options: &Options, node_buf: &mut ByteBufferWrite, data_buf: &mut ByteBufferWrite) -> Result<()> {
let (node_type, is_array) = self.base().node_type_tuple();
let array_mask = if is_array { ARRAY_MASK } else { 0 };
let name = self.base().key()?.ok_or(KbinError::InvalidState)?;
fn write_node(
&self,
options: &Options,
node_buf: &mut ByteBufferWrite,
data_buf: &mut ByteBufferWrite,
) -> Result<()> {
let (node_type, is_array) = self.base().node_type_tuple();
let array_mask = if is_array { ARRAY_MASK } else { 0 };
let name = self.base().key()?.ok_or(KbinError::InvalidState)?;
debug!("NodeCollection write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}",
debug!("NodeCollection write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}",
name,
node_type,
node_type.size,
node_type.count,
is_array);
node_buf.write_u8(node_type as u8 | array_mask).context(DataWrite { node_type: node_type.name })?;
match options.compression {
Compression::Compressed => Sixbit::pack(&mut **node_buf, &name)?,
Compression::Uncompressed => {
let data = options.encoding.encode_bytes(&name)?;
let len = (data.len() - 1) as u8;
node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { node_type: "node name length" })?;
node_buf.write_all(&data).context(DataWrite { node_type: "node name bytes" })?;
},
};
node_buf
.write_u8(node_type as u8 | array_mask)
.context(DataWrite {
node_type: node_type.name,
})?;
match options.compression {
Compression::Compressed => Sixbit::pack(&mut **node_buf, &name)?,
Compression::Uncompressed => {
let data = options.encoding.encode_bytes(&name)?;
let len = (data.len() - 1) as u8;
node_buf.write_u8(len | ARRAY_MASK).context(DataWrite {
node_type: "node name length",
})?;
node_buf.write_all(&data).context(DataWrite {
node_type: "node name bytes",
})?;
},
};
if node_type != StandardType::NodeStart {
let value = self.base().value()?;
write_value(options, data_buf, node_type, is_array, &value)?;
if node_type != StandardType::NodeStart {
let value = self.base().value()?;
write_value(options, data_buf, node_type, is_array, &value)?;
}
for attr in self.attributes() {
let key = attr.key()?.ok_or(KbinError::InvalidState)?;
let value = attr.value_bytes().ok_or(KbinError::InvalidState)?;
trace!(
"NodeCollection write_node => attr: {}, value: 0x{:02x?}",
key,
value
);
data_buf.buf_write(value)?;
node_buf
.write_u8(StandardType::Attribute as u8)
.context(DataWrite {
node_type: StandardType::Attribute.name,
})?;
match options.compression {
Compression::Compressed => Sixbit::pack(&mut **node_buf, &key)?,
Compression::Uncompressed => {
let data = options.encoding.encode_bytes(&key)?;
let len = (data.len() - 1) as u8;
node_buf.write_u8(len | ARRAY_MASK).context(DataWrite {
node_type: "attribute name length",
})?;
node_buf.write_all(&data).context(DataWrite {
node_type: "node name bytes",
})?;
},
};
}
for child in self.children() {
child.write_node(options, node_buf, data_buf)?;
}
// node end always has the array bit set
node_buf
.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK)
.context(DataWrite {
node_type: "node end",
})?;
Ok(())
}
for attr in self.attributes() {
let key = attr.key()?.ok_or(KbinError::InvalidState)?;
let value = attr.value_bytes().ok_or(KbinError::InvalidState)?;
trace!("NodeCollection write_node => attr: {}, value: 0x{:02x?}", key, value);
data_buf.buf_write(value)?;
node_buf.write_u8(StandardType::Attribute as u8).context(DataWrite { node_type: StandardType::Attribute.name })?;
match options.compression {
Compression::Compressed => Sixbit::pack(&mut **node_buf, &key)?,
Compression::Uncompressed => {
let data = options.encoding.encode_bytes(&key)?;
let len = (data.len() - 1) as u8;
node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { node_type: "attribute name length" })?;
node_buf.write_all(&data).context(DataWrite { node_type: "node name bytes" })?;
},
};
}
for child in self.children() {
child.write_node(options, node_buf, data_buf)?;
}
// node end always has the array bit set
node_buf.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK).context(DataWrite { node_type: "node end" })?;
Ok(())
}
}
impl Writeable for Node {
fn write_node(&self, options: &Options, node_buf: &mut ByteBufferWrite, data_buf: &mut ByteBufferWrite) -> Result<()> {
let (node_type, is_array) = match self.value() {
Some(Value::Array(ref values)) => (values.standard_type(), true),
Some(ref value) => (value.standard_type(), false),
None => (StandardType::NodeStart, false),
};
let array_mask = if is_array { ARRAY_MASK } else { 0 };
debug!("Node write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}",
self.key(),
node_type,
node_type.size,
node_type.count,
is_array);
node_buf.write_u8(node_type as u8 | array_mask).context(DataWrite { node_type: node_type.name })?;
match options.compression {
Compression::Compressed => Sixbit::pack(&mut **node_buf, &self.key())?,
Compression::Uncompressed => {
let data = options.encoding.encode_bytes(&self.key())?;
let len = (data.len() - 1) as u8;
node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { node_type: "node name length" })?;
node_buf.write_all(&data).context(DataWrite { node_type: "node name bytes" })?;
},
};
if let Some(value) = self.value() {
write_value(options, data_buf, node_type, is_array, value)?;
}
if let Some(attributes) = self.attributes() {
for (key, value) in attributes {
trace!("Node write_node => attr: {}, value: {}", key, value);
data_buf.write_str(options.encoding, value)?;
node_buf.write_u8(StandardType::Attribute as u8).context(DataWrite { node_type: StandardType::Attribute.name })?;
match options.compression {
Compression::Compressed => Sixbit::pack(&mut **node_buf, &key)?,
Compression::Uncompressed => {
let data = options.encoding.encode_bytes(&key)?;
let len = (data.len() - 1) as u8;
node_buf.write_u8(len | ARRAY_MASK).context(DataWrite { node_type: "attribute name length" })?;
node_buf.write_all(&data).context(DataWrite { node_type: "node name bytes" })?;
},
fn write_node(
&self,
options: &Options,
node_buf: &mut ByteBufferWrite,
data_buf: &mut ByteBufferWrite,
) -> Result<()> {
let (node_type, is_array) = match self.value() {
Some(Value::Array(ref values)) => (values.standard_type(), true),
Some(ref value) => (value.standard_type(), false),
None => (StandardType::NodeStart, false),
};
}
let array_mask = if is_array { ARRAY_MASK } else { 0 };
debug!(
"Node write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}",
self.key(),
node_type,
node_type.size,
node_type.count,
is_array
);
node_buf
.write_u8(node_type as u8 | array_mask)
.context(DataWrite {
node_type: node_type.name,
})?;
match options.compression {
Compression::Compressed => Sixbit::pack(&mut **node_buf, &self.key())?,
Compression::Uncompressed => {
let data = options.encoding.encode_bytes(&self.key())?;
let len = (data.len() - 1) as u8;
node_buf.write_u8(len | ARRAY_MASK).context(DataWrite {
node_type: "node name length",
})?;
node_buf.write_all(&data).context(DataWrite {
node_type: "node name bytes",
})?;
},
};
if let Some(value) = self.value() {
write_value(options, data_buf, node_type, is_array, value)?;
}
if let Some(attributes) = self.attributes() {
for (key, value) in attributes {
trace!("Node write_node => attr: {}, value: {}", key, value);
data_buf.write_str(options.encoding, value)?;
node_buf
.write_u8(StandardType::Attribute as u8)
.context(DataWrite {
node_type: StandardType::Attribute.name,
})?;
match options.compression {
Compression::Compressed => Sixbit::pack(&mut **node_buf, &key)?,
Compression::Uncompressed => {
let data = options.encoding.encode_bytes(&key)?;
let len = (data.len() - 1) as u8;
node_buf.write_u8(len | ARRAY_MASK).context(DataWrite {
node_type: "attribute name length",
})?;
node_buf.write_all(&data).context(DataWrite {
node_type: "node name bytes",
})?;
},
};
}
}
if let Some(children) = self.children() {
for child in children {
child.write_node(options, node_buf, data_buf)?;
}
}
// node end always has the array bit set
node_buf
.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK)
.context(DataWrite {
node_type: "node end",
})?;
Ok(())
}
if let Some(children) = self.children() {
for child in children {
child.write_node(options, node_buf, data_buf)?;
}
}
// node end always has the array bit set
node_buf.write_u8(StandardType::NodeEnd as u8 | ARRAY_MASK).context(DataWrite { node_type: "node end" })?;
Ok(())
}
}
pub struct Writer {
options: Options,
options: Options,
}
impl Writer {
pub fn new() -> Self {
Self {
options: Options::default(),
pub fn new() -> Self {
Self {
options: Options::default(),
}
}
}
pub fn with_options(options: Options) -> Self {
Self {
options,
pub fn with_options(options: Options) -> Self {
Self { options }
}
}
pub fn to_binary<T>(&mut self, input: &T) -> Result<Vec<u8>>
where T: Writeable
{
let mut header = Cursor::new(Vec::with_capacity(8));
header.write_u8(SIGNATURE).context(HeaderWrite { field: "signature" })?;
pub fn to_binary<T>(&mut self, input: &T) -> Result<Vec<u8>>
where
T: Writeable,
{
let mut header = Cursor::new(Vec::with_capacity(8));
header
.write_u8(SIGNATURE)
.context(HeaderWrite { field: "signature" })?;
let compression = self.options.compression.to_byte();
header.write_u8(compression).context(HeaderWrite { field: "compression" })?;
let compression = self.options.compression.to_byte();
header.write_u8(compression).context(HeaderWrite {
field: "compression",
})?;
let encoding = self.options.encoding.to_byte();
header.write_u8(encoding).context(HeaderWrite { field: "encoding" })?;
header.write_u8(0xFF ^ encoding).context(HeaderWrite { field: "encoding negation" })?;
let encoding = self.options.encoding.to_byte();
header
.write_u8(encoding)
.context(HeaderWrite { field: "encoding" })?;
header.write_u8(0xFF ^ encoding).context(HeaderWrite {
field: "encoding negation",
})?;
let mut node_buf = ByteBufferWrite::new(Vec::new());
let mut data_buf = ByteBufferWrite::new(Vec::new());
let mut node_buf = ByteBufferWrite::new(Vec::new());
let mut data_buf = ByteBufferWrite::new(Vec::new());
input.write_node(&self.options, &mut node_buf, &mut data_buf)?;
input.write_node(&self.options, &mut node_buf, &mut data_buf)?;
node_buf.write_u8(StandardType::FileEnd as u8 | ARRAY_MASK).context(DataWrite { node_type: "file end" })?;
node_buf.realign_writes(None)?;
node_buf
.write_u8(StandardType::FileEnd as u8 | ARRAY_MASK)
.context(DataWrite {
node_type: "file end",
})?;
node_buf.realign_writes(None)?;
let mut output = header.into_inner();
let mut output = header.into_inner();
let node_buf = node_buf.into_inner();
debug!("to_binary_internal => node_buf len: {0} (0x{0:x})", node_buf.len());
output.write_u32::<BigEndian>(node_buf.len() as u32).context(HeaderWrite { field: "node buffer length" })?;
output.extend_from_slice(&node_buf);
let node_buf = node_buf.into_inner();
debug!(
"to_binary_internal => node_buf len: {0} (0x{0:x})",
node_buf.len()
);
output
.write_u32::<BigEndian>(node_buf.len() as u32)
.context(HeaderWrite {
field: "node buffer length",
})?;
output.extend_from_slice(&node_buf);
let data_buf = data_buf.into_inner();
debug!("to_binary_internal => data_buf len: {0} (0x{0:x})", data_buf.len());
output.write_u32::<BigEndian>(data_buf.len() as u32).context(HeaderWrite { field: "data buffer length" })?;
output.extend_from_slice(&data_buf);
let data_buf = data_buf.into_inner();
debug!(
"to_binary_internal => data_buf len: {0} (0x{0:x})",
data_buf.len()
);
output
.write_u32::<BigEndian>(data_buf.len() as u32)
.context(HeaderWrite {
field: "data buffer length",
})?;
output.extend_from_slice(&data_buf);
Ok(output)
}
Ok(output)
}
}