<commit_before>use std::io::{Read as IoRead, Result as IoResult, Error as IoError, ErrorKind as IoErrorKind};
use ::Result;
use serde_crate as serde;

/// A byte-oriented reading trait that is specialized for
/// slices and generic readers.
pub trait BincodeRead<'storage>: IoRead {
    #[doc(hidden)]
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) ->  Result<V::Value>
    where V: serde::de::Visitor<'storage>;

    #[doc(hidden)]
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>>;

    #[doc(hidden)]
    fn forward_read_bytes<V: serde::de::Visitor<'storage>>(&mut self, length: usize, visitor: V) ->  Result<V::Value>
    where V: serde::de::Visitor<'storage>;
}

/// A BincodeRead implementation for byte slices
pub struct SliceReader<'storage> {
    slice: &'storage [u8]
}

/// A BincodeRead implementation for io::Readers
pub struct IoReadReader<R> {
    reader: R,
    temp_buffer: Vec<u8>,
}

impl <'storage> SliceReader<'storage> {
    /// Constructs a slice reader
    pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> {
        SliceReader {
            slice: bytes,
        }
    }
}

impl <R> IoReadReader<R> {
    /// Constructs an IoReadReader
    pub fn new(r: R) -> IoReadReader<R> {
        IoReadReader {
            reader: r,
            temp_buffer: vec![],
        }
    }
}

impl <'storage> IoRead for SliceReader<'storage> {
    fn read(&mut self, out: & mut [u8]) -> IoResult<usize> {
        (&mut self.slice).read(out)
    }
}

impl <R: IoRead> IoRead for IoReadReader<R> {
    fn read(&mut self, out: & mut [u8]) -> IoResult<usize> {
        self.reader.read(out)
    }
}

impl <'storage> BincodeRead<'storage> for SliceReader<'storage> {
    fn forward_read_str<V: serde::de::Visitor<'storage>>(&mut self, length: usize, visitor: V) ->  Result<V::Value> {
        use ::ErrorKind;
        if length > self.slice.len() {
            return Err(Box::new(ErrorKind::IoError(IoError::new(IoErrorKind::UnexpectedEof, ""))));
        }

        let string = match ::std::str::from_utf8(&self.slice[..length]) {
            Ok(s) => s,
            Err(_) => return Err(Box::new(ErrorKind::InvalidEncoding {
                desc: "string was not valid utf8",
                detail: None,
            })),
        };
        let r = visitor.visit_borrowed_str(string);
        self.slice = &self.slice[length..];
        r
    }

    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        use ::ErrorKind;
        if length > self.slice.len() {
            return Err(Box::new(ErrorKind::InvalidEncoding {
                            desc: "string was not valid utf8",
                            detail: None,
                        }));
        }

        let r = &self.slice[..length];
        self.slice = &self.slice[length..];
        Ok(r.to_vec())
    }

    fn forward_read_bytes<V: serde::de::Visitor<'storage>>(&mut self, length: usize, visitor: V) ->  Result<V::Value> {
        use ::ErrorKind;
        if length > self.slice.len() {
            return Err(Box::new(ErrorKind::IoError(IoError::new(IoErrorKind::UnexpectedEof, ""))));
        }

        let r = visitor.visit_borrowed_bytes(&self.slice[..length]);
        self.slice = &self.slice[length..];
        r
    }
}

impl <R> BincodeRead<'static> for IoReadReader<R> where R: IoRead {
    fn forward_read_str<V: serde::de::Visitor<'static>>(&mut self, length: usize, visitor: V) ->  Result<V::Value> {
        use ::ErrorKind;
        let current_length = self.temp_buffer.len();
        if length > current_length{
            self.temp_buffer.reserve_exact(length - current_length);
        }

        self.reader.read_exact(&mut self.temp_buffer[..length])?;
        let string = match ::std::str::from_utf8(&self.temp_buffer[..length]) {
            Ok(s) => s,
            Err(_) => return Err(Box::new(ErrorKind::InvalidEncoding {
                desc: "string was not valid utf8",
                detail: None,
            })),
        };

        let r = visitor.visit_str(string);
        r
    }

    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        let current_length = self.temp_buffer.len();
        if length > current_length{
            self.temp_buffer.reserve_exact(length - current_length);
            unsafe { self.temp_buffer.set_len(length); }
        }

        self.reader.read_exact(&mut self.temp_buffer[..length])?;

        Ok(self.temp_buffer[..length].to_vec())
    }

    fn forward_read_bytes<V: serde::de::Visitor<'static>>(&mut self, length: usize, visitor: V) ->  Result<V::Value> {
        let current_length = self.temp_buffer.len();
        if length > current_length{
            self.temp_buffer.reserve_exact(length - current_length);
            unsafe { self.temp_buffer.set_len(length); }
        }

        self.reader.read_exact(&mut self.temp_buffer[..length])?;

        let r = visitor.visit_bytes(&self.temp_buffer[..length]);
        r
    }
}
<commit_msg>factor out some common functionality<commit_after>use std::io::{Read as IoRead, Result as IoResult, Error as IoError, ErrorKind as IoErrorKind};
use ::Result;
use serde_crate as serde;

/// A byte-oriented reading trait that is specialized for
/// slices and generic readers.
pub trait BincodeRead<'storage>: IoRead {
    #[doc(hidden)]
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) ->  Result<V::Value>
    where V: serde::de::Visitor<'storage>;

    #[doc(hidden)]
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>>;

    #[doc(hidden)]
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) ->  Result<V::Value>
    where V: serde::de::Visitor<'storage>;
}

/// A BincodeRead implementation for byte slices
pub struct SliceReader<'storage> {
    slice: &'storage [u8]
}

/// A BincodeRead implementation for io::Readers
pub struct IoReadReader<R> {
    reader: R,
    temp_buffer: Vec<u8>,
}

impl <'storage> SliceReader<'storage> {
    /// Constructs a slice reader
    pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> {
        SliceReader {
            slice: bytes,
        }
    }
}

impl <R> IoReadReader<R> {
    /// Constructs an IoReadReader
    pub fn new(r: R) -> IoReadReader<R> {
        IoReadReader {
            reader: r,
            temp_buffer: vec![],
        }
    }
}

impl <'storage> IoRead for SliceReader<'storage> {
    fn read(&mut self, out: & mut [u8]) -> IoResult<usize> {
        (&mut self.slice).read(out)
    }
}

impl <R: IoRead> IoRead for IoReadReader<R> {
    fn read(&mut self, out: & mut [u8]) -> IoResult<usize> {
        self.reader.read(out)
    }
}

impl <'storage> SliceReader<'storage> {
    fn unexpected_eof() -> Box<::ErrorKind> {
        return Box::new(::ErrorKind::IoError(IoError::new(IoErrorKind::UnexpectedEof, "")));
    }
}

impl <'storage> BincodeRead<'storage> for SliceReader<'storage> {
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) ->  Result<V::Value>
    where V: serde::de::Visitor<'storage> {
        use ::ErrorKind;
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let string = match ::std::str::from_utf8(&self.slice[..length]) {
            Ok(s) => s,
            Err(_) => return Err(Box::new(ErrorKind::InvalidEncoding {
                desc: "string was not valid utf8",
                detail: None,
            })),
        };
        let r = visitor.visit_borrowed_str(string);
        self.slice = &self.slice[length..];
        r
    }

    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let r = &self.slice[..length];
        self.slice = &self.slice[length..];
        Ok(r.to_vec())
    }

    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) ->  Result<V::Value>
    where V: serde::de::Visitor<'storage> {
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let r = visitor.visit_borrowed_bytes(&self.slice[..length]);
        self.slice = &self.slice[length..];
        r
    }
}

impl <R> IoReadReader<R> where R: IoRead {
    fn fill_buffer(&mut self, length: usize) -> Result<()> {
        let current_length = self.temp_buffer.len();
        if length > current_length{
            self.temp_buffer.reserve_exact(length - current_length);
            unsafe { self.temp_buffer.set_len(length); }
        }

        self.reader.read_exact(&mut self.temp_buffer[..length])?;
        Ok(())
    }
}

impl <R> BincodeRead<'static> for IoReadReader<R> where R: IoRead {
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) ->  Result<V::Value>
    where V: serde::de::Visitor<'static> {
        self.fill_buffer(length)?;

        let string = match ::std::str::from_utf8(&self.temp_buffer[..length]) {
            Ok(s) => s,
            Err(_) => return Err(Box::new(::ErrorKind::InvalidEncoding {
                desc: "string was not valid utf8",
                detail: None,
            })),
        };

        let r = visitor.visit_str(string);
        r
    }

    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        self.fill_buffer(length)?;
        Ok(self.temp_buffer[..length].to_vec())
    }

    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) ->  Result<V::Value>
    where V: serde::de::Visitor<'static> {
        self.fill_buffer(length)?;
        let r = visitor.visit_bytes(&self.temp_buffer[..length]);
        r
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::fmt;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result as IoResult;

