mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-08 10:35:32 -05:00
lib: begin work on encoding
This commit is contained in:
@@ -13,3 +13,4 @@ minidom = "0.9.0"
|
||||
num = "0.1.42"
|
||||
pretty_env_logger = "0.2.3"
|
||||
quick-xml = "0.12.1"
|
||||
rustc-hex = "1.0.0"
|
||||
|
||||
@@ -46,6 +46,9 @@ fn main() -> std::io::Result<()> {
|
||||
let stdout = stdout();
|
||||
stdout.lock().write_all(&buf)?;
|
||||
println!();
|
||||
|
||||
let buf = KbinXml::to_binary(&element).map_err(display_err)?;
|
||||
assert_eq!(buf, contents);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -15,18 +15,6 @@ pub enum EncodingType {
|
||||
}
|
||||
|
||||
impl EncodingType {
|
||||
#[allow(dead_code)]
|
||||
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 from_byte(byte: u8) -> Result<Self, KbinError> {
|
||||
let val = match byte {
|
||||
0x00 => EncodingType::None,
|
||||
@@ -41,6 +29,17 @@ impl EncodingType {
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// Decode bytes using the encoding definition from the `encoding` crate.
|
||||
///
|
||||
/// A `Some` value indicates an encoding should be used from the `encoding`
|
||||
|
||||
15
src/error.rs
15
src/error.rs
@@ -70,11 +70,26 @@ pub enum KbinErrorKind {
|
||||
#[fail(display = "Unable to read sixbit string content")]
|
||||
SixbitRead,
|
||||
|
||||
#[fail(display = "Unable to write sixbit string length")]
|
||||
SixbitLengthWrite,
|
||||
|
||||
#[fail(display = "Unable to write sixbit string content")]
|
||||
SixbitWrite,
|
||||
|
||||
#[fail(display = "Unable to interpret string as UTF-8")]
|
||||
Utf8,
|
||||
|
||||
#[fail(display = "Unable to interpret string as alternate encoding")]
|
||||
EncodingDecode,
|
||||
|
||||
#[fail(display = "Unable to write {} header field", _0)]
|
||||
HeaderWrite(&'static str),
|
||||
|
||||
#[fail(display = "Unable to write a {} node", _0)]
|
||||
DataWrite(&'static str),
|
||||
|
||||
#[fail(display = "Unable to interpret input as {}", _0)]
|
||||
StringParse(&'static str),
|
||||
}
|
||||
|
||||
impl fmt::Display for KbinError {
|
||||
|
||||
142
src/lib.rs
142
src/lib.rs
@@ -4,16 +4,17 @@ extern crate byteorder;
|
||||
extern crate encoding;
|
||||
extern crate minidom;
|
||||
extern crate num;
|
||||
extern crate rustc_hex;
|
||||
|
||||
#[macro_use] extern crate failure;
|
||||
#[macro_use] extern crate lazy_static;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
use std::cmp::max;
|
||||
use std::fmt::Write;
|
||||
use std::io::{Cursor, Read, Seek, SeekFrom};
|
||||
use std::fmt::Write as FmtWrite;
|
||||
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use failure::ResultExt;
|
||||
use minidom::Element;
|
||||
|
||||
@@ -25,8 +26,9 @@ mod sixbit;
|
||||
|
||||
use compression::Compression;
|
||||
use encoding_type::EncodingType;
|
||||
use node_types::KbinType;
|
||||
use sixbit::unpack_sixbit;
|
||||
use node_types::{KbinType, StandardType};
|
||||
use sixbit::{pack_sixbit, unpack_sixbit};
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
pub use error::{KbinError, KbinErrorKind};
|
||||
|
||||
@@ -63,7 +65,7 @@ impl KbinXml {
|
||||
data_buf.read_exact(&mut data).context(KbinErrorKind::DataRead)?;
|
||||
trace!("data_buf_read => size: {}, data: 0x{:02x?}", data.len(), data);
|
||||
|
||||
self.data_buf_realign(data_buf, None)?;
|
||||
self.data_buf_realign_reads(data_buf, None)?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
@@ -99,7 +101,7 @@ impl KbinXml {
|
||||
}
|
||||
|
||||
let old_pos = self.data_buf_offset(data_buf);
|
||||
let size = data_type.size() * data_type.count();
|
||||
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 => {
|
||||
@@ -122,7 +124,7 @@ impl KbinXml {
|
||||
size => {
|
||||
let mut data = vec![0; size as usize];
|
||||
data_buf.read_exact(&mut data).context(KbinErrorKind::DataReadAligned)?;
|
||||
self.data_buf_realign(data_buf, None)?;
|
||||
self.data_buf_realign_reads(data_buf, None)?;
|
||||
|
||||
(false, data)
|
||||
},
|
||||
@@ -136,14 +138,14 @@ impl KbinXml {
|
||||
trace!("data_buf_get_aligned => old_pos: {}, trailing: {}", old_pos, trailing);
|
||||
if old_pos < trailing {
|
||||
data_buf.seek(SeekFrom::Start(trailing)).context(KbinErrorKind::Seek)?;
|
||||
self.data_buf_realign(data_buf, None)?;
|
||||
self.data_buf_realign_reads(data_buf, None)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn data_buf_realign(&mut self, data_buf: &mut Cursor<&[u8]>, size: Option<u64>) -> Result<(), KbinError> {
|
||||
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);
|
||||
|
||||
@@ -204,11 +206,11 @@ impl KbinXml {
|
||||
let is_array = raw_node_type & 64 == 64;
|
||||
let node_type = raw_node_type & !64;
|
||||
|
||||
let xml_type = KbinType::from_u8(node_type);
|
||||
let xml_type = StandardType::from_u8(node_type);
|
||||
debug!("raw_node_type: {}, node_type: {:?} ({}), is_array: {}", raw_node_type, xml_type, node_type, is_array);
|
||||
|
||||
match xml_type {
|
||||
KbinType::NodeEnd | KbinType::FileEnd => {
|
||||
StandardType::NodeEnd | StandardType::FileEnd => {
|
||||
if stack.len() > 1 {
|
||||
let node = stack.pop().expect("Stack must have last node");
|
||||
if let Some(to) = stack.last_mut() {
|
||||
@@ -216,9 +218,9 @@ impl KbinXml {
|
||||
}
|
||||
}
|
||||
|
||||
if xml_type == KbinType::NodeEnd {
|
||||
if xml_type == StandardType::NodeEnd {
|
||||
continue;
|
||||
} else if xml_type == KbinType::FileEnd {
|
||||
} else if xml_type == StandardType::FileEnd {
|
||||
break;
|
||||
}
|
||||
},
|
||||
@@ -227,15 +229,15 @@ impl KbinXml {
|
||||
|
||||
let name = unpack_sixbit(&mut node_buf)?;
|
||||
|
||||
if xml_type == KbinType::NodeStart {
|
||||
if xml_type == StandardType::NodeStart {
|
||||
stack.push(Element::bare(name));
|
||||
} else {
|
||||
if xml_type != KbinType::Attribute {
|
||||
if xml_type != StandardType::Attribute {
|
||||
stack.push(Element::bare(name.clone()));
|
||||
}
|
||||
if let Some(to) = stack.last_mut() {
|
||||
match xml_type {
|
||||
KbinType::Attribute => {
|
||||
StandardType::Attribute => {
|
||||
let val = self.data_buf_read_str(&mut data_buf, encoding)?;
|
||||
debug!("attr name: {}, val: {}", name, val);
|
||||
to.set_attr(name, val);
|
||||
@@ -244,18 +246,18 @@ impl KbinXml {
|
||||
//
|
||||
// Handle String nodes separately to use the string reading logic
|
||||
// which automatically removes trailing null bytes.
|
||||
KbinType::String => {
|
||||
to.set_attr("__type", xml_type.name());
|
||||
StandardType::String => {
|
||||
to.set_attr("__type", xml_type.name);
|
||||
|
||||
let val = self.data_buf_read_str(&mut data_buf, encoding)?;
|
||||
debug!("name: {}, val: {}", name, val);
|
||||
to.append_text_node(val);
|
||||
},
|
||||
_ => {
|
||||
to.set_attr("__type", xml_type.name());
|
||||
to.set_attr("__type", xml_type.name);
|
||||
|
||||
let type_size = xml_type.size();
|
||||
let type_count = xml_type.count();
|
||||
let type_size = xml_type.size;
|
||||
let type_count = xml_type.count;
|
||||
let (is_array, size) = if type_count == -1 {
|
||||
(true, data_buf.read_u32::<BigEndian>().context(KbinErrorKind::BinaryLengthRead)?)
|
||||
} else if is_array {
|
||||
@@ -278,15 +280,15 @@ impl KbinXml {
|
||||
|
||||
let data = if is_array {
|
||||
let data = self.data_buf_get(&mut data_buf, size)?;
|
||||
self.data_buf_realign(&mut data_buf, None)?;
|
||||
self.data_buf_realign_reads(&mut data_buf, None)?;
|
||||
|
||||
data
|
||||
} else {
|
||||
self.data_buf_get_aligned(&mut data_buf, xml_type)?
|
||||
self.data_buf_get_aligned(&mut data_buf, *xml_type)?
|
||||
};
|
||||
|
||||
debug!("data: 0x{:02x?}", data);
|
||||
if xml_type == KbinType::Binary {
|
||||
if xml_type == StandardType::Binary {
|
||||
to.set_attr("__size", data.len());
|
||||
|
||||
let len = data.len() * 2;
|
||||
@@ -314,8 +316,98 @@ 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
|
||||
{
|
||||
let text = input.text();
|
||||
let node_type = match input.attr("__type") {
|
||||
Some(name) => StandardType::from_name(name),
|
||||
None => {
|
||||
if text.len() == 0 {
|
||||
StandardType::NodeStart
|
||||
} else {
|
||||
StandardType::String
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
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)
|
||||
},
|
||||
None => {
|
||||
(0, 0)
|
||||
},
|
||||
};
|
||||
|
||||
println!("input name: {}", input.name());
|
||||
|
||||
node_buf.write_u8(node_type.id | array_mask).context(KbinErrorKind::DataWrite(node_type.name))?;
|
||||
pack_sixbit(node_buf, input.name())?;
|
||||
|
||||
match node_type {
|
||||
StandardType::NodeStart => {},
|
||||
|
||||
StandardType::Binary => {
|
||||
let bin = text.from_hex();
|
||||
println!("data: {:?}", bin);
|
||||
},
|
||||
StandardType::String => {
|
||||
println!("str: {}", text);
|
||||
},
|
||||
|
||||
_ => {
|
||||
},
|
||||
}
|
||||
|
||||
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"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_binary_internal(&mut self, input: &Element) -> Result<Vec<u8>, KbinError> {
|
||||
let mut header = Cursor::new(Vec::with_capacity(8));
|
||||
header.write_u8(SIGNATURE).context(KbinErrorKind::HeaderWrite("signature"))?;
|
||||
header.write_u8(SIG_COMPRESSED).context(KbinErrorKind::HeaderWrite("compression"))?;
|
||||
|
||||
let encoding = EncodingType::SHIFT_JIS.to_byte();
|
||||
header.write_u8(encoding).context(KbinErrorKind::HeaderWrite("encoding"))?;
|
||||
header.write_u8(0xFF ^ encoding).context(KbinErrorKind::HeaderWrite("encoding negation"))?;
|
||||
|
||||
let mut node_buf = Cursor::new(Vec::new());
|
||||
let mut data_buf = Cursor::new(Vec::new());
|
||||
|
||||
self.write_node(&mut node_buf, &mut data_buf, input)?;
|
||||
|
||||
node_buf.write_u8(StandardType::FileEnd.id | 64).context(KbinErrorKind::DataWrite("file end"))?;
|
||||
|
||||
let mut output = header.into_inner();
|
||||
|
||||
let node_buf = node_buf.into_inner();
|
||||
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();
|
||||
output.write_u32::<BigEndian>(data_buf.len() as u32).context(KbinErrorKind::HeaderWrite("data buffer length"))?;
|
||||
output.extend_from_slice(&data_buf);
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn from_binary(input: &[u8]) -> Result<Element, KbinError> {
|
||||
let mut kbinxml = KbinXml::new();
|
||||
kbinxml.from_binary_internal(input)
|
||||
}
|
||||
|
||||
pub fn to_binary(input: &Element) -> Result<Vec<u8>, KbinError> {
|
||||
let mut kbinxml = KbinXml::new();
|
||||
kbinxml.to_binary_internal(input)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::ops::Deref;
|
||||
|
||||
use byteorder::WriteBytesExt;
|
||||
use failure::ResultExt;
|
||||
|
||||
trait KbinWrapperType<T> {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError>;
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError>;
|
||||
}
|
||||
|
||||
macro_rules! number_impl {
|
||||
@@ -13,7 +16,7 @@ macro_rules! number_impl {
|
||||
$(
|
||||
impl KbinWrapperType<$inner_type> for $inner_type {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<{}> => input: {:02x?}", stringify!($inner_type), input);
|
||||
trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input);
|
||||
|
||||
let mut data = [0; ::std::mem::size_of::<$inner_type>()];
|
||||
data.clone_from_slice(input);
|
||||
@@ -22,6 +25,16 @@ macro_rules! number_impl {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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)))?;
|
||||
let data = $inner_type::to_bytes($inner_type::to_be(num));
|
||||
output.extend_from_slice(&data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
@@ -29,7 +42,7 @@ macro_rules! number_impl {
|
||||
$(
|
||||
impl KbinWrapperType<$inner_type> for $inner_type {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<{}> => input: {:02x?}", stringify!($inner_type), input);
|
||||
trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input);
|
||||
|
||||
let mut data = [0; ::std::mem::size_of::<$inner_type>()];
|
||||
data.clone_from_slice(input);
|
||||
@@ -40,6 +53,16 @@ macro_rules! number_impl {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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)))?;
|
||||
let data = $intermediate::to_bytes($intermediate::to_be(num.to_bits()));
|
||||
output.extend_from_slice(&data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
@@ -50,7 +73,7 @@ number_impl!(float; u32 => f32, u64 => f64);
|
||||
|
||||
impl KbinWrapperType<bool> for bool {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<bool> => input: {:02x?}", input);
|
||||
trace!("KbinWrapperType<bool> from bytes => input: {:02x?}", input);
|
||||
|
||||
let value = match input[0] {
|
||||
0x00 => "0",
|
||||
@@ -61,6 +84,19 @@ impl KbinWrapperType<bool> for bool {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
output.write_u8(value).context(KbinErrorKind::DataWrite("bool"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct Ip4;
|
||||
@@ -68,8 +104,8 @@ impl KbinWrapperType<Ip4> for Ip4 {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<Ip4> => input: {:02x?}", input);
|
||||
|
||||
if input.len() < 4 {
|
||||
panic!("Ip4 type requires 4 bytes of data, input: {:02x?}", input);
|
||||
if input.len() != 4 {
|
||||
panic!("Ip4 type requires exactly 4 bytes of data, input: {:02x?}", input);
|
||||
}
|
||||
|
||||
write!(output, "{}.{}.{}.{}", input[0], input[1], input[2], input[3])
|
||||
@@ -77,11 +113,23 @@ impl KbinWrapperType<Ip4> for Ip4 {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<Ip4> => self: Ip4 (needs implementation!)");
|
||||
|
||||
for part in input.split('.') {
|
||||
let num = part.parse::<u8>().context(KbinErrorKind::StringParse("ip4 segment"))?;
|
||||
output.write_u8(num).context(KbinErrorKind::DataWrite("ip4"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyConverter;
|
||||
impl KbinWrapperType<DummyConverter> for DummyConverter {
|
||||
fn from_kbin_bytes(_output: &mut String, _input: &[u8]) -> Result<(), KbinError> { Ok(()) }
|
||||
fn to_kbin_bytes(_output: &mut Vec<u8>, _input: &str) -> Result<(), KbinError> { Ok(()) }
|
||||
}
|
||||
|
||||
struct InvalidConverter;
|
||||
@@ -89,118 +137,172 @@ impl KbinWrapperType<InvalidConverter> for InvalidConverter {
|
||||
fn from_kbin_bytes(_output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
panic!("Invalid kbin type converter called for input: {:02x?}", input);
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(_output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
panic!("Invalid kbin type converter called for input: {}", input);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct KbinType {
|
||||
pub id: u8,
|
||||
pub name: &'static str,
|
||||
pub alt_name: Option<&'static str>,
|
||||
pub size: i8,
|
||||
pub count: i8
|
||||
}
|
||||
|
||||
impl KbinType {
|
||||
fn parse_array<T>(&self, output: &mut String, input: &[u8], arr_count: usize) -> Result<(), KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
let size = self.size as usize;
|
||||
let count = self.count as usize;
|
||||
|
||||
{
|
||||
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;
|
||||
let data = &input[offset..end];
|
||||
output.push(' ');
|
||||
T::from_kbin_bytes(output, data)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_bytes_inner<T>(&self, input: &[u8]) -> Result<String, KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
let type_size = (self.size as usize) * (self.count as usize);
|
||||
let arr_count = input.len() / type_size;
|
||||
debug!("parse_bytes({}) => size: {}, count: {}, input_len: {}, arr_count: {}", self.name, self.size, self.count, input.len(), arr_count);
|
||||
|
||||
let mut result = String::new();
|
||||
|
||||
if self.count == -1 {
|
||||
panic!("Tried to parse special type: {}", self.name);
|
||||
} else if self.count == 0 {
|
||||
// Do nothing
|
||||
} 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::from_kbin_bytes(&mut result, input)?;
|
||||
} else {
|
||||
self.parse_array::<T>(&mut result, input, arr_count)?;
|
||||
}
|
||||
} else if self.count > 1 {
|
||||
self.parse_array::<T>(&mut result, input, arr_count)?;
|
||||
} else {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn to_array<T>(&self, output: &mut Vec<u8>, input: &str, arr_count: usize) -> Result<(), KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn to_bytes_inner<T>(&self, data_buf: &mut Vec<u8>, input: &str, arr_count: usize) -> Result<(), 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);
|
||||
|
||||
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)?;
|
||||
} else {
|
||||
self.to_array::<T>(data_buf, input, arr_count)?;
|
||||
}
|
||||
} else if self.count > 1 {
|
||||
self.to_array::<T>(data_buf, input, arr_count)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! construct_types {
|
||||
(
|
||||
$(
|
||||
($id:expr, $konst:ident, $name:expr, $alt_name:expr, $size:expr, $count:expr, $inner_type:ident);
|
||||
($id:expr, $upcase:ident, $konst:ident, $name:expr, $alt_name:expr, $size:expr, $count:expr, $inner_type:ident);
|
||||
)+
|
||||
) => {
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum KbinType {
|
||||
pub enum StandardType {
|
||||
$(
|
||||
$konst,
|
||||
)+
|
||||
}
|
||||
|
||||
impl KbinType {
|
||||
pub fn from_u8(input: u8) -> KbinType {
|
||||
$(
|
||||
pub const $upcase: KbinType = KbinType {
|
||||
id: $id,
|
||||
name: $name,
|
||||
alt_name: $alt_name,
|
||||
size: $size,
|
||||
count: $count,
|
||||
};
|
||||
)+
|
||||
|
||||
impl StandardType {
|
||||
pub fn from_u8(input: u8) -> StandardType {
|
||||
match input {
|
||||
$(
|
||||
$id => KbinType::$konst,
|
||||
$id => StandardType::$konst,
|
||||
)+
|
||||
_ => panic!("Node type {} not implemented", input),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &'static str {
|
||||
match *self {
|
||||
pub fn from_name(input: &str) -> StandardType {
|
||||
match input {
|
||||
$(
|
||||
KbinType::$konst => $name,
|
||||
$name => StandardType::$konst,
|
||||
)+
|
||||
_ => panic!("Node name {} not implemented", input),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn alt_name(&self) -> Option<&'static str> {
|
||||
match *self {
|
||||
$(
|
||||
KbinType::$konst => $alt_name,
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> i8 {
|
||||
match *self {
|
||||
$(
|
||||
KbinType::$konst => $size,
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(&self) -> i8 {
|
||||
match *self {
|
||||
$(
|
||||
KbinType::$konst => $count,
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_array<T>(output: &mut String, input: &[u8], size: usize, count: usize, arr_count: usize) -> Result<(), KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
{
|
||||
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;
|
||||
let data = &input[offset..end];
|
||||
output.push(' ');
|
||||
T::from_kbin_bytes(output, data)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_bytes_inner<T>(&self, input: &[u8], name: &str, size: u8, count: i8) -> Result<String, KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
let type_size = (size as usize) * (count as usize);
|
||||
let arr_count = input.len() / type_size;
|
||||
debug!("parse_bytes({}) => size: {}, count: {}, input_len: {}, arr_count: {}", name, size, count, input.len(), arr_count);
|
||||
|
||||
let mut result = String::new();
|
||||
|
||||
if count == -1 {
|
||||
panic!("Tried to parse special type: {}", self.name());
|
||||
} else if count == 0 {
|
||||
// Do nothing
|
||||
} else if 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::from_kbin_bytes(&mut result, input)?;
|
||||
} else {
|
||||
Self::parse_array::<T>(&mut result, input, size as usize, count as usize, arr_count)?;
|
||||
}
|
||||
} else if count > 1 {
|
||||
Self::parse_array::<T>(&mut result, input, size as usize, count as usize, arr_count)?;
|
||||
} else {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn parse_bytes(&self, input: &[u8]) -> Result<String, KbinError> {
|
||||
match *self {
|
||||
$(
|
||||
KbinType::$konst => self.parse_bytes_inner::<$inner_type>(input, $name, $size, $count),
|
||||
StandardType::$konst => self.parse_bytes_inner::<$inner_type>(input),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn to_bytes(&self, output: &mut Vec<u8>, input: &str, arr_count: usize) -> Result<(), KbinError> {
|
||||
match *self {
|
||||
$(
|
||||
StandardType::$konst => self.to_bytes_inner::<$inner_type>(output, input, arr_count),
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for StandardType {
|
||||
type Target = KbinType;
|
||||
|
||||
fn deref(&self) -> &KbinType {
|
||||
match *self {
|
||||
$(
|
||||
StandardType::$konst => &$upcase,
|
||||
)+
|
||||
}
|
||||
}
|
||||
@@ -209,65 +311,65 @@ macro_rules! construct_types {
|
||||
}
|
||||
|
||||
construct_types! {
|
||||
( 2, S8, "s8", None, 1, 1, i8);
|
||||
( 3, U8, "u8", None, 1, 1, u8);
|
||||
( 4, S16, "s16", None, 2, 1, i16);
|
||||
( 5, U16, "u16", None, 2, 1, u16);
|
||||
( 6, S32, "s32", None, 4, 1, i32);
|
||||
( 7, U32, "u32", None, 4, 1, u32);
|
||||
( 8, S64, "s64", None, 8, 1, i64);
|
||||
( 9, U64, "u64", None, 8, 1, u64);
|
||||
(10, Binary, "bin", Some("binary"), 1, -1, DummyConverter);
|
||||
(11, String, "str", Some("string"), 1, -1, DummyConverter);
|
||||
(12, Ip4, "ip4", None, 4, 1, Ip4); // Using size of 4 rather than count of 4
|
||||
(13, Time, "time", None, 4, 1, u32);
|
||||
(14, Float, "float", Some("f"), 4, 1, f32);
|
||||
(15, Double, "double", Some("d"), 8, 1, f64);
|
||||
(16, S8_2, "2s8", None, 1, 2, i8);
|
||||
(17, U8_2, "2u8", None, 1, 2, u8);
|
||||
(18, S16_2, "2s16", None, 2, 2, i16);
|
||||
(19, U16_2, "2u16", None, 2, 2, u16);
|
||||
(20, S32_2, "2s32", None, 4, 2, i32);
|
||||
(21, U32_2, "2u32", None, 4, 2, u32);
|
||||
(22, S64_2, "2s64", Some("vs64"), 8, 2, i64);
|
||||
(23, U64_2, "2u64", Some("vu64"), 8, 2, u64);
|
||||
(24, Float2, "2f", None, 4, 2, f32);
|
||||
(25, Double2, "2d", Some("vd"), 8, 2, f64);
|
||||
(26, S8_3, "3s8", None, 1, 3, i8);
|
||||
(27, U8_3, "3u8", None, 1, 3, u8);
|
||||
(28, S16_3, "3s16", None, 2, 3, i16);
|
||||
(29, U16_3, "3u16", None, 2, 3, u16);
|
||||
(30, S32_3, "3s32", None, 4, 3, i32);
|
||||
(31, U32_3, "3u32", None, 4, 3, u32);
|
||||
(32, S64_3, "3s64", None, 8, 3, i64);
|
||||
(33, U64_3, "3u64", None, 8, 3, u64);
|
||||
(34, Float3, "3f", None, 4, 3, f32);
|
||||
(35, Double3, "3d", None, 8, 3, f64);
|
||||
(36, S8_4, "4s8", None, 1, 4, i8);
|
||||
(37, U8_4, "4u8", None, 1, 4, u8);
|
||||
(38, S16_4, "4s16", None, 2, 4, i16);
|
||||
(39, U16_4, "4u16", None, 2, 4, u16);
|
||||
(40, S32_4, "4s32", Some("vs32"), 4, 4, i32);
|
||||
(41, U32_4, "4u32", Some("vu32"), 4, 4, u32);
|
||||
(42, S64_4, "4s64", None, 8, 4, i64);
|
||||
(43, U64_4, "4u64", None, 8, 4, u64);
|
||||
(44, Float4, "4f", Some("vf"), 4, 4, f32);
|
||||
(45, Double4, "4d", None, 8, 4, f64);
|
||||
( 2, S8, S8, "s8", None, 1, 1, i8);
|
||||
( 3, U8, U8, "u8", None, 1, 1, u8);
|
||||
( 4, S16, S16, "s16", None, 2, 1, i16);
|
||||
( 5, U16, U16, "u16", None, 2, 1, u16);
|
||||
( 6, S32, S32, "s32", None, 4, 1, i32);
|
||||
( 7, U32, U32, "u32", None, 4, 1, u32);
|
||||
( 8, S64, S64, "s64", None, 8, 1, i64);
|
||||
( 9, U64, U64, "u64", None, 8, 1, u64);
|
||||
(10, BINARY, Binary, "bin", Some("binary"), 1, -1, DummyConverter);
|
||||
(11, STRING, String, "str", Some("string"), 1, -1, DummyConverter);
|
||||
(12, IP4, Ip4, "ip4", None, 4, 1, Ip4); // Using size of 4 rather than count of 4
|
||||
(13, TIME, Time, "time", None, 4, 1, u32);
|
||||
(14, FLOAT, Float, "float", Some("f"), 4, 1, f32);
|
||||
(15, DOUBLE, Double, "double", Some("d"), 8, 1, f64);
|
||||
(16, S8_2, S8_2, "2s8", None, 1, 2, i8);
|
||||
(17, U8_2, U8_2, "2u8", None, 1, 2, u8);
|
||||
(18, S16_2, S16_2, "2s16", None, 2, 2, i16);
|
||||
(19, U16_2, U16_2, "2u16", None, 2, 2, u16);
|
||||
(20, S32_2, S32_2, "2s32", None, 4, 2, i32);
|
||||
(21, U32_2, U32_2, "2u32", None, 4, 2, u32);
|
||||
(22, S64_2, S64_2, "2s64", Some("vs64"), 8, 2, i64);
|
||||
(23, U64_2, U64_2, "2u64", Some("vu64"), 8, 2, u64);
|
||||
(24, FLOAT_2, Float2, "2f", None, 4, 2, f32);
|
||||
(25, DOUBLE_2, Double2, "2d", Some("vd"), 8, 2, f64);
|
||||
(26, S8_3, S8_3, "3s8", None, 1, 3, i8);
|
||||
(27, U8_3, U8_3, "3u8", None, 1, 3, u8);
|
||||
(28, S16_3, S16_3, "3s16", None, 2, 3, i16);
|
||||
(29, U16_3, U16_3, "3u16", None, 2, 3, u16);
|
||||
(30, S32_3, S32_3, "3s32", None, 4, 3, i32);
|
||||
(31, U32_3, U32_3, "3u32", None, 4, 3, u32);
|
||||
(32, S64_3, S64_3, "3s64", None, 8, 3, i64);
|
||||
(33, U64_3, U64_3, "3u64", None, 8, 3, u64);
|
||||
(34, FLOAT_3, Float3, "3f", None, 4, 3, f32);
|
||||
(35, DOUBLE_3, Double3, "3d", None, 8, 3, f64);
|
||||
(36, S8_4, S8_4, "4s8", None, 1, 4, i8);
|
||||
(37, U8_4, U8_4, "4u8", None, 1, 4, u8);
|
||||
(38, S16_4, S16_4, "4s16", None, 2, 4, i16);
|
||||
(39, U16_4, U16_4, "4u16", None, 2, 4, u16);
|
||||
(40, S32_4, S32_4, "4s32", Some("vs32"), 4, 4, i32);
|
||||
(41, U32_4, U32_4, "4u32", Some("vu32"), 4, 4, u32);
|
||||
(42, S64_4, S64_4, "4s64", None, 8, 4, i64);
|
||||
(43, U64_4, U64_4, "4u64", None, 8, 4, u64);
|
||||
(44, FLOAT_4, Float4, "4f", Some("vf"), 4, 4, f32);
|
||||
(45, DOUBLE_4, Double4, "4d", None, 8, 4, f64);
|
||||
// 46 = Attribute
|
||||
// no 47
|
||||
(48, Vs8, "vs8", None, 1, 16, i8);
|
||||
(49, Vu8, "vu8", None, 1, 16, u8);
|
||||
(50, Vs16, "vs16", None, 2, 8, i16);
|
||||
(51, Vu16, "vu16", None, 2, 8, u16);
|
||||
(52, Boolean, "bool", Some("b"), 1, 1, bool);
|
||||
(53, Boolean2, "2b", None, 1, 2, bool);
|
||||
(54, Boolean3, "3b", None, 1, 3, bool);
|
||||
(55, Boolean4, "4b", None, 1, 4, bool);
|
||||
(56, Vb, "vb", None, 1, 16, bool);
|
||||
(48, VS8, Vs8, "vs8", None, 1, 16, i8);
|
||||
(49, VU8, Vu8, "vu8", None, 1, 16, u8);
|
||||
(50, VS16, Vs16, "vs16", None, 2, 8, i16);
|
||||
(51, VU16, Vu16, "vu16", None, 2, 8, u16);
|
||||
(52, BOOL, Boolean, "bool", Some("b"), 1, 1, bool);
|
||||
(53, BOOL_2, Boolean2, "2b", None, 1, 2, bool);
|
||||
(54, BOOL_3, Boolean3, "3b", None, 1, 3, bool);
|
||||
(55, BOOL_4, Boolean4, "4b", None, 1, 4, bool);
|
||||
(56, VB, Vb, "vb", None, 1, 16, bool);
|
||||
|
||||
( 1, NodeStart, "void", None, 0, 0, InvalidConverter);
|
||||
(46, Attribute, "attr", None, 0, 0, InvalidConverter);
|
||||
( 1, NODE_START, NodeStart, "void", None, 0, 0, InvalidConverter);
|
||||
(46, ATTRIBUTE, Attribute, "attr", None, 0, 0, InvalidConverter);
|
||||
|
||||
(190, NodeEnd, "nodeEnd", None, 0, 0, InvalidConverter);
|
||||
(191, FileEnd, "fileEnd", None, 0, 0, InvalidConverter);
|
||||
(190, NODE_END, NodeEnd, "nodeEnd", None, 0, 0, InvalidConverter);
|
||||
(191, FILE_END, FileEnd, "fileEnd", None, 0, 0, InvalidConverter);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
use failure::ResultExt;
|
||||
use num::{BigUint, FromPrimitive, ToPrimitive};
|
||||
|
||||
@@ -21,8 +21,7 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn pack_sixbit<T>(writer: &mut T, input: &str)
|
||||
pub fn pack_sixbit<T>(writer: &mut T, input: &str) -> Result<(), KbinError>
|
||||
where T: Write
|
||||
{
|
||||
let sixbit_chars = input
|
||||
@@ -30,19 +29,24 @@ pub fn pack_sixbit<T>(writer: &mut T, input: &str)
|
||||
.map(|ch| {
|
||||
*BYTE_MAP.get(&ch).expect("Character must be a valid sixbit character")
|
||||
});
|
||||
let padding = 8 - input.len() * 6 % 8;
|
||||
let len = input.len() as usize;
|
||||
let padding = 8 - len * 6 % 8;
|
||||
let padding = if padding == 8 { 0 } else { padding };
|
||||
let real_len = (len * 6 + padding) / 8;
|
||||
debug!("sixbit_len: {}, real_len: {}, padding: {}", len, real_len, padding);
|
||||
|
||||
let mut bits = 0;
|
||||
let mut bits = BigUint::new(vec![0; real_len]);
|
||||
for ch in sixbit_chars {
|
||||
bits <<= 6;
|
||||
bits |= ch as u64;
|
||||
bits |= BigUint::from_u8(ch).unwrap();
|
||||
}
|
||||
bits <<= padding;
|
||||
|
||||
let len = input.len() as u8;
|
||||
writer.write_u8(len).expect("Unable to write sixbit string length");
|
||||
writer.write_uint::<BigEndian>(bits, (input.len() * 6 + padding) / 8).expect("Unable to write sixbit contents");
|
||||
let bytes = bits.to_bytes_be();
|
||||
writer.write_u8(len as u8).context(KbinErrorKind::SixbitLengthWrite)?;
|
||||
writer.write(&bytes).context(KbinErrorKind::SixbitWrite)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unpack_sixbit<T>(reader: &mut T) -> Result<String, KbinError>
|
||||
|
||||
Reference in New Issue
Block a user