mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-08 10:35:32 -05:00
lib: fully working kbin writing
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
#![feature(int_to_from_bytes)]
|
||||
|
||||
extern crate failure;
|
||||
extern crate kbinxml;
|
||||
extern crate minidom;
|
||||
extern crate pretty_env_logger;
|
||||
extern crate quick_xml;
|
||||
|
||||
@@ -9,22 +12,77 @@ use std::io::{Cursor, Error as IoError, ErrorKind as IoErrorKind, Read, Write, s
|
||||
|
||||
use failure::Fail;
|
||||
use kbinxml::KbinXml;
|
||||
use minidom::Element;
|
||||
use quick_xml::Writer;
|
||||
|
||||
fn display_err(err: impl Fail) -> IoError {
|
||||
let mut fail: &Fail = &err;
|
||||
eprintln!("e: {}", err);
|
||||
while let Some(cause) = fail.cause() {
|
||||
eprintln!("Cause: {}", cause);
|
||||
fail = cause;
|
||||
}
|
||||
|
||||
if let Some(backtrace) = err.cause().and_then(|cause| cause.backtrace()) {
|
||||
if let Some(backtrace) = err.backtrace() {
|
||||
eprintln!("{}", backtrace);
|
||||
}
|
||||
|
||||
IoError::new(IoErrorKind::Other, "Error parsing kbin")
|
||||
}
|
||||
|
||||
fn display_element(element: &Element) -> Result<(), IoError> {
|
||||
let inner = Cursor::new(Vec::new());
|
||||
let mut writer = Writer::new_with_indent(inner, b' ', 2);
|
||||
element.to_writer(&mut writer).map_err(|e| IoError::new(IoErrorKind::Other, format!("{:?}", e)))?;
|
||||
|
||||
let buf = writer.into_inner().into_inner();
|
||||
let stdout = stdout();
|
||||
stdout.lock().write_all(&buf)?;
|
||||
println!();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compare_slice(left: &[u8], right: &[u8]) {
|
||||
let mut buf = [0; 4];
|
||||
buf.clone_from_slice(&left[4..8]);
|
||||
let node_buf_length = u32::from_be(u32::from_bytes(buf));
|
||||
//println!("node_buf_length: {}", node_buf_length);
|
||||
|
||||
let data_buf_start = 8 + node_buf_length as usize;
|
||||
let data_buf_len_end = data_buf_start + 4;
|
||||
//println!("data_buf start: {} + 8 = {}", node_buf_length, data_buf_start);
|
||||
|
||||
buf.clone_from_slice(&left[data_buf_start..data_buf_len_end]);
|
||||
//let data_buf_length = u32::from_be(u32::from_bytes(buf));
|
||||
//println!("data_buf_length: {}", data_buf_length);
|
||||
|
||||
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 (i, _, _) = first;
|
||||
eprintln!(r#" left: `{:?}`
|
||||
right: `{:?}`"#, &left[*i..], &right[*i..]);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
pretty_env_logger::init();
|
||||
|
||||
@@ -37,18 +95,13 @@ fn main() -> std::io::Result<()> {
|
||||
|
||||
let element = KbinXml::from_binary(&contents).map_err(display_err)?;
|
||||
//println!("element: {:#?}", element);
|
||||
|
||||
let inner = Cursor::new(Vec::new());
|
||||
let mut writer = Writer::new_with_indent(inner, b' ', 2);
|
||||
element.to_writer(&mut writer).map_err(|e| IoError::new(IoErrorKind::Other, format!("{:?}", e)))?;
|
||||
|
||||
let buf = writer.into_inner().into_inner();
|
||||
let stdout = stdout();
|
||||
stdout.lock().write_all(&buf)?;
|
||||
println!();
|
||||
display_element(&element)?;
|
||||
|
||||
let buf = KbinXml::to_binary(&element).map_err(display_err)?;
|
||||
assert_eq!(buf, contents);
|
||||
compare_slice(&buf, &contents);
|
||||
|
||||
let element = KbinXml::from_binary(&buf).map_err(display_err)?;
|
||||
display_element(&element)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
|
||||
use encoding::{DecoderTrap, Encoding};
|
||||
use encoding::{DecoderTrap, EncoderTrap, Encoding};
|
||||
use encoding::all::{ASCII, EUC_JP, ISO_8859_1, WINDOWS_31J};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
@@ -46,7 +46,7 @@ impl EncodingType {
|
||||
/// crate. A `None` value indicates Rust's own UTF-8 handling should be used.
|
||||
pub fn decode_bytes(&self, input: Vec<u8>) -> Result<String, KbinError> {
|
||||
let decoder_fail = |e| {
|
||||
format_err!("{}", e).context(KbinErrorKind::EncodingDecode)
|
||||
format_err!("{}", e).context(KbinErrorKind::Encoding)
|
||||
};
|
||||
|
||||
let result = match *self {
|
||||
@@ -61,4 +61,29 @@ impl EncodingType {
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// 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>, KbinError> {
|
||||
let encoder_fail = |e| {
|
||||
format_err!("{}", e).context(KbinErrorKind::Encoding)
|
||||
};
|
||||
|
||||
let mut result = match *self {
|
||||
EncodingType::None |
|
||||
EncodingType::UTF_8 => input.as_bytes().to_vec(),
|
||||
|
||||
EncodingType::ASCII => ASCII.encode(input, EncoderTrap::Strict).map_err(encoder_fail)?,
|
||||
EncodingType::ISO_8859_1 => ISO_8859_1.encode(input, EncoderTrap::Strict).map_err(encoder_fail)?,
|
||||
EncodingType::EUC_JP => EUC_JP.encode(input, EncoderTrap::Strict).map_err(encoder_fail)?,
|
||||
EncodingType::SHIFT_JIS => WINDOWS_31J.encode(input, EncoderTrap::Strict).map_err(encoder_fail)?,
|
||||
};
|
||||
|
||||
// Add trailing null byte
|
||||
result.push(0);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
18
src/error.rs
18
src/error.rs
@@ -3,6 +3,8 @@ use std::string::FromUtf8Error;
|
||||
|
||||
use failure::{Backtrace, Context, Fail};
|
||||
|
||||
use node_types::KbinType;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct KbinError {
|
||||
inner: Context<KbinErrorKind>,
|
||||
@@ -43,9 +45,6 @@ pub enum KbinErrorKind {
|
||||
#[fail(display = "Unable to read encoding negation byte")]
|
||||
EncodingNegationRead,
|
||||
|
||||
#[fail(display = "Unknown encoding")]
|
||||
UnknownEncoding,
|
||||
|
||||
#[fail(display = "Unable to read len_node")]
|
||||
LenNodeRead,
|
||||
|
||||
@@ -79,17 +78,26 @@ pub enum KbinErrorKind {
|
||||
#[fail(display = "Unable to interpret string as UTF-8")]
|
||||
Utf8,
|
||||
|
||||
#[fail(display = "Unknown encoding")]
|
||||
UnknownEncoding,
|
||||
|
||||
#[fail(display = "Unable to interpret string as alternate encoding")]
|
||||
EncodingDecode,
|
||||
Encoding,
|
||||
|
||||
#[fail(display = "Unable to write {} header field", _0)]
|
||||
HeaderWrite(&'static str),
|
||||
|
||||
#[fail(display = "Unable to write a {} node", _0)]
|
||||
#[fail(display = "Unable to write a {}", _0)]
|
||||
DataWrite(&'static str),
|
||||
|
||||
#[fail(display = "Size Mismatch, type: {}, expected size: {}, actual size: {}", _0, _1, _2)]
|
||||
SizeMismatch(KbinType, usize, usize),
|
||||
|
||||
#[fail(display = "Unable to interpret input as {}", _0)]
|
||||
StringParse(&'static str),
|
||||
|
||||
#[fail(display = "Unable to convert from hexadecimal")]
|
||||
HexError,
|
||||
}
|
||||
|
||||
impl fmt::Display for KbinError {
|
||||
|
||||
195
src/lib.rs
195
src/lib.rs
@@ -36,6 +36,8 @@ const SIGNATURE: u8 = 0xA0;
|
||||
|
||||
const SIG_COMPRESSED: u8 = 0x42;
|
||||
|
||||
const ARRAY_MASK: u8 = 1 << 6; // 1 << 6 = 64
|
||||
|
||||
pub struct KbinXml {
|
||||
offset_1: u64,
|
||||
offset_2: u64,
|
||||
@@ -50,7 +52,7 @@ impl KbinXml {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn data_buf_offset(&self, data_buf: &Cursor<&[u8]>) -> u64 {
|
||||
fn data_buf_offset<T>(&self, data_buf: &Cursor<T>) -> u64 {
|
||||
// Position is not the index of the previously read byte, it is the current
|
||||
// index (offset).
|
||||
//
|
||||
@@ -61,15 +63,29 @@ impl KbinXml {
|
||||
|
||||
fn data_buf_read(&mut self, data_buf: &mut Cursor<&[u8]>) -> Result<Vec<u8>, KbinError> {
|
||||
let size = data_buf.read_u32::<BigEndian>().context(KbinErrorKind::DataReadSize)?;
|
||||
debug!("data_buf_read => index: {}, size: {}", data_buf.position(), size);
|
||||
|
||||
let mut data = vec![0; size as usize];
|
||||
data_buf.read_exact(&mut data).context(KbinErrorKind::DataRead)?;
|
||||
trace!("data_buf_read => size: {}, data: 0x{:02x?}", data.len(), data);
|
||||
trace!("data_buf_read => index: {}, size: {}, data: 0x{:02x?}", data_buf.position(), data.len(), data);
|
||||
|
||||
self.data_buf_realign_reads(data_buf, None)?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn data_buf_write(&mut self, data_buf: &mut Cursor<Vec<u8>>, data: &[u8]) -> Result<(), KbinError> {
|
||||
data_buf.write_u32::<BigEndian>(data.len() as u32).context(KbinErrorKind::DataWrite("data length integer"))?;
|
||||
debug!("data_buf_write => index: {}, size: {}", data_buf.position(), data.len());
|
||||
|
||||
data_buf.write_all(data).context(KbinErrorKind::DataWrite("data block"))?;
|
||||
trace!("data_buf_write => index: {}, size: {}, data: 0x{:02x?}", data_buf.position(), data.len(), data);
|
||||
|
||||
self.data_buf_realign_writes(data_buf, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn data_buf_read_str(&mut self, data_buf: &mut Cursor<&[u8]>, encoding: EncodingType) -> Result<String, KbinError> {
|
||||
let mut data = self.data_buf_read(data_buf)?;
|
||||
|
||||
@@ -85,6 +101,15 @@ impl KbinXml {
|
||||
encoding.decode_bytes(data)
|
||||
}
|
||||
|
||||
fn data_buf_write_str(&mut self, data_buf: &mut Cursor<Vec<u8>>, data: &str, encoding: EncodingType) -> Result<(), KbinError> {
|
||||
trace!("data_buf_write_str => input: {}", data);
|
||||
|
||||
let bytes = encoding.encode_bytes(data)?;
|
||||
self.data_buf_write(data_buf, &bytes)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn data_buf_get(&mut self, data_buf: &mut Cursor<&[u8]>, size: u32) -> Result<Vec<u8>, KbinError> {
|
||||
let mut data = vec![0; size as usize];
|
||||
data_buf.read_exact(&mut data).context(KbinErrorKind::DataRead)?;
|
||||
@@ -103,6 +128,7 @@ impl KbinXml {
|
||||
let old_pos = self.data_buf_offset(data_buf);
|
||||
let size = data_type.size * data_type.count;
|
||||
trace!("data_buf_get_aligned => old_pos: {}, size: {}", old_pos, size);
|
||||
|
||||
let (check_old, data) = match size {
|
||||
1 => {
|
||||
data_buf.seek(SeekFrom::Start(self.offset_1)).context(KbinErrorKind::Seek)?;
|
||||
@@ -145,19 +171,95 @@ impl KbinXml {
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn data_buf_realign_reads(&mut self, data_buf: &mut Cursor<&[u8]>, size: Option<u64>) -> Result<(), KbinError> {
|
||||
let size = size.unwrap_or(4);
|
||||
trace!("data_buf_realign => position: {}, size: {}", data_buf.position(), size);
|
||||
|
||||
while data_buf.position() % size > 0 {
|
||||
data_buf.seek(SeekFrom::Current(1)).context(KbinErrorKind::Seek)?;
|
||||
fn data_buf_write_aligned(&mut self, data_buf: &mut Cursor<Vec<u8>>, data_type: KbinType, data: &[u8]) -> Result<(), KbinError> {
|
||||
if self.offset_1 % 4 == 0 {
|
||||
self.offset_1 = self.data_buf_offset(data_buf);
|
||||
}
|
||||
if self.offset_2 % 4 == 0 {
|
||||
self.offset_2 = self.data_buf_offset(data_buf);
|
||||
}
|
||||
|
||||
let old_pos = self.data_buf_offset(data_buf);
|
||||
let size = (data_type.size as usize) * (data_type.count as usize);
|
||||
trace!("data_buf_write_aligned => old_pos: {}, size: {}", old_pos, size);
|
||||
|
||||
if size != data.len() {
|
||||
return Err(KbinErrorKind::SizeMismatch(data_type, size, data.len()).into());
|
||||
}
|
||||
|
||||
let check_old = match size {
|
||||
1 => {
|
||||
// Make room for new DWORD
|
||||
if self.offset_1 % 4 == 0 {
|
||||
data_buf.write_u32::<BigEndian>(0).context(KbinErrorKind::DataWrite("empty DWORD"))?;
|
||||
}
|
||||
|
||||
data_buf.seek(SeekFrom::Start(self.offset_1)).context(KbinErrorKind::Seek)?;
|
||||
data_buf.write_u8(data[0]).context(KbinErrorKind::DataWrite("1 byte value"))?;
|
||||
self.offset_1 += 1;
|
||||
|
||||
true
|
||||
},
|
||||
2 => {
|
||||
// Make room for new DWORD
|
||||
if self.offset_2 % 4 == 0 {
|
||||
data_buf.write_u32::<BigEndian>(0).context(KbinErrorKind::DataWrite("empty DWORD"))?;
|
||||
}
|
||||
|
||||
data_buf.seek(SeekFrom::Start(self.offset_2)).context(KbinErrorKind::Seek)?;
|
||||
data_buf.write_u8(data[0]).context(KbinErrorKind::DataWrite("first byte of 2 byte value"))?;
|
||||
data_buf.write_u8(data[1]).context(KbinErrorKind::DataWrite("second byte of 2 byte value"))?;
|
||||
self.offset_2 += 2;
|
||||
|
||||
true
|
||||
},
|
||||
_ => {
|
||||
data_buf.write_all(data).context(KbinErrorKind::DataWrite("large value"))?;
|
||||
self.data_buf_realign_writes(data_buf, None)?;
|
||||
|
||||
false
|
||||
},
|
||||
};
|
||||
|
||||
if check_old {
|
||||
data_buf.seek(SeekFrom::Start(old_pos)).context(KbinErrorKind::Seek)?;
|
||||
|
||||
let trailing = max(self.offset_1, self.offset_2);
|
||||
trace!("data_buf_write_aligned => old_pos: {}, trailing: {}", old_pos, trailing);
|
||||
if old_pos < trailing {
|
||||
data_buf.seek(SeekFrom::Start(trailing)).context(KbinErrorKind::Seek)?;
|
||||
self.data_buf_realign_writes(data_buf, None)?;
|
||||
}
|
||||
}
|
||||
trace!("data_buf_realign => realigned to: {}", data_buf.position());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn from_binary_internal(&mut self, input: &[u8]) -> Result<Element, KbinError> {
|
||||
fn data_buf_realign_reads(&self, data_buf: &mut Cursor<&[u8]>, size: Option<u64>) -> Result<(), KbinError> {
|
||||
let size = size.unwrap_or(4);
|
||||
trace!("data_buf_realign_reads => position: {}, size: {}", data_buf.position(), size);
|
||||
|
||||
while data_buf.position() % size > 0 {
|
||||
data_buf.seek(SeekFrom::Current(1)).context(KbinErrorKind::Seek)?;
|
||||
}
|
||||
trace!("data_buf_realign_reads => realigned to: {}", data_buf.position());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn data_buf_realign_writes(&self, data_buf: &mut Cursor<Vec<u8>>, size: Option<u64>) -> Result<(), KbinError> {
|
||||
let size = size.unwrap_or(4);
|
||||
trace!("data_buf_realign_writes => position: {}, size: {}", data_buf.position(), size);
|
||||
|
||||
while data_buf.position() % size > 0 {
|
||||
data_buf.write_u8(0).context(KbinErrorKind::Seek)?;
|
||||
}
|
||||
trace!("data_buf_realign_writes => realigned to: {}", data_buf.position());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn from_binary_internal(&mut self, stack: &mut Vec<Element>, input: &[u8]) -> Result<Element, KbinError> {
|
||||
// Node buffer starts from the beginning.
|
||||
// Data buffer starts later after reading `len_data`.
|
||||
let mut node_buf = Cursor::new(&input[..]);
|
||||
@@ -198,7 +300,6 @@ impl KbinXml {
|
||||
let len_data = data_buf.read_u32::<BigEndian>().context(KbinErrorKind::LenDataRead)?;
|
||||
info!("len_data: {} (0x{:x})", len_data, len_data);
|
||||
|
||||
let mut stack: Vec<Element> = Vec::new();
|
||||
{
|
||||
let node_buf_end = data_buf_start.into();
|
||||
while node_buf.position() < node_buf_end {
|
||||
@@ -316,9 +417,8 @@ impl KbinXml {
|
||||
Ok(stack.pop().expect("Stack must have root node"))
|
||||
}
|
||||
|
||||
fn write_node<W>(&mut self, node_buf: &mut W, data_buf: &mut W, input: &Element) -> Result<(), KbinError>
|
||||
where W: Write
|
||||
{
|
||||
fn write_node(&mut self, node_buf: &mut Cursor<Vec<u8>>, data_buf: &mut Cursor<Vec<u8>>, input: &Element) -> Result<(), KbinError> {
|
||||
let encoding = EncodingType::SHIFT_JIS;
|
||||
let text = input.text();
|
||||
let node_type = match input.attr("__type") {
|
||||
Some(name) => StandardType::from_name(name),
|
||||
@@ -333,16 +433,22 @@ impl KbinXml {
|
||||
|
||||
let (array_mask, count) = match input.attr("__count") {
|
||||
Some(count) => {
|
||||
let array_mask = 1 << 6;
|
||||
let count = count.parse::<i8>().context(KbinErrorKind::StringParse("array count"))?;
|
||||
(array_mask, count)
|
||||
debug!("write_node => __count = {}", count);
|
||||
(ARRAY_MASK, count)
|
||||
},
|
||||
None => {
|
||||
(0, 0)
|
||||
(0, 1)
|
||||
},
|
||||
};
|
||||
|
||||
println!("input name: {}", input.name());
|
||||
debug!("write_node => name: {}, type: {:?}, type_size: {}, type_count: {}, is_array: {}, size: {}",
|
||||
input.name(),
|
||||
node_type,
|
||||
node_type.size,
|
||||
node_type.count,
|
||||
array_mask,
|
||||
count);
|
||||
|
||||
node_buf.write_u8(node_type.id | array_mask).context(KbinErrorKind::DataWrite(node_type.name))?;
|
||||
pack_sixbit(node_buf, input.name())?;
|
||||
@@ -351,23 +457,54 @@ impl KbinXml {
|
||||
StandardType::NodeStart => {},
|
||||
|
||||
StandardType::Binary => {
|
||||
let bin = text.from_hex();
|
||||
println!("data: {:?}", bin);
|
||||
let data = text.from_hex().context(KbinErrorKind::HexError)?;
|
||||
trace!("data: 0x{:02x?}", data);
|
||||
|
||||
let size = (data.len() as u32) * (node_type.size as u32);
|
||||
data_buf.write_u32::<BigEndian>(size).context(KbinErrorKind::DataWrite("binary node size"))?;
|
||||
data_buf.write(&data).context(KbinErrorKind::DataWrite("binary"))?;
|
||||
self.data_buf_realign_writes(data_buf, None)?;
|
||||
},
|
||||
StandardType::String => {
|
||||
println!("str: {}", text);
|
||||
self.data_buf_write_str(data_buf, &text, encoding)?;
|
||||
},
|
||||
|
||||
_ => {
|
||||
let data = node_type.to_bytes(&text, count as usize)?;
|
||||
if array_mask > 0 {
|
||||
let total_size = (count as u32) * (node_type.count as u32) * (node_type.size as u32);
|
||||
trace!("write_node data_buf array => total_size: {}, data: 0x{:02x?}", total_size, data);
|
||||
|
||||
data_buf.write_u32::<BigEndian>(total_size).context(KbinErrorKind::DataWrite("node size"))?;
|
||||
data_buf.write_all(&data).context(KbinErrorKind::DataWrite(node_type.name))?;
|
||||
self.data_buf_realign_writes(data_buf, None)?;
|
||||
} else {
|
||||
self.data_buf_write_aligned(data_buf, *node_type, &data)?;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
for (key, value) in input.attrs() {
|
||||
match key {
|
||||
"__count" | "__size" | "__type" => continue,
|
||||
_ => {},
|
||||
};
|
||||
|
||||
trace!("write_node => attr: {}, value: {}", key, value);
|
||||
|
||||
self.data_buf_write_str(data_buf, value, encoding)?;
|
||||
|
||||
let node_type = StandardType::Attribute;
|
||||
node_buf.write_u8(node_type.id).context(KbinErrorKind::DataWrite(node_type.name))?;
|
||||
pack_sixbit(node_buf, key)?;
|
||||
}
|
||||
|
||||
for child in input.children() {
|
||||
self.write_node(node_buf, data_buf, child)?;
|
||||
}
|
||||
|
||||
// Always has the array bit set
|
||||
node_buf.write_u8(StandardType::NodeEnd.id | 64).context(KbinErrorKind::DataWrite("node end"))?;
|
||||
node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -386,15 +523,18 @@ impl KbinXml {
|
||||
|
||||
self.write_node(&mut node_buf, &mut data_buf, input)?;
|
||||
|
||||
node_buf.write_u8(StandardType::FileEnd.id | 64).context(KbinErrorKind::DataWrite("file end"))?;
|
||||
node_buf.write_u8(StandardType::FileEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("file end"))?;
|
||||
self.data_buf_realign_writes(&mut node_buf, None)?;
|
||||
|
||||
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(KbinErrorKind::HeaderWrite("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(KbinErrorKind::HeaderWrite("data buffer length"))?;
|
||||
output.extend_from_slice(&data_buf);
|
||||
|
||||
@@ -403,7 +543,14 @@ impl KbinXml {
|
||||
|
||||
pub fn from_binary(input: &[u8]) -> Result<Element, KbinError> {
|
||||
let mut kbinxml = KbinXml::new();
|
||||
kbinxml.from_binary_internal(input)
|
||||
let mut stack: Vec<Element> = Vec::new();
|
||||
|
||||
kbinxml.from_binary_internal(&mut stack, input).map_err(|e| {
|
||||
if let Some(first) = stack.first() {
|
||||
println!("{:?}", first);
|
||||
}
|
||||
e
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_binary(input: &Element) -> Result<Vec<u8>, KbinError> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::fmt::{self, Write};
|
||||
use std::ops::Deref;
|
||||
|
||||
use byteorder::WriteBytesExt;
|
||||
@@ -27,9 +27,9 @@ macro_rules! number_impl {
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<{}> to bytes => input: {}", stringify!($inner_type), input);
|
||||
|
||||
let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?;
|
||||
trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num);
|
||||
|
||||
let data = $inner_type::to_bytes($inner_type::to_be(num));
|
||||
output.extend_from_slice(&data);
|
||||
|
||||
@@ -55,9 +55,9 @@ macro_rules! number_impl {
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<{}> to bytes => input: {}", stringify!($inner_type), input);
|
||||
|
||||
let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?;
|
||||
trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num);
|
||||
|
||||
let data = $intermediate::to_bytes($intermediate::to_be(num.to_bits()));
|
||||
output.extend_from_slice(&data);
|
||||
|
||||
@@ -86,13 +86,13 @@ impl KbinWrapperType<bool> for bool {
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<bool> to bytes => input: {}", input);
|
||||
|
||||
let value = match input {
|
||||
"0" => 0x00,
|
||||
"1" => 0x01,
|
||||
v => panic!("Unsupported value for boolean: {}", v),
|
||||
};
|
||||
|
||||
trace!("KbinWrapperType<bool> to bytes => input: '{}', output: {}", input, value);
|
||||
output.write_u8(value).context(KbinErrorKind::DataWrite("bool"))?;
|
||||
|
||||
Ok(())
|
||||
@@ -102,7 +102,7 @@ impl KbinWrapperType<bool> for bool {
|
||||
struct Ip4;
|
||||
impl KbinWrapperType<Ip4> for Ip4 {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<Ip4> => input: {:02x?}", input);
|
||||
trace!("KbinWrapperType<Ip4> from bytes => input: {:02x?}", input);
|
||||
|
||||
if input.len() != 4 {
|
||||
panic!("Ip4 type requires exactly 4 bytes of data, input: {:02x?}", input);
|
||||
@@ -115,7 +115,7 @@ impl KbinWrapperType<Ip4> for Ip4 {
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<Ip4> => self: Ip4 (needs implementation!)");
|
||||
trace!("KbinWrapperType<Ip4> to bytes => input: '{}'", input);
|
||||
|
||||
for part in input.split('.') {
|
||||
let num = part.parse::<u8>().context(KbinErrorKind::StringParse("ip4 segment"))?;
|
||||
@@ -158,13 +158,18 @@ impl KbinType {
|
||||
{
|
||||
let size = self.size as usize;
|
||||
let count = self.count as usize;
|
||||
let total_nodes = count * arr_count;
|
||||
|
||||
let total_size = size * total_nodes;
|
||||
if total_size != input.len() {
|
||||
return Err(KbinErrorKind::SizeMismatch(*self, total_size, input.len()).into());
|
||||
}
|
||||
|
||||
{
|
||||
let first = &input[..size];
|
||||
T::from_kbin_bytes(output, first)?;
|
||||
}
|
||||
|
||||
let total_nodes = count * arr_count;
|
||||
for i in 1..total_nodes {
|
||||
let offset = i * size;
|
||||
let end = (i + 1) * size;
|
||||
@@ -209,30 +214,47 @@ impl KbinType {
|
||||
fn to_array<T>(&self, output: &mut Vec<u8>, input: &str, arr_count: usize) -> Result<(), KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
for part in input.split(' ') {
|
||||
T::to_kbin_bytes(output, part)?;
|
||||
}
|
||||
|
||||
let type_size = (self.size as usize) * (self.count as usize);
|
||||
let total_size = arr_count * type_size;
|
||||
if total_size != output.len() {
|
||||
return Err(KbinErrorKind::SizeMismatch(*self, total_size, output.len()).into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn to_bytes_inner<T>(&self, data_buf: &mut Vec<u8>, input: &str, arr_count: usize) -> Result<(), KbinError>
|
||||
fn to_bytes_inner<T>(&self, input: &str, arr_count: usize) -> Result<Vec<u8>, KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
debug!("to_bytes_inner({}) => size: {}, count: {}, input_len: {}, arr_count: {}", self.name, self.size, self.count, input.len(), arr_count);
|
||||
|
||||
let mut output = Vec::new();
|
||||
|
||||
if self.count == -1 {
|
||||
panic!("Tried to write special type: {}", self.name);
|
||||
} else if self.count == 1 {
|
||||
// May have a node (i.e. Ip4) that is only a single count, but it
|
||||
// can be part of an array
|
||||
if arr_count == 1 {
|
||||
T::to_kbin_bytes(data_buf, input)?;
|
||||
T::to_kbin_bytes(&mut output, input)?;
|
||||
} else {
|
||||
self.to_array::<T>(data_buf, input, arr_count)?;
|
||||
self.to_array::<T>(&mut output, input, arr_count)?;
|
||||
}
|
||||
} else if self.count > 1 {
|
||||
self.to_array::<T>(data_buf, input, arr_count)?;
|
||||
self.to_array::<T>(&mut output, input, arr_count)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for KbinType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,11 +308,10 @@ macro_rules! construct_types {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn to_bytes(&self, output: &mut Vec<u8>, input: &str, arr_count: usize) -> Result<(), KbinError> {
|
||||
pub fn to_bytes(&self, input: &str, arr_count: usize) -> Result<Vec<u8>, KbinError> {
|
||||
match *self {
|
||||
$(
|
||||
StandardType::$konst => self.to_bytes_inner::<$inner_type>(output, input, arr_count),
|
||||
StandardType::$konst => self.to_bytes_inner::<$inner_type>(input, arr_count),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user