/// Reads HTTP chunks and sends back real data.
///
/// # Example
///
/// ```
/// use chunked_transfer::Decoder;
/// use std::io::Read;
///
/// let encoded = b"3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n";
/// let mut decoded = String::new();
///
/// let mut decoder = Decoder::new(encoded as &[u8]);
/// decoder.read_to_string(&mut decoded);
///
/// assert_eq!(decoded, "hello world!!!");
/// ```
pub struct Decoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,
}

impl<R> Decoder<R>
where
    R: Read,
{
    pub fn new(source: R) -> Decoder<R> {
        Decoder {
            source,
            remaining_chunks_size: None,
        }
    }

    /// Unwraps the Decoder into its inner `Read` source.
    pub fn into_inner(self) -> R {
        self.source
    }

    fn read_chunk_size(&mut self) -> IoResult<usize> {
        let mut chunk_size_bytes = Vec::new();
        let mut has_ext = false;

        loop {
            let byte = match self.source.by_ref().bytes().next() {
                Some(b) => b?,
                None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            };

            if byte == b'\r' {
                break;
            }

            if byte == b';' {
                has_ext = true;
                break;
            }

            chunk_size_bytes.push(byte);
        }

        // Ignore extensions for now
        if has_ext {
            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => b?,
                    None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
                };
                if byte == b'\r' {
                    break;
                }
            }
        }

        self.read_line_feed()?;

        let chunk_size = String::from_utf8(chunk_size_bytes)
            .ok()
            .and_then(|c| usize::from_str_radix(c.trim(), 16).ok())
            .ok_or(IoError::new(ErrorKind::InvalidInput, DecoderError))?;

        Ok(chunk_size)
    }

    fn read_carriage_return(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\r')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }

    fn read_line_feed(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\n')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }
}

impl<R> Read for Decoder<R>
where
    R: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let remaining_chunks_size = match self.remaining_chunks_size {
            Some(c) => c,
            None => {
                // first possibility: we are not in a chunk, so we'll attempt to determine
                // the chunks size
                let chunk_size = self.read_chunk_size()?;

                // if the chunk size is 0, we are at EOF
                if chunk_size == 0 {
                    self.read_carriage_return()?;
                    self.read_line_feed()?;
                    return Ok(0);
                }

                chunk_size
            }
        };

        // second possibility: we continue reading from a chunk
        if buf.len() < remaining_chunks_size {
            let read = self.source.read(buf)?;
            self.remaining_chunks_size = Some(remaining_chunks_size - read);
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= remaining_chunks_size);

        let buf = &mut buf[..remaining_chunks_size];
        let read = self.source.read(buf)?;

        self.remaining_chunks_size = if read == remaining_chunks_size {
            self.read_carriage_return()?;
            self.read_line_feed()?;
            None
        } else {
            Some(remaining_chunks_size - read)
        };

        Ok(read)
    }
}

#[derive(Debug, Copy, Clone)]
struct DecoderError;

impl fmt::Display for DecoderError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for DecoderError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

#[cfg(test)]
mod test {
    use super::Decoder;
    use std::io;
    use std::io::Read;

    /// This unit test is taken from from Hyper
    /// https://github.com/hyperium/hyper
    /// Copyright (c) 2014 Sean McArthur
    #[test]
    fn test_read_chunk_size() {
        fn read(s: &str, expected: usize) {
            let mut decoded = Decoder::new(s.as_bytes());
            let actual = decoded.read_chunk_size().unwrap();
            assert_eq!(expected, actual);
        }

        fn read_err(s: &str) {
            let mut decoded = Decoder::new(s.as_bytes());
            let err_kind = decoded.read_chunk_size().unwrap_err().kind();
            assert_eq!(err_kind, io::ErrorKind::InvalidInput);
        }

        read("1\r\n", 1);
        read("01\r\n", 1);
        read("0\r\n", 0);
        read("00\r\n", 0);
        read("A\r\n", 10);
        read("a\r\n", 10);
        read("Ff\r\n", 255);
        read("Ff   \r\n", 255);
        // Missing LF or CRLF
        read_err("F\rF");
        read_err("F");
        // Invalid hex digit
        read_err("X\r\n");
        read_err("1X\r\n");
        read_err("-\r\n");
        read_err("-1\r\n");
        // Acceptable (if not fully valid) extensions do not influence the size
        read("1;extension\r\n", 1);
        read("a;ext name=value\r\n", 10);
        read("1;extension;extension2\r\n", 1);
        read("1;;;  ;\r\n", 1);
        read("2; extension...\r\n", 2);
        read("3   ; extension=123\r\n", 3);
        read("3   ;\r\n", 3);
        read("3   ;   \r\n", 3);
        // Invalid extensions cause an error
        read_err("1 invalid extension\r\n");
        read_err("1 A\r\n");
        read_err("1;no CRLF");
    }

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new(
            "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    fn test_decode_zero_length() {
        let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        decoder.read_to_string(&mut decoded).unwrap();

        assert_eq!(decoded, "");
    }

    #[test]
    fn test_decode_invalid_chunk_length() {
        let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        assert!(decoder.read_to_string(&mut decoded).is_err());
    }

    #[test]
    fn invalid_input1() {
        let source = io::Cursor::new(
            "2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        assert!(decoded.read_to_string(&mut string).is_err());
    }

    #[test]
    fn invalid_input2() {
        let source = io::Cursor::new(
            "3\rhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        assert!(decoded.read_to_string(&mut string).is_err());
    }
}
<commit_msg>Expose Decoder::remaining_chunks_size<commit_after>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;
use std::fmt;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result as IoResult;

/// Reads HTTP chunks and sends back real data.
///
/// # Example
///
/// ```
/// use chunked_transfer::Decoder;
/// use std::io::Read;
///
/// let encoded = b"3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n";
/// let mut decoded = String::new();
///
/// let mut decoder = Decoder::new(encoded as &[u8]);
/// decoder.read_to_string(&mut decoded);
///
/// assert_eq!(decoded, "hello world!!!");
/// ```
pub struct Decoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,
}

impl<R> Decoder<R>
where
    R: Read,
{
    pub fn new(source: R) -> Decoder<R> {
        Decoder {
            source,
            remaining_chunks_size: None,
        }
    }

	/// Returns the remaining bytes left in the chunk being read.
	pub fn remaining_chunks_size(&self) -> Option<usize> {
		self.remaining_chunks_size
	}

    /// Unwraps the Decoder into its inner `Read` source.
    pub fn into_inner(self) -> R {
        self.source
    }

    fn read_chunk_size(&mut self) -> IoResult<usize> {
        let mut chunk_size_bytes = Vec::new();
        let mut has_ext = false;

        loop {
            let byte = match self.source.by_ref().bytes().next() {
                Some(b) => b?,
                None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            };

            if byte == b'\r' {
                break;
            }

            if byte == b';' {
                has_ext = true;
                break;
            }

            chunk_size_bytes.push(byte);
        }

        // Ignore extensions for now
        if has_ext {
            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => b?,
                    None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
                };
                if byte == b'\r' {
                    break;
                }
            }
        }

        self.read_line_feed()?;

        let chunk_size = String::from_utf8(chunk_size_bytes)
            .ok()
            .and_then(|c| usize::from_str_radix(c.trim(), 16).ok())
            .ok_or(IoError::new(ErrorKind::InvalidInput, DecoderError))?;

        Ok(chunk_size)
    }

    fn read_carriage_return(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\r')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }

    fn read_line_feed(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\n')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }
}

impl<R> Read for Decoder<R>
where
    R: Read,
{
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let remaining_chunks_size = match self.remaining_chunks_size {
            Some(c) => c,
            None => {
                // first possibility: we are not in a chunk, so we'll attempt to determine
                // the chunks size
                let chunk_size = self.read_chunk_size()?;

                // if the chunk size is 0, we are at EOF
                if chunk_size == 0 {
                    self.read_carriage_return()?;
                    self.read_line_feed()?;
                    return Ok(0);
                }

                chunk_size
            }
        };

        // second possibility: we continue reading from a chunk
        if buf.len() < remaining_chunks_size {
            let read = self.source.read(buf)?;
            self.remaining_chunks_size = Some(remaining_chunks_size - read);
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= remaining_chunks_size);

        let buf = &mut buf[..remaining_chunks_size];
        let read = self.source.read(buf)?;

        self.remaining_chunks_size = if read == remaining_chunks_size {
            self.read_carriage_return()?;
            self.read_line_feed()?;
            None
        } else {
            Some(remaining_chunks_size - read)
        };

        Ok(read)
    }
}

#[derive(Debug, Copy, Clone)]
struct DecoderError;

impl fmt::Display for DecoderError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for DecoderError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

#[cfg(test)]
mod test {
    use super::Decoder;
    use std::io;
    use std::io::Read;

