<commit_before>#![feature(slicing_syntax, macro_rules)]
#![feature(overloaded_calls)]

extern crate http;
extern crate url;
extern crate serialize;

use std::os;
use std::sync::{Arc, Mutex};
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::collections::HashMap;

use http::method::{Get, Post};
use http::server::{Config, Server, Request, ResponseWriter};
use http::server::request::{AbsolutePath};

use serialize::json;

use incoming::{SlackPayload};
use outgoing::{SlackEndpoint, OutgoingWebhook};

mod incoming;
mod outgoing;

type Scores = HashMap<String, i32>;

#[deriving(Send,Clone)]
struct KarmaServer {
    scores: Arc<Mutex<Scores>>,
    endpoint: String,
}

impl KarmaServer {
    fn new(scores: Scores, endpoint: String) -> KarmaServer {
        KarmaServer {
            scores: Arc::new(Mutex::new(scores)),
            endpoint: endpoint
        }
    }
}

fn handle_karma(req: Vec<u8>, points: &mut Scores, cb: |&&str, &i32|) {
    let payload = match SlackPayload::from_body(req.as_slice()) {
        Ok(payload) => payload,
        Err(err) => {
            println!("Error! {}", err); return
        }
    };

    let op = match payload.command {
        "%2F++" => |c: i32| c + 1,
        "%2F--" => |c: i32| c - 1,
        _ => return,
    };

    let current = points.insert(payload.user_name.to_string(), 0).unwrap_or(0);
    points.insert(payload.user_name.to_string(), op(current));

    cb(&payload.user_name, &op(current));
}

impl Server for KarmaServer {
    fn get_config(&self) -> Config {
        match os::getenv("PORT") {
            None => panic!("Must specify PORT"),
            Some(port) => {
                let port = from_str::<u16>(port.as_slice()).expect("PORT must be an int");
                Config { bind_address: SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: port } }
            }
        }
    }

    #[allow(unused_must_use)]
    fn handle_request(&self, r: Request, w: &mut ResponseWriter) {
        let path = match r.request_uri { AbsolutePath(ref path) => path[], _ => return };

        println!("{}: {}", r.method, path);

        match (&r.method, path) {
            (&Get, "/") => {
                w.write(b"Hello world!");
            },
            (&Get, "/karma") => {
                let scores = (*self.scores).lock();
                let json = json::encode(&*scores);
                w.write(json.as_bytes());
            }
            (&Post, "/normalise") => {
                let mut scores = (*self.scores).lock();
                for (_, v) in scores.iter_mut() {
                    let new = *v as f64;
                    *v = new.sqrt() as i32;
                }
            }
            (&Post, "/slack") => {
                let mut scores = (*self.scores).lock();
                let slack = self.get_slack_endpoint();
                handle_karma(r.body, &mut *scores, |u, s| {
                    let msg = format!("{} now at {}", u, s);
                    let payload = OutgoingWebhook {
                        text: msg.as_slice(),
                        channel: "#hax",
                        username: "karmabot",
                        icon_emoji: Some(":ghost:"),
                    };

                    slack.send(&payload);
                });
            },
            (_, _) => {
                w.write(b"Not found :(");
            }
        }
    }
}

impl KarmaServer {
    fn get_slack_endpoint(&self) -> SlackEndpoint {
        return SlackEndpoint {
            url: self.endpoint.clone()
        }
    }
}

fn main() {
    let endpoint = match os::getenv("WEBHOOK_ENDPOINT") {
        Some(e) => e,
        None => panic!("Must set WEBHOOK_ENDPOINT"),
    };
    let server = KarmaServer::new(HashMap::new(), endpoint);
    server.serve_forever();
}
<commit_msg>Fix encoding<commit_after>#![feature(slicing_syntax, macro_rules)]
#![feature(overloaded_calls)]

extern crate http;
extern crate url;
extern crate serialize;

use std::os;
use std::sync::{Arc, Mutex};
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::collections::HashMap;

use http::method::{Get, Post};
use http::server::{Config, Server, Request, ResponseWriter};
use http::server::request::{AbsolutePath};

use serialize::json;

use incoming::{SlackPayload};
use outgoing::{SlackEndpoint, OutgoingWebhook};

mod incoming;
mod outgoing;

type Scores = HashMap<String, i32>;

#[deriving(Send,Clone)]
struct KarmaServer {
    scores: Arc<Mutex<Scores>>,
    endpoint: String,
}

impl KarmaServer {
    fn new(scores: Scores, endpoint: String) -> KarmaServer {
        KarmaServer {
            scores: Arc::new(Mutex::new(scores)),
            endpoint: endpoint
        }
    }
}

fn handle_karma(req: Vec<u8>, points: &mut Scores, cb: |&&str, &i32|) {
    let payload = match SlackPayload::from_body(req.as_slice()) {
        Ok(payload) => payload,
        Err(err) => {
            println!("Error! {}", err); return
        }
    };

    let op = match payload.command {
        "%2F%2B%2B" => |c: i32| c + 1,
        "%2F%2D%2D" => |c: i32| c - 1,
        _ => return,
    };

    let current = points.insert(payload.user_name.to_string(), 0).unwrap_or(0);
    points.insert(payload.user_name.to_string(), op(current));

    cb(&payload.user_name, &op(current));
}

impl Server for KarmaServer {
    fn get_config(&self) -> Config {
        match os::getenv("PORT") {
            None => panic!("Must specify PORT"),
            Some(port) => {
                let port = from_str::<u16>(port.as_slice()).expect("PORT must be an int");
                Config { bind_address: SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: port } }
            }
        }
    }

    #[allow(unused_must_use)]
    fn handle_request(&self, r: Request, w: &mut ResponseWriter) {
        let path = match r.request_uri { AbsolutePath(ref path) => path[], _ => return };

        println!("{}: {}", r.method, path);

        match (&r.method, path) {
            (&Get, "/") => {
                w.write(b"Hello world!");
            },
            (&Get, "/karma") => {
                let scores = (*self.scores).lock();
                let json = json::encode(&*scores);
                w.write(json.as_bytes());
            }
            (&Post, "/normalise") => {
                let mut scores = (*self.scores).lock();
                for (_, v) in scores.iter_mut() {
                    let new = *v as f64;
                    *v = new.sqrt() as i32;
                }
            }
            (&Post, "/slack") => {
                let mut scores = (*self.scores).lock();
                let slack = self.get_slack_endpoint();
                handle_karma(r.body, &mut *scores, |u, s| {
                    let msg = format!("{} now at {}", u, s);
                    let payload = OutgoingWebhook {
                        text: msg.as_slice(),
                        channel: "#hax",
                        username: "karmabot",
                        icon_emoji: Some(":ghost:"),
                    };

                    slack.send(&payload);
                });
            },
            (_, _) => {
                w.write(b"Not found :(");
            }
        }
    }
}

impl KarmaServer {
    fn get_slack_endpoint(&self) -> SlackEndpoint {
        return SlackEndpoint {
            url: self.endpoint.clone()
        }
    }
}

fn main() {
    let endpoint = match os::getenv("WEBHOOK_ENDPOINT") {
        Some(e) => e,
        None => panic!("Must set WEBHOOK_ENDPOINT"),
    };
    let server = KarmaServer::new(HashMap::new(), endpoint);
    server.serve_forever();
}
<|endoftext|>


<commit_before>extern crate alpm;
extern crate curl;
extern crate env_logger;
#[macro_use]
extern crate json;
#[macro_use]
extern crate log;
extern crate select;

use curl::easy::Easy;
use select::document::Document;
use select::predicate::Name;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::str;

#[derive(Debug)]
struct CVEInfo {
    cve: Vec<String>,
    version: Option<String>,
}

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

    let mut wikipage = String::new();
    {
        info!("Downloading CVE wiki page...");
        let wikipage_url = "https://wiki.archlinux.org/api.php?format=json&action=parse&page=CVE&section=5";

        let mut easy = Easy::new();
        easy.url(wikipage_url).unwrap();
        let mut transfer = easy.transfer();
        transfer.write_function(|data| {
            wikipage.push_str(str::from_utf8(data).unwrap());
            Ok(data.len())
        }).unwrap();
        transfer.perform().unwrap();
    }

    let json = json::parse(wikipage.as_str()).unwrap();
    let document = Document::from(json["parse"]["text"]["*"].as_str().unwrap());

    let mut infos: HashMap<String, Vec<_>> = HashMap::new();
    for tr in document.find(Name("tbody")).find(Name("tr")).iter() {
        let tds = tr.find(Name("td"));

        match tds.first() {
            Some(td) => {
                let pkgname = tds.next().next().first().unwrap().text().trim().to_string();
                let info = CVEInfo {
                    cve: td.text().split_whitespace().filter(|s| s.starts_with("CVE")).map(|s| s.to_string()).collect(),
                    version: {
                        let v = tds.next().next().next().next().next().next().next().next().first().unwrap().text().trim().to_string();
                        if !v.is_empty() && v != "?".to_string() && v != "-".to_string() { Some(v) } else { None }
                    },
                };

                if !infos.contains_key(&pkgname) {
                    infos.insert(pkgname.clone(), Vec::new());
                }

                infos.get_mut(&pkgname).unwrap().push(info);
            },
            None => {},
        };
    }

    let pacman = alpm::Alpm::new().unwrap();
    for (pkg, cves) in infos {
        match pacman.query_package_version(pkg.clone()) {
            Ok(v) => {
                info!("Found installed version {} for package {}", v, pkg);
                for cve in cves {
                    match cve.version {
                        Some(version) => {
                            info!("Comparing with fixed version {}", version);
                            match pacman.vercmp(v.clone(), version.clone()).unwrap() {
                                Ordering::Less => { println!("Package {} is affected by {:?}. Update to {}!", pkg, cve.cve, version) },
                                _ => {},
                            };
                        },
                        None => { println!("Package {} is affected by {:?}. VULNERABLE!", pkg, cve.cve) },
                    };
                };
            },
            Err(_) => { debug!("Package {} not installed", pkg) },
        }
    }
}

<commit_msg>Ignore reports flagged as Invalid or N/A<commit_after>extern crate alpm;
extern crate curl;
extern crate env_logger;
#[macro_use]
extern crate json;
#[macro_use]
extern crate log;
extern crate select;

