<commit_before>// TODO:
//   - data directories
//   - name sections
//   - list functions
//   - colors
//   - summarize as empty/hex/strings
//   - section entropy
//   - resource parsing
extern crate log;
extern crate lancelot;
#[macro_use] extern crate lazy_static;

use std::collections::HashMap;
use std::env;
use std::ops::Range;
use std::process;

use better_panic;
use failure::{Error, Fail};
use goblin::Object;
use log::{error, info, trace};
use regex::bytes::Regex;

use lancelot::util;
use lancelot::workspace::Workspace;

#[derive(Debug, Fail)]
pub enum MainError {
    #[fail(display = "foo")]
    Foo,
    #[fail(display = "Invalid PE file")]
    InvalidFile,
}

pub struct Config {
    pub filename: String,
}

impl Config {
    pub fn from_args(args: env::Args) -> Result<Config, &'static str> {
        let args: Vec<String> = args.collect();

        if args.len() < 2 {
            return Err("not enough arguments: provide `mapa.exe /path/to/input.exe`");
        }

        let filename = args[1].clone();
        trace!("config: parsed filename: {:?}", filename);

        Ok(Config { filename })
    }
}

pub fn setup_logging(_args: &Config) {
    simplelog::TermLogger::init(simplelog::LevelFilter::Info, simplelog::Config::default())
        .expect("failed to setup logging");
}

/*
    File
      Header,
        IMAGE_DOS_HEADER,
        IMAGE_NT_HEADERS,
          Signature
          IMAGE_FILE_HEADER,
          IMAGE_OPTIONAL_HEADER,
      IMAGE_SECTION_HEADER,
      Section(u32),
      Slack
*/

#[derive(Debug, Copy, Clone)]
enum Structure {
    /// the complete file
    File,
    /// the file headers.
    Header,
    IMAGE_DOS_HEADER,
    IMAGE_NT_HEADERS,
    Signature,
    IMAGE_FILE_HEADER,
    IMAGE_OPTIONAL_HEADER,
    IMAGE_SECTION_HEADER(u16),
    /// a section's content
    Section(u16),
    Slack,
}

fn cmp_ranges(a: &Range<u64>, b: &Range<u64>) -> std::cmp::Ordering {
    if a.start < b.start {
        std::cmp::Ordering::Less
    } else if a.start > b.start {
        std::cmp::Ordering::Greater
    } else if a.end < b.end {
        std::cmp::Ordering::Greater
    } else if a.end > b.end {
        std::cmp::Ordering::Less
    } else {
        std::cmp::Ordering::Equal
    }
}

fn find_ascii_strings(buf: &[u8]) -> Vec<(usize, String)> {
    lazy_static! {
        static ref re: Regex = Regex::new("[ -~]{4,}").unwrap();
    }

    re.captures_iter(buf)
        .map(|cap| {
            // guaranteed to have at least one hit
            let mat = cap.get(0).unwrap();

            // this had better be ASCII, and therefore able to be decoded.
            let s = String::from_utf8(mat.as_bytes().to_vec()).unwrap();

            (mat.start(), s)
        })
        .collect()
}

fn find_unicode_strings(buf: &[u8]) -> Vec<(usize, String)> {
    lazy_static! {
        static ref re: Regex = Regex::new("([ -~]\x00){4,}").unwrap();
    }

    re.captures_iter(buf)
        .map(|cap| {
            // guaranteed to have at least one hit
            let mat = cap.get(0).unwrap();

            // this had better be ASCII, and therefore able to be decoded.
            let bytes = mat.as_bytes();
            let words: Vec<u16> = bytes
                .chunks_exact(2)
                .map(|w| u16::from(w[1]) << 8 | u16::from(w[0]))
                .collect();

            // danger: the unwrap here might feasibly fail
            let s = String::from_utf16(&words).unwrap();

            (mat.start(), s)
        })
        .collect()
}

fn find_strings(buf: &[u8]) -> Vec<(usize, String)> {
    let mut strings: Vec<(usize, String)> = vec![];
    let mut ascii = find_ascii_strings(buf);
    let mut unicode = find_unicode_strings(buf);

    strings.append(&mut ascii);
    strings.append(&mut unicode);

    strings.sort_by(|a, b| a.0.cmp(&b.0));

    strings
}

struct MapNode {
    range: Range<u64>,
    structure: Structure,
    children: Vec<MapNode>,
}

impl MapNode {
    fn new(range: Range<u64>, structure: Structure) -> MapNode {
        MapNode {
            range,
            structure,
            children: vec![],
        }
    }

    fn contains(&self, other: &MapNode) -> bool {
        self.range.start <= other.range.start
          && self.range.end >= other.range.end
    }

    fn insert(&mut self, other: MapNode) {
        if ! self.contains(&other) {
            panic!("this node does not contain the child")
        }

        match self.children.iter_mut().find(|child| child.contains(&other)) {
            Some(child) => child.insert(other),
            None => {
                self.children.push(other);
                self.children.sort_by(|a, b| cmp_ranges(&a.range, &b.range));
            }
        }
    }

    fn find_slack(&mut self) {
        let mut offset = self.range.start;
        let mut slacks: Vec<Range<u64>> = vec![];
        for child in self.children.iter() {
            if child.range.start > offset {
                slacks.push(Range {
                    start: offset,
                    end: child.range.start,
                });
                offset = child.range.end;
            } else {
                offset = child.range.end;
            }
        }
        for slack in slacks.iter() {
            self.insert(MapNode::new(slack.clone(), Structure::Slack));
        }
        for child in self.children.iter_mut() {
            child.find_slack();
        }
    }

    fn render(&self, buf: &[u8]) -> Result<Vec<String>, Error> {
        let mut ret: Vec<String> = vec![];

        // ref: https://www.fileformat.info/info/unicode/block/box_drawing/list.htm
        ret.push(format!("┌── {:#08x} {:?}", self.range.start, self.structure));

        match self.structure {
            Structure::IMAGE_SECTION_HEADER(_)
            | Structure::IMAGE_DOS_HEADER
            | Structure::Signature
            | Structure::IMAGE_FILE_HEADER
            | Structure::IMAGE_OPTIONAL_HEADER
            => {
                // render hexdump
                let region = &buf[self.range.start as usize..self.range.end as usize];
                for line in lancelot::util::hexdump(region,
                                                    self.range.start as usize).split("\n") {
                    if line != "" {
                        ret.push(format!("│   {}", line))
                    }
                }
            },
            Structure::Slack
            | Structure::Section(_)
            => {
                // render strings
                let region = &buf[self.range.start as usize..self.range.end as usize];
                for (offset, string) in find_strings(region).iter() {
                    ret.push(format!("│   {:#08x} string: {}", self.range.start + *offset as u64, string));
                }
            },
            _ => {
                // render children
                for (i, child) in self.children.iter().enumerate() {
                    for line in child.render(buf)?.iter() {
                        ret.push(format!("│  {}", line))
                    }
                    if i < self.children.len() - 1 {
                        ret.push(format!("│"));
                    }
                }
            }
        }

        ret.push(format!("└── {:#08x} ────────", self.range.end));

        Ok(ret)
    }
}

fn get_node(map: &Map, range: Range<u64>) -> MapNode {
    MapNode::new(range.clone(), map.locations[&range])
}

fn build_tree(map: &Map) -> Result<MapNode, Error> {
    let mut locations: Vec<Range<u64>> = map.locations.keys().cloned().collect();
    locations.sort_by(|a, b| cmp_ranges(a, b));
    locations.reverse();
    let mut root_node = get_node(map, locations.pop().unwrap());  // warning

    while !locations.is_empty() {
        root_node.insert(get_node(map, locations.pop().unwrap()));
    }

    root_node.find_slack();

    Ok(root_node)
}

struct Map {
    locations: HashMap<Range<u64>, Structure>,
}

fn compute_map(ws: &Workspace) -> Result<Map, Error> {
    let pe = match Object::parse(&ws.buf) {
        Ok(Object::PE(pe)) => pe,
        _ => return Err(MainError::InvalidFile.into()),
    };

    let mut locations: HashMap<Range<u64>, Structure> = HashMap::new();

    locations.insert(
        Range {
            start: 0,
            end: ws.buf.len() as u64,
        },
        Structure::File,
    );

    let sizeof_IMAGE_DOS_HEADER = 0x40;
    locations.insert(
        Range {
            start: 0,
            end: sizeof_IMAGE_DOS_HEADER,
        },
        Structure::IMAGE_DOS_HEADER,
    );

    let offset_IMAGE_NT_HEADERS = pe.header.dos_header.pe_pointer as u64;
    let sizeof_Signature: u64 = 0x4;
    let sizeof_IMAGE_FILE_HEADER: u64 = 0x14;
    locations.insert(
        Range {
            start: offset_IMAGE_NT_HEADERS,
            end: offset_IMAGE_NT_HEADERS
                + sizeof_Signature
                + sizeof_IMAGE_FILE_HEADER
                + (pe.header.coff_header.size_of_optional_header as u64),
        },
        Structure::IMAGE_NT_HEADERS,
    );

    locations.insert(
        Range {
            start: offset_IMAGE_NT_HEADERS,
            end: offset_IMAGE_NT_HEADERS + sizeof_Signature,
        },
        Structure::Signature,
    );

    let offset_IMAGE_FILE_HEADER = offset_IMAGE_NT_HEADERS + sizeof_Signature;
    locations.insert(
        Range {
            start: offset_IMAGE_FILE_HEADER,
            end: offset_IMAGE_FILE_HEADER + sizeof_IMAGE_FILE_HEADER,
        },
        Structure::IMAGE_FILE_HEADER,
    );

    let end_of_headers = if pe.header.coff_header.size_of_optional_header > 0 {
        let offset_IMAGE_OPTIONAL_HEADER = offset_IMAGE_FILE_HEADER + sizeof_IMAGE_FILE_HEADER;
        let end_of_headers = offset_IMAGE_OPTIONAL_HEADER
                    + (pe.header.coff_header.size_of_optional_header as u64);
        locations.insert(
            Range {
                start: offset_IMAGE_OPTIONAL_HEADER,
                end: end_of_headers,
            },
            Structure::IMAGE_OPTIONAL_HEADER,
        );
        locations.insert(
            Range {
                start: 0x0,
                end: offset_IMAGE_OPTIONAL_HEADER
                    + (pe.header.coff_header.size_of_optional_header as u64),
            },
            Structure::Header,
        );
        end_of_headers
    } else {
        let end_of_headers = offset_IMAGE_FILE_HEADER + sizeof_IMAGE_FILE_HEADER;
        locations.insert(
            Range {
                start: 0x0,
                end: end_of_headers,
            },
            Structure::Header,
        );
        end_of_headers
    };

    let mut offset_IMAGE_SECTION_HEADER = end_of_headers;
    let sizeof_IMAGE_SECTION_HEADER = 0x28;
    for i in 0..pe.header.coff_header.number_of_sections {
        locations.insert(
            Range {
                start: offset_IMAGE_SECTION_HEADER,
                end: offset_IMAGE_SECTION_HEADER + sizeof_IMAGE_SECTION_HEADER,
            },
            Structure::IMAGE_SECTION_HEADER(i)
        );

        let section = &pe.sections[i as usize];
        locations.insert(
            Range {
                start: section.pointer_to_raw_data as u64,
                end: (section.pointer_to_raw_data + section.size_of_raw_data) as u64,
            },
            Structure::Section(i),
        );

        offset_IMAGE_SECTION_HEADER += sizeof_IMAGE_SECTION_HEADER;
    }

    Ok(Map {
        locations
    })

}

