Skip to content

Commit

Permalink
Update nom to the current version 7
Browse files Browse the repository at this point in the history
Closes #37, #92
  • Loading branch information
dequbed committed Nov 16, 2022
1 parent d9913dd commit ec6eca6
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 155 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -35,7 +35,7 @@ async-trait = "0.1.41"

[dependencies.lber]
path = "lber"
version = "0.3.0"
version = "0.4.0"

[features]
default = ["sync", "tls"]
Expand Down
7 changes: 3 additions & 4 deletions lber/Cargo.toml
@@ -1,15 +1,14 @@
[package]
authors = ["Gregor Reitzenstein <dean4devil@paranoidlabs.org>", "Ivan Nejgebauer <inejge@gmail.com>"]
authors = ["Nadja Reitzenstein <me@dequbed.space>", "Ivan Nejgebauer <inejge@gmail.com>"]
categories = ["encoding", "parsing"]
description = "An ASN.1/BER parser/encoder based on nom"
keywords = ["ASN1", "BER", "nom"]
license = "MIT"
name = "lber"
repository = "https://github.com/inejge/ldap3"
documentation = "https://docs.rs/ldap3"
version = "0.3.0"
version = "0.4.0"

[dependencies]
byteorder = "1"
bytes = "1"
nom = "2"
nom = "7"
7 changes: 2 additions & 5 deletions lber/src/lib.rs
@@ -1,6 +1,4 @@
extern crate byteorder;
extern crate bytes;
#[macro_use]
extern crate nom;

pub mod common;
Expand All @@ -10,6 +8,5 @@ pub mod structures;
pub mod universal;
pub mod write;

pub use nom::IResult::*;
pub use nom::{Consumer, ConsumerState, IResult, Input, Move};
pub use parse::Parser;
pub use nom::IResult;
pub use parse::Parser;
157 changes: 50 additions & 107 deletions lber/src/parse.rs
Expand Up @@ -3,148 +3,91 @@ use common::TagStructure;
use structure::{StructureTag, PL};

use nom;
use nom::Consumer;
use nom::ConsumerState;
use nom::ConsumerState::*;
use nom::IResult;
use nom::Input;
use nom::Input::*;
use nom::InputLength;
use nom::Move;

named!(class_bits<(&[u8], usize), TagClass>,
map_opt!(
take_bits!(u8, 2),
TagClass::from_u8
)
);
use nom::bits::streaming as bits;
use nom::number::streaming as number;
use nom::bytes::streaming::take;
use nom::combinator::map_opt;
use nom::{InputLength, IResult, Needed};
use nom::sequence::tuple;

fn class_bits(i: (&[u8], usize)) -> nom::IResult<(&[u8], usize), TagClass> {
map_opt(bits::take(2usize), TagClass::from_u8)(i)
}

named!(pc_bit<(&[u8], usize), TagStructure>,
map_opt!(
take_bits!(u8, 1),
TagStructure::from_u8
)
);
fn pc_bit(i: (&[u8], usize)) -> nom::IResult<(&[u8], usize), TagStructure> {
map_opt(bits::take(1usize), TagStructure::from_u8)(i)
}

named!(tagnr_bits<(&[u8], usize), u64>,
take_bits!(u64, 5)
);
fn tagnr_bits(i: (&[u8], usize)) -> nom::IResult<(&[u8], usize), u64> {
bits::take(5usize)(i)
}

named!(pub parse_type_header<(TagClass, TagStructure, u64)>, bits!(
do_parse!(
class: class_bits >>
pc: pc_bit >>
tagnr: tagnr_bits >>
((class, pc, tagnr))
)
));
fn parse_type_header(i: &[u8]) -> nom::IResult<&[u8], (TagClass, TagStructure, u64)> {
nom::bits(tuple((class_bits, pc_bit, tagnr_bits)))(i)
}