    /// This unit test is taken from from Hyper
    /// https://github.com/hyperium/hyper
    /// Copyright (c) 2014 Sean McArthur
    #[test]
    fn test_read_chunk_size() {
        fn read(s: &str, expected: usize) {
            let mut decoded = Decoder::new(s.as_bytes());
            let actual = decoded.read_chunk_size().unwrap();
            assert_eq!(expected, actual);
        }

        fn read_err(s: &str) {
            let mut decoded = Decoder::new(s.as_bytes());
            let err_kind = decoded.read_chunk_size().unwrap_err().kind();
            assert_eq!(err_kind, io::ErrorKind::InvalidInput);
        }

        read("1\r\n", 1);
        read("01\r\n", 1);
        read("0\r\n", 0);
        read("00\r\n", 0);
        read("A\r\n", 10);
        read("a\r\n", 10);
        read("Ff\r\n", 255);
        read("Ff   \r\n", 255);
        // Missing LF or CRLF
        read_err("F\rF");
        read_err("F");
        // Invalid hex digit
        read_err("X\r\n");
        read_err("1X\r\n");
        read_err("-\r\n");
        read_err("-1\r\n");
        // Acceptable (if not fully valid) extensions do not influence the size
        read("1;extension\r\n", 1);
        read("a;ext name=value\r\n", 10);
        read("1;extension;extension2\r\n", 1);
        read("1;;;  ;\r\n", 1);
        read("2; extension...\r\n", 2);
        read("3   ; extension=123\r\n", 3);
        read("3   ;\r\n", 3);
        read("3   ;   \r\n", 3);
        // Invalid extensions cause an error
        read_err("1 invalid extension\r\n");
        read_err("1 A\r\n");
        read_err("1;no CRLF");
    }

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new(
            "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    fn test_decode_zero_length() {
        let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        decoder.read_to_string(&mut decoded).unwrap();

        assert_eq!(decoded, "");
    }

    #[test]
    fn test_decode_invalid_chunk_length() {
        let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        assert!(decoder.read_to_string(&mut decoded).is_err());
    }

    #[test]
    fn invalid_input1() {
        let source = io::Cursor::new(
            "2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        assert!(decoded.read_to_string(&mut string).is_err());
    }

    #[test]
    fn invalid_input2() {
        let source = io::Cursor::new(
            "3\rhel\r\nb\r\nlo world!!!\r\n0\r\n"
                .to_string()
                .into_bytes(),
        );
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        assert!(decoded.read_to_string(&mut string).is_err());
    }
}
<|endoftext|>


<commit_before>use av_format::error::*;
use std::io::SeekFrom;
use av_data::packet::Packet;
use av_data::timeinfo::TimeInfo;
use av_data::params::*;
use av_format::stream::Stream;
use av_format::buffer::Buffered;
use av_format::demuxer::{Demuxer, Event};
use av_format::demuxer::{Descr, Descriptor};
use av_format::common::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational64;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement, simple_block};
use nom::{self, Err, IResult, Offset};

#[derive(Debug, Clone)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            // println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    // println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    // println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    // println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                el => {
                    println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

use nom::Needed;

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| d as u64);
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| {
                        track_to_stream(self.info.as_ref().unwrap(), tr)
                    }).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            },
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + size,
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            },
            e => {
                println!("error reading headers: {:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            // println!("no more stored packet, parsing a new one");
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            // println!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets();
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {
                            // println!("got element: {:#?}", el);
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                },
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(size))
                },
                e => {
                    println!("parsing issue: {:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS"   => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1"    => Some("av1".to_owned()),
        "V_VP8"    => Some("vp8".to_owned()),
        "V_VP9"    => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    use av_data::audiosample::*;
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let map = if audio.channel_positions.is_none() {
            Some(ChannelMap::default_map(audio.channels as usize))
        } else {
            unimplemented!("Convert matroska map to rust-av map")
        };
        let a = AudioInfo {
            rate: rate as usize,
            map: map,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None,
    }
}

// TODO: make sure the timecode_scale isn't 0
pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = if let Some(ts) = t.track_timecode_scale  {
        (ts * info.timecode_scale as f64) as i64
    } else {
        info.timecode_scale as i64
    };

    Stream {
        id: t.track_uid as isize,
        index: t.track_number as usize,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
        user_private: None
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                //println!("parsing simple block: {:?}", block);
                let packet = Packet {
                    data: i.into(),
                    t: TimeInfo {
                        pts: Some(block.timecode as i64),
                        dts: None,
                        duration: None,
                        timebase: None,
                    },
                    pos: None,
                    stream_index: block.track_number as isize,
                    is_key: block.keyframe,
                    is_corrupted: false,
                };

                v.push(Event::NewPacket(packet));
            } else {
                println!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe<'a>(&'a self) -> &'a Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        match ebml_header(&data[..100]) {
            Ok(_) => 100,
            _ => 0,
        }
    }
}

pub const MKV_DESC: &Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    }
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::Offset;
    use av_format::demuxer::Context;
    use av_format::buffer::*;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => println!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => println!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(Box::new(MkvDemuxer::new()),
                                       Box::new(AccReader::new(Cursor::new(webm))));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers().unwrap());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
    }
}
<commit_msg>Use add_stream to make sure the index is correct<commit_after>use av_format::error::*;
use std::io::SeekFrom;
use av_data::packet::Packet;
use av_data::timeinfo::TimeInfo;
use av_data::params::*;
use av_format::stream::Stream;
use av_format::buffer::Buffered;
use av_format::demuxer::{Demuxer, Event};
use av_format::demuxer::{Descr, Descriptor};
use av_format::common::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational64;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement, simple_block};
use nom::{self, Err, IResult, Offset};

#[derive(Debug, Clone)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        self.seek_head = None;
        self.info = None;
        self.tracks = None;

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return Ok((input, ()));
            }

            // println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    // println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    // println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    // println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return Err(Err::Error(error_position!(input, nom::ErrorKind::Custom(1))));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                el => {
                    println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

use nom::Needed;

impl Demuxer for MkvDemuxer {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            Ok((i, _)) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| d as u64);
                if let Some(ref t) = self.tracks {
                    for tr in t.tracks.iter() {
                        info.add_stream(track_to_stream(self.info.as_ref().unwrap(), tr));
                    }
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            },
            Err(Err::Incomplete(needed)) => {
                let sz = match needed {
                    Needed::Size(size) => buf.data().len() + size,
                    _ => 1024,
                };
                Err(Error::MoreDataNeeded(sz))
            },
            e => {
                println!("error reading headers: {:?}", e);
                Err(Error::InvalidData)
            }
        }
    }

    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        if let Some(event) = self.queue.pop_front() {
            Ok((SeekFrom::Current(0), event))
        } else {
            // println!("no more stored packet, parsing a new one");
            match segment_element(buf.data()) {
                Ok((i, element)) => {
                    let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                    match element {
                        SegmentElement::Cluster(c) => {
                            //self.clusters.push(c);
                            // println!("got cluster element at timecode: {}", c.timecode);
                            let mut packets = c.generate_packets();
                            self.queue.extend(packets.drain(..));
                            if let Some(event) = self.queue.pop_front() {
                                return Ok((seek, event));
                            }
                        }
                        _el => {
                            // println!("got element: {:#?}", el);
                        }
                    }
                    Ok((seek, Event::MoreDataNeeded(0)))
                },
                Err(Err::Incomplete(Needed::Size(size))) => {
                    Err(Error::MoreDataNeeded(size))
                },
                e => {
                    println!("parsing issue: {:?}", e);
                    Err(Error::InvalidData)
                }
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<String> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS"   => Some("opus".to_owned()),
        "A_VORBIS" => Some("vorbis".to_owned()),
        "V_AV1"    => Some("av1".to_owned()),
        "V_VP8"    => Some("vp8".to_owned()),
        "V_VP9"    => Some("vp9".to_owned()),
        _ => None,
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width: video.pixel_width as usize,
            height: video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format: None,
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    use av_data::audiosample::*;
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let map = if audio.channel_positions.is_none() {
            Some(ChannelMap::default_map(audio.channels as usize))
        } else {
            unimplemented!("Convert matroska map to rust-av map")
        };
        let a = AudioInfo {
            rate: rate as usize,
            map: map,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None,
    }
}

// TODO: make sure the timecode_scale isn't 0
pub fn track_to_stream(info: &Info, t: &TrackEntry) -> Stream {
    let num = if let Some(ts) = t.track_timecode_scale  {
        (ts * info.timecode_scale as f64) as i64
    } else {
        info.timecode_scale as i64
    };

    Stream {
        id: t.track_uid as isize,
        index: 0,
        start: None,
        duration: t.default_duration,
        timebase: Rational64::new(num, 1000 * 1000 * 1000),
        // TODO: Extend CodecParams and fill it with the remaining information
        params: CodecParams {
            extradata: t.codec_private.clone(),
            bit_rate: 0,
            delay: t.codec_delay.unwrap_or(0) as usize,
            convergence_window: t.seek_pre_roll.unwrap_or(0) as usize,
            codec_id: track_entry_codec_id(t),
            kind: track_entry_media_kind(t),
        },
        user_private: None
    }
}

impl<'a> Cluster<'a> {
    pub fn generate_packets(&self) -> Vec<Event> {
        let mut v = Vec::new();

        for block_data in self.simple_block.iter() {
            if let Ok((i, block)) = simple_block(block_data) {
                //println!("parsing simple block: {:?}", block);
                let packet = Packet {
                    data: i.into(),
                    t: TimeInfo {
                        pts: Some(block.timecode as i64),
                        dts: None,
                        duration: None,
                        timebase: None,
                    },
                    pos: None,
                    stream_index: block.track_number as isize,
                    is_key: block.keyframe,
                    is_corrupted: false,
                };

                v.push(Event::NewPacket(packet));
            } else {
                println!("error parsing simple block");
            }
        }

        v
    }
}

struct Des {
    d: Descr,
}

impl Descriptor for Des {
    fn create(&self) -> Box<Demuxer> {
        Box::new(MkvDemuxer::new())
    }
    fn describe<'a>(&'a self) -> &'a Descr {
        &self.d
    }
    fn probe(&self, data: &[u8]) -> u8 {
        match ebml_header(&data[..100]) {
            Ok(_) => 100,
            _ => 0,
        }
    }
}