fn render_map(map: &Map, buf: &[u8]) -> Result<(), Error> {
    let tree = build_tree(&map)?;
    for line in tree.render(buf)?.iter() {
        println!("{}", line);
    }

    Ok(())
}

pub fn run(args: &Config) -> Result<(), Error> {
    info!("filename: {:?}", args.filename);

    let ws = Workspace::from_file(&args.filename)?.load()?;
    let map = compute_map(&ws)?;
    render_map(&map, &ws.buf)?;

    Ok(())
}

fn main() {
    better_panic::install();

    let args = Config::from_args(env::args()).unwrap_or_else(|err| {
        eprintln!("error parsing arguments: {}", err);
        process::exit(1);
    });

    setup_logging(&args);

    if let Err(e) = run(&args) {
        error!("{:?}", e)
    }
}
<commit_msg>mapa: add directory parsing<commit_after>// TODO:
//   - data directories
//   - name sections
//   - list functions
//   - colors
//   - summarize as empty/hex/strings
//   - section entropy
//   - resource parsing
extern crate log;
extern crate lancelot;
#[macro_use] extern crate lazy_static;

use std::collections::HashMap;
use std::env;
use std::ops::Range;
use std::process;

use better_panic;
use failure::{Error, Fail};
use goblin::Object;
use log::{error, info, trace};
use regex::bytes::Regex;

use lancelot::util;
use lancelot::workspace::Workspace;

#[derive(Debug, Fail)]
pub enum MainError {
    #[fail(display = "foo")]
    Foo,
    #[fail(display = "Invalid PE file")]
    InvalidFile,
    #[fail(display = "Unmapped address")]
    UnmappedVA,
}

pub struct Config {
    pub filename: String,
}

impl Config {
    pub fn from_args(args: env::Args) -> Result<Config, &'static str> {
        let args: Vec<String> = args.collect();

        if args.len() < 2 {
            return Err("not enough arguments: provide `mapa.exe /path/to/input.exe`");
        }

        let filename = args[1].clone();
        trace!("config: parsed filename: {:?}", filename);

        Ok(Config { filename })
    }
}

pub fn setup_logging(_args: &Config) {
    simplelog::TermLogger::init(simplelog::LevelFilter::Info, simplelog::Config::default())
        .expect("failed to setup logging");
}

/*
    File
      Header,
        IMAGE_DOS_HEADER,
        IMAGE_NT_HEADERS,
          Signature
          IMAGE_FILE_HEADER,
          IMAGE_OPTIONAL_HEADER,
      IMAGE_SECTION_HEADER,
      Section(u32),
      Slack
*/

#[derive(Debug, Clone)]
enum Structure {
    /// the complete file
    File,
    /// the file headers.
    Header,
    IMAGE_DOS_HEADER,
    IMAGE_NT_HEADERS,
    Signature,
    IMAGE_FILE_HEADER,
    IMAGE_OPTIONAL_HEADER,
    IMAGE_SECTION_HEADER(u16, String),
    /// a section's content
    Section(u16, String),
    ImportTable,
    ExportTable,
    ResourceTable,
    ExceptionTable,
    CertificateTable,
    BaseRelocationTable,
    DebugData,
    TlsTable,
    LoadConfigTable,
    BoundImportTable,
    ImportAddressTable,
    DelayImportDescriptor,
    ClrRuntimeHeader,
    Slack,
    String(String),
}

impl std::fmt::Display for Structure {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Structure::File => write!(f, "file"),
            Structure::Header => write!(f, "headers"),
            Structure::IMAGE_DOS_HEADER => write!(f, "IMAGE_DOS_HEADER"),
            Structure::IMAGE_NT_HEADERS => write!(f, "IMAGE_NT_HEADERS"),
            Structure::Signature => write!(f, "signature"),
            Structure::IMAGE_FILE_HEADER => write!(f, "IMAGE_FILE_HEADER"),
            Structure::IMAGE_OPTIONAL_HEADER => write!(f, "IMAGE_OPTIONAL_HEADER"),
            Structure::IMAGE_SECTION_HEADER(_, name) => write!(f, "IMAGE_SECTION_HEADER {}", name),
            Structure::Section(_, name) => write!(f, "section {}", name),
            Structure::Slack => write!(f, "slack"),
            Structure::ImportTable => write!(f, "import table"),
            Structure::ExportTable=> write!(f, "export table"),
            Structure::ResourceTable => write!(f, "resource table"),
            Structure::ExceptionTable => write!(f, "exception table"),
            Structure::CertificateTable => write!(f, "certificate table"),
            Structure::BaseRelocationTable => write!(f, "base relocation table"),
            Structure::DebugData => write!(f, "debug data"),
            Structure::TlsTable => write!(f, "TLS table"),
            Structure::LoadConfigTable => write!(f, "load config table"),
            Structure::BoundImportTable => write!(f, "bound import table"),
            Structure::ImportAddressTable => write!(f, "import address table"),
            Structure::DelayImportDescriptor => write!(f, "delay import descriptor"),
            Structure::ClrRuntimeHeader => write!(f, "CLR runtime header"),
            Structure::String(s) => write!(f, "string: {}", s),
        }
    }
}

fn cmp_ranges<T: PartialOrd>(a: &Range<T>, b: &Range<T>) -> std::cmp::Ordering {
    if a.start < b.start {
        std::cmp::Ordering::Less
    } else if a.start > b.start {
        std::cmp::Ordering::Greater
    } else if a.end < b.end {
        std::cmp::Ordering::Greater
    } else if a.end > b.end {
        std::cmp::Ordering::Less
    } else {
        std::cmp::Ordering::Equal
    }
}

fn find_ascii_strings(buf: &[u8]) -> Vec<(Range<usize>, String)> {
    lazy_static! {
        static ref re: Regex = Regex::new("[ -~]{4,}").unwrap();
    }

    re.captures_iter(buf)
        .map(|cap| {
            // guaranteed to have at least one hit
            let mat = cap.get(0).unwrap();

            // this had better be ASCII, and therefore able to be decoded.
            let s = String::from_utf8(mat.as_bytes().to_vec()).unwrap();

            (Range {
                start: mat.start(),
                end: mat.end(),
            }, s)
        })
        .collect()
}

fn find_unicode_strings(buf: &[u8]) -> Vec<(Range<usize>, String)> {
    lazy_static! {
        static ref re: Regex = Regex::new("([ -~]\x00){4,}").unwrap();
    }

    re.captures_iter(buf)
        .map(|cap| {
            // guaranteed to have at least one hit
            let mat = cap.get(0).unwrap();

            // this had better be ASCII, and therefore able to be decoded.
            let bytes = mat.as_bytes();
            let words: Vec<u16> = bytes
                .chunks_exact(2)
                .map(|w| u16::from(w[1]) << 8 | u16::from(w[0]))
                .collect();

            // danger: the unwrap here might feasibly fail
            let s = String::from_utf16(&words).unwrap();

            (Range {
                start: mat.start(),
                end: mat.end(),
            }, s)
        })
        .collect()
}

fn find_strings(buf: &[u8]) -> Vec<(Range<usize>, String)> {
    let mut strings: Vec<(Range<usize>, String)> = vec![];
    let mut ascii = find_ascii_strings(buf);
    let mut unicode = find_unicode_strings(buf);

    strings.append(&mut ascii);
    strings.append(&mut unicode);

    strings.sort_by(|a, b| cmp_ranges(&a.0, &b.0));

    strings
}

struct MapNode {
    range: Range<u64>,
    structure: Structure,
    children: Vec<MapNode>,
}

impl MapNode {
    fn new(range: Range<u64>, structure: Structure) -> MapNode {
        MapNode {
            range,
            structure,
            children: vec![],
        }
    }

    fn contains(&self, other: &MapNode) -> bool {
        self.range.start <= other.range.start
          && self.range.end >= other.range.end
    }

    fn insert(&mut self, other: MapNode) {
        if ! self.contains(&other) {
            panic!("this node does not contain the child")
        }

        match self.children.iter_mut().find(|child| child.contains(&other)) {
            Some(child) => child.insert(other),
            None => {
                self.children.push(other);
                self.children.sort_by(|a, b| cmp_ranges(&a.range, &b.range));
            }
        }
    }

    fn find_slack(&mut self) {
        let mut offset = self.range.start;
        let mut slacks: Vec<Range<u64>> = vec![];
        for child in self.children.iter() {
            if child.range.start > offset {
                slacks.push(Range {
                    start: offset,
                    end: child.range.start,
                });
                offset = child.range.end;
            } else {
                offset = child.range.end;
            }
        }
        for slack in slacks.iter() {
            self.insert(MapNode::new(slack.clone(), Structure::Slack));
        }
        for child in self.children.iter_mut() {
            child.find_slack();
        }
    }

    fn render(&self, buf: &[u8]) -> Result<Vec<String>, Error> {
        let mut ret: Vec<String> = vec![];

        if let Structure::String(s) = &self.structure {
            ret.push(format!("    {:#08x} string \"{}\"", self.range.start, s));
        } else {
            // ref: https://www.fileformat.info/info/unicode/block/box_drawing/list.htm
            ret.push(format!("┌── {:#08x} {} ────────", self.range.start, self.structure));

            match &self.structure {
                Structure::IMAGE_SECTION_HEADER(_, _)
                | Structure::IMAGE_DOS_HEADER
                | Structure::Signature
                | Structure::IMAGE_FILE_HEADER
                | Structure::IMAGE_OPTIONAL_HEADER
                => {
                    // render hexdump
                    let region = &buf[self.range.start as usize..self.range.end as usize];
                    for line in lancelot::util::hexdump(region,
                                                        self.range.start as usize).split("\n") {
                        if line != "" {
                            ret.push(format!("│   {}", line))
                        }
                    }
                },
                _ => {
                    // render children
                    for (i, child) in self.children.iter().enumerate() {
                        for line in child.render(buf)?.iter() {
                            ret.push(format!("│  {}", line))
                        }
                        if i < self.children.len() - 1 {
                            match (&self.children[i].structure,  &self.children[i + 1].structure) {
                                (Structure::String(_), Structure::String(_)) => {},
                                _ => {ret.push(format!("│")) }
                            }
                        }
                    }
                }
            }

            ret.push(format!("└── {:#08x} ────────────────────────", self.range.end));
        }

        Ok(ret)
    }
}

