diff --git a/Cargo.toml b/Cargo.toml index 29bf08c..a634e43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kbinxml" -version = "0.3.0" +version = "0.4.0" authors = ["Matt Bilker "] [dependencies] diff --git a/src/bin/kbinxml.rs b/src/bin/kbinxml.rs index 7244281..a873cef 100644 --- a/src/bin/kbinxml.rs +++ b/src/bin/kbinxml.rs @@ -11,10 +11,11 @@ extern crate quick_xml; use std::env; use std::fs::File; use std::io::{Cursor, Error as IoError, ErrorKind as IoErrorKind, Read, Write, stdout}; +use std::net::Ipv4Addr; use std::str; use failure::Fail; -use kbinxml::{KbinXml, Options, from_bytes, to_bytes}; +use kbinxml::{Ip4Addr, KbinXml, Options, from_bytes, to_bytes}; use minidom::Element; use quick_xml::Writer; @@ -24,6 +25,9 @@ pub struct Testing2 { hi: u16, ho: i16, vu: Vec, + opt: Option, + opt2: Option, + ip: Ip4Addr, } #[derive(Debug, Deserialize, Serialize)] @@ -154,6 +158,9 @@ fn main() -> std::io::Result<()> { hi: 32423, ho: 32000, vu: vec![33, 255, 254], + opt: None, + opt2: Some(111), + ip: Ip4Addr::new(Ipv4Addr::new(127, 0, 0, 1)), }, }; let bytes = to_bytes(&obj).unwrap(); diff --git a/src/ip4.rs b/src/ip4.rs new file mode 100644 index 0000000..ae77194 --- /dev/null +++ b/src/ip4.rs @@ -0,0 +1,87 @@ +use std::fmt; +use std::net::Ipv4Addr; +use std::ops::{Deref, DerefMut}; + +use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; +use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; + +pub struct Ip4Addr(Ipv4Addr); + +struct Ip4Visitor; + +impl Ip4Addr { + pub fn new(addr: Ipv4Addr) -> Self { + Ip4Addr(addr) + } +} + +impl fmt::Display for Ip4Addr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl fmt::Debug for Ip4Addr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl Deref for Ip4Addr { + type Target = Ipv4Addr; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Ip4Addr { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl<'de> Visitor<'de> for Ip4Visitor { + type Value = [u8; 4]; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a sequence of 4 bytes with no size indicator") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: SeqAccess<'de> + { + trace!("Ip4Addr::visit_seq()"); + let v1: u8 = seq.next_element()?.unwrap(); + let v2: u8 = seq.next_element()?.unwrap(); + let v3: u8 = seq.next_element()?.unwrap(); + let v4: u8 = seq.next_element()?.unwrap(); + trace!("Ip4Addr:visit_seq() => [{}, {}, {}, {}]", v1, v2, v3, v4); + Ok([v1, v2, v3, v4]) + } +} + +impl<'de> Deserialize<'de> for Ip4Addr { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + deserializer.deserialize_tuple_struct("ip4", 4, Ip4Visitor) + .map(|v| { + Ip4Addr(Ipv4Addr::from(v)) + }) + } +} + +impl Serialize for Ip4Addr { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + let octets = self.0.octets(); + let mut ts = serializer.serialize_tuple_struct("ip4", 4)?; + ts.serialize_field(&octets[0])?; + ts.serialize_field(&octets[1])?; + ts.serialize_field(&octets[2])?; + ts.serialize_field(&octets[3])?; + ts.end() + } +} diff --git a/src/lib.rs b/src/lib.rs index c288cac..bcdf501 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ mod byte_buffer; mod compression; mod encoding_type; mod error; +mod ip4; mod node_types; mod options; mod sixbit; @@ -43,6 +44,7 @@ pub use encoding_type::EncodingType; pub use error::{KbinError, KbinErrorKind, Result}; pub use options::Options; pub use de::from_bytes; +pub use ip4::Ip4Addr; pub use ser::to_bytes; const SIGNATURE: u8 = 0xA0;