<commit_before>use {
    AddPolygons,
    Borrowed,
    Color,
    Field,
    Matrix2d,
    TweenPolygonsColorContext,
    Value,
    View,
};
use vecmath::{
    identity
};
use internal::{
    CanColor,
    CanTransform,
    HasColor,
    HasTransform,
};

/// An animation inbetweening context with color.
pub struct TweenColorContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current color.
    pub color: Field<'a, Color>,
    /// Animation inbetweening factor.
    pub tween_factor: Field<'a, f64>,
}

impl<'a> HasColor<'a, Color> for TweenColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, TweenColorContext<'a>, Color> for TweenColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

impl<'a> HasTransform<'a, Matrix2d> for TweenColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, TweenColorContext<'a>, Matrix2d> for TweenColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

impl<'a> AddPolygons<'a, TweenPolygonsColorContext<'a>> for TweenColorContext<'a> {
    #[inline(always)]
    fn polygons(&'a self, polygons: &'a [&'a [f64]]) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
            polygons: Value(polygons),
        }
    }
}

impl<'a> View<'a> for TweenColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            tween_factor: Borrowed(self.tween_factor.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

<commit_msg>Implemented `Clear` for `TweenColorContext`<commit_after>use {
    AddPolygons,
    BackEnd,
    Borrowed,
    Clear,
    Color,
    Field,
    Matrix2d,
    TweenPolygonsColorContext,
    Value,
    View,
};
use vecmath::{
    identity
};
use internal::{
    CanColor,
    CanTransform,
    HasColor,
    HasTransform,
};

/// An animation inbetweening context with color.
pub struct TweenColorContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current color.
    pub color: Field<'a, Color>,
    /// Animation inbetweening factor.
    pub tween_factor: Field<'a, f64>,
}

impl<'a> HasColor<'a, Color> for TweenColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, TweenColorContext<'a>, Color> for TweenColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

impl<'a> HasTransform<'a, Matrix2d> for TweenColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, TweenColorContext<'a>, Matrix2d> for TweenColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

impl<'a> AddPolygons<'a, TweenPolygonsColorContext<'a>> for TweenColorContext<'a> {
    #[inline(always)]
    fn polygons(&'a self, polygons: &'a [&'a [f64]]) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
            polygons: Value(polygons),
        }
    }
}

impl<'a> View<'a> for TweenColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            tween_factor: Borrowed(self.tween_factor.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

impl<'a> Clear for TweenColorContext<'a> {
    fn clear<B: BackEnd>(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        }
    }
}

<|endoftext|>


<commit_before>//! A simple module for creating an OFS disk image

use std::io::prelude::*;
use std::io::BufWriter;
use std::fs::File;
use std::path::Path;
use std::process::exit;
use std::cmp::min;
use std::mem;

/// The size of a sector in bytes
pub const SECTOR_SIZE: u32 = 512; // bytes

const INODE_SIZE: usize = 128; // bytes
const DNODE_SIZE: usize = 512; // bytes

/// Represents an OFS disk image, which can be written to a file
pub struct OFSImage {
    /// The number of inodes in the fs
    num_inodes: u32,

    /// The number of dnodes in the fs
    num_dnodes: u32,

    /// A list of inodes
    inodes: Vec<Option<Inode>>,

    /// A list of dnodes
    dnodes: Vec<Option<Dnode>>,
}

#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct Inode {
    name: [u8; 12], // file name (up to 12B)
    uid: u32, // owner UID
    gid: u32, // group GID
    user_perm: u8, // user permissions
    group_perm: u8, // group permissions
    all_perm: u8, // everyone permissions
    flags: u8, // various flags
    size: u32, // file size in bytes NOTE: for now this must a multiple of 4
    data: u32, // index of Dnode with contents
    created: u32, // date created
    modified: u32, // date last modified
    links: [u32; 22],
}

impl Inode {
    fn new() -> Inode {
        Inode {
            name: [0; 12],
            uid: 0,
            gid: 0,
            user_perm: 0,
            group_perm: 0,
            all_perm: 0,
            flags: 0,
            size: 0,
            data: 0,
            created: 0,
            modified: 0,
            links: [0; 22],
        }
    }
}

#[derive(Copy)]
#[repr(C, packed)]
pub struct Dnode {
    bytes: [u8; DNODE_SIZE], // contents
}

impl Clone for Dnode {
    fn clone(&self) -> Dnode {
        let mut cloned = [0; DNODE_SIZE];
        for d in 0..cloned.len() {
            cloned[d] = self.bytes[d];
        }
        Dnode { bytes: cloned }
    }
}

impl OFSImage {
    /// Create a new OFSImage with the given numbers of inodes and dnodes.
    pub fn new(num_inodes: u32, num_dnodes: u32) -> OFSImage {
        let mut inodes = Vec::with_capacity(num_inodes as usize);
        let mut dnodes = Vec::with_capacity(num_dnodes as usize);

        for _ in 0..num_inodes {
            inodes.push(None)
        }

        for _ in 0..num_dnodes {
            dnodes.push(None)
        }

        OFSImage {
            num_inodes: num_inodes,
            num_dnodes: num_dnodes,
            inodes: inodes,
            dnodes: dnodes,
        }
    }

    /// Allocate an inode in the file system and return mutable reference to it.
    pub fn alloc_inode(&mut self) -> &mut Inode {
        let first_free = (0..self.num_inodes)
            .find(|i| self.inodes.get_mut(*i as usize).unwrap().is_none())
            .unwrap_or_else(|| panic!("No inodes left!")) as usize;

        *self.inodes.get_mut(first_free).unwrap() = Some(Inode::new());

        self.inodes
            .get_mut(first_free)
            .unwrap()
            .as_mut()
            .unwrap()
    }

    /// Allocate a dnode in the file system and return its dnode index.
    pub fn alloc_dnode(&mut self) -> usize {
        let first_free = (0..self.num_dnodes)
            .find(|i| self.dnodes.get_mut(*i as usize).unwrap().is_none())
            .unwrap_or_else(|| panic!("No dnodes left!")) as usize;

        *self.dnodes.get_mut(first_free).unwrap() = Some(Dnode { bytes: [0; DNODE_SIZE] });

        first_free
    }

    /// Get the `i`th dnode.
    ///
    /// # Panics
    /// if the `i`th dnode is not allocated
    pub fn get_dnode(&mut self, i: u32) -> &mut Dnode {
        self.dnodes
            .get_mut(i as usize)
            .unwrap()
            .as_mut()
            .unwrap_or_else(|| panic!("dnode {} is not allocated", i))
    }

    /// Copy the file (on the host machine) to the OFS image. No guarantees are made about
    /// the order of inodes or dnodes chosen.
    pub fn add_file(&mut self, file: &str) {
        // open the file and read it
        if !Path::new(file).is_file() {
            println!("Error! No such file or directory '{}'.", file);
            exit(1);
        }
        let mut f = File::open(file).ok().unwrap();

        // get the file size (bytes)
        let size = f.metadata().ok().unwrap().len();

        // create the dnodes
        let mut remaining = size;
        let mut first_dnode = 0;

        let mut next_dnode = first_dnode;
        while remaining > DNODE_SIZE as u64 {
            // allocate a dnode
            let prev_dnode = next_dnode;
            next_dnode = self.alloc_dnode();
            if remaining == size {
                // don't forget where the file begins ;)
                first_dnode = next_dnode;
            } else {
                // chain the dnodes
                let dnode = self.get_dnode(prev_dnode as u32);
                dnode.bytes[DNODE_SIZE - 1] = ((next_dnode >> 24) & 0xFF) as u8;
                dnode.bytes[DNODE_SIZE - 2] = ((next_dnode >> 16) & 0xFF) as u8;
                dnode.bytes[DNODE_SIZE - 3] = ((next_dnode >> 8) & 0xFF) as u8;
                dnode.bytes[DNODE_SIZE - 4] = ((next_dnode) & 0xFF) as u8;
            }

            // read DNODE_SIZE - 4 bytes
            let mut buf = [0; DNODE_SIZE - 4]; // last 32-bit word is for the next-ptr
            let _ = f.read_exact(&mut buf).ok().unwrap();

            // copy to the dnode
            let mut dnode_bytes = [0; DNODE_SIZE];
            for i in 0..(DNODE_SIZE - 4) {
                dnode_bytes[i] = buf[i];
            }

            let dnode = self.get_dnode(next_dnode as u32);
            dnode.bytes = dnode_bytes;

            // update counter
            remaining -= (DNODE_SIZE - 4) as u64;
        }

        // create the last dnode
        let last_dnode_idx = self.alloc_dnode() as u32;
        {
            let last_dnode = self.get_dnode(last_dnode_idx);
            let _ = f.read_exact(&mut last_dnode.bytes);
        }

        if size > DNODE_SIZE as u64 {
            let second_last = self.get_dnode(next_dnode as u32);
            second_last.bytes[DNODE_SIZE - 1] = ((last_dnode_idx >> 24) & 0xFF) as u8;
            second_last.bytes[DNODE_SIZE - 2] = ((last_dnode_idx >> 16) & 0xFF) as u8;
            second_last.bytes[DNODE_SIZE - 3] = ((last_dnode_idx >> 8) & 0xFF) as u8;
            second_last.bytes[DNODE_SIZE - 4] = ((last_dnode_idx) & 0xFF) as u8;
        }

        // create the inode
        let inode = self.alloc_inode();

        let basename_str = Path::new(file)
            .canonicalize()
            .expect("Cannot canonicalize file path!")
            .file_name()
            .unwrap()
            .to_os_string();

        let basename = basename_str.to_str()
            .unwrap();

        inode.size = size as u32;
        for i in 0..min(12, basename.len()) {
            inode.name[i] = basename.as_bytes()[i];
        }
        inode.data = first_dnode as u32;

        println!("Added file '{}' to image.", basename);
    }