fn get_node(map: &Map, range: Range<u64>) -> MapNode {
    MapNode::new(range.clone(), map.locations[&range].clone())
}

fn build_tree(map: &Map) -> Result<MapNode, Error> {
    let mut locations: Vec<Range<u64>> = map.locations.keys().cloned().collect();
    locations.sort_by(|a, b| cmp_ranges(a, b));
    locations.reverse();
    let mut root_node = get_node(map, locations.pop().unwrap());  // warning

    while !locations.is_empty() {
        root_node.insert(get_node(map, locations.pop().unwrap()));
    }

    //root_node.find_slack();

    Ok(root_node)
}

struct Map {
    locations: HashMap<Range<u64>, Structure>,
}

fn compute_map(ws: &Workspace) -> Result<Map, Error> {
    let pe = match Object::parse(&ws.buf) {
        Ok(Object::PE(pe)) => pe,
        _ => return Err(MainError::InvalidFile.into()),
    };

    let mut locations: HashMap<Range<u64>, Structure> = HashMap::new();

    locations.insert(
        Range {
            start: 0,
            end: ws.buf.len() as u64,
        },
        Structure::File,
    );

    let sizeof_IMAGE_DOS_HEADER = 0x40;
    locations.insert(
        Range {
            start: 0,
            end: sizeof_IMAGE_DOS_HEADER,
        },
        Structure::IMAGE_DOS_HEADER,
    );

    let offset_IMAGE_NT_HEADERS = pe.header.dos_header.pe_pointer as u64;
    let sizeof_Signature: u64 = 0x4;
    let sizeof_IMAGE_FILE_HEADER: u64 = 0x14;
    locations.insert(
        Range {
            start: offset_IMAGE_NT_HEADERS,
            end: offset_IMAGE_NT_HEADERS
                + sizeof_Signature
                + sizeof_IMAGE_FILE_HEADER
                + (pe.header.coff_header.size_of_optional_header as u64),
        },
        Structure::IMAGE_NT_HEADERS,
    );

    locations.insert(
        Range {
            start: offset_IMAGE_NT_HEADERS,
            end: offset_IMAGE_NT_HEADERS + sizeof_Signature,
        },
        Structure::Signature,
    );

    let offset_IMAGE_FILE_HEADER = offset_IMAGE_NT_HEADERS + sizeof_Signature;
    locations.insert(
        Range {
            start: offset_IMAGE_FILE_HEADER,
            end: offset_IMAGE_FILE_HEADER + sizeof_IMAGE_FILE_HEADER,
        },
        Structure::IMAGE_FILE_HEADER,
    );

    let end_of_headers = if pe.header.coff_header.size_of_optional_header > 0 {
        let offset_IMAGE_OPTIONAL_HEADER = offset_IMAGE_FILE_HEADER + sizeof_IMAGE_FILE_HEADER;
        let end_of_headers = offset_IMAGE_OPTIONAL_HEADER
                    + (pe.header.coff_header.size_of_optional_header as u64);
        locations.insert(
            Range {
                start: offset_IMAGE_OPTIONAL_HEADER,
                end: end_of_headers,
            },
            Structure::IMAGE_OPTIONAL_HEADER,
        );
        locations.insert(
            Range {
                start: 0x0,
                end: offset_IMAGE_OPTIONAL_HEADER
                    + (pe.header.coff_header.size_of_optional_header as u64),
            },
            Structure::Header,
        );
        end_of_headers
    } else {
        let end_of_headers = offset_IMAGE_FILE_HEADER + sizeof_IMAGE_FILE_HEADER;
        locations.insert(
            Range {
                start: 0x0,
                end: end_of_headers,
            },
            Structure::Header,
        );
        end_of_headers
    };

    let mut offset_IMAGE_SECTION_HEADER = end_of_headers;
    let sizeof_IMAGE_SECTION_HEADER = 0x28;
    for i in 0..pe.header.coff_header.number_of_sections {
        let section = &pe.sections[i as usize];
        locations.insert(
            Range {
                start: section.pointer_to_raw_data as u64,
                end: (section.pointer_to_raw_data + section.size_of_raw_data) as u64,
            },
            Structure::Section(i, section.name().unwrap_or("").to_string()),
        );

        locations.insert(
            Range {
                start: offset_IMAGE_SECTION_HEADER,
                end: offset_IMAGE_SECTION_HEADER + sizeof_IMAGE_SECTION_HEADER,
            },
            Structure::IMAGE_SECTION_HEADER(i, section.name().unwrap_or("").to_string()),
        );

        offset_IMAGE_SECTION_HEADER += sizeof_IMAGE_SECTION_HEADER;
    }

    if let Some(opt) = pe.header.optional_header {
        let mut directories: Vec<(Box<dyn Fn() -> Option<goblin::pe::data_directories::DataDirectory>>, Structure)> = vec![];
        directories.push((Box::new(|| *opt.data_directories.get_export_table()), Structure::ExportTable));
        directories.push((Box::new(|| *opt.data_directories.get_import_table()), Structure::ImportTable));
        directories.push((Box::new(|| *opt.data_directories.get_resource_table()), Structure::ResourceTable));
        directories.push((Box::new(|| *opt.data_directories.get_exception_table()), Structure::ExceptionTable));
        directories.push((Box::new(|| *opt.data_directories.get_certificate_table()), Structure::CertificateTable));
        directories.push((Box::new(|| *opt.data_directories.get_base_relocation_table()), Structure::BaseRelocationTable));
        directories.push((Box::new(|| *opt.data_directories.get_debug_table()), Structure::DebugData));
        directories.push((Box::new(|| *opt.data_directories.get_tls_table()), Structure::TlsTable));
        directories.push((Box::new(|| *opt.data_directories.get_load_config_table()), Structure::LoadConfigTable));
        directories.push((Box::new(|| *opt.data_directories.get_bound_import_table()), Structure::BoundImportTable));
        directories.push((Box::new(|| *opt.data_directories.get_import_address_table()), Structure::ImportAddressTable));
        directories.push((Box::new(|| *opt.data_directories.get_delay_import_descriptor()), Structure::DelayImportDescriptor));
        directories.push((Box::new(|| *opt.data_directories.get_clr_runtime_header()), Structure::ClrRuntimeHeader));

        for (f, structure) in directories.iter() {
            if let Some(dir) = f() {
                if let Ok(pfile) = va2pfile(&pe, dir.virtual_address) {
                    println!("{:#x} {:#x} {}", pfile, pfile + dir.size, structure);
                    locations.insert(
                        Range {
                            start: pfile as u64,
                            end: (pfile + dir.size) as u64,
                        },
                        structure.clone(),
                    );
                }
            }
        }
    }

    for (loc, string) in find_strings(&ws.buf).iter() {
        locations.insert(Range {
            start: loc.start as u64,
            end: loc.end as u64,
        }, Structure::String(string.clone()));
    }

    Ok(Map {
        locations
    })
}

fn va2pfile(pe: &goblin::pe::PE, va: u32) -> Result<u32, Error> {
    for section in pe.sections.iter() {
        if va >= section.virtual_address && va < section.virtual_address + section.virtual_size {
            let offset = va - section.virtual_address;
            return Ok(section.pointer_to_raw_data + offset);
        }
    }
    return Err(MainError::UnmappedVA.into())
}

fn render_map(map: &Map, buf: &[u8]) -> Result<(), Error> {
    let tree = build_tree(&map)?;
    for line in tree.render(buf)?.iter() {
        println!("{}", line);
    }

    Ok(())
}

pub fn run(args: &Config) -> Result<(), Error> {
    info!("filename: {:?}", args.filename);

    let ws = Workspace::from_file(&args.filename)?.load()?;
    let map = compute_map(&ws)?;
    render_map(&map, &ws.buf)?;

    Ok(())
}

fn main() {
    better_panic::install();

    let args = Config::from_args(env::args()).unwrap_or_else(|err| {
        eprintln!("error parsing arguments: {}", err);
        process::exit(1);
    });

    setup_logging(&args);

    if let Err(e) = run(&args) {
        error!("{:?}", e)
    }
}
<|endoftext|>


<commit_before><commit_msg>Add error type implementation<commit_after>use std::error::Error;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TagErrorKind {
}

fn tag_error_type_as_str(e: &TagErrorKind) -> &'static str {
    match e {
        _ => "",
    }
}

impl Display for TagErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", tag_error_type_as_str(self)));
        Ok(())
    }

}

#[derive(Debug)]
pub struct TagError {
    kind: TagErrorKind,
    cause: Option<Box<Error>>,
}

impl TagError {

    pub fn new(errtype: TagErrorKind, cause: Option<Box<Error>>) -> TagError {
        TagError {
            kind: errtype,
            cause: cause,
        }
    }

}

impl Display for TagError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", tag_error_type_as_str(&self.kind.clone())));
        Ok(())
    }

}

impl Error for TagError {

