<commit_before>extern crate crypto;
extern crate byteorder;
extern crate rand;

use crypto::digest::Digest;
use crypto::sha2::Sha256;
use crypto::hmac::Hmac;
use crypto::mac::{Mac};
use crypto::aes::KeySize;
use crypto::aes_gcm::AesGcm;
use crypto::aead::{AeadEncryptor, AeadDecryptor};
use crypto::curve25519::{curve25519, curve25519_base};

use byteorder::{ByteOrder, BigEndian};
use rand::{OsRng, Rng};

const DHLEN : usize = 32;
const HASHLEN : usize = 32;
//const BLOCKLEN : usize = 64;
const MACLEN : usize = 16;
const CIPHERKEYLEN : usize = 32;

fn copy_memory(data: &[u8], out: &mut [u8]) {
    for count in 0..data.len() {out[count] = data[count];}
}

pub struct KeyPair {
    privkey: [u8; DHLEN],
    pubkey: [u8; DHLEN]
}

pub fn generate_keypair() -> KeyPair {
    let mut privkey = [0u8; 32];
    let mut rng = OsRng::new().unwrap();
    rng.fill_bytes(&mut privkey);
    privkey[0] &= 248;
    privkey[31] &= 127;
    privkey[31] |= 64;
    let pubkey = curve25519_base(&privkey);
    KeyPair{privkey : privkey, pubkey : pubkey}
}

fn dh(keypair : &KeyPair, pubkey: &[u8]) -> [u8; DHLEN] {
    curve25519(&keypair.privkey, pubkey)
}

fn hash(data: &[u8], out: &mut [u8]) {
    let mut h = Sha256::new();
    h.input(data);
    h.result(out);
}

fn hmac_hash(key: &[u8], data: &[u8], out: &mut [u8]) {
    let mut hmac = Hmac::new(Sha256::new(), key);
    hmac.input(data);
    hmac.raw_result(out);
}

fn hkdf(chaining_key: &[u8], data: &[u8], out: &mut [u8]) {
    let mut temp_key = [0u8; HASHLEN];
    let mut in2 = [0u8; HASHLEN+1];
    hmac_hash(chaining_key, data, &mut temp_key);
    hmac_hash(&temp_key, &[1u8], &mut out[0..HASHLEN]);
    copy_memory(&out[0..HASHLEN], &mut in2);
    in2[HASHLEN] = 2;
    hmac_hash(&temp_key, &in2, &mut out[HASHLEN..2*HASHLEN]);
}

fn encrypt(key: &[u8], nonce: u64, authtext: &[u8], plaintext: &[u8], out: &mut[u8]) {
    let mut nonce_bytes = [0u8; 12];
    BigEndian::write_u64(&mut nonce_bytes[4..], nonce);
    let mut cipher = AesGcm::new(KeySize::KeySize256, key, &nonce_bytes, authtext);
    let mut tag = [0u8; MACLEN];
    cipher.encrypt(plaintext, &mut out[..plaintext.len()], &mut tag);
    copy_memory(&tag, &mut out[plaintext.len()..]);
}

fn decrypt(key: &[u8], nonce: u64, authtext: &[u8], ciphertext: &[u8], out: &mut[u8]) -> bool {
    let mut nonce_bytes = [0u8; 12];
    BigEndian::write_u64(&mut nonce_bytes[4..], nonce);
    let mut cipher = AesGcm::new(KeySize::KeySize256, key, &nonce_bytes, authtext);
    let text_len = ciphertext.len() - MACLEN;
    let mut tag = [0u8; MACLEN];
    copy_memory(&ciphertext[text_len..], &mut tag);
    cipher.decrypt(&ciphertext[..text_len], &mut out[..text_len], &tag)
}

pub enum Token {E, S, Dhee, Dhes, Dhse, Dhss}

pub enum NoiseError {DecryptError}

pub struct CipherState {
    k: [u8; CIPHERKEYLEN],
    n: u64
}

struct SymmetricState {
    cipherstate : CipherState,
    has_key : bool,
    ck: [u8; HASHLEN],
    h: [u8; HASHLEN]
}

pub struct HandshakeState {
    symmetricstate: SymmetricState,
    s: KeyPair,
    e: KeyPair,
    rs: [u8; DHLEN],
    re: [u8; DHLEN],
}

impl CipherState {

    pub fn encrypt_and_increment(&mut self, authtext: &[u8], plaintext: &[u8], out: &mut [u8]) {
        encrypt(&self.k, self.n, authtext, plaintext, out);
        self.n += 1;
    }

    pub fn decrypt_and_increment(&mut self, authtext: &[u8], ciphertext: &[u8], out: &mut [u8]) -> bool {
        if !decrypt(&self.k, self.n, authtext, ciphertext, out) {
            self.n += 1;
            return false;
        }
        self.n += 1;
        true
    }
}

impl SymmetricState {

    fn new(handshake_name: &[u8]) -> SymmetricState {
        let mut hname = [0u8; HASHLEN];
        match handshake_name.len() {
            0 ... HASHLEN => copy_memory(handshake_name, &mut hname),
            _ => hash(handshake_name, &mut hname)
        }
        let cipherstate = CipherState{k : [0; CIPHERKEYLEN], n:0};
        SymmetricState{cipherstate: cipherstate, has_key : false, ck : hname, h: hname}
    }

    fn mix_key(&mut self, data: &[u8]) {
        let mut hkdf_output = [0u8; 2*HASHLEN];
        hkdf(&self.ck, data, &mut hkdf_output);
        copy_memory(&hkdf_output[0..HASHLEN], &mut self.ck);
        copy_memory(&hkdf_output[HASHLEN..HASHLEN+CIPHERKEYLEN], &mut self.cipherstate.k);
        self.cipherstate.n = 0;
        self.has_key = true;
    }

    fn mix_hash(&mut self, data: &[u8]) {
        let mut buffer = [0u8; 65535];
        copy_memory(&data, &mut buffer);
        copy_memory(&self.h, &mut buffer[data.len()..data.len() + HASHLEN]);
        hash(&buffer, &mut self.h);
    }

    fn encrypt_and_hash(&mut self, plaintext: &[u8], out: &mut [u8]) -> usize {
        if self.has_key {
            self.cipherstate.encrypt_and_increment(&self.h, plaintext, out);
            self.mix_hash(&out[..plaintext.len() + MACLEN]);
            return plaintext.len() + MACLEN;
        } else {
            copy_memory(plaintext, out);
            self.mix_hash(plaintext);
            return plaintext.len();
        }
    }

    fn decrypt_and_hash(&mut self, data: &[u8], out: &mut [u8]) -> bool {
        if self.has_key {
            if !self.cipherstate.decrypt_and_increment(&self.h, data, out) {
                return false;
            }
            self.mix_hash(data);
        } else {
            copy_memory(data, out);
            self.mix_hash(data);
        }
        true
    }

    fn split(&self) -> (CipherState, CipherState) {
        let mut hkdf_output = [0u8; 2*HASHLEN];
        hkdf(&self.ck, &[0u8; 0], &mut hkdf_output);
        let mut c1 = CipherState{k : [0; CIPHERKEYLEN], n:0};
        let mut c2 = CipherState{k : [0; CIPHERKEYLEN], n:0};
        copy_memory( &hkdf_output[0..CIPHERKEYLEN], &mut c1.k);
        copy_memory( &hkdf_output[HASHLEN..HASHLEN+CIPHERKEYLEN], &mut c2.k);
        (c1, c2)
    }

}

impl HandshakeState {

    pub fn new(handshake_name: &[u8], new_s : KeyPair, new_e : KeyPair, new_rs: [u8; 32], new_re : [u8; 32] ) -> HandshakeState {
        let symmetricstate = SymmetricState::new(handshake_name);
        HandshakeState{symmetricstate: symmetricstate, s: new_s, e: new_e, rs: new_rs, re: new_re}
    }

    pub fn write_handshake_message(&mut self,
                               descriptor: &[Token],
                               last: bool,
                               payload: &[u8],
                               out: &mut [u8]) -> Option<(CipherState, CipherState)> {
        let mut index = 0;
        for token in descriptor {
            match *token {
                Token::E => {
                    self.e = generate_keypair();
                    index += self.symmetricstate.encrypt_and_hash(&self.e.pubkey, &mut out[index..]);
                },
                Token::S => index += self.symmetricstate.encrypt_and_hash(&self.s.pubkey, &mut out[index..]),
                Token::Dhee => self.symmetricstate.mix_key(&dh(&self.e, &self.re)),
                Token::Dhes => self.symmetricstate.mix_key(&dh(&self.e, &self.rs)),
                Token::Dhse => self.symmetricstate.mix_key(&dh(&self.s, &self.re)),
                Token::Dhss => self.symmetricstate.mix_key(&dh(&self.s, &self.rs)),
            }
        }
        self.symmetricstate.encrypt_and_hash(payload, &mut out[index..]);
        match last {
            true => Some(self.symmetricstate.split()),
            false => None
        }
    }

    pub fn read_handshake_message(&mut self,
                              buffer: &[u8],
                              descriptor: &[Token],
                              last: bool,
                              out: &mut [u8]) -> Result<Option<(CipherState, CipherState)>, NoiseError> {
        let mut ptr = buffer;
        for token in descriptor {
            match *token {
                Token::E | Token::S => {
                    let data = match self.symmetricstate.has_key {
                        true =>  {let temp = &ptr[..DHLEN+16]; ptr = &ptr[DHLEN+16..]; temp}
                        false => {let temp = &ptr[..DHLEN];    ptr = &ptr[DHLEN..];    temp}
                    };
                    if !self.symmetricstate.decrypt_and_hash(data, match *token {
                            Token::E => &mut self.re,
                            Token::S => &mut self.rs,
                            _ => unreachable!()}) {
                        return Err(NoiseError::DecryptError);
                    }
                },
                Token::Dhee => self.symmetricstate.mix_key(&dh(&self.e, &self.re)),
                Token::Dhes => self.symmetricstate.mix_key(&dh(&self.s, &self.re)),
                Token::Dhse => self.symmetricstate.mix_key(&dh(&self.e, &self.rs)),
                Token::Dhss => self.symmetricstate.mix_key(&dh(&self.s, &self.rs)),
            }
        }
        if !self.symmetricstate.decrypt_and_hash(ptr, out) {
            return Err(NoiseError::DecryptError);
        }
        match last {
            true => Ok(Some(self.symmetricstate.split())),
            false => Ok(None)
        }
    }

}

#[cfg(test)]
mod tests {

    extern crate rustc_serialize;

    use super::*;
    use super::{hash, hmac_hash, dh, encrypt, decrypt};
    use super::copy_memory;
    use self::rustc_serialize::hex::{FromHex, ToHex};