named!(pub parse_length<u64>,
alt!(
bits!(
do_parse!(
// Short length form
tag_bits!(u8, 1, 0u8) >>
len: take_bits!(u64, 7) >>
(len)
)
)
|
length_value!(
bits!(
do_parse!(
/* // TODO: Fix nom to be able to do this.
*return_error!(nom::ErrorKind::Custom(1),
* not!(tag_bits!(u8, 8, 255u8))
*) >>
*/
// Long length form
tag_bits!(u8, 1, 1u8) >>
len: take_bits!(u8, 7) >>
(len)
)
),
parse_uint
)
)
);
fn parse_length(i: &[u8]) -> nom::IResult<&[u8], u64> {
let (i, len) = number::be_u8(i)?;
if len < 128 {
Ok((i, len as u64))
} else {
let len = len - 128;
let (i, b) = take(len)(i)?;
let (_, len) = parse_uint(b)?;
Ok((i, len))
}
}

/// Extract an unsigned integer value from BER data.
pub fn parse_uint(i: &[u8]) -> nom::IResult<&[u8], u64> {
nom::IResult::Done(i, i.iter().fold(0, |res, &byte| (res << 8) | byte as u64))
Ok((i, i.iter().fold(0, |res, &byte| (res << 8) | byte as u64)))
}

/// Parse raw BER data into a serializable structure.
pub fn parse_tag(i: &[u8]) -> nom::IResult<&[u8], StructureTag> {
let (mut i, ((class, structure, id), len)) = try_parse!(
i,
do_parse!(hdr: parse_type_header >> len: parse_length >> ((hdr, len)))
);
let (mut i, ((class, structure, id), len)) = tuple((parse_type_header, parse_length))(i)?;

let pl: PL = match structure {
TagStructure::Primitive => {
let (j, content) = try_parse!(i, length_data!(value!(len)));
let (j, content) = take(len)(i)?;
i = j;

PL::P(content.to_vec())
}
TagStructure::Constructed => {
let (j, mut content) = try_parse!(i, length_bytes!(value!(len)));
let (j, mut content) = take(len)(i)?;
i = j;

let mut tv: Vec<StructureTag> = Vec::new();
while content.input_len() > 0 {
let pres = try_parse!(content, call!(parse_tag));
content = pres.0;
let res: StructureTag = pres.1;
tv.push(res);
let (j, sub) = parse_tag(content)?;
content = j;
tv.push(sub);
}

PL::C(tv)
}
};

nom::IResult::Done(
Ok((
i,
StructureTag {
class: class,
id: id,
class,
id,
payload: pl,
},
)
))
}

pub struct Parser {
state: ConsumerState<StructureTag, (), Move>,
}
pub struct Parser;

impl Parser {
pub fn new() -> Parser {
Parser {
state: Continue(Move::Consume(0)),
}
}
}

impl<'a> Consumer<&'a [u8], StructureTag, (), Move> for Parser {
fn handle(&mut self, input: Input<&[u8]>) -> &ConsumerState<StructureTag, (), Move> {
use nom::Offset;
match input {
Empty | Eof(None) => self.state(),
Element(data) | Eof(Some(data)) => {
self.state = match parse_tag(data) {
IResult::Incomplete(n) => Continue(Move::Await(n)),
IResult::Error(_) => Error(()),
IResult::Done(i, o) => Done(Move::Consume(data.offset(i)), o),
};

&self.state
}
}
pub fn new() -> Self {
Self
}

fn state(&self) -> &ConsumerState<StructureTag, (), Move> {
&self.state
pub fn parse<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], StructureTag, nom::error::Error<&'a [u8]>> {
if input.is_empty() { return Err(nom::Err::Incomplete(Needed::Unknown)) };
parse_tag(input)
}
}

Expand All @@ -167,7 +110,7 @@ mod test {

let tag = parse_tag(&bytes[..]);

assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag));
assert_eq!(tag, Ok((&rest_tag[..], result_tag)));
}

#[test]
Expand All @@ -188,7 +131,7 @@ mod test {

let tag = parse_tag(&bytes[..]);

assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag));
assert_eq!(tag, Ok((&rest_tag[..], result_tag)));
}

#[test]
Expand Down Expand Up @@ -251,6 +194,6 @@ mod test {
let rest_tag = Vec::new();

let tag = parse_tag(&bytes[..]);
assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag));
assert_eq!(tag, Ok((&rest_tag[..], result_tag)));
}
}
9 changes: 5 additions & 4 deletions lber/src/structures/integer.rs
Expand Up @@ -5,8 +5,6 @@ use universal;