    fn description(&self) -> &str {
        tag_error_type_as_str(&self.kind.clone())
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

<|endoftext|>


<commit_before>use clock;
use cpu;
use cpu::caches;
use cpu::coproc;
use cpu::irq;
use cpu::regs::{GpRegs, Psr};
use mem;

use std::collections::HashSet;

#[derive(Copy, Clone, Debug)]
pub enum Mode {
    Usr = 0b10000,
    Fiq = 0b10001,
    Irq = 0b10010,
    Svc = 0b10011,
    Abt = 0b10111,
    Und = 0b11011,
    Sys = 0b11111
}

impl Mode {
    pub fn from_num(val: u32) -> Mode {
        match val {
            n if n == Mode::Usr as u32 => Mode::Usr,
            n if n == Mode::Fiq as u32 => Mode::Fiq,
            n if n == Mode::Irq as u32 => Mode::Irq,
            n if n == Mode::Svc as u32 => Mode::Svc,
            n if n == Mode::Abt as u32 => Mode::Abt,
            n if n == Mode::Und as u32 => Mode::Und,
            n if n == Mode::Sys as u32 => Mode::Sys,
            _ => unreachable!()
        }
    }
}

pub struct Cpu {
    pub regs: GpRegs,
    pub cpsr: Psr,
    pub spsr_fiq: Psr,
    pub spsr_irq: Psr,
    pub spsr_svc: Psr,
    pub spsr_abt: Psr,
    pub spsr_und: Psr,

    coproc_syscnt: coproc::SysControl,
    pub mpu: caches::Mpu,

    irq_line: irq::IrqLine,
    cycles: usize,
    sys_clk: clock::SysClock,

    pub breakpoints: HashSet<u32> // addr, is_triggered
}

#[derive(Clone)]
pub enum BreakReason {
    LimitReached,
    Breakpoint,
    Trapped,
    WFI
}

const PAUSE_CYCLES: usize = 128;

impl Cpu {
    pub fn new(memory: mem::MemController, irq_line: irq::IrqLine, clk: clock::SysClock) -> Cpu {
        Cpu {
            regs: GpRegs::new(Mode::Svc),
            cpsr: Psr::new(0),
            spsr_fiq: Psr::new(0),
            spsr_irq: Psr::new(0),
            spsr_svc: Psr::new(0),
            spsr_abt: Psr::new(0),
            spsr_und: Psr::new(0),

            coproc_syscnt: coproc::SysControl::new(),
            mpu: caches::Mpu::new(memory),

            irq_line: irq_line,
            cycles: PAUSE_CYCLES,
            sys_clk: clk,

            breakpoints: HashSet::new()
        }
    }

    pub fn reset(&mut self, entry: u32) {
        self.regs.swap(Mode::Svc);
        bf!((self.cpsr).mode = Mode::Svc as u32);
        bf!((self.cpsr).thumb_bit = 0b0);
        bf!((self.cpsr).disable_fiq_bit = 0b1);
        bf!((self.cpsr).disable_irq_bit = 0b1);

        self.regs[15] = entry + self.get_pc_offset();
    }

    pub fn get_pc_offset(&self) -> u32 {
        8 >> bf!((self.cpsr).thumb_bit)
        }

    pub fn get_coprocessor(&mut self, cp_index: usize) -> &mut coproc::Coprocessor {
        match cp_index {
            15 => &mut self.coproc_syscnt,
            _ => panic!("Tried to access unknown CP{}", cp_index),
        }
    }

    pub fn get_current_spsr(&mut self) -> &mut Psr {
        match Mode::from_num(bf!((self.cpsr).mode)) {
            Mode::Fiq => &mut self.spsr_fiq,
            Mode::Irq => &mut self.spsr_irq,
            Mode::Svc => &mut self.spsr_svc,
            Mode::Abt => &mut self.spsr_abt,
            Mode::Und => &mut self.spsr_und,
            _ => panic!("Attempted to access non-existent SPSR!"),
        }
    }

    pub fn spsr_make_current(&mut self) {
        self.cpsr = self.get_current_spsr().clone();
        self.regs.swap(cpu::Mode::from_num(bf!((self.cpsr).mode)));
    }

    #[inline(always)]
    pub fn branch(&mut self, addr: u32) {
        self.regs[15] = addr + self.get_pc_offset();
        // TODO: Invalidate pipeline once/if we have one
    }

    pub fn run(&mut self, num_instrs: u32) -> BreakReason {
        let mut cycles = self.cycles;
        let mut irq_known_pending = false;

        for _ in 0..num_instrs {
            let addr = self.regs[15] - self.get_pc_offset();

            cycles -= 1;
            // Amortize the cost of checking for IRQs, updating clock
            if cycles == 0 {
                self.sys_clk.increment(PAUSE_CYCLES * 8); // Probably speeds up time but w/e
                irq_known_pending = self.irq_line.is_high();
                cycles = PAUSE_CYCLES;
            }
            if irq_known_pending && bf!((self.cpsr).disable_irq_bit) == 0 && self.irq_line.is_high() {
                trace!("ARM9 IRQ triggered!");
                self.enter_exception(addr+4, Mode::Irq);
                irq_known_pending = false;
                continue
            }

            if self.find_toggle_breakpoint(addr) {
                return BreakReason::Breakpoint;
            }

            if bf!((self.cpsr).thumb_bit) == 0 {
                assert_eq!(addr & 0b11, 0);
                let instr = self.mpu.imem_read::<u32>(addr);
                let inst_fn = cpu::arm::decode(instr);
                cpu::arm::interpret(self, inst_fn, instr);
            } else {
                assert_eq!(addr & 0b1, 0);
                let instr = self.mpu.imem_read::<u16>(addr);
                let inst_fn = cpu::thumb::decode(instr);
                cpu::thumb::interpret(self, inst_fn, instr);
            }
        }

        self.cycles = cycles;
        BreakReason::LimitReached
    }

    pub fn enter_exception(&mut self, return_loc: u32, mode: Mode) {
        let r14_exc = return_loc;
        let spsr_exc = self.cpsr;

        self.regs.swap(mode);
        bf!((self.cpsr).mode = mode as u32);

        self.regs[14] = r14_exc;
        *self.get_current_spsr() = spsr_exc;
        bf!((self.cpsr).thumb_bit = 0);
        bf!((self.cpsr).disable_irq_bit = 1);

        // These vectors look like 0x080000XX because that's where the bootrom redirects them
        let vector_addr = match mode {
            Mode::Irq => 0x08000000,
            Mode::Fiq => unimplemented!(),
            Mode::Svc => 0x08000010,
            Mode::Und => 0x08000018,
            Mode::Abt => 0x08000028,
            Mode::Sys | Mode::Usr => panic!("No exception associated with {:?}", mode)
        };
        self.branch(vector_addr);
    }

    pub fn find_toggle_breakpoint(&mut self, addr: u32) -> bool {
        !self.breakpoints.is_empty() && self.breakpoints.remove(&addr)
    }
}
<commit_msg>cpu: Cache thumb/arm decoder results<commit_after>use clock;
use cpu;
use cpu::caches;
use cpu::coproc;
use cpu::irq;
use cpu::regs::{GpRegs, Psr};
use mem;

use utils::cache::TinyCache;

use std::collections::HashSet;

#[derive(Copy, Clone, Debug)]
pub enum Mode {
    Usr = 0b10000,
    Fiq = 0b10001,
    Irq = 0b10010,
    Svc = 0b10011,
    Abt = 0b10111,
    Und = 0b11011,
    Sys = 0b11111
}

impl Mode {
    pub fn from_num(val: u32) -> Mode {
        match val {
            n if n == Mode::Usr as u32 => Mode::Usr,
            n if n == Mode::Fiq as u32 => Mode::Fiq,
            n if n == Mode::Irq as u32 => Mode::Irq,
            n if n == Mode::Svc as u32 => Mode::Svc,
            n if n == Mode::Abt as u32 => Mode::Abt,
            n if n == Mode::Und as u32 => Mode::Und,
            n if n == Mode::Sys as u32 => Mode::Sys,
            _ => unreachable!()
        }
    }
}

pub struct Cpu {
    pub regs: GpRegs,
    pub cpsr: Psr,
    pub spsr_fiq: Psr,
    pub spsr_irq: Psr,
    pub spsr_svc: Psr,
    pub spsr_abt: Psr,
    pub spsr_und: Psr,

    coproc_syscnt: coproc::SysControl,
    pub mpu: caches::Mpu,

    irq_line: irq::IrqLine,
    cycles: usize,
    sys_clk: clock::SysClock,

    thumb_decode_cache: TinyCache<cpu::thumb::InstFn, ()>,
    arm_decode_cache: TinyCache<cpu::arm::InstFn, ()>,

    pub breakpoints: HashSet<u32> // addr, is_triggered
}

#[derive(Clone)]
pub enum BreakReason {
    LimitReached,
    Breakpoint,
    Trapped,
    WFI
}

const PAUSE_CYCLES: usize = 128;

impl Cpu {
    pub fn new(memory: mem::MemController, irq_line: irq::IrqLine, clk: clock::SysClock) -> Cpu {
        Cpu {
            regs: GpRegs::new(Mode::Svc),
            cpsr: Psr::new(0),
            spsr_fiq: Psr::new(0),
            spsr_irq: Psr::new(0),
            spsr_svc: Psr::new(0),
            spsr_abt: Psr::new(0),
            spsr_und: Psr::new(0),

            coproc_syscnt: coproc::SysControl::new(),
            mpu: caches::Mpu::new(memory),

            irq_line: irq_line,
            cycles: PAUSE_CYCLES,
            sys_clk: clk,

            thumb_decode_cache: TinyCache::new(
                |_, k| cpu::thumb::decode(k as u16), |_, _, _| {}
            ),
            arm_decode_cache: TinyCache::new(
                |_, k| cpu::arm::decode(k), |_, _, _| {}
            ),

            breakpoints: HashSet::new()
        }
    }

    pub fn reset(&mut self, entry: u32) {
        self.regs.swap(Mode::Svc);
        bf!((self.cpsr).mode = Mode::Svc as u32);
        bf!((self.cpsr).thumb_bit = 0b0);
        bf!((self.cpsr).disable_fiq_bit = 0b1);
        bf!((self.cpsr).disable_irq_bit = 0b1);

        self.regs[15] = entry + self.get_pc_offset();
    }

    pub fn get_pc_offset(&self) -> u32 {
        8 >> bf!((self.cpsr).thumb_bit)
        }

    pub fn get_coprocessor(&mut self, cp_index: usize) -> &mut coproc::Coprocessor {
        match cp_index {
            15 => &mut self.coproc_syscnt,
            _ => panic!("Tried to access unknown CP{}", cp_index),
        }
    }

    pub fn get_current_spsr(&mut self) -> &mut Psr {
        match Mode::from_num(bf!((self.cpsr).mode)) {
            Mode::Fiq => &mut self.spsr_fiq,
            Mode::Irq => &mut self.spsr_irq,
            Mode::Svc => &mut self.spsr_svc,
            Mode::Abt => &mut self.spsr_abt,
            Mode::Und => &mut self.spsr_und,
            _ => panic!("Attempted to access non-existent SPSR!"),
        }
    }

    pub fn spsr_make_current(&mut self) {
        self.cpsr = self.get_current_spsr().clone();
        self.regs.swap(cpu::Mode::from_num(bf!((self.cpsr).mode)));
    }

    #[inline(always)]
    pub fn branch(&mut self, addr: u32) {
        self.regs[15] = addr + self.get_pc_offset();
        // TODO: Invalidate pipeline once/if we have one
    }

    pub fn run(&mut self, num_instrs: u32) -> BreakReason {
        let mut cycles = self.cycles;
        let mut irq_known_pending = false;

        for _ in 0..num_instrs {
            let addr = self.regs[15] - self.get_pc_offset();

            cycles -= 1;
            // Amortize the cost of checking for IRQs, updating clock
            if cycles == 0 {
                self.sys_clk.increment(PAUSE_CYCLES * 8); // Probably speeds up time but w/e
                irq_known_pending = self.irq_line.is_high();
                cycles = PAUSE_CYCLES;
            }
            if irq_known_pending && bf!((self.cpsr).disable_irq_bit) == 0 && self.irq_line.is_high() {
                trace!("ARM9 IRQ triggered!");
                self.enter_exception(addr+4, Mode::Irq);
                irq_known_pending = false;
                continue
            }

            if self.find_toggle_breakpoint(addr) {
                return BreakReason::Breakpoint;
            }

            if bf!((self.cpsr).thumb_bit) == 0 {
                assert_eq!(addr & 0b11, 0);
                let instr = self.mpu.imem_read::<u32>(addr);
                let inst_fn = *self.arm_decode_cache.get_or(instr, &mut ());
                cpu::arm::interpret(self, inst_fn, instr);
            } else {
                assert_eq!(addr & 0b1, 0);
                let instr = self.mpu.imem_read::<u16>(addr);
                let inst_fn = *self.thumb_decode_cache.get_or(instr as u32, &mut ());
                cpu::thumb::interpret(self, inst_fn, instr);
            }
        }

        self.cycles = cycles;
        BreakReason::LimitReached
    }

    pub fn enter_exception(&mut self, return_loc: u32, mode: Mode) {
        let r14_exc = return_loc;
        let spsr_exc = self.cpsr;

        self.regs.swap(mode);
        bf!((self.cpsr).mode = mode as u32);

        self.regs[14] = r14_exc;
        *self.get_current_spsr() = spsr_exc;
        bf!((self.cpsr).thumb_bit = 0);
        bf!((self.cpsr).disable_irq_bit = 1);

        // These vectors look like 0x080000XX because that's where the bootrom redirects them
        let vector_addr = match mode {
            Mode::Irq => 0x08000000,
            Mode::Fiq => unimplemented!(),
            Mode::Svc => 0x08000010,
            Mode::Und => 0x08000018,
            Mode::Abt => 0x08000028,
            Mode::Sys | Mode::Usr => panic!("No exception associated with {:?}", mode)
        };
        self.branch(vector_addr);
    }

    pub fn find_toggle_breakpoint(&mut self, addr: u32) -> bool {
        !self.breakpoints.is_empty() && self.breakpoints.remove(&addr)
    }
}
<|endoftext|>


<commit_before>use std::os::raw::c_void;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};

#[cfg(feature = "native_lib")]
use wayland_sys::server::*;

pub(crate) struct ClientInternal {
    alive: AtomicBool,
    user_data: AtomicPtr<()>,
    destructor: AtomicPtr<()>,
}

impl ClientInternal {
    fn new() -> ClientInternal {
        ClientInternal {
            alive: AtomicBool::new(true),
            user_data: AtomicPtr::new(::std::ptr::null_mut()),
            destructor: AtomicPtr::new(::std::ptr::null_mut()),
        }
    }
}

/// A handle to a client connected to your server
///
/// There can be several handles referring to the same client
pub struct Client {
    internal: Arc<ClientInternal>,
    #[cfg(feature = "native_lib")]
    ptr: *mut wl_client,
}

impl Client {
    #[cfg(feature = "native_lib")]
    /// Create a client from a `wayland-server.so` pointer
    pub unsafe fn from_ptr(ptr: *mut wl_client) -> Client {
        // check if we are already registered
        let listener = ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_client_get_destroy_listener,
            ptr,
            client_destroy
        );
        if listener.is_null() {
            // need to init this client
            let listener = signal::rust_listener_create(client_destroy);
            let internal = Arc::new(ClientInternal::new());
            signal::rust_listener_set_user_data(
                listener,
                Box::into_raw(Box::new(internal.clone())) as *mut c_void,
            );
            ffi_dispatch!(
                WAYLAND_SERVER_HANDLE,
                wl_client_add_destroy_listener,
                ptr,
                listener
            );
            Client {
                internal: internal,
                ptr: ptr,
            }
        } else {
            // client already initialized
            let internal = signal::rust_listener_get_user_data(listener) as *mut Arc<ClientInternal>;
            Client {
                internal: (*internal).clone(),
                ptr: ptr,
            }
        }
    }