    #[test]
    fn crypto_tests() {

        // SHA256 test
        {
            let mut output = [0u8; 32];
            hash("abc".as_bytes(), &mut output);
            assert!(output.to_hex() == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
        }

        // HMAC-SHA256 test - RFC 4231
        {
            let key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".from_hex().unwrap();
            let data = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd".from_hex().unwrap();
            let mut output = [0u8; 32];
            hmac_hash(&key, &data, &mut output);
            println!("{}, {}, {}", key.len(), data.len(), output.to_hex());
            assert!(output.to_hex() == "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe");
        }

        // Curve25519 test - draft-curves-10
        {
            let scalar = "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4".from_hex().unwrap();
            let mut keypair = KeyPair{privkey: [0; 32], pubkey: [0; 32]};
            copy_memory(&scalar, &mut keypair.privkey);
            let public = "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c".from_hex().unwrap();
            let output = dh(&keypair, &public);
            assert!(output.to_hex() == "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552");
        }

        //AES256-GCM tests - gcm-spec.pdf
        {
            // Test Case 13
            let key = [0u8; 32];
            let nonce = 0u64;
            let plaintext = [0u8; 0];
            let authtext = [0u8; 0];
            let mut ciphertext = [0u8; 16];
            encrypt(&key, nonce, &authtext, &plaintext, &mut ciphertext);
            assert!(ciphertext.to_hex() == "530f8afbc74536b9a963b4f1c4cb738b");

            let mut resulttext = [0u8; 1];
            assert!(decrypt(&key, nonce, &authtext, &ciphertext, &mut resulttext) == true);
            assert!(resulttext[0] == 0);
            ciphertext[0] ^= 1;
            assert!(decrypt(&key, nonce, &authtext, &ciphertext, &mut resulttext) == false);

            // Test Case 14
            let plaintext2 = [0u8; 16];
            let mut ciphertext2 = [0u8; 32];
            encrypt(&key, nonce, &authtext, &plaintext2, &mut ciphertext2);
            assert!(ciphertext2.to_hex() == "cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919");

            let mut resulttext2 = [1u8; 16];
            assert!(decrypt(&key, nonce, &authtext, &ciphertext2, &mut resulttext2) == true);
            assert!(plaintext2 == resulttext2);
            ciphertext2[0] ^= 1;
            assert!(decrypt(&key, nonce, &authtext, &ciphertext2, &mut resulttext2) == false);
        }

    }
}
<commit_msg>Fix order in mix_hash<commit_after>extern crate crypto;
extern crate byteorder;
extern crate rand;

use crypto::digest::Digest;
use crypto::sha2::Sha256;
use crypto::hmac::Hmac;
use crypto::mac::{Mac};
use crypto::aes::KeySize;
use crypto::aes_gcm::AesGcm;
use crypto::aead::{AeadEncryptor, AeadDecryptor};
use crypto::curve25519::{curve25519, curve25519_base};

use byteorder::{ByteOrder, BigEndian};
use rand::{OsRng, Rng};

const DHLEN : usize = 32;
const HASHLEN : usize = 32;
//const BLOCKLEN : usize = 64;
const MACLEN : usize = 16;
const CIPHERKEYLEN : usize = 32;
const MAXMSGLEN = 65535;

fn copy_memory(data: &[u8], out: &mut [u8]) {
    for count in 0..data.len() {out[count] = data[count];}
}

pub struct KeyPair {
    privkey: [u8; DHLEN],
    pubkey: [u8; DHLEN]
}

pub fn generate_keypair() -> KeyPair {
    let mut privkey = [0u8; 32];
    let mut rng = OsRng::new().unwrap();
    rng.fill_bytes(&mut privkey);
    privkey[0] &= 248;
    privkey[31] &= 127;
    privkey[31] |= 64;
    let pubkey = curve25519_base(&privkey);
    KeyPair{privkey : privkey, pubkey : pubkey}
}

fn dh(keypair : &KeyPair, pubkey: &[u8]) -> [u8; DHLEN] {
    curve25519(&keypair.privkey, pubkey)
}

fn hash(data: &[u8], out: &mut [u8]) {
    let mut h = Sha256::new();
    h.input(data);
    h.result(out);
}

fn hmac_hash(key: &[u8], data: &[u8], out: &mut [u8]) {
    let mut hmac = Hmac::new(Sha256::new(), key);
    hmac.input(data);
    hmac.raw_result(out);
}

fn hkdf(chaining_key: &[u8], data: &[u8], out: &mut [u8]) {
    let mut temp_key = [0u8; HASHLEN];
    let mut in2 = [0u8; HASHLEN+1];
    hmac_hash(chaining_key, data, &mut temp_key);
    hmac_hash(&temp_key, &[1u8], &mut out[0..HASHLEN]);
    copy_memory(&out[0..HASHLEN], &mut in2);
    in2[HASHLEN] = 2;
    hmac_hash(&temp_key, &in2, &mut out[HASHLEN..2*HASHLEN]);
}

fn encrypt(key: &[u8], nonce: u64, authtext: &[u8], plaintext: &[u8], out: &mut[u8]) {
    let mut nonce_bytes = [0u8; 12];
    BigEndian::write_u64(&mut nonce_bytes[4..], nonce);
    let mut cipher = AesGcm::new(KeySize::KeySize256, key, &nonce_bytes, authtext);
    let mut tag = [0u8; MACLEN];
    cipher.encrypt(plaintext, &mut out[..plaintext.len()], &mut tag);
    copy_memory(&tag, &mut out[plaintext.len()..]);
}

fn decrypt(key: &[u8], nonce: u64, authtext: &[u8], ciphertext: &[u8], out: &mut[u8]) -> bool {
    let mut nonce_bytes = [0u8; 12];
    BigEndian::write_u64(&mut nonce_bytes[4..], nonce);
    let mut cipher = AesGcm::new(KeySize::KeySize256, key, &nonce_bytes, authtext);
    let text_len = ciphertext.len() - MACLEN;
    let mut tag = [0u8; MACLEN];
    copy_memory(&ciphertext[text_len..], &mut tag);
    cipher.decrypt(&ciphertext[..text_len], &mut out[..text_len], &tag)
}

pub enum Token {E, S, Dhee, Dhes, Dhse, Dhss}

pub enum NoiseError {DecryptError}

pub struct CipherState {
    k: [u8; CIPHERKEYLEN],
    n: u64
}

struct SymmetricState {
    cipherstate : CipherState,
    has_key : bool,
    ck: [u8; HASHLEN],
    h: [u8; HASHLEN]
}

pub struct HandshakeState {
    symmetricstate: SymmetricState,
    s: KeyPair,
    e: KeyPair,
    rs: [u8; DHLEN],
    re: [u8; DHLEN],
}

impl CipherState {

    pub fn encrypt_and_increment(&mut self, authtext: &[u8], plaintext: &[u8], out: &mut [u8]) {
        encrypt(&self.k, self.n, authtext, plaintext, out);
        self.n += 1;
    }

    pub fn decrypt_and_increment(&mut self, authtext: &[u8], ciphertext: &[u8], out: &mut [u8]) -> bool {
        if !decrypt(&self.k, self.n, authtext, ciphertext, out) {
            self.n += 1;
            return false;
        }
        self.n += 1;
        true
    }
}

impl SymmetricState {

    fn new(handshake_name: &[u8]) -> SymmetricState {
        let mut hname = [0u8; HASHLEN];
        match handshake_name.len() {
            0 ... HASHLEN => copy_memory(handshake_name, &mut hname),
            _ => hash(handshake_name, &mut hname)
        }
        let cipherstate = CipherState{k : [0; CIPHERKEYLEN], n:0};
        SymmetricState{cipherstate: cipherstate, has_key : false, ck : hname, h: hname}
    }

    fn mix_key(&mut self, data: &[u8]) {
        let mut hkdf_output = [0u8; 2*HASHLEN];
        hkdf(&self.ck, data, &mut hkdf_output);
        copy_memory(&hkdf_output[0..HASHLEN], &mut self.ck);
        copy_memory(&hkdf_output[HASHLEN..HASHLEN+CIPHERKEYLEN], &mut self.cipherstate.k);
        self.cipherstate.n = 0;
        self.has_key = true;
    }

    fn mix_hash(&mut self, data: &[u8]) {
        let mut buffer = [0u8; HASHLEN + MAXMSGLEN];
        copy_memory(&self.h, &mut buffer);
        copy_memory(&data, &mut buffer[HASHLEN..];
        hash(&buffer[..HASHLEN + data.len()], &mut self.h);
    }

    fn encrypt_and_hash(&mut self, plaintext: &[u8], out: &mut [u8]) -> usize {
        if self.has_key {
            self.cipherstate.encrypt_and_increment(&self.h, plaintext, out);
            self.mix_hash(&out[..plaintext.len() + MACLEN]);
            return plaintext.len() + MACLEN;
        } else {
            copy_memory(plaintext, out);
            self.mix_hash(plaintext);
            return plaintext.len();
        }
    }

    fn decrypt_and_hash(&mut self, data: &[u8], out: &mut [u8]) -> bool {
        if self.has_key {
            if !self.cipherstate.decrypt_and_increment(&self.h, data, out) {
                return false;
            }
            self.mix_hash(data);
        } else {
            copy_memory(data, out);
            self.mix_hash(data);
        }
        true
    }

    fn split(&self) -> (CipherState, CipherState) {
        let mut hkdf_output = [0u8; 2*HASHLEN];
        hkdf(&self.ck, &[0u8; 0], &mut hkdf_output);
        let mut c1 = CipherState{k : [0; CIPHERKEYLEN], n:0};
        let mut c2 = CipherState{k : [0; CIPHERKEYLEN], n:0};
        copy_memory( &hkdf_output[0..CIPHERKEYLEN], &mut c1.k);
        copy_memory( &hkdf_output[HASHLEN..HASHLEN+CIPHERKEYLEN], &mut c2.k);
        (c1, c2)
    }

}

impl HandshakeState {

    pub fn new(handshake_name: &[u8], new_s : KeyPair, new_e : KeyPair, new_rs: [u8; 32], new_re : [u8; 32] ) -> HandshakeState {
        let symmetricstate = SymmetricState::new(handshake_name);
        HandshakeState{symmetricstate: symmetricstate, s: new_s, e: new_e, rs: new_rs, re: new_re}
    }

    pub fn write_handshake_message(&mut self,
                               descriptor: &[Token],
                               last: bool,
                               payload: &[u8],
                               out: &mut [u8]) -> Option<(CipherState, CipherState)> {
        let mut index = 0;
        for token in descriptor {
            match *token {
                Token::E => {
                    self.e = generate_keypair();
                    index += self.symmetricstate.encrypt_and_hash(&self.e.pubkey, &mut out[index..]);
                },
                Token::S => index += self.symmetricstate.encrypt_and_hash(&self.s.pubkey, &mut out[index..]),
                Token::Dhee => self.symmetricstate.mix_key(&dh(&self.e, &self.re)),
                Token::Dhes => self.symmetricstate.mix_key(&dh(&self.e, &self.rs)),
                Token::Dhse => self.symmetricstate.mix_key(&dh(&self.s, &self.re)),
                Token::Dhss => self.symmetricstate.mix_key(&dh(&self.s, &self.rs)),
            }
        }
        self.symmetricstate.encrypt_and_hash(payload, &mut out[index..]);
        match last {
            true => Some(self.symmetricstate.split()),
            false => None
        }
    }

