<commit_before>extern crate libc;
extern crate termios;

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, winsize};
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Stdin, Stdout, Read, Error, ErrorKind, Write};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(PartialEq, Clone, Copy)]
enum Key {
    Character(u8),
    ArrowLeft,
    ArrowRight,
    ArrowUp,
    ArrowDown,
    PageUp,
    PageDown,
}

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct RawMode {
    orig_term: Termios
}

struct Editor {
    _mode: RawMode,
    cx: u16,
    cy: u16,
    screenrows: u16,
    screencols: u16,
    stdin: Stdin,
    stdout: Stdout,
}

impl RawMode {
    fn enable_raw_mode() -> io::Result<RawMode> {
        let mut term = Termios::from_fd(STDIN_FILENO)?;
        let mode = RawMode { orig_term: term.clone() };

        term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        term.c_oflag &= !OPOST;
        term.c_cflag |= CS8;
        term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
        term.c_cc[VMIN] = 0;
        term.c_cc[VTIME] = 1;

        tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
        Ok(mode)
    }
}

impl Drop for RawMode {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn read_non_blocking<R : Read>(r : &mut R, buf: &mut [u8]) -> usize {
    r.read(buf)
     .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
     .expect("read_non_blocking")
}

fn editor_read_key(stdin: &mut Stdin) -> Key {
    let mut buf = [0; 1];
    loop {
        let n = read_non_blocking(stdin, &mut buf);
        if n == 1 {
            if buf[0] == b'\x1b' {
                let mut seq = [0; 2];
                let n = read_non_blocking(stdin, &mut seq);
                if n == 2 && seq[0] == b'[' {
                    if seq[1] >= b'0' && seq[1] <= b'9' {
                        let mut last = [0; 1];
                        let n = read_non_blocking(stdin, &mut last);
                        if n == 0 {
                            return Key::Character(b'\x1b');
                        }
                        if last[0] == b'~' {
                            if seq[1] == b'5' {
                                return Key::PageUp;
                            } else if seq[1] == b'6' {
                                return Key::PageDown;
                            }
                        }
                    } else {
                        return match seq[1] {
                            b'A' => Key::ArrowUp,
                            b'B' => Key::ArrowDown,
                            b'C' => Key::ArrowRight,
                            b'D' => Key::ArrowLeft,
                            _ => Key::Character(b'\x1b'),
                        }
                    }
                } else {
                    return Key::Character(b'\x1b');
                }
            } else {
                return Key::Character(buf[0]);
            }
        }
    }
}

fn get_window_size() -> io::Result<(u16, u16)> {
    let ws = winsize { ws_col: 0, ws_row: 0, ws_xpixel: 0, ws_ypixel: 0 };
    unsafe {
        if libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0 {
            return Err(Error::new(ErrorKind::Other, "get_window_size: ioctl failed"))
        }
    }
    Ok((ws.ws_row, ws.ws_col))
}

impl Editor {
    fn new() -> io::Result<Editor> {
        let mode = RawMode::enable_raw_mode()?;
        let (rows, cols) = get_window_size()?;
        let stdin = io::stdin();
        let stdout = io::stdout();
        Ok(Editor {
            _mode: mode,
            cx: 0,
            cy: 0,
            screenrows: rows,
            screencols: cols,
            stdin: stdin,
            stdout: stdout
        })
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stdout.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdout.flush()
    }

    fn draw_rows(&mut self) -> io::Result<()> {
        for y in 0..(self.screenrows) {
            if y == self.screenrows / 3 {
                let mut msg = format!("Kilo-rs editor -- version {}", VERSION);
                msg.truncate(self.screencols as usize);
                let padding = (self.screencols - msg.len() as u16) / 2;
                if padding > 0 {
                    self.write(b"~")?;
                    for _ in 1..padding {
                        self.write(b" ")?;
                    }
                }
                self.write(msg.as_bytes())?;
            } else {
                self.write(b"~")?;
            }

            self.write(b"\x1b[K")?;
            if y < self.screenrows - 1 {
                self.write(b"\r\n")?;
            }
        }
        Ok(())
    }

    fn refresh_screen(&mut self) -> io::Result<()> {
        self.write(b"\x1b[?25l")?;
        self.write(b"\x1b[H")?;

        self.draw_rows()?;

        let move_cursor = format!("\x1b[{};{}H", self.cy + 1, self.cx + 1).into_bytes();
        self.write(&move_cursor)?;

        self.write(b"\x1b[?25h")?;
        self.flush()
    }

    fn move_cursor(&mut self, k: Key) {
        match k {
            Key::ArrowUp => {
                if self.cy > 0 {
                    self.cy -= 1;
                }
            },
            Key::ArrowDown => {
                if self.cy < self.screenrows - 1 {
                    self.cy += 1;
                }
            },
            Key::ArrowLeft => {
                if self.cx > 0 {
                    self.cx -= 1;
                }
            },
            Key::ArrowRight => {
                if self.cx < self.screencols - 1 {
                    self.cx += 1;
                }
            },
            _ => (),
        }
    }

    fn process_keypress(&mut self) -> bool {
        let c = editor_read_key(&mut self.stdin);

        match c {
            Key::Character(k) if k == ctrl_key!(b'q') => {
                return false
            },
            Key::PageUp | Key::PageDown => {
                let key = if c == Key::PageUp { Key::ArrowUp } else { Key::ArrowDown };
                for _ in 0..(self.screenrows) {
                    self.move_cursor(key);
                }
            },
            Key::ArrowUp | Key::ArrowDown | Key::ArrowLeft | Key::ArrowRight => {
                self.move_cursor(c);
            },
            _ => ()
        };
        true
    }
}

impl Drop for Editor {
    fn drop(&mut self) {
        // clear screen
        self.stdout.write(b"\x1b[2J").unwrap();
        self.stdout.write(b"\x1b[H").unwrap();
        self.stdout.flush().unwrap();
    }
}

fn main() {
    let mut editor = Editor::new().unwrap();

    editor.refresh_screen().unwrap();
    while editor.process_keypress() {
        editor.refresh_screen().unwrap();
    }
}
<commit_msg>Home and End keys<commit_after>extern crate libc;
extern crate termios;

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, winsize};
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Stdin, Stdout, Read, Error, ErrorKind, Write};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(PartialEq, Clone, Copy)]
enum Key {
    Character(u8),
    ArrowLeft,
    ArrowRight,
    ArrowUp,
    ArrowDown,
    HomeKey,
    EndKey,
    PageUp,
    PageDown,
}

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct RawMode {
    orig_term: Termios
}

struct Editor {
    _mode: RawMode,
    cx: u16,
    cy: u16,
    screenrows: u16,
    screencols: u16,
    stdin: Stdin,
    stdout: Stdout,
}

impl RawMode {
    fn enable_raw_mode() -> io::Result<RawMode> {
        let mut term = Termios::from_fd(STDIN_FILENO)?;
        let mode = RawMode { orig_term: term.clone() };

        term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        term.c_oflag &= !OPOST;
        term.c_cflag |= CS8;
        term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
        term.c_cc[VMIN] = 0;
        term.c_cc[VTIME] = 1;

        tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
        Ok(mode)
    }
}