    #[cfg(feature = "native_lib")]
    /// Retrieve a pointer to the underlying `wl_client` of `wayland-server.so`
    pub fn c_ptr(&self) -> *mut wl_client {
        self.ptr
    }

    /// Check whether this client is still connected to the server
    pub fn alive(&self) -> bool {
        self.internal.alive.load(Ordering::Acquire)
    }

    /// Flush the pending events to this client
    pub fn flush(&self) {
        if !self.alive() {
            return;
        }
        unsafe {
            ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_client_flush, self.ptr);
        }
    }

    /// Associate an arbitrary payload to this client
    ///
    /// The pointer you associate here can be retrieved from any
    /// other handle to the same client.
    ///
    /// Setting or getting user data is done as an atomic operation.
    /// You are responsible for the correct initialization of this
    /// pointer, synchronisation of access, and destruction of the
    /// contents at the appropriate time.
    pub fn set_user_data(&self, data: *mut ()) {
        self.internal.user_data.store(data, Ordering::Release);
    }

    /// Retrieve the arbitrary payload associated to this client
    ///
    /// See `set_user_data` for explanations.
    pub fn get_user_data(&self) -> *mut () {
        self.internal.user_data.load(Ordering::Acquire)
    }

    /// Set a destructor for this client
    ///
    /// the provided function will be called when the client disconnects
    /// or is killed. It's argument is what you would get from calling
    /// `get_user_data`.
    pub fn set_destructor(&self, destructor: fn(*mut ())) {
        self.internal
            .destructor
            .store(destructor as *const () as *mut (), Ordering::Release);
    }
}

unsafe extern "C" fn client_destroy(listener: *mut wl_listener, _data: *mut c_void) {
    let internal = Box::from_raw(signal::rust_listener_get_user_data(listener) as *mut Arc<ClientInternal>);
    signal::rust_listener_set_user_data(listener, ptr::null_mut());
    // Store that we are dead
    internal.alive.store(false, Ordering::Release);
    // TODO: call the user callback
    let destructor = internal.destructor.load(Ordering::Acquire);
    if !destructor.is_null() {
        let destructor_func: fn(*mut ()) = ::std::mem::transmute(destructor);
        destructor_func(internal.user_data.load(Ordering::Acquire));
    }
    signal::rust_listener_destroy(listener);
}
<commit_msg>server: Client::equals(..)<commit_after>use std::os::raw::c_void;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};

#[cfg(feature = "native_lib")]
use wayland_sys::server::*;

pub(crate) struct ClientInternal {
    alive: AtomicBool,
    user_data: AtomicPtr<()>,
    destructor: AtomicPtr<()>,
}

impl ClientInternal {
    fn new() -> ClientInternal {
        ClientInternal {
            alive: AtomicBool::new(true),
            user_data: AtomicPtr::new(::std::ptr::null_mut()),
            destructor: AtomicPtr::new(::std::ptr::null_mut()),
        }
    }
}

/// A handle to a client connected to your server
///
/// There can be several handles referring to the same client
pub struct Client {
    internal: Arc<ClientInternal>,
    #[cfg(feature = "native_lib")]
    ptr: *mut wl_client,
}

impl Client {
    #[cfg(feature = "native_lib")]
    /// Create a client from a `wayland-server.so` pointer
    pub unsafe fn from_ptr(ptr: *mut wl_client) -> Client {
        // check if we are already registered
        let listener = ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_client_get_destroy_listener,
            ptr,
            client_destroy
        );
        if listener.is_null() {
            // need to init this client
            let listener = signal::rust_listener_create(client_destroy);
            let internal = Arc::new(ClientInternal::new());
            signal::rust_listener_set_user_data(
                listener,
                Box::into_raw(Box::new(internal.clone())) as *mut c_void,
            );
            ffi_dispatch!(
                WAYLAND_SERVER_HANDLE,
                wl_client_add_destroy_listener,
                ptr,
                listener
            );
            Client {
                internal: internal,
                ptr: ptr,
            }
        } else {
            // client already initialized
            let internal = signal::rust_listener_get_user_data(listener) as *mut Arc<ClientInternal>;
            Client {
                internal: (*internal).clone(),
                ptr: ptr,
            }
        }
    }

    #[cfg(feature = "native_lib")]
    /// Retrieve a pointer to the underlying `wl_client` of `wayland-server.so`
    pub fn c_ptr(&self) -> *mut wl_client {
        self.ptr
    }

    /// Check whether this client is still connected to the server
    pub fn alive(&self) -> bool {
        self.internal.alive.load(Ordering::Acquire)
    }

    /// Check whether this client handle refers to the same client as
    /// an other
    pub fn equals(&self, other: &Client) -> bool {
        Arc::ptr_eq(&self.internal, &other.internal)
    }

    /// Flush the pending events to this client
    pub fn flush(&self) {
        if !self.alive() {
            return;
        }
        unsafe {
            ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_client_flush, self.ptr);
        }
    }

    /// Associate an arbitrary payload to this client
    ///
    /// The pointer you associate here can be retrieved from any
    /// other handle to the same client.
    ///
    /// Setting or getting user data is done as an atomic operation.
    /// You are responsible for the correct initialization of this
    /// pointer, synchronisation of access, and destruction of the
    /// contents at the appropriate time.
    pub fn set_user_data(&self, data: *mut ()) {
        self.internal.user_data.store(data, Ordering::Release);
    }

    /// Retrieve the arbitrary payload associated to this client
    ///
    /// See `set_user_data` for explanations.
    pub fn get_user_data(&self) -> *mut () {
        self.internal.user_data.load(Ordering::Acquire)
    }

    /// Set a destructor for this client
    ///
    /// the provided function will be called when the client disconnects
    /// or is killed. It's argument is what you would get from calling
    /// `get_user_data`.
    pub fn set_destructor(&self, destructor: fn(*mut ())) {
        self.internal
            .destructor
            .store(destructor as *const () as *mut (), Ordering::Release);
    }
}

unsafe extern "C" fn client_destroy(listener: *mut wl_listener, _data: *mut c_void) {
    let internal = Box::from_raw(signal::rust_listener_get_user_data(listener) as *mut Arc<ClientInternal>);
    signal::rust_listener_set_user_data(listener, ptr::null_mut());
    // Store that we are dead
    internal.alive.store(false, Ordering::Release);
    // TODO: call the user callback
    let destructor = internal.destructor.load(Ordering::Acquire);
    if !destructor.is_null() {
        let destructor_func: fn(*mut ()) = ::std::mem::transmute(destructor);
        destructor_func(internal.user_data.load(Ordering::Acquire));
    }
    signal::rust_listener_destroy(listener);
}
<|endoftext|>


<commit_before>mod meta_item_ext;
mod arg_ext;
mod parser_ext;
mod ident_ext;
mod span_ext;

pub use self::arg_ext::ArgExt;
pub use self::meta_item_ext::MetaItemExt;
pub use self::parser_ext::ParserExt;
pub use self::ident_ext::IdentExt;
pub use self::span_ext::SpanExt;

use syntax::parse::token::Token;
use syntax::tokenstream::TokenTree;
use syntax::ast::{Item, Expr};
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::codemap::{spanned, Span, Spanned, DUMMY_SP};
use syntax::ext::quote::rt::ToTokens;
use syntax::print::pprust::item_to_string;
use syntax::ptr::P;

#[inline]
pub fn span<T>(t: T, span: Span) -> Spanned<T> {
    spanned(span.lo, span.hi, t)
}

#[inline]
pub fn sep_by_tok<T>(ecx: &ExtCtxt, things: &[T], token: Token) -> Vec<TokenTree>
    where T: ToTokens
{
    let mut output: Vec<TokenTree> = vec![];
    for (i, thing) in things.iter().enumerate() {
        output.extend(thing.to_tokens(ecx));
        if i < things.len() - 1 {
            output.push(TokenTree::Token(DUMMY_SP, token.clone()));
        }
    }

    output
}