pub const MKV_DESC: &Descriptor = &Des {
    d: Descr {
        name: "matroska",
        demuxer: "mkv",
        description: "Nom-based Matroska demuxer",
        extensions: &["mkv", "webm", "mka"],
        mime: &["video/x-matroska", "audio/x-matroska"],
    }
};

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::Offset;
    use av_format::demuxer::Context;
    use av_format::buffer::*;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            Ok((i, _)) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
    }

    #[test]
    fn parse_headers_incremental_buffer() {
        let mut demuxer = MkvDemuxer::new();

        for n in 100..2000 {
            let res = demuxer.parse_until_tracks(&webm[0..n]);
            match res {
                Ok(_) => println!("Size {} ok", n),
                Err(Err::Incomplete(needed)) => println!("Incomplete {} needs {:?}", n, needed),
                Err(e) => {
                    panic!("Error at size {}: {:?}", n, e);
                }
            }
        }
    }

    #[test]
    fn context() {
        let mut context = Context::new(Box::new(MkvDemuxer::new()),
                                       Box::new(AccReader::new(Cursor::new(webm))));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers().unwrap());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
        println!("DEMUXER CONTEXT event: {:?}", context.read_event().unwrap());
    }
}
<|endoftext|>


<commit_before>pub const WIDTH: usize = 64;
pub const HEIGHT: usize = 32;

pub const SPRITES: [u8; 80] = [0xF0, 0x90, 0x90, 0x90, 0xF0 /* 0 */, 0x20, 0x60, 0x20, 0x20,
                               0x70 /* 1 */, 0xF0, 0x10, 0xF0, 0x80, 0xF0 /* 2 */, 0xF0,
                               0x10, 0xF0, 0x10, 0xF0 /* 3 */, 0x90, 0x90, 0xF0, 0x10,
                               0x10 /* 4 */, 0xF0, 0x80, 0xF0, 0x10, 0xF0 /* 5 */, 0xF0,
                               0x80, 0xF0, 0x90, 0xF0 /* 6 */, 0xF0, 0x10, 0x20, 0x40,
                               0x40 /* 7 */, 0xF0, 0x90, 0xF0, 0x90, 0xF0 /* 8 */, 0xF0,
                               0x90, 0xF0, 0x10, 0xF0 /* 9 */, 0xF0, 0x90, 0xF0, 0x90,
                               0x90 /* a */, 0xE0, 0x90, 0xE0, 0x90, 0xE0 /* b */, 0xF0,
                               0x80, 0x80, 0x80, 0xF0 /* c */, 0xE0, 0x90, 0x90, 0x90,
                               0xE0 /* d */, 0xF0, 0x80, 0xF0, 0x80, 0xF0 /* e */, 0xF0,
                               0x80, 0xF0, 0x80, 0x80];// f

pub type Screen = [[bool; WIDTH]; HEIGHT];

pub struct Display {
    screen: Screen,
}

impl Display {
    pub fn new() -> Display {
        Display {
            screen: [[false; WIDTH]; HEIGHT],
        }
    }

    pub fn get_screen(&mut self) -> &Screen {
        &self.screen
    }

    // TODO: Please find a better way to do this...it hurts.
    pub fn draw_sprite(&mut self, sprite: &[u8], x: usize, y: usize) -> bool {
        let flipped = false;
        for (i, row) in sprite.iter().enumerate() {
            println!("Drawing sprite row at ({}, {}) => {:08b}", x, y, row);
            // Ex. 11110000 -> 0 0 0 0 1 1 1 1
            // Because we get them in the reverse order of the indexing
            // we need to use "7-j" for the column index.
            for j in 0..8 {
                let pixel_val = (row >> j) & 0b1;

                let y_pixel = y + i;
                let x_pixel = x + (7-j);

                if self.coords_out_of_bounds(x_pixel, y_pixel) {
                    continue;
                }

                let current_val = self.screen[ y + i ][ x + (7-j)];
                let new_val = pixel_val != 0;

                self.screen[ y + i ][ x + (7-j)] = new_val;

                flipped = flipped || (current_val && !new_val);
            }
        }

        flipped
    }

    pub fn clear(&mut self) {
        self.screen = [[false; WIDTH]; HEIGHT];
    }

    fn coords_out_of_bounds(&self, x: usize, y: usize) -> bool {
        return y >= HEIGHT || x >= WIDTH;
    }
}
<commit_msg>mut flipped<commit_after>pub const WIDTH: usize = 64;
pub const HEIGHT: usize = 32;

pub const SPRITES: [u8; 80] = [0xF0, 0x90, 0x90, 0x90, 0xF0 /* 0 */, 0x20, 0x60, 0x20, 0x20,
                               0x70 /* 1 */, 0xF0, 0x10, 0xF0, 0x80, 0xF0 /* 2 */, 0xF0,
                               0x10, 0xF0, 0x10, 0xF0 /* 3 */, 0x90, 0x90, 0xF0, 0x10,
                               0x10 /* 4 */, 0xF0, 0x80, 0xF0, 0x10, 0xF0 /* 5 */, 0xF0,
                               0x80, 0xF0, 0x90, 0xF0 /* 6 */, 0xF0, 0x10, 0x20, 0x40,
                               0x40 /* 7 */, 0xF0, 0x90, 0xF0, 0x90, 0xF0 /* 8 */, 0xF0,
                               0x90, 0xF0, 0x10, 0xF0 /* 9 */, 0xF0, 0x90, 0xF0, 0x90,
                               0x90 /* a */, 0xE0, 0x90, 0xE0, 0x90, 0xE0 /* b */, 0xF0,
                               0x80, 0x80, 0x80, 0xF0 /* c */, 0xE0, 0x90, 0x90, 0x90,
                               0xE0 /* d */, 0xF0, 0x80, 0xF0, 0x80, 0xF0 /* e */, 0xF0,
                               0x80, 0xF0, 0x80, 0x80];// f

pub type Screen = [[bool; WIDTH]; HEIGHT];

pub struct Display {
    screen: Screen,
}

impl Display {
    pub fn new() -> Display {
        Display {
            screen: [[false; WIDTH]; HEIGHT],
        }
    }

    pub fn get_screen(&mut self) -> &Screen {
        &self.screen
    }

    // TODO: Please find a better way to do this...it hurts.
    pub fn draw_sprite(&mut self, sprite: &[u8], x: usize, y: usize) -> bool {
        let mut flipped = false;
        for (i, row) in sprite.iter().enumerate() {
            println!("Drawing sprite row at ({}, {}) => {:08b}", x, y, row);
            // Ex. 11110000 -> 0 0 0 0 1 1 1 1
            // Because we get them in the reverse order of the indexing
            // we need to use "7-j" for the column index.
            for j in 0..8 {
                let pixel_val = (row >> j) & 0b1;

                let y_pixel = y + i;
                let x_pixel = x + (7-j);

                if self.coords_out_of_bounds(x_pixel, y_pixel) {
                    continue;
                }

                let current_val = self.screen[ y + i ][ x + (7-j)];
                let new_val = pixel_val != 0;

                self.screen[ y + i ][ x + (7-j)] = new_val;

                flipped = flipped || (current_val && !new_val);
            }
        }

        flipped
    }

    pub fn clear(&mut self) {
        self.screen = [[false; WIDTH]; HEIGHT];
    }

    fn coords_out_of_bounds(&self, x: usize, y: usize) -> bool {
        return y >= HEIGHT || x >= WIDTH;
    }
}
<|endoftext|>


<commit_before>use rustc::mir::repr as mir;

use error::{EvalError, EvalResult};
use memory::Pointer;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal {
    Bool(bool),
    I8(i8), I16(i16), I32(i32), I64(i64),
    U8(u8), U16(u16), U32(u32), U64(u64),

    AbstractPtr(Pointer),
    FnPtr(Pointer),
    IntegerPtr(u64),
}