    /// Write the bytes of this OFSImage to the given file.
    pub fn burn(&self, file: &str) {
        let outfile = File::create(file)
            .expect(format!("Cannot write to file '{}'", file).as_str());
        let mut wbuf = BufWriter::new(outfile); // buffer writes

        // metadata sector
        let mut buf = [0; SECTOR_SIZE as usize];

        // magic bytes
        buf[0] = 'O' as u8;
        buf[1] = 'F' as u8;
        buf[2] = 'S' as u8;

        // inode count
        buf[7] = ((self.num_inodes >> 24) & 0xFF) as u8;
        buf[6] = ((self.num_inodes >> 16) & 0xFF) as u8;
        buf[5] = ((self.num_inodes >> 8) & 0xFF) as u8;
        buf[4] = ((self.num_inodes) & 0xFF) as u8;

        // dnode count
        buf[11] = ((self.num_dnodes >> 24) & 0xFF) as u8;
        buf[10] = ((self.num_dnodes >> 16) & 0xFF) as u8;
        buf[9] = ((self.num_dnodes >> 8) & 0xFF) as u8;
        buf[8] = ((self.num_dnodes) & 0xFF) as u8;

        let _ = wbuf.write_all(&buf);

        // inode bitmap
        let inode_bitmap_sectors =
            (self.num_inodes as f64 / SECTOR_SIZE as f64 / 8.0).ceil() as usize;
        for i in 0..inode_bitmap_sectors {
            buf = [0; SECTOR_SIZE as usize];

            // create this section of the bit map
            for j in 0..(SECTOR_SIZE * 8) as usize {
                if self.inodes.get(i * SECTOR_SIZE as usize * 8 + j).unwrap().is_some() {
                    buf[j / 8] |= (1 << (j % 8)) as u8;
                }
            }

            let _ = wbuf.write_all(&buf);
        }

        // dnode bitmap
        let dnode_bitmap_sectors =
            (self.num_dnodes as f64 / SECTOR_SIZE as f64 / 8.0).ceil() as usize;
        for i in 0..dnode_bitmap_sectors {
            buf = [0; SECTOR_SIZE as usize];

            // create this section of the bit map
            for j in 0..(SECTOR_SIZE * 8) as usize {
                if self.dnodes.get(i * SECTOR_SIZE as usize * 8 + j).unwrap().is_some() {
                    buf[j / 8] |= (1 << (j % 8)) as u8;
                }
            }

            let _ = wbuf.write_all(&buf);
        }

        // inodes
        let inodes_per_sector = SECTOR_SIZE as usize / INODE_SIZE;
        let mut inode_ct = 0;
        let mut inode_buf = [Inode::new(); SECTOR_SIZE as usize / INODE_SIZE];

        for inode_opt in self.inodes.iter() {
            inode_buf[inode_ct % inodes_per_sector] = match *inode_opt {
                Some(ref inode) => (*inode).clone(),
                None => Inode::new(),
            };

            inode_ct += 1;

            if inode_ct % (SECTOR_SIZE as usize / INODE_SIZE) == 0 {
                let _ = wbuf.write_all(unsafe {
                    &mem::transmute::<_, [u8; SECTOR_SIZE as usize]>(inode_buf)
                });
            }
        }

        // dnodes
        let dnodes_per_sector = SECTOR_SIZE as usize / DNODE_SIZE;
        let mut dnode_ct = 0;
        let mut dnode_buf = [Dnode { bytes: [0; DNODE_SIZE] }; SECTOR_SIZE as usize / DNODE_SIZE];

        for dnode_opt in self.dnodes.iter() {
            dnode_buf[dnode_ct % dnodes_per_sector] = match *dnode_opt {
                Some(ref dnode) => (*dnode).clone(),
                None => Dnode { bytes: [0; DNODE_SIZE] },
            };

            dnode_ct += 1;

            if dnode_ct % dnodes_per_sector == 0 {
                let _ = wbuf.write_all(unsafe {
                    &mem::transmute::<_, [u8; SECTOR_SIZE as usize]>(dnode_buf)
                });
            }
        }

        // flush the buffer
        let _ = wbuf.flush();

        println!("Burned image to file '{}'.", file);
    }
}
<commit_msg>Minor improvement<commit_after>//! A simple module for creating an OFS disk image

use std::io::prelude::*;
use std::io::BufWriter;
use std::fs::File;
use std::path::Path;
use std::process::exit;
use std::cmp::min;
use std::mem;

/// The size of a sector in bytes
pub const SECTOR_SIZE: u32 = 512; // bytes

const INODE_SIZE: usize = 128; // bytes
const DNODE_SIZE: usize = 512; // bytes

/// Represents an OFS disk image, which can be written to a file
pub struct OFSImage {
    /// The number of inodes in the fs
    num_inodes: u32,

    /// The number of dnodes in the fs
    num_dnodes: u32,

    /// A list of inodes
    inodes: Vec<Option<Inode>>,

    /// A list of dnodes
    dnodes: Vec<Option<Dnode>>,
}

#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct Inode {
    name: [u8; 12], // file name (up to 12B)
    uid: u32, // owner UID
    gid: u32, // group GID
    user_perm: u8, // user permissions
    group_perm: u8, // group permissions
    all_perm: u8, // everyone permissions
    flags: u8, // various flags
    size: u32, // file size in bytes NOTE: for now this must a multiple of 4
    data: u32, // index of Dnode with contents
    created: u32, // date created
    modified: u32, // date last modified
    links: [u32; 22],
}

impl Inode {
    fn new() -> Inode {
        Inode {
            name: [0; 12],
            uid: 0,
            gid: 0,
            user_perm: 0,
            group_perm: 0,
            all_perm: 0,
            flags: 0,
            size: 0,
            data: 0,
            created: 0,
            modified: 0,
            links: [0; 22],
        }
    }
}

#[derive(Copy)]
#[repr(C, packed)]
pub struct Dnode {
    bytes: [u8; DNODE_SIZE], // contents
}

impl Clone for Dnode {
    fn clone(&self) -> Dnode {
        let mut cloned = [0; DNODE_SIZE];
        for d in 0..cloned.len() {
            cloned[d] = self.bytes[d];
        }
        Dnode { bytes: cloned }
    }
}

impl OFSImage {
    /// Create a new OFSImage with the given numbers of inodes and dnodes.
    pub fn new(num_inodes: u32, num_dnodes: u32) -> OFSImage {
        OFSImage {
            num_inodes: num_inodes,
            num_dnodes: num_dnodes,
            inodes: vec![None; num_inodes as usize],
            dnodes: vec![None; num_dnodes as usize],
        }
    }

    /// Allocate an inode in the file system and return mutable reference to it.
    pub fn alloc_inode(&mut self) -> &mut Inode {
        let first_free = (0..self.num_inodes)
            .find(|i| self.inodes.get_mut(*i as usize).unwrap().is_none())
            .unwrap_or_else(|| panic!("No inodes left!")) as usize;

        *self.inodes.get_mut(first_free).unwrap() = Some(Inode::new());

        self.inodes
            .get_mut(first_free)
            .unwrap()
            .as_mut()
            .unwrap()
    }

    /// Allocate a dnode in the file system and return its dnode index.
    pub fn alloc_dnode(&mut self) -> usize {
        let first_free = (0..self.num_dnodes)
            .find(|i| self.dnodes.get_mut(*i as usize).unwrap().is_none())
            .unwrap_or_else(|| panic!("No dnodes left!")) as usize;

        *self.dnodes.get_mut(first_free).unwrap() = Some(Dnode { bytes: [0; DNODE_SIZE] });

        first_free
    }

    /// Get the `i`th dnode.
    ///
    /// # Panics
    /// if the `i`th dnode is not allocated
    pub fn get_dnode(&mut self, i: u32) -> &mut Dnode {
        self.dnodes
            .get_mut(i as usize)
            .unwrap()
            .as_mut()
            .unwrap_or_else(|| panic!("dnode {} is not allocated", i))
    }

    /// Copy the file (on the host machine) to the OFS image. No guarantees are made about
    /// the order of inodes or dnodes chosen.
    pub fn add_file(&mut self, file: &str) {
        // open the file and read it
        if !Path::new(file).is_file() {
            println!("Error! No such file or directory '{}'.", file);
            exit(1);
        }
        let mut f = File::open(file).ok().unwrap();

        // get the file size (bytes)
        let size = f.metadata().ok().unwrap().len();

        // create the dnodes
        let mut remaining = size;
        let mut first_dnode = 0;

        let mut next_dnode = first_dnode;
        while remaining > DNODE_SIZE as u64 {
            // allocate a dnode
            let prev_dnode = next_dnode;
            next_dnode = self.alloc_dnode();
            if remaining == size {
                // don't forget where the file begins ;)
                first_dnode = next_dnode;
            } else {
                // chain the dnodes
                let dnode = self.get_dnode(prev_dnode as u32);
                dnode.bytes[DNODE_SIZE - 1] = ((next_dnode >> 24) & 0xFF) as u8;
                dnode.bytes[DNODE_SIZE - 2] = ((next_dnode >> 16) & 0xFF) as u8;
                dnode.bytes[DNODE_SIZE - 3] = ((next_dnode >> 8) & 0xFF) as u8;
                dnode.bytes[DNODE_SIZE - 4] = ((next_dnode) & 0xFF) as u8;
            }

            // read DNODE_SIZE - 4 bytes
            let mut buf = [0; DNODE_SIZE - 4]; // last 32-bit word is for the next-ptr
            let _ = f.read_exact(&mut buf).ok().unwrap();

            // copy to the dnode
            let mut dnode_bytes = [0; DNODE_SIZE];
            for i in 0..(DNODE_SIZE - 4) {
                dnode_bytes[i] = buf[i];
            }

            let dnode = self.get_dnode(next_dnode as u32);
            dnode.bytes = dnode_bytes;

            // update counter
            remaining -= (DNODE_SIZE - 4) as u64;
        }

        // create the last dnode
        let last_dnode_idx = self.alloc_dnode() as u32;
        {
            let last_dnode = self.get_dnode(last_dnode_idx);
            let _ = f.read_exact(&mut last_dnode.bytes);
        }

        if size > DNODE_SIZE as u64 {
            let second_last = self.get_dnode(next_dnode as u32);
            second_last.bytes[DNODE_SIZE - 1] = ((last_dnode_idx >> 24) & 0xFF) as u8;
            second_last.bytes[DNODE_SIZE - 2] = ((last_dnode_idx >> 16) & 0xFF) as u8;
            second_last.bytes[DNODE_SIZE - 3] = ((last_dnode_idx >> 8) & 0xFF) as u8;
            second_last.bytes[DNODE_SIZE - 4] = ((last_dnode_idx) & 0xFF) as u8;
        }

        // create the inode
        let inode = self.alloc_inode();

        let basename_str = Path::new(file)
            .canonicalize()
            .expect("Cannot canonicalize file path!")
            .file_name()
            .unwrap()
            .to_os_string();

        let basename = basename_str.to_str()
            .unwrap();

        inode.size = size as u32;
        for i in 0..min(12, basename.len()) {
            inode.name[i] = basename.as_bytes()[i];
        }
        inode.data = first_dnode as u32;

        println!("Added file '{}' to image.", basename);
    }

