mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-07 18:15:22 -05:00
cargo: rustfmt
This commit is contained in:
4
rustfmt.toml
Normal file
4
rustfmt.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
binop_separator = "Back"
|
||||
edition = "2018"
|
||||
match_block_trailing_comma = true
|
||||
overflow_delimited_expr = true
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
258
src/error.rs
258
src/error.rs
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
67
src/lib.rs
67
src/lib.rs
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
593
src/node/mod.rs
593
src/node/mod.rs
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
360
src/reader.rs
360
src/reader.rs
@@ -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
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
249
src/sixbit.rs
249
src/sixbit.rs
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
386
src/value/mod.rs
386
src/value/mod.rs
@@ -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! {
|
||||
|
||||
452
src/writer.rs
452
src/writer.rs
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user