mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-10 11:35:22 -05:00
types: handle kbin type conversion in separate handler
- Reduces code duplication between Value and ValueArray handling - Reduces code and macro complexity for Value and ValueArray
This commit is contained in:
@@ -6,7 +6,7 @@ description = "An encoder/decoder for Konami's binary XML format used in many of
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.3.1"
|
||||
byteorder = "1.3.2"
|
||||
bytes = "0.4.10"
|
||||
encoding_rs = "0.8.6"
|
||||
failure = "0.1.1"
|
||||
|
||||
@@ -32,6 +32,9 @@ pub enum KbinErrorKind {
|
||||
#[fail(display = "Unable to write a {} to data buffer", _0)]
|
||||
DataWrite(&'static str),
|
||||
|
||||
#[fail(display = "Unable to read bytes or not enough data read")]
|
||||
DataConvert,
|
||||
|
||||
#[fail(display = "Unable to read data size")]
|
||||
DataReadSize,
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ mod sixbit;
|
||||
mod text_reader;
|
||||
mod to_element;
|
||||
mod to_text_xml;
|
||||
mod types;
|
||||
mod value;
|
||||
mod writer;
|
||||
|
||||
@@ -40,7 +41,7 @@ pub use crate::node_types::StandardType;
|
||||
pub use crate::options::Options;
|
||||
pub use crate::to_element::ToElement;
|
||||
pub use crate::to_text_xml::ToTextXml;
|
||||
pub use crate::value::Value;
|
||||
pub use crate::value::{Value, ValueArray};
|
||||
pub use crate::writer::{Writer, Writeable};
|
||||
|
||||
const SIGNATURE: u8 = 0xA0;
|
||||
|
||||
213
src/types/bytes.rs
Normal file
213
src/types/bytes.rs
Normal file
@@ -0,0 +1,213 @@
|
||||
use std::io::Read;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use byteorder::ReadBytesExt;
|
||||
use bytes::{BigEndian, BufMut};
|
||||
use failure::ResultExt;
|
||||
|
||||
use crate::error::{KbinError, KbinErrorKind};
|
||||
|
||||
pub trait IntoKbinBytes {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B);
|
||||
}
|
||||
|
||||
pub trait FromKbinBytes: Sized {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError>;
|
||||
}
|
||||
|
||||
impl IntoKbinBytes for i8 {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
buf.put_i8(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for i8 {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
input.read_i8().context(KbinErrorKind::DataConvert).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoKbinBytes for u8 {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
buf.put_u8(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for u8 {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
input.read_u8().context(KbinErrorKind::DataConvert).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoKbinBytes for bool {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
buf.put_u8(if self { 0x01 } else { 0x00 })
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for bool {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
match u8::from_kbin_bytes(input)? {
|
||||
0x00 => Ok(false),
|
||||
0x01 => Ok(true),
|
||||
input => Err(KbinErrorKind::InvalidBooleanInput(input).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoKbinBytes for &'a [u8] {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
buf.put(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoKbinBytes for Ipv4Addr {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
let octets = self.octets();
|
||||
|
||||
buf.put(&octets[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for Ipv4Addr {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
let mut octets = [0; 4];
|
||||
input.read_exact(&mut octets).context(KbinErrorKind::DataConvert)?;
|
||||
|
||||
Ok(Ipv4Addr::from(octets))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! multibyte_impl {
|
||||
(
|
||||
$(($type:ty, $write_method:ident, $read_method:ident)),*$(,)?
|
||||
) => {
|
||||
$(
|
||||
impl IntoKbinBytes for $type {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
buf.$write_method(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for $type {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
input.$read_method::<BigEndian>().context(KbinErrorKind::DataConvert).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! tuple_impl {
|
||||
(
|
||||
i8: [$($i8_count:expr),*],
|
||||
u8: [$($u8_count:expr),*],
|
||||
bool: [$($bool_count:expr),*],
|
||||
multi: [
|
||||
$([$type:ty ; $($count:expr),*] => ($write_method:ident, $read_method:ident)),*$(,)?
|
||||
]
|
||||
) => {
|
||||
$(
|
||||
impl<'a> IntoKbinBytes for &'a [i8; $i8_count] {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
for value in self.into_iter() {
|
||||
buf.put_i8(*value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for [i8; $i8_count] {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
let mut values = Self::default();
|
||||
input.read_i8_into(&mut values).context(KbinErrorKind::DataConvert)?;
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
)*
|
||||
$(
|
||||
impl<'a> IntoKbinBytes for &'a [u8; $u8_count] {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
buf.put_slice(&self[..]);
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for [u8; $u8_count] {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
let mut values = Self::default();
|
||||
input.read_exact(&mut values).context(KbinErrorKind::DataConvert)?;
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
)*
|
||||
$(
|
||||
impl<'a> IntoKbinBytes for &'a [bool; $bool_count] {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
for value in self.into_iter() {
|
||||
value.write_kbin_bytes(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for [bool; $bool_count] {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
let mut values = Self::default();
|
||||
|
||||
for i in 0..$bool_count {
|
||||
values[i] = bool::from_kbin_bytes(input)?;
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
impl<'a> IntoKbinBytes for &'a [$type; $count] {
|
||||
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
|
||||
for value in self.into_iter() {
|
||||
buf.$write_method(*value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinBytes for [$type; $count] {
|
||||
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
|
||||
let mut values = Self::default();
|
||||
input.$read_method::<BigEndian>(&mut values).context(KbinErrorKind::DataConvert)?;
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
)*
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
multibyte_impl! {
|
||||
(i16, put_i16_be, read_i16),
|
||||
(u16, put_u16_be, read_u16),
|
||||
(i32, put_i32_be, read_i32),
|
||||
(u32, put_u32_be, read_u32),
|
||||
(i64, put_i64_be, read_i64),
|
||||
(u64, put_u64_be, read_u64),
|
||||
(f32, put_f32_be, read_f32),
|
||||
(f64, put_f64_be, read_f64),
|
||||
}
|
||||
|
||||
tuple_impl! {
|
||||
i8: [2, 3, 4, 16],
|
||||
u8: [2, 3, 4, 16],
|
||||
bool: [2, 3, 4, 16],
|
||||
multi: [
|
||||
[i16; 2, 3, 4, 8] => (put_i16_be, read_i16_into),
|
||||
[u16; 2, 3, 4, 8] => (put_u16_be, read_u16_into),
|
||||
[i32; 2, 3, 4] => (put_i32_be, read_i32_into),
|
||||
[u32; 2, 3, 4] => (put_u32_be, read_u32_into),
|
||||
[i64; 2, 3, 4] => (put_i64_be, read_i64_into),
|
||||
[u64; 2, 3, 4] => (put_u64_be, read_u64_into),
|
||||
[f32; 2, 3, 4] => (put_f32_be, read_f32_into),
|
||||
[f64; 2, 3, 4] => (put_f64_be, read_f64_into),
|
||||
]
|
||||
}
|
||||
3
src/types/mod.rs
Normal file
3
src/types/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
mod bytes;
|
||||
|
||||
pub use self::bytes::{FromKbinBytes, IntoKbinBytes};
|
||||
@@ -1,14 +1,14 @@
|
||||
//use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::net::Ipv4Addr;
|
||||
//use std::str::FromStr;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
||||
use failure::ResultExt;
|
||||
//use rustc_hex::FromHex;
|
||||
|
||||
use crate::error::{KbinError, KbinErrorKind};
|
||||
use crate::node_types::{self, StandardType};
|
||||
use crate::node_types::StandardType;
|
||||
use crate::types::{FromKbinBytes, IntoKbinBytes};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ValueArray {
|
||||
@@ -66,14 +66,7 @@ pub enum ValueArray {
|
||||
|
||||
macro_rules! tuple {
|
||||
(
|
||||
byte: [
|
||||
s8: [$($s8_konst:ident),*],
|
||||
u8: [$($u8_konst:ident),*],
|
||||
bool: [$($bool_konst:ident),*]
|
||||
],
|
||||
multi: [
|
||||
$($read_method:ident $write_method:ident $inner_type:ty => [$($multi_konst:ident),*]),*
|
||||
]
|
||||
$($konst:ident),*$(,)?
|
||||
) => {
|
||||
pub fn from_standard_type(node_type: StandardType, input: &[u8]) -> Result<Option<ValueArray>, KbinError> {
|
||||
let node_size = node_type.size * node_type.count;
|
||||
@@ -84,6 +77,8 @@ macro_rules! tuple {
|
||||
return Err(KbinErrorKind::SizeMismatch(*node_type, node_size, input.len()).into());
|
||||
}
|
||||
|
||||
let mut reader = Cursor::new(input);
|
||||
|
||||
let value = match node_type {
|
||||
StandardType::NodeStart |
|
||||
StandardType::NodeEnd |
|
||||
@@ -92,266 +87,34 @@ macro_rules! tuple {
|
||||
StandardType::Binary |
|
||||
StandardType::String |
|
||||
StandardType::Time => return Ok(None),
|
||||
StandardType::S8 => ValueArray::S8(input.iter().map(|v| *v as i8).collect()),
|
||||
StandardType::U8 => ValueArray::U8(input.to_vec()),
|
||||
StandardType::S16 => {
|
||||
let mut values = vec![0; len];
|
||||
BigEndian::read_i16_into(input, &mut values);
|
||||
ValueArray::S16(values)
|
||||
},
|
||||
StandardType::U16 => {
|
||||
let mut values = vec![0; len];
|
||||
BigEndian::read_u16_into(input, &mut values);
|
||||
ValueArray::U16(values)
|
||||
},
|
||||
StandardType::S32 => {
|
||||
let mut values = vec![0; len];
|
||||
BigEndian::read_i32_into(input, &mut values);
|
||||
ValueArray::S32(values)
|
||||
},
|
||||
StandardType::U32 => {
|
||||
let mut values = vec![0; len];
|
||||
BigEndian::read_u32_into(input, &mut values);
|
||||
ValueArray::U32(values)
|
||||
},
|
||||
StandardType::S64 => {
|
||||
let mut values = vec![0; len];
|
||||
BigEndian::read_i64_into(input, &mut values);
|
||||
ValueArray::S64(values)
|
||||
},
|
||||
StandardType::U64 => {
|
||||
let mut values = vec![0; len];
|
||||
BigEndian::read_u64_into(input, &mut values);
|
||||
ValueArray::U64(values)
|
||||
},
|
||||
StandardType::Ip4 => {
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
for chunk in input.chunks(4) {
|
||||
let mut octets = [0; 4];
|
||||
octets.copy_from_slice(chunk);
|
||||
values.push(Ipv4Addr::from(octets));
|
||||
}
|
||||
|
||||
ValueArray::Ip4(values)
|
||||
},
|
||||
StandardType::Float => {
|
||||
let mut values = vec![0.0; len];
|
||||
BigEndian::read_f32_into(input, &mut values);
|
||||
ValueArray::Float(values)
|
||||
},
|
||||
StandardType::Double => {
|
||||
let mut values = vec![0.0; len];
|
||||
BigEndian::read_f64_into(input, &mut values);
|
||||
ValueArray::Double(values)
|
||||
},
|
||||
StandardType::Boolean => {
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
for value in input {
|
||||
match value {
|
||||
0x00 => values.push(false),
|
||||
0x01 => values.push(true),
|
||||
input => return Err(KbinErrorKind::InvalidBooleanInput(*input).into()),
|
||||
};
|
||||
}
|
||||
|
||||
ValueArray::Boolean(values)
|
||||
},
|
||||
$(
|
||||
StandardType::$s8_konst => {
|
||||
const COUNT: usize = node_types::$s8_konst.count;
|
||||
|
||||
StandardType::$konst => {
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
for chunk in input.chunks(COUNT) {
|
||||
let mut value = [0; COUNT];
|
||||
for i in 0..COUNT {
|
||||
value[i] = chunk[i] as i8;
|
||||
}
|
||||
values.push(value);
|
||||
for _ in 0..len {
|
||||
values.push(FromKbinBytes::from_kbin_bytes(&mut reader)?);
|
||||
}
|
||||
|
||||
ValueArray::$s8_konst(values)
|
||||
ValueArray::$konst(values)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
StandardType::$u8_konst => {
|
||||
const COUNT: usize = node_types::$u8_konst.count;
|
||||
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
for chunk in input.chunks(COUNT) {
|
||||
let mut value = [0; COUNT];
|
||||
value[0..COUNT].copy_from_slice(&chunk[0..COUNT]);
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
ValueArray::$u8_konst(values)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
StandardType::$bool_konst => {
|
||||
const COUNT: usize = node_types::$bool_konst.count;
|
||||
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
for chunk in input.chunks(COUNT) {
|
||||
let mut value: [_; COUNT] = Default::default();
|
||||
for i in 0..COUNT {
|
||||
value[i] = match chunk[i] {
|
||||
0x00 => false,
|
||||
0x01 => true,
|
||||
input => return Err(KbinErrorKind::InvalidBooleanInput(input).into()),
|
||||
};
|
||||
}
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
ValueArray::$bool_konst(values)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
StandardType::$multi_konst => {
|
||||
const COUNT: usize = node_types::$multi_konst.count;
|
||||
const SIZE: usize = node_types::$multi_konst.size * COUNT;
|
||||
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
for chunk in input.chunks(SIZE) {
|
||||
let mut value: [_; COUNT] = Default::default();
|
||||
BigEndian::$read_method(chunk, &mut value);
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
ValueArray::$multi_konst(values)
|
||||
},
|
||||
)*
|
||||
)*
|
||||
};
|
||||
|
||||
Ok(Some(value))
|
||||
}
|
||||
|
||||
pub(super) fn to_bytes_inner(&self, output: &mut Vec<u8>) -> Result<(), KbinError> {
|
||||
macro_rules! gen_error {
|
||||
($konst:ident) => {
|
||||
KbinErrorKind::DataWrite(StandardType::$konst.name)
|
||||
};
|
||||
}
|
||||
|
||||
let node_size = self.standard_type().size;
|
||||
|
||||
match self {
|
||||
ValueArray::S8(ref values) => {
|
||||
output.reserve(values.len());
|
||||
for n in values {
|
||||
output.push(*n as u8);
|
||||
}
|
||||
},
|
||||
ValueArray::U8(ref values) => output.extend(values),
|
||||
ValueArray::S16(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for n in values {
|
||||
output.write_i16::<BigEndian>(*n).context(gen_error!(S16))?;
|
||||
}
|
||||
},
|
||||
ValueArray::U16(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for n in values {
|
||||
output.write_u16::<BigEndian>(*n).context(gen_error!(U16))?;
|
||||
}
|
||||
},
|
||||
ValueArray::S32(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for n in values {
|
||||
output.write_i32::<BigEndian>(*n).context(gen_error!(S32))?;
|
||||
}
|
||||
},
|
||||
ValueArray::U32(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for n in values {
|
||||
output.write_u32::<BigEndian>(*n).context(gen_error!(U32))?;
|
||||
}
|
||||
},
|
||||
ValueArray::S64(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for n in values {
|
||||
output.write_i64::<BigEndian>(*n).context(gen_error!(S64))?;
|
||||
}
|
||||
},
|
||||
ValueArray::U64(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for n in values {
|
||||
output.write_u64::<BigEndian>(*n).context(gen_error!(U64))?;
|
||||
}
|
||||
},
|
||||
ValueArray::Ip4(ref values) => {
|
||||
for addr in values {
|
||||
output.extend_from_slice(&addr.octets());
|
||||
}
|
||||
},
|
||||
ValueArray::Float(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for n in values {
|
||||
output.write_f32::<BigEndian>(*n).context(gen_error!(Float))?;
|
||||
}
|
||||
},
|
||||
ValueArray::Double(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for n in values {
|
||||
output.write_f64::<BigEndian>(*n).context(gen_error!(Double))?;
|
||||
}
|
||||
},
|
||||
ValueArray::Boolean(ref values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for v in values {
|
||||
output.push(if *v { 0x01 } else { 0x00 });
|
||||
}
|
||||
},
|
||||
$(
|
||||
ValueArray::$s8_konst(values) => {
|
||||
ValueArray::$konst(values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for value in values {
|
||||
for n in value.into_iter() {
|
||||
output.push(*n as u8);
|
||||
}
|
||||
value.write_kbin_bytes(output);
|
||||
}
|
||||
},
|
||||
)*
|
||||
$(
|
||||
ValueArray::$u8_konst(values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for value in values {
|
||||
for n in value.into_iter() {
|
||||
output.push(*n);
|
||||
}
|
||||
}
|
||||
},
|
||||
)*
|
||||
$(
|
||||
ValueArray::$bool_konst(values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for value in values {
|
||||
for v in value.into_iter() {
|
||||
output.push(if *v { 0x01 } else { 0x00 });
|
||||
}
|
||||
}
|
||||
},
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
ValueArray::$multi_konst(values) => {
|
||||
output.reserve(values.len() * node_size);
|
||||
for value in values {
|
||||
for v in value.into_iter() {
|
||||
output.$write_method::<BigEndian>(*v).context(gen_error!($multi_konst))?;
|
||||
}
|
||||
}
|
||||
},
|
||||
)*
|
||||
)*
|
||||
};
|
||||
|
||||
Ok(())
|
||||
@@ -361,21 +124,29 @@ macro_rules! tuple {
|
||||
|
||||
impl ValueArray {
|
||||
tuple! {
|
||||
byte: [
|
||||
s8: [S8_2, S8_3, S8_4, Vs8],
|
||||
u8: [U8_2, U8_3, U8_4, Vu8],
|
||||
bool: [Boolean2, Boolean3, Boolean4, Vb]
|
||||
],
|
||||
multi: [
|
||||
read_i16_into write_i16 i16 => [S16_2, S16_3, S16_4, Vs16],
|
||||
read_i32_into write_i32 i32 => [S32_2, S32_3, S32_4],
|
||||
read_i64_into write_i64 i64 => [S64_2, S64_3, S64_4],
|
||||
read_u16_into write_u16 u16 => [U16_2, U16_3, U16_4, Vu16],
|
||||
read_u32_into write_u32 u32 => [U32_2, U32_3, U32_4],
|
||||
read_u64_into write_u64 u64 => [U64_2, U64_3, U64_4],
|
||||
read_f32_into write_f32 f32 => [Float2, Float3, Float4],
|
||||
read_f64_into write_f64 f64 => [Double2, Double3, Double4]
|
||||
]
|
||||
S8,
|
||||
U8,
|
||||
S16,
|
||||
U16,
|
||||
S32,
|
||||
U32,
|
||||
S64,
|
||||
U64,
|
||||
Ip4,
|
||||
Float,
|
||||
Double,
|
||||
Boolean,
|
||||
S8_2, S8_3, S8_4, Vs8,
|
||||
U8_2, U8_3, U8_4, Vu8,
|
||||
Boolean2, Boolean3, Boolean4, Vb,
|
||||
S16_2, S16_3, S16_4, Vs16,
|
||||
S32_2, S32_3, S32_4,
|
||||
S64_2, S64_3, S64_4,
|
||||
U16_2, U16_3, U16_4, Vu16,
|
||||
U32_2, U32_3, U32_4,
|
||||
U64_2, U64_3, U64_4,
|
||||
Float2, Float3, Float4,
|
||||
Double2, Double3, Double4,
|
||||
}
|
||||
|
||||
pub fn standard_type(&self) -> StandardType {
|
||||
|
||||
161
src/value/mod.rs
161
src/value/mod.rs
@@ -1,15 +1,15 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
||||
use failure::{Fail, ResultExt};
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
use crate::error::{KbinError, KbinErrorKind};
|
||||
use crate::node_types::{self, StandardType};
|
||||
use crate::types::FromKbinBytes;
|
||||
use crate::types::{FromKbinBytes, IntoKbinBytes};
|
||||
|
||||
mod array;
|
||||
|
||||
@@ -147,12 +147,13 @@ macro_rules! construct_types {
|
||||
macro_rules! tuple {
|
||||
(
|
||||
byte: [
|
||||
s8: [$($s8_konst:ident),*],
|
||||
u8: [$($u8_konst:ident),*],
|
||||
int: [
|
||||
$($int_konst:ident),*$(,)?
|
||||
],
|
||||
bool: [$($bool_konst:ident),*]
|
||||
],
|
||||
multi: [
|
||||
$($read_method:ident $write_method:ident $inner_type:ty => [$($multi_konst:ident),*]),*
|
||||
$($inner_type:ty => [$($multi_konst:ident),*]),*
|
||||
]
|
||||
) => {
|
||||
pub fn from_standard_type(node_type: StandardType, is_array: bool, input: &[u8]) -> Result<Option<Value>, KbinError> {
|
||||
@@ -183,62 +184,42 @@ macro_rules! tuple {
|
||||
},
|
||||
};
|
||||
|
||||
let mut reader = Cursor::new(input);
|
||||
|
||||
let value = match node_type {
|
||||
StandardType::NodeStart |
|
||||
StandardType::NodeEnd |
|
||||
StandardType::FileEnd |
|
||||
StandardType::Attribute |
|
||||
StandardType::String => return Ok(None),
|
||||
StandardType::S8 => i8::from_kbin_bytes(input).map(Value::S8)?,
|
||||
StandardType::U8 => u8::from_kbin_bytes(input).map(Value::U8)?,
|
||||
StandardType::S16 => i16::from_kbin_bytes(input).map(Value::S16)?,
|
||||
StandardType::U16 => u16::from_kbin_bytes(input).map(Value::U16)?,
|
||||
StandardType::S32 => i32::from_kbin_bytes(input).map(Value::S32)?,
|
||||
StandardType::U32 => u32::from_kbin_bytes(input).map(Value::U32)?,
|
||||
StandardType::S64 => i64::from_kbin_bytes(input).map(Value::S64)?,
|
||||
StandardType::U64 => u64::from_kbin_bytes(input).map(Value::U64)?,
|
||||
StandardType::S8 => i8::from_kbin_bytes(&mut reader).map(Value::S8)?,
|
||||
StandardType::U8 => u8::from_kbin_bytes(&mut reader).map(Value::U8)?,
|
||||
StandardType::S16 => i16::from_kbin_bytes(&mut reader).map(Value::S16)?,
|
||||
StandardType::U16 => u16::from_kbin_bytes(&mut reader).map(Value::U16)?,
|
||||
StandardType::S32 => i32::from_kbin_bytes(&mut reader).map(Value::S32)?,
|
||||
StandardType::U32 => u32::from_kbin_bytes(&mut reader).map(Value::U32)?,
|
||||
StandardType::S64 => i64::from_kbin_bytes(&mut reader).map(Value::S64)?,
|
||||
StandardType::U64 => u64::from_kbin_bytes(&mut reader).map(Value::U64)?,
|
||||
StandardType::Binary => Value::Binary(input.to_vec()),
|
||||
StandardType::Time => u32::from_kbin_bytes(input).map(Value::Time)?,
|
||||
StandardType::Ip4 => Ipv4Addr::from_kbin_bytes(input).map(Value::Ip4)?,
|
||||
StandardType::Float => f32::from_kbin_bytes(input).map(Value::Float)?,
|
||||
StandardType::Double => f64::from_kbin_bytes(input).map(Value::Double)?,
|
||||
StandardType::Boolean => bool::from_kbin_bytes(input).map(Value::Boolean)?,
|
||||
StandardType::Time => u32::from_kbin_bytes(&mut reader).map(Value::Time)?,
|
||||
StandardType::Ip4 => Ipv4Addr::from_kbin_bytes(&mut reader).map(Value::Ip4)?,
|
||||
StandardType::Float => f32::from_kbin_bytes(&mut reader).map(Value::Float)?,
|
||||
StandardType::Double => f64::from_kbin_bytes(&mut reader).map(Value::Double)?,
|
||||
StandardType::Boolean => bool::from_kbin_bytes(&mut reader).map(Value::Boolean)?,
|
||||
$(
|
||||
StandardType::$s8_konst => {
|
||||
const COUNT: usize = node_types::$s8_konst.count;
|
||||
let mut value = [0; COUNT];
|
||||
for i in 0..COUNT {
|
||||
value[i] = input[i] as i8;
|
||||
}
|
||||
Value::$s8_konst(value)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
StandardType::$u8_konst => {
|
||||
const COUNT: usize = node_types::$u8_konst.count;
|
||||
let mut value = [0; COUNT];
|
||||
value[0..COUNT].copy_from_slice(&input[0..COUNT]);
|
||||
Value::$u8_konst(value)
|
||||
StandardType::$int_konst => {
|
||||
FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$int_konst)?
|
||||
},
|
||||
)*
|
||||
$(
|
||||
StandardType::$bool_konst => {
|
||||
const COUNT: usize = node_types::$bool_konst.count;
|
||||
let mut value: [_; COUNT] = Default::default();
|
||||
for i in 0..COUNT {
|
||||
value[i] = bool::from_kbin_bytes(&input[i..i + 1])?;
|
||||
}
|
||||
Value::$bool_konst(value)
|
||||
FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$bool_konst)?
|
||||
},
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
StandardType::$multi_konst => {
|
||||
const COUNT: usize = node_types::$multi_konst.count;
|
||||
const SIZE: usize = node_types::$multi_konst.size * COUNT;
|
||||
let mut value: [_; COUNT] = Default::default();
|
||||
BigEndian::$read_method(&input[0..SIZE], &mut value);
|
||||
Value::$multi_konst(value)
|
||||
FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$multi_konst)?
|
||||
},
|
||||
)*
|
||||
)*
|
||||
@@ -311,19 +292,11 @@ macro_rules! tuple {
|
||||
StandardType::FileEnd |
|
||||
StandardType::NodeStart => return Err(KbinErrorKind::InvalidNodeType(node_type).into()),
|
||||
$(
|
||||
StandardType::$s8_konst => {
|
||||
const COUNT: usize = node_types::$s8_konst.count;
|
||||
StandardType::$int_konst => {
|
||||
const COUNT: usize = node_types::$int_konst.count;
|
||||
let mut value = [0; COUNT];
|
||||
parse_tuple::<i8>(node_type, input, &mut value)?;
|
||||
Value::$s8_konst(value)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
StandardType::$u8_konst => {
|
||||
const COUNT: usize = node_types::$u8_konst.count;
|
||||
let mut value = [0; COUNT];
|
||||
parse_tuple::<u8>(node_type, input, &mut value)?;
|
||||
Value::$u8_konst(value)
|
||||
parse_tuple(node_type, input, &mut value)?;
|
||||
Value::$int_konst(value)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
@@ -366,27 +339,21 @@ macro_rules! tuple {
|
||||
fn to_bytes_inner(&self, output: &mut Vec<u8>) -> Result<(), KbinError> {
|
||||
debug!("Value::to_bytes_inner(self: {:?})", self);
|
||||
|
||||
macro_rules! gen_error {
|
||||
($konst:ident) => {
|
||||
KbinErrorKind::DataWrite(StandardType::$konst.name)
|
||||
};
|
||||
}
|
||||
|
||||
match self {
|
||||
Value::S8(ref n) => output.push(*n as u8),
|
||||
Value::U8(ref n) => output.push(*n),
|
||||
Value::S16(ref n) => output.write_i16::<BigEndian>(*n).context(gen_error!(S16))?,
|
||||
Value::U16(ref n) => output.write_u16::<BigEndian>(*n).context(gen_error!(U16))?,
|
||||
Value::S32(ref n) => output.write_i32::<BigEndian>(*n).context(gen_error!(S32))?,
|
||||
Value::U32(ref n) => output.write_u32::<BigEndian>(*n).context(gen_error!(U32))?,
|
||||
Value::S64(ref n) => output.write_i64::<BigEndian>(*n).context(gen_error!(S64))?,
|
||||
Value::U64(ref n) => output.write_u64::<BigEndian>(*n).context(gen_error!(U64))?,
|
||||
Value::S8(ref n) => n.write_kbin_bytes(output),
|
||||
Value::U8(ref n) => n.write_kbin_bytes(output),
|
||||
Value::S16(ref n) => n.write_kbin_bytes(output),
|
||||
Value::U16(ref n) => n.write_kbin_bytes(output),
|
||||
Value::S32(ref n) => n.write_kbin_bytes(output),
|
||||
Value::U32(ref n) => n.write_kbin_bytes(output),
|
||||
Value::S64(ref n) => n.write_kbin_bytes(output),
|
||||
Value::U64(ref n) => n.write_kbin_bytes(output),
|
||||
Value::Binary(ref data) => output.extend_from_slice(data),
|
||||
Value::Time(ref n) => output.write_u32::<BigEndian>(*n).context(gen_error!(Time))?,
|
||||
Value::Ip4(addr) => output.extend_from_slice(&addr.octets()),
|
||||
Value::Float(ref n) => output.write_f32::<BigEndian>(*n).context(gen_error!(Float))?,
|
||||
Value::Double(ref n) => output.write_f64::<BigEndian>(*n).context(gen_error!(Double))?,
|
||||
Value::Boolean(ref v) => output.push(if *v { 0x01 } else { 0x00 }),
|
||||
Value::Time(ref n) => n.write_kbin_bytes(output),
|
||||
Value::Ip4(addr) => addr.write_kbin_bytes(output),
|
||||
Value::Float(ref n) => n.write_kbin_bytes(output),
|
||||
Value::Double(ref n) => n.write_kbin_bytes(output),
|
||||
Value::Boolean(ref v) => v.write_kbin_bytes(output),
|
||||
Value::Array(_, values) => {
|
||||
for value in values {
|
||||
value.to_bytes_inner(output)?;
|
||||
@@ -396,36 +363,22 @@ macro_rules! tuple {
|
||||
Value::Attribute(_) |
|
||||
Value::String(_) => return Err(KbinErrorKind::InvalidNodeType(self.standard_type()).into()),
|
||||
$(
|
||||
Value::$s8_konst(value) => {
|
||||
Value::$int_konst(value) => {
|
||||
output.reserve(value.len());
|
||||
for n in value.into_iter() {
|
||||
output.push(*n as u8);
|
||||
}
|
||||
},
|
||||
)*
|
||||
$(
|
||||
Value::$u8_konst(value) => {
|
||||
output.reserve(value.len());
|
||||
for n in value.into_iter() {
|
||||
output.push(*n);
|
||||
}
|
||||
value.write_kbin_bytes(output);
|
||||
},
|
||||
)*
|
||||
$(
|
||||
Value::$bool_konst(value) => {
|
||||
output.reserve(value.len());
|
||||
for v in value.into_iter() {
|
||||
output.push(if *v { 0x01 } else { 0x00 });
|
||||
}
|
||||
value.write_kbin_bytes(output);
|
||||
},
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
Value::$multi_konst(value) => {
|
||||
output.reserve(value.len() * StandardType::$multi_konst.size);
|
||||
for v in value.into_iter() {
|
||||
output.$write_method::<BigEndian>(*v).context(gen_error!($multi_konst))?;
|
||||
}
|
||||
value.write_kbin_bytes(output);
|
||||
},
|
||||
)*
|
||||
)*
|
||||
@@ -439,19 +392,21 @@ macro_rules! tuple {
|
||||
impl Value {
|
||||
tuple! {
|
||||
byte: [
|
||||
s8: [S8_2, S8_3, S8_4, Vs8],
|
||||
u8: [U8_2, U8_3, U8_4, Vu8],
|
||||
int: [
|
||||
S8_2, S8_3, S8_4, Vs8,
|
||||
U8_2, U8_3, U8_4, Vu8,
|
||||
],
|
||||
bool: [Boolean2, Boolean3, Boolean4, Vb]
|
||||
],
|
||||
multi: [
|
||||
read_i16_into write_i16 i16 => [S16_2, S16_3, S16_4, Vs16],
|
||||
read_i32_into write_i32 i32 => [S32_2, S32_3, S32_4],
|
||||
read_i64_into write_i64 i64 => [S64_2, S64_3, S64_4],
|
||||
read_u16_into write_u16 u16 => [U16_2, U16_3, U16_4, Vu16],
|
||||
read_u32_into write_u32 u32 => [U32_2, U32_3, U32_4],
|
||||
read_u64_into write_u64 u64 => [U64_2, U64_3, U64_4],
|
||||
read_f32_into write_f32 f32 => [Float2, Float3, Float4],
|
||||
read_f64_into write_f64 f64 => [Double2, Double3, Double4]
|
||||
i16 => [S16_2, S16_3, S16_4, Vs16],
|
||||
i32 => [S32_2, S32_3, S32_4],
|
||||
i64 => [S64_2, S64_3, S64_4],
|
||||
u16 => [U16_2, U16_3, U16_4, Vu16],
|
||||
u32 => [U32_2, U32_3, U32_4],
|
||||
u64 => [U64_2, U64_3, U64_4],
|
||||
f32 => [Float2, Float3, Float4],
|
||||
f64 => [Double2, Double3, Double4]
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user