/// returns the result of the operation and whether the operation overflowed
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, (PrimVal, bool)> {
    use rustc::mir::repr::BinOp::*;
    use self::PrimVal::*;

    macro_rules! overflow {
        ($v:ident, $v2:ident, $l:ident, $op:ident, $r:ident) => ({
            let (val, of) = $l.$op($r);
            if of {
                return Ok(($v(val), true));
            } else {
                $v(val)
            }
        })
    }

    macro_rules! int_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => overflow!($v, $v, $l, overflowing_add, $r),
                Sub    => overflow!($v, $v, $l, overflowing_sub, $r),
                Mul    => overflow!($v, $v, $l, overflowing_mul, $r),
                Div    => overflow!($v, $v, $l, overflowing_div, $r),
                Rem    => overflow!($v, $v, $l, overflowing_rem, $r),
                BitXor => $v($l ^ $r),
                BitAnd => $v($l & $r),
                BitOr  => $v($l | $r),

                // these have already been handled
                Shl => unreachable!(),
                Shr => unreachable!(),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
        use rustc::mir::repr::BinOp::*;
        match bin_op {
            Eq => Ok(Bool(false)),
            Ne => Ok(Bool(true)),
            Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
            _ => unimplemented!(),
        }
    }

    match bin_op {
        // can have rhs with a different numeric type
        Shl | Shr => {
            // these numbers are the maximum number of bits a bitshift rhs could possibly have
            // e.g. u16 can be bitshifted by 0..16, so 2^4 - 1 is the largest possible bitshift
            let mask_bits = match left {
                I8(_) => 3,
                I16(_) => 4,
                I32(_) => 5,
                I64(_) => 6,
                U8(_) => 3,
                U16(_) => 4,
                U32(_) => 5,
                U64(_) => 6,
                _ => unreachable!(),
            };
            let mask = (1 << mask_bits) - 1;
            let r = match right {
                I8(i) => i as u8 & mask,
                I16(i) => i as u8 & mask,
                I32(i) => i as u8 & mask,
                I64(i) => i as u8 & mask,
                U8(i) => i as u8 & mask,
                U16(i) => i as u8 & mask,
                U32(i) => i as u8 & mask,
                U64(i) => i as u8 & mask,
                _ => panic!("bad MIR: bitshift rhs is not integral"),
            };
            let r = r as u32;
            macro_rules! shift {
                ($v:ident, $l:ident, $r:ident) => ({
                    match bin_op {
                        Shl => overflow!($v, U32, $l, overflowing_shl, $r),
                        Shr => overflow!($v, U32, $l, overflowing_shr, $r),
                        _ => unreachable!(),
                    }
                })
            }
            let val = match left {
                I8(l) => shift!(I8, l, r),
                I16(l) => shift!(I16, l, r),
                I32(l) => shift!(I32, l, r),
                I64(l) => shift!(I64, l, r),
                U8(l) => shift!(U8, l, r),
                U16(l) => shift!(U16, l, r),
                U32(l) => shift!(U32, l, r),
                U64(l) => shift!(U64, l, r),
                _ => unreachable!(),
            };
            return Ok((val, false));
        },
        _ => {},
    }

    let val = match (left, right) {
        (I8(l),  I8(r))  => int_binops!(I8, l, r),
        (I16(l), I16(r)) => int_binops!(I16, l, r),
        (I32(l), I32(r)) => int_binops!(I32, l, r),
        (I64(l), I64(r)) => int_binops!(I64, l, r),
        (U8(l),  U8(r))  => int_binops!(U8, l, r),
        (U16(l), U16(r)) => int_binops!(U16, l, r),
        (U32(l), U32(r)) => int_binops!(U32, l, r),
        (U64(l), U64(r)) => int_binops!(U64, l, r),

        (Bool(l), Bool(r)) => {
            Bool(match bin_op {
                Eq => l == r,
                Ne => l != r,
                Lt => l < r,
                Le => l <= r,
                Gt => l > r,
                Ge => l >= r,
                BitOr => l | r,
                BitXor => l ^ r,
                BitAnd => l & r,
                Add | Sub | Mul | Div | Rem | Shl | Shr => return Err(EvalError::InvalidBoolOp(bin_op)),
            })
        }

        (IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),

        (AbstractPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), AbstractPtr(_)) |
        (FnPtr(_), AbstractPtr(_)) |
        (AbstractPtr(_), FnPtr(_)) |
        (FnPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), FnPtr(_)) =>
            unrelated_ptr_ops(bin_op)?,

        (FnPtr(l_ptr), FnPtr(r_ptr)) => match bin_op {
            Eq => Bool(l_ptr == r_ptr),
            Ne => Bool(l_ptr != r_ptr),
            _ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
        },

        (AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
            if l_ptr.alloc_id != r_ptr.alloc_id {
                return Ok((unrelated_ptr_ops(bin_op)?, false));
            }

            let l = l_ptr.offset;
            let r = r_ptr.offset;

            match bin_op {
                Eq => Bool(l == r),
                Ne => Bool(l != r),
                Lt => Bool(l < r),
                Le => Bool(l <= r),
                Gt => Bool(l > r),
                Ge => Bool(l >= r),
                _ => return Err(EvalError::Unimplemented(format!("unimplemented ptr op: {:?}", bin_op))),
            }
        }

        (l, r) => return Err(EvalError::Unimplemented(format!("unimplemented binary op: {:?}, {:?}, {:?}", l, r, bin_op))),
    };

    Ok((val, false))
}

pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
    use rustc::mir::repr::UnOp::*;
    use self::PrimVal::*;
    match (un_op, val) {
        (Not, Bool(b)) => Ok(Bool(!b)),
        (Not, I8(n))  => Ok(I8(!n)),
        (Neg, I8(n))  => Ok(I8(-n)),
        (Not, I16(n)) => Ok(I16(!n)),
        (Neg, I16(n)) => Ok(I16(-n)),
        (Not, I32(n)) => Ok(I32(!n)),
        (Neg, I32(n)) => Ok(I32(-n)),
        (Not, I64(n)) => Ok(I64(!n)),
        (Neg, I64(n)) => Ok(I64(-n)),
        (Not, U8(n))  => Ok(U8(!n)),
        (Not, U16(n)) => Ok(U16(!n)),
        (Not, U32(n)) => Ok(U32(!n)),
        (Not, U64(n)) => Ok(U64(!n)),
        _ => Err(EvalError::Unimplemented(format!("unimplemented unary op: {:?}, {:?}", un_op, val))),
    }
}
<commit_msg>simplify even more<commit_after>use rustc::mir::repr as mir;

use error::{EvalError, EvalResult};
use memory::Pointer;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal {
    Bool(bool),
    I8(i8), I16(i16), I32(i32), I64(i64),
    U8(u8), U16(u16), U32(u32), U64(u64),

    AbstractPtr(Pointer),
    FnPtr(Pointer),
    IntegerPtr(u64),
}