impl Drop for RawMode {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn read_non_blocking<R : Read>(r : &mut R, buf: &mut [u8]) -> usize {
    r.read(buf)
     .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
     .expect("read_non_blocking")
}

fn editor_read_key(stdin: &mut Stdin) -> Key {
    let mut buf = [0; 1];
    loop {
        let n = read_non_blocking(stdin, &mut buf);
        if n == 1 {
            if buf[0] == b'\x1b' {
                let mut seq = [0; 2];
                let n = read_non_blocking(stdin, &mut seq);
                if n == 2 && seq[0] == b'[' {
                    if seq[1] >= b'0' && seq[1] <= b'9' {
                        let mut last = [0; 1];
                        let n = read_non_blocking(stdin, &mut last);
                        if n == 1 {
                            if last[0] == b'~' {
                                return match seq[1] {
                                    b'1' => Key::HomeKey,
                                    b'4' => Key::EndKey,
                                    b'5' => Key::PageUp,
                                    b'6' => Key::PageDown,
                                    b'7' => Key::HomeKey,
                                    b'8' => Key::EndKey,
                                    _ => Key::Character(b'\x1b'),
                                }
                            }
                        }
                    } else {
                        return match seq[1] {
                            b'A' => Key::ArrowUp,
                            b'B' => Key::ArrowDown,
                            b'C' => Key::ArrowRight,
                            b'D' => Key::ArrowLeft,
                            b'H' => Key::HomeKey,
                            b'F' => Key::EndKey,
                            _ => Key::Character(b'\x1b'),
                        }
                    }
                } else if n == 2 && seq[0] == b'O' {
                    return match seq[1] {
                        b'H' => Key::HomeKey,
                        b'F' => Key::EndKey,
                        _ => Key::Character(b'\x1b'),
                    }
                }
                return Key::Character(b'\x1b');
            } else {
                return Key::Character(buf[0]);
            }
        }
    }
}

fn get_window_size() -> io::Result<(u16, u16)> {
    let ws = winsize { ws_col: 0, ws_row: 0, ws_xpixel: 0, ws_ypixel: 0 };
    unsafe {
        if libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0 {
            return Err(Error::new(ErrorKind::Other, "get_window_size: ioctl failed"))
        }
    }
    Ok((ws.ws_row, ws.ws_col))
}

impl Editor {
    fn new() -> io::Result<Editor> {
        let mode = RawMode::enable_raw_mode()?;
        let (rows, cols) = get_window_size()?;
        let stdin = io::stdin();
        let stdout = io::stdout();
        Ok(Editor {
            _mode: mode,
            cx: 0,
            cy: 0,
            screenrows: rows,
            screencols: cols,
            stdin: stdin,
            stdout: stdout
        })
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stdout.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdout.flush()
    }

    fn draw_rows(&mut self) -> io::Result<()> {
        for y in 0..(self.screenrows) {
            if y == self.screenrows / 3 {
                let mut msg = format!("Kilo-rs editor -- version {}", VERSION);
                msg.truncate(self.screencols as usize);
                let padding = (self.screencols - msg.len() as u16) / 2;
                if padding > 0 {
                    self.write(b"~")?;
                    for _ in 1..padding {
                        self.write(b" ")?;
                    }
                }
                self.write(msg.as_bytes())?;
            } else {
                self.write(b"~")?;
            }

            self.write(b"\x1b[K")?;
            if y < self.screenrows - 1 {
                self.write(b"\r\n")?;
            }
        }
        Ok(())
    }

    fn refresh_screen(&mut self) -> io::Result<()> {
        self.write(b"\x1b[?25l")?;
        self.write(b"\x1b[H")?;

        self.draw_rows()?;

        let move_cursor = format!("\x1b[{};{}H", self.cy + 1, self.cx + 1).into_bytes();
        self.write(&move_cursor)?;

        self.write(b"\x1b[?25h")?;
        self.flush()
    }

    fn move_cursor(&mut self, k: Key) {
        match k {
            Key::ArrowUp => {
                if self.cy > 0 {
                    self.cy -= 1;
                }
            },
            Key::ArrowDown => {
                if self.cy < self.screenrows - 1 {
                    self.cy += 1;
                }
            },
            Key::ArrowLeft => {
                if self.cx > 0 {
                    self.cx -= 1;
                }
            },
            Key::ArrowRight => {
                if self.cx < self.screencols - 1 {
                    self.cx += 1;
                }
            },
            _ => (),
        }
    }