    pub fn read_handshake_message(&mut self,
                              buffer: &[u8],
                              descriptor: &[Token],
                              last: bool,
                              out: &mut [u8]) -> Result<Option<(CipherState, CipherState)>, NoiseError> {
        let mut ptr = buffer;
        for token in descriptor {
            match *token {
                Token::E | Token::S => {
                    let data = match self.symmetricstate.has_key {
                        true =>  {let temp = &ptr[..DHLEN+16]; ptr = &ptr[DHLEN+16..]; temp}
                        false => {let temp = &ptr[..DHLEN];    ptr = &ptr[DHLEN..];    temp}
                    };
                    if !self.symmetricstate.decrypt_and_hash(data, match *token {
                            Token::E => &mut self.re,
                            Token::S => &mut self.rs,
                            _ => unreachable!()}) {
                        return Err(NoiseError::DecryptError);
                    }
                },
                Token::Dhee => self.symmetricstate.mix_key(&dh(&self.e, &self.re)),
                Token::Dhes => self.symmetricstate.mix_key(&dh(&self.s, &self.re)),
                Token::Dhse => self.symmetricstate.mix_key(&dh(&self.e, &self.rs)),
                Token::Dhss => self.symmetricstate.mix_key(&dh(&self.s, &self.rs)),
            }
        }
        if !self.symmetricstate.decrypt_and_hash(ptr, out) {
            return Err(NoiseError::DecryptError);
        }
        match last {
            true => Ok(Some(self.symmetricstate.split())),
            false => Ok(None)
        }
    }

}

#[cfg(test)]
mod tests {

    extern crate rustc_serialize;

    use super::*;
    use super::{hash, hmac_hash, dh, encrypt, decrypt};
    use super::copy_memory;
    use self::rustc_serialize::hex::{FromHex, ToHex};