/// returns the result of the operation and whether the operation overflowed
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, (PrimVal, bool)> {
    use rustc::mir::repr::BinOp::*;
    use self::PrimVal::*;

    macro_rules! overflow {
        ($v:ident, $v2:ident, $l:ident, $op:ident, $r:ident) => ({
            let (val, of) = $l.$op($r);
            if of {
                return Ok(($v(val), true));
            } else {
                $v(val)
            }
        })
    }

    macro_rules! int_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => overflow!($v, $v, $l, overflowing_add, $r),
                Sub    => overflow!($v, $v, $l, overflowing_sub, $r),
                Mul    => overflow!($v, $v, $l, overflowing_mul, $r),
                Div    => overflow!($v, $v, $l, overflowing_div, $r),
                Rem    => overflow!($v, $v, $l, overflowing_rem, $r),
                BitXor => $v($l ^ $r),
                BitAnd => $v($l & $r),
                BitOr  => $v($l | $r),

                // these have already been handled
                Shl => unreachable!(),
                Shr => unreachable!(),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
        use rustc::mir::repr::BinOp::*;
        match bin_op {
            Eq => Ok(Bool(false)),
            Ne => Ok(Bool(true)),
            Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
            _ => unimplemented!(),
        }
    }

    match bin_op {
        // can have rhs with a different numeric type
        Shl | Shr => {
            // these numbers are the maximum number a bitshift rhs could possibly have
            // e.g. u16 can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in that range
            let type_bits: u32 = match left {
                I8(_) | U8(_) => 8,
                I16(_) | U16(_) => 16,
                I32(_) | U32(_) => 32,
                I64(_) | U64(_) => 64,
                _ => unreachable!(),
            };
            assert!(type_bits.is_power_of_two());
            // turn into `u32` because `overflowing_sh{l,r}` only take `u32`
            let r = match right {
                I8(i) => i as u32,
                I16(i) => i as u32,
                I32(i) => i as u32,
                I64(i) => i as u32,
                U8(i) => i as u32,
                U16(i) => i as u32,
                U32(i) => i as u32,
                U64(i) => i as u32,
                _ => panic!("bad MIR: bitshift rhs is not integral"),
            };
            // apply mask
            let r = r & (type_bits - 1);
            macro_rules! shift {
                ($v:ident, $l:ident, $r:ident) => ({
                    match bin_op {
                        Shl => overflow!($v, U32, $l, overflowing_shl, $r),
                        Shr => overflow!($v, U32, $l, overflowing_shr, $r),
                        _ => unreachable!(),
                    }
                })
            }
            let val = match left {
                I8(l) => shift!(I8, l, r),
                I16(l) => shift!(I16, l, r),
                I32(l) => shift!(I32, l, r),
                I64(l) => shift!(I64, l, r),
                U8(l) => shift!(U8, l, r),
                U16(l) => shift!(U16, l, r),
                U32(l) => shift!(U32, l, r),
                U64(l) => shift!(U64, l, r),
                _ => unreachable!(),
            };
            return Ok((val, false));
        },
        _ => {},
    }

    let val = match (left, right) {
        (I8(l),  I8(r))  => int_binops!(I8, l, r),
        (I16(l), I16(r)) => int_binops!(I16, l, r),
        (I32(l), I32(r)) => int_binops!(I32, l, r),
        (I64(l), I64(r)) => int_binops!(I64, l, r),
        (U8(l),  U8(r))  => int_binops!(U8, l, r),
        (U16(l), U16(r)) => int_binops!(U16, l, r),
        (U32(l), U32(r)) => int_binops!(U32, l, r),
        (U64(l), U64(r)) => int_binops!(U64, l, r),

        (Bool(l), Bool(r)) => {
            Bool(match bin_op {
                Eq => l == r,
                Ne => l != r,
                Lt => l < r,
                Le => l <= r,
                Gt => l > r,
                Ge => l >= r,
                BitOr => l | r,
                BitXor => l ^ r,
                BitAnd => l & r,
                Add | Sub | Mul | Div | Rem | Shl | Shr => return Err(EvalError::InvalidBoolOp(bin_op)),
            })
        }

        (IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),

        (AbstractPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), AbstractPtr(_)) |
        (FnPtr(_), AbstractPtr(_)) |
        (AbstractPtr(_), FnPtr(_)) |
        (FnPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), FnPtr(_)) =>
            unrelated_ptr_ops(bin_op)?,

        (FnPtr(l_ptr), FnPtr(r_ptr)) => match bin_op {
            Eq => Bool(l_ptr == r_ptr),
            Ne => Bool(l_ptr != r_ptr),
            _ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
        },

        (AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
            if l_ptr.alloc_id != r_ptr.alloc_id {
                return Ok((unrelated_ptr_ops(bin_op)?, false));
            }

            let l = l_ptr.offset;
            let r = r_ptr.offset;

            match bin_op {
                Eq => Bool(l == r),
                Ne => Bool(l != r),
                Lt => Bool(l < r),
                Le => Bool(l <= r),
                Gt => Bool(l > r),
                Ge => Bool(l >= r),
                _ => return Err(EvalError::Unimplemented(format!("unimplemented ptr op: {:?}", bin_op))),
            }
        }

        (l, r) => return Err(EvalError::Unimplemented(format!("unimplemented binary op: {:?}, {:?}, {:?}", l, r, bin_op))),
    };

    Ok((val, false))
}

pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
    use rustc::mir::repr::UnOp::*;
    use self::PrimVal::*;
    match (un_op, val) {
        (Not, Bool(b)) => Ok(Bool(!b)),
        (Not, I8(n))  => Ok(I8(!n)),
        (Neg, I8(n))  => Ok(I8(-n)),
        (Not, I16(n)) => Ok(I16(!n)),
        (Neg, I16(n)) => Ok(I16(-n)),
        (Not, I32(n)) => Ok(I32(!n)),
        (Neg, I32(n)) => Ok(I32(-n)),
        (Not, I64(n)) => Ok(I64(!n)),
        (Neg, I64(n)) => Ok(I64(-n)),
        (Not, U8(n))  => Ok(U8(!n)),
        (Not, U16(n)) => Ok(U16(!n)),
        (Not, U32(n)) => Ok(U32(!n)),
        (Not, U64(n)) => Ok(U64(!n)),
        _ => Err(EvalError::Unimplemented(format!("unimplemented unary op: {:?}, {:?}", un_op, val))),
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use svgdom;

use math::{
    Size,
    Rect,
};

mod attribute;
mod dump;
mod element;

pub use self::element::*;
pub use self::attribute::*;

/// Container for a preprocessed SVG.
///
/// Unlike svgdom's `Document` this one is immutable for a backend code
/// and contains only supported, resolved elements and attributes.
pub struct Document {
    /// Image size.
    ///
    /// Size of an image that should be created to fit the SVG.
    pub size: Size,
    /// SVG viewbox.
    ///
    /// Specifies which part of the SVG image should be rendered.
    pub view_box: Rect,
    /// Image DPI.
    ///
    /// Has the same value as `Options::dpi`. Used for text rendering.
    pub dpi: f64,
    /// List of all referenced elements.
    ///
    /// Currently, can contain only `linearGradient` and `radialGradient`.
    pub defs: Vec<RefElement>,
    /// List of all elements.
    ///
    /// Contains list of all elements that should be rendered.
    pub elements: Vec<Element>,
}

impl Document {
    /// Returns referenced element by id.
    pub fn get_defs<'a>(&'a self, id: usize) -> &'a RefElement {
        &self.defs[id]
    }

    /// Converts the document to `svgdom::Document`.
    ///
    /// Used to save document to file for debug purposes.
    pub fn to_svgdom(&self) -> svgdom::Document {
        dump::conv_doc(self)
    }
}
<commit_msg>Doc fix.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use svgdom;

use math::{
    Size,
    Rect,
};

mod attribute;
mod dump;
mod element;

pub use self::element::*;
pub use self::attribute::*;

/// Container for a preprocessed SVG.
///
/// Unlike svgdom's `Document` this one is immutable for a backend code
/// and contains only supported, resolved elements and attributes.
pub struct Document {
    /// Image size.
    ///
    /// Size of an image that should be created to fit the SVG.
    pub size: Size,
    /// SVG viewbox.
    ///
    /// Specifies which part of the SVG image should be rendered.
    pub view_box: Rect,
    /// Image DPI.
    ///
    /// Has the same value as `Options::dpi`. Used for text rendering.
    pub dpi: f64,
    /// List of all referenced elements.
    pub defs: Vec<RefElement>,
    /// List of all elements.
    ///
    /// Contains list of all elements that should be rendered.
    pub elements: Vec<Element>,
}

impl Document {
    /// Returns referenced element by id.
    pub fn get_defs<'a>(&'a self, id: usize) -> &'a RefElement {
        &self.defs[id]
    }

    /// Converts the document to `svgdom::Document`.
    ///
    /// Used to save document to file for debug purposes.
    pub fn to_svgdom(&self) -> svgdom::Document {
        dump::conv_doc(self)
    }
}
<|endoftext|>


<commit_before>#![crate_name = "sum"]

/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

extern crate getopts;
extern crate libc;

use std::fs::File;
use std::io::{Read, Result, stdin, Write};
use std::path::Path;

#[path="../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "sum";
static VERSION: &'static str = "1.0.0";

fn bsd_sum(mut reader: Box<Read>) -> (usize, u16) {
    let mut buf = [0; 1024];
    let mut blocks_read = 0;
    let mut checksum: u16 = 0;
    loop {
        match reader.read(&mut buf) {
            Ok(n) if n != 0 => {
                blocks_read += 1;
                for &byte in buf[..n].iter() {
                    checksum = (checksum >> 1) + ((checksum & 1) << 15);
                    checksum += byte as u16;
                }
            },
            _ => break,
        }
    }

    (blocks_read, checksum)
}

fn sysv_sum(mut reader: Box<Read>) -> (usize, u16) {
    let mut buf = [0; 512];
    let mut blocks_read = 0;
    let mut ret = 0;

    loop {
        match reader.read(&mut buf) {
            Ok(n) if n != 0 => {
                blocks_read += 1;
                for &byte in buf[..n].iter() {
                    ret += byte as u32;
                }
            },
            _ => break,
        }
    }

    ret = (ret & 0xffff) + (ret >> 16);
    ret = (ret & 0xffff) + (ret >> 16);

    (blocks_read, ret as u16)
}