    fn process_keypress(&mut self) -> bool {
        let c = editor_read_key(&mut self.stdin);

        match c {
            Key::Character(k) if k == ctrl_key!(b'q') => {
                return false
            },
            Key::HomeKey => {
                self.cx = 0;
            },
            Key::EndKey => {
                self.cx = self.screencols - 1;
            },
            Key::PageUp | Key::PageDown => {
                let key = if c == Key::PageUp { Key::ArrowUp } else { Key::ArrowDown };
                for _ in 0..(self.screenrows) {
                    self.move_cursor(key);
                }
            },
            Key::ArrowUp | Key::ArrowDown | Key::ArrowLeft | Key::ArrowRight => {
                self.move_cursor(c);
            },
            _ => ()
        };
        true
    }
}

impl Drop for Editor {
    fn drop(&mut self) {
        // clear screen
        self.stdout.write(b"\x1b[2J").unwrap();
        self.stdout.write(b"\x1b[H").unwrap();
        self.stdout.flush().unwrap();
    }
}

fn main() {
    let mut editor = Editor::new().unwrap();

    editor.refresh_screen().unwrap();
    while editor.process_keypress() {
        editor.refresh_screen().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate gfx_gl as gl;
extern crate camera_controllers;
extern crate collada;
extern crate env_logger;
extern crate gfx;
extern crate gfx_debug_draw;
extern crate gfx_device_gl;
extern crate piston;
extern crate sdl2;
extern crate sdl2_window;
extern crate shader_version;
extern crate skeletal_animation;
extern crate vecmath;

use gfx::traits::*;
use gfx_debug_draw::DebugRenderer;

use gl::Gl;

use std::path::Path;
use std::rc::Rc;
use std::cell::RefCell;
use piston::window::WindowSettings;
use piston::event::{
    events,
    RenderEvent,
    ResizeEvent,
};

use vecmath::mat4_id;

use sdl2_window::Sdl2Window;

use camera_controllers::{
    OrbitZoomCamera,
    OrbitZoomCameraSettings,
    CameraPerspective,
    model_view_projection
};

use skeletal_animation::SkinnedRenderer;
use collada::document::ColladaDocument;

fn main() {

    env_logger::init().unwrap();

    let (win_width, win_height) = (640, 480);

    let window = Sdl2Window::new(
        shader_version::OpenGL::_3_2,
        WindowSettings::new(
            "Animation Viewer".to_string(),
            piston::window::Size { width: 640, height: 480 }
        ).exit_on_esc(true)
    );

    let device = gfx_device_gl::GlDevice::new(|s| unsafe {
        std::mem::transmute(sdl2::video::gl_get_proc_address(s))
    });

    let mut frame = gfx::Frame::new(win_width as u16, win_height as u16);

    let window = Rc::new(RefCell::new(window));

    let clear = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0
    };

    let mut graphics = device.into_graphics();

    let mut debug_renderer = DebugRenderer::new(*graphics.device.get_capabilities(), &mut graphics.device, [frame.width as u32, frame.height as u32], 64, None, None).ok().unwrap();

    // TODO - these are (usually) available in the COLLADA file, associated with a <mesh> element in a somewhat convoluted way
    let texture_paths = vec![
        "assets/young_lightskinned_male_diffuse.png",
        "assets/suit01lres_diffuse.png",
        "assets/male02_diffuse_black.png",
        "assets/brown_eye.png",
        "assets/eyebrow009.png",
        "assets/eyelashes01.png",
    ];

    let collada_document = ColladaDocument::from_path(&Path::new("assets/suit_guy.dae")).unwrap();
    let mut skinned_renderer = SkinnedRenderer::from_collada(&mut graphics, collada_document, texture_paths).unwrap();

    let model = mat4_id();
    let mut projection = CameraPerspective {
        fov: 90.0f32,
        near_clip: 0.1,
        far_clip: 1000.0,
        aspect_ratio: (win_width as f32) / (win_height as f32)
    }.projection();

    let mut orbit_zoom_camera: OrbitZoomCamera<f32> = OrbitZoomCamera::new(
        [0.0, 0.0, 0.0],
        OrbitZoomCameraSettings::default()
    );

    // Start event loop

    Gl::load_with(|s| unsafe {
        std::mem::transmute(sdl2::video::gl_get_proc_address(s))
    });

    let mut elapsed_time = 0f64;

    for e in events(window) {

        e.resize(|width, height| {
            debug_renderer.resize(width, height);

            // Update frame
            frame.width = width as u16;
            frame.height = height as u16;

            // Update projection matrix
            projection = CameraPerspective {
                fov: 90.0f32,
                near_clip: 0.1,
                far_clip: 1000.0,
                aspect_ratio: (width as f32) / (height as f32)
            }.projection();
        });

        orbit_zoom_camera.event(&e);

        if let Some(args) = e.render_args() {
            graphics.clear(clear, gfx::COLOR | gfx::DEPTH, &frame);

            let camera_view = orbit_zoom_camera.camera(args.ext_dt).orthogonal();

            let camera_projection = model_view_projection(
                model,
                camera_view,
                projection
            );

            // Draw axes
            debug_renderer.draw_line([0.0, 0.0, 0.0], [5.0, 0.0, 0.0], [1.0, 0.0, 0.0, 1.0]);
            debug_renderer.draw_line([0.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 1.0, 0.0, 1.0]);
            debug_renderer.draw_line([0.0, 0.0, 0.0], [0.0, 0.0, 5.0], [0.0, 0.0, 1.0, 1.0]);

            debug_renderer.draw_text_at_position(
                "X",
                [6.0, 0.0, 0.0],
                [1.0, 0.0, 0.0, 1.0],
            );

            debug_renderer.draw_text_at_position(
                "Y",
                [0.0, 6.0, 0.0],
                [0.0, 1.0, 0.0, 1.0],
            );

            debug_renderer.draw_text_at_position(
                "Z",
                [0.0, 0.0, 6.0],
                [0.0, 0.0, 1.0, 1.0],
            );

            debug_renderer.update(&mut graphics.device);
            debug_renderer.render(&mut graphics, &frame, camera_projection);

            elapsed_time = elapsed_time + 0.02f64; // TODO use actual time
            skinned_renderer.render(&mut graphics, &frame, camera_view, camera_projection, elapsed_time as f32);

            graphics.end_frame();
        }
    }
}
<commit_msg>Update to latest gfx-rs<commit_after>extern crate gfx_gl as gl;
extern crate camera_controllers;
extern crate collada;
extern crate env_logger;
extern crate gfx;
extern crate gfx_debug_draw;
extern crate gfx_device_gl;
extern crate piston;
extern crate sdl2;
extern crate sdl2_window;
extern crate shader_version;
extern crate skeletal_animation;
extern crate vecmath;

use gfx::traits::*;
use gfx_debug_draw::DebugRenderer;

use gl::Gl;

use std::path::Path;
use std::rc::Rc;
use std::cell::RefCell;

use piston::window::{
    WindowSettings,
    OpenGLWindow,
};

use piston::event::{
    events,
    RenderEvent,
    ResizeEvent,
};

use vecmath::mat4_id;

use sdl2_window::Sdl2Window;

use camera_controllers::{
    OrbitZoomCamera,
    OrbitZoomCameraSettings,
    CameraPerspective,
    model_view_projection
};

use skeletal_animation::SkinnedRenderer;
use collada::document::ColladaDocument;

fn main() {

    env_logger::init().unwrap();

    let (win_width, win_height) = (640, 480);

    let mut window = Sdl2Window::new(
        shader_version::OpenGL::_3_2,
        WindowSettings::new(
            "Animation Viewer".to_string(),
            piston::window::Size { width: 640, height: 480 }
        ).exit_on_esc(true)
    );

    let mut graphics = gfx_device_gl::create(|s| window.get_proc_address(s)).into_graphics();

    let mut frame = gfx::Frame::new(win_width as u16, win_height as u16);

    let window = Rc::new(RefCell::new(window));

    let clear = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0
    };

    let mut debug_renderer = DebugRenderer::new(&mut graphics, [frame.width as u32, frame.height as u32], 64, None, None).ok().unwrap();

    // TODO - these are (usually) available in the COLLADA file, associated with a <mesh> element in a somewhat convoluted way
    let texture_paths = vec![
        "assets/young_lightskinned_male_diffuse.png",
        "assets/suit01lres_diffuse.png",
        "assets/male02_diffuse_black.png",
        "assets/brown_eye.png",
        "assets/eyebrow009.png",
        "assets/eyelashes01.png",
    ];

    let collada_document = ColladaDocument::from_path(&Path::new("assets/suit_guy.dae")).unwrap();
    let mut skinned_renderer = SkinnedRenderer::from_collada(&mut graphics, collada_document, texture_paths).unwrap();

    let model = mat4_id();
    let mut projection = CameraPerspective {
        fov: 90.0f32,
        near_clip: 0.1,
        far_clip: 1000.0,
        aspect_ratio: (win_width as f32) / (win_height as f32)
    }.projection();

    let mut orbit_zoom_camera: OrbitZoomCamera<f32> = OrbitZoomCamera::new(
        [0.0, 0.0, 0.0],
        OrbitZoomCameraSettings::default()
    );

    // Start event loop

    Gl::load_with(|s| unsafe {
        std::mem::transmute(sdl2::video::gl_get_proc_address(s))
    });

    let mut elapsed_time = 0f64;

    for e in events(window) {

        e.resize(|width, height| {
            debug_renderer.resize(width, height);

            // Update frame
            frame.width = width as u16;
            frame.height = height as u16;

            // Update projection matrix
            projection = CameraPerspective {
                fov: 90.0f32,
                near_clip: 0.1,
                far_clip: 1000.0,
                aspect_ratio: (width as f32) / (height as f32)
            }.projection();
        });

        orbit_zoom_camera.event(&e);

        if let Some(args) = e.render_args() {
            graphics.clear(clear, gfx::COLOR | gfx::DEPTH, &frame);

            let camera_view = orbit_zoom_camera.camera(args.ext_dt).orthogonal();

            let camera_projection = model_view_projection(
                model,
                camera_view,
                projection
            );

            // Draw axes
            debug_renderer.draw_line([0.0, 0.0, 0.0], [5.0, 0.0, 0.0], [1.0, 0.0, 0.0, 1.0]);
            debug_renderer.draw_line([0.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 1.0, 0.0, 1.0]);
            debug_renderer.draw_line([0.0, 0.0, 0.0], [0.0, 0.0, 5.0], [0.0, 0.0, 1.0, 1.0]);

            debug_renderer.draw_text_at_position(
                "X",
                [6.0, 0.0, 0.0],
                [1.0, 0.0, 0.0, 1.0],
            );

            debug_renderer.draw_text_at_position(
                "Y",
                [0.0, 6.0, 0.0],
                [0.0, 1.0, 0.0, 1.0],
            );

            debug_renderer.draw_text_at_position(
                "Z",
                [0.0, 0.0, 6.0],
                [0.0, 0.0, 1.0, 1.0],
            );

            debug_renderer.render(&mut graphics, &frame, camera_projection);

            elapsed_time = elapsed_time + 0.02f64; // TODO use actual time
            skinned_renderer.render(&mut graphics, &frame, camera_view, camera_projection, elapsed_time as f32);

            graphics.end_frame();
        }
    }
}
<|endoftext|>


<commit_before>//! A flat representation of memory provided by lifters, typically used in a
//! read-only fashion
//!
//! This memory model implements the `TranslationMemory` trait, allowing lifters
//! to use it to lift instructions.

use architecture::Endian;
use error::*;
use memory::MemoryPermissions;
use std::collections::Bound::Included;
use std::collections::BTreeMap;
use translator::TranslationMemory;

/// A section of backed memory. Essentially a vector of type `u8` with
/// permissions.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Section {
    data: Vec<u8>,
    permissions: MemoryPermissions,
}

impl Section {
    /// Create a new memory section.
    pub fn new(data: Vec<u8>, permissions: MemoryPermissions) -> Section {
        Section {
            data: data,
            permissions: permissions,
        }
    }

    /// Get this memory section's data.
    pub fn data(&self) -> &[u8] {
        &self.data
    }

    /// Get the length of this memory section.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Get the permissions of this memory section.
    pub fn permissions(&self) -> MemoryPermissions {
        self.permissions.clone()
    }

    /// Truncate the data of this memory section.
    fn truncate(&mut self, size: usize) {
        self.data.truncate(size);
    }
}

/// A simple memory model, containing permissioned sections of type `u8`.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Memory {
    endian: Endian,
    sections: BTreeMap<u64, Section>
}

impl Memory {
    /// Create a new backed memory module with the given endianness.
    pub fn new(endian: Endian) -> Memory {
        Memory {
            endian: endian,
            sections: BTreeMap::new()
        }
    }

    /// Get the sections in this memory module.
    pub fn sections(&self) -> &BTreeMap<u64, Section> {
        &self.sections
    }