#[inline]
pub fn option_as_expr<T: ToTokens>(ecx: &ExtCtxt, opt: &Option<T>) -> P<Expr> {
    match *opt {
        Some(ref item) => quote_expr!(ecx, Some($item)),
        None => quote_expr!(ecx, None),
    }
}

#[inline]
pub fn emit_item(push: &mut FnMut(Annotatable), item: P<Item>) {
    debug!("Emitting item: {}", item_to_string(&item));
    push(Annotatable::Item(item));
}

#[macro_export]
macro_rules! quote_enum {
    ($ecx:expr, $var:expr => $(::$root:ident)+
     { $($variant:ident),+ ; $($extra:pat => $result:expr),* }) => ({
        use syntax::codemap::DUMMY_SP;
        use $(::$root)+::*;
        let root_idents = vec![$(str_to_ident(stringify!($root))),+];
        match $var {
            $($variant => {
                let variant = str_to_ident(stringify!($variant));
                let mut idents = root_idents.clone();
                idents.push(variant);
                $ecx.path_global(DUMMY_SP, idents)
            })+
            $($extra => $result)*
        }
    })
}

<commit_msg>Add missing comma to quote_enum macro.<commit_after>mod meta_item_ext;
mod arg_ext;
mod parser_ext;
mod ident_ext;
mod span_ext;

pub use self::arg_ext::ArgExt;
pub use self::meta_item_ext::MetaItemExt;
pub use self::parser_ext::ParserExt;
pub use self::ident_ext::IdentExt;
pub use self::span_ext::SpanExt;

use syntax::parse::token::Token;
use syntax::tokenstream::TokenTree;
use syntax::ast::{Item, Expr};
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::codemap::{spanned, Span, Spanned, DUMMY_SP};
use syntax::ext::quote::rt::ToTokens;
use syntax::print::pprust::item_to_string;
use syntax::ptr::P;

#[inline]
pub fn span<T>(t: T, span: Span) -> Spanned<T> {
    spanned(span.lo, span.hi, t)
}

#[inline]
pub fn sep_by_tok<T>(ecx: &ExtCtxt, things: &[T], token: Token) -> Vec<TokenTree>
    where T: ToTokens
{
    let mut output: Vec<TokenTree> = vec![];
    for (i, thing) in things.iter().enumerate() {
        output.extend(thing.to_tokens(ecx));
        if i < things.len() - 1 {
            output.push(TokenTree::Token(DUMMY_SP, token.clone()));
        }
    }

    output
}

#[inline]
pub fn option_as_expr<T: ToTokens>(ecx: &ExtCtxt, opt: &Option<T>) -> P<Expr> {
    match *opt {
        Some(ref item) => quote_expr!(ecx, Some($item)),
        None => quote_expr!(ecx, None),
    }
}

#[inline]
pub fn emit_item(push: &mut FnMut(Annotatable), item: P<Item>) {
    debug!("Emitting item: {}", item_to_string(&item));
    push(Annotatable::Item(item));
}

#[macro_export]
macro_rules! quote_enum {
    ($ecx:expr, $var:expr => $(::$root:ident)+
     { $($variant:ident),+ ; $($extra:pat => $result:expr),* }) => ({
        use syntax::codemap::DUMMY_SP;
        use $(::$root)+::*;
        let root_idents = vec![$(str_to_ident(stringify!($root))),+];
        match $var {
            $($variant => {
                let variant = str_to_ident(stringify!($variant));
                let mut idents = root_idents.clone();
                idents.push(variant);
                $ecx.path_global(DUMMY_SP, idents)
            })+
            $($extra => $result),*
        }
    })
}

<|endoftext|>


<commit_before>use lopdf::Document;
use lopdf::Object;
use log::info;

#[macro_use]
extern crate clap;
use clap::{App, Arg, SubCommand};
use std::str::FromStr;

fn main() {
	env_logger::init();

	let app = App::new("PDF utility program using lopdf library")
		.version(crate_version!())
		.author(crate_authors!())
		.arg(Arg::with_name("input").short("i").long("input").value_name("input file").takes_value(true).global(true))
		.arg(Arg::with_name("output").short("o").long("output").value_name("output file").takes_value(true).global(true))
		.subcommand(
			SubCommand::with_name("process").about("Process PDF document with specified operations").arg(
				Arg::with_name("operations")
					.value_name("operations")
					.help("e.g. prune_objects delete_zero_length_streams renumber_objects")
					.takes_value(true)
					.multiple(true),
			),
		)
		.subcommand(SubCommand::with_name("compress").about("Compress PDF document"))
		.subcommand(SubCommand::with_name("decompress").about("Decompress PDF document"))
		.subcommand(
			SubCommand::with_name("delete_pages")
				.about("Delete pages")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_pages")
				.about("Extract pages")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(SubCommand::with_name("prune_objects").about("Prune unused objects"))
		.subcommand(
			SubCommand::with_name("delete_objects")
				.about("Delete objects")
				.arg(Arg::with_name("ids").value_name("object ids").help("e.g. \"1 0,2 1,35,36\"").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_text")
				.about("Extract text")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("replace_text")
				.about("Replace text")
				.arg(Arg::with_name("text").value_name("page_number:old_text=>new_text").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_stream")
				.about("Extract stream content")
				.arg(Arg::with_name("ids").value_name("object ids").help("e.g. \"1 0,2 1,35,36\"").takes_value(true)),
		)
		.subcommand(SubCommand::with_name("print_streams").about("Print streams"))
		.subcommand(SubCommand::with_name("renumber_objects").about("Renumber objects"))
		.subcommand(SubCommand::with_name("delete_zero_length_streams").about("Delete zero length stream objects"))
		.get_matches();

	if let (cmd, Some(args)) = app.subcommand() {
		if let Some(input) = args.value_of("input") {
			info!("Open {}", input);
			let mut doc = Document::load(input).unwrap();
			//info!("{:?}", doc.get_pages());

			info!("Do {}", cmd);
			match cmd {
				"process" => {
					if let Some(operations) = args.values_of("operations") {
						for operation in operations {
							info!("Do {}", operation);
							apply_operation(&mut doc, operation);
						}
					}
				}
				"extract_pages" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						let total = *doc.get_pages().keys().max().unwrap_or(&0);
						let page_numbers = complement_page_numbers(&page_numbers, total);
						doc.delete_pages(&page_numbers);
					}
				}
				"delete_pages" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						doc.delete_pages(&page_numbers);
					}
				}
				"delete_objects" => {
					if let Some(ids) = args.value_of("ids") {
						for id in ids.split(',') {
							let nums: Vec<u32> = id.split(' ').map(|num| u32::from_str(num).unwrap()).collect();
							match nums.len() {
								1 => doc.delete_object((nums[0], 0)),
								2 => doc.delete_object((nums[0], nums[1] as u16)),
								_ => None,
							};
						}
					}
				}
				"extract_text" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						let text = doc.extract_text(&page_numbers);
						info!("{}", text);
					}
				}
				"replace_text" => {
					if let Some(text) = args.value_of("text") {
						let parts: Vec<&str> = text.splitn(2, ':').collect();
						let page = u32::from_str(parts[0]).unwrap();
						let words: Vec<&str> = parts[1].splitn(2, "=>").collect();
						doc.replace_text(page, words[0], words[1]);
					}
				}
				"print_streams" => for (_, object) in doc.objects.iter() {
					match *object {
						Object::Stream(ref stream) => info!("{:?}", stream.dict),
						_ => (),
					}
				},
				"extract_stream" => {
					if let Some(ids) = args.value_of("ids") {
						for id in ids.split(',') {
							let nums: Vec<u32> = id.split(' ').map(|num| u32::from_str(num).unwrap()).collect();
							match nums.len() {
								1 => doc.extract_stream((nums[0], 0), false).ok(),
								2 => doc.extract_stream((nums[0], nums[1] as u16), false).ok(),
								_ => None,
							};
						}
					}
				}
				operation @ _ => {
					apply_operation(&mut doc, operation);
				}
			}

			doc.change_producer("https://crates.io/crates/lopdf");

			if let Some(output) = args.value_of("output") {
				info!("Save to {}", output);
				doc.save(output).unwrap();
			}
		}
	}

	fn apply_operation(doc: &mut Document, operation: &str) {
		match operation {
			"compress" => doc.compress(),
			"decompress" => doc.decompress(),
			"renumber_objects" => doc.renumber_objects(),
			"prune_objects" => {
				let ids = doc.prune_objects();
				info!("Deleted {:?}", ids);
			}
			"delete_zero_length_streams" => {
				let streams = doc.delete_zero_length_streams();
				if streams.len() > 0 {
					info!("Deleted {:?}", streams);
				}
			}
			_ => {}
		}
	}

	fn compute_page_numbers(pages: &str) -> Vec<u32> {
		let mut page_numbers = vec![];
		for page in pages.split(',') {
			let nums: Vec<u32> = page.split('-').map(|num| u32::from_str(num).unwrap()).collect();
			match nums.len() {
				1 => page_numbers.push(nums[0]),
				2 => page_numbers.append(&mut (nums[0]..nums[1] + 1).collect()),
				_ => {}
			}
		}
		page_numbers
	}

	fn complement_page_numbers(pages: &[u32], total: u32) -> Vec<u32> {
		let mut page_numbers = vec![];
		for page in 1..(total + 1) {
			if !pages.contains(&page) {
				page_numbers.push(page);
			}
		}
		page_numbers
	}
}
<commit_msg>Unwrap the text (#119)<commit_after>use lopdf::Document;
use lopdf::Object;
use log::info;

#[macro_use]
extern crate clap;
use clap::{App, Arg, SubCommand};
use std::str::FromStr;

fn main() {
	env_logger::init();

	let app = App::new("PDF utility program using lopdf library")
		.version(crate_version!())
		.author(crate_authors!())
		.arg(Arg::with_name("input").short("i").long("input").value_name("input file").takes_value(true).global(true))
		.arg(Arg::with_name("output").short("o").long("output").value_name("output file").takes_value(true).global(true))
		.subcommand(
			SubCommand::with_name("process").about("Process PDF document with specified operations").arg(
				Arg::with_name("operations")
					.value_name("operations")
					.help("e.g. prune_objects delete_zero_length_streams renumber_objects")
					.takes_value(true)
					.multiple(true),
			),
		)
		.subcommand(SubCommand::with_name("compress").about("Compress PDF document"))
		.subcommand(SubCommand::with_name("decompress").about("Decompress PDF document"))
		.subcommand(
			SubCommand::with_name("delete_pages")
				.about("Delete pages")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_pages")
				.about("Extract pages")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(SubCommand::with_name("prune_objects").about("Prune unused objects"))
		.subcommand(
			SubCommand::with_name("delete_objects")
				.about("Delete objects")
				.arg(Arg::with_name("ids").value_name("object ids").help("e.g. \"1 0,2 1,35,36\"").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_text")
				.about("Extract text")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("replace_text")
				.about("Replace text")
				.arg(Arg::with_name("text").value_name("page_number:old_text=>new_text").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_stream")
				.about("Extract stream content")
				.arg(Arg::with_name("ids").value_name("object ids").help("e.g. \"1 0,2 1,35,36\"").takes_value(true)),
		)
		.subcommand(SubCommand::with_name("print_streams").about("Print streams"))
		.subcommand(SubCommand::with_name("renumber_objects").about("Renumber objects"))
		.subcommand(SubCommand::with_name("delete_zero_length_streams").about("Delete zero length stream objects"))
		.get_matches();

	if let (cmd, Some(args)) = app.subcommand() {
		if let Some(input) = args.value_of("input") {
			info!("Open {}", input);
			let mut doc = Document::load(input).unwrap();
			//info!("{:?}", doc.get_pages());

			info!("Do {}", cmd);
			match cmd {
				"process" => {
					if let Some(operations) = args.values_of("operations") {
						for operation in operations {
							info!("Do {}", operation);
							apply_operation(&mut doc, operation);
						}
					}
				}
				"extract_pages" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						let total = *doc.get_pages().keys().max().unwrap_or(&0);
						let page_numbers = complement_page_numbers(&page_numbers, total);
						doc.delete_pages(&page_numbers);
					}
				}
				"delete_pages" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						doc.delete_pages(&page_numbers);
					}
				}
				"delete_objects" => {
					if let Some(ids) = args.value_of("ids") {
						for id in ids.split(',') {
							let nums: Vec<u32> = id.split(' ').map(|num| u32::from_str(num).unwrap()).collect();
							match nums.len() {
								1 => doc.delete_object((nums[0], 0)),
								2 => doc.delete_object((nums[0], nums[1] as u16)),
								_ => None,
							};
						}
					}
				}
				"extract_text" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						let text = doc.extract_text(&page_numbers);
						info!("{}", text.unwrap());
					}
				}
				"replace_text" => {
					if let Some(text) = args.value_of("text") {
						let parts: Vec<&str> = text.splitn(2, ':').collect();
						let page = u32::from_str(parts[0]).unwrap();
						let words: Vec<&str> = parts[1].splitn(2, "=>").collect();
						doc.replace_text(page, words[0], words[1]);
					}
				}
				"print_streams" => for (_, object) in doc.objects.iter() {
					match *object {
						Object::Stream(ref stream) => info!("{:?}", stream.dict),
						_ => (),
					}
				},
				"extract_stream" => {
					if let Some(ids) = args.value_of("ids") {
						for id in ids.split(',') {
							let nums: Vec<u32> = id.split(' ').map(|num| u32::from_str(num).unwrap()).collect();
							match nums.len() {
								1 => doc.extract_stream((nums[0], 0), false).ok(),
								2 => doc.extract_stream((nums[0], nums[1] as u16), false).ok(),
								_ => None,
							};
						}
					}
				}
				operation @ _ => {
					apply_operation(&mut doc, operation);
				}
			}

			doc.change_producer("https://crates.io/crates/lopdf");

			if let Some(output) = args.value_of("output") {
				info!("Save to {}", output);
				doc.save(output).unwrap();
			}
		}
	}

	fn apply_operation(doc: &mut Document, operation: &str) {
		match operation {
			"compress" => doc.compress(),
			"decompress" => doc.decompress(),
			"renumber_objects" => doc.renumber_objects(),
			"prune_objects" => {
				let ids = doc.prune_objects();
				info!("Deleted {:?}", ids);
			}
			"delete_zero_length_streams" => {
				let streams = doc.delete_zero_length_streams();
				if streams.len() > 0 {
					info!("Deleted {:?}", streams);
				}
			}
			_ => {}
		}
	}

	fn compute_page_numbers(pages: &str) -> Vec<u32> {
		let mut page_numbers = vec![];
		for page in pages.split(',') {
			let nums: Vec<u32> = page.split('-').map(|num| u32::from_str(num).unwrap()).collect();
			match nums.len() {
				1 => page_numbers.push(nums[0]),
				2 => page_numbers.append(&mut (nums[0]..nums[1] + 1).collect()),
				_ => {}
			}
		}
		page_numbers
	}

	fn complement_page_numbers(pages: &[u32], total: u32) -> Vec<u32> {
		let mut page_numbers = vec![];
		for page in 1..(total + 1) {
			if !pages.contains(&page) {
				page_numbers.push(page);
			}
		}
		page_numbers
	}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