fn open(name: &str) -> Result<Box<Read>> {
    match name {
        "-" => Ok(Box::new(stdin()) as Box<Read>),
        _ => {
            let f = try!(File::open(&Path::new(name)));
            Ok(Box::new(f) as Box<Read>)
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optflag("r", "", "use the BSD compatible algorithm (default)");
    opts.optflag("s", "sysv", "use System V compatible algorithm");
    opts.optflag("h", "help", "show this help message");
    opts.optflag("v", "version", "print the version and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };

    if matches.opt_present("help") {
        let msg = format!("{0} {1}

Usage:
  {0} [OPTION]... [FILE]...

Checksum and count the blocks in a file.", NAME, VERSION);
        println!("{}\nWith no FILE, or when  FILE is -, read standard input.", opts.usage(&msg));
        return 0;
    }
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let sysv = matches.opt_present("sysv");

    let files = if matches.free.is_empty() {
        vec!["-".to_string()]
    } else {
        matches.free
    };

    let print_names = sysv || files.len() > 1;

    for file in files.iter() {
        let reader = match open(file) {
            Ok(f) => f,
            _ => crash!(1, "unable to open file")
        };
        let (blocks, sum) = if sysv {
            sysv_sum(reader)
        } else {
            bsd_sum(reader)
        };

        if print_names {
            println!("{} {} {}", sum, blocks, file);
        } else {
            println!("{} {}", sum, blocks);
        }
    }

    0
}
<commit_msg>Fix difference w/ GNU coreutils' sum.<commit_after>#![crate_name = "sum"]

/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

extern crate getopts;
extern crate libc;

use std::fs::File;
use std::io::{Read, Result, stdin, Write};
use std::path::Path;

#[path="../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "sum";
static VERSION: &'static str = "1.0.0";

fn bsd_sum(mut reader: Box<Read>) -> (usize, u16) {
    let mut buf = [0; 1024];
    let mut blocks_read = 0;
    let mut checksum: u16 = 0;
    loop {
        match reader.read(&mut buf) {
            Ok(n) if n != 0 => {
                blocks_read += 1;
                for &byte in buf[..n].iter() {
                    checksum = (checksum >> 1) + ((checksum & 1) << 15);
                    checksum += byte as u16;
                }
            },
            _ => break,
        }
    }

    (blocks_read, checksum)
}

fn sysv_sum(mut reader: Box<Read>) -> (usize, u16) {
    let mut buf = [0; 512];
    let mut blocks_read = 0;
    let mut ret = 0;

    loop {
        match reader.read(&mut buf) {
            Ok(n) if n != 0 => {
                blocks_read += 1;
                for &byte in buf[..n].iter() {
                    ret += byte as u32;
                }
            },
            _ => break,
        }
    }

    ret = (ret & 0xffff) + (ret >> 16);
    ret = (ret & 0xffff) + (ret >> 16);

    (blocks_read, ret as u16)
}

fn open(name: &str) -> Result<Box<Read>> {
    match name {
        "-" => Ok(Box::new(stdin()) as Box<Read>),
        _ => {
            let f = try!(File::open(&Path::new(name)));
            Ok(Box::new(f) as Box<Read>)
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optflag("r", "", "use the BSD compatible algorithm (default)");
    opts.optflag("s", "sysv", "use System V compatible algorithm");
    opts.optflag("h", "help", "show this help message");
    opts.optflag("v", "version", "print the version and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };

    if matches.opt_present("help") {
        let msg = format!("{0} {1}

Usage:
  {0} [OPTION]... [FILE]...

Checksum and count the blocks in a file.", NAME, VERSION);
        println!("{}\nWith no FILE, or when  FILE is -, read standard input.", opts.usage(&msg));
        return 0;
    }
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let sysv = matches.opt_present("sysv");

    let files = if matches.free.is_empty() {
        vec!["-".to_string()]
    } else {
        matches.free
    };

    let print_names = if sysv {
        files.len() > 1 || files[0] != "-"
    } else {
        files.len() > 1
    };

    for file in files.iter() {
        let reader = match open(file) {
            Ok(f) => f,
            _ => crash!(1, "unable to open file")
        };
        let (blocks, sum) = if sysv {
            sysv_sum(reader)
        } else {
            bsd_sum(reader)
        };

        if print_names {
            println!("{} {} {}", sum, blocks, file);
        } else {
            println!("{} {}", sum, blocks);
        }
    }

    0
}
<|endoftext|>


<commit_before>#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
          target_os = "netbsd", target_os = "macos", target_os = "linux"))]
pub mod aio;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod epoll;

#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd",
    target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
pub mod event;

#[cfg(target_os = "linux")]
pub mod eventfd;

#[cfg(target_os = "linux")]
pub mod memfd;

#[macro_use]
pub mod ioctl;

// TODO: Add support for dragonfly, freebsd, and ios/macos.
#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod sendfile;

pub mod signal;

#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod signalfd;

pub mod socket;

pub mod stat;

#[cfg(any(target_os = "linux"))]
pub mod reboot;

pub mod termios;

pub mod utsname;

pub mod wait;

pub mod mman;

pub mod uio;

pub mod time;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod ptrace;

pub mod select;

#[cfg(target_os = "linux")]
pub mod quota;

#[cfg(all(target_os = "linux",
          any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm")),
          )]
pub mod statfs;

#[cfg(all(any(target_os = "linux",
              target_os = "macos"),
          any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm")),
          )]
pub mod statvfs;
pub mod pthread;
<commit_msg>Sort target OSes alphabetically<commit_after>#[cfg(any(target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "ios",
          target_os = "linux",
          target_os = "macos",
          target_os = "netbsd"))]
pub mod aio;

#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod epoll;

#[cfg(any(target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "ios",
          target_os = "macos",
          target_os = "netbsd",
          target_os = "openbsd"))]
pub mod event;

#[cfg(target_os = "linux")]
pub mod eventfd;

#[cfg(target_os = "linux")]
pub mod memfd;

#[macro_use]
pub mod ioctl;

// TODO: Add support for dragonfly, freebsd, and ios/macos.
#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod sendfile;

pub mod signal;

#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod signalfd;

pub mod socket;

pub mod stat;

#[cfg(any(target_os = "linux"))]
pub mod reboot;

pub mod termios;

pub mod utsname;

pub mod wait;

pub mod mman;

pub mod uio;

pub mod time;

#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod ptrace;

pub mod select;

#[cfg(target_os = "linux")]
pub mod quota;

#[cfg(all(target_os = "linux",
          any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm")),
          )]
pub mod statfs;

#[cfg(all(any(target_os = "linux",
              target_os = "macos"),
          any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm")),
          )]
pub mod statvfs;
pub mod pthread;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::{self, File};
use std::iter::FromIterator;
use std::path::Path;

use xmltree::Element;

use {Error, Result};

#[derive(Debug, PartialEq)]
pub struct Project {
    scan_positions: HashMap<String, ScanPosition>,
}

impl Project {
    /// Reads a RiSCAN Pro project from a path.
    ///
    /// The path can either be the project directoy, which ends in `RiSCAN`, or the project XML
    /// file, `project.rsp`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use riscan_pro::Project;
    /// let project1 = Project::from_path("data/project.RiSCAN").unwrap();
    /// let project2 = Project::from_path("data/project.RiSCAN/project.rsp").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Project> {
        let mut path = path.as_ref().to_owned();
        if try!(fs::metadata(&path)).is_dir() {
            path.push("project.rsp");
        }
        let xml = try!(File::open(path)
            .map_err(Error::from)
            .and_then(|file| Element::parse(file).map_err(Error::from)));
        let scan_positions = try!(xml.map_children("scanpositions", |child| {
            let scan_position = try!(ScanPosition::from_element(child));
            Ok((scan_position.name().to_string(), scan_position))
        }));
        Ok(Project { scan_positions: scan_positions })
    }

    /// Returns scan position with the provided name.
    ///
    /// # Examples
    ///
    /// ```
    /// # use riscan_pro::Project;
    /// # let project = Project::from_path("data/project.RiSCAN").unwrap();
    /// let scan_position = project.scan_position("SP01").unwrap();
    /// ```
    pub fn scan_position(&self, name: &str) -> Option<&ScanPosition> {
        self.scan_positions.get(name)
    }

    /// Returns the image of the provided name in the specified scan position.
    ///
    /// # Examples
    ///
    /// ```
    /// # use riscan_pro::Project;
    /// # let project = Project::from_path("data/project.RiSCAN").unwrap();
    /// let image = project.image("SP01", "SP01 - Image001").unwrap();
    /// ```
    pub fn image(&self, scan_position: &str, image: &str) -> Option<&Image> {
        self.scan_position(scan_position).and_then(|scan_position| scan_position.image(image))
    }
}

trait GetDescendant {
    fn get_descendant(&self, name: &str) -> Result<&Element>;
    fn get_children(&self, name: &str) -> Result<&Vec<Element>> {
        self.get_descendant(name).map(|e| &e.children)
    }
    fn get_text(&self, name: &str) -> Result<&str> {
        self.get_descendant(name)
            .and_then(|e| {
                e.text.as_ref().map(|s| s.as_str()).ok_or(Error::MissingElement(name.to_string()))
            })
    }
    fn map_children<F, A, B>(&self, name: &str, function: F) -> Result
        where F: Fn(&Element) -> Result,
              A: FromIterator
    {
        self.get_children(name).and_then(|children| {
            children.iter()
                .map(function)
                .collect()
        })
    }
}