    /// Get the permissions at the given address.
    pub fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        match self.section_address(address) {
            Some(section_address) =>
                Some(self.sections
                        .get(&section_address)
                        .expect(&format!(
                            "Failed to get section at 0x{:x} in \
                             backing::Memory::permissions()",
                            section_address))
                        .permissions()),
            None => None
        }
    }

    /// Get the `u8` value at the given address.
    pub fn get8(&self, address: u64) -> Option<u8> {
        match self.section_address_offset(address) {
            Some((address, offset)) =>
                Some(*self.sections
                        .get(&address)
                        .expect(&format!(
                            "Failed to get section at 0x{:x} in \
                             backing::Memory::permissions()",
                            address))
                        .data()
                        .get(offset)
                        .expect(&format!(
                            "Failed to get offset 0x{:x} from 0x{:x} in \
                             backing::Memory::permissions()",
                            offset, address))),
            None => None
        }
    }

    /// Set the 32-bit value at the given address, allowing the memory model
    /// to account for the underlying endianness.
    pub fn set32(&mut self, address: u64, value: u32) -> Result<()> {
        let (section_address, offset) =
            self.section_address_offset(address)
                .expect(&format!("Address 0x{:x} has no section", address));

        let section = self.sections.get_mut(&section_address).unwrap();

        if offset + 4 > section.len() {
            bail!(format!("Section at 0x{:x} is of size {}, and not big \
                           enough to hold 32-bit value",
                           section_address,
                           section.len()));
        }

        match self.endian {
            Endian::Big => {
                *section.data.get_mut(offset    ).unwrap() = (value >> 24) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 8 ) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value      ) as u8;
            },
            Endian::Little => {
                *section.data.get_mut(offset    ).unwrap() = (value      ) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 8 ) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value >> 24) as u8;
            }
        }

        Ok(())
    }

    /// Get the 32-bit value at the given address, allowing the memory model to
    /// account for the underlying endianness.
    pub fn get32(&self, address: u64) -> Option<u32> {
        let (section_address, offset) = match self.section_address_offset(address) {
            Some((section_address, offset)) => (section_address, offset),
            None => return None
        };

        let section = self.sections.get(&section_address).unwrap();

        if offset + 4 > section.len() {
            return None;
        }

        Some(match self.endian {
            Endian::Big => {
                (section.data[offset    ] as u32) << 24 |
                (section.data[offset + 1] as u32) << 16 |
                (section.data[offset + 2] as u32) <<  8 |
                (section.data[offset + 3] as u32)
            },
            Endian::Little => {
                (section.data[offset    ] as u32)       |
                (section.data[offset + 1] as u32) <<  8 |
                (section.data[offset + 2] as u32) << 16 |
                (section.data[offset + 3] as u32) << 24
            }
        })
    }

    /// Set the memory at the given address, and give that memory the given
    /// permissions.
    ///
    /// This takes care of the underlying memory sections automatically.
    pub fn set_memory(
        &mut self,
        address: u64,
        data: Vec<u8>,
        permissions: MemoryPermissions
    ) {
        // All overlapping memory sections need to be adjusted
        // Start by collecting addresses and lengths
        let als = self.sections
                      .iter()
                      .map(|(address, section)| (*address, section.len()))
                      .collect::<Vec<(u64, usize)>>();

        // Adjust overlapping memory sections
        for al in als {
            let (a, l) = (al.0, al.1 as u64);
            if a < address && a + l > address {
                if a + l <= address + data.len() as u64 {
                    let new_length = (address - a) as usize;
                    self.sections
                        .get_mut(&a)
                        .expect(&format!(
                            "Failed to get section 0x{:x} in \
                            backing::Memory::set_memory(). This should never \
                            happen.", a))
                        .truncate(new_length);
                }
                else {
                    let offset = address + data.len() as u64 - a;
                    let split =
                        self.sections
                            .get_mut(&a)
                            .expect(&format!(
                                "Failed to get section 0x{:x} in \
                                backing::Memory::set_memory(). This should \
                                never happen.", a))
                            .data
                            .split_off(offset as usize);
                    let permissions =
                        self.sections
                            .get(&a)
                            .expect(&format!(
                                "Failed to get section 0x{:x} in \
                                 backing::Memory::set_memory(). This should \
                                 never happen.", a))
                            .permissions();
                    self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions)
                    );

                    let new_length = (address - a) as usize;
                    self.sections.get_mut(&a).unwrap().truncate(new_length);
                }
            }
            else if a >= address && a + l <= address + data.len() as u64 {
                if self.sections.get(&a).is_none() {
                    panic!("About to remove 0x{:x} from sections in \
                            backing::Memory::set_memory, but address does not
                            exist");
                }
                self.sections.remove(&a);
            }
            else if a >= address &&
                    a < address + data.len() as u64 &&
                    a + l > address + data.len() as u64 {
                let offset = address + data.len() as u64 - a;
                let data_len = self.sections
                                .get(&a)
                                .unwrap()
                                .data
                                .len() as u64;
                if offset > data_len {
                    panic!("offset 0x{:x} is > data.len() 0x{:x}", offset, data_len);
                }
                let split = self.sections
                                .get_mut(&a)
                                .unwrap()
                                .data
                                .split_off(offset as usize);
                let permissions =
                    self.sections
                        .get(&a)
                        .expect(&format!(
                            "Failed to get section for 0x{:x} while updating \
                             permissions in backing::Memory::set_memory(). \
                             This should never happen.", a))
                        .permissions();
                self.sections.remove(&a);
                self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions)
                );
            }
        }

        self.sections.insert(address, Section::new(data, permissions));
    }

    fn section_address(&self, address: u64) -> Option<u64> {
        let mut sections = self.sections.range((Included(0), Included(address)));
        if let Some((section_address, section)) = sections.next_back() {
            if    *section_address <= address
               && *section_address + section.len() as u64 > address {
                return Some(*section_address);
            }
        }
        None
    }

    fn section_address_offset(&self, address: u64) -> Option<(u64, usize)> {
        match self.section_address(address) {
            Some(section_address) =>
                Some((section_address, (address - section_address) as usize)),
            None => None
        }
    }
}

impl TranslationMemory for Memory {
    fn get_u8(&self, address: u64) -> Option<u8> {
        self.get8(address)
    }

    fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        self.permissions(address)
    }
}<commit_msg>add get() function for memory backing<commit_after>//! A flat representation of memory provided by lifters, typically used in a
//! read-only fashion
//!
//! This memory model implements the `TranslationMemory` trait, allowing lifters
//! to use it to lift instructions.

use architecture::Endian;
use error::*;
use executor;
use il;
use memory::MemoryPermissions;
use std::collections::Bound::Included;
use std::collections::BTreeMap;
use translator::TranslationMemory;

/// A section of backed memory. Essentially a vector of type `u8` with
/// permissions.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Section {
    data: Vec<u8>,
    permissions: MemoryPermissions,
}

impl Section {
    /// Create a new memory section.
    pub fn new(data: Vec<u8>, permissions: MemoryPermissions) -> Section {
        Section {
            data: data,
            permissions: permissions,
        }
    }

    /// Get this memory section's data.
    pub fn data(&self) -> &[u8] {
        &self.data
    }

    /// Get the length of this memory section.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Get the permissions of this memory section.
    pub fn permissions(&self) -> MemoryPermissions {
        self.permissions.clone()
    }

    /// Truncate the data of this memory section.
    fn truncate(&mut self, size: usize) {
        self.data.truncate(size);
    }
}

/// A simple memory model, containing permissioned sections of type `u8`.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Memory {
    endian: Endian,
    sections: BTreeMap<u64, Section>
}

impl Memory {
    /// Create a new backed memory module with the given endianness.
    pub fn new(endian: Endian) -> Memory {
        Memory {
            endian: endian,
            sections: BTreeMap::new()
        }
    }

    /// Get the sections in this memory module.
    pub fn sections(&self) -> &BTreeMap<u64, Section> {
        &self.sections
    }