extern crate libamg;
extern crate nalgebra as na;

use libamg::io::MatrixMarketReader;
use std::time::{Duration, Instant};
use na::io::cs_matrix_from_matrix_market;

fn main()
{
    let matches = clap_app!(ramg =>
            (version: "0.0.1")
            (author: "Alexander Samoilov <alexander.samoilov@gmail.com>")
            (@arg SET_MATRIX: -A --matrix +takes_value "System matrix in the MatrixMarket format.")
            (@arg SET_BLOCKSIZE: -b --block-size +takes_value "The block size of the system matrix.")
        ).get_matches();

    let block_size = if let Ok(block_size) = value_t!(matches, "SET_BLOCKSIZE", usize) {
            block_size
        } else {
            1 // default value
        };
    println!("block size: {}", block_size);

    if let Ok(matrix_name) = value_t!(matches, "SET_MATRIX", String) {
        println!("the matrix: {}", matrix_name);
        let mut start = Instant::now();
        let mmr = MatrixMarketReader::new(&matrix_name);
        let mut duration = start.elapsed();
        println!("Time elapsed in `MatrixMarketReader::new()` is: {:?}", duration);
        start = Instant::now();
        let csr = libamg::io::mm::create_csr(&mmr.unwrap());
        duration = start.elapsed();
        println!("Time elapsed in `create_csr()` is: {:?}", duration);
        //println!("csr: {:?}", &csr);

        duration = start.elapsed();
        let cs = cs_matrix_from_matrix_market::<f64, &str>(&matrix_name);
        println!("Time elapsed in `cs_matrix_from_matrix_market()` is: {:?}", duration);
        //println!("cs: {:?}", &cs);

    }
}
<commit_msg>fix time elapse for `cs_matrix_from_matrix_market`<commit_after>#[macro_use]
extern crate clap;

extern crate libamg;
extern crate nalgebra as na;

use libamg::io::MatrixMarketReader;
use std::time::{Duration, Instant};
use na::io::cs_matrix_from_matrix_market;

fn main()
{
    let matches = clap_app!(ramg =>
            (version: "0.0.1")
            (author: "Alexander Samoilov <alexander.samoilov@gmail.com>")
            (@arg SET_MATRIX: -A --matrix +takes_value "System matrix in the MatrixMarket format.")
            (@arg SET_BLOCKSIZE: -b --block-size +takes_value "The block size of the system matrix.")
        ).get_matches();

    let block_size = if let Ok(block_size) = value_t!(matches, "SET_BLOCKSIZE", usize) {
            block_size
        } else {
            1 // default value
        };
    println!("block size: {}", block_size);

    if let Ok(matrix_name) = value_t!(matches, "SET_MATRIX", String) {
        println!("the matrix: {}", matrix_name);
        let mut start = Instant::now();
        let mmr = MatrixMarketReader::new(&matrix_name);
        let mut duration = start.elapsed();
        println!("Time elapsed in `MatrixMarketReader::new()` is: {:?}", duration);
        start = Instant::now();
        let csr = libamg::io::mm::create_csr(&mmr.unwrap());
        duration = start.elapsed();
        println!("Time elapsed in `create_csr()` is: {:?}", duration);
        //println!("csr: {:?}", &csr);

        start = Instant::now();
        let cs = cs_matrix_from_matrix_market::<f64, &str>(&matrix_name);
        duration = start.elapsed();
        println!("Time elapsed in `cs_matrix_from_matrix_market()` is: {:?}", duration);
        //println!("cs: {:?}", &cs);

    }
}
<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};
use core::f64::consts::pi;
use funs::triganomic::{cos, sin};
use mat::{Mat3, Mat4};
use num::cast::{NumCast, cast};
use quat::Quat;
use vec::Vec3;

/**
 * The base trait for anglular units
 */
pub trait Angle<T>: Add<self,self>
                  , Sub<self,self>
                  , Mul<T,self>
                  , Div<T,self>
                  , Modulo<T,self>
                  , Neg<self>
                  , Eq, Ord {
    static pure fn full_rotation() -> self;
    static pure fn half_rotation() -> self;
    static pure fn quarter_rotation() -> self;
    static pure fn eighth_rotation() -> self;

    pure fn to_radians() -> Radians<T>;
    pure fn to_degrees() -> Degrees<T>;
}

pub enum Radians<T> = T;

pub impl<T:Copy Num NumCast> Radians<T>: Angle<T> {
    #[inline(always)] static pure fn full_rotation()    -> Radians<T> { Radians(move cast(2.0 * pi)) }
    #[inline(always)] static pure fn half_rotation()    -> Radians<T> { Radians(move cast(pi))       }
    #[inline(always)] static pure fn quarter_rotation() -> Radians<T> { Radians(move cast(pi / 2.0)) }
    #[inline(always)] static pure fn eighth_rotation()  -> Radians<T> { Radians(move cast(pi / 4.0)) }

    #[inline(always)] pure fn to_radians() -> Radians<T> { self }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { Degrees(*self * cast(180.0 / pi)) }

    #[inline(always)] pure fn add(rhs: &Radians<T>) -> Radians<T> { Radians(*self + **rhs) }
    #[inline(always)] pure fn sub(rhs: &Radians<T>) -> Radians<T> { Radians(*self - **rhs) }
    #[inline(always)] pure fn mul(rhs: &T)          -> Radians<T> { Radians(*self * *rhs) }
    #[inline(always)] pure fn div(rhs: &T)          -> Radians<T> { Radians(*self / *rhs) }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Radians<T> { Radians(*self % *rhs) }
    #[inline(always)] pure fn neg()                 -> Radians<T> { Radians(-*self) }
}

pub impl<T:Copy Eq> Radians<T>: Eq {
    #[inline(always)] pure fn eq(other: &Radians<T>) -> bool { *self == **other }
    #[inline(always)] pure fn ne(other: &Radians<T>) -> bool { *self != **other }
}

pub impl<T:Copy Ord> Radians<T>: Ord {
    #[inline(always)] pure fn lt(other: &Radians<T>) -> bool { *self <  **other }
    #[inline(always)] pure fn le(other: &Radians<T>) -> bool { *self <= **other }
    #[inline(always)] pure fn ge(other: &Radians<T>) -> bool { *self >= **other }
    #[inline(always)] pure fn gt(other: &Radians<T>) -> bool { *self >  **other }
}

pub enum Degrees<T> = T;