use curl::easy::Easy;
use select::document::Document;
use select::predicate::Name;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::str;

#[derive(Debug)]
struct CVEInfo {
    cve: Vec<String>,
    version: Option<String>,
}

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

    let mut wikipage = String::new();
    {
        info!("Downloading CVE wiki page...");
        let wikipage_url = "https://wiki.archlinux.org/api.php?format=json&action=parse&page=CVE&section=5";

        let mut easy = Easy::new();
        easy.url(wikipage_url).unwrap();
        let mut transfer = easy.transfer();
        transfer.write_function(|data| {
            wikipage.push_str(str::from_utf8(data).unwrap());
            Ok(data.len())
        }).unwrap();
        transfer.perform().unwrap();
    }

    let json = json::parse(wikipage.as_str()).unwrap();
    let document = Document::from(json["parse"]["text"]["*"].as_str().unwrap());

    let mut infos: HashMap<String, Vec<_>> = HashMap::new();
    for tr in document.find(Name("tbody")).find(Name("tr")).iter() {
        let tds = tr.find(Name("td"));

        match tds.first() {
            Some(td) => {
                let mut next = tds.next().next();
                let pkgname = next.first().unwrap().text().trim().to_string();
                next = next.next().next().next().next().next().next();
                let info = CVEInfo {
                    cve: td.text().split_whitespace().filter(|s| s.starts_with("CVE")).map(|s| s.to_string()).collect(),
                    version: {
                        let v = next.first().unwrap().text().trim().to_string();
                        if !v.is_empty() && v != "?".to_string() && v != "-".to_string() { Some(v) } else { None }
                    },
                };
                next = next.next().next().next().next();
                let status = next.first().unwrap().text().trim().to_string();

                if !status.starts_with("Invalid") && !status.starts_with("Not Affected") {
                  if !infos.contains_key(&pkgname) {
                      infos.insert(pkgname.clone(), Vec::new());
                  }

                  infos.get_mut(&pkgname).unwrap().push(info);
                }
            },
            None => {},
        };
    }

    let pacman = alpm::Alpm::new().unwrap();
    for (pkg, cves) in infos {
        match pacman.query_package_version(pkg.clone()) {
            Ok(v) => {
                info!("Found installed version {} for package {}", v, pkg);
                for cve in cves {
                    match cve.version {
                        Some(version) => {
                            info!("Comparing with fixed version {}", version);
                            match pacman.vercmp(v.clone(), version.clone()).unwrap() {
                                Ordering::Less => { println!("Package {} is affected by {:?}. Update to {}!", pkg, cve.cve, version) },
                                _ => {},
                            };
                        },
                        None => { println!("Package {} is affected by {:?}. VULNERABLE!", pkg, cve.cve) },
                    };
                };
            },
            Err(_) => { debug!("Package {} not installed", pkg) },
        }
    }
}

<|endoftext|>


<commit_before>extern crate bencode;
extern crate rand;
extern crate bittorrent;
extern crate hyper;

use std::env;
use std::io::Read;
use std::collections::HashMap;
use std::net::{Ipv4Addr, TcpStream, SocketAddrV4};
use bencode::{deserialize, deserialize_file, Bencode, TypedMethods, BencodeVecOption};
use rand::{Rng, thread_rng};
use bittorrent::querystring::QueryString;
use bittorrent::metadata::{MetadataDict, Metadata};
use hyper::Client;
use hyper::header::Connection;

const PEER_ID_LENGTH:usize = 20;
const PEER_ID_PREFIX:&'static str = "ABT:";

#[derive(Debug)]
enum Address {
    TCP(Ipv4Addr, u16)
}

fn gen_rand_peer_id (prefix: &str) -> String {
    let rand_length = PEER_ID_LENGTH - prefix.len();
    let rand = thread_rng().gen_ascii_chars()
                           .take(rand_length)
                           .collect::<String>();

    prefix.to_string() + &rand
}

fn ping_tracker (announce: String, args: Vec<(&str, String)>) -> Option<HashMap<String, Bencode>> {
    let req_addr = announce + "?" + &QueryString::from(args).query_string();
    let client = Client::new();
    let mut res = client.get(&req_addr)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = Vec::new();
    res.read_to_end(&mut body).unwrap();

    deserialize(body).to_singleton_dict()
}

fn get_peers <T> (tracker_response: &T) -> Vec<Address> where T:TypedMethods {
    let peers = tracker_response.get_owned_string("peers").unwrap();
    //for now keep the bottom unused value, it's for ipv6. which maybe will be addressed
    let peers6 = tracker_response.get_owned_string("peers6").unwrap();
    let peers_bytes = peers.chars().map(|x| x as u8).collect::<Vec<u8>>();
    assert!(peers_bytes.len() % 6 == 0);
    (0..peers_bytes.len()/6).map(|x| {
        let ip_start = x * 6;
        let ip_end = ip_start + 4;
        let ip_bytes = &peers_bytes[ip_start..ip_end];
        let ip = Ipv4Addr::new(ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3]);
        /*let ip = (&peers_bytes[ip_start..ip_end]).iter()
                                                 .map(|y| y.to_string())
                                                 .collect::<Vec<String>>()
                                                 .join(".");*/
        let port = (peers_bytes[ip_end] as u16)*256 + peers_bytes[ip_end+1] as u16;
        Address::TCP(ip, port)
    }).collect::<Vec<Address>>()
}

fn connect_to_peer(address:Address) {
    let (ip, port) = match address {
        Address::TCP(ip_address, port) => (ip_address, port)
    };

    let stream = match TcpStream::connect(SocketAddrV4::new(ip, port)) {
        Ok(tcp_stream) => tcp_stream,
        _ => panic!("unable to connect to socket")
    };

}

fn init (metadata: Metadata, listen_port: u32, bytes_dled: u32) {
    let peer_id = gen_rand_peer_id(PEER_ID_PREFIX);
    let bytes_left = metadata.get_total_length() - bytes_dled;

    let response = ping_tracker(metadata.announce, vec![
                                ("info_hash", metadata.info_hash),
                                ("peer_id", peer_id),
                                ("port", listen_port.to_string()),
                                ("uploaded", 0.to_string()),
                                ("downloaded", bytes_dled.to_string()),
                                ("left", bytes_left.to_string()),
                                ("compact", 1.to_string()),
                                ("event", "started".to_string())
                                ]);

    let tracker_resp = match response {
        Some(a) => a,
        None => panic!("no valid bencode response from tracker")
    };

    let peers = get_peers(&tracker_resp);

    for peer in peers {
        connect_to_peer(peer);
    }
}

fn main () {
    let path = env::args().nth(1)
                          .unwrap_or_else(||panic!("no path to torrent provided"));

    let content = deserialize_file(path).unwrap_or_else(||panic!("unable to parse bencoded metadata"));

    let metadata = match content.first() {
        Some(&Bencode::Dict(ref dict)) => dict.to_metadata(),
        _ => panic!("no valid information in torrent file")
    }.unwrap();

    //println!("{:?}", metadata);
    init(metadata, 6888, 0);
}
<commit_msg>adding peer handshake message fn<commit_after>extern crate bencode;
extern crate rand;
extern crate bittorrent;
extern crate hyper;

use std::env;
use std::io::Read;
use std::collections::HashMap;
use std::net::{Ipv4Addr, TcpStream, SocketAddrV4};
use bencode::{deserialize, deserialize_file, Bencode, TypedMethods, BencodeVecOption};
use rand::{Rng, thread_rng};
use bittorrent::querystring::QueryString;
use bittorrent::metadata::{MetadataDict, Metadata};
use hyper::Client;
use hyper::header::Connection;

const PEER_ID_LENGTH:usize = 20;
const PEER_ID_PREFIX:&'static str = "ABT:";

#[derive(Debug)]
enum Address {
    TCP(Ipv4Addr, u16)
}

fn gen_rand_peer_id (prefix: &str) -> String {
    let rand_length = PEER_ID_LENGTH - prefix.len();
    let rand = thread_rng().gen_ascii_chars()
                           .take(rand_length)
                           .collect::<String>();

    prefix.to_string() + &rand
}

fn ping_tracker (announce: String, args: Vec<(&str, String)>) -> Option<HashMap<String, Bencode>> {
    let req_addr = announce + "?" + &QueryString::from(args).query_string();
    let client = Client::new();
    let mut res = client.get(&req_addr)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = Vec::new();
    res.read_to_end(&mut body).unwrap();

    deserialize(body).to_singleton_dict()
}

fn get_peers <T> (tracker_response: &T) -> Vec<Address> where T:TypedMethods {
    let peers = tracker_response.get_owned_string("peers").unwrap();
    //for now keep the bottom unused value, it's for ipv6. which maybe will be addressed
    let peers6 = tracker_response.get_owned_string("peers6").unwrap();
    let peers_bytes = peers.chars().map(|x| x as u8).collect::<Vec<u8>>();
    assert!(peers_bytes.len() % 6 == 0);
    (0..peers_bytes.len()/6).map(|x| {
        let ip_start = x * 6;
        let ip_end = ip_start + 4;
        let ip_bytes = &peers_bytes[ip_start..ip_end];
        let ip = Ipv4Addr::new(ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3]);
        let port = (peers_bytes[ip_end] as u16)*256 + peers_bytes[ip_end+1] as u16;
        Address::TCP(ip, port)
    }).collect::<Vec<Address>>()
}

/// The peer handshake message, according to protocol
///
fn to_handshake (pstr:&str, info_hash: &String, peer_id: &String) -> Vec<u8> {
    let reserved:[u8; 8] = [0; 8];
    let pstr_bytes = pstr.to_string().into_bytes();
    let a = [pstr_bytes.len() as u8];
    let b = pstr_bytes;
    let c = reserved;
    let d = info_hash.clone().into_bytes();
    let e = peer_id.clone().into_bytes();

    [a.iter(),
     b.iter(),
     c.iter(),
     d.iter(),
     e.iter()].iter().flat_map(|y| y.to_owned().map(|x| *x).collect::<Vec<u8>>())
                    .collect::<Vec<u8>>()
}