    /// Get the permissions at the given address.
    pub fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        match self.section_address(address) {
            Some(section_address) =>
                Some(self.sections
                        .get(&section_address)
                        .expect(&format!(
                            "Failed to get section at 0x{:x} in \
                             backing::Memory::permissions()",
                            section_address))
                        .permissions()),
            None => None
        }
    }

    /// Get the `u8` value at the given address.
    pub fn get8(&self, address: u64) -> Option<u8> {
        match self.section_address_offset(address) {
            Some((address, offset)) =>
                Some(*self.sections
                        .get(&address)
                        .expect(&format!(
                            "Failed to get section at 0x{:x} in \
                             backing::Memory::permissions()",
                            address))
                        .data()
                        .get(offset)
                        .expect(&format!(
                            "Failed to get offset 0x{:x} from 0x{:x} in \
                             backing::Memory::permissions()",
                            offset, address))),
            None => None
        }
    }

    /// Set the 32-bit value at the given address, allowing the memory model
    /// to account for the underlying endianness.
    pub fn set32(&mut self, address: u64, value: u32) -> Result<()> {
        let (section_address, offset) =
            self.section_address_offset(address)
                .expect(&format!("Address 0x{:x} has no section", address));

        let section = self.sections.get_mut(&section_address).unwrap();

        if offset + 4 > section.len() {
            bail!(format!("Section at 0x{:x} is of size {}, and not big \
                           enough to hold 32-bit value",
                           section_address,
                           section.len()));
        }

        match self.endian {
            Endian::Big => {
                *section.data.get_mut(offset    ).unwrap() = (value >> 24) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 8 ) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value      ) as u8;
            },
            Endian::Little => {
                *section.data.get_mut(offset    ).unwrap() = (value      ) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 8 ) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value >> 24) as u8;
            }
        }

        Ok(())
    }

    /// Get the 32-bit value at the given address, allowing the memory model to
    /// account for the underlying endianness.
    pub fn get32(&self, address: u64) -> Option<u32> {
        let (section_address, offset) = match self.section_address_offset(address) {
            Some((section_address, offset)) => (section_address, offset),
            None => return None
        };

        let section = self.sections.get(&section_address).unwrap();

        if offset + 4 > section.len() {
            return None;
        }

        Some(match self.endian {
            Endian::Big => {
                (section.data[offset    ] as u32) << 24 |
                (section.data[offset + 1] as u32) << 16 |
                (section.data[offset + 2] as u32) <<  8 |
                (section.data[offset + 3] as u32)
            },
            Endian::Little => {
                (section.data[offset    ] as u32)       |
                (section.data[offset + 1] as u32) <<  8 |
                (section.data[offset + 2] as u32) << 16 |
                (section.data[offset + 3] as u32) << 24
            }
        })
    }

    /// Get a constant value up to a certain number of bits
    pub fn get(&self, address: u64, bits: usize) -> Option<il::Constant> {
        if bits % 8 > 0 || bits == 0 {
            return None;
        }

        let mut value = il::expr_const(self.get8(address)? as u64, 8);

        match self.endian {
            Endian::Big => {
                for i in 1..(bits / 8) {
                    let expr_bits = (i + 1) * 8;
                    value = il::Expression::or(
                        il::Expression::shl(
                            il::Expression::zext(expr_bits, value).unwrap(),
                            il::expr_const(8, expr_bits)).unwrap(),

                        il::expr_const(self.get8(address + i as u64).unwrap() as u64, expr_bits)
                    ).unwrap();
                }
                Some(executor::eval(&value).unwrap())
            },
            Endian::Little => {
                for i in 1..(bits / 8) {
                    let expr_bits = value.bits() + 8;
                    value = il::Expression::or(
                        il::Expression::shl(
                            il::expr_const(self.get8(address + i as u64).unwrap() as u64, expr_bits),
                            il::expr_const((i * 8) as u64, expr_bits)).unwrap(),
                        il::Expression::zext(expr_bits,
                            il::Expression::zext(expr_bits, value).unwrap()
                        ).unwrap()).unwrap();
                }
                Some(executor::eval(&value).unwrap())
            }
        }
    }

    /// Set the memory at the given address, and give that memory the given
    /// permissions.
    ///
    /// This takes care of the underlying memory sections automatically.
    pub fn set_memory(
        &mut self,
        address: u64,
        data: Vec<u8>,
        permissions: MemoryPermissions
    ) {
        // All overlapping memory sections need to be adjusted
        // Start by collecting addresses and lengths
        let als = self.sections
                      .iter()
                      .map(|(address, section)| (*address, section.len()))
                      .collect::<Vec<(u64, usize)>>();

        // Adjust overlapping memory sections
        for al in als {
            let (a, l) = (al.0, al.1 as u64);
            if a < address && a + l > address {
                if a + l <= address + data.len() as u64 {
                    let new_length = (address - a) as usize;
                    self.sections
                        .get_mut(&a)
                        .expect(&format!(
                            "Failed to get section 0x{:x} in \
                            backing::Memory::set_memory(). This should never \
                            happen.", a))
                        .truncate(new_length);
                }
                else {
                    let offset = address + data.len() as u64 - a;
                    let split =
                        self.sections
                            .get_mut(&a)
                            .expect(&format!(
                                "Failed to get section 0x{:x} in \
                                backing::Memory::set_memory(). This should \
                                never happen.", a))
                            .data
                            .split_off(offset as usize);
                    let permissions =
                        self.sections
                            .get(&a)
                            .expect(&format!(
                                "Failed to get section 0x{:x} in \
                                 backing::Memory::set_memory(). This should \
                                 never happen.", a))
                            .permissions();
                    self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions)
                    );

                    let new_length = (address - a) as usize;
                    self.sections.get_mut(&a).unwrap().truncate(new_length);
                }
            }
            else if a >= address && a + l <= address + data.len() as u64 {
                if self.sections.get(&a).is_none() {
                    panic!("About to remove 0x{:x} from sections in \
                            backing::Memory::set_memory, but address does not
                            exist");
                }
                self.sections.remove(&a);
            }
            else if a >= address &&
                    a < address + data.len() as u64 &&
                    a + l > address + data.len() as u64 {
                let offset = address + data.len() as u64 - a;
                let data_len = self.sections
                                .get(&a)
                                .unwrap()
                                .data
                                .len() as u64;
                if offset > data_len {
                    panic!("offset 0x{:x} is > data.len() 0x{:x}", offset, data_len);
                }
                let split = self.sections
                                .get_mut(&a)
                                .unwrap()
                                .data
                                .split_off(offset as usize);
                let permissions =
                    self.sections
                        .get(&a)
                        .expect(&format!(
                            "Failed to get section for 0x{:x} while updating \
                             permissions in backing::Memory::set_memory(). \
                             This should never happen.", a))
                        .permissions();
                self.sections.remove(&a);
                self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions)
                );
            }
        }

        self.sections.insert(address, Section::new(data, permissions));
    }

    fn section_address(&self, address: u64) -> Option<u64> {
        let mut sections = self.sections.range((Included(0), Included(address)));
        if let Some((section_address, section)) = sections.next_back() {
            if    *section_address <= address
               && *section_address + section.len() as u64 > address {
                return Some(*section_address);
            }
        }
        None
    }

    fn section_address_offset(&self, address: u64) -> Option<(u64, usize)> {
        match self.section_address(address) {
            Some(section_address) =>
                Some((section_address, (address - section_address) as usize)),
            None => None
        }
    }
}

impl TranslationMemory for Memory {
    fn get_u8(&self, address: u64) -> Option<u8> {
        self.get8(address)
    }

    fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        self.permissions(address)
    }
}<|endoftext|>


<commit_before>use std::env;
use std::ffi::CString;
use std::fs::File;
use std::io;
use std::path::Path;
use std::process;

extern crate getopts;
extern crate image;
extern crate isatty;
extern crate libc;
extern crate time;
extern crate x11;
use x11::xlib;

mod xwrap;
use xwrap::Display;

