From 6ae41637b48d4e52c4741a9d4388f0329c873053 Mon Sep 17 00:00:00 2001 From: Michael Watzko Date: Thu, 30 Apr 2020 16:12:38 +0200 Subject: [PATCH] Support OCTET STRING in declarativ notation #11 --- asn1rs-macros/src/ast/mod.rs | 1 + src/syn/io/println.rs | 10 +++++++- src/syn/io/uper.rs | 22 +++++++++++++++++ src/syn/mod.rs | 9 +++++++ src/syn/octetstring.rs | 37 +++++++++++++++++++++++++++++ tests/basic_proc_macro_attribute.rs | 22 +++++++++++++++++ 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/syn/octetstring.rs diff --git a/asn1rs-macros/src/ast/mod.rs b/asn1rs-macros/src/ast/mod.rs index 849f40e3..1523838c 100644 --- a/asn1rs-macros/src/ast/mod.rs +++ b/asn1rs-macros/src/ast/mod.rs @@ -241,6 +241,7 @@ impl Parse for Asn { let ident = input.step(|c| c.ident().ok_or_else(|| c.error("Expected ASN-Type")))?; match ident.to_string().to_lowercase().as_str() { "utf8string" if first => asn.r#type = Some(Type::UTF8String), + "octet_string" if first => asn.r#type = Some(Type::OctetString), "integer" if first => { let range = MaybeRanged::parse(input)?; asn.r#type = Some(Type::Integer(range.0.map(|(min, max)| Range(min, max)))); diff --git a/src/syn/io/println.rs b/src/syn/io/println.rs index 5687d0cc..9b694c23 100644 --- a/src/syn/io/println.rs +++ b/src/syn/io/println.rs @@ -4,7 +4,7 @@ use crate::prelude::*; pub struct PrintlnWriter(usize); impl PrintlnWriter { - fn indented_println(&self, text: &str) { + fn indented_println(&self, text: T) { println!("{}{}", " ".repeat(self.0), text); } @@ -109,4 +109,12 @@ impl Writer for PrintlnWriter { )); Ok(()) } + + fn write_octet_string( + &mut self, + value: &[u8], + ) -> Result<(), Self::Error> { + self.indented_println(format!("WRITING OctetString {:?}", value)); + Ok(()) + } } diff --git a/src/syn/io/uper.rs b/src/syn/io/uper.rs index f9229fcd..099b92b7 100644 --- a/src/syn/io/uper.rs +++ b/src/syn/io/uper.rs @@ -115,6 +115,14 @@ impl Writer for UperWriter { ) -> Result<(), Self::Error> { self.buffer.write_utf8_string(value) } + + fn write_octet_string( + &mut self, + value: &[u8], + ) -> Result<(), Self::Error> { + self.buffer + .write_octet_string(value, bit_buffer_range::()) + } } pub struct UperReader { @@ -219,4 +227,18 @@ impl Reader for UperReader { fn read_utf8string(&mut self) -> Result { self.buffer.read_utf8_string() } + + fn read_octet_string(&mut self) -> Result, Self::Error> { + self.buffer.read_octet_string(bit_buffer_range::()) + } +} + +fn bit_buffer_range() -> Option<(i64, i64)> { + match (C::MIN, C::MAX) { + (None, None) => None, + (min, max) => Some(( + min.unwrap_or(0) as i64, + max.unwrap_or(std::i64::MAX as usize) as i64, // TODO never verified! + )), + } } diff --git a/src/syn/mod.rs b/src/syn/mod.rs index f0bad910..fb56021a 100644 --- a/src/syn/mod.rs +++ b/src/syn/mod.rs @@ -5,6 +5,7 @@ pub mod complex; pub mod enumerated; pub mod io; pub mod numbers; +pub mod octetstring; pub mod optional; pub mod sequence; pub mod utf8string; @@ -13,6 +14,7 @@ pub use choice::Choice; pub use complex::Complex; pub use enumerated::Enumerated; pub use numbers::Integer; +pub use octetstring::OctetString; pub use sequence::Sequence; pub use utf8string::Utf8String; @@ -46,6 +48,8 @@ pub trait Reader { fn read_int_max(&mut self) -> Result; fn read_utf8string(&mut self) -> Result; + + fn read_octet_string(&mut self) -> Result, Self::Error>; } pub trait Readable: Sized { @@ -102,6 +106,11 @@ pub trait Writer { &mut self, value: &str, ) -> Result<(), Self::Error>; + + fn write_octet_string( + &mut self, + value: &[u8], + ) -> Result<(), Self::Error>; } pub trait Writable { diff --git a/src/syn/octetstring.rs b/src/syn/octetstring.rs new file mode 100644 index 00000000..4a1f01ce --- /dev/null +++ b/src/syn/octetstring.rs @@ -0,0 +1,37 @@ +use crate::syn::{ReadableType, Reader, WritableType, Writer}; +use core::marker::PhantomData; + +pub struct OctetString(PhantomData); + +impl Default for OctetString { + fn default() -> Self { + Self(Default::default()) + } +} + +pub trait Constraint { + const MIN: Option = None; + const MAX: Option = None; +} + +#[derive(Default)] +pub struct NoConstraint; +impl Constraint for NoConstraint {} + +impl WritableType for OctetString { + type Type = Vec; + + #[inline] + fn write_value(writer: &mut W, value: &Self::Type) -> Result<(), W::Error> { + writer.write_octet_string::(value.as_slice()) + } +} + +impl ReadableType for OctetString { + type Type = Vec; + + #[inline] + fn read_value(reader: &mut R) -> Result::Error> { + reader.read_octet_string::() + } +} diff --git a/tests/basic_proc_macro_attribute.rs b/tests/basic_proc_macro_attribute.rs index 7b822d76..fcac9101 100644 --- a/tests/basic_proc_macro_attribute.rs +++ b/tests/basic_proc_macro_attribute.rs @@ -231,3 +231,25 @@ BEGIN END */ + +#[asn(sequence)] +#[derive(Debug, PartialOrd, PartialEq)] +pub struct AreWeBinaryYet { + #[asn(octet_string)] + binary: Vec, +} + +#[test] +fn are_we_binary_yet_uper() { + let mut uper = UperWriter::default(); + let are_we = AreWeBinaryYet { + binary: vec![0x13, 0x37], + }; + uper.write(&are_we).unwrap(); + // https://asn1.io/asn1playground/ + assert_eq!(&[02, 0x13, 0x37], uper.byte_content()); + assert_eq!(3 * 8, uper.bit_len()); + let mut uper = uper.into_reader(); + assert_eq!(are_we, uper.read::().unwrap()); + assert_eq!(0, uper.bits_remaining()); +}