fn connect_to_peer(address:Address) {
    println!("connecting to {:?}", address);
    let (ip, port) = match address {
        Address::TCP(ip_address, port) => (ip_address, port)
    };

    let stream = match TcpStream::connect(SocketAddrV4::new(ip, port)) {
        Ok(tcp_stream) => tcp_stream,
        _ => panic!("unable to connect to socket")
    };
    println!("connected to {:?}", address);

}

fn init (metadata: Metadata, listen_port: u32, bytes_dled: u32) {
    let peer_id = gen_rand_peer_id(PEER_ID_PREFIX);
    let bytes_left = metadata.get_total_length() - bytes_dled;

    let response = ping_tracker(metadata.announce, vec![
                                ("info_hash", metadata.info_hash.clone()),
                                ("peer_id", peer_id.clone()),
                                ("port", listen_port.to_string()),
                                ("uploaded", 0.to_string()),
                                ("downloaded", bytes_dled.to_string()),
                                ("left", bytes_left.to_string()),
                                ("compact", 1.to_string()),
                                ("event", "started".to_string())
                                ]);

    let tracker_resp = match response {
        Some(a) => a,
        None => panic!("no valid bencode response from tracker")
    };

    let peers = get_peers(&tracker_resp);
    to_handshake("BitTorrent protocol", &metadata.info_hash, &peer_id);

    for peer in peers {
        connect_to_peer(peer);
    }
}

fn main () {
    let path = env::args().nth(1)
                          .unwrap_or_else(||panic!("no path to torrent provided"));

    let content = deserialize_file(path).unwrap_or_else(||panic!("unable to parse bencoded metadata"));

    let metadata = match content.first() {
        Some(&Bencode::Dict(ref dict)) => dict.to_metadata(),
        _ => panic!("no valid information in torrent file")
    }.unwrap();

    //println!("{:?}", metadata);
    init(metadata, 6888, 0);
}
<|endoftext|>


<commit_before>#![feature(phase)]

#[phase(plugin, link)]
extern crate log;

extern crate sdl2;

use mem::Mem;
use std::io::stdio;

mod cartridge;
mod cpu;
mod debug;
mod disasm;
mod interrupt;
mod joypad;
mod mem;
mod ram;
mod serial;
mod sound;
mod timer;
mod video;

//
// Memory Map
//

struct Dummy;
impl Mem for Dummy {
  fn loadb(&mut self, addr: u16) -> u8 {
    //debug!("load in unmapped memory at 0x{:04X}", addr);
    0xff
  }

  fn storeb(&mut self, addr: u16, val: u8) {
    //debug!("store in unmapped memory at 0x{:04X}", addr);
  }
}

struct MemMap<'a> {
  cart: Box<cartridge::Cartridge>,
  wram: ram::WorkRam,
  timer: timer::Timer,
  intr: interrupt::InterruptCtrl,
  sound: sound::Sound,
  video: video::Video,
  serial: serial::SerialIO<'a>,
  joypad: joypad::Joypad,
  dummy: Dummy,
}

impl<'a> MemMap<'a> {
  fn mem_from_addr(&mut self, addr: u16) -> &mut Mem {
    match addr {
      0x0000...0x7fff | // ROM banks
      0xa000...0xbfff   // External RAM
                       => &mut *self.cart as &mut Mem,
      0x8000...0x9fff | // VRAM
      0xfe00...0xfe9f | // OAM
      0xff40...0xff4b   // Video I/O
                       => &mut self.video as &mut Mem,
      0xc000...0xfdff | // WRAM (including echo area 0xe000-0xfdff)
      0xff80...0xfffe   // HRAM
                       => &mut self.wram as &mut Mem,
      0xff00           => &mut self.joypad as &mut Mem,
      0xff01...0xff02  => &mut self.serial as &mut Mem,
      0xff04...0xff07  => &mut self.timer as &mut Mem,
      0xff0f | 0xffff  => &mut self.intr as &mut Mem,
      0xff10...0xff3f  => &mut self.sound as &mut Mem,
      _ => &mut self.dummy as &mut Mem,
    }
  }
}

impl<'a> Mem for MemMap<'a> {
  fn loadb(&mut self, addr: u16) -> u8 {
    self.mem_from_addr(addr).loadb(addr)
  }

  fn storeb(&mut self, addr: u16, val: u8) {
    self.mem_from_addr(addr).storeb(addr, val)
  }
}

//
// Video Output
//

struct VideoOut {
  renderer: Box<sdl2::render::Renderer<sdl2::video::Window>>,
  texture: Box<sdl2::render::Texture>,
}

impl VideoOut {
  fn new(scale: int) -> VideoOut {
    use sdl2::render::Renderer;

    sdl2::init(sdl2::INIT_VIDEO);

    let window_width = video::SCREEN_WIDTH as int * scale;
    let window_height = video::SCREEN_HEIGHT as int * scale;

    let renderer = match Renderer::new_with_window(window_width,
                                                   window_height,
                                                   sdl2::video::RESIZABLE) {
      Ok(renderer) => renderer,
      Err(err) => panic!("Failed to create renderer: {}", err)
    };

    let texture = match renderer.create_texture(sdl2::pixels::ARGB8888,
                                                sdl2::render::AccessStreaming,
                                                video::SCREEN_WIDTH as int,
                                                video::SCREEN_HEIGHT as int) {
      Ok(texture) => texture,
      Err(err) => panic!("Failed to create texture: {}", err),
    };

    VideoOut { renderer: box renderer, texture: box texture }
  }

  fn blit_and_present(&self, pixels: &[u8]) {
    self.texture.update(None, pixels, (video::SCREEN_WIDTH * 4) as int);
    self.renderer.copy(&*self.texture, None, None);
    self.renderer.present();
  }

  fn set_title(&self, title: &str) {
    self.renderer.get_parent().set_title(title);
  }
}

fn keymap(code: sdl2::keycode::KeyCode) -> Option<joypad::Button> {
  match code {
    sdl2::keycode::UpKey     => Some(joypad::Up),
    sdl2::keycode::DownKey   => Some(joypad::Down),
    sdl2::keycode::LeftKey   => Some(joypad::Left),
    sdl2::keycode::RightKey  => Some(joypad::Right),
    sdl2::keycode::ReturnKey => Some(joypad::Start),
    sdl2::keycode::RShiftKey => Some(joypad::Select),
    sdl2::keycode::CKey      => Some(joypad::ButtonA),
    sdl2::keycode::XKey      => Some(joypad::ButtonB),
    _ => None,
  }
}

#[deriving(PartialEq)]
enum State {
  Paused,
  Running,
  Step,
  Done,
}

fn main() {
  let args = std::os::args();
  if args.len() != 2 && !(args.len() == 3 && args[1] == "-d".to_string()) {
    println!("Usage: {:s} [-d] rom.gb", args[0]);
    return;
  }

  let mut disassemble = false;
  let path =
    if args.len() == 2 {
      &args[1]
    } else {
      disassemble = true;
      &args[2]
    };

  let mut cart = match cartridge::Cartridge::from_path(&Path::new(path.as_slice())) {
    Ok(cart) => box cart,
    Err(e)   => panic!("I/O error: {}", e),
  };

  if disassemble {
    // Disassemble only
    let mut d = disasm::Disasm { mem: &mut *cart, pc: 0 };
    while d.pc <= 0x7fff {
      let pc = d.pc;
      println!("${:04X}\t{:s}", pc, cpu::decode(&mut d));
    }
    return;
  }

  println!("Name: {:s}", cart.title);
  println!("Type: {:u}", cart.cartridge_type);

  let memmap = MemMap {
    cart: cart,
    wram: ram::WorkRam::new(),
    timer: timer::Timer::new(),
    intr: interrupt::InterruptCtrl::new(),
    sound: sound::Sound,
    video: video::Video::new(),
    serial: serial::SerialIO::new(Some(box stdio::stdout() as Box<std::io::Writer>)),
    joypad: joypad::Joypad::new(),
    dummy: Dummy,
  };
  let mut cpu = cpu::Cpu::new(memmap);
  cpu.regs.pc = 0x100;

  let video_out = VideoOut::new(4);
  video_out.set_title("Rustboy");

  let mut state = Paused;
  let mut debugger = debug::Debugger::new();

  let counts_per_sec = sdl2::timer::get_performance_frequency();
  let counts_per_frame = counts_per_sec * video::SCREEN_REFRESH_CYCLES as u64 / cpu::CYCLES_PER_SEC as u64;
  let mut last_frame_start_count = sdl2::timer::get_performance_counter();

  let mut last_fps_update = last_frame_start_count;
  let mut frames = 0;

  println!("c/s: {:u}; c/f: {:u}", counts_per_sec, counts_per_frame);

  while state != Done {
    if state == Paused || state == Step {
      match debugger.prompt(&mut cpu) {
        debug::Quit => break,
        debug::Run  => state = Running,
        debug::Step => state = Step,
      }
    }

    // Emulation loop
    loop {
      let cycles = cpu.step();

      match cpu.mem.timer.tick(cycles) {
        Some(timer::TIMAOverflow) => cpu.mem.intr.irq(interrupt::IRQ_TIMER),
        None => (),
      }

      let mut new_frame = false;
      let video_signals = cpu.mem.video.tick(cycles);
      for signal in video_signals.iter() {
        match *signal {
          video::DMA(base) => {
            // Do DMA transfer instantaneously
            let base_addr = base as u16 << 8;
            for offset in range(0x00u16, 0xa0u16) {
              let val = cpu.mem.loadb(base_addr + offset);
              cpu.mem.storeb(0xfe00 + offset, val);
            }
          },
          video::VBlank => {
            video_out.blit_and_present(cpu.mem.video.screen);
            cpu.mem.intr.irq(interrupt::IRQ_VBLANK);
            new_frame = true;
          }
          video::LCD    => cpu.mem.intr.irq(interrupt::IRQ_LCD),
        }
      }

      // Synchronize speed based on frame time
      if new_frame {
        let now = sdl2::timer::get_performance_counter();
        let frame_time = now - last_frame_start_count;
        if frame_time < counts_per_frame {
          let delay_msec = (1_000 * (counts_per_frame - frame_time) / counts_per_sec) as uint;
          sdl2::timer::delay(delay_msec);
        }
        // TODO: What should we do when we take longer than counts_per_frame?
        last_frame_start_count = sdl2::timer::get_performance_counter();

        frames += 1;
        if last_frame_start_count - last_fps_update > counts_per_sec {
          let fps = frames * (last_frame_start_count - last_fps_update) / counts_per_sec;
          video_out.set_title(format!("Rustboy - {} fps", fps).as_slice());
          last_fps_update = now;
          frames = 0;
        }

        // Exit emulation loop to handle events
        break;
      }

      if debugger.should_break(&cpu) {
        state = Paused;
        break;
      }

      if state == Step {
        // Stop emulation loop after one instruction
        break;
      }
    }

    // Event handling loop
    loop {
      match sdl2::event::poll_event() {
        sdl2::event::QuitEvent(_) => { state = Done; break }
        sdl2::event::KeyDownEvent(_, _, key, _, _) => {
          match keymap(key) {
            Some(button) => cpu.mem.joypad.set_button(button, true),
            None => {
              match key {
                sdl2::keycode::EscapeKey => { state = Paused },
                _ => (),
              }
            }
          }
        },
        sdl2::event::KeyUpEvent(_, _, key, _, _) => {
          match keymap(key) {
            Some(button) => cpu.mem.joypad.set_button(button, false),
            None => (),
          }
        }
        sdl2::event::NoEvent => break,
        _ => (),
      }
    }
  }
}
<commit_msg>Fixed build with latest rust-sdl2<commit_after>#![feature(phase)]