fn usage(progname: &str, opts: getopts::Options) {
    let brief = format!("Usage: {} [options] [file]", progname);
    eprint!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let progname = args[0].clone();

    let mut opts = getopts::Options::new();
    opts.optopt("i", "id", "Window to capture", "ID");
    opts.optopt("g", "geometry", "Area to capture", "WxH+X+Y");
    opts.optflag("h", "help", "Print help and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            eprintln!("{}", f.to_string());
            usage(&progname, opts);
            process::exit(1);
        }
    };

    // One loose argument allowed (file name)
    if matches.opt_present("h") || matches.free.len() > 1 {
        usage(&progname, opts);
        return;
    }

    let display = match Display::open(None) {
        Some(d) => d,
        None => {
            eprintln!("Failed to open display");
            process::exit(1);
        }
    };
    let root = display.get_default_root();

    let window = matches.opt_str("i").map_or(root, |s| match s.parse::<xlib::Window>() {
        Ok(r) => r,
        Err(_) => {
            eprintln!("Window ID is not a valid integer");
            process::exit(1);
        },
    });

    let (w, h, x, y) = matches.opt_str("g").map_or_else(|| {
        let attrs = display.get_window_attributes(window);
        (attrs.width as libc::c_uint, attrs.height as libc::c_uint, 0, 0)
    },
    |s| {
        xwrap::parse_geometry(CString::new(s).expect("Failed to convert CString"))
    });

    if w <= 0 || h <= 0 {
        eprintln!("Capture dimensions must be greater than 0");
        process::exit(1);
    }

    let image = match display.get_image(window, x, y, w, h, xwrap::ALL_PLANES, xlib::ZPixmap) {
        Some(i) => i,
        None => {
            eprintln!("Failed to get image from X");
            process::exit(1);
        },
    };

    let image = match image.into_image_buffer() {
        Some(i) => image::ImageRgba8(i),
        None => {
            eprintln!("Failed to convert captured framebuffer, only 24/32 \
                      bit (A)RGB8 is supported");
            process::exit(1);
        }
    };

    let ts_path = format!("{}.png", time::get_time().sec);
    let path = match matches.free.get(0) {
        Some(p) => p,
        None => if !isatty::stdout_isatty() {
            "-"
        } else {
            ts_path.as_str()
        },
    };

    if path == "-" {
        image.save(&mut io::stdout(), image::PNG).expect("Writing to stdout failed");
    } else {
        match File::create(&Path::new(&path)) {
            Ok(mut f) => image.save(&mut f, image::PNG).expect("Writing to file failed"),
            Err(e) => {
                eprintln!("Failed to create {}: {}", path, e);
                process::exit(1)
            },
        }
    }
}
<commit_msg>Cleanup<commit_after>use std::env;
use std::ffi::CString;
use std::fs::File;
use std::io;
use std::path::Path;
use std::process;

extern crate getopts;
use getopts::Options;
extern crate image;
extern crate isatty;
extern crate libc;
extern crate time;
extern crate x11;
use x11::xlib;

mod xwrap;
use xwrap::Display;

fn usage(progname: &str, opts: getopts::Options) {
    let brief = format!("Usage: {} [options] [file]", progname);
    eprint!("{}", opts.usage(&brief));
}

fn run() -> i32 {
    let args: Vec<String> = env::args().collect();
    let progname = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("i", "id", "Window to capture", "ID");
    opts.optopt("g", "geometry", "Area to capture", "WxH+X+Y");
    opts.optflag("h", "help", "Print help and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            eprintln!("{}", f.to_string());
            usage(&progname, opts);
            return 1;
        }
    };

    if matches.opt_present("h") {
        usage(&progname, opts);
        return 0;
    }

    // One loose argument allowed (file name)
    if matches.free.len() > 1 {
        eprintln!("Too many arguments");
        usage(&progname, opts);
        return 1;
    }

    let display = match Display::open(None) {
        Some(d) => d,
        None => {
            eprintln!("Failed to open display");
            return 1;
        }
    };
    let root = display.get_default_root();

    let window = match matches.opt_str("i") {
        Some(s) => match s.parse::<xlib::Window>() {
            Ok(r) => r,
            Err(_) => {
                eprintln!("Window ID is not a valid integer");
                return 1;
            },
        },
        None => root,
    };

    let attrs = display.get_window_attributes(window);
    let (w, h, x, y) = match matches.opt_str("g") {
        Some(s) => xwrap::parse_geometry(CString::new(s).expect("Failed to convert CString")),
        None => {
            (attrs.width as libc::c_uint, attrs.height as libc::c_uint, 0, 0)
        },
    };
    if w <= 0 || h <= 0 || x < 0 || y < 0
        || x + w as libc::c_int > attrs.width || y + h as libc::c_int > attrs.height {
        eprintln!("Invalid geometry");
        return 1;
    }

    let image = match display.get_image(window, x, y, w, h, xwrap::ALL_PLANES, xlib::ZPixmap) {
        Some(i) => i,
        None => {
            eprintln!("Failed to get image from X");
            return 1;
        },
    };

    let image = match image.into_image_buffer() {
        Some(i) => image::ImageRgba8(i),
        None => {
            eprintln!("Failed to convert captured framebuffer, only 24/32 \
                      bit (A)RGB8 is supported");
            return 1;
        }
    };

    let ts_path = format!("{}.png", time::get_time().sec);
    let path = match matches.free.get(0) {
        Some(p) => p,
        None => if !isatty::stdout_isatty() {
            "-"
        } else {
            ts_path.as_str()
        },
    };

    if path == "-" {
        image.save(&mut io::stdout(), image::PNG).expect("Writing to stdout failed");
    } else {
        match File::create(&Path::new(&path)) {
            Ok(mut f) => image.save(&mut f, image::PNG).expect("Writing to file failed"),
            Err(e) => {
                eprintln!("Failed to create {}: {}", path, e);
                return 1
            },
        }
    }

    0
}

fn main() {
    process::exit(run());
}
<|endoftext|>


<commit_before>//! A flat representation of memory provided by lifters, typically used in a
//! read-only fashion
//!
//! This memory model implements the `TranslationMemory` trait, allowing lifters
//! to use it to lift instructions.

use crate::architecture::Endian;
use crate::error::*;
use crate::executor;
use crate::il;
use crate::memory::MemoryPermissions;
use crate::translator::TranslationMemory;
use std::collections::BTreeMap;
use std::collections::Bound::Included;

/// A section of backed memory. Essentially a vector of type `u8` with
/// permissions.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Section {
    data: Vec<u8>,
    permissions: MemoryPermissions,
}

impl Section {
    /// Create a new memory section.
    pub fn new(data: Vec<u8>, permissions: MemoryPermissions) -> Section {
        Section { data, permissions }
    }

    /// Get this memory section's data.
    pub fn data(&self) -> &[u8] {
        &self.data
    }

    /// Get the length of this memory section.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Return `true` if the data field is empty, `false` otherwise.
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    /// Get the permissions of this memory section.
    pub fn permissions(&self) -> MemoryPermissions {
        self.permissions
    }

    /// Truncate the data of this memory section.
    fn truncate(&mut self, size: usize) {
        self.data.truncate(size);
    }
}

/// A simple memory model, containing permissioned sections of type `u8`.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Memory {
    endian: Endian,
    sections: BTreeMap<u64, Section>,
}

impl Memory {
    /// Create a new backed memory module with the given endianness.
    pub fn new(endian: Endian) -> Memory {
        Memory {
            endian,
            sections: BTreeMap::new(),
        }
    }

    /// Get the sections in this memory module.
    pub fn sections(&self) -> &BTreeMap<u64, Section> {
        &self.sections
    }