pub impl<T:Copy Num NumCast> Degrees<T>: Angle<T> {
    #[inline(always)] static pure fn full_rotation()    -> Degrees<T> { Degrees(move cast(360.0)) }
    #[inline(always)] static pure fn half_rotation()    -> Degrees<T> { Degrees(move cast(180.0)) }
    #[inline(always)] static pure fn quarter_rotation() -> Degrees<T> { Degrees(move cast(90.0))  }
    #[inline(always)] static pure fn eighth_rotation()  -> Degrees<T> { Degrees(move cast(45.0))  }

    #[inline(always)] pure fn to_radians() -> Radians<T> { Radians(*self * cast(pi / 180.0)) }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { self }

    #[inline(always)] pure fn add(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self + **rhs) }
    #[inline(always)] pure fn sub(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self - **rhs) }
    #[inline(always)] pure fn mul(rhs: &T)          -> Degrees<T> { Degrees(*self * *rhs) }
    #[inline(always)] pure fn div(rhs: &T)          -> Degrees<T> { Degrees(*self / *rhs) }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Degrees<T> { Degrees(*self % *rhs) }
    #[inline(always)] pure fn neg()                 -> Degrees<T> { Degrees(-*self) }
}

pub impl<T:Copy Eq> Degrees<T>: Eq {
    #[inline(always)] pure fn eq(other: &Degrees<T>) -> bool { *self == **other }
    #[inline(always)] pure fn ne(other: &Degrees<T>) -> bool { *self != **other }
}

pub impl<T:Copy Ord> Degrees<T>: Ord {
    #[inline(always)] pure fn lt(other: &Degrees<T>) -> bool { *self <  **other }
    #[inline(always)] pure fn le(other: &Degrees<T>) -> bool { *self <= **other }
    #[inline(always)] pure fn ge(other: &Degrees<T>) -> bool { *self >= **other }
    #[inline(always)] pure fn gt(other: &Degrees<T>) -> bool { *self >  **other }
}

/**
 * An angular rotation around an arbitary axis
 */
pub struct Rotation<T> {
    theta: Radians<T>,
    axis: Vec3<T>,
}

pub impl<T:Copy Num NumCast> Rotation<T> {
    static pure fn new(theta: Radians<T>, axis: Vec3<T>) -> Rotation<T> {
        Rotation { theta: move theta, axis: move axis }
    }

    pure fn to_mat3() -> Mat3<T> {
        let c:  T = cos(&self.theta);
        let s:  T = sin(&self.theta);
        let _0: T = cast(0);
        let _1: T = cast(1);
        let t:  T = _1 - c;

        let x = self.axis.x;
        let y = self.axis.y;
        let z = self.axis.z;

        Mat3::new(t * x * x + c,       t * x * y + s * z,   t * x * z - s * y,
                  t * x * y - s * z,   t * y * y + c,       t * y * z + s * x,
                  t * x * z - s - y,   t * y * z - s * x,   t * z * z + c)
    }

    pure fn to_mat4() -> Mat4<T> {
        self.to_mat3().to_mat4()
    }

    pure fn to_quat() -> Quat<T> {
        let half = self.theta / cast(2);
        Quat::from_sv(cos(&half), self.axis.mul_t(sin(&half)))
    }
}

pub struct Euler<T> {
    x: Radians<T>,   // pitch
    y: Radians<T>,   // yaw
    z: Radians<T>,   // roll
}<commit_msg>Separate operator overload implementations<commit_after>use core::cmp::{Eq, Ord};
use core::f64::consts::pi;
use funs::triganomic::{cos, sin};
use mat::{Mat3, Mat4};
use num::cast::{NumCast, cast};
use quat::Quat;
use vec::Vec3;

/**
 * The base trait for anglular units
 */
pub trait Angle<T>: Add<self,self>
                  , Sub<self,self>
                  , Mul<T,self>
                  , Div<T,self>
                  , Modulo<T,self>
                  , Neg<self>
                  , Eq, Ord {
    static pure fn full_rotation() -> self;
    static pure fn half_rotation() -> self;
    static pure fn quarter_rotation() -> self;
    static pure fn eighth_rotation() -> self;

    pure fn to_radians() -> Radians<T>;
    pure fn to_degrees() -> Degrees<T>;
}

pub enum Radians<T> = T;

pub impl<T:Copy Num NumCast> Radians<T>: Angle<T> {
    #[inline(always)] static pure fn full_rotation()    -> Radians<T> { Radians(move cast(2.0 * pi)) }
    #[inline(always)] static pure fn half_rotation()    -> Radians<T> { Radians(move cast(pi))       }
    #[inline(always)] static pure fn quarter_rotation() -> Radians<T> { Radians(move cast(pi / 2.0)) }
    #[inline(always)] static pure fn eighth_rotation()  -> Radians<T> { Radians(move cast(pi / 4.0)) }

    #[inline(always)] pure fn to_radians() -> Radians<T> { self }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { Degrees(*self * cast(180.0 / pi)) }

}

pub impl<T:Copy Num> Radians<T>: Add<Radians<T>, Radians<T>> {
    #[inline(always)] pure fn add(rhs: &Radians<T>) -> Radians<T> { Radians(*self + **rhs) }
}

pub impl<T:Copy Num> Radians<T>: Sub<Radians<T>, Radians<T>> {
    #[inline(always)] pure fn sub(rhs: &Radians<T>) -> Radians<T> { Radians(*self - **rhs) }
}

pub impl<T:Copy Num> Radians<T>: Mul<T, Radians<T>> {
    #[inline(always)] pure fn mul(rhs: &T) -> Radians<T> { Radians(*self * *rhs) }
}

pub impl<T:Copy Num> Radians<T>: Div<T, Radians<T>> {
    #[inline(always)] pure fn div(rhs: &T) -> Radians<T> { Radians(*self / *rhs) }
}

pub impl<T:Copy Num> Radians<T>: Modulo<T, Radians<T>> {
    #[inline(always)] pure fn modulo(rhs: &T) -> Radians<T> { Radians(*self % *rhs) }
}

pub impl<T:Copy Num> Radians<T>: Neg<Radians<T>> {
    #[inline(always)] pure fn neg() -> Radians<T> { Radians(-*self) }
}

pub impl<T:Copy Eq> Radians<T>: Eq {
    #[inline(always)] pure fn eq(other: &Radians<T>) -> bool { *self == **other }
    #[inline(always)] pure fn ne(other: &Radians<T>) -> bool { *self != **other }
}

pub impl<T:Copy Ord> Radians<T>: Ord {
    #[inline(always)] pure fn lt(other: &Radians<T>) -> bool { *self <  **other }
    #[inline(always)] pure fn le(other: &Radians<T>) -> bool { *self <= **other }
    #[inline(always)] pure fn ge(other: &Radians<T>) -> bool { *self >= **other }
    #[inline(always)] pure fn gt(other: &Radians<T>) -> bool { *self >  **other }
}

pub enum Degrees<T> = T;

pub impl<T:Copy Num NumCast> Degrees<T>: Angle<T> {
    #[inline(always)] static pure fn full_rotation()    -> Degrees<T> { Degrees(move cast(360.0)) }
    #[inline(always)] static pure fn half_rotation()    -> Degrees<T> { Degrees(move cast(180.0)) }
    #[inline(always)] static pure fn quarter_rotation() -> Degrees<T> { Degrees(move cast(90.0))  }
    #[inline(always)] static pure fn eighth_rotation()  -> Degrees<T> { Degrees(move cast(45.0))  }

    #[inline(always)] pure fn to_radians() -> Radians<T> { Radians(*self * cast(pi / 180.0)) }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { self }

}

pub impl<T:Copy Num> Degrees<T>: Add<Degrees<T>, Degrees<T>> {
    #[inline(always)] pure fn add(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self + **rhs) }
}

pub impl<T:Copy Num> Degrees<T>: Sub<Degrees<T>, Degrees<T>> {
    #[inline(always)] pure fn sub(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self - **rhs) }
}

pub impl<T:Copy Num> Degrees<T>: Mul<T, Degrees<T>> {
    #[inline(always)] pure fn mul(rhs: &T) -> Degrees<T> { Degrees(*self * *rhs) }
}

pub impl<T:Copy Num> Degrees<T>: Div<T, Degrees<T>> {
    #[inline(always)] pure fn div(rhs: &T) -> Degrees<T> { Degrees(*self / *rhs) }
}

pub impl<T:Copy Num> Degrees<T>: Modulo<T, Degrees<T>> {
    #[inline(always)] pure fn modulo(rhs: &T) -> Degrees<T> { Degrees(*self % *rhs) }
}

pub impl<T:Copy Num> Degrees<T>: Neg<Degrees<T>> {
    #[inline(always)] pure fn neg() -> Degrees<T> { Degrees(-*self) }
}

pub impl<T:Copy Eq> Degrees<T>: Eq {
    #[inline(always)] pure fn eq(other: &Degrees<T>) -> bool { *self == **other }
    #[inline(always)] pure fn ne(other: &Degrees<T>) -> bool { *self != **other }
}

pub impl<T:Copy Ord> Degrees<T>: Ord {
    #[inline(always)] pure fn lt(other: &Degrees<T>) -> bool { *self <  **other }
    #[inline(always)] pure fn le(other: &Degrees<T>) -> bool { *self <= **other }
    #[inline(always)] pure fn ge(other: &Degrees<T>) -> bool { *self >= **other }
    #[inline(always)] pure fn gt(other: &Degrees<T>) -> bool { *self >  **other }
}

/**
 * An angular rotation around an arbitary axis
 */
pub struct Rotation<T> {
    theta: Radians<T>,
    axis: Vec3<T>,
}

pub impl<T:Copy Num NumCast> Rotation<T> {
    static pure fn new(theta: Radians<T>, axis: Vec3<T>) -> Rotation<T> {
        Rotation { theta: move theta, axis: move axis }
    }

    pure fn to_mat3() -> Mat3<T> {
        let c:  T = cos(&self.theta);
        let s:  T = sin(&self.theta);
        let _0: T = cast(0);
        let _1: T = cast(1);
        let t:  T = _1 - c;

        let x = self.axis.x;
        let y = self.axis.y;
        let z = self.axis.z;

        Mat3::new(t * x * x + c,       t * x * y + s * z,   t * x * z - s * y,
                  t * x * y - s * z,   t * y * y + c,       t * y * z + s * x,
                  t * x * z - s - y,   t * y * z - s * x,   t * z * z + c)
    }

    pure fn to_mat4() -> Mat4<T> {
        self.to_mat3().to_mat4()
    }

    pure fn to_quat() -> Quat<T> {
        let half = self.theta / cast(2);
        Quat::from_sv(cos(&half), self.axis.mul_t(sin(&half)))
    }
}

pub struct Euler<T> {
    x: Radians<T>,   // pitch
    y: Radians<T>,   // yaw
    z: Radians<T>,   // roll
}<|endoftext|>