#[phase(plugin, link)]
extern crate log;

extern crate sdl2;

use mem::Mem;
use std::io::stdio;

mod cartridge;
mod cpu;
mod debug;
mod disasm;
mod interrupt;
mod joypad;
mod mem;
mod ram;
mod serial;
mod sound;
mod timer;
mod video;

//
// Memory Map
//

struct Dummy;
impl Mem for Dummy {
  fn loadb(&mut self, addr: u16) -> u8 {
    //debug!("load in unmapped memory at 0x{:04X}", addr);
    0xff
  }

  fn storeb(&mut self, addr: u16, val: u8) {
    //debug!("store in unmapped memory at 0x{:04X}", addr);
  }
}

struct MemMap<'a> {
  cart: Box<cartridge::Cartridge>,
  wram: ram::WorkRam,
  timer: timer::Timer,
  intr: interrupt::InterruptCtrl,
  sound: sound::Sound,
  video: video::Video,
  serial: serial::SerialIO<'a>,
  joypad: joypad::Joypad,
  dummy: Dummy,
}

impl<'a> MemMap<'a> {
  fn mem_from_addr(&mut self, addr: u16) -> &mut Mem {
    match addr {
      0x0000...0x7fff | // ROM banks
      0xa000...0xbfff   // External RAM
                       => &mut *self.cart as &mut Mem,
      0x8000...0x9fff | // VRAM
      0xfe00...0xfe9f | // OAM
      0xff40...0xff4b   // Video I/O
                       => &mut self.video as &mut Mem,
      0xc000...0xfdff | // WRAM (including echo area 0xe000-0xfdff)
      0xff80...0xfffe   // HRAM
                       => &mut self.wram as &mut Mem,
      0xff00           => &mut self.joypad as &mut Mem,
      0xff01...0xff02  => &mut self.serial as &mut Mem,
      0xff04...0xff07  => &mut self.timer as &mut Mem,
      0xff0f | 0xffff  => &mut self.intr as &mut Mem,
      0xff10...0xff3f  => &mut self.sound as &mut Mem,
      _ => &mut self.dummy as &mut Mem,
    }
  }
}

impl<'a> Mem for MemMap<'a> {
  fn loadb(&mut self, addr: u16) -> u8 {
    self.mem_from_addr(addr).loadb(addr)
  }

  fn storeb(&mut self, addr: u16, val: u8) {
    self.mem_from_addr(addr).storeb(addr, val)
  }
}

//
// Video Output
//

struct VideoOut {
  renderer: Box<sdl2::render::Renderer>,
  texture: Box<sdl2::render::Texture>,
}

impl VideoOut {
  fn new(scale: int) -> VideoOut {
    use sdl2::render::Renderer;

    sdl2::init(sdl2::INIT_VIDEO);

    let window_width = video::SCREEN_WIDTH as int * scale;
    let window_height = video::SCREEN_HEIGHT as int * scale;

    let renderer = match Renderer::new_with_window(window_width,
                                                   window_height,
                                                   sdl2::video::RESIZABLE) {
      Ok(renderer) => renderer,
      Err(err) => panic!("Failed to create renderer: {}", err)
    };

    let texture = match renderer.create_texture(sdl2::pixels::ARGB8888,
                                                sdl2::render::AccessStreaming,
                                                video::SCREEN_WIDTH as int,
                                                video::SCREEN_HEIGHT as int) {
      Ok(texture) => texture,
      Err(err) => panic!("Failed to create texture: {}", err),
    };

    VideoOut { renderer: box renderer, texture: box texture }
  }

  fn blit_and_present(&self, pixels: &[u8]) {
    self.texture.update(None, pixels, (video::SCREEN_WIDTH * 4) as int);
    self.renderer.copy(&*self.texture, None, None);
    self.renderer.present();
  }

  fn set_title(&self, title: &str) {
    match self.renderer.get_parent() {
      &sdl2::render::WindowParent(ref window) => window.set_title(title),
      _ => (),
    }
  }
}

fn keymap(code: sdl2::keycode::KeyCode) -> Option<joypad::Button> {
  match code {
    sdl2::keycode::UpKey     => Some(joypad::Up),
    sdl2::keycode::DownKey   => Some(joypad::Down),
    sdl2::keycode::LeftKey   => Some(joypad::Left),
    sdl2::keycode::RightKey  => Some(joypad::Right),
    sdl2::keycode::ReturnKey => Some(joypad::Start),
    sdl2::keycode::RShiftKey => Some(joypad::Select),
    sdl2::keycode::CKey      => Some(joypad::ButtonA),
    sdl2::keycode::XKey      => Some(joypad::ButtonB),
    _ => None,
  }
}

#[deriving(PartialEq)]
enum State {
  Paused,
  Running,
  Step,
  Done,
}

fn main() {
  let args = std::os::args();
  if args.len() != 2 && !(args.len() == 3 && args[1] == "-d".to_string()) {
    println!("Usage: {:s} [-d] rom.gb", args[0]);
    return;
  }

  let mut disassemble = false;
  let path =
    if args.len() == 2 {
      &args[1]
    } else {
      disassemble = true;
      &args[2]
    };

  let mut cart = match cartridge::Cartridge::from_path(&Path::new(path.as_slice())) {
    Ok(cart) => box cart,
    Err(e)   => panic!("I/O error: {}", e),
  };

  if disassemble {
    // Disassemble only
    let mut d = disasm::Disasm { mem: &mut *cart, pc: 0 };
    while d.pc <= 0x7fff {
      let pc = d.pc;
      println!("${:04X}\t{:s}", pc, cpu::decode(&mut d));
    }
    return;
  }

  println!("Name: {:s}", cart.title);
  println!("Type: {:u}", cart.cartridge_type);

  let memmap = MemMap {
    cart: cart,
    wram: ram::WorkRam::new(),
    timer: timer::Timer::new(),
    intr: interrupt::InterruptCtrl::new(),
    sound: sound::Sound,
    video: video::Video::new(),
    serial: serial::SerialIO::new(Some(box stdio::stdout() as Box<std::io::Writer>)),
    joypad: joypad::Joypad::new(),
    dummy: Dummy,
  };
  let mut cpu = cpu::Cpu::new(memmap);
  cpu.regs.pc = 0x100;

  let video_out = VideoOut::new(4);
  video_out.set_title("Rustboy");

  let mut state = Paused;
  let mut debugger = debug::Debugger::new();

  let counts_per_sec = sdl2::timer::get_performance_frequency();
  let counts_per_frame = counts_per_sec * video::SCREEN_REFRESH_CYCLES as u64 / cpu::CYCLES_PER_SEC as u64;
  let mut last_frame_start_count = sdl2::timer::get_performance_counter();

  let mut last_fps_update = last_frame_start_count;
  let mut frames = 0;

  println!("c/s: {:u}; c/f: {:u}", counts_per_sec, counts_per_frame);

  while state != Done {
    if state == Paused || state == Step {
      match debugger.prompt(&mut cpu) {
        debug::Quit => break,
        debug::Run  => state = Running,
        debug::Step => state = Step,
      }
    }

    // Emulation loop
    loop {
      let cycles = cpu.step();

      match cpu.mem.timer.tick(cycles) {
        Some(timer::TIMAOverflow) => cpu.mem.intr.irq(interrupt::IRQ_TIMER),
        None => (),
      }

      let mut new_frame = false;
      let video_signals = cpu.mem.video.tick(cycles);
      for signal in video_signals.iter() {
        match *signal {
          video::DMA(base) => {
            // Do DMA transfer instantaneously
            let base_addr = base as u16 << 8;
            for offset in range(0x00u16, 0xa0u16) {
              let val = cpu.mem.loadb(base_addr + offset);
              cpu.mem.storeb(0xfe00 + offset, val);
            }
          },
          video::VBlank => {
            video_out.blit_and_present(cpu.mem.video.screen);
            cpu.mem.intr.irq(interrupt::IRQ_VBLANK);
            new_frame = true;
          }
          video::LCD    => cpu.mem.intr.irq(interrupt::IRQ_LCD),
        }
      }

      // Synchronize speed based on frame time
      if new_frame {
        let now = sdl2::timer::get_performance_counter();
        let frame_time = now - last_frame_start_count;
        if frame_time < counts_per_frame {
          let delay_msec = (1_000 * (counts_per_frame - frame_time) / counts_per_sec) as uint;
          sdl2::timer::delay(delay_msec);
        }
        // TODO: What should we do when we take longer than counts_per_frame?
        last_frame_start_count = sdl2::timer::get_performance_counter();

        frames += 1;
        if last_frame_start_count - last_fps_update > counts_per_sec {
          let fps = frames * (last_frame_start_count - last_fps_update) / counts_per_sec;
          video_out.set_title(format!("Rustboy - {} fps", fps).as_slice());
          last_fps_update = now;
          frames = 0;
        }

        // Exit emulation loop to handle events
        break;
      }

      if debugger.should_break(&cpu) {
        state = Paused;
        break;
      }

      if state == Step {
        // Stop emulation loop after one instruction
        break;
      }
    }

    // Event handling loop
    loop {
      match sdl2::event::poll_event() {
        sdl2::event::QuitEvent(_) => { state = Done; break }
        sdl2::event::KeyDownEvent(_, _, key, _, _) => {
          match keymap(key) {
            Some(button) => cpu.mem.joypad.set_button(button, true),
            None => {
              match key {
                sdl2::keycode::EscapeKey => { state = Paused },
                _ => (),
              }
            }
          }
        },
        sdl2::event::KeyUpEvent(_, _, key, _, _) => {
          match keymap(key) {
            Some(button) => cpu.mem.joypad.set_button(button, false),
            None => (),
          }
        }
        sdl2::event::NoEvent => break,
        _ => (),
      }
    }
  }
}
<|endoftext|>


