mirror of https://github.com/briansmith/webpki
107 lines
3.5 KiB
Rust
107 lines
3.5 KiB
Rust
// Copyright 2015 Brian Smith.
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
/// Calls `read` with the given input as a `Reader`, ensuring that `read`
|
|
/// consumed the entire input. If `read` does not consume the entire input,
|
|
/// `incomplete_read` is returned.
|
|
pub fn read_all<'a, F, R, E>(input: Input<'a>, incomplete_read: E, read: F)
|
|
-> Result<R, E>
|
|
where F: FnOnce(&mut Reader<'a>) -> Result<R, E> {
|
|
let mut input = Reader::new(input);
|
|
let result = try!(read(&mut input));
|
|
if input.at_end() {
|
|
Ok(result)
|
|
} else {
|
|
Err(incomplete_read)
|
|
}
|
|
}
|
|
|
|
/// Calls `read` with the given input as a `Reader`, ensuring that `read`
|
|
/// consumed the entire input. When `input` is `None`, `read` will be called
|
|
/// with `None`.
|
|
pub fn read_all_optional<'a, F, R, E>(input: Option<Input<'a>>,
|
|
incomplete_read: E, read: F)
|
|
-> Result<R, E>
|
|
where F: FnOnce(Option<&mut Reader>)
|
|
-> Result<R, E> {
|
|
match input {
|
|
Some(input) => {
|
|
let mut input = Reader::new(input);
|
|
let result = try!(read(Option::Some(&mut input)));
|
|
if input.at_end() {
|
|
Ok(result)
|
|
} else {
|
|
Err(incomplete_read)
|
|
}
|
|
},
|
|
None => read(Option::None)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
pub struct Input<'a> {
|
|
bytes: &'a [u8]
|
|
}
|
|
|
|
impl<'a> Input<'a> {
|
|
pub fn new(bytes: &'a [u8]) -> Option<Input<'a>> {
|
|
// This limit is important for avoiding integer overflow. In particular,
|
|
// `Reader` assumes that an `i + 1 > i` if `input.bytes.get(i)` does
|
|
// not return `None`.
|
|
if bytes.len() > 0xFFFF {
|
|
return None
|
|
}
|
|
Some(Input { bytes: bytes })
|
|
}
|
|
}
|
|
|
|
pub struct Reader<'a> {
|
|
input: Input<'a>,
|
|
i: usize
|
|
}
|
|
|
|
impl<'a> Reader<'a> {
|
|
pub fn new(input: Input<'a>) -> Reader<'a> {
|
|
Reader {
|
|
input: input,
|
|
i: 0
|
|
}
|
|
}
|
|
|
|
pub fn at_end(&self) -> bool { self.i == self.input.bytes.len() }
|
|
|
|
pub fn read_byte(&mut self) -> Option<u8> {
|
|
match self.input.bytes.get(self.i) {
|
|
Some(b) => {
|
|
self.i += 1; // safe from overflow; see Input::new.
|
|
Some(*b)
|
|
}
|
|
None => None
|
|
}
|
|
}
|
|
|
|
pub fn skip_and_get_input(&mut self, num_bytes: usize)
|
|
-> Option<Input<'a>> {
|
|
match self.i.checked_add(num_bytes) {
|
|
Some(new_i) if new_i <= self.input.bytes.len() => {
|
|
let ret =
|
|
Some(Input { bytes: &self.input.bytes[self.i..new_i] });
|
|
self.i = new_i;
|
|
ret
|
|
},
|
|
_ => None
|
|
}
|
|
}
|
|
}
|