mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-10 03:25:14 -05:00
node_types: use Value for handling byte serialization
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "kbinxml"
|
||||
version = "0.8.0"
|
||||
version = "0.9.2"
|
||||
authors = ["Matt Bilker <me@mbilker.us>"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -65,9 +65,6 @@ pub enum KbinErrorKind {
|
||||
#[fail(display = "Unable to read array node length")]
|
||||
ArrayLengthRead,
|
||||
|
||||
#[fail(display = "Failed to write {} to output string", _0)]
|
||||
ByteParse(&'static str),
|
||||
|
||||
#[fail(display = "Unable to read sixbit string length")]
|
||||
SixbitLengthRead,
|
||||
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use byteorder::WriteBytesExt;
|
||||
use failure::ResultExt;
|
||||
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
|
||||
pub(crate) trait KbinWrapperType<T> {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError>;
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError>;
|
||||
}
|
||||
|
||||
macro_rules! number_impl {
|
||||
(int; $($inner_type:ident),*) => {
|
||||
$(
|
||||
impl KbinWrapperType<$inner_type> for $inner_type {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input);
|
||||
|
||||
let mut data = [0; ::std::mem::size_of::<$inner_type>()];
|
||||
data.clone_from_slice(input);
|
||||
write!(output, "{}", $inner_type::from_be_bytes(data))
|
||||
.context(KbinErrorKind::ByteParse(stringify!($inner_type)))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?;
|
||||
trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num);
|
||||
|
||||
let data = $inner_type::to_be_bytes(num);
|
||||
output.extend_from_slice(&data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
(float; $($intermediate:ident => $inner_type:ident),*) => {
|
||||
$(
|
||||
impl KbinWrapperType<$inner_type> for $inner_type {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input);
|
||||
|
||||
let mut data = [0; ::std::mem::size_of::<$inner_type>()];
|
||||
data.clone_from_slice(input);
|
||||
let bits = $intermediate::from_be_bytes(data);
|
||||
|
||||
write!(output, "{:.6}", $inner_type::from_bits(bits))
|
||||
.context(KbinErrorKind::ByteParse(stringify!($inner_type)))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?;
|
||||
trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num);
|
||||
|
||||
let data = $intermediate::to_be_bytes(num.to_bits());
|
||||
output.extend_from_slice(&data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
number_impl!(int; u8, u16, u32, u64);
|
||||
number_impl!(int; i8, i16, i32, i64);
|
||||
number_impl!(float; u32 => f32, u64 => f64);
|
||||
|
||||
impl KbinWrapperType<bool> for bool {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<bool> from bytes => input: {:02x?}", input);
|
||||
|
||||
let value = match input[0] {
|
||||
0x00 => "0",
|
||||
0x01 => "1",
|
||||
v => panic!("Unsupported value for boolean: {}", v),
|
||||
};
|
||||
output.push_str(value);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
let value = match input {
|
||||
"0" => 0x00,
|
||||
"1" => 0x01,
|
||||
v => panic!("Unsupported value for boolean: {}", v),
|
||||
};
|
||||
|
||||
trace!("KbinWrapperType<bool> to bytes => input: '{}', output: {}", input, value);
|
||||
output.write_u8(value).context(KbinErrorKind::DataWrite("bool"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Ip4;
|
||||
pub(crate) struct DummyConverter;
|
||||
pub(crate) struct InvalidConverter;
|
||||
|
||||
impl KbinWrapperType<Ip4> for Ip4 {
|
||||
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<Ip4> from bytes => input: {:02x?}", input);
|
||||
|
||||
if input.len() != 4 {
|
||||
panic!("Ip4 type requires exactly 4 bytes of data, input: {:02x?}", input);
|
||||
}
|
||||
|
||||
write!(output, "{}.{}.{}.{}", input[0], input[1], input[2], input[3])
|
||||
.context(KbinErrorKind::ByteParse("Ip4"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
trace!("KbinWrapperType<Ip4> to bytes => input: '{}'", input);
|
||||
|
||||
for part in input.split('.') {
|
||||
let num = part.parse::<u8>().context(KbinErrorKind::StringParse("ip4 segment"))?;
|
||||
output.write_u8(num).context(KbinErrorKind::DataWrite("ip4"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl KbinWrapperType<DummyConverter> for DummyConverter {
|
||||
fn from_kbin_bytes(_output: &mut String, _input: &[u8]) -> Result<(), KbinError> { Ok(()) }
|
||||
fn to_kbin_bytes(_output: &mut Vec<u8>, _input: &str) -> Result<(), KbinError> { Ok(()) }
|
||||
}
|
||||
|
||||
impl KbinWrapperType<InvalidConverter> for InvalidConverter {
|
||||
fn from_kbin_bytes(_output: &mut String, input: &[u8]) -> Result<(), KbinError> {
|
||||
panic!("Invalid kbin type converter called for input: {:02x?}", input);
|
||||
}
|
||||
|
||||
fn to_kbin_bytes(_output: &mut Vec<u8>, input: &str) -> Result<(), KbinError> {
|
||||
panic!("Invalid kbin type converter called for input: {}", input);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
#![feature(int_to_from_bytes)]
|
||||
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
||||
extern crate byteorder;
|
||||
@@ -27,7 +25,6 @@ mod compression;
|
||||
mod encoding_type;
|
||||
mod error;
|
||||
mod ip4;
|
||||
mod kbin_wrapper;
|
||||
mod node;
|
||||
mod node_types;
|
||||
mod options;
|
||||
@@ -227,7 +224,9 @@ impl KbinXml {
|
||||
},
|
||||
|
||||
_ => {
|
||||
let data = node_type.to_bytes(&text, count as usize)?;
|
||||
let value = Value::from_string(node_type, &text, array_mask > 0, count as usize)?;
|
||||
let data = value.to_bytes()?;
|
||||
|
||||
if array_mask > 0 {
|
||||
let total_size = (count as u32) * (node_type.count as u32) * (node_type.size as u32);
|
||||
trace!("write_node data_buf array => total_size: {}, data: 0x{:02x?}", total_size, data);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
use kbin_wrapper::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct KbinType {
|
||||
pub id: u8,
|
||||
@@ -14,106 +11,6 @@ pub struct KbinType {
|
||||
pub count: usize
|
||||
}
|
||||
|
||||
impl KbinType {
|
||||
fn parse_array<T>(&self, output: &mut String, input: &[u8], arr_count: usize) -> Result<(), KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
let total_nodes = self.count * arr_count;
|
||||
let total_size = self.size * total_nodes;
|
||||
if total_size != input.len() {
|
||||
return Err(KbinErrorKind::SizeMismatch(*self, total_size, input.len()).into());
|
||||
}
|
||||
|
||||
// Guard when the input is of zero elements
|
||||
if arr_count == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
{
|
||||
let first = &input[..self.size];
|
||||
T::from_kbin_bytes(output, first)?;
|
||||
}
|
||||
|
||||
for i in 1..total_nodes {
|
||||
let offset = i * self.size;
|
||||
let end = (i + 1) * self.size;
|
||||
let data = &input[offset..end];
|
||||
output.push(' ');
|
||||
T::from_kbin_bytes(output, data)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_bytes_inner<T>(&self, input: &[u8]) -> Result<String, KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
let type_size = self.size * self.count;
|
||||
let arr_count = input.len() / type_size;
|
||||
debug!("parse_bytes({}) => size: {}, count: {}, input_len: {}, arr_count: {}", self.name, self.size, self.count, input.len(), arr_count);
|
||||
|
||||
let mut result = String::new();
|
||||
|
||||
match self.count {
|
||||
0 => panic!("Tried to parse special type: {}", self.name),
|
||||
1 => {
|
||||
// May have a node (i.e. Ip4) that is only a single count, but it
|
||||
// can be part of an array
|
||||
if arr_count == 1 {
|
||||
T::from_kbin_bytes(&mut result, input)?;
|
||||
} else {
|
||||
self.parse_array::<T>(&mut result, input, arr_count)?;
|
||||
}
|
||||
},
|
||||
count if count > 1 => self.parse_array::<T>(&mut result, input, arr_count)?,
|
||||
_ => return Err(KbinErrorKind::InvalidState.into()),
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn to_array<T>(&self, output: &mut Vec<u8>, input: &str, arr_count: usize) -> Result<(), KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
for part in input.split(' ') {
|
||||
T::to_kbin_bytes(output, part)?;
|
||||
}
|
||||
|
||||
let type_size = self.size * self.count;
|
||||
let total_size = arr_count * type_size;
|
||||
if total_size != output.len() {
|
||||
return Err(KbinErrorKind::SizeMismatch(*self, total_size, output.len()).into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_bytes_inner<T>(&self, input: &str, arr_count: usize) -> Result<Vec<u8>, KbinError>
|
||||
where T: KbinWrapperType<T>
|
||||
{
|
||||
debug!("to_bytes_inner({}) => size: {}, count: {}, input_len: {}, arr_count: {}", self.name, self.size, self.count, input.len(), arr_count);
|
||||
|
||||
let mut output = Vec::new();
|
||||
|
||||
match self.count {
|
||||
0 => panic!("Tried to write special type: {}", self.name),
|
||||
1 => {
|
||||
// May have a node (i.e. Ip4) that is only a single count, but it
|
||||
// can be part of an array
|
||||
match arr_count {
|
||||
0 => {},
|
||||
1 => T::to_kbin_bytes(&mut output, input)?,
|
||||
_ => self.to_array::<T>(&mut output, input, arr_count)?,
|
||||
};
|
||||
},
|
||||
count if count > 1 => self.to_array::<T>(&mut output, input, arr_count)?,
|
||||
_ => return Err(KbinErrorKind::InvalidState.into()),
|
||||
};
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for KbinType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} ({})", self.konst, self.name)
|
||||
@@ -183,22 +80,6 @@ macro_rules! construct_types {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_bytes(&self, input: &[u8]) -> Result<String, KbinError> {
|
||||
match *self {
|
||||
$(
|
||||
StandardType::$konst => self.parse_bytes_inner::<$inner_type>(input),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self, input: &str, arr_count: usize) -> Result<Vec<u8>, KbinError> {
|
||||
match *self {
|
||||
$(
|
||||
StandardType::$konst => self.to_bytes_inner::<$inner_type>(input, arr_count),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
find_type! {
|
||||
S8 => [ 2 S8_2 3 S8_3 4 S8_4 ]
|
||||
U8 => [ 2 U8_2 3 U8_3 4 U8_4 ]
|
||||
|
||||
287
src/value/mod.rs
287
src/value/mod.rs
@@ -1,11 +1,14 @@
|
||||
use std::fmt;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
||||
use failure::{Fail, ResultExt};
|
||||
use rustc_hex::FromHex;
|
||||
use serde::de::{Deserialize, Deserializer, DeserializeSeed};
|
||||
use serde_bytes::ByteBuf;
|
||||
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
use node::Node;
|
||||
use node::de::NodeSeed;
|
||||
use node_types::{self, StandardType};
|
||||
@@ -21,7 +24,7 @@ macro_rules! tuple {
|
||||
bool: [$($bool_konst:ident),*]
|
||||
],
|
||||
multi: [
|
||||
$($read_method:ident => [$($multi_konst:ident),*]),*
|
||||
$($read_method:ident $write_method:ident $inner_type:ty => [$($multi_konst:ident),*]),*
|
||||
]
|
||||
) => {
|
||||
pub fn from_standard_type(node_type: StandardType, is_array: bool, input: &[u8]) -> Result<Option<Value>, KbinError> {
|
||||
@@ -31,14 +34,15 @@ macro_rules! tuple {
|
||||
let mut values = Vec::new();
|
||||
|
||||
for chunk in input.chunks(node_size) {
|
||||
trace!("chunk: {:?}", chunk);
|
||||
match Value::from_standard_type(node_type, false, chunk)? {
|
||||
Some(value) => values.push(value),
|
||||
None => return Err(KbinErrorKind::InvalidState.into()),
|
||||
}
|
||||
}
|
||||
debug!("values: {:?}", values);
|
||||
return Ok(Some(Value::Array(node_type, values)));
|
||||
let value = Value::Array(node_type, values);
|
||||
debug!("Value::from_standard_type({:?}) input: 0x{:02x?} => {:?}", node_type, input, value);
|
||||
|
||||
return Ok(Some(value));
|
||||
}
|
||||
|
||||
match node_type {
|
||||
@@ -54,7 +58,9 @@ macro_rules! tuple {
|
||||
let value = match node_type {
|
||||
StandardType::NodeStart |
|
||||
StandardType::NodeEnd |
|
||||
StandardType::FileEnd => return Ok(None),
|
||||
StandardType::FileEnd |
|
||||
StandardType::Attribute |
|
||||
StandardType::String => return Ok(None),
|
||||
StandardType::S8 => Value::S8(input[0] as i8),
|
||||
StandardType::U8 => Value::U8(input[0]),
|
||||
StandardType::S16 => Value::S16(BigEndian::read_i16(input)),
|
||||
@@ -63,8 +69,6 @@ macro_rules! tuple {
|
||||
StandardType::U32 => Value::U32(BigEndian::read_u32(input)),
|
||||
StandardType::S64 => Value::S64(BigEndian::read_i64(input)),
|
||||
StandardType::U64 => Value::U64(BigEndian::read_u64(input)),
|
||||
StandardType::Attribute |
|
||||
StandardType::String => unimplemented!(),
|
||||
StandardType::Binary => Value::Binary(input.to_vec()),
|
||||
StandardType::Time => Value::Time(BigEndian::read_u32(input)),
|
||||
StandardType::Ip4 => {
|
||||
@@ -123,9 +127,251 @@ macro_rules! tuple {
|
||||
)*
|
||||
)*
|
||||
};
|
||||
debug!("Value::from_standard_type({:?}) input: 0x{:02x?} => {:?}", node_type, input, value);
|
||||
|
||||
Ok(Some(value))
|
||||
}
|
||||
|
||||
pub fn from_string(node_type: StandardType, input: &str, is_array: bool, arr_count: usize) -> Result<Value, KbinError> {
|
||||
#[inline]
|
||||
fn parse<T>(node_type: StandardType, input: &str) -> Result<T, KbinError>
|
||||
where T: FromStr,
|
||||
T::Err: Fail
|
||||
{
|
||||
// TODO(mbilker): Add string check for spaces
|
||||
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 mut i = 0;
|
||||
for part in input.split(' ') {
|
||||
output[i] = part.parse::<T>().context(KbinErrorKind::StringParse(node_type.name))?;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if i != node_type.count {
|
||||
return Err(KbinErrorKind::SizeMismatch(*node_type, node_type.count, i).into());
|
||||
}
|
||||
|
||||
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);
|
||||
let iter = input.split(|c| {
|
||||
if c == ' ' {
|
||||
// Increment the space counter
|
||||
i += 1;
|
||||
|
||||
// If the space counter is equal to count, then split
|
||||
i == count
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
let mut values = Vec::new();
|
||||
|
||||
for part in iter {
|
||||
debug!("part: {:?}", part);
|
||||
values.push(Value::from_string(node_type, part, false, 1)?);
|
||||
}
|
||||
|
||||
Ok(Value::Array(node_type, values))
|
||||
}
|
||||
|
||||
if is_array {
|
||||
let value = match node_type.count {
|
||||
//0 => return Err(KbinErrorKind::InvalidState.into()),
|
||||
1 => {
|
||||
// May have a node (i.e. `Ip4`) that is only a single count, but it
|
||||
// can be part of an array
|
||||
match arr_count {
|
||||
0 => return Err(KbinErrorKind::InvalidState.into()),
|
||||
1 => Value::from_string(node_type, input, false, arr_count)?,
|
||||
_ => to_array(node_type, node_type.count, input, arr_count)?,
|
||||
}
|
||||
},
|
||||
count if count > 1 => to_array(node_type, count, input, arr_count)?,
|
||||
_ => return Err(KbinErrorKind::InvalidState.into()),
|
||||
};
|
||||
debug!("Value::from_string({:?}) input: {:?} => {:?}", node_type, input, value);
|
||||
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
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::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::NodeEnd |
|
||||
StandardType::FileEnd |
|
||||
StandardType::NodeStart => return Err(KbinErrorKind::InvalidNodeType(node_type).into()),
|
||||
$(
|
||||
StandardType::$s8_konst => {
|
||||
const COUNT: usize = node_types::$s8_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)
|
||||
},
|
||||
)*
|
||||
$(
|
||||
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)
|
||||
},
|
||||
)*
|
||||
)*
|
||||
};
|
||||
debug!("Value::from_string({:?}) input: {:?} => {:?}", node_type, input, value);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
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(n) => output.push(n as u8),
|
||||
Value::U8(n) => output.push(n),
|
||||
Value::S16(n) => output.write_i16::<BigEndian>(n).context(gen_error!(S16))?,
|
||||
Value::U16(n) => output.write_u16::<BigEndian>(n).context(gen_error!(U16))?,
|
||||
Value::S32(n) => output.write_i32::<BigEndian>(n).context(gen_error!(S32))?,
|
||||
Value::U32(n) => output.write_u32::<BigEndian>(n).context(gen_error!(U32))?,
|
||||
Value::S64(n) => output.write_i64::<BigEndian>(n).context(gen_error!(S64))?,
|
||||
Value::U64(n) => output.write_u64::<BigEndian>(n).context(gen_error!(U64))?,
|
||||
Value::Binary(data) => output.extend_from_slice(&data),
|
||||
Value::Time(n) => output.write_u32::<BigEndian>(n).context(gen_error!(Time))?,
|
||||
Value::Ip4(addr) => output.extend_from_slice(&addr.octets()),
|
||||
Value::Float(n) => output.write_f32::<BigEndian>(n).context(gen_error!(Float))?,
|
||||
Value::Double(n) => output.write_f64::<BigEndian>(n).context(gen_error!(Double))?,
|
||||
Value::Boolean(v) => output.push(if v { 0x01 } else { 0x00 }),
|
||||
Value::Array(_, values) => {
|
||||
for value in values {
|
||||
value.to_bytes_inner(output)?;
|
||||
}
|
||||
},
|
||||
Value::Attribute(_) |
|
||||
Value::String(_) |
|
||||
Value::Node(_) => return Err(KbinErrorKind::InvalidNodeType(self.standard_type()).into()),
|
||||
$(
|
||||
Value::$s8_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::$bool_konst(value) => {
|
||||
output.reserve(value.len());
|
||||
for v in value.into_iter() {
|
||||
output.push(if *v { 0x01 } else { 0x00 });
|
||||
}
|
||||
},
|
||||
)*
|
||||
$(
|
||||
$(
|
||||
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))?;
|
||||
}
|
||||
},
|
||||
)*
|
||||
)*
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -164,17 +410,24 @@ macro_rules! construct_types {
|
||||
bool: [Boolean2, Boolean3, Boolean4, Vb]
|
||||
],
|
||||
multi: [
|
||||
read_i16_into => [S16_2, S16_3, S16_4, Vs16],
|
||||
read_i32_into => [S32_2, S32_3, S32_4],
|
||||
read_i64_into => [S64_2, S64_3, S64_4],
|
||||
read_u16_into => [U16_2, U16_3, U16_4, Vu16],
|
||||
read_u32_into => [U32_2, U32_3, U32_4],
|
||||
read_u64_into => [U64_2, U64_3, U64_4],
|
||||
read_f32_into_unchecked => [Float2, Float3, Float4],
|
||||
read_f64_into_unchecked => [Double2, Double3, Double4]
|
||||
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_unchecked write_f32 f32 => [Float2, Float3, Float4],
|
||||
read_f64_into_unchecked write_f64 f64 => [Double2, Double3, Double4]
|
||||
]
|
||||
}
|
||||
|
||||
pub fn to_bytes(self) -> Result<Vec<u8>, KbinError> {
|
||||
let mut output = Vec::new();
|
||||
self.to_bytes_inner(&mut output)?;
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn standard_type(&self) -> StandardType {
|
||||
match *self {
|
||||
$(
|
||||
|
||||
Reference in New Issue
Block a user