<commit_before>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

use std::collections::HashMap;
use std::process;
use std::io::{self, Write};

extern crate cargo_metadata;

use std::path::{Path, PathBuf};

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit
    --all                    Run over all packages in the current workspace

Other options are the same as `cargo rustc`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    let mut manifest_path_arg = std::env::args()
        .skip(2)
        .skip_while(|val| !val.starts_with("--manifest-path"));
    let manifest_path_arg = manifest_path_arg.next().and_then(|val| {
        if val == "--manifest-path" {
            manifest_path_arg.next()
        } else if val.starts_with("--manifest-path=") {
            Some(val["--manifest-path=".len()..].to_owned())
        } else {
            None
        }
    });

    let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
        metadata
    } else {
        println!(
            "{:?}",
            cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))
        );
        let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
        process::exit(101);
    };

    let manifest_path = manifest_path_arg.map(|arg| {
        PathBuf::from(arg)
            .canonicalize()
            .expect("manifest path could not be canonicalized")
    });

    let packages = if std::env::args().any(|a| a == "--all") {
        metadata.packages
    } else {
        let package_index = {
            if let Some(manifest_path) = manifest_path {
                metadata.packages.iter().position(|package| {
                    let package_manifest_path = Path::new(&package.manifest_path)
                        .canonicalize()
                        .expect("package manifest path could not be canonicalized");
                    package_manifest_path == manifest_path
                })
            } else {
                let package_manifest_paths: HashMap<_, _> = metadata
                    .packages
                    .iter()
                    .enumerate()
                    .map(|(i, package)| {
                        let package_manifest_path = Path::new(&package.manifest_path)
                            .parent()
                            .expect("could not find parent directory of package manifest")
                            .canonicalize()
                            .expect("package directory cannot be canonicalized");
                        (package_manifest_path, i)
                    })
                    .collect();

                let current_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")
                    .expect("CARGO_MANIFEST_DIR not set"))
                    .canonicalize()
                    .expect("manifest directory cannot be canonicalized");

                let mut current_path: &Path = &current_dir;

                // This gets the most-recent parent (the one that takes the fewest `cd ..`s to
                // reach).
                loop {
                    if let Some(&package_index) = package_manifest_paths.get(current_path) {
                        break Some(package_index);
                    } else {
                        // We'll never reach the filesystem root, because to get to this point in the
                        // code
                        // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to
                        // unwrap the current path's parent.
                        current_path = current_path
                            .parent()
                            .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display()));
                    }
                }
            }
        }.expect("could not find matching package");

        vec![metadata.packages.remove(package_index)]
    };

    for package in packages {
        let manifest_path = package.manifest_path;

        for target in package.targets {
            let args = std::env::args()
                .skip(2)
                .filter(|a| a != "--all" && !a.starts_with("--manifest-path="));

            let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args);
            if let Some(first) = target.kind.get(0) {
                if target.kind.len() > 1 || first.ends_with("lib") {
                    println!("lib: {}", target.name);
                    if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
                        std::process::exit(code);
                    }
                } else if ["bin", "example", "test", "bench"].contains(&&**first) {
                    println!("{}: {}", first, target.name);
                    if let Err(code) = process(
                        vec![format!("--{}", first), target.name]
                            .into_iter()
                            .chain(args),
                    ) {
                        std::process::exit(code);
                    }
                }
            } else {
                panic!("badly formatted cargo metadata: target::kind is an empty array");
            }
        }
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-clippy""#.to_owned());

    let mut path = std::env::current_exe()
        .expect("current executable path invalid")
        .with_file_name("clippy-driver");
    if cfg!(windows) {
        path.set_extension("exe");
    }
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC_WRAPPER", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<commit_msg>Undo current_dir -> CARGO_MANIFEST_DIR move<commit_after>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

use std::collections::HashMap;
use std::process;
use std::io::{self, Write};

extern crate cargo_metadata;

use std::path::{Path, PathBuf};

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit
    --all                    Run over all packages in the current workspace

Other options are the same as `cargo rustc`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    let mut manifest_path_arg = std::env::args()
        .skip(2)
        .skip_while(|val| !val.starts_with("--manifest-path"));
    let manifest_path_arg = manifest_path_arg.next().and_then(|val| {
        if val == "--manifest-path" {
            manifest_path_arg.next()
        } else if val.starts_with("--manifest-path=") {
            Some(val["--manifest-path=".len()..].to_owned())
        } else {
            None
        }
    });

    let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
        metadata
    } else {
        println!(
            "{:?}",
            cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))
        );
        let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
        process::exit(101);
    };

    let manifest_path = manifest_path_arg.map(|arg| {
        PathBuf::from(arg)
            .canonicalize()
            .expect("manifest path could not be canonicalized")
    });

    let packages = if std::env::args().any(|a| a == "--all") {
        metadata.packages
    } else {
        let package_index = {
            if let Some(manifest_path) = manifest_path {
                metadata.packages.iter().position(|package| {
                    let package_manifest_path = Path::new(&package.manifest_path)
                        .canonicalize()
                        .expect("package manifest path could not be canonicalized");
                    package_manifest_path == manifest_path
                })
            } else {
                let package_manifest_paths: HashMap<_, _> = metadata
                    .packages
                    .iter()
                    .enumerate()
                    .map(|(i, package)| {
                        let package_manifest_path = Path::new(&package.manifest_path)
                            .parent()
                            .expect("could not find parent directory of package manifest")
                            .canonicalize()
                            .expect("package directory cannot be canonicalized");
                        (package_manifest_path, i)
                    })
                    .collect();

                let current_dir = std::env::current_dir()
                    .expect("CARGO_MANIFEST_DIR not set")
                    .canonicalize()
                    .expect("manifest directory cannot be canonicalized");

                let mut current_path: &Path = &current_dir;

                // This gets the most-recent parent (the one that takes the fewest `cd ..`s to
                // reach).
                loop {
                    if let Some(&package_index) = package_manifest_paths.get(current_path) {
                        break Some(package_index);
                    } else {
                        // We'll never reach the filesystem root, because to get to this point in the
                        // code
                        // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to
                        // unwrap the current path's parent.
                        current_path = current_path
                            .parent()
                            .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display()));
                    }
                }
            }
        }.expect("could not find matching package");

        vec![metadata.packages.remove(package_index)]
    };

    for package in packages {
        let manifest_path = package.manifest_path;

        for target in package.targets {
            let args = std::env::args()
                .skip(2)
                .filter(|a| a != "--all" && !a.starts_with("--manifest-path="));

            let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args);
            if let Some(first) = target.kind.get(0) {
                if target.kind.len() > 1 || first.ends_with("lib") {
                    println!("lib: {}", target.name);
                    if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
                        std::process::exit(code);
                    }
                } else if ["bin", "example", "test", "bench"].contains(&&**first) {
                    println!("{}: {}", first, target.name);
                    if let Err(code) = process(
                        vec![format!("--{}", first), target.name]
                            .into_iter()
                            .chain(args),
                    ) {
                        std::process::exit(code);
                    }
                }
            } else {
                panic!("badly formatted cargo metadata: target::kind is an empty array");
            }
        }
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-clippy""#.to_owned());

    let mut path = std::env::current_exe()
        .expect("current executable path invalid")
        .with_file_name("clippy-driver");
    if cfg!(windows) {
        path.set_extension("exe");
    }
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC_WRAPPER", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate serde_derive;

mod grammar;

use grammar::{TurtleParser, Rule};
use pest::{Parser, iterators, inputs};
use std::{fs, env};
use std::io::Read;

#[derive(Serialize, Deserialize)]
struct Result {
    rule: String,
    text: Option<String>,
    children: Vec<Result>,
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut file = fs::File::open(&args[1]).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents);

    let pairs = TurtleParser::parse_str(Rule::turtle_doc, &contents)
        .unwrap_or_else(|e| panic!("{}", e));
    let mut result = Vec::new();
    create_result_from_pairs(pairs, &mut result);
    println!("{}", serde_json::to_string(&result).unwrap());
}

fn create_result_from_pairs(
    pairs: iterators::Pairs<grammar::Rule, inputs::StrInput>,
    result: &mut Vec<Result>,
) {
    for pair in pairs {
        let rule = format!("{:?}", pair.as_rule());
        let text = String::from(pair.as_str());
        let mut children = Vec::new();
        create_result_from_pairs(pair.into_inner(), &mut children);
        result.push(Result {
            rule,
            text: if children.len() == 0 {
                Some(text)
            } else {
                None
            },
            children,
        });
    }
}
<commit_msg>Add parse function<commit_after>extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate serde_derive;

mod grammar;

use grammar::{TurtleParser, Rule};
use pest::{Parser, iterators, inputs};
use std::{fs, env};
use std::io::Read;

#[derive(Serialize, Deserialize)]
struct Result {
    rule: String,
    text: Option<String>,
    children: Vec<Result>,
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut file = fs::File::open(&args[1]).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents);

    let mut result = Vec::new();
    parse(&contents, &mut result);
    println!("{}", serde_json::to_string(&result).unwrap());
}

fn parse(contents: &String, result: &mut Vec<Result>) {
    let pairs = TurtleParser::parse_str(Rule::turtle_doc, &contents)
        .unwrap_or_else(|e| panic!("{}", e));
    create_result_from_pairs(pairs, result);
}