    #[test]
    fn crypto_tests() {

        // SHA256 test
        {
            let mut output = [0u8; 32];
            hash("abc".as_bytes(), &mut output);
            assert!(output.to_hex() == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
        }

        // HMAC-SHA256 test - RFC 4231
        {
            let key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".from_hex().unwrap();
            let data = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd".from_hex().unwrap();
            let mut output = [0u8; 32];
            hmac_hash(&key, &data, &mut output);
            println!("{}, {}, {}", key.len(), data.len(), output.to_hex());
            assert!(output.to_hex() == "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe");
        }

        // Curve25519 test - draft-curves-10
        {
            let scalar = "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4".from_hex().unwrap();
            let mut keypair = KeyPair{privkey: [0; 32], pubkey: [0; 32]};
            copy_memory(&scalar, &mut keypair.privkey);
            let public = "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c".from_hex().unwrap();
            let output = dh(&keypair, &public);
            assert!(output.to_hex() == "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552");
        }

        //AES256-GCM tests - gcm-spec.pdf
        {
            // Test Case 13
            let key = [0u8; 32];
            let nonce = 0u64;
            let plaintext = [0u8; 0];
            let authtext = [0u8; 0];
            let mut ciphertext = [0u8; 16];
            encrypt(&key, nonce, &authtext, &plaintext, &mut ciphertext);
            assert!(ciphertext.to_hex() == "530f8afbc74536b9a963b4f1c4cb738b");

            let mut resulttext = [0u8; 1];
            assert!(decrypt(&key, nonce, &authtext, &ciphertext, &mut resulttext) == true);
            assert!(resulttext[0] == 0);
            ciphertext[0] ^= 1;
            assert!(decrypt(&key, nonce, &authtext, &ciphertext, &mut resulttext) == false);

            // Test Case 14
            let plaintext2 = [0u8; 16];
            let mut ciphertext2 = [0u8; 32];
            encrypt(&key, nonce, &authtext, &plaintext2, &mut ciphertext2);
            assert!(ciphertext2.to_hex() == "cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919");

            let mut resulttext2 = [1u8; 16];
            assert!(decrypt(&key, nonce, &authtext, &ciphertext2, &mut resulttext2) == true);
            assert!(plaintext2 == resulttext2);
            ciphertext2[0] ^= 1;
            assert!(decrypt(&key, nonce, &authtext, &ciphertext2, &mut resulttext2) == false);
        }

    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mattis Marjak (mattis.marjak@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#![allow(dead_code)]

#[macro_use]
extern crate log;
#[macro_use]
mod macros;
use std::fmt;

pub trait Name {
    fn name(&self) -> &'static str;
}

pub trait Initializer {
    fn new() -> Self;
}

#[derive(Debug)]
pub enum Action<UsrStEnum: fmt::Debug> {
    Ignore,
    Parent,
    DelayedTransition,
    Transition(UsrStEnum),
}

#[derive(Debug, Clone)]
pub enum Event<UsrEvtEnum: Clone> {
    Enter,
    User(UsrEvtEnum),
    Exit
}

pub trait Parent<UsrStEnum> {
    fn get_parent() -> Option<UsrStEnum>;
}

pub trait InstanceParent<UsrStEnum> {
    fn get_parent(&self) -> Option<UsrStEnum>;
}

pub trait State<UsrEvtEnum, UsrStEnum, UsrShrData>
    where Self: Name {
    fn handle_event(&mut self, shr_data: &mut UsrShrData, evt: Event<UsrEvtEnum>, probe: bool) -> Action<UsrStEnum>;
}
impl<'a, UsrEvtEnum, UsrStEnum, UsrShrData> fmt::Debug for &'a State<UsrEvtEnum, UsrStEnum, UsrShrData> {
    fn fmt(&self, f:&mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(fmt::Debug::fmt(self.name(), f));
        Ok(())
    }
}

pub trait StateLookup<UsrStEnum, UsrEvtEnum, UsrShrData> {
    fn lookup(&mut self, typ: &UsrStEnum) -> &mut State<UsrEvtEnum, UsrStEnum, UsrShrData>;
}

#[derive(Clone)]
struct Task<UsrStEnum, UsrEvtEnum: Clone> {
    state: UsrStEnum,
    event: Event<UsrEvtEnum>
}
impl<UsrStEnum, UsrEvtEnum: Clone> Task<UsrStEnum, UsrEvtEnum> {
    fn new(state:  UsrStEnum, event: Event<UsrEvtEnum>) -> Self {
        Task { state:  state, event: event }
    }
}

pub struct StateMachine<UsrStStr, UsrStEnum, UsrEvtEnum: Clone, UsrShrData> {
    current     : UsrStEnum,
    started     : bool,
    states      : UsrStStr,
    shr_data    : UsrShrData,
    exit_tasks  : Vec<Task<UsrStEnum, UsrEvtEnum>>,
    enter_tasks : Vec<Task<UsrStEnum, UsrEvtEnum>>,
    _phantom    : ::std::marker::PhantomData<UsrEvtEnum>
}
impl<UsrStStr, UsrStEnum, UsrEvtEnum, UsrShrData> StateMachine<UsrStStr, UsrStEnum, UsrEvtEnum, UsrShrData>
    where UsrStStr   : Initializer + StateLookup<UsrStEnum, UsrEvtEnum, UsrShrData>,
          UsrStEnum  : fmt::Debug+Eq+Clone+InstanceParent<UsrStEnum>,
          UsrEvtEnum : fmt::Debug+Clone {

    pub fn new(initial: UsrStEnum, shared_data: UsrShrData) -> Self {
        StateMachine {
            current     : initial,
            started     : false,
            states      : UsrStStr::new(),
            shr_data    : shared_data,
            exit_tasks  : Vec::new(),
            enter_tasks : Vec::new(),
            _phantom    : ::std::marker::PhantomData
        }
    }

    pub fn start(&mut self) {
        let mut parent = Some(self.current.clone());
        while let Some(state) = parent {
            parent = state.get_parent();
            self.enter_tasks.push(Task::new(state, Event::Enter));
        }
        self.process_enter_tasks();
        self.started = true;
    }

    fn process_exit_tasks(&mut self) {
        for task in self.exit_tasks.iter() {
            debug!("send {:?} to {:?}", task.event, task.state);
            match self.states.lookup(&task.state).handle_event(
                  &mut self.shr_data, task.event.clone(), false){
                Action::Ignore | Action::Parent => {},
                _ => error!("Transitions from exit events are not allowed, \
                            ignoring transition from state {:?} on event {:?}",
                            task.state, task.event)
            };
        }
        self.exit_tasks.clear();
    }

    fn process_enter_tasks(&mut self) {
        self.enter_tasks.reverse();
        for task in self.enter_tasks.iter() {
            debug!("send {:?} to {:?}", task.event, task.state);
            match self.states.lookup(&task.state).handle_event(
                  &mut self.shr_data, task.event.clone(), false){
                Action::Ignore | Action::Parent => {},
                _ => error!("Transitions from enter events are not allowed, \
                            ignoring transition from state {:?} on event {:?}",
                            task.state, task.event)
            }
        }
        self.enter_tasks.clear();
    }

    fn transition(&mut self, from_state: UsrStEnum, to_state: UsrStEnum) {
        let mut parent = Some(from_state);
        while let Some(state) = parent {
            parent = state.get_parent();
            self.exit_tasks.push(Task::new(state, Event::Exit));
        }
        let mut same_idx: Option<usize> = None;
        parent = Some(to_state);
        'outer: while let Some(state) = parent {
            for (i, task) in self.exit_tasks.iter().enumerate() {
                if task.state == state {
                    same_idx = Some(i);
                    break 'outer;
                }
            }
            parent = state.get_parent();
            self.enter_tasks.push(Task::new(state, Event::Enter));
        }
        if let Some(i) = same_idx {
            let drop_num = self.exit_tasks.len() - i;
            for _ in 0..drop_num {
                self.exit_tasks.pop();
            }
        }
        self.process_exit_tasks();
        self.process_enter_tasks();
    }

    pub fn input(&mut self, evt: UsrEvtEnum) {
        assert!(self.started, "Can't call input before starting the state machine with start()");
        let evt = Event::User(evt);
        debug!("state:  {:?}", self.current);
        debug!("input:  {:?}", evt);
        let mut action;
        let mut state = self.current.clone();
        loop {
            action = self.states.lookup(&state).handle_event(&mut self.shr_data, evt.clone(), true);
            match action {
                Action::Ignore               => {
                    self.exit_tasks.clear();
                    break;
                },
                Action::Parent               => {
                    if let Some(parent) = state.get_parent() {
                        self.exit_tasks.push(Task::new(state.clone(), Event::Exit));
                        state = parent;
                    } else {
                        error!("State {:?} responded with Action::Parent to event {:?}, but the state has no parent", state, evt);
                        break;
                    }
                },
                Action::Transition(x)        => {
                    debug!("send {:?} to {:?}", evt, state);
                    self.process_exit_tasks();  // exit until in the parent that handles the signal
                    self.current = x.clone(); // signal allready handled
                    self.transition(state.clone(), x);
                    break;
                },
                Action::DelayedTransition => {
                    self.process_exit_tasks(); // exit until in the parent that handles the signal
                    debug!("send {:?} to {:?}", evt, state);
                    if let Action::Transition(x) = self.states.lookup(&state).handle_event(&mut self.shr_data, evt.clone(), false) { // handle the signal
                        self.current = x.clone();
                        self.transition(state.clone(), x);
                    } else {
                        error!("State {:?} probed Action::DelayedTransition to event {:?}, but doesn't return Action::Transition", state, evt);
                        self.current = state;
                    }
                    break;
                },
            }
        }
    }
}
<commit_msg>replace errors with panic<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mattis Marjak (mattis.marjak@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#![allow(dead_code)]

#[macro_use]
extern crate log;
#[macro_use]
mod macros;
use std::fmt;

pub trait Name {
    fn name(&self) -> &'static str;
}

pub trait Initializer {
    fn new() -> Self;
}

#[derive(Debug)]
pub enum Action<UsrStEnum: fmt::Debug> {
    Ignore,
    Parent,
    DelayedTransition,
    Transition(UsrStEnum),
}

#[derive(Debug, Clone)]
pub enum Event<UsrEvtEnum: Clone> {
    Enter,
    User(UsrEvtEnum),
    Exit
}

pub trait Parent<UsrStEnum> {
    fn get_parent() -> Option<UsrStEnum>;
}

pub trait InstanceParent<UsrStEnum> {
    fn get_parent(&self) -> Option<UsrStEnum>;
}

pub trait State<UsrEvtEnum, UsrStEnum, UsrShrData>
    where Self: Name {
    fn handle_event(&mut self, shr_data: &mut UsrShrData, evt: Event<UsrEvtEnum>, probe: bool) -> Action<UsrStEnum>;
}
impl<'a, UsrEvtEnum, UsrStEnum, UsrShrData> fmt::Debug for &'a State<UsrEvtEnum, UsrStEnum, UsrShrData> {
    fn fmt(&self, f:&mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(fmt::Debug::fmt(self.name(), f));
        Ok(())
    }
}

pub trait StateLookup<UsrStEnum, UsrEvtEnum, UsrShrData> {
    fn lookup(&mut self, typ: &UsrStEnum) -> &mut State<UsrEvtEnum, UsrStEnum, UsrShrData>;
}

#[derive(Clone)]
struct Task<UsrStEnum, UsrEvtEnum: Clone> {
    state: UsrStEnum,
    event: Event<UsrEvtEnum>
}
impl<UsrStEnum, UsrEvtEnum: Clone> Task<UsrStEnum, UsrEvtEnum> {
    fn new(state:  UsrStEnum, event: Event<UsrEvtEnum>) -> Self {
        Task { state:  state, event: event }
    }
}

pub struct StateMachine<UsrStStr, UsrStEnum, UsrEvtEnum: Clone, UsrShrData> {
    current     : UsrStEnum,
    started     : bool,
    states      : UsrStStr,
    shr_data    : UsrShrData,
    exit_tasks  : Vec<Task<UsrStEnum, UsrEvtEnum>>,
    enter_tasks : Vec<Task<UsrStEnum, UsrEvtEnum>>,
    _phantom    : ::std::marker::PhantomData<UsrEvtEnum>
}
impl<UsrStStr, UsrStEnum, UsrEvtEnum, UsrShrData> StateMachine<UsrStStr, UsrStEnum, UsrEvtEnum, UsrShrData>
    where UsrStStr   : Initializer + StateLookup<UsrStEnum, UsrEvtEnum, UsrShrData>,
          UsrStEnum  : fmt::Debug+Eq+Clone+InstanceParent<UsrStEnum>,
          UsrEvtEnum : fmt::Debug+Clone {

    pub fn new(initial: UsrStEnum, shared_data: UsrShrData) -> Self {
        StateMachine {
            current     : initial,
            started     : false,
            states      : UsrStStr::new(),
            shr_data    : shared_data,
            exit_tasks  : Vec::new(),
            enter_tasks : Vec::new(),
            _phantom    : ::std::marker::PhantomData
        }
    }

    pub fn start(&mut self) {
        let mut parent = Some(self.current.clone());
        while let Some(state) = parent {
            parent = state.get_parent();
            self.enter_tasks.push(Task::new(state, Event::Enter));
        }
        self.process_enter_tasks();
        self.started = true;
    }

    fn process_exit_tasks(&mut self) {
        for task in self.exit_tasks.iter() {
            debug!("send {:?} to {:?}", task.event, task.state);
            match self.states.lookup(&task.state).handle_event(
                  &mut self.shr_data, task.event.clone(), false){
                Action::Ignore | Action::Parent => {},
                _ => panic!("Transitions from exit events are not allowed, \
                            ignoring transition from state {:?} on event {:?}",
                            task.state, task.event)
            };
        }
        self.exit_tasks.clear();
    }

    fn process_enter_tasks(&mut self) {
        self.enter_tasks.reverse();
        for task in self.enter_tasks.iter() {
            debug!("send {:?} to {:?}", task.event, task.state);
            match self.states.lookup(&task.state).handle_event(
                  &mut self.shr_data, task.event.clone(), false){
                Action::Ignore | Action::Parent => {},
                _ => panic!("Transitions from enter events are not allowed, \
                            ignoring transition from state {:?} on event {:?}",
                            task.state, task.event)
            }
        }
        self.enter_tasks.clear();
    }

    fn transition(&mut self, from_state: UsrStEnum, to_state: UsrStEnum) {
        let mut parent = Some(from_state);
        while let Some(state) = parent {
            parent = state.get_parent();
            self.exit_tasks.push(Task::new(state, Event::Exit));
        }
        let mut same_idx: Option<usize> = None;
        parent = Some(to_state);
        'outer: while let Some(state) = parent {
            for (i, task) in self.exit_tasks.iter().enumerate() {
                if task.state == state {
                    same_idx = Some(i);
                    break 'outer;
                }
            }
            parent = state.get_parent();
            self.enter_tasks.push(Task::new(state, Event::Enter));
        }
        if let Some(i) = same_idx {
            let drop_num = self.exit_tasks.len() - i;
            for _ in 0..drop_num {
                self.exit_tasks.pop();
            }
        }
        self.process_exit_tasks();
        self.process_enter_tasks();
    }

    pub fn input(&mut self, evt: UsrEvtEnum) {
        assert!(self.started, "Can't call input before starting the state machine with start()");
        let evt = Event::User(evt);
        debug!("state:  {:?}", self.current);
        debug!("input:  {:?}", evt);
        let mut action;
        let mut state = self.current.clone();
        loop {
            action = self.states.lookup(&state).handle_event(&mut self.shr_data, evt.clone(), true);
            match action {
                Action::Ignore               => {
                    self.exit_tasks.clear();
                    break;
                },
                Action::Parent               => {
                    if let Some(parent) = state.get_parent() {
                        self.exit_tasks.push(Task::new(state.clone(), Event::Exit));
                        state = parent;
                    } else {
                        panic!("State {:?} responded with Action::Parent to event {:?}, but the state has no parent", state, evt);
                        break;
                    }
                },
                Action::Transition(x)        => {
                    debug!("send {:?} to {:?}", evt, state);
                    self.process_exit_tasks();  // exit until in the parent that handles the signal
                    self.current = x.clone(); // signal allready handled
                    self.transition(state.clone(), x);
                    break;
                },
                Action::DelayedTransition => {
                    self.process_exit_tasks(); // exit until in the parent that handles the signal
                    debug!("send {:?} to {:?}", evt, state);
                    if let Action::Transition(x) = self.states.lookup(&state).handle_event(&mut self.shr_data, evt.clone(), false) { // handle the signal
                        self.current = x.clone();
                        self.transition(state.clone(), x);
                    } else {
                        panic!("State {:?} probed Action::DelayedTransition to event {:?}, but doesn't return Action::Transition", state, evt);
                        self.current = state;
                    }
                    break;
                },
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_uint, c_int};
use std::sync::Arc;
use ffi::{QrsEngine, QObject};
use std::path::Path;
use std::convert::AsRef;

/* Re-exports */

pub use variant::{Variant, FromQVariant, ToQVariant, unpack_varlist};
pub use ffi::QVariant as OpaqueQVariant;

/* Submodules */

#[allow(dead_code)]
pub mod ffi;
mod macros;
pub mod variant;

struct EngineInternal {
    p: *mut QrsEngine,
}

/* Hack to get invoke working. Need to figure out better way for invokes anyway.. */
unsafe impl Send for EngineInternal { }
unsafe impl Sync for EngineInternal { }

impl Drop for EngineInternal {
    fn drop(&mut self) {
        unsafe { ffi::qmlrs_destroy_engine(self.p); }
    }
}

pub struct Engine {
    i: Arc<EngineInternal>,
}

impl Engine {
    pub fn new() -> Engine {
        let p = unsafe { ffi::qmlrs_create_engine() };
        assert!(!p.is_null());

        let i = Arc::new(EngineInternal {
            p: p,
        });

        Engine {
            i: i
        }
    }

    pub fn new_headless() -> Engine {
        let p = unsafe { ffi::qmlrs_create_engine_headless() };
        assert!(!p.is_null());

        let i = Arc::new(EngineInternal {
            p: p,
        });

        Engine {
            i: i
        }
    }

    pub fn load_url(&mut self, path: &str) {
        unsafe {
            ffi::qmlrs_engine_load_url(self.i.p, path.as_ptr() as *const c_char,
                                       path.len() as c_uint);
        }
    }

    pub fn load_data(&mut self, data: &str) {
        unsafe {
            ffi::qmlrs_engine_load_from_data(self.i.p, data.as_ptr() as *const c_char,
                                             data.len() as c_uint);
        }
    }

    pub fn load_local_file<P: AsRef<Path>>(&mut self, name: P) {
        let path_raw = std::env::current_dir().unwrap().join(name);
        let path
            = if cfg!(windows) {
                format!("file:///{}",path_raw.display())
            } else {
                format!("file://{}",path_raw.display())
            } ;
        self.load_url(&path);
    }

    pub fn exec(self) {
        unsafe { ffi::qmlrs_app_exec(); }
    }

    pub fn set_property(&mut self, name: &str, obj: &Object) {
        unsafe {
            ffi::qmlrs_engine_set_property(self.i.p, name.as_ptr() as *const c_char,
                                           name.len() as c_uint, obj.p);
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct MetaObject {
    p: *mut ffi::QrsMetaObject
}

impl MetaObject {
    pub fn new(name: &str, fun: ffi::SlotFunction) -> MetaObject {
        let p = unsafe { ffi::qmlrs_metaobject_create(name.as_ptr() as *const c_char,name.len() as c_uint,fun) };
        assert!(!p.is_null());

        MetaObject { p: p }
    }

    pub fn add_signal(&mut self, sig: &str) -> isize {
        unsafe { ffi::qmlrs_metaobject_add_signal(self.p,sig.as_ptr() as *const c_char,sig.len() as c_uint) as isize }
    }

    pub fn add_property(&mut self, name: &str, ty: &str, signal: Option<&str>) {
        unsafe {
            if let Some(sig) = signal {
                ffi::qmlrs_metaobject_add_property(self.p,name.as_ptr() as *const c_char,name.len() as c_uint,
                                                   ty.as_ptr() as *const c_char, ty.len() as c_uint,
                                                   sig.as_ptr() as *const c_char, sig.len() as c_uint);
            } else {
                let s = "";
                ffi::qmlrs_metaobject_add_property(self.p,name.as_ptr() as *const c_char,name.len() as c_uint,
                                                   ty.as_ptr() as *const c_char,ty.len() as c_uint,
                                                   s.as_ptr() as *const c_char, 0);
            }
        }
    }

    pub fn add_slot(&mut self, sig: &str) -> isize {
        unsafe { ffi::qmlrs_metaobject_add_slot(self.p,sig.as_ptr() as *const c_char,sig.len() as c_uint) as isize }
    }

    pub fn add_method(&mut self, sig: &str, ret: &str) -> isize {
        unsafe {
            ffi::qmlrs_metaobject_add_method(self.p,sig.as_ptr() as *const c_char,sig.len() as c_uint,
                                             ret.as_ptr() as *const c_char,ret.len() as c_uint) as isize
        }
    }

    pub fn instantiate(&mut self) -> Object {
        Object{ p: unsafe {
            ffi::qmlrs_metaobject_instantiate(self.p)
        } }
    }
}

pub struct Object {
    p: *mut ffi::QObject
}

unsafe impl Send for Object { }

impl Object {
    pub fn from_ptr(p: *mut ffi::QObject) -> Object {
        Object{ p: p }
    }

    pub fn set_property(&mut self, name: &str, value: Variant) {
        unsafe {
            let var = ffi::qmlrs_variant_create();
            value.to_qvariant(var);

            ffi::qmlrs_object_set_property(self.p,name.as_ptr() as *const c_char,name.len() as c_uint,var);
            ffi::qmlrs_variant_destroy(var);
        }
    }

    pub fn get_property(&self, name: &str) -> Variant {
        unsafe {
            let var = ffi::qmlrs_variant_create();

            ffi::qmlrs_object_get_property(self.p,name.as_ptr() as *const c_char,name.len() as c_uint,var);
            let ret = Variant::from_qvariant(var);

            ffi::qmlrs_variant_destroy(var);
            ret.unwrap()
        }
    }

    pub fn call(&self, id: isize, args: &[Variant]) -> Option<Variant> {
        unsafe {
            let vl = ffi::qmlrs_varlist_create();
            let ret = ffi::qmlrs_variant_create();

            for v in args {
                let var = ffi::qmlrs_varlist_push(vl);
                v.to_qvariant(var);
            }

            ffi::qmlrs_object_call(self.p, id as c_int, vl, ret);
            ffi::qmlrs_varlist_destroy(vl);

            let r = Variant::from_qvariant(ret);
            ffi::qmlrs_variant_destroy(ret);

            r
        }
    }

    pub fn emit(&self, id: isize, args: &[Variant]) {
        unsafe {
            let vl = ffi::qmlrs_varlist_create();

            for v in args {
                let var = ffi::qmlrs_varlist_push(vl);
                v.to_qvariant(var);
            }

            ffi::qmlrs_object_emit(self.p, id as c_int, vl);
            ffi::qmlrs_varlist_destroy(vl);
        }
    }

    pub fn delete_later(&mut self) {
        unsafe { ffi::qmlrs_object_delete_later(self.p) };
    }

    pub fn as_ptr(&mut self) -> *mut QObject {
        self.p
    }
}

pub fn register_singleton_type(module: &str, major: isize, minor: isize, typenam: &str, fun: ffi::SingletonFunction) {
    unsafe {
        ffi::qmlrs_register_singleton_type(module.as_ptr() as *const c_char,module.len() as c_uint,
                                           major as c_int,minor as c_int,
                                           typenam.as_ptr() as *const c_char,typenam.len() as c_uint,
                                           fun);
    }
}

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

    #[test]
    fn test_create_engine() {
        Engine::new_headless();
    }
}
<commit_msg>impl Sync for QObject<commit_after>extern crate libc;

use libc::{c_char, c_uint, c_int};
use std::sync::Arc;
use ffi::{QrsEngine, QObject};
use std::path::Path;
use std::convert::AsRef;

/* Re-exports */

pub use variant::{Variant, FromQVariant, ToQVariant, unpack_varlist};
pub use ffi::QVariant as OpaqueQVariant;

/* Submodules */

#[allow(dead_code)]
pub mod ffi;
mod macros;
pub mod variant;

struct EngineInternal {
    p: *mut QrsEngine,
}

/* Hack to get invoke working. Need to figure out better way for invokes anyway.. */
unsafe impl Send for EngineInternal { }
unsafe impl Sync for EngineInternal { }

impl Drop for EngineInternal {
    fn drop(&mut self) {
        unsafe { ffi::qmlrs_destroy_engine(self.p); }
    }
}

pub struct Engine {
    i: Arc<EngineInternal>,
}

impl Engine {
    pub fn new() -> Engine {
        let p = unsafe { ffi::qmlrs_create_engine() };
        assert!(!p.is_null());

        let i = Arc::new(EngineInternal {
            p: p,
        });

        Engine {
            i: i
        }
    }

    pub fn new_headless() -> Engine {
        let p = unsafe { ffi::qmlrs_create_engine_headless() };
        assert!(!p.is_null());

        let i = Arc::new(EngineInternal {
            p: p,
        });

        Engine {
            i: i
        }
    }

    pub fn load_url(&mut self, path: &str) {
        unsafe {
            ffi::qmlrs_engine_load_url(self.i.p, path.as_ptr() as *const c_char,
                                       path.len() as c_uint);
        }
    }

    pub fn load_data(&mut self, data: &str) {
        unsafe {
            ffi::qmlrs_engine_load_from_data(self.i.p, data.as_ptr() as *const c_char,
                                             data.len() as c_uint);
        }
    }

    pub fn load_local_file<P: AsRef<Path>>(&mut self, name: P) {
        let path_raw = std::env::current_dir().unwrap().join(name);
        let path
            = if cfg!(windows) {
                format!("file:///{}",path_raw.display())
            } else {
                format!("file://{}",path_raw.display())
            } ;
        self.load_url(&path);
    }

    pub fn exec(self) {
        unsafe { ffi::qmlrs_app_exec(); }
    }

    pub fn set_property(&mut self, name: &str, obj: &Object) {
        unsafe {
            ffi::qmlrs_engine_set_property(self.i.p, name.as_ptr() as *const c_char,
                                           name.len() as c_uint, obj.p);
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct MetaObject {
    p: *mut ffi::QrsMetaObject
}

impl MetaObject {
    pub fn new(name: &str, fun: ffi::SlotFunction) -> MetaObject {
        let p = unsafe { ffi::qmlrs_metaobject_create(name.as_ptr() as *const c_char,name.len() as c_uint,fun) };
        assert!(!p.is_null());

        MetaObject { p: p }
    }

    pub fn add_signal(&mut self, sig: &str) -> isize {
        unsafe { ffi::qmlrs_metaobject_add_signal(self.p,sig.as_ptr() as *const c_char,sig.len() as c_uint) as isize }
    }

    pub fn add_property(&mut self, name: &str, ty: &str, signal: Option<&str>) {
        unsafe {
            if let Some(sig) = signal {
                ffi::qmlrs_metaobject_add_property(self.p,name.as_ptr() as *const c_char,name.len() as c_uint,
                                                   ty.as_ptr() as *const c_char, ty.len() as c_uint,
                                                   sig.as_ptr() as *const c_char, sig.len() as c_uint);
            } else {
                let s = "";
                ffi::qmlrs_metaobject_add_property(self.p,name.as_ptr() as *const c_char,name.len() as c_uint,
                                                   ty.as_ptr() as *const c_char,ty.len() as c_uint,
                                                   s.as_ptr() as *const c_char, 0);
            }
        }
    }

    pub fn add_slot(&mut self, sig: &str) -> isize {
        unsafe { ffi::qmlrs_metaobject_add_slot(self.p,sig.as_ptr() as *const c_char,sig.len() as c_uint) as isize }
    }

    pub fn add_method(&mut self, sig: &str, ret: &str) -> isize {
        unsafe {
            ffi::qmlrs_metaobject_add_method(self.p,sig.as_ptr() as *const c_char,sig.len() as c_uint,
                                             ret.as_ptr() as *const c_char,ret.len() as c_uint) as isize
        }
    }

    pub fn instantiate(&mut self) -> Object {
        Object{ p: unsafe {
            ffi::qmlrs_metaobject_instantiate(self.p)
        } }
    }
}

pub struct Object {
    p: *mut ffi::QObject
}

unsafe impl Send for Object { }
unsafe impl Sync for Object { }

impl Object {
    pub fn from_ptr(p: *mut ffi::QObject) -> Object {
        Object{ p: p }
    }

    pub fn set_property(&mut self, name: &str, value: Variant) {
        unsafe {
            let var = ffi::qmlrs_variant_create();
            value.to_qvariant(var);

            ffi::qmlrs_object_set_property(self.p,name.as_ptr() as *const c_char,name.len() as c_uint,var);
            ffi::qmlrs_variant_destroy(var);
        }
    }

    pub fn get_property(&self, name: &str) -> Variant {
        unsafe {
            let var = ffi::qmlrs_variant_create();

            ffi::qmlrs_object_get_property(self.p,name.as_ptr() as *const c_char,name.len() as c_uint,var);
            let ret = Variant::from_qvariant(var);

            ffi::qmlrs_variant_destroy(var);
            ret.unwrap()
        }
    }

    pub fn call(&self, id: isize, args: &[Variant]) -> Option<Variant> {
        unsafe {
            let vl = ffi::qmlrs_varlist_create();
            let ret = ffi::qmlrs_variant_create();

            for v in args {
                let var = ffi::qmlrs_varlist_push(vl);
                v.to_qvariant(var);
            }

            ffi::qmlrs_object_call(self.p, id as c_int, vl, ret);
            ffi::qmlrs_varlist_destroy(vl);

            let r = Variant::from_qvariant(ret);
            ffi::qmlrs_variant_destroy(ret);

            r
        }
    }

    pub fn emit(&self, id: isize, args: &[Variant]) {
        unsafe {
            let vl = ffi::qmlrs_varlist_create();

            for v in args {
                let var = ffi::qmlrs_varlist_push(vl);
                v.to_qvariant(var);
            }

            ffi::qmlrs_object_emit(self.p, id as c_int, vl);
            ffi::qmlrs_varlist_destroy(vl);
        }
    }

    pub fn delete_later(&mut self) {
        unsafe { ffi::qmlrs_object_delete_later(self.p) };
    }

    pub fn as_ptr(&mut self) -> *mut QObject {
        self.p
    }
}

pub fn register_singleton_type(module: &str, major: isize, minor: isize, typenam: &str, fun: ffi::SingletonFunction) {
    unsafe {
        ffi::qmlrs_register_singleton_type(module.as_ptr() as *const c_char,module.len() as c_uint,
                                           major as c_int,minor as c_int,
                                           typenam.as_ptr() as *const c_char,typenam.len() as c_uint,
                                           fun);
    }
}

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

    #[test]
    fn test_create_engine() {
        Engine::new_headless();
    }
}
<|endoftext|>


<commit_before>extern crate libc;

pub mod instruction;
pub mod constants;
mod ffi;
pub mod capstone;

pub use instruction::*;
pub use constants::*;

pub use capstone::Capstone;

/// An opaque reference to a capstone engine.
///
/// bindgen by default used this type name everywhere, so it is easier to leave it with a confusing
/// name.
///
/// It should not be exported, rust's new visibility rules make tackling this not immediately
/// obvious
#[allow(non_camel_case_types)]
type csh = libc::size_t;

#[cfg(test)]
mod test {
    use std::collections::HashSet;
    use super::*;

    static CODE: &'static [u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00";

    #[test]
    fn test_x86_simple() {
        match capstone::Capstone::new(constants::CsArch::ARCH_X86, constants::CsMode::MODE_64) {
            Ok(cs) => {
                match cs.disasm(CODE, 0x1000, 0) {
                    Ok(insns) => {
                        assert_eq!(insns.len(), 2);
                        let is: Vec<_> = insns.iter().collect();
                        assert_eq!(is[0].mnemonic().unwrap(), "push");
                        assert_eq!(is[1].mnemonic().unwrap(), "mov");

                        assert_eq!(is[0].address, 0x1000);
                        assert_eq!(is[1].address, 0x1001);

                        assert_eq!(is[0].get_bytes(), b"\x55");
                        assert_eq!(is[1].get_bytes(), b"\x48\x8b\x05\xb8\x13\x00\x00");
                    }
                    Err(err) => assert!(false, "Couldn't disasm instructions: {}", err),
                }
            }
            Err(e) => {
                assert!(false, "Couldn't create a cs engine: {}", e);
            }
        }
    }

    #[test]
    fn test_x86_names() {
        match capstone::Capstone::new(constants::CsArch::ARCH_X86, constants::CsMode::MODE_64) {
            Ok(cs) => {
                let reg_id = 1;
                match cs.reg_name(reg_id) {
                    Some(reg_name) => assert_eq!(reg_name, "ah"),
                    None => assert!(false, "Couldn't get register name"),
                }

                let insn_id = 1;
                match cs.insn_name(insn_id) {
                    Some(insn_name) => assert_eq!(insn_name, "aaa"),
                    None => assert!(false, "Couldn't get instruction name"),
                }

                assert_eq!(cs.group_name(1), Some(String::from("jump")));

                let reg_id = 6000;
                match cs.reg_name(reg_id) {
                    Some(_) => assert!(false, "invalid register worked"),
                    None => {}
                }

                let insn_id = 6000;
                match cs.insn_name(insn_id) {
                    Some(_) => assert!(false, "invalid instruction worked"),
                    None => {}
                }

                assert_eq!(cs.group_name(6000), None);
            }
            Err(e) => {
                assert!(false, "Couldn't create a cs engine: {}", e);
            }
        }
    }

    #[test]
    fn test_detail_false_fail() {
        let mut cs = capstone::Capstone::new(constants::CsArch::ARCH_X86,
                                             constants::CsMode::MODE_64)
                .unwrap();
        cs.set_detail(false).unwrap();
        let insns: Vec<_> = cs.disasm(CODE, 0x1000, 0).unwrap().iter().collect();
        assert_eq!(cs.insn_belongs_to_group(&insns[0], 0),
                   Err(CsErr::CS_ERR_DETAIL));
        assert_eq!(cs.insn_belongs_to_group(&insns[1], 0),
                   Err(CsErr::CS_ERR_DETAIL));
    }

    #[test]
    fn test_detail_true() {
        let mut cs = capstone::Capstone::new(constants::CsArch::ARCH_X86,
                                             constants::CsMode::MODE_64)
                .unwrap();
        cs.set_detail(true).unwrap();
        let insns: Vec<_> = cs.disasm(CODE, 0x1000, 0).unwrap().iter().collect();
        let insn_group_ids = [CsGroupType::CS_GRP_JUMP,
                              CsGroupType::CS_GRP_CALL,
                              CsGroupType::CS_GRP_RET,
                              CsGroupType::CS_GRP_INT,
                              CsGroupType::CS_GRP_IRET];
        for insn_idx in 0..1 + 1 {
            for insn_group_id in &insn_group_ids {
                assert_eq!(cs.insn_belongs_to_group(&insns[insn_idx], *insn_group_id as u64),
                           Ok(false));
            }
        }
    }

    /// Assert instruction belongs or does not belong to groups
    fn test_x86_instruction_groups_helper(mnemonic_name: &str,
                                          bytes: &[u8],
                                          belong_groups: &[CsGroupType],
                                          not_belong_groups: &[CsGroupType]) {
        let mut cs = capstone::Capstone::new(constants::CsArch::ARCH_X86,
                                             constants::CsMode::MODE_64)
                .expect("Failed to create capstone handle");

        // Details required to get groups information
        cs.set_detail(true).unwrap();

        // Disassemble instructions
        let insns: Vec<_> = cs.disasm(bytes, 0x1000, 0)
            .expect("Failed to disassemble")
            .iter()
            .collect();

        // Check number of instructions
        assert_eq!(insns.len(), 1, "Expected exactly 1 instruction");

        let insn = &insns[0];

        // Check mnemonic
        assert_eq!(mnemonic_name,
                   cs.insn_name(insn.get_id() as u64)
                       .expect("Failed to get instruction name"));

        // Assert instruction belongs to belong_groups
        for belong_group in belong_groups {
            assert_eq!(Ok(true),
                       cs.insn_belongs_to_group(&insn, *belong_group as u64),
                       "{:?} does NOT BELONG to group {:?}",
                       insn,
                       *belong_group);
        }

        // Assert instruction does not belong to not_belong_groups
        for not_belong_group in not_belong_groups {
            assert_eq!(Ok(false),
                       cs.insn_belongs_to_group(&insn, *not_belong_group as u64),
                       "{:?} BELONGS to group {:?}",
                       insn,
                       *not_belong_group);
        }
    }

    #[test]
    fn test_instruction_groups() {
        let jump = CsGroupType::CS_GRP_JUMP;
        let call = CsGroupType::CS_GRP_CALL;
        let ret = CsGroupType::CS_GRP_RET;
        let int = CsGroupType::CS_GRP_INT;
        let iret = CsGroupType::CS_GRP_IRET;

        test_x86_instruction_groups_helper("nop", b"\x90", &[], &[jump, call, ret, int, iret]);
        test_x86_instruction_groups_helper("je", b"\x74\x05", &[jump], &[call, ret, int, iret]);
        test_x86_instruction_groups_helper("call",
                                           b"\xe8\x28\x07\x00\x00",
                                           &[call],
                                           &[jump, ret, int, iret]);
        test_x86_instruction_groups_helper("ret", b"\xc3", &[ret], &[jump, call, int, iret]);
        test_x86_instruction_groups_helper("syscall",
                                           b"\x0f\x05",
                                           &[int],
                                           &[jump, call, ret, iret]);
        test_x86_instruction_groups_helper("iretd", b"\xcf", &[iret], &[jump, call, ret, int]);
        test_x86_instruction_groups_helper("sub",
                                           b"\x48\x83\xec\x08",
                                           &[],
                                           &[jump, call, ret, int, iret]);
        test_x86_instruction_groups_helper("test",
                                           b"\x48\x85\xc0",
                                           &[],
                                           &[jump, call, ret, int, iret]);
    }

    /// Assert instruction belongs or does not belong to groups
    fn test_x86_instruction_group_ids_helper(mnemonic_name: &str,
                                             bytes: &[u8],
                                             expected_groups: &[CsGroupType]) {
        let mut cs = capstone::Capstone::new(constants::CsArch::ARCH_X86,
                                             constants::CsMode::MODE_64)
                .expect("Failed to create capstone handle");

        // Details required to get groups information
        cs.set_detail(true).unwrap();

        // Disassemble instructions
        let insns: Vec<_> = cs.disasm(bytes, 0x1000, 0)
            .expect("Failed to disassemble")
            .iter()
            .collect();

        // Check number of instructions
        assert_eq!(insns.len(), 1, "Expected exactly 1 instruction");

        let insn = &insns[0];

        // Check mnemonic
        assert_eq!(mnemonic_name,
                   cs.insn_name(insn.get_id() as u64)
                       .expect("Failed to get instruction name"));

        // Assert expected instruction groups is a subset of computed groups
        let instruction_groups: HashSet<u8> = cs.get_insn_group_ids(&insn)
            .expect("failed to get instruction groups")
            .iter()
            .map(|&x| x)
            .collect();
        let expected_groups: HashSet<u8> = expected_groups.iter().map(|&x| x as u8).collect();
        assert!(expected_groups.is_subset(&instruction_groups),
                "Expected groups {:?} does NOT match computed insn groups {:?}",
                expected_groups,
                instruction_groups);
    }

    #[test]
    fn test_instruction_group_ids() {
        let jump = CsGroupType::CS_GRP_JUMP;
        let call = CsGroupType::CS_GRP_CALL;
        let ret = CsGroupType::CS_GRP_RET;
        let int = CsGroupType::CS_GRP_INT;
        let iret = CsGroupType::CS_GRP_IRET;

        test_x86_instruction_group_ids_helper("nop", b"\x90", &[]);
        test_x86_instruction_group_ids_helper("je", b"\x74\x05", &[jump]);
        test_x86_instruction_group_ids_helper("call", b"\xe8\x28\x07\x00\x00", &[call]);
        test_x86_instruction_group_ids_helper("ret", b"\xc3", &[ret]);
        test_x86_instruction_group_ids_helper("syscall", b"\x0f\x05", &[int]);
        test_x86_instruction_group_ids_helper("iretd", b"\xcf", &[iret]);
        test_x86_instruction_group_ids_helper("sub", b"\x48\x83\xec\x08", &[]);
        test_x86_instruction_group_ids_helper("test", b"\x48\x85\xc0", &[]);
    }

    #[test]
    fn test_invalid_mode() {
        match capstone::Capstone::new(constants::CsArch::ARCH_ALL, constants::CsMode::MODE_64) {
            Ok(_) => assert!(false, "Invalid open worked"),
            Err(err) => assert!(err == constants::CsErr::CS_ERR_ARCH),
        }
    }

    #[test]
    fn test_capstone_version() {
        let (major, minor) = capstone::lib_version();
        println!("Capstone lib version: ({}, {})", major, minor);
        assert!(major > 0 && major < 100, "Invalid major version {}", major);
        assert!(minor < 500, "Invalid minor version {}", minor);
    }

    #[test]
    fn test_capstone_supports_arch() {
        let architectures = vec![CsArch::ARCH_ARM,
                                 CsArch::ARCH_ARM64,
                                 CsArch::ARCH_MIPS,
                                 CsArch::ARCH_X86,
                                 CsArch::ARCH_PPC,
                                 CsArch::ARCH_SPARC,
                                 CsArch::ARCH_SYSZ,
                                 CsArch::ARCH_XCORE,
                                 CsArch::CS_ARCH_M68K];

        println!("Supported architectures");
        for arch in architectures {
            let supports_arch = capstone::supports_arch(arch);
            println!("  {:?}: {}", arch, if supports_arch { "yes" } else { "no" });
        }
    }

    #[test]
    fn test_capstone_is_diet() {
        println!("Capstone is diet: {}", capstone::is_diet());
    }
}
<commit_msg>Simplify instruction group tests<commit_after>extern crate libc;

pub mod instruction;
pub mod constants;
mod ffi;
pub mod capstone;

pub use instruction::*;
pub use constants::*;

pub use capstone::Capstone;

/// An opaque reference to a capstone engine.
///
/// bindgen by default used this type name everywhere, so it is easier to leave it with a confusing
/// name.
///
/// It should not be exported, rust's new visibility rules make tackling this not immediately
/// obvious
#[allow(non_camel_case_types)]
type csh = libc::size_t;

#[cfg(test)]
mod test {
    use std::collections::HashSet;
    use super::*;

    static CODE: &'static [u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00";

    #[test]
    fn test_x86_simple() {
        match capstone::Capstone::new(constants::CsArch::ARCH_X86, constants::CsMode::MODE_64) {
            Ok(cs) => {
                match cs.disasm(CODE, 0x1000, 0) {
                    Ok(insns) => {
                        assert_eq!(insns.len(), 2);
                        let is: Vec<_> = insns.iter().collect();
                        assert_eq!(is[0].mnemonic().unwrap(), "push");
                        assert_eq!(is[1].mnemonic().unwrap(), "mov");

                        assert_eq!(is[0].address, 0x1000);
                        assert_eq!(is[1].address, 0x1001);

                        assert_eq!(is[0].get_bytes(), b"\x55");
                        assert_eq!(is[1].get_bytes(), b"\x48\x8b\x05\xb8\x13\x00\x00");
                    }
                    Err(err) => assert!(false, "Couldn't disasm instructions: {}", err),
                }
            }
            Err(e) => {
                assert!(false, "Couldn't create a cs engine: {}", e);
            }
        }
    }

    #[test]
    fn test_x86_names() {
        match capstone::Capstone::new(constants::CsArch::ARCH_X86, constants::CsMode::MODE_64) {
            Ok(cs) => {
                let reg_id = 1;
                match cs.reg_name(reg_id) {
                    Some(reg_name) => assert_eq!(reg_name, "ah"),
                    None => assert!(false, "Couldn't get register name"),
                }

                let insn_id = 1;
                match cs.insn_name(insn_id) {
                    Some(insn_name) => assert_eq!(insn_name, "aaa"),
                    None => assert!(false, "Couldn't get instruction name"),
                }

                assert_eq!(cs.group_name(1), Some(String::from("jump")));

                let reg_id = 6000;
                match cs.reg_name(reg_id) {
                    Some(_) => assert!(false, "invalid register worked"),
                    None => {}
                }

                let insn_id = 6000;
                match cs.insn_name(insn_id) {
                    Some(_) => assert!(false, "invalid instruction worked"),
                    None => {}
                }

                assert_eq!(cs.group_name(6000), None);
            }
            Err(e) => {
                assert!(false, "Couldn't create a cs engine: {}", e);
            }
        }
    }

    #[test]
    fn test_detail_false_fail() {
        let mut cs = capstone::Capstone::new(constants::CsArch::ARCH_X86,
                                             constants::CsMode::MODE_64)
                .unwrap();
        cs.set_detail(false).unwrap();
        let insns: Vec<_> = cs.disasm(CODE, 0x1000, 0).unwrap().iter().collect();
        assert_eq!(cs.insn_belongs_to_group(&insns[0], 0),
                   Err(CsErr::CS_ERR_DETAIL));
        assert_eq!(cs.insn_belongs_to_group(&insns[1], 0),
                   Err(CsErr::CS_ERR_DETAIL));
    }

    #[test]
    fn test_detail_true() {
        let mut cs = capstone::Capstone::new(constants::CsArch::ARCH_X86,
                                             constants::CsMode::MODE_64)
                .unwrap();
        cs.set_detail(true).unwrap();
        let insns: Vec<_> = cs.disasm(CODE, 0x1000, 0).unwrap().iter().collect();
        let insn_group_ids = [CsGroupType::CS_GRP_JUMP,
                              CsGroupType::CS_GRP_CALL,
                              CsGroupType::CS_GRP_RET,
                              CsGroupType::CS_GRP_INT,
                              CsGroupType::CS_GRP_IRET];
        for insn_idx in 0..1 + 1 {
            for insn_group_id in &insn_group_ids {
                assert_eq!(cs.insn_belongs_to_group(&insns[insn_idx], *insn_group_id as u64),
                           Ok(false));
            }
        }
    }

    /// Assert instruction belongs or does not belong to groups, testing both insn_belongs_to_group
    /// and get_insn_group_ids
    fn test_x86_instruction_group_ids_helper(mnemonic_name: &str,
                                             bytes: &[u8],
                                             expected_groups: &[CsGroupType]) {
        let mut cs = capstone::Capstone::new(constants::CsArch::ARCH_X86,
                                             constants::CsMode::MODE_64)
                .expect("Failed to create capstone handle");

        // Details required to get groups information
        cs.set_detail(true).unwrap();

        // Disassemble instructions
        let insns: Vec<_> = cs.disasm(bytes, 0x1000, 0)
            .expect("Failed to disassemble")
            .iter()
            .collect();

        // Check number of instructions
        assert_eq!(insns.len(), 1, "Expected exactly 1 instruction");

        let insn = &insns[0];

        // Check mnemonic
        assert_eq!(mnemonic_name,
                   cs.insn_name(insn.get_id() as u64)
                       .expect("Failed to get instruction name"));

        // Assert expected instruction groups is a subset of computed groups
        let instruction_groups: HashSet<u8> = cs.get_insn_group_ids(&insn)
            .expect("failed to get instruction groups")
            .iter()
            .map(|&x| x)
            .collect();
        let expected_groups_u8: HashSet<u8> = expected_groups.iter().map(|&x| x as u8).collect();
        assert!(expected_groups_u8.is_subset(&instruction_groups),
                "Expected groups {:?} does NOT match computed insn groups {:?}",
                expected_groups_u8,
                instruction_groups);

        // Create sets of expected groups and unexpected groups
        let instruction_types: HashSet<CsGroupType> = [CsGroupType::CS_GRP_JUMP,
                                                       CsGroupType::CS_GRP_CALL,
                                                       CsGroupType::CS_GRP_RET,
                                                       CsGroupType::CS_GRP_INT,
                                                       CsGroupType::CS_GRP_IRET]
                .iter()
                .cloned()
                .collect();
        let expected_groups_set: HashSet<CsGroupType> =
            expected_groups.iter().map(|&x| x).collect();
        let not_belong_groups = instruction_types.difference(&expected_groups_set);

        // Assert instruction belongs to belong_groups
        for belong_group in expected_groups {
            assert_eq!(Ok(true),
                       cs.insn_belongs_to_group(&insn, *belong_group as u64),
                       "{:?} does NOT BELONG to group {:?}, but the instruction SHOULD",
                       insn,
                       *belong_group);
        }

        // Assert instruction does not belong to not_belong_groups
        for not_belong_group in not_belong_groups {
            assert_eq!(Ok(false),
                       cs.insn_belongs_to_group(&insn, *not_belong_group as u64),
                       "{:?} BELONGS to group {:?}, but the instruction SHOULD NOT",
                       insn,
                       *not_belong_group);
        }
    }

    #[test]
    fn test_instruction_group_ids() {
        let jump = CsGroupType::CS_GRP_JUMP;
        let call = CsGroupType::CS_GRP_CALL;
        let ret = CsGroupType::CS_GRP_RET;
        let int = CsGroupType::CS_GRP_INT;
        let iret = CsGroupType::CS_GRP_IRET;

        test_x86_instruction_group_ids_helper("nop", b"\x90", &[]);
        test_x86_instruction_group_ids_helper("je", b"\x74\x05", &[jump]);
        test_x86_instruction_group_ids_helper("call", b"\xe8\x28\x07\x00\x00", &[call]);
        test_x86_instruction_group_ids_helper("ret", b"\xc3", &[ret]);
        test_x86_instruction_group_ids_helper("syscall", b"\x0f\x05", &[int]);
        test_x86_instruction_group_ids_helper("iretd", b"\xcf", &[iret]);
        test_x86_instruction_group_ids_helper("sub", b"\x48\x83\xec\x08", &[]);
        test_x86_instruction_group_ids_helper("test", b"\x48\x85\xc0", &[]);
    }

    #[test]
    fn test_invalid_mode() {
        match capstone::Capstone::new(constants::CsArch::ARCH_ALL, constants::CsMode::MODE_64) {
            Ok(_) => assert!(false, "Invalid open worked"),
            Err(err) => assert!(err == constants::CsErr::CS_ERR_ARCH),
        }
    }

    #[test]
    fn test_capstone_version() {
        let (major, minor) = capstone::lib_version();
        println!("Capstone lib version: ({}, {})", major, minor);
        assert!(major > 0 && major < 100, "Invalid major version {}", major);
        assert!(minor < 500, "Invalid minor version {}", minor);
    }

    #[test]
    fn test_capstone_supports_arch() {
        let architectures = vec![CsArch::ARCH_ARM,
                                 CsArch::ARCH_ARM64,
                                 CsArch::ARCH_MIPS,
                                 CsArch::ARCH_X86,
                                 CsArch::ARCH_PPC,
                                 CsArch::ARCH_SPARC,
                                 CsArch::ARCH_SYSZ,
                                 CsArch::ARCH_XCORE,
                                 CsArch::CS_ARCH_M68K];

        println!("Supported architectures");
        for arch in architectures {
            let supports_arch = capstone::supports_arch(arch);
            println!("  {:?}: {}", arch, if supports_arch { "yes" } else { "no" });
        }
    }

    #[test]
    fn test_capstone_is_diet() {
        println!("Capstone is diet: {}", capstone::is_diet());
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use std::str;
use std::str::FromStr;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;

// TODO: store formatting hints in Sexp
#[derive(Debug, Clone)]
pub struct Sexp {
    element:Element,
}

#[derive(Debug, Clone)]
pub enum Element {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

pub type ERes<T> = Result<T, String>;

impl Sexp {

    fn new_empty() -> Sexp {
        Sexp { element:Element::Empty }
    }

    fn from(element:Element) -> Sexp {
        Sexp { element:element }
    }

    pub fn list(&self) -> ERes<&Vec<Sexp> > {
        match self.element {
            Element::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> ERes<&String> {
        match self.element {
            Element::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self))
        }
    }

    pub fn f(&self) -> ERes<f64> {
        let s = try!(self.string());
        match f64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing float"))
        }
    }

    pub fn i(&self) -> ERes<i64> {
        let s = try!(self.string());
        match i64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing int"))
        }
    }

    pub fn list_name(&self) -> ERes<&String> {
        let l = try!(self.list());
        let l = &l[..];
        let a = try!(l[0].string());
        Ok(a)
    }

    pub fn slice_atom(&self, s:&str) -> ERes<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st))
        };
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.element {
            Element::String(ref s) => {
                if s.contains("(") || s.contains(" ") {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Element::List(ref v) => {
                try!(write!(f, "("));
                for (i, x) in v.iter().enumerate() {
                    let s = if i == 0 { "" } else { " " };
                    try!(write!(f, "{}{}", s, x));
                }
                write!(f, ")")
            },
            Element::Empty => Ok(())
        }
    }
}

pub fn display_string(s:&String) -> String {
    if s.contains("(") || s.contains(" ") || s.len() == 0 {
        format!("\"{}\"", s)
    } else {
        s.clone()
    }
}

pub fn parse_str(sexp: &str) -> Result<Sexp, String> {
    if sexp.len() == 0 {
        return Ok(Sexp::new_empty())
    }
    match parse_sexp(&sexp.as_bytes()[..]) {
        nom::IResult::Done(_, c) => Ok(c),
        nom::IResult::Error(err) => {
            match err {
                nom::Err::Position(kind,p) =>
                    Err(format!("parse error: {:?} |{}|", kind, str::from_utf8(p).unwrap())),
                _ => Err(format!("parse error"))
            }
        },
        nom::IResult::Incomplete(x) => Err(format!("incomplete: {:?}", x)),
    }
}

fn read_file(name: &str) -> Result<String, std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_file(name: &str) -> ERes<Sexp> {
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("{:?}", x))
    });
    parse_str(&s[..])
}

named!(parse_qstring<String>,
       map_res!(
           map_res!(
               delimited!(char!('\"'), is_not!("\""), char!('\"')),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_bare_string<String>,
       map_res!(
           map_res!(
               is_not!(b")( \r\n"),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_string<String>,
       alt!(parse_qstring | parse_bare_string)
       );

named!(parse_list<Vec<Sexp> >,
       chain!(
           char!('(') ~
           v: many0!(parse_sexp) ~
           char!(')'),
           || v)
       );

named!(parse_sexp<Sexp>,
       map!(
       chain!(
           opt!(nom::multispace) ~
               s: alt!(map!(parse_list,Element::List) | map!(parse_string,Element::String)) ~
               opt!(nom::multispace)
               ,|| s),
               Sexp::from)
       );

// internal tests
#[test]
fn test_qstring1() {
    assert_eq!(parse_string(&b"\"hello world\""[..]), nom::IResult::Done(&b""[..], String::from("hello world")));
}

#[test]
#[should_panic(expected="assertion failed: `(left == right)` (left: `Incomplete(Size(1))`, right: `Done([], \"hello\")`)")]
fn test_qstring2() {
    assert_eq!(parse_string(&b"\"hello"[..]), nom::IResult::Done(&b""[..], String::from("hello")));
}

#[test]
fn test_string1() {
    assert_eq!(parse_string(&b"hello world"[..]), nom::IResult::Done(&b" world"[..], String::from("hello")));
}

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

    #[allow(dead_code)]
    fn check_parse_res(s: &str, o:&str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(o, t)
    }
    #[allow(dead_code)]
    fn check_parse(s: &str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(s, t)
    }

    #[allow(dead_code)]
    fn parse_fail(s: &str) {
        parse_str(s).unwrap();
    }

    #[test]
    fn test_empty() { check_parse("") }

    #[test]
    fn test_empty_qstring() { check_parse("(hello \"\")") }

    #[test]
    fn test_minimal() { check_parse("()") }

    #[test]
    fn test_string() { check_parse("hello") }

    #[test]
    fn test_qstring_a() { check_parse_res("\"hello\"", "hello") }

    #[test]
    fn test_qstring_a2() { check_parse("\"hello world\"") }

    #[test]
    fn test_qstring_a3() { check_parse("\"hello(world)\"") }

    #[test]
    fn test_number() { check_parse("1.3") }

    #[test]
    fn test_float_vs_int() { check_parse("2.0") }

    #[test]
    fn test_double() { check_parse("(())") }

    #[test]
    fn test_br_string() { check_parse("(world)") }

    #[test]
    fn test_br_qstring() { check_parse_res("(\"world\")", "(world)") }

    #[test]
    fn test_br_int() { check_parse("(42)") }

    #[test]
    fn test_br_float() { check_parse("(12.7)") }

    #[test]
    fn test_br_qbrstring() { check_parse("(\"(()\")") }

    #[test]
    fn test_number_string() { check_parse("567A_WZ") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(2)\"")]
    fn test_invalid1() { parse_fail("(") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"parse error: Alt |)|\"")]
    fn test_invalid2() { parse_fail(")") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(1)\"")]
    fn test_invalid3() { parse_fail("\"hello") }

    #[test]
    fn test_complex() { check_parse("(module SWITCH_3W_SIDE_MMP221-R (layer F.Cu) (descr \"\") (pad 1 thru_hole rect (size 1.2 1.2) (at -2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 2 thru_hole rect (size 1.2 1.2) (at 0.0 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 3 thru_hole rect (size 1.2 1.2) (at 2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 5 thru_hole rect (size 1.2 1.2) (at 0.0 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 6 thru_hole rect (size 1.2 1.2) (at -2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 4 thru_hole rect (size 1.2 1.2) (at 2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (fp_line (start -4.5 -1.75) (end 4.5 -1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 -1.75) (end 4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 1.75) (end -4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start -4.5 1.75) (end -4.5 -1.75) (layer F.SilkS) (width 0.127)))") }
}

<commit_msg>indent,nl (unused)<commit_after>#[macro_use]
extern crate nom;

use std::str;
use std::str::FromStr;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;

// TODO: store formatting hints in Sexp
#[derive(Debug, Clone)]
pub struct Sexp {
    element:Element,
    indent:i64,
    nl:bool,
}

#[derive(Debug, Clone)]
pub enum Element {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

pub type ERes<T> = Result<T, String>;

impl Sexp {

    fn new_empty() -> Sexp {
        Sexp { element:Element::Empty, indent:0, nl:false, }
    }

    fn from(element:Element) -> Sexp {
        Sexp { element:element, indent:0, nl:false, }
    }

    pub fn list(&self) -> ERes<&Vec<Sexp> > {
        match self.element {
            Element::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> ERes<&String> {
        match self.element {
            Element::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self))
        }
    }

    pub fn f(&self) -> ERes<f64> {
        let s = try!(self.string());
        match f64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing float"))
        }
    }

    pub fn i(&self) -> ERes<i64> {
        let s = try!(self.string());
        match i64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing int"))
        }
    }

    pub fn list_name(&self) -> ERes<&String> {
        let l = try!(self.list());
        let l = &l[..];
        let a = try!(l[0].string());
        Ok(a)
    }

    pub fn slice_atom(&self, s:&str) -> ERes<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st))
        };
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.element {
            Element::String(ref s) => {
                if s.contains("(") || s.contains(" ") {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Element::List(ref v) => {
                try!(write!(f, "("));
                for (i, x) in v.iter().enumerate() {
                    let s = if i == 0 { "" } else { " " };
                    try!(write!(f, "{}{}", s, x));
                }
                write!(f, ")")
            },
            Element::Empty => Ok(())
        }
    }
}

pub fn display_string(s:&String) -> String {
    if s.contains("(") || s.contains(" ") || s.len() == 0 {
        format!("\"{}\"", s)
    } else {
        s.clone()
    }
}

pub fn parse_str(sexp: &str) -> Result<Sexp, String> {
    if sexp.len() == 0 {
        return Ok(Sexp::new_empty())
    }
    match parse_sexp(&sexp.as_bytes()[..]) {
        nom::IResult::Done(_, c) => Ok(c),
        nom::IResult::Error(err) => {
            match err {
                nom::Err::Position(kind,p) =>
                    Err(format!("parse error: {:?} |{}|", kind, str::from_utf8(p).unwrap())),
                _ => Err(format!("parse error"))
            }
        },
        nom::IResult::Incomplete(x) => Err(format!("incomplete: {:?}", x)),
    }
}

fn read_file(name: &str) -> Result<String, std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_file(name: &str) -> ERes<Sexp> {
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("{:?}", x))
    });
    parse_str(&s[..])
}

named!(parse_qstring<String>,
       map_res!(
           map_res!(
               delimited!(char!('\"'), is_not!("\""), char!('\"')),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_bare_string<String>,
       map_res!(
           map_res!(
               is_not!(b")( \r\n"),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_string<String>,
       alt!(parse_qstring | parse_bare_string)
       );

named!(parse_list<Vec<Sexp> >,
       chain!(
           char!('(') ~
           v: many0!(parse_sexp) ~
           char!(')'),
           || v)
       );

named!(parse_sexp<Sexp>,
       map!(
           chain!(
               // TODO: count space
               opt!(nom::multispace) ~
               s: alt!(map!(parse_list,Element::List) | map!(parse_string,Element::String)) ~
               opt!(nom::multispace)
               // TODO: eat space and return nl
               ,|| s),
               Sexp::from)
       );

// internal tests
#[test]
fn test_qstring1() {
    assert_eq!(parse_string(&b"\"hello world\""[..]), nom::IResult::Done(&b""[..], String::from("hello world")));
}

#[test]
#[should_panic(expected="assertion failed: `(left == right)` (left: `Incomplete(Size(1))`, right: `Done([], \"hello\")`)")]
fn test_qstring2() {
    assert_eq!(parse_string(&b"\"hello"[..]), nom::IResult::Done(&b""[..], String::from("hello")));
}

#[test]
fn test_string1() {
    assert_eq!(parse_string(&b"hello world"[..]), nom::IResult::Done(&b" world"[..], String::from("hello")));
}

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

    #[allow(dead_code)]
    fn check_parse_res(s: &str, o:&str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(o, t)
    }
    #[allow(dead_code)]
    fn check_parse(s: &str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(s, t)
    }

    #[allow(dead_code)]
    fn parse_fail(s: &str) {
        parse_str(s).unwrap();
    }

    #[test]
    fn test_empty() { check_parse("") }

    #[test]
    fn test_empty_qstring() { check_parse("(hello \"\")") }

    #[test]
    fn test_minimal() { check_parse("()") }

    #[test]
    fn test_string() { check_parse("hello") }

    #[test]
    fn test_qstring_a() { check_parse_res("\"hello\"", "hello") }

    #[test]
    fn test_qstring_a2() { check_parse("\"hello world\"") }

    #[test]
    fn test_qstring_a3() { check_parse("\"hello(world)\"") }

    #[test]
    fn test_number() { check_parse("1.3") }

    #[test]
    fn test_float_vs_int() { check_parse("2.0") }

    #[test]
    fn test_double() { check_parse("(())") }

    #[test]
    fn test_br_string() { check_parse("(world)") }

    #[test]
    fn test_br_qstring() { check_parse_res("(\"world\")", "(world)") }

    #[test]
    fn test_br_int() { check_parse("(42)") }

    #[test]
    fn test_br_float() { check_parse("(12.7)") }

    #[test]
    fn test_br_qbrstring() { check_parse("(\"(()\")") }

    #[test]
    fn test_number_string() { check_parse("567A_WZ") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(2)\"")]
    fn test_invalid1() { parse_fail("(") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"parse error: Alt |)|\"")]
    fn test_invalid2() { parse_fail(")") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(1)\"")]
    fn test_invalid3() { parse_fail("\"hello") }

    #[test]
    fn test_complex() { check_parse("(module SWITCH_3W_SIDE_MMP221-R (layer F.Cu) (descr \"\") (pad 1 thru_hole rect (size 1.2 1.2) (at -2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 2 thru_hole rect (size 1.2 1.2) (at 0.0 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 3 thru_hole rect (size 1.2 1.2) (at 2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 5 thru_hole rect (size 1.2 1.2) (at 0.0 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 6 thru_hole rect (size 1.2 1.2) (at -2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 4 thru_hole rect (size 1.2 1.2) (at 2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (fp_line (start -4.5 -1.75) (end 4.5 -1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 -1.75) (end 4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 1.75) (end -4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start -4.5 1.75) (end -4.5 -1.75) (layer F.SilkS) (width 0.127)))") }
}

<|endoftext|>


<commit_before>//! This library allows you to communicate with an IGD enabled device.
//! Use one of the `search_gateway` functions to obtain a `Gateway` object.
//! You can then communicate with the device via this object.

#![deny(missing_docs)]

extern crate hyper;
extern crate regex;
extern crate xml;
extern crate xmltree;
extern crate rand;

// data structures
pub use self::gateway::Gateway;
pub use self::gateway::PortMappingProtocol;
pub use self::gateway::RequestError;

// search of gateway
pub use self::search::search_gateway;
pub use self::search::search_gateway_timeout;
pub use self::search::search_gateway_from;
pub use self::search::search_gateway_from_timeout;
pub use self::search::SearchError;

// re-export error types
pub use hyper::Error as HttpError;
pub use xml::common::Error as XmlError;

mod gateway;
mod search;
mod soap;
<commit_msg>Export error types.<commit_after>//! This library allows you to communicate with an IGD enabled device.
//! Use one of the `search_gateway` functions to obtain a `Gateway` object.
//! You can then communicate with the device via this object.

#![deny(missing_docs)]

extern crate hyper;
extern crate regex;
extern crate xml;
extern crate xmltree;
extern crate rand;

// data structures
pub use self::gateway::Gateway;
pub use self::gateway::PortMappingProtocol;
pub use self::gateway::RequestError;
pub use self::gateway::GetExternalIpError;
pub use self::gateway::RemovePortError;
pub use self::gateway::AddPortError;
pub use self::gateway::AddAnyPortError;

// search of gateway
pub use self::search::search_gateway;
pub use self::search::search_gateway_timeout;
pub use self::search::search_gateway_from;
pub use self::search::search_gateway_from_timeout;
pub use self::search::SearchError;

// re-export error types
pub use hyper::Error as HttpError;
pub use xml::common::Error as XmlError;

mod gateway;
mod search;
mod soap;
<|endoftext|>