    /// Get the permissions at the given address.
    pub fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        match self.section_address(address) {
            Some(section_address) => Some(
                self.sections
                    .get(&section_address)
                    .unwrap_or_else(|| {
                        panic!(
                            "Failed to get section at 0x{:x} in \
                         backing::Memory::permissions()",
                            section_address
                        )
                    })
                    .permissions(),
            ),
            None => None,
        }
    }

    /// Get the `u8` value at the given address.
    pub fn get8(&self, address: u64) -> Option<u8> {
        match self.section_address_offset(address) {
            Some((address, offset)) => Some(
                *self
                    .sections
                    .get(&address)
                    .unwrap_or_else(|| {
                        panic!(
                            "Failed to get section at 0x{:x} in \
                         backing::Memory::permissions()",
                            address
                        )
                    })
                    .data()
                    .get(offset)
                    .unwrap_or_else(|| {
                        panic!(
                            "Failed to get offset 0x{:x} from 0x{:x} in \
                         backing::Memory::permissions()",
                            offset, address
                        )
                    }),
            ),
            None => None,
        }
    }

    /// Set the 32-bit value at the given address, allowing the memory model
    /// to account for the underlying endianness.
    pub fn set32(&mut self, address: u64, value: u32) -> Result<()> {
        let (section_address, offset) = self
            .section_address_offset(address)
            .unwrap_or_else(|| panic!("Address 0x{:x} has no section", address));

        let section = self.sections.get_mut(&section_address).unwrap();

        if offset + 4 > section.len() {
            bail!(format!(
                "Section at 0x{:x} is of size {}, and not big \
                 enough to hold 32-bit value",
                section_address,
                section.len()
            ));
        }

        match self.endian {
            Endian::Big => {
                *section.data.get_mut(offset).unwrap() = (value >> 24) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 8) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value) as u8;
            }
            Endian::Little => {
                *section.data.get_mut(offset).unwrap() = (value) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 8) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value >> 24) as u8;
            }
        }

        Ok(())
    }

    /// Get the 32-bit value at the given address, allowing the memory model to
    /// account for the underlying endianness.
    pub fn get32(&self, address: u64) -> Option<u32> {
        let (section_address, offset) = match self.section_address_offset(address) {
            Some((section_address, offset)) => (section_address, offset),
            None => return None,
        };

        let section = self.sections.get(&section_address).unwrap();

        if offset + 4 > section.len() {
            return None;
        }

        Some(match self.endian {
            Endian::Big => {
                (section.data[offset] as u32) << 24
                    | (section.data[offset + 1] as u32) << 16
                    | (section.data[offset + 2] as u32) << 8
                    | (section.data[offset + 3] as u32)
            }
            Endian::Little => {
                (section.data[offset] as u32)
                    | (section.data[offset + 1] as u32) << 8
                    | (section.data[offset + 2] as u32) << 16
                    | (section.data[offset + 3] as u32) << 24
            }
        })
    }

    /// Get a constant value up to a certain number of bits
    pub fn get(&self, address: u64, bits: usize) -> Option<il::Constant> {
        if bits % 8 > 0 || bits == 0 {
            return None;
        }

        let mut value = il::expr_const(self.get8(address)? as u64, bits);

        match self.endian {
            Endian::Big => {
                for i in 1..(bits / 8) {
                    value = il::Expression::or(
                        il::Expression::shl(value, il::expr_const(8, bits)).unwrap(),
                        il::expr_const(self.get8(address + i as u64).unwrap() as u64, bits),
                    )
                    .unwrap();
                }
                Some(executor::eval(&value).unwrap())
            }
            Endian::Little => {
                for i in 1..(bits / 8) {
                    value = il::Expression::or(
                        il::Expression::shl(
                            il::expr_const(self.get8(address + i as u64).unwrap() as u64, bits),
                            il::expr_const((i * 8) as u64, bits),
                        )
                        .unwrap(),
                        value,
                    )
                    .unwrap();
                }
                Some(executor::eval(&value).unwrap())
            }
        }
    }

    /// Set the memory at the given address, and give that memory the given
    /// permissions.
    ///
    /// This takes care of the underlying memory sections automatically.
    pub fn set_memory(&mut self, address: u64, data: Vec<u8>, permissions: MemoryPermissions) {
        // All overlapping memory sections need to be adjusted
        // Start by collecting addresses and lengths
        let als = self
            .sections
            .iter()
            .map(|(address, section)| (*address, section.len()))
            .collect::<Vec<(u64, usize)>>();

        // Adjust overlapping memory sections
        for al in als {
            let (a, l) = (al.0, al.1 as u64);
            if a < address && a + l > address {
                if a + l <= address + data.len() as u64 {
                    let new_length = (address - a) as usize;
                    self.sections
                        .get_mut(&a)
                        .unwrap_or_else(|| {
                            panic!(
                                "Failed to get section 0x{:x} in \
                             backing::Memory::set_memory(). This should never \
                             happen.",
                                a
                            )
                        })
                        .truncate(new_length);
                } else {
                    let offset = address + data.len() as u64 - a;
                    let split = self
                        .sections
                        .get_mut(&a)
                        .unwrap_or_else(|| {
                            panic!(
                                "Failed to get section 0x{:x} in \
                             backing::Memory::set_memory(). This should \
                             never happen.",
                                a
                            )
                        })
                        .data
                        .split_off(offset as usize);
                    let permissions = self
                        .sections
                        .get(&a)
                        .unwrap_or_else(|| {
                            panic!(
                                "Failed to get section 0x{:x} in \
                             backing::Memory::set_memory(). This should \
                             never happen.",
                                a
                            )
                        })
                        .permissions();
                    self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions),
                    );

                    let new_length = (address - a) as usize;
                    self.sections.get_mut(&a).unwrap().truncate(new_length);
                }
            } else if a >= address && a + l <= address + data.len() as u64 {
                if self.sections.get(&a).is_none() {
                    panic!(
                        "About to remove 0x{:x} from sections in \
                            backing::Memory::set_memory, but address does not
                            exist",
                        a
                    );
                }
                self.sections.remove(&a);
            } else if a >= address
                && a < address + data.len() as u64
                && a + l > address + data.len() as u64
            {
                let offset = address + data.len() as u64 - a;
                let data_len = self.sections.get(&a).unwrap().data.len() as u64;
                if offset > data_len {
                    panic!("offset 0x{:x} is > data.len() 0x{:x}", offset, data_len);
                }
                let split = self
                    .sections
                    .get_mut(&a)
                    .unwrap()
                    .data
                    .split_off(offset as usize);
                let permissions = self
                    .sections
                    .get(&a)
                    .unwrap_or_else(|| {
                        panic!(
                            "Failed to get section for 0x{:x} while updating \
                         permissions in backing::Memory::set_memory(). \
                         This should never happen.",
                            a
                        )
                    })
                    .permissions();
                self.sections.remove(&a);
                self.sections.insert(
                    address + data.len() as u64,
                    Section::new(split, permissions),
                );
            }
        }

        self.sections
            .insert(address, Section::new(data, permissions));
    }

    fn section_address(&self, address: u64) -> Option<u64> {
        let mut sections = self.sections.range((Included(0), Included(address)));
        if let Some((section_address, section)) = sections.next_back() {
            if *section_address <= address && *section_address + section.len() as u64 > address {
                return Some(*section_address);
            }
        }
        None
    }

    fn section_address_offset(&self, address: u64) -> Option<(u64, usize)> {
        match self.section_address(address) {
            Some(section_address) => Some((section_address, (address - section_address) as usize)),
            None => None,
        }
    }
}

impl TranslationMemory for Memory {
    fn get_u8(&self, address: u64) -> Option<u8> {
        self.get8(address)
    }

    fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        self.permissions(address)
    }
}
<commit_msg>Replace deprecated collections::Bound with ops::Bound (#97)<commit_after>//! A flat representation of memory provided by lifters, typically used in a
//! read-only fashion
//!
//! This memory model implements the `TranslationMemory` trait, allowing lifters
//! to use it to lift instructions.

use crate::architecture::Endian;
use crate::error::*;
use crate::executor;
use crate::il;
use crate::memory::MemoryPermissions;
use crate::translator::TranslationMemory;
use std::collections::BTreeMap;
use std::ops::Bound::Included;

/// A section of backed memory. Essentially a vector of type `u8` with
/// permissions.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Section {
    data: Vec<u8>,
    permissions: MemoryPermissions,
}

impl Section {
    /// Create a new memory section.
    pub fn new(data: Vec<u8>, permissions: MemoryPermissions) -> Section {
        Section { data, permissions }
    }

    /// Get this memory section's data.
    pub fn data(&self) -> &[u8] {
        &self.data
    }

    /// Get the length of this memory section.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Return `true` if the data field is empty, `false` otherwise.
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    /// Get the permissions of this memory section.
    pub fn permissions(&self) -> MemoryPermissions {
        self.permissions
    }

    /// Truncate the data of this memory section.
    fn truncate(&mut self, size: usize) {
        self.data.truncate(size);
    }
}

/// A simple memory model, containing permissioned sections of type `u8`.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Memory {
    endian: Endian,
    sections: BTreeMap<u64, Section>,
}

impl Memory {
    /// Create a new backed memory module with the given endianness.
    pub fn new(endian: Endian) -> Memory {
        Memory {
            endian,
            sections: BTreeMap::new(),
        }
    }