fn create_result_from_pairs(
    pairs: iterators::Pairs<grammar::Rule, inputs::StrInput>,
    result: &mut Vec<Result>,
) {
    for pair in pairs {
        let rule = format!("{:?}", pair.as_rule());
        let text = String::from(pair.as_str());
        let mut children = Vec::new();
        create_result_from_pairs(pair.into_inner(), &mut children);
        result.push(Result {
            rule,
            text: if children.len() == 0 {
                Some(text)
            } else {
                None
            },
            children,
        });
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}

#[test]
fn it_works() {
}
<commit_msg>added another example test<commit_after>fn main() {
    println!("Hello, world!");
}

#[test]
fn it_works() {
}

pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[test]
fn it_works() {
    assert_eq!(4, add_two(2));
}
<|endoftext|>


<commit_before>extern crate websocat;

extern crate futures;
extern crate tokio_core;
extern crate tokio_stdin_stdout;

extern crate env_logger;

#[macro_use]
extern crate structopt;

use structopt::StructOpt;

use tokio_core::reactor::{Core};
use websocat::{spec, WebsocatConfiguration};

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

#[derive(StructOpt, Debug)]
#[structopt(after_help = "
Some examples:
  Connect stdin/stdout to a websocket:
    websocat - ws://echo.websocket.org/

  Listen websocket and redirect it to a TCP port:
    websocat ws-l:127.0.0.1:8080 tcp:127.0.0.1:5678

  See more examples at the bottom

Full list of specifiers:
  `-` -- Stdin/stdout
    Read input from console, print to console.
    Can be specified only one time.
    Aliases: `stdio:`, `inetd:`

    `inetd:` also disables logging to stderr.

    Example: like `cat(1)`.
      websocat - -

    Example: for inetd mode
      websocat inetd: literal:$'Hello, world.\n'

  `ws://<url>`, `wss://<url>` -- WebSocket client
    Example: forward port 4554 to a websocket
      websocat tcp-l:127.0.0.1:4554 wss://127.0.0.1/some_websocket

  `ws-listen:<spec>` - Listen for websocket connections
    A combining specifier, but given IPv4 address as argument auto-inserts `tcp-l:`
    Aliases: `listen-ws:` `ws-l:` `l-ws:`

    Example:
        websocat ws-l:127.0.0.1:8808 -

    Example: the same, but more verbose:
        websocat ws-l:tcp-l:127.0.0.1:8808 reuse:-

  `inetd-ws:` - Alias of `ws-l:inetd:`

    Example of inetd.conf line:
      1234 stream tcp nowait myuser  /opt/websocat websocat inetd-ws: tcp:127.0.0.1:22

  `tcp:<hostport>` - connect to specified TCP host and port
    Aliases: `tcp-connect:`,`connect-tcp:`,`c-tcp:`,`tcp-c:`

    Example: like netcat
      websocat - tcp:127.0.0.1:22

    Example: IPv6
      websocat - tcp:[::1]:22

  `tcp-l:<hostport>` - listen TCP port on specified address
    Aliases: `l-tcp:`  `tcp-listen:` `listen-tcp:`

    Example: echo server
      websocat tcp-l:0.0.0.0:1441 mirror:

  `ws-connect:<spec>` - low-level WebSocket connector
    A combining specifier. Underlying specifier is should be after the colon.
    URL and Host: header being sent are independent from underlying specifier
    Aliases: `ws-c:` `c-ws:` `connect-ws:`

    Example:
      websocat - ws-c:tcp:127.0.0.1:8808

  `autoreconnect:<spec>` - Auto-reconnector
    Re-establish underlying specifier on any error or EOF

    Example: keep connecting to the port or spin 100% CPU trying if it is closed.
      websocat - autoreconnect:tcp:127.0.0.1:5445

    TODO: implement timeouts

  `reuse:<spec>` - Reuse one connection for serving multiple clients
    Better suited for unidirectional connections

    Example (unreliable): don't disconnect SSH when websocket reconnects
      websocat ws-l:[::]:8088 reuse:tcp:127.0.0.1:22

  `threadedstdio:` - Stdin/stdout, spawning a thread
    Like `-`, but forces threaded mode instead of async mode
    Use when standard input is not `epoll(7)`-able.
    Replaces `-` when `no_unix_stdio` Cargo feature is activated

  `mirror:` - Simply copy output to input

  `clogged:` - Do nothing
    Don't read or write any bytes. Keep connections hanging.

  `literal:<string>` - Output a string, discard input.
    Ignore all input, use specified string as output.

  `literalreply:<string>` - Reply with this string for each input packet

  `assert:<string>` - Check the input.
    Read entire input and panic the program if the input is not equal
    to the specified string.

  TODO:
  `exec:`, `unix-l:`

More examples:
  Wacky mode:
    websocat ws-l:ws-l:ws-c:- tcp:127.0.0.1:5678

    Connect to a websocket using stdin/stdout as a transport,
    then accept a websocket connection over this previous websocket as a transport,
    then connect to a websocket using previous step as a transport,
    then forward resulting connection to the TCP port.

    (Excercise to the reader: manage to actually connect to it).
")]
struct Opt {
    /// First, "listening" specifier
    s1: String,
    /// Second, "connecting" specifier
    s2: String,

    #[structopt(short = "u", long = "unidirectional")]
    unidirectional: bool,
    #[structopt(short = "U", long = "unidirectional-reverse")]
    unidirectional_reverse: bool,

    #[structopt(short = "t", long = "text", help="Send text WebSocket messages instead of binary")]
    text_mode: bool,

    #[structopt(long="oneshot", help="Serve only once")]
    oneshot: bool,
}

fn run() -> Result<()> {
    let cmd = Opt::from_args();

    if false
        || cmd.text_mode
        || cmd.unidirectional
        || cmd.unidirectional_reverse
        || cmd.oneshot {
        Err("This mode is not implemented")?
    }

    let opts = Default::default();

    let s1 = spec(&cmd.s1)?;
    let s2 = spec(&cmd.s2)?;

    let mut websocat = WebsocatConfiguration { opts, s1, s2 };

    while let Some(concern) = websocat.get_concern() {
        use websocat::ConfigurationConcern::*;
        if concern == StdinToStdout {
            // Degenerate mode: just copy stdin to stdout and call it a day
            ::std::io::copy(&mut ::std::io::stdin(), &mut ::std::io::stdout())?;
            return Ok(())
        }

        if concern == StdioConflict {
            Err("Too many usages of stdin/stdout")?;
        }

        if concern == NeedsStdioReuser {
            //Err("Stdin/stdout is used without a `reuse:` overlay.")?;
            eprintln!("Warning: replies on stdio get directed at random connected client");
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == MultipleReusers {
            eprintln!("Specifier dump: {:?} {:?}", websocat.s1, websocat.s2);
            Err("Multiple reusers is not allowed")?;
        }
        break;
    }

    let mut core = Core::new()?;

    let prog = websocat.serve(core.handle(), std::rc::Rc::new(|e| {
        eprintln!("websocat: {}", e);
    }));
    core.run(prog).map_err(|()|"error running".to_string())?;
    Ok(())
}

fn main() {
    env_logger::init();
    let r = run();

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<commit_msg>Split help messages into two<commit_after>extern crate websocat;

extern crate futures;
extern crate tokio_core;
extern crate tokio_stdin_stdout;

extern crate env_logger;

#[macro_use]
extern crate structopt;

use structopt::StructOpt;

use tokio_core::reactor::{Core};
use websocat::{spec, WebsocatConfiguration};

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

#[derive(StructOpt, Debug)]
#[structopt(after_help = "
Basic examples:
  Connect stdin/stdout to a websocket:
    websocat - ws://echo.websocket.org/

  Listen websocket and redirect it to a TCP port:
    websocat ws-l:127.0.0.1:8080 tcp:127.0.0.1:5678

  See more examples with the --long-help option

Short list of specifiers (see --long-help):
  ws:// wss:// - inetd: ws-listen: inetd-ws: tcp: tcp-l: ws-c:
  autoreconnect: reuse: mirror: threadedstdio: clogged:
  literal: literalreply: assert:
")]
struct Opt {
    /// First, listening/connecting specifier. See --long-help for info about specifiers.
    s1: String,
    /// Second, connecting specifier
    s2: String,

    #[structopt(short = "u", long = "unidirectional")]
    unidirectional: bool,
    #[structopt(short = "U", long = "unidirectional-reverse")]
    unidirectional_reverse: bool,

    #[structopt(short = "t", long = "text", help="Send text WebSocket messages instead of binary")]
    text_mode: bool,

    #[structopt(long="oneshot", help="Serve only once")]
    oneshot: bool,

    #[structopt(long="long-help", help="Show full help aboput specifiers and examples")]
    longhelp: bool,
}

fn longhelp() {
    println!("(see also usual --help message)

Full list of specifiers:
  `-` -- Stdin/stdout
    Read input from console, print to console.
    Can be specified only one time.
    Aliases: `stdio:`, `inetd:`

    `inetd:` also disables logging to stderr.

    Example: like `cat(1)`.
      websocat - -

    Example: for inetd mode
      websocat inetd: literal:$'Hello, world.\n'

  `ws://<url>`, `wss://<url>` -- WebSocket client
    Example: forward port 4554 to a websocket
      websocat tcp-l:127.0.0.1:4554 wss://127.0.0.1/some_websocket

  `ws-listen:<spec>` - Listen for websocket connections
    A combining specifier, but given IPv4 address as argument auto-inserts `tcp-l:`
    Aliases: `listen-ws:` `ws-l:` `l-ws:`

    Example:
        websocat ws-l:127.0.0.1:8808 -

    Example: the same, but more verbose:
        websocat ws-l:tcp-l:127.0.0.1:8808 reuse:-

  `inetd-ws:` - Alias of `ws-l:inetd:`

    Example of inetd.conf line:
      1234 stream tcp nowait myuser  /opt/websocat websocat inetd-ws: tcp:127.0.0.1:22

  `tcp:<hostport>` - connect to specified TCP host and port
    Aliases: `tcp-connect:`,`connect-tcp:`,`c-tcp:`,`tcp-c:`

    Example: like netcat
      websocat - tcp:127.0.0.1:22

    Example: IPv6
      websocat - tcp:[::1]:22

  `tcp-l:<hostport>` - listen TCP port on specified address
    Aliases: `l-tcp:`  `tcp-listen:` `listen-tcp:`

    Example: echo server
      websocat tcp-l:0.0.0.0:1441 mirror:

  `ws-connect:<spec>` - low-level WebSocket connector
    A combining specifier. Underlying specifier is should be after the colon.
    URL and Host: header being sent are independent from underlying specifier
    Aliases: `ws-c:` `c-ws:` `connect-ws:`

    Example:
      websocat - ws-c:tcp:127.0.0.1:8808

  `autoreconnect:<spec>` - Auto-reconnector
    Re-establish underlying specifier on any error or EOF

    Example: keep connecting to the port or spin 100% CPU trying if it is closed.
      websocat - autoreconnect:tcp:127.0.0.1:5445

    TODO: implement timeouts

  `reuse:<spec>` - Reuse one connection for serving multiple clients
    Better suited for unidirectional connections

    Example (unreliable): don't disconnect SSH when websocket reconnects
      websocat ws-l:[::]:8088 reuse:tcp:127.0.0.1:22

  `threadedstdio:` - Stdin/stdout, spawning a thread
    Like `-`, but forces threaded mode instead of async mode
    Use when standard input is not `epoll(7)`-able.
    Replaces `-` when `no_unix_stdio` Cargo feature is activated

  `mirror:` - Simply copy output to input

  `clogged:` - Do nothing
    Don't read or write any bytes. Keep connections hanging.

  `literal:<string>` - Output a string, discard input.
    Ignore all input, use specified string as output.

  `literalreply:<string>` - Reply with this string for each input packet

  `assert:<string>` - Check the input.
    Read entire input and panic the program if the input is not equal
    to the specified string.

  TODO:
  `exec:`, `unix-l:`

More examples:
  Wacky mode:
    websocat ws-l:ws-l:ws-c:- tcp:127.0.0.1:5678

    Connect to a websocket using stdin/stdout as a transport,
    then accept a websocket connection over this previous websocket as a transport,
    then connect to a websocket using previous step as a transport,
    then forward resulting connection to the TCP port.

    (Excercise to the reader: manage to actually connect to it).
");
}

fn run() -> Result<()> {
    if std::env::args().nth(1).unwrap_or_default() == "--long-help" {
        longhelp();
        return Ok(());
    }

    let cmd = Opt::from_args();

    if cmd.longhelp {
        longhelp();
        return Ok(());
    }

    if false
        || cmd.text_mode
        || cmd.unidirectional
        || cmd.unidirectional_reverse
        || cmd.oneshot {
        Err("This mode is not implemented")?
    }

    let opts = Default::default();

    let s1 = spec(&cmd.s1)?;
    let s2 = spec(&cmd.s2)?;

    let mut websocat = WebsocatConfiguration { opts, s1, s2 };

    while let Some(concern) = websocat.get_concern() {
        use websocat::ConfigurationConcern::*;
        if concern == StdinToStdout {
            // Degenerate mode: just copy stdin to stdout and call it a day
            ::std::io::copy(&mut ::std::io::stdin(), &mut ::std::io::stdout())?;
            return Ok(())
        }

        if concern == StdioConflict {
            Err("Too many usages of stdin/stdout")?;
        }

        if concern == NeedsStdioReuser {
            //Err("Stdin/stdout is used without a `reuse:` overlay.")?;
            eprintln!("Warning: replies on stdio get directed at random connected client");
            websocat = websocat.auto_install_reuser();
            continue;
        }

        if concern == MultipleReusers {
            eprintln!("Specifier dump: {:?} {:?}", websocat.s1, websocat.s2);
            Err("Multiple reusers is not allowed")?;
        }
        break;
    }

    let mut core = Core::new()?;

    let prog = websocat.serve(core.handle(), std::rc::Rc::new(|e| {
        eprintln!("websocat: {}", e);
    }));
    core.run(prog).map_err(|()|"error running".to_string())?;
    Ok(())
}

fn main() {
    env_logger::init();
    let r = run();

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::fs::File;
use std::io::SeekFrom;
use std::io::Seek;
use std::io::Read;
use std::io::Write;
use std::io::Take;
use std::io::Error;
use std::io::ErrorKind;
use std::collections::HashMap;
use std::env;
use std::cmp;
use std::path::Path;

static __VERSION__: &str = "0.1.2";

fn advance_magic(magic: &mut u32) -> u32 {
    let old = *magic;
    *magic = magic.wrapping_mul(7) + 3;
    return old;
}

fn ru32(stream: &mut File, result: &mut u32) -> bool {
    let mut buff = [0; 4];
    if let Err(_) = stream.read_exact(&mut buff) {
        return false;
    }

    *result = (((buff[0] as u32) << 0x00) & 0x000000FF) |
              (((buff[1] as u32) << 0x08) & 0x0000FF00) |
              (((buff[2] as u32) << 0x10) & 0x00FF0000) |
              (((buff[3] as u32) << 0x18) & 0xFF000000) ;

    return true;
}

struct EntryData {
    offset: u32,
    magic: u32,
    size: u32,
}

struct Entry {
    offset: u32,
    magic: u32,
    stream: Take<File>,
}

impl Entry {
    fn read(&mut self, buf: &mut [u8]) -> usize {
        let mut maski = self.offset % 4;
        let mut offset = 0;
        let count = self.stream.read(buf).unwrap();
        let pre = ((4 - maski) % 4) as usize;

        self.offset += count as u32;

        for _ in 0..cmp::min(pre, count) {
            buf[offset] ^= ((self.magic >> (maski * 8)) & 0xff) as u8;
            maski += 1; offset += 1;
            if maski % 4 == 0 {
                advance_magic(&mut self.magic);
                maski = 0;
            }
        }

        if maski != 0 { return count; }

        unsafe {
            let len = (count - pre) / 4;
            let dat = buf[..len*4].as_mut_ptr() as *mut u32;

            for i in 0..(len as isize) {
                *dat.offset(i) = *dat.offset(i) ^ advance_magic(&mut self.magic);
            }

            offset += len * 4;
        }

        for _ in 0..(count%4) {
            buf[offset] ^= ((self.magic >> (maski * 8)) & 0xff) as u8;
            maski += 1; offset += 1;
            if maski % 4 == 0 {
                advance_magic(&mut self.magic);
                maski = 0;
            }
        }

        return count;
    }
}

struct RGSSArchive {
    entry: HashMap<String, EntryData>,
    stream: File,
}

impl RGSSArchive {
    fn open(location: &str) -> Result<RGSSArchive, Error> {
        let mut stream = File::open(location)?;

        let mut header = [0u8; 8];
        stream.read_exact(&mut header)?;

        match String::from_utf8(header[..6].to_vec()) {
            Ok(header) => {
                if header != "RGSSAD" {
                    return Err(Error::new(ErrorKind::InvalidData, "File header mismatch."));
                }
            },
            Err(_) => return Err(Error::new(ErrorKind::InvalidData, "File header mismatch."))
        }

        // Check rgssad file version.
        if header[7] < 3 { RGSSArchive::open_rgssad(stream) } else { RGSSArchive::open_rgss3a(stream) }
    }

    fn open_rgssad(mut stream: File) -> Result<RGSSArchive, Error> {
        let mut magic = 0xDEADCAFEu32;
        let mut entry = HashMap::new();

        loop {
            let mut name_len: u32 = 0;
            let resp = ru32(&mut stream, &mut name_len);
            if !resp { break }
            name_len ^= advance_magic(&mut magic);

            let mut name_buf = vec![0u8; name_len as usize];
            stream.read_exact(&mut name_buf)?;
            for i in 0..(name_len as usize) {
                name_buf[i] ^= (advance_magic(&mut magic) & 0xff) as u8;
                if name_buf[i] == '\\' as u8 { name_buf[i] = '/' as u8 }
            }
            let name_buf = String::from_utf8(name_buf).unwrap();

            let mut data = EntryData { size: 0, offset: 0, magic: 0 };
            ru32(&mut stream, &mut data.size);
            data.size ^= advance_magic(&mut magic);
            data.offset = stream.seek(SeekFrom::Current(0))? as u32;
            data.magic = magic;

            stream.seek(SeekFrom::Current(data.size as i64))?;
            entry.insert(name_buf, data);
        }

        stream.seek(SeekFrom::Start(0))?;
        return Ok(RGSSArchive { entry: entry, stream: stream });
    }

    fn open_rgss3a(mut stream: File) -> Result<RGSSArchive, Error> {
        let mut magic = 0u32;
        let mut entry = HashMap::new();

        ru32(&mut stream, &mut magic);
        magic = magic * 9 + 3;

        loop {
            let mut offset: u32 = 0;
            let mut size: u32 = 0;
            let mut start_magic: u32 = 0;
            let mut name_len: u32 = 0;

            let resp = ru32(&mut stream, &mut offset);
            if !resp { break }
            offset ^= magic;

            if offset == 0 { break }

            let resp = ru32(&mut stream, &mut size);
            if !resp { break }
            size ^= magic;

            let resp = ru32(&mut stream, &mut start_magic);
            if !resp { break }
            start_magic ^= magic;

            let resp = ru32(&mut stream, &mut name_len);
            if !resp { break }
            name_len ^= magic;

            let mut name_buf = vec![0u8; name_len as usize];
            stream.read_exact(&mut name_buf)?;
            for i in 0..(name_len as usize) {
                name_buf[i] ^= ((magic >> 8*(i%4)) & 0xff) as u8;
                if name_buf[i] == '\\' as u8 { name_buf[i] = '/' as u8 }
            }
            let name_buf = String::from_utf8(name_buf).unwrap();

            let data = EntryData {
                size: size, offset: offset, magic: start_magic
            };

            entry.insert(name_buf, data);
        }

        stream.seek(SeekFrom::Start(0))?;
        return Ok(RGSSArchive { entry: entry, stream: stream });
    }

    fn read_entry(&self, key: &str) -> Option<Entry> {
        match self.entry.get(key) {
            Some(entry) => {
                let mut stream = self.stream.try_clone().unwrap();
                stream.seek(SeekFrom::Start(entry.offset as u64)).unwrap();
                Some(Entry {
                    offset: 0,
                    magic: entry.magic,
                    stream: stream.take(entry.size as u64),
                })
            }
            None => None
        }
    }
}

fn usage() {
    println!("Extract rgssad/rgss2a/rgss3a files.\n");
    println!("Commands:");
    println!("    version");
    println!("    list        <filename>");
    println!("    save        <filename> <location>");
}

fn create(location: String) -> File {
    let path = Path::new(location.as_str());
    fs::create_dir_all(path.parent().unwrap()).unwrap();
    return File::create(path.to_str().unwrap()).unwrap();
}

fn main() {
    let args: Vec<String> = env::args().collect();
    match args.len() {
        1 => usage(),
        2 => {
            if args[1] != "version" { usage(); return; }
            println!("version: {}", __VERSION__);
        },
        3 => {
            if args[1] != "list" { usage(); return; }
            match RGSSArchive::open(args[2].as_str()) {
                Ok(archive) => {
                    for (name, data) in &archive.entry {
                        println!("{}: EntryData {{ size: {}, offset: {}, magic: {} }}", name, data.size, data.offset, data.magic);
                    }
                },
                Err(err) => println!("FAILED: {}", err.to_string())
            }
        },
        4 => {
            if args[1] != "save" { usage(); return; }
            let archive = RGSSArchive::open(args[2].as_str());
            if let Err(err) = archive {
                println!("FAILED: {}", err.to_string()); return;
            }
            let archive = archive.unwrap();
            let entries = archive.entry.iter();

            let mut buf = [0u8; 8192];

            for (name, _) in entries {
                println!("Extracting: {}", name);
                let mut entry = archive.read_entry(name).unwrap();
                let mut file = create(args[3].clone() + &"/".to_string() + &name.to_string());
                loop {
                    let count = entry.read(&mut buf);
                    if count == 0 { break }
                    file.write(&buf[..count]).unwrap();
                }
            }
        },
        _ => usage(),
    }
}
<commit_msg>Update error handling.<commit_after>use std::fs;
use std::fs::File;
use std::io::SeekFrom;
use std::io::Seek;
use std::io::Read;
use std::io::Write;
use std::io::Take;
use std::io::Error;
use std::io::ErrorKind;
use std::collections::HashMap;
use std::env;
use std::cmp;
use std::path::Path;

static __VERSION__: &str = "0.1.2";

fn advance_magic(magic: &mut u32) -> u32 {
    let old = *magic;
    *magic = magic.wrapping_mul(7) + 3;
    return old;
}

fn ru32(stream: &mut File, result: &mut u32) -> bool {
    let mut buff = [0; 4];
    if let Err(_) = stream.read_exact(&mut buff) {
        return false;
    }

    *result = (((buff[0] as u32) << 0x00) & 0x000000FF) |
              (((buff[1] as u32) << 0x08) & 0x0000FF00) |
              (((buff[2] as u32) << 0x10) & 0x00FF0000) |
              (((buff[3] as u32) << 0x18) & 0xFF000000) ;

    return true;
}

struct EntryData {
    offset: u32,
    magic: u32,
    size: u32,
}

struct Entry {
    offset: u32,
    magic: u32,
    stream: Take<File>,
}

impl Entry {
    fn read(&mut self, buf: &mut [u8]) -> usize {
        let mut maski = self.offset % 4;
        let mut offset = 0;
        let count = self.stream.read(buf).unwrap();
        let pre = ((4 - maski) % 4) as usize;

        self.offset += count as u32;

        for _ in 0..cmp::min(pre, count) {
            buf[offset] ^= ((self.magic >> (maski * 8)) & 0xff) as u8;
            maski += 1; offset += 1;
            if maski % 4 == 0 {
                advance_magic(&mut self.magic);
                maski = 0;
            }
        }

        if maski != 0 { return count; }

        unsafe {
            let len = (count - pre) / 4;
            let dat = buf[..len*4].as_mut_ptr() as *mut u32;

            for i in 0..(len as isize) {
                *dat.offset(i) = *dat.offset(i) ^ advance_magic(&mut self.magic);
            }

            offset += len * 4;
        }

        for i in 0..(count%4) {
            buf[offset + i] ^= ((self.magic >> (maski * 8)) & 0xff) as u8;
        }

        return count;
    }
}

struct RGSSArchive {
    entry: HashMap<String, EntryData>,
    stream: File,
}

impl RGSSArchive {
    fn open(location: &str) -> Result<RGSSArchive, Error> {
        let mut stream = File::open(location)?;

        let mut header = [0u8; 8];
        stream.read_exact(&mut header)?;

        if let Err(_) | (Ok(header) if header != "RGSSAD") = String::from_utf8(header[..6].to_vec()) {
            return Err(Error::new(ErrorKind::InvalidData, "File header mismatch."));
        }

        // Check rgssad file version.
        match header[7] {
            1..2 => RGSSArchive::open_rgssad(stream),
               3 => RGSSArchive::open_rgss3a(stream),
               _ => Err(Error::new(ErrorKind::InvalidData, format!("RGSSArchive file version:{} is not support.", header[7])),
        }
    }

    fn open_rgssad(mut stream: File) -> Result<RGSSArchive, Error> {
        let mut magic = 0xDEADCAFEu32;
        let mut entry = HashMap::new();

        loop {
            let mut name_len: u32 = 0;
            let resp = ru32(&mut stream, &mut name_len);
            if !resp { break }
            name_len ^= advance_magic(&mut magic);

            let mut name_buf = vec![0u8; name_len as usize];
            stream.read_exact(&mut name_buf)?;
            for i in 0..(name_len as usize) {
                name_buf[i] ^= (advance_magic(&mut magic) & 0xff) as u8;
                if name_buf[i] == '\\' as u8 { name_buf[i] = '/' as u8 }
            }
            let name_buf = String::from_utf8(name_buf);
            if let Err(_) = name_buf { break }
            let name_buf = name_buf.unwrap();

            let mut data = EntryData { size: 0, offset: 0, magic: 0 };
            ru32(&mut stream, &mut data.size);
            data.size ^= advance_magic(&mut magic);
            data.offset = stream.seek(SeekFrom::Current(0))? as u32;
            data.magic = magic;

            stream.seek(SeekFrom::Current(data.size as i64))?;
            entry.insert(name_buf, data);
        }

        stream.seek(SeekFrom::Start(0))?;
        return Ok(RGSSArchive { entry: entry, stream: stream });
    }

    fn open_rgss3a(mut stream: File) -> Result<RGSSArchive, Error> {
        let mut magic = 0u32;
        let mut entry = HashMap::new();

        if !ru32(&mut stream, &mut magic) {
            return Err::New(ErrorKind::InvalidData, format!("Magic number read failed, {:?}",));
        }
        magic = magic * 9 + 3;

        loop {
            let mut offset: u32 = 0;
            let mut size: u32 = 0;
            let mut start_magic: u32 = 0;
            let mut name_len: u32 = 0;

            let resp = ru32(&mut stream, &mut offset);
            if !resp { break }
            offset ^= magic;

            if offset == 0 { break }

            let resp = ru32(&mut stream, &mut size);
            if !resp { break }
            size ^= magic;

            let resp = ru32(&mut stream, &mut start_magic);
            if !resp { break }
            start_magic ^= magic;

            let resp = ru32(&mut stream, &mut name_len);
            if !resp { break }
            name_len ^= magic;

            let mut name_buf = vec![0u8; name_len as usize];
            stream.read_exact(&mut name_buf)?;
            for i in 0..(name_len as usize) {
                name_buf[i] ^= ((magic >> 8*(i%4)) & 0xff) as u8;
                if name_buf[i] == '\\' as u8 { name_buf[i] = '/' as u8 }
            }
            let name_buf = String::from_utf8(name_buf);
            if let Err(_) = name_buf { break }
            let name_buf = name_buf.unwrap();

            let data = EntryData {
                size: size, offset: offset, magic: start_magic
            };

            entry.insert(name_buf, data);
        }

        stream.seek(SeekFrom::Start(0))?;
        return Ok(RGSSArchive { entry: entry, stream: stream });
    }

    fn read_entry(&self, key: &str) -> Reault<Entry, Error> {
        match self.entry.get(key) {
            Some(entry) => {
                let mut stream = self.stream.try_clone()?;
                stream.seek(SeekFrom::Start(entry.offset as u64))?;
                Ok(Entry {
                    offset: 0,
                    magic: entry.magic,
                    stream: stream.take(entry.size as u64),
                })
            }
            None => Err::New(ErrorKind::InvalidData, "key not found."),
        }
    }
}

fn usage() {
    println!("Extract rgssad/rgss2a/rgss3a files.\n");
    println!("Commands:");
    println!("    version");
    println!("    list        <filename>");
    println!("    save        <filename> <location>");
}

fn create(location: String) -> File {
    let path = Path::new(location.as_str());
    fs::create_dir_all(path.parent().unwrap()).unwrap();
    return File::create(path.to_str().unwrap()).unwrap();
}

fn main() {
    let args: Vec<String> = env::args().collect();
    match args.len() {
        1 => usage(),
        2 => {
            if args[1] != "version" { usage(); return; }
            println!("version: {}", __VERSION__);
        },
        3 => {
            if args[1] != "list" { usage(); return; }
            match RGSSArchive::open(args[2].as_str()) {
                Ok(archive) => {
                    for (name, data) in &archive.entry {
                        println!("{}: EntryData {{ size: {}, offset: {}, magic: {} }}", name, data.size, data.offset, data.magic);
                    }
                },
                Err(err) => println!("FAILED: {}", err.to_string())
            }
        },
        4 => {
            if args[1] != "save" { usage(); return; }
            let archive = RGSSArchive::open(args[2].as_str());
            if let Err(err) = archive {
                println!("FAILED: {}", err.to_string()); return;
            }
            let archive = archive.ok();
            let entries = archive.entry.iter();

            let mut buf = [0u8; 8192];

            for (name, _) in entries {
                println!("Extracting: {}", name);
                let mut entry = archive.read_entry(name);
                if let Err(err) = entry {
                    println!("FAILED: {}", err.to_string()); return;
                }
                let entry = entry.ok();
                let mut file = create(args[3].clone() + &"/".to_string() + &name.to_string());
                loop {
                    let count = entry.read(&mut buf);
                    if count == 0 { break }
                    file.write(&buf[..count]).unwrap();
                }
            }
        },
        _ => usage(),
    }
}
<|endoftext|>