    /// Write the bytes of this OFSImage to the given file.
    pub fn burn(&self, file: &str) {
        let outfile = File::create(file)
            .expect(format!("Cannot write to file '{}'", file).as_str());
        let mut wbuf = BufWriter::new(outfile); // buffer writes

        // metadata sector
        let mut buf = [0; SECTOR_SIZE as usize];

        // magic bytes
        buf[0] = 'O' as u8;
        buf[1] = 'F' as u8;
        buf[2] = 'S' as u8;

        // inode count
        buf[7] = ((self.num_inodes >> 24) & 0xFF) as u8;
        buf[6] = ((self.num_inodes >> 16) & 0xFF) as u8;
        buf[5] = ((self.num_inodes >> 8) & 0xFF) as u8;
        buf[4] = ((self.num_inodes) & 0xFF) as u8;

        // dnode count
        buf[11] = ((self.num_dnodes >> 24) & 0xFF) as u8;
        buf[10] = ((self.num_dnodes >> 16) & 0xFF) as u8;
        buf[9] = ((self.num_dnodes >> 8) & 0xFF) as u8;
        buf[8] = ((self.num_dnodes) & 0xFF) as u8;

        let _ = wbuf.write_all(&buf);

        // inode bitmap
        let inode_bitmap_sectors =
            (self.num_inodes as f64 / SECTOR_SIZE as f64 / 8.0).ceil() as usize;
        for i in 0..inode_bitmap_sectors {
            buf = [0; SECTOR_SIZE as usize];

            // create this section of the bit map
            for j in 0..(SECTOR_SIZE * 8) as usize {
                if self.inodes.get(i * SECTOR_SIZE as usize * 8 + j).unwrap().is_some() {
                    buf[j / 8] |= (1 << (j % 8)) as u8;
                }
            }

            let _ = wbuf.write_all(&buf);
        }

        // dnode bitmap
        let dnode_bitmap_sectors =
            (self.num_dnodes as f64 / SECTOR_SIZE as f64 / 8.0).ceil() as usize;
        for i in 0..dnode_bitmap_sectors {
            buf = [0; SECTOR_SIZE as usize];

            // create this section of the bit map
            for j in 0..(SECTOR_SIZE * 8) as usize {
                if self.dnodes.get(i * SECTOR_SIZE as usize * 8 + j).unwrap().is_some() {
                    buf[j / 8] |= (1 << (j % 8)) as u8;
                }
            }

            let _ = wbuf.write_all(&buf);
        }

        // inodes
        let inodes_per_sector = SECTOR_SIZE as usize / INODE_SIZE;
        let mut inode_ct = 0;
        let mut inode_buf = [Inode::new(); SECTOR_SIZE as usize / INODE_SIZE];

        for inode_opt in self.inodes.iter() {
            inode_buf[inode_ct % inodes_per_sector] = match *inode_opt {
                Some(ref inode) => (*inode).clone(),
                None => Inode::new(),
            };

            inode_ct += 1;

            if inode_ct % (SECTOR_SIZE as usize / INODE_SIZE) == 0 {
                let _ = wbuf.write_all(unsafe {
                    &mem::transmute::<_, [u8; SECTOR_SIZE as usize]>(inode_buf)
                });
            }
        }

        // dnodes
        let dnodes_per_sector = SECTOR_SIZE as usize / DNODE_SIZE;
        let mut dnode_ct = 0;
        let mut dnode_buf = [Dnode { bytes: [0; DNODE_SIZE] }; SECTOR_SIZE as usize / DNODE_SIZE];

        for dnode_opt in self.dnodes.iter() {
            dnode_buf[dnode_ct % dnodes_per_sector] = match *dnode_opt {
                Some(ref dnode) => (*dnode).clone(),
                None => Dnode { bytes: [0; DNODE_SIZE] },
            };

            dnode_ct += 1;

            if dnode_ct % dnodes_per_sector == 0 {
                let _ = wbuf.write_all(unsafe {
                    &mem::transmute::<_, [u8; SECTOR_SIZE as usize]>(dnode_buf)
                });
            }
        }

        // flush the buffer
        let _ = wbuf.flush();

        println!("Burned image to file '{}'.", file);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Rouille developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::io;
use std::io::Write;
use std::mem;
use std::sync::mpsc::Sender;
use ReadWrite;
use Upgrade;

use websocket::low_level;

/// A successful websocket. An open channel of communication. Implements `Read` and `Write`.
pub struct Websocket {
    // The socket. `None` if closed.
    socket: Option<Box<ReadWrite + Send>>,
    // The websocket state machine.
    state_machine: low_level::StateMachine,
    // True if the fragmented message currently being processed is binary. False if string. Pings
    // are excluded.
    current_message_binary: bool,
    // Buffer for the fragmented message currently being processed. Pings are excluded.
    current_message_payload: Vec<u8>,
    // Opcode of the fragment currently being processed.
    current_frame_opcode: u8,
    // Fin flag of the fragment currently being processed.
    current_frame_fin: bool,
    // Data of the fragment currently being processed.
    current_frame_payload: Vec<u8>,
    // Queue of the messages that are going to be returned by `next()`.
    messages_in_queue: Vec<Message>,
}

/// A message produced by a websocket connection.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Message {
    /// Text data. If the client is in Javascript, this happens when the client called `send()`
    /// with a string.
    Text(String),

    /// Binary data. If the client is in Javascript, this happens when the client called `send()`
    /// with a blob or an arraybuffer.
    Binary(Vec<u8>),
}

/// Error that can happen when sending a message to the client.
#[derive(Debug)]
pub enum SendError {
    /// Failed to transfer the message on the socket.
    IoError(io::Error),

    /// The websocket connection is closed.
    Closed,
}

impl From<io::Error> for SendError {
    #[inline]
    fn from(err: io::Error) -> SendError {
        SendError::IoError(err)
    }
}

impl Websocket {
    /// Sends text data over the websocket.
    ///
    /// Returns an error if the message didn't send correctly or if the connection is closed.
    ///
    /// If the client is in javascript, the message will contain a string.
    #[inline]
    pub fn send_text(&mut self, data: &str) -> Result<(), SendError> {
        let socket = match self.socket {
            Some(ref mut s) => s,
            None => return Err(SendError::Closed),
        };

        try!(send(data.as_bytes(), Write::by_ref(socket), 0x1));
        Ok(())
    }

    /// Sends binary data over the websocket.
    ///
    /// Returns an error if the message didn't send correctly or if the connection is closed.
    ///
    /// If the client is in javascript, the message will contain a blob or an arraybuffer.
    #[inline]
    pub fn send_binary(&mut self, data: &[u8]) -> Result<(), SendError> {
        let socket = match self.socket {
            Some(ref mut s) => s,
            None => return Err(SendError::Closed),
        };

        try!(send(data, Write::by_ref(socket), 0x2));
        Ok(())
    }

    /// Returns `true` if the websocket has been closed by either the client (voluntarily or not)
    /// or by the server (if the websocket protocol was violated).
    #[inline]
    pub fn is_closed(&self) -> bool {
        self.socket.is_none()
    }

    // TODO: give access to close reason
}

impl Upgrade for Sender<Websocket> {
    fn build(&mut self, socket: Box<ReadWrite + Send>) {
        let websocket = Websocket {
            socket: Some(socket),
            state_machine: low_level::StateMachine::new(),
            current_message_binary: false,
            current_message_payload: Vec::new(),
            current_frame_opcode: 0,
            current_frame_fin: false,
            current_frame_payload: Vec::new(),
            messages_in_queue: Vec::new(),
        };

        let _ = self.send(websocket);
    }
}

impl Iterator for Websocket {
    type Item = Message;

