mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-04-20 14:07:26 -05:00
value: add FromKbinString for trait-based kbin string parsing
This commit is contained in:
parent
b8921a157a
commit
cda8719cab
|
|
@ -221,7 +221,7 @@ impl ByteBufferWrite {
|
|||
trace!("write_aligned => old_pos: {}, size: {}, data: 0x{:02x?}", old_pos, size, data);
|
||||
|
||||
if size != data.len() {
|
||||
return Err(KbinErrorKind::SizeMismatch(data_type, size, data.len()).into());
|
||||
return Err(KbinErrorKind::SizeMismatch(data_type.name, size, data.len()).into());
|
||||
}
|
||||
|
||||
let check_old = match size {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
mod bytes;
|
||||
mod string;
|
||||
|
||||
pub use self::bytes::{FromKbinBytes, IntoKbinBytes};
|
||||
pub use self::string::FromKbinString;
|
||||
|
|
|
|||
153
src/types/string.rs
Normal file
153
src/types/string.rs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use failure::{Fail, ResultExt};
|
||||
|
||||
use crate::error::{KbinError, KbinErrorKind};
|
||||
|
||||
/*
|
||||
pub trait IntoKbinString {
|
||||
fn write_kbin_string(self, output: &mut String);
|
||||
}
|
||||
*/
|
||||
|
||||
pub trait FromKbinString: Sized {
|
||||
fn from_kbin_string(input: &str) -> Result<Self, KbinError>;
|
||||
}
|
||||
|
||||
fn space_check(input: &str) -> Result<(), KbinError> {
|
||||
// check for space character
|
||||
if input.find(' ').is_some() {
|
||||
return Err(KbinErrorKind::InvalidState.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_tuple<T>(node_type: &'static str, input: &str, output: &mut [T]) -> Result<(), KbinError>
|
||||
where T: FromStr,
|
||||
T::Err: Fail
|
||||
{
|
||||
let count = input.split(' ').count();
|
||||
if count != output.len() {
|
||||
return Err(KbinErrorKind::SizeMismatch(node_type, output.len(), count).into());
|
||||
}
|
||||
|
||||
for (i, part) in input.split(' ').enumerate() {
|
||||
output[i] = part.parse::<T>().context(KbinErrorKind::StringParse(node_type))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl FromKbinString for bool {
|
||||
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
|
||||
match input {
|
||||
"0" => Ok(false),
|
||||
"1" => Ok(true),
|
||||
input => Err(KbinErrorKind::InvalidBooleanInput(u8::from_kbin_string(input)?).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromKbinString for Ipv4Addr {
|
||||
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
|
||||
space_check(input)?;
|
||||
|
||||
let count = input.split('.').count();
|
||||
if count != 4 {
|
||||
return Err(KbinErrorKind::SizeMismatch("Ipv4Addr", 4, count).into());
|
||||
}
|
||||
|
||||
let mut octets = [0; 4];
|
||||
|
||||
// IP addresses are split by a period, so do not use `parse_tuple`
|
||||
for (i, part) in input.split('.').enumerate() {
|
||||
octets[i] = part.parse::<u8>().context(KbinErrorKind::StringParse("Ipv4Addr"))?;
|
||||
}
|
||||
|
||||
Ok(Ipv4Addr::from(octets))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! basic_parse {
|
||||
(
|
||||
$($type:ty),*$(,)?
|
||||
) => {
|
||||
$(
|
||||
impl FromKbinString for $type {
|
||||
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
|
||||
space_check(input)?;
|
||||
|
||||
input.parse::<$type>().context(KbinErrorKind::StringParse(stringify!($type))).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! tuple_parse {
|
||||
(
|
||||
bool: [$($bool_count:expr),*],
|
||||
multi: [
|
||||
$([$type:ident ; $($count:expr),*]),*$(,)?
|
||||
]
|
||||
) => {
|
||||
$(
|
||||
impl FromKbinString for [bool; $bool_count] {
|
||||
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
|
||||
const TYPE_NAME: &'static str = concat!("[bool; ", stringify!($bool_count), "]");
|
||||
|
||||
let count = input.split(' ').count();
|
||||
if count != $bool_count {
|
||||
return Err(KbinErrorKind::SizeMismatch(TYPE_NAME, $bool_count, count).into());
|
||||
}
|
||||
|
||||
let mut value = Self::default();
|
||||
|
||||
for (i, part) in input.split(' ').enumerate() {
|
||||
value[i] = bool::from_kbin_string(part)?;
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
impl FromKbinString for [$type; $count] {
|
||||
fn from_kbin_string(input: &str) -> Result<Self, KbinError> {
|
||||
let mut value = Self::default();
|
||||
parse_tuple(concat!("[", stringify!($type), "; ", stringify!($count), "]"), input, &mut value)?;
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
)*
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
basic_parse! {
|
||||
i8, u8,
|
||||
i16, u16,
|
||||
i32, u32,
|
||||
i64, u64,
|
||||
f32, f64,
|
||||
}
|
||||
|
||||
tuple_parse! {
|
||||
bool: [2, 3, 4, 16],
|
||||
multi: [
|
||||
[i8; 2, 3, 4, 16],
|
||||
[u8; 2, 3, 4, 16],
|
||||
[i16; 2, 3, 4, 8],
|
||||
[u16; 2, 3, 4, 8],
|
||||
[i32; 2, 3, 4],
|
||||
[u32; 2, 3, 4],
|
||||
[i64; 2, 3, 4],
|
||||
[u64; 2, 3, 4],
|
||||
[f32; 2, 3, 4],
|
||||
[f64; 2, 3, 4],
|
||||
]
|
||||
}
|
||||
|
|
@ -68,13 +68,13 @@ macro_rules! type_impl {
|
|||
(
|
||||
$($konst:ident),*$(,)?
|
||||
) => {
|
||||
pub fn from_standard_type(node_type: StandardType, input: &[u8]) -> Result<Option<ValueArray>, KbinError> {
|
||||
pub fn from_standard_type(node_type: StandardType, input: &[u8]) -> Result<Option<Self>, KbinError> {
|
||||
let node_size = node_type.size * node_type.count;
|
||||
let len = input.len() / node_size;
|
||||
|
||||
// Prevent reading incomplete input data
|
||||
if node_size * len != input.len() {
|
||||
return Err(KbinErrorKind::SizeMismatch(*node_type, node_size, input.len()).into());
|
||||
return Err(KbinErrorKind::SizeMismatch(node_type.name, node_size, input.len()).into());
|
||||
}
|
||||
|
||||
let mut reader = Cursor::new(input);
|
||||
|
|
@ -140,14 +140,10 @@ macro_rules! type_impl {
|
|||
|
||||
impl ValueArray {
|
||||
type_impl! {
|
||||
S8,
|
||||
U8,
|
||||
S16,
|
||||
U16,
|
||||
S32,
|
||||
U32,
|
||||
S64,
|
||||
U64,
|
||||
S8, U8,
|
||||
S16, U16,
|
||||
S32, U32,
|
||||
S64, U64,
|
||||
Ip4,
|
||||
Float,
|
||||
Double,
|
||||
|
|
|
|||
221
src/value/mod.rs
221
src/value/mod.rs
|
|
@ -2,50 +2,18 @@ use std::convert::TryFrom;
|
|||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use failure::{Fail, ResultExt};
|
||||
use failure::ResultExt;
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
use crate::error::{KbinError, KbinErrorKind};
|
||||
use crate::node_types::{self, StandardType};
|
||||
use crate::types::{FromKbinBytes, IntoKbinBytes};
|
||||
use crate::node_types::StandardType;
|
||||
use crate::types::{FromKbinBytes, FromKbinString, IntoKbinBytes};
|
||||
|
||||
mod array;
|
||||
|
||||
pub use self::array::ValueArray;
|
||||
|
||||
#[inline]
|
||||
fn parse<T>(node_type: StandardType, input: &str) -> Result<T, KbinError>
|
||||
where T: FromStr,
|
||||
T::Err: Fail
|
||||
{
|
||||
// Check for space character
|
||||
if input.find(' ').is_some() {
|
||||
return Err(KbinErrorKind::InvalidState.into());
|
||||
}
|
||||
|
||||
let n = input.parse::<T>().context(KbinErrorKind::StringParse(node_type.name))?;
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parse_tuple<T>(node_type: StandardType, input: &str, output: &mut [T]) -> Result<(), KbinError>
|
||||
where T: FromStr,
|
||||
T::Err: Fail
|
||||
{
|
||||
let count = input.split(' ').count();
|
||||
if count != node_type.count {
|
||||
return Err(KbinErrorKind::SizeMismatch(*node_type, node_type.count, count).into());
|
||||
}
|
||||
|
||||
for (i, part) in input.split(' ').enumerate() {
|
||||
output[i] = part.parse::<T>().context(KbinErrorKind::StringParse(node_type.name))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_array(node_type: StandardType, count: usize, input: &str, arr_count: usize) -> Result<Value, KbinError> {
|
||||
let mut i = 0;
|
||||
trace!("to_array(count: {}, input: {:?}, arr_count: {})", count, input, arr_count);
|
||||
|
|
@ -146,15 +114,7 @@ macro_rules! construct_types {
|
|||
|
||||
macro_rules! tuple {
|
||||
(
|
||||
byte: [
|
||||
int: [
|
||||
$($int_konst:ident),*$(,)?
|
||||
],
|
||||
bool: [$($bool_konst:ident),*]
|
||||
],
|
||||
multi: [
|
||||
$($inner_type:ty => [$($multi_konst:ident),*]),*
|
||||
]
|
||||
$($konst:ident),*$(,)?
|
||||
) => {
|
||||
pub fn from_standard_type(node_type: StandardType, is_array: bool, input: &[u8]) -> Result<Option<Value>, KbinError> {
|
||||
let node_size = node_type.size * node_type.count;
|
||||
|
|
@ -174,7 +134,7 @@ macro_rules! tuple {
|
|||
StandardType::Binary => {},
|
||||
_ => {
|
||||
if input.len() != node_size {
|
||||
return Err(KbinErrorKind::SizeMismatch(*node_type, node_size, input.len()).into());
|
||||
return Err(KbinErrorKind::SizeMismatch(node_type.name, node_size, input.len()).into());
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
@ -202,22 +162,10 @@ macro_rules! tuple {
|
|||
StandardType::Double => f64::from_kbin_bytes(&mut reader).map(Value::Double)?,
|
||||
StandardType::Boolean => bool::from_kbin_bytes(&mut reader).map(Value::Boolean)?,
|
||||
$(
|
||||
StandardType::$int_konst => {
|
||||
FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$int_konst)?
|
||||
StandardType::$konst => {
|
||||
FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$konst)?
|
||||
},
|
||||
)*
|
||||
$(
|
||||
StandardType::$bool_konst => {
|
||||
FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$bool_konst)?
|
||||
},
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
StandardType::$multi_konst => {
|
||||
FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$multi_konst)?
|
||||
},
|
||||
)*
|
||||
)*
|
||||
};
|
||||
debug!("Value::from_standard_type({:?}) input: 0x{:02x?} => {:?}", node_type, input, value);
|
||||
|
||||
|
|
@ -245,85 +193,30 @@ macro_rules! tuple {
|
|||
}
|
||||
|
||||
let value = match node_type {
|
||||
StandardType::S8 => Value::S8(parse::<i8>(node_type, input)?),
|
||||
StandardType::U8 => Value::U8(parse::<u8>(node_type, input)?),
|
||||
StandardType::S16 => Value::S16(parse::<i16>(node_type, input)?),
|
||||
StandardType::U16 => Value::U16(parse::<u16>(node_type, input)?),
|
||||
StandardType::S32 => Value::S32(parse::<i32>(node_type, input)?),
|
||||
StandardType::U32 => Value::U32(parse::<u32>(node_type, input)?),
|
||||
StandardType::S64 => Value::S64(parse::<i64>(node_type, input)?),
|
||||
StandardType::U64 => Value::U64(parse::<u64>(node_type, input)?),
|
||||
StandardType::S8 => i8::from_kbin_string(input).map(Value::S8)?,
|
||||
StandardType::U8 => u8::from_kbin_string(input).map(Value::U8)?,
|
||||
StandardType::S16 => i16::from_kbin_string(input).map(Value::S16)?,
|
||||
StandardType::U16 => u16::from_kbin_string(input).map(Value::U16)?,
|
||||
StandardType::S32 => i32::from_kbin_string(input).map(Value::S32)?,
|
||||
StandardType::U32 => u32::from_kbin_string(input).map(Value::U32)?,
|
||||
StandardType::S64 => i64::from_kbin_string(input).map(Value::S64)?,
|
||||
StandardType::U64 => u64::from_kbin_string(input).map(Value::U64)?,
|
||||
StandardType::Binary => {
|
||||
let data: Vec<u8> = input.from_hex().context(KbinErrorKind::HexError)?;
|
||||
Value::Binary(data)
|
||||
},
|
||||
StandardType::String => Value::String(input.to_owned()),
|
||||
StandardType::Attribute => Value::Attribute(input.to_owned()),
|
||||
StandardType::Ip4 => {
|
||||
let mut i = 0;
|
||||
let mut octets = [0; 4];
|
||||
|
||||
// IP Addresses are split by a period, don't use `parse_tuple`
|
||||
for part in input.split('.') {
|
||||
octets[i] = parse::<u8>(node_type, part)?;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if i != 4 {
|
||||
return Err(KbinErrorKind::SizeMismatch(*node_type, 4, i).into());
|
||||
}
|
||||
|
||||
Value::Ip4(Ipv4Addr::from(octets))
|
||||
},
|
||||
StandardType::Time => Value::Time(parse::<u32>(node_type, input)?),
|
||||
StandardType::Float => Value::Float(parse::<f32>(node_type, input)?),
|
||||
StandardType::Double => Value::Double(parse::<f64>(node_type, input)?),
|
||||
StandardType::Boolean => Value::Boolean(match input {
|
||||
"0" => false,
|
||||
"1" => true,
|
||||
v => return Err(KbinErrorKind::InvalidBooleanInput(parse::<u8>(node_type, v)?).into()),
|
||||
}),
|
||||
StandardType::Ip4 => Ipv4Addr::from_kbin_string(input).map(Value::Ip4)?,
|
||||
StandardType::Time => u32::from_kbin_string(input).map(Value::Time)?,
|
||||
StandardType::Float => f32::from_kbin_string(input).map(Value::Float)?,
|
||||
StandardType::Double => f64::from_kbin_string(input).map(Value::Double)?,
|
||||
StandardType::Boolean => bool::from_kbin_string(input).map(Value::Boolean)?,
|
||||
StandardType::NodeEnd |
|
||||
StandardType::FileEnd |
|
||||
StandardType::NodeStart => return Err(KbinErrorKind::InvalidNodeType(node_type).into()),
|
||||
$(
|
||||
StandardType::$int_konst => {
|
||||
const COUNT: usize = node_types::$int_konst.count;
|
||||
let mut value = [0; COUNT];
|
||||
parse_tuple(node_type, input, &mut value)?;
|
||||
Value::$int_konst(value)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
StandardType::$bool_konst => {
|
||||
const COUNT: usize = node_types::$bool_konst.count;
|
||||
let mut i = 0;
|
||||
let mut value: [_; COUNT] = Default::default();
|
||||
for part in input.split(' ') {
|
||||
value[i] = match part {
|
||||
"0" => false,
|
||||
"1" => true,
|
||||
v => return Err(KbinErrorKind::InvalidBooleanInput(parse::<u8>(node_type, v)?).into()),
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if i != COUNT {
|
||||
return Err(KbinErrorKind::SizeMismatch(*node_type, COUNT, i).into());
|
||||
}
|
||||
|
||||
Value::$bool_konst(value)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
StandardType::$multi_konst => {
|
||||
const COUNT: usize = node_types::$multi_konst.count;
|
||||
let mut value: [_; COUNT] = Default::default();
|
||||
parse_tuple::<$inner_type>(node_type, input, &mut value)?;
|
||||
Value::$multi_konst(value)
|
||||
},
|
||||
)*
|
||||
StandardType::$konst => FromKbinString::from_kbin_string(input).map(Value::$konst)?,
|
||||
)*
|
||||
};
|
||||
debug!("Value::from_string({:?}) input: {:?} => {:?}", node_type, input, value);
|
||||
|
|
@ -335,20 +228,20 @@ macro_rules! tuple {
|
|||
debug!("Value::to_bytes_inner(self: {:?})", self);
|
||||
|
||||
match self {
|
||||
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) => n.write_kbin_bytes(output),
|
||||
Value::S8(n) => n.write_kbin_bytes(output),
|
||||
Value::U8(n) => n.write_kbin_bytes(output),
|
||||
Value::S16(n) => n.write_kbin_bytes(output),
|
||||
Value::U16(n) => n.write_kbin_bytes(output),
|
||||
Value::S32(n) => n.write_kbin_bytes(output),
|
||||
Value::U32(n) => n.write_kbin_bytes(output),
|
||||
Value::S64(n) => n.write_kbin_bytes(output),
|
||||
Value::U64(n) => n.write_kbin_bytes(output),
|
||||
Value::Binary(data) => output.extend_from_slice(data),
|
||||
Value::Time(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::Float(n) => n.write_kbin_bytes(output),
|
||||
Value::Double(n) => n.write_kbin_bytes(output),
|
||||
Value::Boolean(v) => v.write_kbin_bytes(output),
|
||||
Value::Array(_, values) => {
|
||||
for value in values {
|
||||
value.to_bytes_inner(output)?;
|
||||
|
|
@ -358,25 +251,11 @@ macro_rules! tuple {
|
|||
Value::Attribute(_) |
|
||||
Value::String(_) => return Err(KbinErrorKind::InvalidNodeType(self.standard_type()).into()),
|
||||
$(
|
||||
Value::$int_konst(value) => {
|
||||
output.reserve(value.len());
|
||||
Value::$konst(value) => {
|
||||
output.reserve(value.len() * StandardType::$konst.size);
|
||||
value.write_kbin_bytes(output);
|
||||
},
|
||||
)*
|
||||
$(
|
||||
Value::$bool_konst(value) => {
|
||||
output.reserve(value.len());
|
||||
value.write_kbin_bytes(output);
|
||||
},
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
Value::$multi_konst(value) => {
|
||||
output.reserve(value.len() * StandardType::$multi_konst.size);
|
||||
value.write_kbin_bytes(output);
|
||||
},
|
||||
)*
|
||||
)*
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
@ -386,23 +265,17 @@ macro_rules! tuple {
|
|||
|
||||
impl Value {
|
||||
tuple! {
|
||||
byte: [
|
||||
int: [
|
||||
S8_2, S8_3, S8_4, Vs8,
|
||||
U8_2, U8_3, U8_4, Vu8,
|
||||
],
|
||||
bool: [Boolean2, Boolean3, Boolean4, Vb]
|
||||
],
|
||||
multi: [
|
||||
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]
|
||||
]
|
||||
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 to_bytes(&self) -> Result<Vec<u8>, KbinError> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user