mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-12 04:25:09 -05:00
ser: initial Serde Serializer for kbin
This commit is contained in:
@@ -14,3 +14,5 @@ num = "0.1.42"
|
||||
pretty_env_logger = "0.2.3"
|
||||
quick-xml = "0.12.1"
|
||||
rustc-hex = "1.0.0"
|
||||
serde = "1.0.69"
|
||||
serde_derive = "1.0.69"
|
||||
|
||||
@@ -6,15 +6,37 @@ extern crate minidom;
|
||||
extern crate pretty_env_logger;
|
||||
extern crate quick_xml;
|
||||
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{Cursor, Error as IoError, ErrorKind as IoErrorKind, Read, Write, stdout};
|
||||
use std::str;
|
||||
|
||||
use failure::Fail;
|
||||
use kbinxml::{KbinXml, Options};
|
||||
use kbinxml::{KbinXml, Options, to_bytes};
|
||||
use minidom::Element;
|
||||
use quick_xml::Writer;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename = "test2")]
|
||||
pub struct Testing2 {
|
||||
hi: u16,
|
||||
ho: i16,
|
||||
vu: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename = "test")]
|
||||
pub struct Testing {
|
||||
hi: u8,
|
||||
ok: [u8; 3],
|
||||
hhh: (u8, u8),
|
||||
hhg: (u32, u32),
|
||||
foo: String,
|
||||
testing2: Testing2,
|
||||
}
|
||||
|
||||
fn display_err(err: impl Fail) -> IoError {
|
||||
let mut fail: &Fail = &err;
|
||||
eprintln!("e: {}", err);
|
||||
@@ -97,19 +119,48 @@ fn main() -> std::io::Result<()> {
|
||||
let mut contents = Vec::new();
|
||||
file.read_to_end(&mut contents)?;
|
||||
|
||||
let (element, encoding_original) = KbinXml::from_binary(&contents).map_err(display_err)?;
|
||||
//println!("element: {:#?}", element);
|
||||
let text_original = to_text(&element)?;
|
||||
display_buf(&text_original)?;
|
||||
if KbinXml::is_binary_xml(&contents) {
|
||||
let (element, encoding_original) = KbinXml::from_binary(&contents).map_err(display_err)?;
|
||||
//println!("element: {:#?}", element);
|
||||
let text_original = to_text(&element)?;
|
||||
display_buf(&text_original)?;
|
||||
|
||||
let options = Options::with_encoding(encoding_original);
|
||||
let buf = KbinXml::to_binary_with_options(options, &element).map_err(display_err)?;
|
||||
compare_slice(&buf, &contents);
|
||||
let options = Options::with_encoding(encoding_original);
|
||||
let buf = KbinXml::to_binary_with_options(options, &element).map_err(display_err)?;
|
||||
compare_slice(&buf, &contents);
|
||||
} else {
|
||||
let contents = str::from_utf8(&contents).expect("Unable to interpret file contents as UTF-8");
|
||||
let element: Element = contents.parse().expect("Unable to construct DOM for input text XML");
|
||||
|
||||
let options = Options::default();
|
||||
let buf = KbinXml::to_binary_with_options(options, &element).map_err(display_err)?;
|
||||
eprintln!("data: {:02x?}", buf);
|
||||
}
|
||||
|
||||
/*
|
||||
let (element, encoding_new) = KbinXml::from_binary(&buf).map_err(display_err)?;
|
||||
let text_new = to_text(&element)?;
|
||||
assert_eq!(encoding_original, encoding_new);
|
||||
assert_eq!(text_original, text_new);
|
||||
*/
|
||||
} else {
|
||||
let obj = Testing {
|
||||
hi: 12,
|
||||
ok: [12, 24, 48],
|
||||
hhh: (55, 66),
|
||||
hhg: (55, 66),
|
||||
foo: "foobarbaz".to_string(),
|
||||
testing2: Testing2 {
|
||||
hi: 32423,
|
||||
ho: 32000,
|
||||
vu: vec![33, 255, 254],
|
||||
},
|
||||
};
|
||||
let bytes = to_bytes(&obj).unwrap();
|
||||
eprintln!("bytes: {:02x?}", bytes);
|
||||
|
||||
let mut file = File::create("testing.kbin")?;
|
||||
file.write_all(&bytes)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -95,6 +95,9 @@ pub enum KbinErrorKind {
|
||||
|
||||
#[fail(display = "Unable to convert from hexadecimal")]
|
||||
HexError,
|
||||
|
||||
#[fail(display = "Missing type hint where one is required")]
|
||||
MissingTypeHint,
|
||||
}
|
||||
|
||||
impl fmt::Display for KbinError {
|
||||
|
||||
14
src/lib.rs
14
src/lib.rs
@@ -5,11 +5,15 @@ extern crate encoding;
|
||||
extern crate minidom;
|
||||
extern crate num;
|
||||
extern crate rustc_hex;
|
||||
extern crate serde;
|
||||
|
||||
#[macro_use] extern crate failure;
|
||||
#[macro_use] extern crate lazy_static;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
use std::fmt::Write as FmtWrite;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
@@ -26,6 +30,9 @@ mod node_types;
|
||||
mod options;
|
||||
mod sixbit;
|
||||
|
||||
//mod de;
|
||||
mod ser;
|
||||
|
||||
use byte_buffer::{ByteBufferRead, ByteBufferWrite};
|
||||
use compression::Compression;
|
||||
use node_types::StandardType;
|
||||
@@ -35,6 +42,7 @@ use sixbit::{pack_sixbit, unpack_sixbit};
|
||||
pub use encoding_type::EncodingType;
|
||||
pub use error::{KbinError, KbinErrorKind, Result};
|
||||
pub use options::Options;
|
||||
pub use ser::to_bytes;
|
||||
|
||||
const SIGNATURE: u8 = 0xA0;
|
||||
|
||||
@@ -68,6 +76,10 @@ impl KbinXml {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_binary_xml(input: &[u8]) -> bool {
|
||||
input.len() > 2 && input[0] == SIGNATURE && input[1] == SIG_COMPRESSED
|
||||
}
|
||||
|
||||
fn from_binary_internal(&mut self, stack: &mut Vec<Element>, input: &[u8]) -> Result<(Element, EncodingType)> {
|
||||
// Node buffer starts from the beginning.
|
||||
// Data buffer starts later after reading `len_data`.
|
||||
@@ -278,7 +290,7 @@ impl KbinXml {
|
||||
|
||||
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"))?;
|
||||
data_buf.write_all(&data).context(KbinErrorKind::DataWrite("binary"))?;
|
||||
data_buf.realign_writes(None)?;
|
||||
},
|
||||
StandardType::String => {
|
||||
|
||||
59
src/ser/error.rs
Normal file
59
src/ser/error.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use failure::{Compat, Context, Fail};
|
||||
use serde::{de, ser};
|
||||
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Error {
|
||||
Message(String),
|
||||
|
||||
Wrapped(Compat<KbinError>),
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
Error::Message(msg.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
Error::Message(msg.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(StdError::description(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::Message(ref msg) => msg,
|
||||
Error::Wrapped(ref err) => err.description(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KbinError> for Error {
|
||||
fn from(inner: KbinError) -> Self {
|
||||
Error::Wrapped(inner.compat())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KbinErrorKind> for Error {
|
||||
fn from(inner: KbinErrorKind) -> Self {
|
||||
Error::Wrapped(KbinError::from(inner).compat())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Context<KbinErrorKind>> for Error {
|
||||
fn from(inner: Context<KbinErrorKind>) -> Self {
|
||||
Error::Wrapped(KbinError::from(inner).compat())
|
||||
}
|
||||
}
|
||||
465
src/ser/mod.rs
Normal file
465
src/ser/mod.rs
Normal file
@@ -0,0 +1,465 @@
|
||||
use std::io::{Cursor, Write};
|
||||
use std::mem;
|
||||
use std::result::Result as StdResult;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
||||
use failure::ResultExt;
|
||||
use serde::ser::{self, Impossible, Serialize};
|
||||
|
||||
use byte_buffer::ByteBufferWrite;
|
||||
use encoding_type::EncodingType;
|
||||
use node_types::StandardType;
|
||||
use sixbit::pack_sixbit;
|
||||
use super::error::{KbinError, KbinErrorKind};
|
||||
|
||||
mod error;
|
||||
mod tuple;
|
||||
|
||||
use self::error::Error;
|
||||
use self::tuple::Tuple;
|
||||
|
||||
const SIGNATURE: u8 = 0xA0;
|
||||
|
||||
const SIG_COMPRESSED: u8 = 0x42;
|
||||
|
||||
const ARRAY_MASK: u8 = 1 << 6; // 1 << 6 = 64
|
||||
|
||||
pub type Result<T> = StdResult<T, Error>;
|
||||
|
||||
// Writing arrays should not be aligned after each write. Buffer realignment
|
||||
// should be performed after Writing a single value.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum WriteMode {
|
||||
Single,
|
||||
Array,
|
||||
}
|
||||
|
||||
pub struct Serializer {
|
||||
encoding: EncodingType,
|
||||
|
||||
pub(crate) write_mode: WriteMode,
|
||||
|
||||
pub(crate) node_buf: Cursor<Vec<u8>>,
|
||||
pub(crate) data_buf: ByteBufferWrite,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TypeHint {
|
||||
node_type: StandardType,
|
||||
is_array: bool,
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl TypeHint {
|
||||
/*
|
||||
fn new(node_type: StandardType, is_array: bool, count: usize) -> Self {
|
||||
Self { node_type, is_array, count }
|
||||
}
|
||||
*/
|
||||
|
||||
fn from_type(node_type: StandardType) -> Self {
|
||||
Self {
|
||||
node_type,
|
||||
is_array: false,
|
||||
count: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bytes<T>(value: &T) -> Result<Vec<u8>>
|
||||
where T: Serialize
|
||||
{
|
||||
let mut serializer = Serializer {
|
||||
encoding: EncodingType::SHIFT_JIS,
|
||||
write_mode: WriteMode::Single,
|
||||
node_buf: Cursor::new(Vec::new()),
|
||||
data_buf: ByteBufferWrite::new(Vec::new()),
|
||||
};
|
||||
value.serialize(&mut serializer)?;
|
||||
|
||||
let output = serializer.finalize()?;
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
impl Serializer {
|
||||
fn finalize(mut self) -> StdResult<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 = self.encoding.to_byte();
|
||||
header.write_u8(encoding).context(KbinErrorKind::HeaderWrite("encoding"))?;
|
||||
header.write_u8(0xFF ^ encoding).context(KbinErrorKind::HeaderWrite("encoding negation"))?;
|
||||
|
||||
self.node_buf.write_u8(StandardType::FileEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("file end"))?;
|
||||
self.data_buf.realign_writes(None)?;
|
||||
|
||||
let mut output = header.into_inner();
|
||||
|
||||
let node_buf = self.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 = self.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)
|
||||
}
|
||||
}
|
||||
|
||||
// `straight_impl` passes a single element array to `write_aligned` where
|
||||
// `primitive_impl` will use `BigEndian` to populate a multi-element array for
|
||||
// `write_aligned`
|
||||
macro_rules! byte_impl {
|
||||
($inner_type:ident, $method:ident, $standard_type:ident $($cast:tt)*) => {
|
||||
fn $method(self, value: $inner_type) -> Result<Self::Ok> {
|
||||
debug!(concat!(stringify!($method), " => value: {}"), value);
|
||||
|
||||
let node_type = StandardType::$standard_type;
|
||||
match self.write_mode {
|
||||
WriteMode::Single => {
|
||||
let value = value $($cast)*;
|
||||
self.data_buf.write_aligned(*node_type, &[value])?;
|
||||
},
|
||||
WriteMode::Array => {
|
||||
self.data_buf.write_u8(value $($cast)*).context(KbinErrorKind::DataWrite(node_type.name))?;
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(TypeHint::from_type(node_type)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! primitive_impl {
|
||||
($inner_type:ident, $method:ident, $write_method:ident, $standard_type:ident $($cast:tt)*) => {
|
||||
fn $method(self, value: $inner_type) -> Result<Self::Ok> {
|
||||
debug!(concat!(stringify!($method), " => value: {}"), value);
|
||||
|
||||
let node_type = StandardType::$standard_type;
|
||||
match self.write_mode {
|
||||
WriteMode::Single => {
|
||||
let mut buf = [0; ::std::mem::size_of::<$inner_type>()];
|
||||
BigEndian::$write_method(&mut buf, value);
|
||||
self.data_buf.write_aligned(*node_type, &buf)?;
|
||||
},
|
||||
WriteMode::Array => {
|
||||
self.data_buf.$write_method::<BigEndian>(value $($cast)*).context(KbinErrorKind::DataWrite(node_type.name))?;
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(TypeHint::from_type(node_type)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ser::Serializer for &'a mut Serializer {
|
||||
type Ok = Option<TypeHint>;
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = Tuple<'a>;
|
||||
type SerializeTuple = Tuple<'a>;
|
||||
type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeMap = Self;
|
||||
type SerializeStruct = Self;
|
||||
type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
|
||||
|
||||
byte_impl!(bool, serialize_bool, Boolean as u8);
|
||||
byte_impl!(u8, serialize_u8, U8);
|
||||
byte_impl!(i8, serialize_i8, S8 as u8);
|
||||
primitive_impl!(u16, serialize_u16, write_u16, U16);
|
||||
primitive_impl!(i16, serialize_i16, write_i16, S16);
|
||||
primitive_impl!(u32, serialize_u32, write_u32, U32);
|
||||
primitive_impl!(i32, serialize_i32, write_i32, S32);
|
||||
primitive_impl!(u64, serialize_u64, write_u64, U64);
|
||||
primitive_impl!(i64, serialize_i64, write_i64, S64);
|
||||
primitive_impl!(f32, serialize_f32, write_f32, Float);
|
||||
primitive_impl!(f64, serialize_f64, write_f64, Double);
|
||||
|
||||
/*
|
||||
fn serialize_bool(self, value: bool) -> Result<Self::Ok> {
|
||||
debug!("serialize_bool => value: {}", value);
|
||||
let value = value as u8;
|
||||
|
||||
let node_type = StandardType::Boolean;
|
||||
match self.write_mode {
|
||||
WriteMode::Single => self.data_buf.write_aligned(*node_type, &[value])
|
||||
.context(KbinErrorKind::DataWrite("bool"))?,
|
||||
WriteMode::Array => self.data_buf.write_u8(value)
|
||||
.context(KbinErrorKind::DataWrite("bool"))?,
|
||||
};
|
||||
|
||||
Ok(TypeHint::from_type(node_type))
|
||||
}
|
||||
|
||||
fn serialize_u8(self, value: u8) -> Result<Self::Ok> {
|
||||
debug!("serialize_u8 => value: {}", value);
|
||||
|
||||
let node_type = StandardType::U8;
|
||||
match self.write_mode {
|
||||
WriteMode::Single => self.data_buf.write_aligned(*node_type, &[value])
|
||||
.context(KbinErrorKind::DataWrite("bool"))?,
|
||||
WriteMode::Array => self.data_buf.write_u8(value)
|
||||
.context(KbinErrorKind::DataWrite("bool"))?,
|
||||
};
|
||||
|
||||
Ok(TypeHint::from_type(node_type))
|
||||
}
|
||||
|
||||
fn serialize_i8(self, value: i8) -> Result<Self::Ok> {
|
||||
debug!("serialize_i8 => value: {}", value);
|
||||
let hint = self.write(StandardType::S8, &[value as u8]).context(KbinErrorKind::DataWrite("i8"))?;
|
||||
Ok(hint)
|
||||
}
|
||||
|
||||
fn serialize_u16(self, value: u16) -> Result<Self::Ok> {
|
||||
debug!("serialize_u16 => value: {}", value);
|
||||
self.data_buf.write_u16::<BigEndian>(value).context(KbinErrorKind::DataWrite("u16"))?;
|
||||
|
||||
Ok(TypeHint::from_type(StandardType::U16))
|
||||
}
|
||||
|
||||
fn serialize_i16(self, value: i16) -> Result<Self::Ok> {
|
||||
debug!("serialize_i16 => value: {}", value);
|
||||
|
||||
let node_type = StandardType::S16;
|
||||
match self.write_mode {
|
||||
WriteMode::Single => {
|
||||
let mut buf = [0; 2];
|
||||
BigEndian::write_i16(&mut buf, value);
|
||||
self.data_buf.write_aligned(*node_type, &buf)?;
|
||||
},
|
||||
WriteMode::Array => {
|
||||
self.data_buf.write_i16::<BigEndian>(value).context(KbinErrorKind::DataWrite(node_type.name))?;
|
||||
}
|
||||
};
|
||||
|
||||
Ok(TypeHint::from_type(node_type))
|
||||
}
|
||||
|
||||
fn serialize_u32(self, value: u32) -> Result<Self::Ok> {
|
||||
debug!("serialize_u32 => value: {}", value);
|
||||
self.data_buf.write_u32::<BigEndian>(value).context(KbinErrorKind::DataWrite("u32"))?;
|
||||
|
||||
Ok(TypeHint::from_type(StandardType::U32))
|
||||
}
|
||||
|
||||
fn serialize_i32(self, value: i32) -> Result<Self::Ok> {
|
||||
debug!("serialize_i32 => value: {}", value);
|
||||
self.data_buf.write_i32::<BigEndian>(value).context(KbinErrorKind::DataWrite("i32"))?;
|
||||
|
||||
Ok(TypeHint::from_type(StandardType::S32))
|
||||
}
|
||||
|
||||
fn serialize_u64(self, value: u64) -> Result<Self::Ok> {
|
||||
debug!("serialize_u64 => value: {}", value);
|
||||
self.data_buf.write_u64::<BigEndian>(value).context(KbinErrorKind::DataWrite("u64"))?;
|
||||
|
||||
Ok(TypeHint::from_type(StandardType::U64))
|
||||
}
|
||||
|
||||
fn serialize_i64(self, value: i64) -> Result<Self::Ok> {
|
||||
debug!("serialize_i64 => value: {}", value);
|
||||
self.data_buf.write_i64::<BigEndian>(value).context(KbinErrorKind::DataWrite("i64"))?;
|
||||
|
||||
Ok(TypeHint::from_type(StandardType::S64))
|
||||
}
|
||||
|
||||
fn serialize_f32(self, value: f32) -> Result<Self::Ok> {
|
||||
debug!("serialize_f32 => value: {}", value);
|
||||
self.data_buf.write_f32::<BigEndian>(value).context(KbinErrorKind::DataWrite("f32"))?;
|
||||
|
||||
Ok(TypeHint::from_type(StandardType::Float))
|
||||
}
|
||||
|
||||
fn serialize_f64(self, value: f64) -> Result<Self::Ok> {
|
||||
debug!("serialize_f64 => value: {}", value);
|
||||
self.data_buf.write_f64::<BigEndian>(value).context(KbinErrorKind::DataWrite("f64"))?;
|
||||
|
||||
Ok(Some(TypeHint::from_type(StandardType::Double)))
|
||||
}
|
||||
*/
|
||||
|
||||
fn serialize_char(self, value: char) -> Result<Self::Ok> {
|
||||
debug!("serialize_char => value: {}", value);
|
||||
self.data_buf.write_str(self.encoding, &value.to_string())?;
|
||||
|
||||
Ok(Some(TypeHint::from_type(StandardType::String)))
|
||||
}
|
||||
|
||||
fn serialize_str(self, value: &str) -> Result<Self::Ok> {
|
||||
debug!("serialize_str => value: {}", value);
|
||||
self.data_buf.write_str(self.encoding, value)?;
|
||||
|
||||
Ok(Some(TypeHint::from_type(StandardType::String)))
|
||||
}
|
||||
|
||||
// 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<Self::Ok> {
|
||||
debug!("serialize_bytes => value: {:02x?}", value);
|
||||
let node_type = StandardType::Binary;
|
||||
let size = (value.len() as u32) * (node_type.size as u32);
|
||||
self.data_buf.write_u32::<BigEndian>(size).context(KbinErrorKind::DataWrite("binary node size"))?;
|
||||
self.data_buf.write_all(value).context(KbinErrorKind::DataWrite("binary"))?;
|
||||
self.data_buf.realign_writes(None)?;
|
||||
|
||||
Ok(Some(TypeHint::from_type(node_type)))
|
||||
}
|
||||
|
||||
// TODO: Figure out a good way to serialize this
|
||||
fn serialize_none(self) -> Result<Self::Ok> {
|
||||
debug!("serialize_none");
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn serialize_some<T>(self, v: &T) -> Result<Self::Ok>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
debug!("serialize_some");
|
||||
let hint = v.serialize(&mut *self)?;
|
||||
Ok(hint)
|
||||
}
|
||||
|
||||
// TODO: Figure out a good way to serialize this
|
||||
fn serialize_unit(self) -> Result<Self::Ok> {
|
||||
debug!("serialize_unit");
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok> {
|
||||
debug!("serialize_unit_struct => name: {}", name);
|
||||
let hint = name.serialize(&mut *self)?;
|
||||
Ok(hint)
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(self, name: &'static str, variant_index: u32, variant: &'static str) -> Result<Self::Ok> {
|
||||
debug!("serialize_unit_variant => name: {}, variant_index: {}, variant: {}", name, variant_index, variant);
|
||||
let hint = variant.serialize(&mut *self)?;
|
||||
Ok(hint)
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<Self::Ok>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
debug!("serialize_newtype_struct => name: {}", name);
|
||||
let hint = value.serialize(&mut *self)?;
|
||||
Ok(hint)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T>(self, name: &'static str, variant_index: u32, variant: &'static str, value: &T) -> Result<Self::Ok>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
debug!("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;
|
||||
hint
|
||||
});
|
||||
Ok(hint)
|
||||
}
|
||||
|
||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
|
||||
debug!("serialize_seq => len: {:?}", len);
|
||||
let len = len.ok_or(Error::Message("unsized sequences not supported".to_string()))?;
|
||||
Ok(Tuple::new(self, len))
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
|
||||
debug!("serialize_tuple => len: {}", len);
|
||||
Ok(Tuple::new(self, len))
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeTupleStruct> {
|
||||
debug!("serialize_tuple_struct => name: {}, len: {}", name, len);
|
||||
Err(Error::Message("tuple struct not supported".to_string()))
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<Self::SerializeTupleVariant> {
|
||||
debug!("serialize_tuple_variant => name: {}, variant_index: {}, variant: {}, len: {}", name, variant_index, variant, len);
|
||||
Err(Error::Message("tuple variant not supported".to_string()))
|
||||
}
|
||||
|
||||
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
|
||||
debug!("serialize_map => len: {:?}", len);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
|
||||
debug!("serialize_struct => name: {}, len: {}", name, len);
|
||||
|
||||
let node_type = StandardType::NodeStart;
|
||||
self.node_buf.write_u8(node_type.id).context(KbinErrorKind::DataWrite(node_type.name))?;
|
||||
pack_sixbit(&mut self.node_buf, name)?;
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<Self::SerializeStructVariant> {
|
||||
debug!("serialize_struct_variant => name: {}, variant_index: {}, variant: {}, len: {}", name, variant_index, variant, len);
|
||||
Err(Error::Message("struct variant not supported".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ser::SerializeMap for &'a mut Serializer {
|
||||
type Ok = Option<TypeHint>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_key<T>(&mut self, key: &T) -> Result<()>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
debug!("SerializeMap: serialize_key");
|
||||
let hint = key.serialize(&mut **self)?;
|
||||
debug!("SerializeMap: serialize_key, hint: {:?}", hint);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_value<T>(&mut self, value: &T) -> Result<()>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
debug!("SerializeMap: serialize_value");
|
||||
let hint = value.serialize(&mut **self)?;
|
||||
debug!("SerializeMap: serialize_value, hint: {:?}", hint);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok> {
|
||||
debug!("SerializeMap: end");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ser::SerializeStruct for &'a mut Serializer {
|
||||
type Ok = Option<TypeHint>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
let size = mem::size_of_val(value);
|
||||
debug!("SerializeStruct: serialize_field, key: {}, value size: {}", key, size);
|
||||
|
||||
let hint = value.serialize(&mut **self)?.ok_or(KbinErrorKind::MissingTypeHint)?;
|
||||
let array_mask = if hint.is_array { ARRAY_MASK } else { 0 };
|
||||
debug!("SerializeStruct: serialize_field, key: {}, hint: {:?}", key, hint);
|
||||
|
||||
self.node_buf.write_u8(hint.node_type.id | array_mask).context(KbinErrorKind::DataWrite(hint.node_type.name))?;
|
||||
pack_sixbit(&mut self.node_buf, key)?;
|
||||
|
||||
// TODO: Make sure this does not prematurely end nodes
|
||||
self.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok> {
|
||||
debug!("SerializeStruct: end");
|
||||
self.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
|
||||
|
||||
trace!("SerializeStruct::end() => node_buf: {:02x?}", self.node_buf.get_ref());
|
||||
|
||||
Ok(Some(TypeHint::from_type(StandardType::NodeStart)))
|
||||
}
|
||||
}
|
||||
101
src/ser/tuple.rs
Normal file
101
src/ser/tuple.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use std::io::{Seek, SeekFrom};
|
||||
|
||||
use byteorder::{BigEndian, WriteBytesExt};
|
||||
use failure::ResultExt;
|
||||
use serde::ser::{Serialize, SerializeSeq, SerializeTuple};
|
||||
|
||||
use error::KbinErrorKind;
|
||||
use node_types::StandardType;
|
||||
use ser::{Error, Result, Serializer, TypeHint, WriteMode};
|
||||
|
||||
pub struct Tuple<'a> {
|
||||
ser: &'a mut Serializer,
|
||||
|
||||
size_index: u64,
|
||||
node_type: StandardType,
|
||||
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;
|
||||
|
||||
let size_index = ser.data_buf.position();
|
||||
|
||||
// Estimate u32 for the total size of the tuple
|
||||
debug!("big endian length: {:02x?}", u32::to_bytes(u32::to_be(len as u32)));
|
||||
ser.data_buf.write_u32::<BigEndian>(len as u32).expect("Unable to write size placeholder");
|
||||
|
||||
Self {
|
||||
ser,
|
||||
size_index,
|
||||
node_type: StandardType::String,
|
||||
len,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_standard_type(&self) -> StandardType {
|
||||
debug!("find_standard_type => len: {}", self.len);
|
||||
self.node_type
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeTuple for Tuple<'a> {
|
||||
type Ok = Option<TypeHint>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T>(&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);
|
||||
|
||||
self.node_type = hint.node_type;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok> {
|
||||
debug!("SerializeTuple: end");
|
||||
|
||||
self.ser.write_mode = WriteMode::Single;
|
||||
self.ser.data_buf.realign_writes(None)?;
|
||||
|
||||
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 old_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::<BigEndian>(size).context(KbinErrorKind::DataWrite("node size"))?;
|
||||
self.ser.data_buf.seek(SeekFrom::Start(old_pos)).context(KbinErrorKind::Seek)?;
|
||||
}
|
||||
|
||||
// Taken care of by `SerializerStruct`
|
||||
//self.ser.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
|
||||
|
||||
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<TypeHint>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
<Self as SerializeTuple>::serialize_element(self, value)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok> {
|
||||
<Self as SerializeTuple>::end(self)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user