    fn next(&mut self) -> Option<Message> {
        loop {
            // If the socket is `None`, the connection has been closed.
            if self.socket.is_none() {
                return None;
            }

            // There may be some messages waiting to be processed.
            if !self.messages_in_queue.is_empty() {
                return Some(self.messages_in_queue.remove(0));
            }

            // Read `n` bytes in `buf`.
            let mut buf = [0; 256];
            let n = match self.socket.as_mut().unwrap().read(&mut buf) {
                Ok(n) => n,
                Err(ref err) if err.kind() == io::ErrorKind::Interrupted => 0,
                Err(_) => {
                    self.socket = None;
                    return None;
                },
            };

            // Fill `messages_in_queue` by analyzing the packets.
            for element in self.state_machine.feed(&buf[0 .. n]) {
                match element {
                    low_level::Element::FrameStart { fin, opcode, .. } => {
                        debug_assert!(self.current_frame_payload.is_empty());
                        self.current_frame_fin = fin;
                        self.current_frame_opcode = opcode;
                    },

                    low_level::Element::Data { data, last_in_frame } => {
                        // Under normal circumstances we just handle data by pushing it to
                        // `current_frame_payload`.
                        self.current_frame_payload.extend(data);

                        // But if the frame is finished we additionnally need to dispatch it.
                        if last_in_frame {
                            match self.current_frame_opcode {
                                // Frame is a continuation of the current message.
                                0x0 => {
                                    self.current_message_payload.append(&mut self.current_frame_payload);

                                    // If the message is finished, dispatch it.
                                    if self.current_frame_fin {
                                        let binary = mem::replace(&mut self.current_message_payload, Vec::new());

                                        if self.current_message_binary {
                                            self.messages_in_queue.push(Message::Binary(binary));
                                        } else {
                                            let string = match String::from_utf8(binary) {
                                                Ok(s) => s,
                                                Err(_) => {
                                                    // Closing connection because text wasn't UTF-8
                                                    let _ = send(b"1007 Invalid UTF-8 encoding",
                                                                 Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                                    self.socket = None;
                                                    return None;
                                                },
                                            };

                                            self.messages_in_queue.push(Message::Text(string));
                                        }
                                    }
                                },

                                // Frame is an individual text frame.
                                0x1 => {
                                    // If we're in the middle of a message, this frame is invalid
                                    // and we need to close.
                                    if !self.current_message_payload.is_empty() {
                                        let _ = send(b"1002 Expected continuation frame",
                                                     Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                        self.socket = None;
                                        return None;
                                    }

                                    if self.current_frame_fin {
                                        // There's only one frame in this message.
                                        let binary = mem::replace(&mut self.current_frame_payload,
                                                                  Vec::new());
                                        let string = match String::from_utf8(binary) {
                                            Ok(s) => s,
                                            Err(_err) => {
                                                // Closing connection because text wasn't UTF-8
                                                let _ = send(b"1007 Invalid UTF-8 encoding",
                                                             Write::by_ref(self.socket.as_mut().unwrap()),
                                                             0x8);
                                                self.socket = None;
                                                return None;
                                            },
                                        };

                                        self.messages_in_queue.push(Message::Text(string));

                                    } else {
                                        // Start of a fragmented message.
                                        self.current_message_binary = false;
                                        self.current_message_payload.append(&mut self.current_frame_payload);
                                    }
                                },

                                // Frame is an individual binary frame.
                                0x2 => {
                                    // If we're in the middle of a message, this frame is invalid
                                    // and we need to close.
                                    if !self.current_message_payload.is_empty() {
                                        let _ = send(b"1002 Expected continuation frame",
                                                     Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                        self.socket = None;
                                        return None;
                                    }

                                    if self.current_frame_fin {
                                        let binary = mem::replace(&mut self.current_frame_payload,
                                                                  Vec::new());
                                        self.messages_in_queue.push(Message::Binary(binary));
                                    } else {
                                        // Start of a fragmented message.
                                        self.current_message_binary = true;
                                        self.current_message_payload.append(&mut self.current_frame_payload);
                                    }
                                },

                                // Close request.
                                0x8 => {
                                    // We need to send a confirmation.
                                    let _ = send(&self.current_frame_payload,
                                                 Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                    // Since the packets are always received in order, and since
                                    // the server is considered dead as soon as it sends the
                                    // confirmation, we have no risk of losing packets.
                                    self.socket = None;
                                    return None;
                                },

                                // Ping.
                                0x9 => {
                                    // Send the pong.
                                    let _ = send(&self.current_frame_payload,
                                                 Write::by_ref(self.socket.as_mut().unwrap()), 0xA);
                                },

                                // Pong. We ignore this as there's nothing to do.
                                0xA => {},

                                // Unknown opcode means error and close.
                                _ => {
                                    let _ = send(b"Unknown opcode",
                                                 Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                    self.socket = None;
                                    return None;
                                },
                            }

                            self.current_frame_payload.clear();
                        }
                    },

                    low_level::Element::Error { desc } => {
                        // The low level layer signaled an error. Sending it to client and closing.
                        let _ = send(desc.as_bytes(), Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                        self.socket = None;
                        return None;
                    },
                }
            }
        }
    }
}

// Sends a mesage to a websocket.
// TODO: message fragmentation?
fn send<W: Write>(data: &[u8], mut dest: W, opcode: u8) -> io::Result<()> {
    // Write the opcode
    assert!(opcode <= 0xf);
    let first_byte = 0x80 | opcode;
    try!(dest.write_all(&[first_byte]));

    // Write the length
    if data.len() >= 65536 {
        try!(dest.write_all(&[127u8]));
        let len = data.len() as u64;
        assert!(len < 0x8000_0000_0000_0000);
        let len1 = (len >> 56) as u8;
        let len2 = (len >> 48) as u8;
        let len3 = (len >> 40) as u8;
        let len4 = (len >> 32) as u8;
        let len5 = (len >> 24) as u8;
        let len6 = (len >> 16) as u8;
        let len7 = (len >> 8) as u8;
        let len8 = (len >> 0) as u8;
        try!(dest.write_all(&[len1, len2, len3, len4, len5, len6, len7, len8]));

    } else if data.len() >= 126 {
        try!(dest.write_all(&[126u8]));
        let len = data.len() as u16;
        let len1 = (len >> 8) as u8;
        let len2 = len as u8;
        try!(dest.write_all(&[len1, len2]));

    } else {
        try!(dest.write_all(&[data.len() as u8]));
    }

    // Write the data
    try!(dest.write_all(data));
    try!(dest.flush());
    Ok(())
}
<commit_msg>Close websocket on EOF<commit_after>// Copyright (c) 2016 The Rouille developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::io;
use std::io::Write;
use std::mem;
use std::sync::mpsc::Sender;
use ReadWrite;
use Upgrade;

use websocket::low_level;

/// A successful websocket. An open channel of communication. Implements `Read` and `Write`.
pub struct Websocket {
    // The socket. `None` if closed.
    socket: Option<Box<ReadWrite + Send>>,
    // The websocket state machine.
    state_machine: low_level::StateMachine,
    // True if the fragmented message currently being processed is binary. False if string. Pings
    // are excluded.
    current_message_binary: bool,
    // Buffer for the fragmented message currently being processed. Pings are excluded.
    current_message_payload: Vec<u8>,
    // Opcode of the fragment currently being processed.
    current_frame_opcode: u8,
    // Fin flag of the fragment currently being processed.
    current_frame_fin: bool,
    // Data of the fragment currently being processed.
    current_frame_payload: Vec<u8>,
    // Queue of the messages that are going to be returned by `next()`.
    messages_in_queue: Vec<Message>,
}

/// A message produced by a websocket connection.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Message {
    /// Text data. If the client is in Javascript, this happens when the client called `send()`
    /// with a string.
    Text(String),

    /// Binary data. If the client is in Javascript, this happens when the client called `send()`
    /// with a blob or an arraybuffer.
    Binary(Vec<u8>),
}

/// Error that can happen when sending a message to the client.
#[derive(Debug)]
pub enum SendError {
    /// Failed to transfer the message on the socket.
    IoError(io::Error),

    /// The websocket connection is closed.
    Closed,
}

impl From<io::Error> for SendError {
    #[inline]
    fn from(err: io::Error) -> SendError {
        SendError::IoError(err)
    }
}

impl Websocket {
    /// Sends text data over the websocket.
    ///
    /// Returns an error if the message didn't send correctly or if the connection is closed.
    ///
    /// If the client is in javascript, the message will contain a string.
    #[inline]
    pub fn send_text(&mut self, data: &str) -> Result<(), SendError> {
        let socket = match self.socket {
            Some(ref mut s) => s,
            None => return Err(SendError::Closed),
        };

        try!(send(data.as_bytes(), Write::by_ref(socket), 0x1));
        Ok(())
    }

    /// Sends binary data over the websocket.
    ///
    /// Returns an error if the message didn't send correctly or if the connection is closed.
    ///
    /// If the client is in javascript, the message will contain a blob or an arraybuffer.
    #[inline]
    pub fn send_binary(&mut self, data: &[u8]) -> Result<(), SendError> {
        let socket = match self.socket {
            Some(ref mut s) => s,
            None => return Err(SendError::Closed),
        };

        try!(send(data, Write::by_ref(socket), 0x2));
        Ok(())
    }

    /// Returns `true` if the websocket has been closed by either the client (voluntarily or not)
    /// or by the server (if the websocket protocol was violated).
    #[inline]
    pub fn is_closed(&self) -> bool {
        self.socket.is_none()
    }

    // TODO: give access to close reason
}

impl Upgrade for Sender<Websocket> {
    fn build(&mut self, socket: Box<ReadWrite + Send>) {
        let websocket = Websocket {
            socket: Some(socket),
            state_machine: low_level::StateMachine::new(),
            current_message_binary: false,
            current_message_payload: Vec::new(),
            current_frame_opcode: 0,
            current_frame_fin: false,
            current_frame_payload: Vec::new(),
            messages_in_queue: Vec::new(),
        };

        let _ = self.send(websocket);
    }
}

impl Iterator for Websocket {
    type Item = Message;

    fn next(&mut self) -> Option<Message> {
        loop {
            // If the socket is `None`, the connection has been closed.
            if self.socket.is_none() {
                return None;
            }

            // There may be some messages waiting to be processed.
            if !self.messages_in_queue.is_empty() {
                return Some(self.messages_in_queue.remove(0));
            }

            // Read `n` bytes in `buf`.
            let mut buf = [0; 256];
            let n = match self.socket.as_mut().unwrap().read(&mut buf) {
                Ok(n) if n == 0 => {
                    // Read returning zero means EOF
                    self.socket = None;
                    return None;
                }
                Ok(n) => n,
                Err(ref err) if err.kind() == io::ErrorKind::Interrupted => 0,
                Err(_) => {
                    self.socket = None;
                    return None;
                },
            };

            // Fill `messages_in_queue` by analyzing the packets.
            for element in self.state_machine.feed(&buf[0 .. n]) {
                match element {
                    low_level::Element::FrameStart { fin, opcode, .. } => {
                        debug_assert!(self.current_frame_payload.is_empty());
                        self.current_frame_fin = fin;
                        self.current_frame_opcode = opcode;
                    },

                    low_level::Element::Data { data, last_in_frame } => {
                        // Under normal circumstances we just handle data by pushing it to
                        // `current_frame_payload`.
                        self.current_frame_payload.extend(data);

                        // But if the frame is finished we additionnally need to dispatch it.
                        if last_in_frame {
                            match self.current_frame_opcode {
                                // Frame is a continuation of the current message.
                                0x0 => {
                                    self.current_message_payload.append(&mut self.current_frame_payload);

                                    // If the message is finished, dispatch it.
                                    if self.current_frame_fin {
                                        let binary = mem::replace(&mut self.current_message_payload, Vec::new());

                                        if self.current_message_binary {
                                            self.messages_in_queue.push(Message::Binary(binary));
                                        } else {
                                            let string = match String::from_utf8(binary) {
                                                Ok(s) => s,
                                                Err(_) => {
                                                    // Closing connection because text wasn't UTF-8
                                                    let _ = send(b"1007 Invalid UTF-8 encoding",
                                                                 Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                                    self.socket = None;
                                                    return None;
                                                },
                                            };

                                            self.messages_in_queue.push(Message::Text(string));
                                        }
                                    }
                                },

                                // Frame is an individual text frame.
                                0x1 => {
                                    // If we're in the middle of a message, this frame is invalid
                                    // and we need to close.
                                    if !self.current_message_payload.is_empty() {
                                        let _ = send(b"1002 Expected continuation frame",
                                                     Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                        self.socket = None;
                                        return None;
                                    }

                                    if self.current_frame_fin {
                                        // There's only one frame in this message.
                                        let binary = mem::replace(&mut self.current_frame_payload,
                                                                  Vec::new());
                                        let string = match String::from_utf8(binary) {
                                            Ok(s) => s,
                                            Err(_err) => {
                                                // Closing connection because text wasn't UTF-8
                                                let _ = send(b"1007 Invalid UTF-8 encoding",
                                                             Write::by_ref(self.socket.as_mut().unwrap()),
                                                             0x8);
                                                self.socket = None;
                                                return None;
                                            },
                                        };

                                        self.messages_in_queue.push(Message::Text(string));

                                    } else {
                                        // Start of a fragmented message.
                                        self.current_message_binary = false;
                                        self.current_message_payload.append(&mut self.current_frame_payload);
                                    }
                                },

                                // Frame is an individual binary frame.
                                0x2 => {
                                    // If we're in the middle of a message, this frame is invalid
                                    // and we need to close.
                                    if !self.current_message_payload.is_empty() {
                                        let _ = send(b"1002 Expected continuation frame",
                                                     Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                        self.socket = None;
                                        return None;
                                    }

                                    if self.current_frame_fin {
                                        let binary = mem::replace(&mut self.current_frame_payload,
                                                                  Vec::new());
                                        self.messages_in_queue.push(Message::Binary(binary));
                                    } else {
                                        // Start of a fragmented message.
                                        self.current_message_binary = true;
                                        self.current_message_payload.append(&mut self.current_frame_payload);
                                    }
                                },

                                // Close request.
                                0x8 => {
                                    // We need to send a confirmation.
                                    let _ = send(&self.current_frame_payload,
                                                 Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                    // Since the packets are always received in order, and since
                                    // the server is considered dead as soon as it sends the
                                    // confirmation, we have no risk of losing packets.
                                    self.socket = None;
                                    return None;
                                },

                                // Ping.
                                0x9 => {
                                    // Send the pong.
                                    let _ = send(&self.current_frame_payload,
                                                 Write::by_ref(self.socket.as_mut().unwrap()), 0xA);
                                },

                                // Pong. We ignore this as there's nothing to do.
                                0xA => {},

                                // Unknown opcode means error and close.
                                _ => {
                                    let _ = send(b"Unknown opcode",
                                                 Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                                    self.socket = None;
                                    return None;
                                },
                            }

                            self.current_frame_payload.clear();
                        }
                    },

                    low_level::Element::Error { desc } => {
                        // The low level layer signaled an error. Sending it to client and closing.
                        let _ = send(desc.as_bytes(), Write::by_ref(self.socket.as_mut().unwrap()), 0x8);
                        self.socket = None;
                        return None;
                    },
                }
            }
        }
    }
}

// Sends a mesage to a websocket.
// TODO: message fragmentation?
fn send<W: Write>(data: &[u8], mut dest: W, opcode: u8) -> io::Result<()> {
    // Write the opcode
    assert!(opcode <= 0xf);
    let first_byte = 0x80 | opcode;
    try!(dest.write_all(&[first_byte]));

    // Write the length
    if data.len() >= 65536 {
        try!(dest.write_all(&[127u8]));
        let len = data.len() as u64;
        assert!(len < 0x8000_0000_0000_0000);
        let len1 = (len >> 56) as u8;
        let len2 = (len >> 48) as u8;
        let len3 = (len >> 40) as u8;
        let len4 = (len >> 32) as u8;
        let len5 = (len >> 24) as u8;
        let len6 = (len >> 16) as u8;
        let len7 = (len >> 8) as u8;
        let len8 = (len >> 0) as u8;
        try!(dest.write_all(&[len1, len2, len3, len4, len5, len6, len7, len8]));

    } else if data.len() >= 126 {
        try!(dest.write_all(&[126u8]));
        let len = data.len() as u16;
        let len1 = (len >> 8) as u8;
        let len2 = len as u8;
        try!(dest.write_all(&[len1, len2]));

    } else {
        try!(dest.write_all(&[data.len() as u8]));
    }

    // Write the data
    try!(dest.write_all(data));
    try!(dest.flush());
    Ok(())
}
<|endoftext|>


<commit_before>use std::fs;
use std::io::ErrorKind;
use std::path::Path;
use std::process::Command;

fn main() {
    let out_dir = Path::new(env!("OUT_DIR")).to_owned();
    let root = Path::new(env!("CARGO_MANIFEST_DIR")).to_owned();

    // Compile SCSS
    let scss_out = &out_dir.join("styles.css");
    Command::new("sass")
        .arg("scss/main.scss")
        .arg(scss_out.as_path().to_str().unwrap())
        .spawn()
        .unwrap_or_else(|e| {
            match e.kind() {
                ErrorKind::NotFound => panic!("sass not installed"),
                _ => panic!(e),
            }
        });

    // Apply PostCSS
    let output = &root.join("static/css/");
    fs::create_dir_all(&output).unwrap();
    Command::new("postcss")
        .args(&["--use", "autoprefixer"])
        .arg(scss_out.as_path().to_str().unwrap())
        .args(&["-d", output.as_path().to_str().unwrap()])
        .spawn()
        .unwrap_or_else(|e| {
            match e.kind() {
                ErrorKind::NotFound => panic!("postcss not installed"),
                _ => panic!(e),
            }
        });
}
<commit_msg>check output of commands in build script<commit_after>use std::fs;
use std::io::ErrorKind;
use std::path::Path;
use std::process::Command;

fn main() {
    let out_dir = Path::new(env!("OUT_DIR")).to_owned();
    let root = Path::new(env!("CARGO_MANIFEST_DIR")).to_owned();

    // Compile SCSS
    let scss_out = &out_dir.join("styles.css");
    let mut sass = Command::new("sass")
                       .arg("scss/main.scss")
                       .arg(scss_out.as_path().to_str().unwrap())
                       .spawn()
                       .unwrap_or_else(|e| {
                           match e.kind() {
                               ErrorKind::NotFound => panic!("sass not installed"),
                               _ => panic!(e),
                           }
                       });
    assert!(sass.wait().unwrap().success(),
            "there was a problem compiling scss");

    // Apply PostCSS
    let output = &root.join("static/css/");
    fs::create_dir_all(&output).unwrap();
    let mut postcss = Command::new("postcss")
                          .args(&["--use", "autoprefixer"])
                          .arg(scss_out.as_path().to_str().unwrap())
                          .args(&["-d", output.as_path().to_str().unwrap()])
                          .spawn()
                          .unwrap_or_else(|e| {
                              match e.kind() {
                                  ErrorKind::NotFound => panic!("postcss not installed"),
                                  _ => panic!(e),
                              }
                          });
    assert!(postcss.wait().unwrap().success(),
            "there was a problem postprocessing css");
}
<|endoftext|>


<commit_before>extern crate bindgen;

use std::env;
use std::io::Write;
use std::path::PathBuf;

#[cfg(not(target_os="windows"))]
fn default_include_dir(_: env::VarError) -> String {
    "/usr/include".to_owned()
}

#[cfg(target_os="windows")]
fn default_include_dir(_: env::VarError) -> String {
    panic!("No default directory for includes in windows")
}

fn main() {
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let in_path = PathBuf::from(env::var("CAPSTONE_INCLUDE_DIR")
        .unwrap_or_else(default_include_dir));

    let wrapper = out_path.join("wrapper.h");
    {
        let mut file = std::fs::File::create(&wrapper).unwrap();
        file.write_all(b"#include <capstone/capstone.h>").unwrap();
    }

    println!("cargo:rerun-if-changed={}",
             in_path.join("capstone").join("capstone.h").display());

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header(wrapper.to_str().unwrap())
        .clang_arg(format!("-I{}", in_path.display()))
        .link("capstone")
        .generate_comments(true)
        .bitfield_enum("cs_.*")
        .bitfield_enum("x86_.*")
        .bitfield_enum("arm_.*")
        .bitfield_enum("arm64_.*")
        .bitfield_enum("mips_.*")
        .bitfield_enum("ppc_.*")
        .bitfield_enum("sparc_.*")
        .bitfield_enum("sysz_.*")
        .bitfield_enum("xcore_.*")
        // Only generate bindings for all types that start with cs_ and types included by them.
        // This avoids generating bindings for standard c functions.
        .whitelisted_type("cs_.*")
        .whitelisted_function("cs_.*")
        .prepend_enum_name(false)
        .raw_line(DEBUG_IMPL)
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    bindings.write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

const DEBUG_IMPL: &'static str =
    "
use std::fmt;
impl fmt::Debug for cs_insn {
    fn fmt(&self, f: &mut fmt::Formatter) -> \
     fmt::Result {
        f.debug_struct(\"cs_insn\")
            .field(\"id\", &self.id)
            \
     .field(\"address\", &self.address)
            .field(\"size\", &self.size)
            \
     .field(\"bytes\", &self.bytes)
            .field(\"mnemonic\", &self.mnemonic)
            \
     .field(\"detail\", &self.detail)
            .finish()
    }
}
";<commit_msg>Fix linking with capstone<commit_after>extern crate bindgen;

use std::env;
use std::io::Write;
use std::path::PathBuf;

#[cfg(not(target_os="windows"))]
fn default_include_dir(_: env::VarError) -> String {
    "/usr/include".to_owned()
}

#[cfg(target_os="windows")]
fn default_include_dir(_: env::VarError) -> String {
    panic!("No default directory for includes in windows")
}

fn main() {
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let in_path = PathBuf::from(env::var("CAPSTONE_INCLUDE_DIR")
        .unwrap_or_else(default_include_dir));

    let wrapper = out_path.join("wrapper.h");
    {
        let mut file = std::fs::File::create(&wrapper).unwrap();
        file.write_all(b"#include <capstone/capstone.h>").unwrap();
    }

    println!("cargo:rerun-if-changed={}",
             in_path.join("capstone").join("capstone.h").display());

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header(wrapper.to_str().unwrap())
        .clang_arg(format!("-I{}", in_path.display()))
        .link("capstone")
        .generate_comments(true)
        .bitfield_enum("cs_.*")
        .bitfield_enum("x86_.*")
        .bitfield_enum("arm_.*")
        .bitfield_enum("arm64_.*")
        .bitfield_enum("mips_.*")
        .bitfield_enum("ppc_.*")
        .bitfield_enum("sparc_.*")
        .bitfield_enum("sysz_.*")
        .bitfield_enum("xcore_.*")
        // Only generate bindings for all types that start with cs_ and types included by them.
        // This avoids generating bindings for standard c functions.
        .whitelisted_type("cs_.*")
        .whitelisted_function("cs_.*")
        .prepend_enum_name(false)
        .raw_line(DEBUG_IMPL)
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    bindings.write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");

    // TODO: For some reason .link("capstone") won't work.
    // Remove this once it does again.
    // TODO: Add support for library search paths.
    println!("cargo:rustc-link-lib=dylib=capstone");
}

const DEBUG_IMPL: &'static str =
    "
use std::fmt;
impl fmt::Debug for cs_insn {
    fn fmt(&self, f: &mut fmt::Formatter) -> \
     fmt::Result {
        f.debug_struct(\"cs_insn\")
            .field(\"id\", &self.id)
            \
     .field(\"address\", &self.address)
            .field(\"size\", &self.size)
            \
     .field(\"bytes\", &self.bytes)
            .field(\"mnemonic\", &self.mnemonic)
            \
     .field(\"detail\", &self.detail)
            .finish()
    }
}
";<|endoftext|>


<commit_before>// build.rs

extern crate pkg_config;
extern crate bindgen;
extern crate cmake;
extern crate cc;

use std::env;
use std::path::Path;

use std::fs::{self, File};
use std::io::Write;

fn format_write(builder: bindgen::Builder, output: &str) {
    let s = builder
        .generate()
        .unwrap()
        .to_string()
        .replace("/**", "/*")
        .replace("/*!", "/*");

    let mut file = File::create(output).unwrap();

    let _ = file.write(s.as_bytes());
}

fn main() {
    let cargo_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let build_path = Path::new(&cargo_dir).join("aom_build/aom");

    let dst = cmake::Config::new(build_path)
        .define("CONFIG_AV1_ENCODER", "0")
        .define("CONFIG_DEBUG", "1")
        .define("CONFIG_EXPERIMENTAL", "1")
        .define("CONFIG_UNIT_TESTS", "0")
        .define("CONFIG_EXT_PARTITION", "0")
        .define("CONFIG_EXT_PARTITION_TYPES", "0")
        .define("CONFIG_OBU", "0")
        .define("CONFIG_FILTER_INTRA", "0")
        .define("CONFIG_EXT_SKIP", "0")
        .define("CONFIG_LV_MAP", "1")
        .define("CONFIG_ANALYZER", "0")
        .define("CONFIG_Q_ADAPT_PROBS", "0")
        .define("AOM_TARGET_CPU", "generic")
        .build();

    // Dirty hack to force a rebuild whenever the defaults are changed upstream
    let _ = fs::remove_file(dst.join("build/CMakeCache.txt"));

    env::set_var("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));

    let libs = pkg_config::Config::new().statik(true).probe("aom").unwrap();
    let headers = libs.include_paths.clone();

    let mut builder = bindgen::builder()
        .raw_line("#![allow(dead_code)]")
        .raw_line("#![allow(non_camel_case_types)]")
        .raw_line("#![allow(non_snake_case)]")
        .raw_line("#![allow(non_upper_case_globals)]")
        .blacklist_type("max_align_t")
        .rustfmt_bindings(false)
        .header("data/aom.h");

    for header in headers {
        builder = builder.clang_arg("-I").clang_arg(header.to_str().unwrap());
    }

    // Manually fix the comment so rustdoc won't try to pick them
    format_write(builder, "tests/aom.rs");

    {
        use std::fs;
        fn rerun_dir<P: AsRef<Path>>(dir: P) {
            for entry in fs::read_dir(dir).unwrap() {
                let entry = entry.unwrap();
                let path = entry.path();
                println!("cargo:rerun-if-changed={}", path.to_string_lossy());

                if path.is_dir() {
                    rerun_dir(path);
                }
            }
        }

        rerun_dir("aom_build");
    }

    cc::Build::new()
        .file("aom_build/aom/aom_dsp/fwd_txfm.c")
        .file("aom_build/aom/av1/encoder/dct.c")
        .include("aom_build")
        .include("aom_build/aom")
        .flag("-std=c99")
        .compile("libntr.a");
}
<commit_msg>Do not try to build the aom documentation<commit_after>// build.rs

extern crate pkg_config;
extern crate bindgen;
extern crate cmake;
extern crate cc;

use std::env;
use std::path::Path;

use std::fs::{self, File};
use std::io::Write;

fn format_write(builder: bindgen::Builder, output: &str) {
    let s = builder
        .generate()
        .unwrap()
        .to_string()
        .replace("/**", "/*")
        .replace("/*!", "/*");

    let mut file = File::create(output).unwrap();

    let _ = file.write(s.as_bytes());
}

fn main() {
    let cargo_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let build_path = Path::new(&cargo_dir).join("aom_build/aom");

    let dst = cmake::Config::new(build_path)
        .define("CONFIG_AV1_ENCODER", "0")
        .define("CONFIG_DEBUG", "1")
        .define("CONFIG_EXPERIMENTAL", "1")
        .define("CONFIG_UNIT_TESTS", "0")
        .define("CONFIG_EXT_PARTITION", "0")
        .define("CONFIG_EXT_PARTITION_TYPES", "0")
        .define("CONFIG_OBU", "0")
        .define("CONFIG_FILTER_INTRA", "0")
        .define("CONFIG_EXT_SKIP", "0")
        .define("CONFIG_LV_MAP", "1")
        .define("CONFIG_ANALYZER", "0")
        .define("CONFIG_Q_ADAPT_PROBS", "0")
        .define("AOM_TARGET_CPU", "generic")
        .define("ENABLE_DOCS", "0")
        .build();

    // Dirty hack to force a rebuild whenever the defaults are changed upstream
    let _ = fs::remove_file(dst.join("build/CMakeCache.txt"));

    env::set_var("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));

    let libs = pkg_config::Config::new().statik(true).probe("aom").unwrap();
    let headers = libs.include_paths.clone();

    let mut builder = bindgen::builder()
        .raw_line("#![allow(dead_code)]")
        .raw_line("#![allow(non_camel_case_types)]")
        .raw_line("#![allow(non_snake_case)]")
        .raw_line("#![allow(non_upper_case_globals)]")
        .blacklist_type("max_align_t")
        .rustfmt_bindings(false)
        .header("data/aom.h");

    for header in headers {
        builder = builder.clang_arg("-I").clang_arg(header.to_str().unwrap());
    }

    // Manually fix the comment so rustdoc won't try to pick them
    format_write(builder, "tests/aom.rs");

    {
        use std::fs;
        fn rerun_dir<P: AsRef<Path>>(dir: P) {
            for entry in fs::read_dir(dir).unwrap() {
                let entry = entry.unwrap();
                let path = entry.path();
                println!("cargo:rerun-if-changed={}", path.to_string_lossy());

                if path.is_dir() {
                    rerun_dir(path);
                }
            }
        }

        rerun_dir("aom_build");
    }

    cc::Build::new()
        .file("aom_build/aom/aom_dsp/fwd_txfm.c")
        .file("aom_build/aom/av1/encoder/dct.c")
        .include("aom_build")
        .include("aom_build/aom")
        .flag("-std=c99")
        .compile("libntr.a");
}
<|endoftext|>


<commit_before>extern crate phf_codegen;

use std::ascii::AsciiExt;
use std::env;
use std::fs::File;
use std::io::{Write, BufWriter};
use std::path::Path;
use std::convert::AsRef;

const ERRCODES_TXT: &'static str = include_str!("errcodes.txt");

struct Code {
    code: String,
    variant: String,
}

fn main() {
    let path = env::var_os("OUT_DIR").unwrap();
    let path: &Path = path.as_ref();
    let path = path.join("sqlstate.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    let codes = parse_codes();

    make_enum(&codes, &mut file);
    make_map(&codes, &mut file);
    make_impl(&codes, &mut file);

    // This is already assumed to be the case but there's no way to say that
    // you don't depend on anything at all
    println!("cargo:rerun-if-changed=build.rs");
}

fn parse_codes() -> Vec<Code> {
    let mut codes = vec![];

    for line in ERRCODES_TXT.lines() {
        if line.starts_with("#") || line.starts_with("Section") || line.trim().is_empty() {
            continue;
        }

        let mut it = line.split_whitespace();
        let code = it.next().unwrap().to_owned();
        it.next();
        it.next();
        // for 2202E
        let name = match it.next() {
            Some(name) => name,
            None => continue,
        };
        let variant = match variant_name(&code) {
            Some(variant) => variant,
            None => snake_to_camel(&name),
        };

        codes.push(Code {
            code: code,
            variant: variant,
        });
    }

    codes
}

fn snake_to_camel(s: &str) -> String {
    let mut out = String::new();

    let mut upper = true;
    for ch in s.chars() {
        if ch == '_' {
            upper = true;
        } else {
            let ch = if upper {
                upper = false;
                ch.to_ascii_uppercase()
            } else {
                ch
            };
            out.push(ch);
        }
    }

    out
}

fn variant_name(code: &str) -> Option<String> {
    match code {
        "01004" => Some("WarningStringDataRightTruncation".to_owned()),
        "22001" => Some("DataStringDataRightTruncation".to_owned()),
        "2F002" => Some("SqlRoutineModifyingSqlDataNotPermitted".to_owned()),
        "38002" => Some("ForeignRoutineModifyingSqlDataNotPermitted".to_owned()),
        "2F003" => Some("SqlRoutineProhibitedSqlStatementAttempted".to_owned()),
        "38003" => Some("ForeignRoutineProhibitedSqlStatementAttempted".to_owned()),
        "2F004" => Some("SqlRoutineReadingSqlDataNotPermitted".to_owned()),
        "38004" => Some("ForeignRoutineReadingSqlDataNotPermitted".to_owned()),
        "22004" => Some("DataNullValueNotAllowed".to_owned()),
        "39004" => Some("ExternalRoutineInvocationNullValueNotAllowed".to_owned()),
        _ => None,
    }
}

fn make_enum(codes: &[Code], file: &mut BufWriter<File>) {
    write!(file,
r#"/// SQLSTATE error codes
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum SqlState {{
"#
           ).unwrap();

    for code in codes {
        write!(file,
"    /// `{}`
    {},\n",
               code.code, code.variant).unwrap();
    }

    write!(file,
"    /// An unknown code
    Other(String)
}}
"
           ).unwrap();
}

fn make_map(codes: &[Code], file: &mut BufWriter<File>) {
    write!(file, "static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ").unwrap();
    let mut builder = phf_codegen::Map::new();
    for code in codes {
        builder.entry(&*code.code, &format!("SqlState::{}", code.variant));
    }
    builder.build(file).unwrap();
    write!(file, ";\n").unwrap();
}

fn make_impl(codes: &[Code], file: &mut BufWriter<File>) {
    write!(file, r#"
impl SqlState {{
    /// Creates a `SqlState` from its error code.
    pub fn from_code(s: String) -> SqlState {{
        match SQLSTATE_MAP.get(&*s) {{
            Some(state) => state.clone(),
            None => SqlState::Other(s)
        }}
    }}

    /// Returns the error code corresponding to the `SqlState`.
    pub fn code(&self) -> &str {{
        match *self {{"#
           ).unwrap();

    for code in codes {
        write!(file, r#"
            SqlState::{} => "{}","#,
               code.variant, code.code).unwrap();
    }

    write!(file, r#"
            SqlState::Other(ref s) => s,
        }}
    }}
}}
"#
           ).unwrap();
}
<commit_msg>Depend on errcodes.txt<commit_after>extern crate phf_codegen;

use std::ascii::AsciiExt;
use std::env;
use std::fs::File;
use std::io::{Write, BufWriter};
use std::path::Path;
use std::convert::AsRef;

const ERRCODES_TXT: &'static str = include_str!("errcodes.txt");

struct Code {
    code: String,
    variant: String,
}

fn main() {
    let path = env::var_os("OUT_DIR").unwrap();
    let path: &Path = path.as_ref();
    let path = path.join("sqlstate.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    let codes = parse_codes();

    make_enum(&codes, &mut file);
    make_map(&codes, &mut file);
    make_impl(&codes, &mut file);

    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=errcodes.txt");
}

fn parse_codes() -> Vec<Code> {
    let mut codes = vec![];

    for line in ERRCODES_TXT.lines() {
        if line.starts_with("#") || line.starts_with("Section") || line.trim().is_empty() {
            continue;
        }

        let mut it = line.split_whitespace();
        let code = it.next().unwrap().to_owned();
        it.next();
        it.next();
        // for 2202E
        let name = match it.next() {
            Some(name) => name,
            None => continue,
        };
        let variant = match variant_name(&code) {
            Some(variant) => variant,
            None => snake_to_camel(&name),
        };

        codes.push(Code {
            code: code,
            variant: variant,
        });
    }

    codes
}

fn snake_to_camel(s: &str) -> String {
    let mut out = String::new();

    let mut upper = true;
    for ch in s.chars() {
        if ch == '_' {
            upper = true;
        } else {
            let ch = if upper {
                upper = false;
                ch.to_ascii_uppercase()
            } else {
                ch
            };
            out.push(ch);
        }
    }

    out
}

fn variant_name(code: &str) -> Option<String> {
    match code {
        "01004" => Some("WarningStringDataRightTruncation".to_owned()),
        "22001" => Some("DataStringDataRightTruncation".to_owned()),
        "2F002" => Some("SqlRoutineModifyingSqlDataNotPermitted".to_owned()),
        "38002" => Some("ForeignRoutineModifyingSqlDataNotPermitted".to_owned()),
        "2F003" => Some("SqlRoutineProhibitedSqlStatementAttempted".to_owned()),
        "38003" => Some("ForeignRoutineProhibitedSqlStatementAttempted".to_owned()),
        "2F004" => Some("SqlRoutineReadingSqlDataNotPermitted".to_owned()),
        "38004" => Some("ForeignRoutineReadingSqlDataNotPermitted".to_owned()),
        "22004" => Some("DataNullValueNotAllowed".to_owned()),
        "39004" => Some("ExternalRoutineInvocationNullValueNotAllowed".to_owned()),
        _ => None,
    }
}

fn make_enum(codes: &[Code], file: &mut BufWriter<File>) {
    write!(file,
r#"/// SQLSTATE error codes
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum SqlState {{
"#
           ).unwrap();

    for code in codes {
        write!(file,
"    /// `{}`
    {},\n",
               code.code, code.variant).unwrap();
    }

    write!(file,
"    /// An unknown code
    Other(String)
}}
"
           ).unwrap();
}

fn make_map(codes: &[Code], file: &mut BufWriter<File>) {
    write!(file, "static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ").unwrap();
    let mut builder = phf_codegen::Map::new();
    for code in codes {
        builder.entry(&*code.code, &format!("SqlState::{}", code.variant));
    }
    builder.build(file).unwrap();
    write!(file, ";\n").unwrap();
}

fn make_impl(codes: &[Code], file: &mut BufWriter<File>) {
    write!(file, r#"
impl SqlState {{
    /// Creates a `SqlState` from its error code.
    pub fn from_code(s: String) -> SqlState {{
        match SQLSTATE_MAP.get(&*s) {{
            Some(state) => state.clone(),
            None => SqlState::Other(s)
        }}
    }}

    /// Returns the error code corresponding to the `SqlState`.
    pub fn code(&self) -> &str {{
        match *self {{"#
           ).unwrap();

    for code in codes {
        write!(file, r#"
            SqlState::{} => "{}","#,
               code.variant, code.code).unwrap();
    }

    write!(file, r#"
            SqlState::Other(ref s) => s,
        }}
    }}
}}
"#
           ).unwrap();
}
<|endoftext|>


<commit_before>mod nombc;
mod mbc1;
mod mbc3;

use gameboy::cartridge::nombc::NoMBC;
use gameboy::cartridge::mbc1::MBC1;
use gameboy::cartridge::mbc3::MBC3;

pub const ROM_BANK_SIZE: usize = 0x4000;
pub const RAM_BANK_SIZE: usize = 0x2000;

#[derive(Debug)]
pub enum MBCType {
	NONE,
	MBC1,
	MBC2,
	MMM01,
	MBC3,
	MBC4,
	MBC5,
	MBC6,
	MBC7,
	CAMERA,
	TAMA5,
	HUC3,
	HUC1
}

#[derive(Debug)]
pub struct CartInfo {
	pub title: String,
	pub sgb: bool,
	pub cgb: bool,
	pub mbc_type: MBCType,
	pub battery: bool,
	pub rtc: bool,
	pub rom_size: usize,
	pub ram_size: usize,
}

pub trait Cartridge {
	fn read_byte_rom(&self, address: u16) -> u8;
	fn read_byte_ram(&self, address: u16) -> u8;

	fn write_byte_rom(&mut self, address: u16, value: u8);
	fn write_byte_ram(&mut self, address: u16, value: u8);

	fn get_cart_info(&self) -> &CartInfo;

	fn rom(&self) -> &[u8];
	fn rom_mut(&mut self) -> &mut[u8];

	fn banked_rom(&self) -> &[u8];
	fn banked_rom_mut(&mut self) -> &mut[u8];

	fn ram(&self) -> &[u8];
	fn ram_mut(&mut self) -> &mut[u8];
}

pub trait MemoryBankController {
	fn read_byte_rom(&self, rom: &Box<[u8]>, rom_size: usize, address: u16) -> u8;
	fn read_byte_ram(&self, ram: &Box<[u8]>, ram_size: usize, address: u16) -> u8;

	fn write_byte_rom(&mut self, address: u16, value: u8);
	fn write_byte_ram(&mut self, ram: &mut Box<[u8]>, ram_size: usize, adress: u16, value: u8);

	fn rom_bank(&self) -> usize;
	fn ram_bank(&self) -> usize;
}

impl CartInfo {
	pub fn new(rom: &Box<[u8]>) -> Result<CartInfo, & 'static str> {
		let mbc_type: MBCType = try!(CartInfo::get_type(rom[0x0147]));
		let rom_size: usize = try!(CartInfo::get_rom_size(rom[0x0148]));
		let ram_size: usize = try!(CartInfo::get_ram_size(rom[0x0149]));

		if rom.len() < 0x150 {
			return Err("Rom is too small to contain a rom header (rom is smaller than 0x150 bytes)");
		}

		let info = CartInfo {
			title: String::from(""),	//TODO: Cart title
			sgb: rom[0x0146] == 0x03,
			cgb: rom[0x0143] & 0x80 == 0x80,
			battery: CartInfo::has_battery(rom[0x0147]),
			rtc: CartInfo::has_rtc(rom[0x0147]),
			mbc_type: mbc_type,
			rom_size: rom_size,
			ram_size: ram_size,
		};

		Ok(info)
	}

	fn has_battery(cart_type: u8) -> bool {
		match cart_type {
			0x03 => true,
			0x06 => true,
			0x09 => true,
			0x0D => true,
			0x0F...0x10 => true,
			0x13 => true,
			0x17 => true,
			0x1B => true,
			0x1E => true,
			0x22 => true,
			0xFF => true,
			_ => false,
		}
	}

	fn has_rtc(cart_type: u8) -> bool {
		match cart_type {
			0x0F | 0x10 => true,
			_ => false
		}
	}

	fn get_type(cart_type: u8) -> Result<MBCType, & 'static str> {
		match cart_type {
			0x00 => Ok(MBCType::NONE),
			0x01...0x03 => Ok(MBCType::MBC1),
			0x05...0x06 => Ok(MBCType::MBC2),
			0x08...0x09 => Ok(MBCType::NONE),
			0x0B...0x0D => Ok(MBCType::MMM01),
			0x0F...0x13 => Ok(MBCType::MBC3),
			0x15...0x17 => Ok(MBCType::MBC4),
			0x19...0x1E => Ok(MBCType::MBC5),
			0x20 => Ok(MBCType::MBC6),
			0x22 => Ok(MBCType::MBC7),
			0xFC => Ok(MBCType::CAMERA),
			0xFD => Ok(MBCType::TAMA5),
			0xFE => Ok(MBCType::HUC3),
			0xFF => Ok(MBCType::HUC1),
			_ => Err(("Invalid value Cartridge Type in Cartridge Header at index 0x0147!")),
		}
	}

	fn get_rom_size(rom_size: u8) -> Result<usize, & 'static str> {
		match rom_size {
			0x00...0x07 => Ok(0x8000 << rom_size),
			0x52 => Ok(0x4000 * 72),
			0x53 => Ok(0x4000 * 80),
			0x54 => Ok(0x4000 * 96),
			_ => Err(("Invalid value Rom Size in Cartridge Header at index 0x0148!")),
		}
	}

	fn get_ram_size(ram_size: u8) -> Result<usize, & 'static str> {
		match ram_size {
			0x00 => Ok(0),
			0x01 => Ok(2 * 1024), 	//2KB
			0x02 => Ok(8 * 1024),	//8KB
			0x03 => Ok(32 * 1024),	//4 8KB banks
			0x04 => Ok(128 * 1024),	//16 8KB banks
			0x05 => Ok(64 * 1024),	//8 8KB banks
			_ => Err(("Invalid value Ram Size in Cartridge Header at index 0x0149!")),
		}
	}
}

pub struct VirtualCartridge {
	rom: Box<[u8]>,
	ram: Box<[u8]>,
	cart_info: CartInfo,
	mbc: Box<MemoryBankController>,
}

impl VirtualCartridge {
	pub fn new(rom: Box<[u8]>, ram: Option<Box<[u8]>>) -> Result<VirtualCartridge, & 'static str> {
		let cart_info: CartInfo = try!(CartInfo::new(&rom));

		//TODO: expand ram if the ram file loaded is too small (and give a warning?)
		//TODO: rom as well?
		let ram = match ram {
			Some(ram) => ram,
			None => {
				//No ram supplied, allocate some.
				let vec: Vec<u8> = Vec::with_capacity(cart_info.ram_size);
				vec.into_boxed_slice()
			}
		};

		let mbc: Result<Box<MemoryBankController>, & 'static str> = match cart_info.mbc_type {
			MBCType::NONE => Ok(Box::new(NoMBC::new())),
			MBCType::MBC1 => Ok(Box::new(MBC1::new())),
			MBCType::MBC3 => Ok(Box::new(MBC3::new(cart_info.rtc))),
			_ => {
				Err("Unimplemented MBC")	//TODO: more helpful error message
			},
		};

		let mbc = try!(mbc);

		let cart = VirtualCartridge {
			rom: rom,
			ram: ram,
			mbc: mbc,
			cart_info: cart_info,
		};

		Ok(cart)
	}
}

impl Cartridge for VirtualCartridge {
	fn read_byte_rom(&self, address: u16) -> u8  {
		self.mbc.read_byte_rom(&self.rom, self.cart_info.rom_size, address)
	}

	fn read_byte_ram(&self, address: u16) -> u8 {
		self.mbc.read_byte_ram(&self.ram, self.cart_info.ram_size, address)
	}

	fn write_byte_rom(&mut self, address: u16, value: u8) {
		self.mbc.write_byte_rom(address, value);
	}

	fn write_byte_ram(&mut self, address: u16, value: u8) {
		self.mbc.write_byte_ram(&mut self.ram, self.cart_info.ram_size, address, value);
	}

	fn get_cart_info(&self) -> &CartInfo {
		&self.cart_info
	}

	fn rom(&self) -> &[u8] {
		&self.rom[0..0x4000]
	}

	fn rom_mut(&mut self) -> &mut[u8] {
		&mut self.rom[0..0x4000]
	}

	fn banked_rom(&self) -> &[u8] {
		let rom_bank = self.mbc.rom_bank();
		let base_address = rom_bank * ROM_BANK_SIZE;
		if base_address >= self.rom.len() {
			&self.rom[0..0]  //this doesn't exist so return an empty slice
		}
		else {
			let end_address = base_address + ROM_BANK_SIZE;
			if end_address >= self.rom.len() {
				&self.rom[base_address..self.rom.len()]
			}
			else {
				&self.rom[base_address..end_address]
			}
		}
	}

	fn banked_rom_mut(&mut self) -> &mut[u8] {
		let rom_bank = self.mbc.rom_bank();
		let rom_length = self.rom.len();
		let base_address = rom_bank * ROM_BANK_SIZE;
		if base_address >= rom_length {
			&mut self.rom[0..0]  //this doesn't exist so return an empty slice
		}
		else {
			let end_address = base_address + ROM_BANK_SIZE;
			if end_address >= rom_length {
				&mut self.rom[base_address..rom_length]
			}
			else {
				&mut self.rom[base_address..end_address]
			}
		}
	}

	fn ram(&self) -> &[u8] {
		let ram_bank = self.mbc.ram_bank();
		let base_address = ram_bank * RAM_BANK_SIZE;
		if base_address >= self.ram.len() {
			&self.ram[0..0]
		}
		else {
			let end_address = base_address + RAM_BANK_SIZE;
			if end_address >= self.ram.len() {
				&self.ram[base_address..self.ram.len()]
			}
			else {
				&self.ram[base_address..end_address]
			}
		}
	}

	fn ram_mut(&mut self) -> &mut[u8] {
		let ram_bank = self.mbc.ram_bank();
		let ram_length = self.ram.len();
		let base_address = ram_bank * RAM_BANK_SIZE;
		if base_address >= ram_length {
			&mut self.ram[0..0]
		}
		else {
			let end_address = base_address + RAM_BANK_SIZE;
			if end_address >= ram_length {
				&mut self.ram[base_address..ram_length]
			}
			else {
				&mut self.ram[base_address..end_address]
			}
		}
	}
}
<commit_msg>Fixed a possible segfault when reading the header of a rom file smaller than 0x150 bytes.<commit_after>mod nombc;
mod mbc1;
mod mbc3;

use gameboy::cartridge::nombc::NoMBC;
use gameboy::cartridge::mbc1::MBC1;
use gameboy::cartridge::mbc3::MBC3;

pub const ROM_BANK_SIZE: usize = 0x4000;
pub const RAM_BANK_SIZE: usize = 0x2000;

#[derive(Debug)]
pub enum MBCType {
	NONE,
	MBC1,
	MBC2,
	MMM01,
	MBC3,
	MBC4,
	MBC5,
	MBC6,
	MBC7,
	CAMERA,
	TAMA5,
	HUC3,
	HUC1
}

#[derive(Debug)]
pub struct CartInfo {
	pub title: String,
	pub sgb: bool,
	pub cgb: bool,
	pub mbc_type: MBCType,
	pub battery: bool,
	pub rtc: bool,
	pub rom_size: usize,
	pub ram_size: usize,
}

pub trait Cartridge {
	fn read_byte_rom(&self, address: u16) -> u8;
	fn read_byte_ram(&self, address: u16) -> u8;

	fn write_byte_rom(&mut self, address: u16, value: u8);
	fn write_byte_ram(&mut self, address: u16, value: u8);

	fn get_cart_info(&self) -> &CartInfo;

	fn rom(&self) -> &[u8];
	fn rom_mut(&mut self) -> &mut[u8];

	fn banked_rom(&self) -> &[u8];
	fn banked_rom_mut(&mut self) -> &mut[u8];

	fn ram(&self) -> &[u8];
	fn ram_mut(&mut self) -> &mut[u8];
}

pub trait MemoryBankController {
	fn read_byte_rom(&self, rom: &Box<[u8]>, rom_size: usize, address: u16) -> u8;
	fn read_byte_ram(&self, ram: &Box<[u8]>, ram_size: usize, address: u16) -> u8;

	fn write_byte_rom(&mut self, address: u16, value: u8);
	fn write_byte_ram(&mut self, ram: &mut Box<[u8]>, ram_size: usize, adress: u16, value: u8);

	fn rom_bank(&self) -> usize;
	fn ram_bank(&self) -> usize;
}

impl CartInfo {
	pub fn new(rom: &Box<[u8]>) -> Result<CartInfo, & 'static str> {
		if rom.len() < 0x150 {
			return Err("Rom is too small to contain a rom header (rom is smaller than 0x150 bytes)");
		}

		let mbc_type: MBCType = try!(CartInfo::get_type(rom[0x0147]));
		let rom_size: usize = try!(CartInfo::get_rom_size(rom[0x0148]));
		let ram_size: usize = try!(CartInfo::get_ram_size(rom[0x0149]));

		let info = CartInfo {
			title: String::from(""),	//TODO: Cart title
			sgb: rom[0x0146] == 0x03,
			cgb: rom[0x0143] & 0x80 == 0x80,
			battery: CartInfo::has_battery(rom[0x0147]),
			rtc: CartInfo::has_rtc(rom[0x0147]),
			mbc_type: mbc_type,
			rom_size: rom_size,
			ram_size: ram_size,
		};

		Ok(info)
	}

	fn has_battery(cart_type: u8) -> bool {
		match cart_type {
			0x03 => true,
			0x06 => true,
			0x09 => true,
			0x0D => true,
			0x0F...0x10 => true,
			0x13 => true,
			0x17 => true,
			0x1B => true,
			0x1E => true,
			0x22 => true,
			0xFF => true,
			_ => false,
		}
	}

	fn has_rtc(cart_type: u8) -> bool {
		match cart_type {
			0x0F | 0x10 => true,
			_ => false
		}
	}

	fn get_type(cart_type: u8) -> Result<MBCType, & 'static str> {
		match cart_type {
			0x00 => Ok(MBCType::NONE),
			0x01...0x03 => Ok(MBCType::MBC1),
			0x05...0x06 => Ok(MBCType::MBC2),
			0x08...0x09 => Ok(MBCType::NONE),
			0x0B...0x0D => Ok(MBCType::MMM01),
			0x0F...0x13 => Ok(MBCType::MBC3),
			0x15...0x17 => Ok(MBCType::MBC4),
			0x19...0x1E => Ok(MBCType::MBC5),
			0x20 => Ok(MBCType::MBC6),
			0x22 => Ok(MBCType::MBC7),
			0xFC => Ok(MBCType::CAMERA),
			0xFD => Ok(MBCType::TAMA5),
			0xFE => Ok(MBCType::HUC3),
			0xFF => Ok(MBCType::HUC1),
			_ => Err(("Invalid value Cartridge Type in Cartridge Header at index 0x0147!")),
		}
	}

	fn get_rom_size(rom_size: u8) -> Result<usize, & 'static str> {
		match rom_size {
			0x00...0x07 => Ok(0x8000 << rom_size),
			0x52 => Ok(0x4000 * 72),
			0x53 => Ok(0x4000 * 80),
			0x54 => Ok(0x4000 * 96),
			_ => Err(("Invalid value Rom Size in Cartridge Header at index 0x0148!")),
		}
	}

	fn get_ram_size(ram_size: u8) -> Result<usize, & 'static str> {
		match ram_size {
			0x00 => Ok(0),
			0x01 => Ok(2 * 1024), 	//2KB
			0x02 => Ok(8 * 1024),	//8KB
			0x03 => Ok(32 * 1024),	//4 8KB banks
			0x04 => Ok(128 * 1024),	//16 8KB banks
			0x05 => Ok(64 * 1024),	//8 8KB banks
			_ => Err(("Invalid value Ram Size in Cartridge Header at index 0x0149!")),
		}
	}
}

pub struct VirtualCartridge {
	rom: Box<[u8]>,
	ram: Box<[u8]>,
	cart_info: CartInfo,
	mbc: Box<MemoryBankController>,
}

impl VirtualCartridge {
	pub fn new(rom: Box<[u8]>, ram: Option<Box<[u8]>>) -> Result<VirtualCartridge, & 'static str> {
		let cart_info: CartInfo = try!(CartInfo::new(&rom));

		//TODO: expand ram if the ram file loaded is too small (and give a warning?)
		//TODO: rom as well?
		let ram = match ram {
			Some(ram) => ram,
			None => {
				//No ram supplied, allocate some.
				let vec: Vec<u8> = Vec::with_capacity(cart_info.ram_size);
				vec.into_boxed_slice()
			}
		};

		let mbc: Result<Box<MemoryBankController>, & 'static str> = match cart_info.mbc_type {
			MBCType::NONE => Ok(Box::new(NoMBC::new())),
			MBCType::MBC1 => Ok(Box::new(MBC1::new())),
			MBCType::MBC3 => Ok(Box::new(MBC3::new(cart_info.rtc))),
			_ => {
				Err("Unimplemented MBC")	//TODO: more helpful error message
			},
		};

		let mbc = try!(mbc);

		let cart = VirtualCartridge {
			rom: rom,
			ram: ram,
			mbc: mbc,
			cart_info: cart_info,
		};

		Ok(cart)
	}
}

impl Cartridge for VirtualCartridge {
	fn read_byte_rom(&self, address: u16) -> u8  {
		self.mbc.read_byte_rom(&self.rom, self.cart_info.rom_size, address)
	}

	fn read_byte_ram(&self, address: u16) -> u8 {
		self.mbc.read_byte_ram(&self.ram, self.cart_info.ram_size, address)
	}

	fn write_byte_rom(&mut self, address: u16, value: u8) {
		self.mbc.write_byte_rom(address, value);
	}

	fn write_byte_ram(&mut self, address: u16, value: u8) {
		self.mbc.write_byte_ram(&mut self.ram, self.cart_info.ram_size, address, value);
	}

	fn get_cart_info(&self) -> &CartInfo {
		&self.cart_info
	}

	fn rom(&self) -> &[u8] {
		&self.rom[0..0x4000]
	}

	fn rom_mut(&mut self) -> &mut[u8] {
		&mut self.rom[0..0x4000]
	}

	fn banked_rom(&self) -> &[u8] {
		let rom_bank = self.mbc.rom_bank();
		let base_address = rom_bank * ROM_BANK_SIZE;
		if base_address >= self.rom.len() {
			&self.rom[0..0]  //this doesn't exist so return an empty slice
		}
		else {
			let end_address = base_address + ROM_BANK_SIZE;
			if end_address >= self.rom.len() {
				&self.rom[base_address..self.rom.len()]
			}
			else {
				&self.rom[base_address..end_address]
			}
		}
	}

	fn banked_rom_mut(&mut self) -> &mut[u8] {
		let rom_bank = self.mbc.rom_bank();
		let rom_length = self.rom.len();
		let base_address = rom_bank * ROM_BANK_SIZE;
		if base_address >= rom_length {
			&mut self.rom[0..0]  //this doesn't exist so return an empty slice
		}
		else {
			let end_address = base_address + ROM_BANK_SIZE;
			if end_address >= rom_length {
				&mut self.rom[base_address..rom_length]
			}
			else {
				&mut self.rom[base_address..end_address]
			}
		}
	}

	fn ram(&self) -> &[u8] {
		let ram_bank = self.mbc.ram_bank();
		let base_address = ram_bank * RAM_BANK_SIZE;
		if base_address >= self.ram.len() {
			&self.ram[0..0]
		}
		else {
			let end_address = base_address + RAM_BANK_SIZE;
			if end_address >= self.ram.len() {
				&self.ram[base_address..self.ram.len()]
			}
			else {
				&self.ram[base_address..end_address]
			}
		}
	}

	fn ram_mut(&mut self) -> &mut[u8] {
		let ram_bank = self.mbc.ram_bank();
		let ram_length = self.ram.len();
		let base_address = ram_bank * RAM_BANK_SIZE;
		if base_address >= ram_length {
			&mut self.ram[0..0]
		}
		else {
			let end_address = base_address + RAM_BANK_SIZE;
			if end_address >= ram_length {
				&mut self.ram[base_address..ram_length]
			}
			else {
				&mut self.ram[base_address..end_address]
			}
		}
	}
}
<|endoftext|>