lib: begin work on encoding

This commit is contained in:
Matt Bilker
2018-06-10 23:45:16 +00:00
parent 995193dd75
commit 8d8df1de0f
7 changed files with 408 additions and 192 deletions

View File

@@ -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"

View File

@@ -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(())
}

View File

@@ -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`

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -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);
}

View File

@@ -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>