From 112e7da3f300ea06b3c445daf1318ec7ef7bc901 Mon Sep 17 00:00:00 2001 From: Tangent 128 Date: Thu, 12 Jan 2017 00:41:35 -0500 Subject: [PATCH] Implement EBML varint parser --- src/lib.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 9194270..4e305b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,72 @@ extern crate futures; +#[derive(Debug, PartialEq)] +pub enum Error { + CorruptVarint +} + +#[derive(Debug, PartialEq)] +pub enum EbmlVarint { + Value(u64), + Unknown +} + +/// Try to parse an EBML varint starting at the start of the given slice. +/// Returns an Err() if the format is corrupt. +/// Returns Ok(None) if more bytes are needed to get a result. +/// Returns Ok(Some((varint, next))) to return a varint value and +/// the starting location fo the next +pub fn decode_varint(bytes: &[u8]) -> Result, Error> { + let mut value: u64 = 0; + let mut value_length = 1; + let mut mask: u8 = 0x80; + let mut unknown_marker: u64 = !0; + + if bytes.len() == 0 { + return Ok(None) + } + + // get length marker bit from first byte & parse first byte + while mask > 0 { + if (mask & bytes[0]) != 0 { + value = (bytes[0] & !mask) as u64; + unknown_marker = (mask - 1) as u64; + break + } + value_length += 1; + mask = mask >> 1; + } + + if mask == 0 { + return Err(Error::CorruptVarint) + } + + // check we have enough data to parse + if value_length > bytes.len() { + return Ok(None) + } + + // decode remaining bytes + for i in 1..value_length { + value = (value << 8) + (bytes[i] as u64); + unknown_marker = (unknown_marker << 8) + 0xFF; + } + + // determine result + if value == unknown_marker { + Ok(Some((EbmlVarint::Unknown, value_length))) + } else { + Ok(Some((EbmlVarint::Value(value), value_length))) + } +} + #[cfg(test)] mod tests { use futures::future::{ok, Future}; + use super::{decode_varint, Error}; + use super::EbmlVarint::{Unknown, Value}; #[test] fn hello_futures() { @@ -15,4 +77,29 @@ mod tests { assert_eq!(string_result, "Hello, Futures!"); } + + #[test] + fn fail_corrupted_varints() { + assert_eq!(decode_varint(&[0]), Err(Error::CorruptVarint)); + assert_eq!(decode_varint(&[0, 0, 0]), Err(Error::CorruptVarint)); + } + + #[test] + fn incomplete_varints() { + assert_eq!(decode_varint(&[]), Ok(None)); + assert_eq!(decode_varint(&[0x40]), Ok(None)); + assert_eq!(decode_varint(&[0x01, 0, 0]), Ok(None)); + } + + #[test] + fn parse_varints() { + assert_eq!(decode_varint(&[0xFF]), Ok(Some((Unknown, 1)))); + assert_eq!(decode_varint(&[0x7F, 0xFF]), Ok(Some((Unknown, 2)))); + assert_eq!(decode_varint(&[0x80]), Ok(Some((Value(0), 1)))); + assert_eq!(decode_varint(&[0x81]), Ok(Some((Value(1), 1)))); + assert_eq!(decode_varint(&[0x40, 52]), Ok(Some((Value(52), 2)))); + + // test extra data in buffer + assert_eq!(decode_varint(&[0x83, 0x11]), Ok(Some((Value(3), 1)))); + } }