diff --git a/src/error.rs b/src/error.rs index 10dd799..1b12f46 100644 --- a/src/error.rs +++ b/src/error.rs @@ -98,6 +98,9 @@ pub enum KbinErrorKind { #[fail(display = "Unable to convert from hexadecimal")] HexError, + #[fail(display = "Missing base kbin type where one is required")] + MissingBaseType, + #[fail(display = "Missing type hint where one is required")] MissingTypeHint, @@ -153,6 +156,7 @@ impl From for KbinError { #[derive(Clone, Debug)] pub enum Error { Message(String), + StaticMessage(&'static str), Wrapped(Compat), } @@ -179,6 +183,7 @@ impl StdError for Error { fn description(&self) -> &str { match *self { Error::Message(ref msg) => msg, + Error::StaticMessage(ref msg) => msg, Error::Wrapped(ref err) => err.description(), } } diff --git a/src/node_types.rs b/src/node_types.rs index fbead55..5b8e67d 100644 --- a/src/node_types.rs +++ b/src/node_types.rs @@ -287,6 +287,25 @@ impl fmt::Display for KbinType { } } +macro_rules! find_type { + ($($base:ident => [$($size:tt $alternate:ident)+])+) => { + pub fn find_type(base: StandardType, len: usize) -> StandardType { + match base { + $( + StandardType::$base => match len { + 1 => StandardType::$base, + $( + $size => StandardType::$alternate, + )+ + _ => panic!("Unsupported len, base: {:?}, len: {}", base, len), + }, + )* + _ => panic!("Unsupported base, base: {:?}, len: {}", base, len), + } + } + }; +} + macro_rules! construct_types { ( $( @@ -345,6 +364,18 @@ macro_rules! construct_types { )+ } } + + find_type! { + S8 => [ 2 S8_2 3 S8_3 4 S8_4 ] + U8 => [ 2 U8_2 3 U8_3 4 U8_4 ] + S16 => [ 2 S16_2 3 S16_3 4 S16_4 ] + U16 => [ 2 U16_2 3 U16_3 4 U16_4 ] + S32 => [ 2 S32_2 3 S32_3 4 S32_4 ] + U32 => [ 2 U32_2 3 U32_3 4 U32_4 ] + Float => [ 2 Float2 3 Float3 4 Float4 ] + Double => [ 2 Double2 3 Double3 4 Double4 ] + Boolean => [ 2 Boolean2 3 Boolean3 4 Boolean4 ] + } } impl Deref for StandardType { diff --git a/src/ser/buffer.rs b/src/ser/buffer.rs new file mode 100644 index 0000000..fb5cc5f --- /dev/null +++ b/src/ser/buffer.rs @@ -0,0 +1,174 @@ +use byteorder::{BigEndian, WriteBytesExt}; +use failure::ResultExt; +use serde::ser::{self, Impossible, Serialize}; + +use error::{Error, KbinErrorKind}; +use node_types::StandardType; + +pub struct BufferSerializer { + buffer: Vec, +} + +impl BufferSerializer { + pub fn new() -> Self { + Self { + buffer: Vec::new(), + } + } + + #[inline] + pub fn get_ref(&self) -> &[u8] { + &self.buffer + } + + #[inline] + pub fn into_inner(self) -> Vec { + self.buffer + } +} + +macro_rules! ser_type { + (byte; $inner_type:ident, $method:ident, $standard_type:ident $($cast:tt)*) => { + fn $method(self, value: $inner_type) -> Result { + let node_type = StandardType::$standard_type; + + trace!("BufferSerializer::{}(node_type: {}, value: {})", stringify!($method), stringify!($standard_type), value); + self.buffer.write_u8(value $($cast)*).context(KbinErrorKind::DataWrite(node_type.name))?; + + Ok(node_type) + } + }; + (large; $inner_type:ident, $method:ident, $write_method:ident, $standard_type:ident $($cast:tt)*) => { + fn $method(self, value: $inner_type) -> Result { + trace!(concat!("BufferSerializer::{}(node_type: {}, value: {})"), stringify!($method), stringify!($standard_type), value); + + //self.buffer.push(Value::$standard_type(value)); + let node_type = StandardType::$standard_type; + self.buffer.$write_method::(value $($cast)*).context(KbinErrorKind::DataWrite(node_type.name))?; + + Ok(node_type) + } + } +} + +impl<'a> ser::Serializer for &'a mut BufferSerializer { + type Ok = StandardType; + type Error = Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeTupleVariant = Impossible; + type SerializeMap = Impossible; + type SerializeStruct = Impossible; + type SerializeStructVariant = Impossible; + + fn is_human_readable(&self) -> bool { + false + } + + ser_type!(byte; bool, serialize_bool, Boolean as u8); + ser_type!(byte; u8, serialize_u8, U8); + ser_type!(byte; i8, serialize_i8, S8 as u8); + ser_type!(large; u16, serialize_u16, write_u16, U16); + ser_type!(large; i16, serialize_i16, write_i16, S16); + ser_type!(large; u32, serialize_u32, write_u32, U32); + ser_type!(large; i32, serialize_i32, write_i32, S32); + ser_type!(large; u64, serialize_u64, write_u64, U64); + ser_type!(large; i64, serialize_i64, write_i64, S64); + ser_type!(large; f32, serialize_f32, write_f32, Float); + ser_type!(large; f64, serialize_f64, write_f64, Double); + + fn serialize_char(self, value: char) -> Result { + trace!("BufferSerializer::serialize_char(value: {})", value); + Err(Error::StaticMessage("char not supported")) + } + + fn serialize_str(self, value: &str) -> Result { + trace!("BufferSerializer::serialize_str(value: {})", value); + Err(Error::StaticMessage("str not supported")) + } + + // Binary data is handled separately from other array types. + // Binary data should also be the only element of its node. + fn serialize_bytes(self, value: &[u8]) -> Result { + trace!("BufferSerializer::serialize_bytes(value: {:02x?})", value); + Err(Error::StaticMessage("bytes not supported")) + } + + fn serialize_none(self) -> Result { + trace!("BufferSerializer::serialize_none()"); + Err(Error::StaticMessage("option not supported")) + } + + fn serialize_some(self, _v: &T) -> Result + where T: ?Sized + Serialize + { + trace!("BufferSerializer::serialize_some()"); + Err(Error::StaticMessage("option not supported")) + } + + fn serialize_unit(self) -> Result { + trace!("BufferSerializer::serialize_unit()"); + Err(Error::StaticMessage("unit not supported")) + } + + fn serialize_unit_struct(self, name: &'static str) -> Result { + trace!("BufferSerializer::serialize_unit_struct(name: {})", name); + Err(Error::StaticMessage("unit struct not supported")) + } + + fn serialize_unit_variant(self, name: &'static str, variant_index: u32, variant: &'static str) -> Result { + trace!("BufferSerializer::serialize_unit_variant(name: {}, variant_index: {}, variant: {})", name, variant_index, variant); + Err(Error::StaticMessage("unit variant not supported")) + } + + fn serialize_newtype_struct(self, name: &'static str, _value: &T) -> Result + where T: ?Sized + Serialize + { + trace!("BufferSerializer::serialize_newtype_struct(name: {})", name); + Err(Error::StaticMessage("newtype struct not supported")) + } + + fn serialize_newtype_variant(self, name: &'static str, variant_index: u32, variant: &'static str, _value: &T) -> Result + where T: ?Sized + Serialize + { + trace!("BufferSerializer::serialize_newtype_variant(name: {}, variant_index: {}, variant: {})", name, variant_index, variant); + Err(Error::StaticMessage("newtype variant not supported")) + } + + fn serialize_seq(self, len: Option) -> Result { + trace!("BufferSerializer::serialize_seq(len: {:?})", len); + Err(Error::StaticMessage("sequences not supported")) + } + + fn serialize_tuple(self, len: usize) -> Result { + trace!("BufferSerializer::serialize_tuple(len: {})", len); + Err(Error::StaticMessage("tuple not supported")) + } + + fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result { + trace!("BufferSerializer::serialize_tuple_struct(name: {}, len: {})", name, len); + Err(Error::StaticMessage("tuple struct not supported")) + } + + fn serialize_tuple_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result { + trace!("BufferSerializer::serialize_tuple_variant(name: {}, variant_index: {}, variant: {}, len: {})", name, variant_index, variant, len); + Err(Error::StaticMessage("tuple variant not supported")) + } + + fn serialize_map(self, len: Option) -> Result { + trace!("BufferSerializer::serialize_map(len: {:?})", len); + Err(Error::StaticMessage("map not supported")) + } + + fn serialize_struct(self, name: &'static str, len: usize) -> Result { + trace!("BufferSerializer::serialize_struct(name: {}, len: {})", name, len); + Err(Error::StaticMessage("struct not supported")) + } + + fn serialize_struct_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result { + trace!("BufferSerializer::serialize_struct_variant(name: {}, variant_index: {}, variant: {}, len: {})", name, variant_index, variant, len); + Err(Error::StaticMessage("struct variant not supported")) + } +} diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 71821ce..2bb8b3c 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -12,14 +12,17 @@ use error::{Error, KbinError, KbinErrorKind}; use sixbit::pack_sixbit; use super::{ARRAY_MASK, SIGNATURE, SIG_COMPRESSED}; +mod buffer; mod custom; mod map; mod structure; +mod seq; mod tuple; use self::custom::Custom; use self::map::Map; use self::structure::Struct; +use self::seq::Seq; use self::tuple::Tuple; pub type Result = StdResult; @@ -122,7 +125,7 @@ impl Serializer { macro_rules! ser_type { (byte; $inner_type:ident, $method:ident, $standard_type:ident $($cast:tt)*) => { fn $method(self, value: $inner_type) -> Result { - trace!(concat!("Serializer::", stringify!($method), " => value: {}"), value); + trace!(concat!("Serializer::", stringify!($method), "(value: {})"), value); let node_type = StandardType::$standard_type; match self.write_mode { @@ -141,7 +144,7 @@ macro_rules! ser_type { }; (large; $inner_type:ident, $method:ident, $write_method:ident, $standard_type:ident $($cast:tt)*) => { fn $method(self, value: $inner_type) -> Result { - trace!(concat!("Serializer::", stringify!($method), " => value: {}"), value); + trace!(concat!("Serializer::", stringify!($method), "(value: {})"), value); let node_type = StandardType::$standard_type; match self.write_mode { @@ -165,7 +168,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { type Ok = Option; type Error = Error; - type SerializeSeq = Tuple<'a>; + type SerializeSeq = Seq<'a>; type SerializeTuple = Tuple<'a>; type SerializeTupleStruct = Custom<'a>; type SerializeTupleVariant = Impossible; @@ -234,45 +237,44 @@ impl<'a> ser::Serializer for &'a mut Serializer { // TODO: Figure out a good way to serialize this fn serialize_none(self) -> Result { - debug!("serialize_none"); + trace!("Serializer::serialize_none()"); Ok(None) } - fn serialize_some(self, v: &T) -> Result + fn serialize_some(self, value: &T) -> Result where T: ?Sized + Serialize { trace!("Serializer::serialize_some()"); - v.serialize(&mut *self) + value.serialize(&mut *self) } // TODO: Figure out a good way to serialize this fn serialize_unit(self) -> Result { - debug!("serialize_unit"); - unimplemented!(); + trace!("Serializer::serialize_unit()"); + Err(Error::StaticMessage("unit not supported")) } fn serialize_unit_struct(self, name: &'static str) -> Result { - debug!("serialize_unit_struct => name: {}", name); - let hint = name.serialize(&mut *self)?; - Ok(hint) + trace!("Serializer::serialize_unit_struct(name: {})", name); + name.serialize(&mut *self) } fn serialize_unit_variant(self, name: &'static str, variant_index: u32, variant: &'static str) -> Result { - debug!("serialize_unit_variant => name: {}, variant_index: {}, variant: {}", name, variant_index, variant); + trace!("Serializer::serialize_unit_variant(name: {}, variant_index: {}, variant: {})", name, variant_index, variant); variant.serialize(&mut *self) } fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result where T: ?Sized + Serialize { - debug!("serialize_newtype_struct => name: {}", name); + trace!("Serializer::serialize_newtype_struct(name: {})", name); value.serialize(&mut *self) } fn serialize_newtype_variant(self, name: &'static str, variant_index: u32, variant: &'static str, value: &T) -> Result where T: ?Sized + Serialize { - debug!("serialize_newtype_variant => name: {}, variant_index: {}, variant: {}", name, variant_index, variant); + trace!("Serializer::serialize_newtype_variant(name: {}, variant_index: {}, variant: {})", name, variant_index, variant); variant.serialize(&mut *self)?; let hint = value.serialize(&mut *self)?.map(|mut hint| { hint.is_array = false; @@ -282,24 +284,25 @@ impl<'a> ser::Serializer for &'a mut Serializer { } fn serialize_seq(self, len: Option) -> Result { - debug!("serialize_seq => len: {:?}", len); - let len = len.ok_or(Error::Message("unsized sequences not supported".to_string()))?; - Ok(Tuple::new(self, len)) + trace!("Serializer::serialize_seq(len: {:?})", len); + + let len = len.ok_or(Error::StaticMessage("unsized sequences not supported"))?; + Seq::new(self, len) } fn serialize_tuple(self, len: usize) -> Result { - debug!("serialize_tuple => len: {}", len); + trace!("Serializer::serialize_tuple(len: {})", len); Ok(Tuple::new(self, len)) } fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result { - debug!("serialize_tuple_struct => name: {}, len: {}", name, len); + trace!("Serializer::serialize_tuple_struct(name: {}, len: {})", name, len); Custom::new(self, name, len) } fn serialize_tuple_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result { - debug!("serialize_tuple_variant => name: {}, variant_index: {}, variant: {}, len: {}", name, variant_index, variant, len); - Err(Error::Message("tuple variant not supported".to_string())) + trace!("Serializer::serialize_tuple_variant(name: {}, variant_index: {}, variant: {}, len: {})", name, variant_index, variant, len); + Err(Error::StaticMessage("tuple variant not supported")) } fn serialize_map(self, len: Option) -> Result { @@ -308,13 +311,12 @@ impl<'a> ser::Serializer for &'a mut Serializer { } fn serialize_struct(self, name: &'static str, len: usize) -> Result { - debug!("serialize_struct => name: {}, len: {}", name, len); - + trace!("Serializer::serialize_struct(name: {}, len: {})", name, len); Struct::new(self, name, len) } fn serialize_struct_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result { - debug!("serialize_struct_variant => name: {}, variant_index: {}, variant: {}, len: {}", name, variant_index, variant, len); - Err(Error::Message("struct variant not supported".to_string())) + trace!("Serializer::serialize_struct_variant(name: {}, variant_index: {}, variant: {}, len: {})", name, variant_index, variant, len); + Err(Error::StaticMessage("struct variant not supported")) } } diff --git a/src/ser/seq.rs b/src/ser/seq.rs new file mode 100644 index 0000000..d9ba8a1 --- /dev/null +++ b/src/ser/seq.rs @@ -0,0 +1,84 @@ +use std::io::{Seek, SeekFrom}; + +use byteorder::{BigEndian, WriteBytesExt}; +use failure::ResultExt; +use serde::ser::{Serialize, SerializeSeq}; + +use error::KbinErrorKind; +use node_types::StandardType; +use ser::{Error, Result, Serializer, TypeHint, WriteMode}; + +pub struct Seq<'a> { + ser: &'a mut Serializer, + + size_index: u64, + node_type: Option, + len: usize, +} + +impl<'a> Seq<'a> { + pub fn new(ser: &'a mut Serializer, len: usize) -> Result { + trace!("Tuple::new(len: {})", len); + + ser.write_mode = WriteMode::Array; + + // Estimate u32 for the total size of the tuple + let size_index = ser.data_buf.position(); + ser.data_buf.write_u32::(len as u32).context(KbinErrorKind::DataWrite("size placeholder"))?; + + Ok(Self { + ser, + size_index, + node_type: None, + len, + }) + } +} + +impl<'a> SerializeSeq for Seq<'a> { + type Ok = Option; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where T: ?Sized + Serialize + { + trace!("::serialize_element()"); + + let hint = value.serialize(&mut *self.ser)?.ok_or(KbinErrorKind::MissingTypeHint)?; + debug!("::serialize_element() => hint: {:?}", hint); + + // Rust tuple types can have different types per element, this is not + // permitted by kbin + if let Some(node_type) = self.node_type { + if node_type != hint.node_type { + return Err(KbinErrorKind::TypeMismatch(*node_type, *hint.node_type).into()); + } + } else { + self.node_type = Some(hint.node_type); + } + + Ok(()) + } + + fn end(self) -> Result { + trace!("::end()"); + + self.ser.write_mode = WriteMode::Single; + self.ser.data_buf.realign_writes(None)?; + + let node_type = self.node_type.ok_or(KbinErrorKind::InvalidState)?; + let size = (self.len as u32) * (node_type.size as u32); + + // Update the size estimate from the constructor + if size as usize != self.len { + debug!("::end() => size correction: {}", size); + + let current_pos = self.ser.data_buf.position(); + self.ser.data_buf.seek(SeekFrom::Start(self.size_index)).context(KbinErrorKind::Seek)?; + self.ser.data_buf.write_u32::(size).context(KbinErrorKind::DataWrite("node size"))?; + self.ser.data_buf.seek(SeekFrom::Start(current_pos)).context(KbinErrorKind::Seek)?; + } + + Ok(Some(TypeHint { node_type, is_array: true, count: self.len })) + } +} diff --git a/src/ser/tuple.rs b/src/ser/tuple.rs index 4daf92f..f90e406 100644 --- a/src/ser/tuple.rs +++ b/src/ser/tuple.rs @@ -1,42 +1,47 @@ -use std::io::{Seek, SeekFrom}; - -use byteorder::{BigEndian, WriteBytesExt}; -use failure::ResultExt; -use serde::ser::{Serialize, SerializeSeq, SerializeTuple}; +use serde::ser::{Serialize, SerializeTuple}; use error::KbinErrorKind; use node_types::StandardType; -use ser::{Error, Result, Serializer, TypeHint, WriteMode}; +use ser::{Error, Result, Serializer, TypeHint}; +use ser::buffer::BufferSerializer; +/// Tuple handler for serialization. +/// +/// Kbin tuple types are monotype (all tuple elements have the same type) +/// which differs from Rust's tuples that can have different types for each +/// element. +/// +/// This key difference is what makes it harder to seralize tuples, which is +/// why the `BufferSerializer` is used to serialize tuple elements to an +/// intermediate byte array before running the write logic. Kbin's write logic +/// depends on the size of the type, which is taken care of by +/// `ByteBuffer::write_aligned`. pub struct Tuple<'a> { ser: &'a mut Serializer, + buffer: BufferSerializer, - size_index: u64, node_type: Option, len: usize, } impl<'a> Tuple<'a> { pub fn new(ser: &'a mut Serializer, len: usize) -> Self { - debug!("Tuple::new(len: {})", len); - - ser.write_mode = WriteMode::Array; - - // Estimate u32 for the total size of the tuple - let size_index = ser.data_buf.position(); - ser.data_buf.write_u32::(len as u32).expect("Unable to write size placeholder"); + trace!("Tuple::new(len: {})", len); Self { ser, - size_index, + buffer: BufferSerializer::new(), node_type: None, len, } } - fn find_standard_type(&self) -> StandardType { - debug!("find_standard_type => len: {}", self.len); - self.node_type.unwrap_or(StandardType::String) + fn find_standard_type(&self) -> Result { + let base = self.node_type.ok_or(KbinErrorKind::MissingBaseType)?; + let combined = StandardType::find_type(base, self.len); + debug!("find_standard_type => StandardType::find_type(base: {:?}, len: {}) = {:?}", base, self.len, combined); + + Ok(combined) } } @@ -47,58 +52,28 @@ impl<'a> SerializeTuple for Tuple<'a> { fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize { - debug!("SerializeTuple: serialize_element"); - let hint = value.serialize(&mut *self.ser)?.ok_or(KbinErrorKind::MissingTypeHint)?; - debug!("SerializeTuple: serialize_element, hint: {:?}", hint); + let node_type = value.serialize(&mut self.buffer)?; // Rust tuple types can have different types per element, this is not // permitted by kbin - if let Some(node_type) = self.node_type { - if node_type != hint.node_type { - return Err(KbinErrorKind::TypeMismatch(*node_type, *hint.node_type).into()); + if let Some(known) = self.node_type { + if known != node_type { + return Err(KbinErrorKind::TypeMismatch(*known, *node_type).into()); } } else { - self.node_type = Some(hint.node_type); + self.node_type = Some(node_type); } Ok(()) } fn end(self) -> Result { - debug!("SerializeTuple: end"); + let node_type = self.find_standard_type()?; + let buffer = self.buffer.into_inner(); + debug!("::end() => buffer: {:?}, node_type: {:?}", buffer, node_type); - self.ser.write_mode = WriteMode::Single; - self.ser.data_buf.realign_writes(None)?; + self.ser.data_buf.write_aligned(*node_type, &buffer)?; - let node_type = self.find_standard_type(); - let size = (self.len as u32) * (node_type.size as u32); - - // Update the size estimate from the constructor - if size as usize != self.len { - debug!("SerializeTuple: end, size correction: {}", size); - - let current_pos = self.ser.data_buf.position(); - self.ser.data_buf.seek(SeekFrom::Start(self.size_index)).context(KbinErrorKind::Seek)?; - self.ser.data_buf.write_u32::(size).context(KbinErrorKind::DataWrite("node size"))?; - self.ser.data_buf.seek(SeekFrom::Start(current_pos)).context(KbinErrorKind::Seek)?; - } - - Ok(Some(TypeHint { node_type, is_array: true, count: self.len })) - } -} - -// kbin only supports sized arrays, coerce sequence types to tuple processing -impl<'a> SerializeSeq for Tuple<'a> { - type Ok = Option; - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<()> - where T: ?Sized + Serialize - { - ::serialize_element(self, value) - } - - fn end(self) -> Result { - ::end(self) + Ok(Some(TypeHint::from_type(node_type))) } }