use std::default;

use byteorder::{BigEndian, WriteBytesExt};

/// Integer value.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Integer {
Expand Down Expand Up @@ -40,8 +38,11 @@ fn i_e_into_structure(id: u64, class: TagClass, inner: i64) -> structure::Struct
}

let mut out: Vec<u8> = Vec::with_capacity(count as usize);

out.write_int::<BigEndian>(inner, count as usize).unwrap();
let repr = inner.to_be_bytes();
if (count as usize) > repr.len() {
out.push(0);
}
out.extend_from_slice(&repr);

structure::StructureTag {
id: id,
Expand Down
16 changes: 9 additions & 7 deletions lber/src/write.rs
@@ -1,5 +1,4 @@
//! BER encoding support.
use byteorder::{BigEndian, WriteBytesExt};
use bytes::BytesMut;
use common::{TagClass, TagStructure};
use structure::{StructureTag, PL};
Expand Down Expand Up @@ -75,7 +74,7 @@ fn write_type(w: &mut dyn Write, class: TagClass, structure: TagStructure, id: u
}
}; // let type_byte

let _ = w.write_u8(type_byte);
let _ = w.write(&[type_byte]);

if let Some(mut ext_bytes) = extended_tag {
for _ in 0..ext_bytes.len() - 1 {
Expand All @@ -84,19 +83,19 @@ fn write_type(w: &mut dyn Write, class: TagClass, structure: TagStructure, id: u
// Set the first bit
byte |= 0x80;

let _ = w.write_u8(byte);
let _ = w.write(&[byte]);
}

let byte = ext_bytes.pop().unwrap();
let _ = w.write_u8(byte);
let _ = w.write(&[byte]);
}
}

// Yes I know you could overflow the length in theory. But, do you have 2^64 bytes of memory?
fn write_length(w: &mut dyn Write, length: usize) {
// Short form
if length < 128 {
let _ = w.write_u8(length as u8);
let _ = w.write(&[length as u8]);
}
// Long form
else {
Expand All @@ -108,8 +107,11 @@ fn write_length(w: &mut dyn Write, length: usize) {
len > 0
} {}

let _ = w.write_u8(count | 0x80);
let _ = w.write_uint::<BigEndian>(length as u64, count as usize);
let _ = w.write(&[count | 0x80]);
let repr = &length.to_be_bytes();
let len = repr.len();
let bytes = &repr[(len-(count as usize))..];
let _ = w.write_all(bytes);
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/controls_impl/content_sync.rs
Expand Up @@ -107,7 +107,7 @@ pub enum EntryState {
impl ControlParser for SyncState {
fn parse(val: &[u8]) -> Self {
let mut tags = match parse_tag(val) {
IResult::Done(_, tag) => tag,
IResult::Ok((_, tag)) => tag,
_ => panic!("syncstate: failed to parse tag"),
}
.expect_constructed()
Expand All @@ -122,7 +122,7 @@ impl ControlParser for SyncState {
.expect("syncstate: state")
.as_slice(),
) {
IResult::Done(_, state) => state,
Ok((_, state)) => state,
_ => panic!("syncstate: failed to parse state"),
} {
0 => EntryState::Present,
Expand Down Expand Up @@ -157,7 +157,7 @@ pub struct SyncDone {
impl ControlParser for SyncDone {
fn parse(val: &[u8]) -> Self {
let tags = match parse_tag(val) {
IResult::Done(_, tag) => tag,
Ok((_, tag)) => tag,
_ => panic!("syncdone: failed to parse tag"),
}
.expect_constructed()
Expand Down Expand Up @@ -229,7 +229,7 @@ pub fn parse_syncinfo(entry: ResultEntry) -> SyncInfo {
Some(tag) if tag.id == 1 => {
let syncinfo_val =
match parse_tag(tag.expect_primitive().expect("octet string").as_ref()) {
IResult::Done(_, tag) => tag,
Ok((_, tag)) => tag,
_ => panic!("syncinfo: error parsing value"),
};
return match syncinfo_val {
Expand Down

0 comments on commit ec6eca6

Please sign in to comment.