    /// Get the sections in this memory module.
    pub fn sections(&self) -> &BTreeMap<u64, Section> {
        &self.sections
    }

    /// Get the permissions at the given address.
    pub fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        match self.section_address(address) {
            Some(section_address) => Some(
                self.sections
                    .get(&section_address)
                    .unwrap_or_else(|| {
                        panic!(
                            "Failed to get section at 0x{:x} in \
                         backing::Memory::permissions()",
                            section_address
                        )
                    })
                    .permissions(),
            ),
            None => None,
        }
    }

    /// Get the `u8` value at the given address.
    pub fn get8(&self, address: u64) -> Option<u8> {
        match self.section_address_offset(address) {
            Some((address, offset)) => Some(
                *self
                    .sections
                    .get(&address)
                    .unwrap_or_else(|| {
                        panic!(
                            "Failed to get section at 0x{:x} in \
                         backing::Memory::permissions()",
                            address
                        )
                    })
                    .data()
                    .get(offset)
                    .unwrap_or_else(|| {
                        panic!(
                            "Failed to get offset 0x{:x} from 0x{:x} in \
                         backing::Memory::permissions()",
                            offset, address
                        )
                    }),
            ),
            None => None,
        }
    }

    /// Set the 32-bit value at the given address, allowing the memory model
    /// to account for the underlying endianness.
    pub fn set32(&mut self, address: u64, value: u32) -> Result<()> {
        let (section_address, offset) = self
            .section_address_offset(address)
            .unwrap_or_else(|| panic!("Address 0x{:x} has no section", address));

        let section = self.sections.get_mut(&section_address).unwrap();

        if offset + 4 > section.len() {
            bail!(format!(
                "Section at 0x{:x} is of size {}, and not big \
                 enough to hold 32-bit value",
                section_address,
                section.len()
            ));
        }

        match self.endian {
            Endian::Big => {
                *section.data.get_mut(offset).unwrap() = (value >> 24) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 8) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value) as u8;
            }
            Endian::Little => {
                *section.data.get_mut(offset).unwrap() = (value) as u8;
                *section.data.get_mut(offset + 1).unwrap() = (value >> 8) as u8;
                *section.data.get_mut(offset + 2).unwrap() = (value >> 16) as u8;
                *section.data.get_mut(offset + 3).unwrap() = (value >> 24) as u8;
            }
        }

        Ok(())
    }

    /// Get the 32-bit value at the given address, allowing the memory model to
    /// account for the underlying endianness.
    pub fn get32(&self, address: u64) -> Option<u32> {
        let (section_address, offset) = match self.section_address_offset(address) {
            Some((section_address, offset)) => (section_address, offset),
            None => return None,
        };

        let section = self.sections.get(&section_address).unwrap();

        if offset + 4 > section.len() {
            return None;
        }

        Some(match self.endian {
            Endian::Big => {
                (section.data[offset] as u32) << 24
                    | (section.data[offset + 1] as u32) << 16
                    | (section.data[offset + 2] as u32) << 8
                    | (section.data[offset + 3] as u32)
            }
            Endian::Little => {
                (section.data[offset] as u32)
                    | (section.data[offset + 1] as u32) << 8
                    | (section.data[offset + 2] as u32) << 16
                    | (section.data[offset + 3] as u32) << 24
            }
        })
    }

    /// Get a constant value up to a certain number of bits
    pub fn get(&self, address: u64, bits: usize) -> Option<il::Constant> {
        if bits % 8 > 0 || bits == 0 {
            return None;
        }

        let mut value = il::expr_const(self.get8(address)? as u64, bits);

        match self.endian {
            Endian::Big => {
                for i in 1..(bits / 8) {
                    value = il::Expression::or(
                        il::Expression::shl(value, il::expr_const(8, bits)).unwrap(),
                        il::expr_const(self.get8(address + i as u64).unwrap() as u64, bits),
                    )
                    .unwrap();
                }
                Some(executor::eval(&value).unwrap())
            }
            Endian::Little => {
                for i in 1..(bits / 8) {
                    value = il::Expression::or(
                        il::Expression::shl(
                            il::expr_const(self.get8(address + i as u64).unwrap() as u64, bits),
                            il::expr_const((i * 8) as u64, bits),
                        )
                        .unwrap(),
                        value,
                    )
                    .unwrap();
                }
                Some(executor::eval(&value).unwrap())
            }
        }
    }

    /// Set the memory at the given address, and give that memory the given
    /// permissions.
    ///
    /// This takes care of the underlying memory sections automatically.
    pub fn set_memory(&mut self, address: u64, data: Vec<u8>, permissions: MemoryPermissions) {
        // All overlapping memory sections need to be adjusted
        // Start by collecting addresses and lengths
        let als = self
            .sections
            .iter()
            .map(|(address, section)| (*address, section.len()))
            .collect::<Vec<(u64, usize)>>();

        // Adjust overlapping memory sections
        for al in als {
            let (a, l) = (al.0, al.1 as u64);
            if a < address && a + l > address {
                if a + l <= address + data.len() as u64 {
                    let new_length = (address - a) as usize;
                    self.sections
                        .get_mut(&a)
                        .unwrap_or_else(|| {
                            panic!(
                                "Failed to get section 0x{:x} in \
                             backing::Memory::set_memory(). This should never \
                             happen.",
                                a
                            )
                        })
                        .truncate(new_length);
                } else {
                    let offset = address + data.len() as u64 - a;
                    let split = self
                        .sections
                        .get_mut(&a)
                        .unwrap_or_else(|| {
                            panic!(
                                "Failed to get section 0x{:x} in \
                             backing::Memory::set_memory(). This should \
                             never happen.",
                                a
                            )
                        })
                        .data
                        .split_off(offset as usize);
                    let permissions = self
                        .sections
                        .get(&a)
                        .unwrap_or_else(|| {
                            panic!(
                                "Failed to get section 0x{:x} in \
                             backing::Memory::set_memory(). This should \
                             never happen.",
                                a
                            )
                        })
                        .permissions();
                    self.sections.insert(
                        address + data.len() as u64,
                        Section::new(split, permissions),
                    );

                    let new_length = (address - a) as usize;
                    self.sections.get_mut(&a).unwrap().truncate(new_length);
                }
            } else if a >= address && a + l <= address + data.len() as u64 {
                if self.sections.get(&a).is_none() {
                    panic!(
                        "About to remove 0x{:x} from sections in \
                            backing::Memory::set_memory, but address does not
                            exist",
                        a
                    );
                }
                self.sections.remove(&a);
            } else if a >= address
                && a < address + data.len() as u64
                && a + l > address + data.len() as u64
            {
                let offset = address + data.len() as u64 - a;
                let data_len = self.sections.get(&a).unwrap().data.len() as u64;
                if offset > data_len {
                    panic!("offset 0x{:x} is > data.len() 0x{:x}", offset, data_len);
                }
                let split = self
                    .sections
                    .get_mut(&a)
                    .unwrap()
                    .data
                    .split_off(offset as usize);
                let permissions = self
                    .sections
                    .get(&a)
                    .unwrap_or_else(|| {
                        panic!(
                            "Failed to get section for 0x{:x} while updating \
                         permissions in backing::Memory::set_memory(). \
                         This should never happen.",
                            a
                        )
                    })
                    .permissions();
                self.sections.remove(&a);
                self.sections.insert(
                    address + data.len() as u64,
                    Section::new(split, permissions),
                );
            }
        }

        self.sections
            .insert(address, Section::new(data, permissions));
    }

    fn section_address(&self, address: u64) -> Option<u64> {
        let mut sections = self.sections.range((Included(0), Included(address)));
        if let Some((section_address, section)) = sections.next_back() {
            if *section_address <= address && *section_address + section.len() as u64 > address {
                return Some(*section_address);
            }
        }
        None
    }

    fn section_address_offset(&self, address: u64) -> Option<(u64, usize)> {
        match self.section_address(address) {
            Some(section_address) => Some((section_address, (address - section_address) as usize)),
            None => None,
        }
    }
}

impl TranslationMemory for Memory {
    fn get_u8(&self, address: u64) -> Option<u8> {
        self.get8(address)
    }

    fn permissions(&self, address: u64) -> Option<MemoryPermissions> {
        self.permissions(address)
    }
}
<|endoftext|>