impl GetDescendant for Element {
    fn get_descendant(&self, name: &str) -> Result<&Element> {
        let mut element = self;
        for name in name.split('/') {
            match element.get_child(name) {
                Some(child) => element = child,
                None => return Err(Error::MissingElement(name.to_string())),
            }
        }
        Ok(element)
    }
}

/// A fixed postion where one or more scans were taken, along with optional pictures and other data.
#[derive(Debug, PartialEq)]
pub struct ScanPosition {
    name: String,
    images: HashMap<String, Image>,
}

impl ScanPosition {
    fn from_element(element: &Element) -> Result<ScanPosition> {
        let images = try!(element.map_children("scanposimages", |child| {
            let image = try!(Image::from_element(child));
            Ok((image.name().to_string(), image))
        }));
        Ok(ScanPosition {
            name: try!(element.get_text("name")).to_string(),
            images: images,
        })
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn color(&self, x: f64, y: f64, z: f64) -> Option<f64> {
        for image in self.images() {
            let color = image.color(x, y, z);
            if color.is_some() {
                return color;
            }
        }
        None
    }

    fn images(&self) -> &Vec<Image> {
        unimplemented!()
    }

    fn image(&self, name: &str) -> Option<&Image> {
        self.images.get(name)
    }
}

#[derive(Debug, PartialEq)]
pub struct Image {
    name: String,
}

impl Image {
    fn from_element(element: &Element) -> Result<Image> {
        Ok(Image { name: try!(element.get_text("name")).to_string() })
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn color(&self, x: f64, y: f64, z: f64) -> Option<f64> {
        let (u, v) = self.project(x, y, z);
        unimplemented!()
    }

    fn project(&self, x: f64, y: f64, z: f64) -> (f64, f64) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn project_from_path_ok() {
        let project1 = Project::from_path("data/project.RiSCAN").unwrap();
        let project2 = Project::from_path("data/project.RiSCAN/project.rsp").unwrap();
        assert_eq!(project1, project2);
    }

    #[test]
    fn project_from_path_not_ok() {
        assert!(Project::from_path("notaproject").is_err());
    }

    #[test]
    fn project_scan_position() {
        let project = Project::from_path("data/project.RiSCAN").unwrap();
        assert!(project.scan_position("SP01").is_some());
        assert!(project.scan_position("SP02").is_some());
        assert!(project.scan_position("SP03").is_none());
    }

    #[test]
    fn image_color() {
        let project = Project::from_path("data/project.RiSCAN").unwrap();
        let image = project.image("SP01", "SP01 - Image001").unwrap();
        assert_eq!(22.49,
                   image.color(-139.31727, -239.32973, -10.49305).unwrap());
    }

    #[test]
    fn scan_position_color() {
        let project = Project::from_path("data/project.RiSCAN").unwrap();
        let scan_position = project.scan_position("SP01").unwrap();
        assert_eq!(22.49,
                   scan_position.color(-139.31727, -239.32973, -10.49305).unwrap());
    }
}
<commit_msg>Cleanup and make things public<commit_after>use std::collections::HashMap;
use std::fs::{self, File};
use std::iter::FromIterator;
use std::path::Path;

use xmltree::Element;

use {Error, Result};

#[derive(Debug, PartialEq)]
pub struct Project {
    scan_positions: HashMap<String, ScanPosition>,
}

impl Project {
    /// Reads a RiSCAN Pro project from a path.
    ///
    /// The path can either be the project directoy, which ends in `RiSCAN`, or the project XML
    /// file, `project.rsp`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use riscan_pro::Project;
    /// let project1 = Project::from_path("data/project.RiSCAN").unwrap();
    /// let project2 = Project::from_path("data/project.RiSCAN/project.rsp").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Project> {
        let mut path = path.as_ref().to_owned();
        if try!(fs::metadata(&path)).is_dir() {
            path.push("project.rsp");
        }
        let xml = try!(File::open(path)
            .map_err(Error::from)
            .and_then(|file| Element::parse(file).map_err(Error::from)));
        let scan_positions = try!(xml.map_children("scanpositions", |child| {
            let scan_position = try!(ScanPosition::from_element(child));
            Ok((scan_position.name().to_string(), scan_position))
        }));
        Ok(Project { scan_positions: scan_positions })
    }

    /// Returns scan position with the provided name.
    ///
    /// # Examples
    ///
    /// ```
    /// # use riscan_pro::Project;
    /// # let project = Project::from_path("data/project.RiSCAN").unwrap();
    /// let scan_position = project.scan_position("SP01").unwrap();
    /// ```
    pub fn scan_position(&self, name: &str) -> Option<&ScanPosition> {
        self.scan_positions.get(name)
    }

    /// Returns the image of the provided name in the specified scan position.
    ///
    /// # Examples
    ///
    /// ```
    /// # use riscan_pro::Project;
    /// # let project = Project::from_path("data/project.RiSCAN").unwrap();
    /// let image = project.image("SP01", "SP01 - Image001").unwrap();
    /// ```
    pub fn image(&self, scan_position: &str, image: &str) -> Option<&Image> {
        self.scan_position(scan_position).and_then(|scan_position| scan_position.image(image))
    }
}

trait GetDescendant {
    fn get_descendant(&self, name: &str) -> Result<&Element>;
    fn get_children(&self, name: &str) -> Result<&Vec<Element>> {
        self.get_descendant(name).map(|e| &e.children)
    }
    fn get_text(&self, name: &str) -> Result<&str> {
        self.get_descendant(name)
            .and_then(|e| {
                e.text.as_ref().map(|s| s.as_str()).ok_or(Error::MissingElement(name.to_string()))
            })
    }
    fn map_children<F, A, B>(&self, name: &str, function: F) -> Result
        where F: Fn(&Element) -> Result,
              A: FromIterator
    {
        self.get_children(name).and_then(|children| {
            children.iter()
                .map(function)
                .collect()
        })
    }
}

impl GetDescendant for Element {
    fn get_descendant(&self, name: &str) -> Result<&Element> {
        let mut element = self;
        for name in name.split('/') {
            match element.get_child(name) {
                Some(child) => element = child,
                None => return Err(Error::MissingElement(name.to_string())),
            }
        }
        Ok(element)
    }
}

/// A fixed postion where one or more scans were taken, along with optional pictures and other data.
#[derive(Debug, PartialEq)]
pub struct ScanPosition {
    name: String,
    images: HashMap<String, Image>,
}

impl ScanPosition {
    fn from_element(element: &Element) -> Result<ScanPosition> {
        let images = try!(element.map_children("scanposimages", |child| {
            let image = try!(Image::from_element(child));
            Ok((image.name().to_string(), image))
        }));
        Ok(ScanPosition {
            name: try!(element.get_text("name")).to_string(),
            images: images,
        })
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn color(&self, x: f64, y: f64, z: f64) -> Option<f64> {
        for image in self.images() {
            let color = image.color(x, y, z);
            if color.is_some() {
                return color;
            }
        }
        None
    }

    pub fn images(&self) -> &Vec<Image> {
        unimplemented!()
    }

    pub fn image(&self, name: &str) -> Option<&Image> {
        self.images.get(name)
    }
}

#[derive(Debug, PartialEq)]
pub struct Image {
    name: String,
}

impl Image {
    fn from_element(element: &Element) -> Result<Image> {
        Ok(Image { name: try!(element.get_text("name")).to_string() })
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn color(&self, x: f64, y: f64, z: f64) -> Option<f64> {
        let (u, v) = self.project(x, y, z);
        unimplemented!()
    }

    fn project(&self, x: f64, y: f64, z: f64) -> (f64, f64) {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn project_from_path_ok() {
        let project1 = Project::from_path("data/project.RiSCAN").unwrap();
        let project2 = Project::from_path("data/project.RiSCAN/project.rsp").unwrap();
        assert_eq!(project1, project2);
    }

    #[test]
    fn project_from_path_not_ok() {
        assert!(Project::from_path("notaproject").is_err());
    }

    #[test]
    fn project_scan_position() {
        let project = Project::from_path("data/project.RiSCAN").unwrap();
        assert!(project.scan_position("SP01").is_some());
        assert!(project.scan_position("SP02").is_some());
        assert!(project.scan_position("SP03").is_none());
    }

    #[test]
    fn image_color() {
        let project = Project::from_path("data/project.RiSCAN").unwrap();
        let image = project.image("SP01", "SP01 - Image001").unwrap();
        assert_eq!(22.49,
                   image.color(-139.31727, -239.32973, -10.49305).unwrap());
    }

    #[test]
    fn scan_position_color() {
        let project = Project::from_path("data/project.RiSCAN").unwrap();
        let scan_position = project.scan_position("SP01").unwrap();
        assert_eq!(22.49,
                   scan_position.color(-139.31727, -239.32973, -10.49305).unwrap());
    }
}
<|endoftext|>