<commit_before>// Copyright © 2016 Cormac O'Brien
//
// 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.

extern crate byteorder;
extern crate env_logger;
#[macro_use]
extern crate num;
extern crate log;
extern crate pnet;
extern crate richter;

use byteorder::{LittleEndian, ReadBytesExt};
use num::FromPrimitive;
use std::fmt;
use std::io::Cursor;
use std::str::{self, FromStr};
use pnet::packet::Packet;
use pnet::packet::udp::UdpPacket;
use pnet::packet::ip::IpNextHeaderProtocols::Udp;
use pnet::transport::{self, TransportChannelType};
use richter::qw::{self, ClCmd, MoveDelta, MoveDeltaFlags, SvCmd};

static USAGE: &'static str = "Usage: cl-sniff <client IP> <client port> <server IP> <server port>";

const SEQUENCE_RELIABLE: i32 = (1 << 31);

enum QwPacket {
    Oob(OobPacket),
    Netchan(NetchanPacket),
}

impl QwPacket {
    pub fn new<'a>(src: &'a [u8]) -> QwPacket {
        if src.len() < 4 {
            panic!("Packet is too short");
        }

        let mut curs = Cursor::new(src);
        let seq = curs.read_i32::<LittleEndian>().unwrap();

        if seq == -1 {
            return QwPacket::Oob(OobPacket::new(&curs.into_inner()[4..]));
        }

        if src.len() < 8 {
            panic!("Packet is too short for a netchannel packet");
        }

        let ack_seq = curs.read_i32::<LittleEndian>().unwrap();
        let payload = Vec::from(&curs.into_inner()[8..]);

        QwPacket::Netchan(NetchanPacket {
            seq: seq,
            ack: ack_seq,
            payload: payload,
        })
    }
}

enum OobPacket {
    GetChallenge,
    Challenge(i32),
    Connect(ConnectPacket),
    Accept,
    Ping,
    Ack,
    Status,
    Log,
    Rcon,
}

impl OobPacket {
    pub fn new<'a>(src: &'a [u8]) -> OobPacket {
        // TODO: specify a maximum out-of-band packet length
        let mut len = 0;
        while len < src.len() && src[len] != 0 {
            len += 1;
        }

        let cmd_text = String::from(str::from_utf8(&src[..len]).unwrap());
        let mut cmd_args = cmd_text.split_whitespace();

        match cmd_args.next().unwrap() {
            "getchallenge" => OobPacket::GetChallenge,
            "ping" | "k" => OobPacket::Ping,
            "l" => OobPacket::Ack,
            "status" => OobPacket::Status,
            "log" => OobPacket::Log,
            "connect" => {
                let qwcol = i32::from_str(cmd_args.next().unwrap()).unwrap();
                let qport = u16::from_str(cmd_args.next().unwrap()).unwrap();
                let challenge = i32::from_str(cmd_args.next().unwrap()).unwrap();

                OobPacket::Connect(ConnectPacket {
                    qwcol: qwcol,
                    qport: qport,
                    challenge: challenge,
                    userinfo: String::from(cmd_args.next().unwrap()),
                })
            }
            "rcon" => OobPacket::Rcon,
            "j" => OobPacket::Accept,
            s => {
                if s.starts_with("c") {
                    return OobPacket::Challenge(i32::from_str(&s[1..]).unwrap());
                } else {
                    panic!("Unrecognized out-of-band command");
                }
            }
        }
    }
}

struct ConnectPacket {
    qwcol: i32,
    qport: u16,
    challenge: i32,
    userinfo: String,
}

impl fmt::Display for ConnectPacket {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "qw={} qport={} challenge={} userinfo={}",
               self.qwcol,
               self.qport,
               self.challenge,
               self.userinfo)
    }
}

struct NetchanPacket {
    seq: i32,
    ack: i32,
    payload: Vec<u8>,
}

impl NetchanPacket {
    pub fn get_sequence(&self) -> i32 {
        self.seq & !SEQUENCE_RELIABLE
    }

    pub fn get_sequence_reliable(&self) -> bool {
        self.seq & SEQUENCE_RELIABLE == SEQUENCE_RELIABLE
    }

    pub fn get_ack_sequence(&self) -> i32 {
        self.ack & !SEQUENCE_RELIABLE
    }

    pub fn get_ack_sequence_reliable(&self) -> bool {
        self.ack & SEQUENCE_RELIABLE == SEQUENCE_RELIABLE
    }

    pub fn payload(&self) -> &[u8] {
        &self.payload
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 5 {
        println!("{}", USAGE);
        std::process::exit(1);
    }

    let client_ip = std::net::Ipv4Addr::from_str(&args[1]).unwrap();
    let client_port = u16::from_str(&args[2]).unwrap();
    let server_ip = std::net::Ipv4Addr::from_str(&args[3]).unwrap();
    let server_port = u16::from_str(&args[4]).unwrap();

    let (_, mut rx) = match pnet::transport::transport_channel(4096,
                                                               TransportChannelType::Layer3(Udp)) {
        Ok((tx, rx)) => (tx, rx),
        Err(why) => panic!("Error creating channel: {}", why),
    };

    let mut iter = transport::ipv4_packet_iter(&mut rx);
    loop {
        match iter.next() {
            Ok((packet, addr)) => {
                let udp_packet = UdpPacket::new(packet.payload()).unwrap();
                let dest_ip = packet.get_destination();
                let dest_port = udp_packet.get_destination();

                if dest_ip == server_ip && dest_port == server_port {
                    print!("CL: ");
                } else if dest_ip == client_ip && dest_port == client_port {
                    print!("SV: ");
                } else {
                    continue;
                }

                let qw_packet = QwPacket::new(udp_packet.payload());
                match qw_packet {
                    QwPacket::Oob(oob_packet) => {
                        match oob_packet {
                            OobPacket::GetChallenge => println!("getchallenge"),
                            OobPacket::Challenge(challenge) => println!("challenge={}", challenge),
                            OobPacket::Connect(conn_packet) => println!("{}", conn_packet),
                            _ => (),
                        }
                    }

                    QwPacket::Netchan(nc_packet) => {
                        print!("seq={} [", nc_packet.get_sequence());
                        if nc_packet.get_sequence_reliable() {
                            print!("R");
                        } else {
                            print!(" ");
                        }
                        print!("] ack={} ", nc_packet.get_ack_sequence());

                        let mut curs = Cursor::new(nc_packet.payload());

                        if dest_ip == server_ip && dest_port == server_port {
                            let qport = curs.read_u16::<LittleEndian>().unwrap();
                            print!("qport={} ", qport);

                            match ClCmd::from_u8(curs.read_u8().unwrap()).unwrap() {
                                ClCmd::Move => {
                                    let flags = MoveDeltaFlags::from_bits(curs.read_u8().unwrap())
                                                    .unwrap();
                                    print!("move: ");

                                    if flags.contains(qw::CM_ANGLE1) {
                                        print!("angle1 ");
                                    }
                                }
                                _ => (),
                            }
                        } else if dest_ip == client_ip && dest_port == client_port {
                        }
                    }
                }

                println!("");
            }

            Err(why) => panic!("Error reading packet: {}"),
        }
    }
}
<commit_msg>Add support for logging client move commands<commit_after>// Copyright © 2016 Cormac O'Brien
//
// 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.

extern crate byteorder;
extern crate env_logger;
#[macro_use]
extern crate num;
extern crate log;
extern crate pnet;
extern crate richter;

use byteorder::{LittleEndian, ReadBytesExt};
use num::FromPrimitive;
use std::fmt;
use std::io::Cursor;
use std::str::{self, FromStr};
use pnet::packet::Packet;
use pnet::packet::udp::UdpPacket;
use pnet::packet::ip::IpNextHeaderProtocols::Udp;
use pnet::transport::{self, TransportChannelType};
use richter::qw::{self, ClCmd, MoveDelta, MoveDeltaFlags, SvCmd};

static USAGE: &'static str = "Usage: cl-sniff <client IP> <client port> <server IP> <server port>";

const SEQUENCE_RELIABLE: i32 = (1 << 31);

enum QwPacket {
    Oob(OobPacket),
    Netchan(NetchanPacket),
}

impl QwPacket {
    pub fn new<'a>(src: &'a [u8]) -> QwPacket {
        if src.len() < 4 {
            panic!("Packet is too short");
        }

        let mut curs = Cursor::new(src);
        let seq = curs.read_i32::<LittleEndian>().unwrap();

        if seq == -1 {
            return QwPacket::Oob(OobPacket::new(&curs.into_inner()[4..]));
        }

        if src.len() < 8 {
            panic!("Packet is too short for a netchannel packet");
        }

        let ack_seq = curs.read_i32::<LittleEndian>().unwrap();
        let payload = Vec::from(&curs.into_inner()[8..]);

        QwPacket::Netchan(NetchanPacket {
            seq: seq,
            ack: ack_seq,
            payload: payload,
        })
    }
}

enum OobPacket {
    GetChallenge,
    Challenge(i32),
    Connect(ConnectPacket),
    Accept,
    Ping,
    Ack,
    Status,
    Log,
    Rcon,
}

impl OobPacket {
    pub fn new<'a>(src: &'a [u8]) -> OobPacket {
        // TODO: specify a maximum out-of-band packet length
        let mut len = 0;
        while len < src.len() && src[len] != 0 {
            len += 1;
        }

        let cmd_text = String::from(str::from_utf8(&src[..len]).unwrap());
        let mut cmd_args = cmd_text.split_whitespace();

        match cmd_args.next().unwrap() {
            "getchallenge" => OobPacket::GetChallenge,
            "ping" | "k" => OobPacket::Ping,
            "l" => OobPacket::Ack,
            "status" => OobPacket::Status,
            "log" => OobPacket::Log,
            "connect" => {
                let qwcol = i32::from_str(cmd_args.next().unwrap()).unwrap();
                let qport = u16::from_str(cmd_args.next().unwrap()).unwrap();
                let challenge = i32::from_str(cmd_args.next().unwrap()).unwrap();

                OobPacket::Connect(ConnectPacket {
                    qwcol: qwcol,
                    qport: qport,
                    challenge: challenge,
                    userinfo: String::from(cmd_args.next().unwrap()),
                })
            }
            "rcon" => OobPacket::Rcon,
            "j" => OobPacket::Accept,
            s => {
                if s.starts_with("c") {
                    return OobPacket::Challenge(i32::from_str(&s[1..]).unwrap());
                } else {
                    panic!("Unrecognized out-of-band command");
                }
            }
        }
    }
}

struct ConnectPacket {
    qwcol: i32,
    qport: u16,
    challenge: i32,
    userinfo: String,
}

impl fmt::Display for ConnectPacket {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "qw={} qport={} challenge={} userinfo={}",
               self.qwcol,
               self.qport,
               self.challenge,
               self.userinfo)
    }
}

struct NetchanPacket {
    seq: i32,
    ack: i32,
    payload: Vec<u8>,
}

impl NetchanPacket {
    pub fn get_sequence(&self) -> i32 {
        self.seq & !SEQUENCE_RELIABLE
    }

    pub fn get_sequence_reliable(&self) -> bool {
        self.seq & SEQUENCE_RELIABLE == SEQUENCE_RELIABLE
    }

    pub fn get_ack_sequence(&self) -> i32 {
        self.ack & !SEQUENCE_RELIABLE
    }

    pub fn get_ack_sequence_reliable(&self) -> bool {
        self.ack & SEQUENCE_RELIABLE == SEQUENCE_RELIABLE
    }

    pub fn payload(&self) -> &[u8] {
        &self.payload
    }
}

fn transcribe_clcmd<'a>(src: &'a [u8]) -> String {
    let mut result = String::new();
    let mut curs = Cursor::new(src);

    let qport = curs.read_u16::<LittleEndian>().unwrap();
    result += &format!("qport={} ", qport);

    match ClCmd::from_u8(curs.read_u8().unwrap()).unwrap() {
        ClCmd::Move => {
            result += &format!("Move ");
            result += &format!("crc={} ", curs.read_u8().unwrap());
            result += &format!("loss={} ", curs.read_u8().unwrap());

            let indent = result.len();

            for i in 0..3 {
                result += &format!("[D{}] ", i);

                let flags = MoveDeltaFlags::from_bits(curs.read_u8().unwrap()).unwrap();

                if flags.contains(qw::CM_ANGLE1) {
                    result += &format!("angle1={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::CM_ANGLE2) {
                    result += &format!("angle2={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::CM_ANGLE3) {
                    result += &format!("angle3={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::CM_FORWARD) {
                    result += &format!("forward={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::CM_SIDE) {
                    result += &format!("side={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::CM_UP) {
                    result += &format!("up={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::CM_BUTTONS) {
                    result += &format!("buttons={} ", curs.read_u8().unwrap());
                }

                if flags.contains(qw::CM_IMPULSE) {
                    result += &format!("impulse={} ", curs.read_u8().unwrap());
                }

                result += &format!("msec={} ", curs.read_u8().unwrap());
            }
        }

        _ => (),
    }

    return result;
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 5 {
        println!("{}", USAGE);
        std::process::exit(1);
    }

    let client_ip = std::net::Ipv4Addr::from_str(&args[1]).unwrap();
    let client_port = u16::from_str(&args[2]).unwrap();
    let server_ip = std::net::Ipv4Addr::from_str(&args[3]).unwrap();
    let server_port = u16::from_str(&args[4]).unwrap();

    let (_, mut rx) = match pnet::transport::transport_channel(4096,
                                                               TransportChannelType::Layer3(Udp)) {
        Ok((tx, rx)) => (tx, rx),
        Err(why) => panic!("Error creating channel: {}", why),
    };

    let mut iter = transport::ipv4_packet_iter(&mut rx);
    loop {
        match iter.next() {
            Ok((packet, addr)) => {
                let udp_packet = UdpPacket::new(packet.payload()).unwrap();
                let dest_ip = packet.get_destination();
                let dest_port = udp_packet.get_destination();

                if dest_ip == server_ip && dest_port == server_port {
                    print!("CL: ");
                } else if dest_ip == client_ip && dest_port == client_port {
                    print!("SV: ");
                } else {
                    continue;
                }

                let qw_packet = QwPacket::new(udp_packet.payload());
                match qw_packet {
                    QwPacket::Oob(oob_packet) => {
                        match oob_packet {
                            OobPacket::GetChallenge => println!("getchallenge"),
                            OobPacket::Challenge(challenge) => println!("challenge={}", challenge),
                            OobPacket::Connect(conn_packet) => println!("{}", conn_packet),
                            OobPacket::Accept => println!("accept"),
                            _ => (),
                        }
                    }

                    QwPacket::Netchan(nc_packet) => {
                        print!("seq={} [", nc_packet.get_sequence());
                        if nc_packet.get_sequence_reliable() {
                            print!("R");
                        } else {
                            print!(" ");
                        }
                        print!("] ack={} ", nc_packet.get_ack_sequence());

                        if dest_ip == server_ip && dest_port == server_port {
                            print!("{} ", transcribe_clcmd(nc_packet.payload()));
                        } else if dest_ip == client_ip && dest_port == client_port {
                        }
                    }
                }

                println!("");
            }

            Err(why) => panic!("Error reading packet: {}", why),
        }
    }
}
<|endoftext|>


<commit_before>/**
Efficient Exponentiation
Problem 122
https://projecteuler.net/problem=122

The most naive way of computing n^15 requires fourteen Multiplications:

n × n × ... × n = n^15

But using a "binary" method you can compute it in six Multiplications:

n × n = n^2
n^2 × n^2 = n^4
n^4 × n^4 = n^8
n^8 × n^4 = n^12
n^12 × n^2 = n^14
n^14 × n = n^15

However it is yet possible to compute it in only five Multiplications:

n × n = n^2
n^2 × n = n^3
n^3 × n^3 = n^6
n^6 × n^6 = n^12
n^12 × n^3 = n^15

We shall define m(k) to be the minimum number of Multiplications to compute n^k; for example m(15) = 5.

For 1 ≤ k ≤ 200, find ∑ m(k).

----------------------------------------------------------------------------------------------------

**/

extern crate eulerrust;
use std::collections::TrieMap;
use std::collections::dlist::DList;
use std::collections::Deque;

fn merge_vecs<T : Eq + Clone>(v1 : &Vec<T>, v2 : &Vec<T>) -> Vec<T> {
	let mut v : Vec<T> = v1.clone();
	for val in v2.iter() {
		if v.contains(val) {continue;};
		v.push(val.clone());
	}

	v
}

pub struct Multiplications {
	sum : uint,
	path : Vec<(uint, uint, uint)> // x,y,z where n^x = n^y * n^z
}

impl Multiplications {
	pub fn contains(&self, n : uint) -> bool {
		let mut f = self.path.iter().filter(|&&(nsum, _, _)| {n == nsum});
		match f.next() {
			Some(_) => true,
			None => false
		}
	}

	pub fn append(&self, n1 : uint, n2 : uint) -> Multiplications {
		let mut newpath = self.path.clone();
		newpath.push((n1 + n2, n1, n2));
		Multiplications {
			sum : n1 + n2,
			path : newpath
		}
	}
}

fn find_ms(n : uint) -> TrieMap<Vec<(uint,uint,uint)>> {
	let mut tmap = TrieMap::new();
	let mut queue = DList::new();

	let first = Multiplications {
		sum : 1,
		path : vec![(1,0,0)]
	};

	tmap.insert(first.sum, first.path.clone());

	queue.push(first);

	loop {
		let last = match queue.pop_front() {
			Some(newk1) => newk1,
			None => {return tmap;}
		};

		//~ println!("------------------------------");
		//~ println!("{} : {}", last.sum, last.path);

		for (i1, &(n1, _, _)) in last.path.iter().enumerate() {
			for &(n2, _, _) in last.path.slice_from(i1).iter() {
				if n1 + n2 <= last.sum { continue; }
				if n1 + n2 > n { continue;}
				let maxn = ((n1 + n2) as f32).log2().ceil() as uint * 2;
				if last.path.len() >= maxn {continue;}
				let new_m = last.append(n1,n2);
				//~ println!("  =>  {} : {}", new_m.sum, new_m.path);
				//~ match tmap.find_mut(&new_m.sum) {
					//~ None => {tmap.insert(new_m.sum, new_m.path.clone());},
					//~ Some(old) => { if old.len() > new_m.path.len() {*old = new_m.path};}
				//~ }

				let should_insert = match tmap.find_mut(&new_m.sum) {
					None => true,
					Some(old) => {
							if old.len() > new_m.path.len() {
								println!("  =>  {} : {}", new_m.sum, new_m.path);
								println!("      replacing {}", old);
								*old = new_m.path.clone()
							};
							false
						}
				};

				if should_insert {
					println!("  =>  {} : {}", new_m.sum, new_m.path);
					println!("      New!");
					tmap.insert(new_m.sum, new_m.path.clone());
				};

				if new_m.sum < n {queue.push_front(new_m);};
			}
		}
	}
}

#[test]
fn test_merge_vecs(){
	let (v1, v2) = (vec!(1u,2,3), vec!(2,3,4,5));
	let v = merge_vecs(&v1, &v2);
	assert_eq!(v, vec!(1,2,3,4,5));
}

pub fn main(){
	let ms = find_ms(100);

	for (k, v) in ms.iter() {
		println!("{} :: {}", k, v.len() - 1);
	}
}
<commit_msg>Updated 122<commit_after>/**
Efficient Exponentiation
Problem 122
https://projecteuler.net/problem=122

The most naive way of computing n^15 requires fourteen Multiplications:

n × n × ... × n = n^15

But using a "binary" method you can compute it in six Multiplications:

n × n = n^2
n^2 × n^2 = n^4
n^4 × n^4 = n^8
n^8 × n^4 = n^12
n^12 × n^2 = n^14
n^14 × n = n^15

However it is yet possible to compute it in only five Multiplications:

n × n = n^2
n^2 × n = n^3
n^3 × n^3 = n^6
n^6 × n^6 = n^12
n^12 × n^3 = n^15

We shall define m(k) to be the minimum number of Multiplications to compute n^k; for example m(15) = 5.

For 1 ≤ k ≤ 200, find ∑ m(k).

----------------------------------------------------------------------------------------------------

This code is a bit messy, and does things it doesn't need to - it took me a while to figure things out.

Basically, it just follows the tree to every possibility < n, and stops at a max level of the tree.

**/

extern crate eulerrust;
use std::collections::TrieMap;
use std::collections::dlist::DList;
use std::collections::Deque;

pub struct Multiplications {
	sum : uint,
	path : Vec<(uint, uint, uint)>, // x,y,z where n^x = n^y * n^z
	increasing : bool
}

impl Multiplications {
	pub fn contains(&self, n : uint) -> bool {
		let mut f = self.path.iter().filter(|&&(nsum, _, _)| {n == nsum});
		match f.next() {
			Some(_) => true,
			None => false
		}
	}

	pub fn append(&self, n1 : uint, n2 : uint) -> Multiplications {
		let mut newpath = self.path.clone();
		newpath.push((n1 + n2, n1, n2));
		let increasing = match self.path.last() {
			None => true,
			Some(&(_, _, m2)) if m2 > n2 => false,
			Some(&(_, _, m2)) if m2 == n2 => self.increasing,
			Some(_) => true,

		};
		Multiplications {
			sum : n1 + n2,
			path : newpath,
			increasing : increasing
		}
	}
}

fn find_ms(n : uint, max_depth : Option<uint>) -> TrieMap<Vec<(uint,uint,uint)>> {
	let mut tmap = TrieMap::new();
	let mut queue = DList::new();

	let first = Multiplications {
		sum : 1,
		path : vec![(1,0,0)],
		increasing : true
	};

	tmap.insert(first.sum, first.path.clone());

	queue.push(first);

	let maxn = (n as f32).log2().ceil() as uint * 2;

	loop {
		let last = match queue.pop_front() {
			Some(newk1) => newk1,
			None => {return tmap;}
		};

		//~ println!("------------------------------");
		//~ println!("{} : {}", last.sum, last.path);

		let n1 = last.sum;
		for &(n2, _, _) in last.path.iter() {
			if n1 + n2 > n { continue;}
			if !last.increasing {
				//~ match last.path.last() {
					//~ None => fail!("This should be impossible."),
					//~ Some(&(m12, m1, m2)) if m2 < n2 => {
						//~ println!("CONTINUING: {} :: {}", last.path, (n1,n2));
						//~ continue;
					//~ }
					//~ _ => {}
				//~ }
			};
			// let maxn = ((n1 + n2) as f32).log2().ceil() as uint * 2;
			if last.path.len() >= maxn {continue;}
			match max_depth {
				Some(d) if d < last.path.len() => {continue;}
				_ => {}
			}
			let new_m = last.append(n1,n2);
			//~ println!("  =>  {} : {}", new_m.sum, new_m.path);
			//~ match tmap.find_mut(&new_m.sum) {
				//~ None => {tmap.insert(new_m.sum, new_m.path.clone());},
				//~ Some(old) => { if old.len() > new_m.path.len() {*old = new_m.path};}
			//~ }

			let should_insert = match tmap.find_mut(&new_m.sum) {
				None => true,
				Some(old) => {
						if old.len() > new_m.path.len() {
							//~ if new_m.sum == 37 {
								//~ println!("  =>  {} : {}", new_m.sum, new_m.path);
								//~ println!("      replacing {}", old);
							//~ }
							*old = new_m.path.clone()
						//~ } else if new_m.sum == 37 {
							//~ println!("  =>  {} : {}", new_m.sum, new_m.path);
							//~ println!("      NOT replacing {}", old);
						};
						false
					}
			};

			if should_insert {
				//~ if new_m.sum == 37 {
					//~ println!("  =>  {} : {}", new_m.sum, new_m.path);
					//~ println!("      New!");
				//~ }
				tmap.insert(new_m.sum, new_m.path.clone());
			};

			if new_m.sum < n {queue.push_front(new_m);};
		}
	}
}

#[test]
fn test_find_ms() {
	let ms = find_ms(15, Some(11));
	let v = match ms.find(&15){
		None => fail!("15 NOT FOUND"),
		Some(v2) => v2
	};

	assert_eq!(v.len() - 1, 5);
}

pub fn main(){
	let bigm = 200;
	let ms = find_ms(bigm, Some(11)); // 11 found by trial and error; 10 doesn't get everything, 11 works, so take 11...

	let mut msum = 0;
	for k in range(1, bigm+1){
		let v = match ms.find(&k){
			None => fail!("NOT FOUND: {}", k),
			Some(v2) => v2
		};
	//~ for (k, v) in ms.iter() {
		println!("{} :: {} {}", k, v.len() - 1, v);
		msum += v.len() - 1;
	}
	println!("================================================================================");
	println!("Final sum: {} {}", msum, ms.len());
}
<|endoftext|>


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

use std::{convert::TryFrom, io};

use crate::{
    binlog::{decimal, jsonb, jsondiff::JsonDiff, misc::*},
    constants::{ColumnFlags, ColumnType},
    io::ParseBuf,
    misc::raw::int::*,
    proto::MyDeserialize,
    value::Value::{self, *},
};

/// Value of a binlog event.
#[derive(Debug, Clone, PartialEq)]
pub enum BinlogValue<'a> {
    /// MySql value.
    Value(Value),
    /// JSONB value.
    Jsonb(jsonb::Value<'a>),
    /// Value of a partial JSON modification event.
    JsonDiff(Vec<JsonDiff<'a>>),
}

impl<'a> BinlogValue<'a> {
    /// Returns a `'static` version of `self`.
    pub fn into_owned(self) -> BinlogValue<'static> {
        match self {
            BinlogValue::Value(x) => BinlogValue::Value(x),
            BinlogValue::Jsonb(x) => BinlogValue::Jsonb(x.into_owned()),
            BinlogValue::JsonDiff(x) => {
                BinlogValue::JsonDiff(x.into_iter().map(|x| x.into_owned()).collect())
            }
        }
    }
}

impl<'de> MyDeserialize<'de> for BinlogValue<'de> {
    const SIZE: Option<usize> = None;
    /// <col_type, col_meta, is_unsigned, is_partial>
    type Ctx = (ColumnType, &'de [u8], bool, bool);

    fn deserialize(
        (mut col_type, col_meta, is_unsigned, is_partial): Self::Ctx,
        buf: &mut ParseBuf<'de>,
    ) -> io::Result<Self> {
        use ColumnType::*;

        let mut length = 0_usize;

        if col_type == MYSQL_TYPE_TYPED_ARRAY {
            let type_byte = col_meta[0];
            col_type = ColumnType::try_from(type_byte).unwrap_or(col_type);
        }

        if col_type == MYSQL_TYPE_STRING {
            if col_meta[0] >= 1 {
                let byte0 = col_meta[0] as usize;
                let byte1 = col_meta[1] as usize;

                if (byte0 & 0x30) != 0x30 {
                    // a long CHAR() field: see #37426
                    length = byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
                    col_type = ColumnType::try_from(byte0 as u8 | 0x30).unwrap_or(col_type);
                } else {
                    length = byte1;
                }
            } else {
                length = (ParseBuf(col_meta)).eat_u16_le() as usize;
            }
        }

        match col_type {
            MYSQL_TYPE_TINY | MYSQL_TYPE_SHORT | MYSQL_TYPE_LONG | MYSQL_TYPE_LONGLONG
            | MYSQL_TYPE_FLOAT | MYSQL_TYPE_DOUBLE => {
                let mut flags = ColumnFlags::empty();
                flags.set(ColumnFlags::UNSIGNED_FLAG, is_unsigned);
                Value::deserialize_bin((col_type, flags), &mut *buf).map(BinlogValue::Value)
            }
            MYSQL_TYPE_TIMESTAMP => {
                let val: RawInt<LeU32> = buf.parse(())?;
                Ok(BinlogValue::Value(Int(*val as i64)))
            }
            MYSQL_TYPE_INT24 => {
                if is_unsigned {
                    let val: RawInt<LeU24> = buf.parse(())?;
                    Ok(BinlogValue::Value(Int(*val as i64)))
                } else {
                    let val: RawInt<LeI24> = buf.parse(())?;
                    Ok(BinlogValue::Value(Int(*val as i64)))
                }
            }
            MYSQL_TYPE_TIME => {
                let tmp: RawInt<LeU24> = buf.parse(())?;
                let h = *tmp / 10000;
                let m = (*tmp % 10000) / 100;
                let s = *tmp % 100;
                Ok(BinlogValue::Value(Time(
                    false, 0, h as u8, m as u8, s as u8, 0,
                )))
            }
            MYSQL_TYPE_DATETIME => {
                // read YYYYMMDDHHMMSS representaion
                let raw: RawInt<LeU64> = buf.parse(())?;
                let d_part = *raw / 1_000_000;
                let t_part = *raw % 1_000_000;
                Ok(BinlogValue::Value(Date(
                    (d_part / 10000) as u16,
                    ((d_part % 10000) / 100) as u8,
                    (d_part % 100) as u8,
                    (t_part / 10000) as u8,
                    ((t_part % 10000) / 100) as u8,
                    (t_part % 100) as u8,
                    0,
                )))
            }
            MYSQL_TYPE_YEAR => {
                let y = *buf.parse::<RawInt<u8>>(())? as i32;
                Ok(BinlogValue::Value(Bytes(
                    (1900 + y).to_string().into_bytes(),
                )))
            }
            MYSQL_TYPE_NEWDATE => {
                let tmp = *buf.parse::<RawInt<LeU24>>(())?;
                let d = tmp & 31;
                let m = (tmp >> 5) & 15;
                let y = tmp >> 9;
                Ok(BinlogValue::Value(Date(
                    y as u16, m as u8, d as u8, 0, 0, 0, 0,
                )))
            }
            MYSQL_TYPE_BIT => {
                let nbits = col_meta[0] as usize * 8 + (col_meta[1] as usize);
                let nbytes = (nbits + 7) / 8;
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            MYSQL_TYPE_TIMESTAMP2 => {
                let dec = col_meta[0];
                let (sec, usec) = my_timestamp_from_binary(&mut *buf, dec)?;
                if usec == 0 {
                    Ok(BinlogValue::Value(Bytes(sec.to_string().into_bytes())))
                } else {
                    Ok(BinlogValue::Value(Bytes(
                        format!("{}.{:06}", sec, usec).into_bytes(),
                    )))
                }
            }
            MYSQL_TYPE_DATETIME2 => {
                let dec = col_meta[0];
                my_datetime_packed_from_binary(&mut *buf, dec as u32)
                    .map(datetime_from_packed)
                    .map(BinlogValue::Value)
            }
            MYSQL_TYPE_TIME2 => {
                let dec = col_meta[0];
                my_time_packed_from_binary(&mut *buf, dec as u32)
                    .map(time_from_packed)
                    .map(BinlogValue::Value)
            }
            MYSQL_TYPE_JSON => {
                length = *buf.parse::<RawInt<LeU32>>(())? as usize;
                let mut json_value_buf: ParseBuf = buf.parse(length)?;
                if is_partial {
                    let mut diffs = Vec::new();
                    while !json_value_buf.is_empty() {
                        diffs.push(json_value_buf.parse(())?);
                    }
                    Ok(BinlogValue::JsonDiff(diffs))
                } else {
                    Ok(BinlogValue::Jsonb(json_value_buf.parse(())?))
                }
            }
            MYSQL_TYPE_NEWDECIMAL => {
                // precision is the maximum number of decimal digits
                let precision = col_meta[0] as usize;
                // scale (aka decimals) is the number of decimal digits after the point
                let scale = col_meta[1] as usize;

                let dec = decimal::Decimal::read_bin(&mut *buf, precision, scale, false)?;

                Ok(BinlogValue::Value(Bytes(dec.to_string().into_bytes())))
            }
            MYSQL_TYPE_ENUM => match col_meta[1] {
                1 => {
                    let val = buf.parse::<RawInt<u8>>(())?;
                    Ok(BinlogValue::Value(Int(*val as i64)))
                }
                2 => {
                    let val = buf.parse::<RawInt<LeU16>>(())?;
                    Ok(BinlogValue::Value(Int(*val as i64)))
                }
                _ => Err(io::Error::new(io::ErrorKind::InvalidData, "Unknown ENUM")),
            },
            MYSQL_TYPE_SET => {
                let nbytes = col_meta[1] as usize * 8;
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            MYSQL_TYPE_TINY_BLOB
            | MYSQL_TYPE_MEDIUM_BLOB
            | MYSQL_TYPE_LONG_BLOB
            | MYSQL_TYPE_BLOB => {
                let nbytes = match col_meta[0] {
                    1 => *buf.parse::<RawInt<u8>>(())? as usize,
                    2 => *buf.parse::<RawInt<LeU16>>(())? as usize,
                    3 => *buf.parse::<RawInt<LeU24>>(())? as usize,
                    4 => *buf.parse::<RawInt<LeU32>>(())? as usize,
                    _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Unknown BLOB")),
                };
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            MYSQL_TYPE_VARCHAR | MYSQL_TYPE_VAR_STRING => {
                let type_len = (col_meta[0] as u16 | ((col_meta[1] as u16) << 8)) as usize;
                let nbytes = if type_len < 256 {
                    *buf.parse::<RawInt<u8>>(())? as usize
                } else {
                    *buf.parse::<RawInt<LeU16>>(())? as usize
                };
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            MYSQL_TYPE_STRING => {
                let nbytes = if length < 256 {
                    *buf.parse::<RawInt<u8>>(())? as usize
                } else {
                    *buf.parse::<RawInt<LeU16>>(())? as usize
                };
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Don't know how to handle column",
            )),
        }
    }
}
<commit_msg>binlog row event: fix MYSQL_TYPE_SET deserialization<commit_after>// Copyright (c) 2021 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::{convert::TryFrom, io};

use crate::{
    binlog::{decimal, jsonb, jsondiff::JsonDiff, misc::*},
    constants::{ColumnFlags, ColumnType},
    io::ParseBuf,
    misc::raw::int::*,
    proto::MyDeserialize,
    value::Value::{self, *},
};

/// Value of a binlog event.
#[derive(Debug, Clone, PartialEq)]
pub enum BinlogValue<'a> {
    /// MySql value.
    Value(Value),
    /// JSONB value.
    Jsonb(jsonb::Value<'a>),
    /// Value of a partial JSON modification event.
    JsonDiff(Vec<JsonDiff<'a>>),
}

impl<'a> BinlogValue<'a> {
    /// Returns a `'static` version of `self`.
    pub fn into_owned(self) -> BinlogValue<'static> {
        match self {
            BinlogValue::Value(x) => BinlogValue::Value(x),
            BinlogValue::Jsonb(x) => BinlogValue::Jsonb(x.into_owned()),
            BinlogValue::JsonDiff(x) => {
                BinlogValue::JsonDiff(x.into_iter().map(|x| x.into_owned()).collect())
            }
        }
    }
}

impl<'de> MyDeserialize<'de> for BinlogValue<'de> {
    const SIZE: Option<usize> = None;
    /// <col_type, col_meta, is_unsigned, is_partial>
    type Ctx = (ColumnType, &'de [u8], bool, bool);

    fn deserialize(
        (mut col_type, col_meta, is_unsigned, is_partial): Self::Ctx,
        buf: &mut ParseBuf<'de>,
    ) -> io::Result<Self> {
        use ColumnType::*;

        let mut length = 0_usize;

        if col_type == MYSQL_TYPE_TYPED_ARRAY {
            let type_byte = col_meta[0];
            col_type = ColumnType::try_from(type_byte).unwrap_or(col_type);
        }

        if col_type == MYSQL_TYPE_STRING {
            if col_meta[0] >= 1 {
                let byte0 = col_meta[0] as usize;
                let byte1 = col_meta[1] as usize;

                if (byte0 & 0x30) != 0x30 {
                    // a long CHAR() field: see #37426
                    length = byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
                    col_type = ColumnType::try_from(byte0 as u8 | 0x30).unwrap_or(col_type);
                } else {
                    length = byte1;
                }
            } else {
                length = (ParseBuf(col_meta)).eat_u16_le() as usize;
            }
        }

        match col_type {
            MYSQL_TYPE_TINY | MYSQL_TYPE_SHORT | MYSQL_TYPE_LONG | MYSQL_TYPE_LONGLONG
            | MYSQL_TYPE_FLOAT | MYSQL_TYPE_DOUBLE => {
                let mut flags = ColumnFlags::empty();
                flags.set(ColumnFlags::UNSIGNED_FLAG, is_unsigned);
                Value::deserialize_bin((col_type, flags), &mut *buf).map(BinlogValue::Value)
            }
            MYSQL_TYPE_TIMESTAMP => {
                let val: RawInt<LeU32> = buf.parse(())?;
                Ok(BinlogValue::Value(Int(*val as i64)))
            }
            MYSQL_TYPE_INT24 => {
                if is_unsigned {
                    let val: RawInt<LeU24> = buf.parse(())?;
                    Ok(BinlogValue::Value(Int(*val as i64)))
                } else {
                    let val: RawInt<LeI24> = buf.parse(())?;
                    Ok(BinlogValue::Value(Int(*val as i64)))
                }
            }
            MYSQL_TYPE_TIME => {
                let tmp: RawInt<LeU24> = buf.parse(())?;
                let h = *tmp / 10000;
                let m = (*tmp % 10000) / 100;
                let s = *tmp % 100;
                Ok(BinlogValue::Value(Time(
                    false, 0, h as u8, m as u8, s as u8, 0,
                )))
            }
            MYSQL_TYPE_DATETIME => {
                // read YYYYMMDDHHMMSS representaion
                let raw: RawInt<LeU64> = buf.parse(())?;
                let d_part = *raw / 1_000_000;
                let t_part = *raw % 1_000_000;
                Ok(BinlogValue::Value(Date(
                    (d_part / 10000) as u16,
                    ((d_part % 10000) / 100) as u8,
                    (d_part % 100) as u8,
                    (t_part / 10000) as u8,
                    ((t_part % 10000) / 100) as u8,
                    (t_part % 100) as u8,
                    0,
                )))
            }
            MYSQL_TYPE_YEAR => {
                let y = *buf.parse::<RawInt<u8>>(())? as i32;
                Ok(BinlogValue::Value(Bytes(
                    (1900 + y).to_string().into_bytes(),
                )))
            }
            MYSQL_TYPE_NEWDATE => {
                let tmp = *buf.parse::<RawInt<LeU24>>(())?;
                let d = tmp & 31;
                let m = (tmp >> 5) & 15;
                let y = tmp >> 9;
                Ok(BinlogValue::Value(Date(
                    y as u16, m as u8, d as u8, 0, 0, 0, 0,
                )))
            }
            MYSQL_TYPE_BIT => {
                let nbits = col_meta[0] as usize * 8 + (col_meta[1] as usize);
                let nbytes = (nbits + 7) / 8;
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            MYSQL_TYPE_TIMESTAMP2 => {
                let dec = col_meta[0];
                let (sec, usec) = my_timestamp_from_binary(&mut *buf, dec)?;
                if usec == 0 {
                    Ok(BinlogValue::Value(Bytes(sec.to_string().into_bytes())))
                } else {
                    Ok(BinlogValue::Value(Bytes(
                        format!("{}.{:06}", sec, usec).into_bytes(),
                    )))
                }
            }
            MYSQL_TYPE_DATETIME2 => {
                let dec = col_meta[0];
                my_datetime_packed_from_binary(&mut *buf, dec as u32)
                    .map(datetime_from_packed)
                    .map(BinlogValue::Value)
            }
            MYSQL_TYPE_TIME2 => {
                let dec = col_meta[0];
                my_time_packed_from_binary(&mut *buf, dec as u32)
                    .map(time_from_packed)
                    .map(BinlogValue::Value)
            }
            MYSQL_TYPE_JSON => {
                length = *buf.parse::<RawInt<LeU32>>(())? as usize;
                let mut json_value_buf: ParseBuf = buf.parse(length)?;
                if is_partial {
                    let mut diffs = Vec::new();
                    while !json_value_buf.is_empty() {
                        diffs.push(json_value_buf.parse(())?);
                    }
                    Ok(BinlogValue::JsonDiff(diffs))
                } else {
                    Ok(BinlogValue::Jsonb(json_value_buf.parse(())?))
                }
            }
            MYSQL_TYPE_NEWDECIMAL => {
                // precision is the maximum number of decimal digits
                let precision = col_meta[0] as usize;
                // scale (aka decimals) is the number of decimal digits after the point
                let scale = col_meta[1] as usize;

                let dec = decimal::Decimal::read_bin(&mut *buf, precision, scale, false)?;

                Ok(BinlogValue::Value(Bytes(dec.to_string().into_bytes())))
            }
            MYSQL_TYPE_ENUM => match col_meta[1] {
                1 => {
                    let val = buf.parse::<RawInt<u8>>(())?;
                    Ok(BinlogValue::Value(Int(*val as i64)))
                }
                2 => {
                    let val = buf.parse::<RawInt<LeU16>>(())?;
                    Ok(BinlogValue::Value(Int(*val as i64)))
                }
                _ => Err(io::Error::new(io::ErrorKind::InvalidData, "Unknown ENUM")),
            },
            MYSQL_TYPE_SET => {
                let nbytes = col_meta[1] as usize;
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            MYSQL_TYPE_TINY_BLOB
            | MYSQL_TYPE_MEDIUM_BLOB
            | MYSQL_TYPE_LONG_BLOB
            | MYSQL_TYPE_BLOB => {
                let nbytes = match col_meta[0] {
                    1 => *buf.parse::<RawInt<u8>>(())? as usize,
                    2 => *buf.parse::<RawInt<LeU16>>(())? as usize,
                    3 => *buf.parse::<RawInt<LeU24>>(())? as usize,
                    4 => *buf.parse::<RawInt<LeU32>>(())? as usize,
                    _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Unknown BLOB")),
                };
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            MYSQL_TYPE_VARCHAR | MYSQL_TYPE_VAR_STRING => {
                let type_len = (col_meta[0] as u16 | ((col_meta[1] as u16) << 8)) as usize;
                let nbytes = if type_len < 256 {
                    *buf.parse::<RawInt<u8>>(())? as usize
                } else {
                    *buf.parse::<RawInt<LeU16>>(())? as usize
                };
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            MYSQL_TYPE_STRING => {
                let nbytes = if length < 256 {
                    *buf.parse::<RawInt<u8>>(())? as usize
                } else {
                    *buf.parse::<RawInt<LeU16>>(())? as usize
                };
                let bytes: &[u8] = buf.parse(nbytes)?;
                Ok(BinlogValue::Value(Bytes(bytes.into())))
            }
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Don't know how to handle column",
            )),
        }
    }
}
<|endoftext|>


<commit_before>use tempdir::TempDir;

use portpicker::pick_unused_port;
use pueue_lib::settings::*;

pub fn get_shared_settings() -> (Shared, TempDir) {
    // Create a temporary directory used for testing.
    let tempdir = TempDir::new("pueue_lib").unwrap();
    let tempdir_path = tempdir.path();

    std::fs::create_dir(tempdir_path.join("certs")).unwrap();

    let shared_settings = Shared {
        pueue_directory: tempdir_path.clone().to_path_buf(),
        #[cfg(not(target_os = "windows"))]
        use_unix_socket: true,
        #[cfg(not(target_os = "windows"))]
        unix_socket_path: tempdir_path.join("test.socket"),
        host: "localhost".to_string(),
        port: pick_unused_port()
            .expect("There should be a free port")
            .to_string(),
        daemon_cert: tempdir_path.join("certs").join("daemon.cert"),
        daemon_key: tempdir_path.join("certs").join("daemon.key"),
        shared_secret_path: tempdir_path.join("secret"),
    };

    (shared_settings, tempdir)
}
<commit_msg>fix: Clippy lints<commit_after>use tempdir::TempDir;

use portpicker::pick_unused_port;
use pueue_lib::settings::*;

pub fn get_shared_settings() -> (Shared, TempDir) {
    // Create a temporary directory used for testing.
    let tempdir = TempDir::new("pueue_lib").unwrap();
    let tempdir_path = tempdir.path();

    std::fs::create_dir(tempdir_path.join("certs")).unwrap();

    let shared_settings = Shared {
        pueue_directory: tempdir_path.to_path_buf(),
        #[cfg(not(target_os = "windows"))]
        use_unix_socket: true,
        #[cfg(not(target_os = "windows"))]
        unix_socket_path: tempdir_path.join("test.socket"),
        host: "localhost".to_string(),
        port: pick_unused_port()
            .expect("There should be a free port")
            .to_string(),
        daemon_cert: tempdir_path.join("certs").join("daemon.cert"),
        daemon_key: tempdir_path.join("certs").join("daemon.key"),
        shared_secret_path: tempdir_path.join("secret"),
    };

    (shared_settings, tempdir)
}
<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0
 *
 * © Gregor Reitzenstein, Harald Seiler
 */

use std::os;
use std::env;
use std::io::{Write, Read, ErrorKind};
use std::fs::{self, File};
use std::collections::BTreeMap;
use std::sync::mpsc::{Sender, Receiver};

use toml::{self, Value};

use serialize::Decodable;

#[derive(Clone)]
/// The configparser reads the config file and provides functions to access config values.
pub struct ConfigReader
{
    config_map: Value, //BTreeMap<String, Value>,
}

impl ConfigReader
{
    /// Create a new ConfigReader object. This should only be called in the setup() function.
    pub fn new() -> ConfigReader
    {
        // Get the current pwd
        let mut config = env::current_exe().ok().expect("huh?");

        // Create the configuration directory if it does not exist yet.
        config.push("config/");

        //let configdir = Path::new("config/");
        // This returns a Result with an error if the directory already exists or the user does not
        // have write permissions. We ignore that possibility for now.
        fs::create_dir(&config);

        // Open the configuration file.
        config.push("redstart.toml");
        //let configpath  = Path::new("config/redstart.toml");
        let mut configfile = match File::open(&config)
        {
            // File does exists -> return file descriptor.
            Ok(f) => f,
            // File does *not* exist -> create file, dump default config, return file descriptor
            Err(e) =>
            {
                match e.kind()
                {
                    ErrorKind::PermissionDenied => panic!("Could not read config file. Does it have the correct permissions?"),
                    ErrorKind::NotFound =>
                    {
                        // There is no config file. So create one.
                        // This opens the file in writeable mode.
                        let mut fd = File::create(&config).unwrap();

                        // Write default values.
                        fd.write(b"[General]\nname=\"RedStart\"\n\n[Networking]\naddress = \"127.0.0.1\"\nport = 8080\n\n[Logging]\nloglevel = \"NORMAL\"\nlogfile = \"log/default.log\"\n\n[Security]\nhttps = false\ncertificate = \"../../ssl/cert.pem\"\nkey = \"../../ssl/key.pem\"\n"
);
                        // Open the file in readonly mode again
                        let mut fd = File::open(&config);
                        fd.unwrap()
                    }
                    _ => panic!("File error: {}!", e),
                }
            }
        };

        // Read the config-file into memory.
        let mut configstring = String::new();
        configfile.read_to_string(&mut configstring).unwrap();

        // Create a new TOML Parser from the config
        let mut configparser = toml::Parser::new(configstring.as_ref());

        // Parse the TOML configfile into a Binary Tree map.
        let table = match configparser.parse()
        {
            Some(val) => val,
            None => panic!("Configfile parse error! Check config syntax!"),
        };

        // Save the BTreeMap into the struct
        let value: Value = Value::Table(table);
        ConfigReader { config_map: value }
    }

    /// Return the value that belongs to the key given. If no value was found, `None` will be returned
    pub fn get_value<T: Decodable>(&mut self, key: &str) -> Option<T>
    {
        match self.config_map.lookup(key)
        {
            Some(value) => toml::decode::<T>(value.clone()),
            None => None
        }
    }

    /// Return the value that belongs to the key given. If no value was found, a given default value
    /// will be returned.
    pub fn get_value_or<T: Decodable>(&mut self, key: &str, default: T) -> T
    {
        match self.get_value::<T>(key)
        {
            Some(e) => e,
            None => default,
        }
    }
}
<commit_msg>Resolved Runtime error<commit_after>/*
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0
 *
 * © Gregor Reitzenstein, Harald Seiler
 */

use std::os;
use std::env;
use std::io::{Write, Read, ErrorKind};
use std::fs::{self, File};
use std::collections::BTreeMap;
use std::sync::mpsc::{Sender, Receiver};

use toml::{self, Value};

use serialize::Decodable;

#[derive(Clone)]
/// The configparser reads the config file and provides functions to access config values.
pub struct ConfigReader
{
    config_map: Value, //BTreeMap<String, Value>,
}

impl ConfigReader
{
    /// Create a new ConfigReader object. This should only be called in the setup() function.
    pub fn new() -> ConfigReader
    {
        // Get the current pwd
        let mut config = env::current_dir().ok().expect("huh?");

        // Create the configuration directory if it does not exist yet.
        config.push("config/");

        //let configdir = Path::new("config/");
        // This returns a Result with an error if the directory already exists or the user does not
        // have write permissions. We ignore that possibility for now.
        fs::create_dir(&config);

        // Open the configuration file.
        config.push("redstart.toml");
        //let configpath  = Path::new("config/redstart.toml");
        let mut configfile = match File::open(&config)
        {
            // File does exists -> return file descriptor.
            Ok(f) => f,
            // File does *not* exist -> create file, dump default config, return file descriptor
            Err(e) =>
            {
                match e.kind()
                {
                    ErrorKind::PermissionDenied => panic!("Could not read config file. Does it have the correct permissions?"),
                    ErrorKind::NotFound =>
                    {
                        // There is no config file. So create one.
                        // This opens the file in writeable mode.
                        let mut fd = File::create(&config).unwrap();

                        // Write default values.
                        fd.write(b"[General]\nname=\"RedStart\"\n\n[Networking]\naddress = \"127.0.0.1\"\nport = 8080\n\n[Logging]\nloglevel = \"NORMAL\"\nlogfile = \"log/default.log\"\n\n[Security]\nhttps = false\ncertificate = \"../../ssl/cert.pem\"\nkey = \"../../ssl/key.pem\"\n"
);
                        // Open the file in readonly mode again
                        let mut fd = File::open(&config);
                        fd.unwrap()
                    }
                    _ => panic!("File error: {}!", e),
                }
            }
        };

        // Read the config-file into memory.
        let mut configstring = String::new();
        configfile.read_to_string(&mut configstring).unwrap();

        // Create a new TOML Parser from the config
        let mut configparser = toml::Parser::new(configstring.as_ref());

        // Parse the TOML configfile into a Binary Tree map.
        let table = match configparser.parse()
        {
            Some(val) => val,
            None => panic!("Configfile parse error! Check config syntax!"),
        };

        // Save the BTreeMap into the struct
        let value: Value = Value::Table(table);
        ConfigReader { config_map: value }
    }

    /// Return the value that belongs to the key given. If no value was found, `None` will be returned
    pub fn get_value<T: Decodable>(&mut self, key: &str) -> Option<T>
    {
        match self.config_map.lookup(key)
        {
            Some(value) => toml::decode::<T>(value.clone()),
            None => None
        }
    }

    /// Return the value that belongs to the key given. If no value was found, a given default value
    /// will be returned.
    pub fn get_value_or<T: Decodable>(&mut self, key: &str, default: T) -> T
    {
        match self.get_value::<T>(key)
        {
            Some(e) => e,
            None => default,
        }
    }
}
<|endoftext|>


<commit_before>use core::ptr;

#[no_mangle]
pub unsafe extern fn reset_handler() {
    init_data();
    init_bss();

    extern {
        fn main() -> !;
    }
    main();
}

unsafe fn init_data() {
    extern {
        static __data_load: u32;
        static mut __data_start: u32;
        static __data_end: u32;
    }
    let src = &__data_load as *const u32;
    let dst = &mut __data_start as *mut u32;
    let end = &__data_end as *const u32;
    let count = (end as usize) - (dst as usize);
    ptr::copy_nonoverlapping(src, dst, count);
}

unsafe fn init_bss() {
    extern {
        static mut __bss_start: u32;
        static __bss_end: u32;
    }
    let dst = &mut __bss_start as *mut u32;
    let end = &__bss_end as *const u32;
    let count = (end as usize) - (dst as usize);
    ptr::write_bytes(dst, 0, count);
}
<commit_msg>Fix bugs<commit_after>use core::ptr;

#[no_mangle]
pub unsafe extern fn reset_handler() {
    init_data();
    init_bss();

    extern {
        fn main() -> !;
    }
    main();
}

unsafe fn init_data() {
    extern {
        static __data_load: u8;
        static mut __data_start: u8;
        static __data_end: u8;
    }
    let src = &__data_load as *const u8;
    let dst = &mut __data_start as *mut u8;
    let end = &__data_end as *const u8;
    let count = (end as usize) - (dst as usize);
    ptr::copy_nonoverlapping(src, dst, count);
}

unsafe fn init_bss() {
    extern {
        static mut __bss_start: u8;
        static __bss_end: u8;
    }
    let dst = &mut __bss_start as *mut u8;
    let end = &__bss_end as *const u8;
    let count = (end as usize) - (dst as usize);
    ptr::write_bytes(dst, 0, count);
}
<|endoftext|>


<commit_before>extern crate pkg_config;

fn main() {
    pkg_config::find_library("libsodium").unwrap();
}
<commit_msg>Adding support for static linking again<commit_after>use std::env;
extern crate pkg_config;

fn main() {

    if let Ok(lib_dir) = env::var("SODIUM_LIB_DIR") {

    	println!("cargo:rustc-flags=-L native={}", lib_dir);

        let mode = match env::var_os("SODIUM_STATIC") {
            Some(_) => "static",
            None => "dylib"
        };
        println!("cargo:rustc-flags=-l {0}=sodium", mode);

    } else {

        pkg_config::find_library("libsodium").unwrap();

    }

}
<|endoftext|>


<commit_before><commit_msg>example update<commit_after><|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syn::Attribute;

use crate::types::validate_ident_ok_for_rust;

use self::fun::FnAnalysis;

use super::{
    api::{Api, ApiDetail},
    error_reporter::convert_item_apis,
    ConvertError,
};

pub(crate) mod abstract_types;
pub(crate) mod ctypes;
pub(crate) mod fun;
pub(crate) mod gc;
pub(crate) mod pod; // hey, that rhymes
pub(crate) mod remove_ignored;
pub(crate) mod tdef;
mod type_converter;

// Remove `bindgen_` attributes. They don't have a corresponding macro defined anywhere,
// so they will cause compilation errors if we leave them in.
// We may return an error if one of the bindgen attributes shows that the
// item can't be processed.
fn remove_bindgen_attrs(attrs: &mut Vec<Attribute>) -> Result<(), ConvertError> {
    if has_attr(&attrs, "bindgen_unused_template_param") {
        return Err(ConvertError::UnusedTemplateParam);
    }

    fn is_bindgen_attr(attr: &Attribute) -> bool {
        let segments = &attr.path.segments;
        segments.len() == 1
            && segments
                .first()
                .unwrap()
                .ident
                .to_string()
                .starts_with("bindgen_")
    }

    attrs.retain(|a| !is_bindgen_attr(a));
    Ok(())
}

fn has_attr(attrs: &[Attribute], attr_name: &str) -> bool {
    attrs.iter().any(|at| at.path.is_ident(attr_name))
}

/// If any items have names which can't be represented by cxx,
/// abort.
pub(crate) fn check_names(apis: Vec<Api<FnAnalysis>>) -> Vec<Api<FnAnalysis>> {
    let mut results = Vec::new();
    convert_item_apis(apis, &mut results, |api| match api.detail {
        ApiDetail::Typedef { .. }
        | ApiDetail::ForwardDeclaration
        | ApiDetail::Const { .. }
        | ApiDetail::Enum { .. }
        | ApiDetail::Struct { .. } => validate_ident_ok_for_rust(api.cxx_name()).map(|_| Some(api)),
        _ => Ok(Some(api)),
    });
    results
}
<commit_msg>Check all item names.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syn::Attribute;

use crate::types::{validate_ident_ok_for_rust, QualifiedName};

use self::fun::FnAnalysis;

use super::{
    api::{Api, ApiDetail},
    error_reporter::convert_item_apis,
    ConvertError,
};

pub(crate) mod abstract_types;
pub(crate) mod ctypes;
pub(crate) mod fun;
pub(crate) mod gc;
pub(crate) mod pod; // hey, that rhymes
pub(crate) mod remove_ignored;
pub(crate) mod tdef;
mod type_converter;

// Remove `bindgen_` attributes. They don't have a corresponding macro defined anywhere,
// so they will cause compilation errors if we leave them in.
// We may return an error if one of the bindgen attributes shows that the
// item can't be processed.
fn remove_bindgen_attrs(attrs: &mut Vec<Attribute>) -> Result<(), ConvertError> {
    if has_attr(&attrs, "bindgen_unused_template_param") {
        return Err(ConvertError::UnusedTemplateParam);
    }

    fn is_bindgen_attr(attr: &Attribute) -> bool {
        let segments = &attr.path.segments;
        segments.len() == 1
            && segments
                .first()
                .unwrap()
                .ident
                .to_string()
                .starts_with("bindgen_")
    }

    attrs.retain(|a| !is_bindgen_attr(a));
    Ok(())
}

fn has_attr(attrs: &[Attribute], attr_name: &str) -> bool {
    attrs.iter().any(|at| at.path.is_ident(attr_name))
}

/// If any items have names which can't be represented by cxx,
/// abort.
pub(crate) fn check_names(apis: Vec<Api<FnAnalysis>>) -> Vec<Api<FnAnalysis>> {
    let mut results = Vec::new();
    convert_item_apis(apis, &mut results, |api| match api.detail {
        ApiDetail::Typedef { .. }
        | ApiDetail::ForwardDeclaration
        | ApiDetail::Const { .. }
        | ApiDetail::Enum { .. }
        | ApiDetail::Struct { .. } => {
            let cxx_name = api
                .original_name
                .as_ref()
                .map(|s| {
                    // Occasionally we might have outer_type::inner_type.
                    // We'll just check that inner_type is acceptable cxx spelling.
                    let parsed = QualifiedName::new_from_cpp_name(&s);
                    parsed.get_final_item().to_string()
                })
                .unwrap_or(api.name.get_final_item().to_string());
            validate_ident_ok_for_rust(&cxx_name).map(|_| Some(api))
        }
        ApiDetail::Function { .. } // we don't handle functions here because
            // the function analysis does an equivalent check. Instead of just rejecting
            // the function, it creates a wrapper function instead with a more
            // palatable name. That's preferable to rejecting the API entirely.
        | ApiDetail::ConcreteType  { .. }
        | ApiDetail::CType { .. }
        | ApiDetail::StringConstructor
        | ApiDetail::IgnoredItem { .. } => Ok(Some(api)),
    });
    results
}
<|endoftext|>


<commit_before>use crate::decode::lzbuffer;
use crate::decode::lzbuffer::LZBuffer;
use crate::decode::lzma;
use crate::decode::rangecoder;
use crate::error;
use byteorder::{BigEndian, ReadBytesExt};
use std::io;
use std::io::Read;

pub fn decode_stream<R, W>(input: &mut R, output: &mut W) -> error::Result<()>
where
    R: io::BufRead,
    W: io::Write,
{
    let accum = lzbuffer::LZAccumBuffer::from_stream(output);
    let mut decoder = lzma::new_accum(accum, 0, 0, 0, None);

    loop {
        let status = input.read_u8().or_else(|e| {
            Err(error::Error::LZMAError(format!(
                "LZMA2 expected new status: {}",
                e
            )))
        })?;

        lzma_info!("LZMA2 status: {}", status);

        if status == 0 {
            lzma_info!("LZMA2 end of input");
            break;
        } else if status == 1 {
            // uncompressed reset dict
            parse_uncompressed(&mut decoder, input, true)?;
        } else if status == 2 {
            // uncompressed no reset
            parse_uncompressed(&mut decoder, input, false)?;
        } else {
            parse_lzma(&mut decoder, input, status)?;
        }
    }

    decoder.output.finish()?;
    Ok(())
}

fn parse_lzma<'a, R, W>(
    decoder: &mut lzma::DecoderState<lzbuffer::LZAccumBuffer<'a, W>>,
    input: &mut R,
    status: u8,
) -> error::Result<()>
where
    R: io::BufRead,
    W: io::Write,
{
    if status & 0x80 == 0 {
        return Err(error::Error::LZMAError(format!(
            "LZMA2 invalid status {}, must be 0, 1, 2 or >= 128",
            status
        )));
    }

    let reset_dict: bool;
    let reset_state: bool;
    let reset_props: bool;
    match (status >> 5) & 0x3 {
        0 => {
            reset_dict = false;
            reset_state = false;
            reset_props = false;
        }
        1 | 2 => {
            reset_dict = false;
            reset_state = true;
            reset_props = false;
        }
        3 => {
            reset_dict = true;
            reset_state = true;
            reset_props = true;
        }
        _ => unreachable!(),
    }

    let unpacked_size = input.read_u16::<BigEndian>().or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA2 expected unpacked size: {}",
            e
        )))
    })?;
    let unpacked_size = ((((status & 0x1F) as u64) << 16) | (unpacked_size as u64)) + 1;

    let packed_size = input.read_u16::<BigEndian>().or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA2 expected packed size: {}",
            e
        )))
    })?;
    let packed_size = (packed_size as u64) + 1;

    lzma_info!(
        "LZMA2 compressed block {{ unpacked_size: {}, packed_size: {}, reset_dict: {}, reset_state: {}, reset_props: {} }}",
        unpacked_size,
        packed_size,
        reset_dict,
        reset_state,
        reset_props
    );

    if reset_dict {
        decoder.output.reset()?;
    }

    if reset_state {
        let lc: u32;
        let lp: u32;
        let mut pb: u32;

        if reset_props {
            let props = input.read_u8().or_else(|e| {
                Err(error::Error::LZMAError(format!(
                    "LZMA2 expected new properties: {}",
                    e
                )))
            })?;

            pb = props as u32;
            if pb >= 225 {
                return Err(error::Error::LZMAError(format!(
                    "LZMA2 invalid properties: {} must be < 225",
                    pb
                )));
            }

            lc = pb % 9;
            pb /= 9;
            lp = pb % 5;
            pb /= 5;

            if lc + lp > 4 {
                return Err(error::Error::LZMAError(format!(
                    "LZMA2 invalid properties: lc + lp ({} + {}) must be <= 4",
                    lc, lp
                )));
            }

            lzma_info!("Properties {{ lc: {}, lp: {}, pb: {} }}", lc, lp, pb);
        } else {
            lc = decoder.lc;
            lp = decoder.lp;
            pb = decoder.pb;
        }

        decoder.reset_state(lc, lp, pb);
    }

    decoder.set_unpacked_size(Some(unpacked_size));

    let mut taken = input.take(packed_size);
    let mut rangecoder = rangecoder::RangeDecoder::new(&mut taken).or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA input too short: {}",
            e
        )))
    })?;
    decoder.process(&mut rangecoder)
}

fn parse_uncompressed<'a, R, W>(
    decoder: &mut lzma::DecoderState<lzbuffer::LZAccumBuffer<'a, W>>,
    input: &mut R,
    reset_dict: bool,
) -> error::Result<()>
where
    R: io::BufRead,
    W: io::Write,
{
    let unpacked_size = input.read_u16::<BigEndian>().or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA2 expected unpacked size: {}",
            e
        )))
    })?;
    let unpacked_size = (unpacked_size as usize) + 1;

    lzma_info!(
        "LZMA2 uncompressed block {{ unpacked_size: {}, reset_dict: {} }}",
        unpacked_size,
        reset_dict
    );

    if reset_dict {
        decoder.output.reset()?;
    }

    let mut buf = vec![0; unpacked_size];
    input.read_exact(buf.as_mut_slice()).or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA2 expected {} uncompressed bytes: {}",
            unpacked_size, e
        )))
    })?;
    decoder.output.append_bytes(buf.as_slice());

    Ok(())
}
<commit_msg>Fix lzma2 header parsing<commit_after>use crate::decode::lzbuffer;
use crate::decode::lzbuffer::LZBuffer;
use crate::decode::lzma;
use crate::decode::rangecoder;
use crate::error;
use byteorder::{BigEndian, ReadBytesExt};
use std::io;
use std::io::Read;

pub fn decode_stream<R, W>(input: &mut R, output: &mut W) -> error::Result<()>
where
    R: io::BufRead,
    W: io::Write,
{
    let accum = lzbuffer::LZAccumBuffer::from_stream(output);
    let mut decoder = lzma::new_accum(accum, 0, 0, 0, None);

    loop {
        let status = input.read_u8().or_else(|e| {
            Err(error::Error::LZMAError(format!(
                "LZMA2 expected new status: {}",
                e
            )))
        })?;

        lzma_info!("LZMA2 status: {}", status);

        if status == 0 {
            lzma_info!("LZMA2 end of input");
            break;
        } else if status == 1 {
            // uncompressed reset dict
            parse_uncompressed(&mut decoder, input, true)?;
        } else if status == 2 {
            // uncompressed no reset
            parse_uncompressed(&mut decoder, input, false)?;
        } else {
            parse_lzma(&mut decoder, input, status)?;
        }
    }

    decoder.output.finish()?;
    Ok(())
}

fn parse_lzma<'a, R, W>(
    decoder: &mut lzma::DecoderState<lzbuffer::LZAccumBuffer<'a, W>>,
    input: &mut R,
    status: u8,
) -> error::Result<()>
where
    R: io::BufRead,
    W: io::Write,
{
    if status & 0x80 == 0 {
        return Err(error::Error::LZMAError(format!(
            "LZMA2 invalid status {}, must be 0, 1, 2 or >= 128",
            status
        )));
    }

    let reset_dict: bool;
    let reset_state: bool;
    let reset_props: bool;
    match (status >> 5) & 0x3 {
        0 => {
            reset_dict = false;
            reset_state = false;
            reset_props = false;
        }
        1 => {
            reset_dict = false;
            reset_state = true;
            reset_props = false;
        }
        2 => {
            reset_dict = false;
            reset_state = true;
            reset_props = true;
        }
        3 => {
            reset_dict = true;
            reset_state = true;
            reset_props = true;
        }
        _ => unreachable!(),
    }

    let unpacked_size = input.read_u16::<BigEndian>().or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA2 expected unpacked size: {}",
            e
        )))
    })?;
    let unpacked_size = ((((status & 0x1F) as u64) << 16) | (unpacked_size as u64)) + 1;

    let packed_size = input.read_u16::<BigEndian>().or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA2 expected packed size: {}",
            e
        )))
    })?;
    let packed_size = (packed_size as u64) + 1;

    lzma_info!(
        "LZMA2 compressed block {{ unpacked_size: {}, packed_size: {}, reset_dict: {}, reset_state: {}, reset_props: {} }}",
        unpacked_size,
        packed_size,
        reset_dict,
        reset_state,
        reset_props
    );

    if reset_dict {
        decoder.output.reset()?;
    }

    if reset_state {
        let lc: u32;
        let lp: u32;
        let mut pb: u32;

        if reset_props {
            let props = input.read_u8().or_else(|e| {
                Err(error::Error::LZMAError(format!(
                    "LZMA2 expected new properties: {}",
                    e
                )))
            })?;

            pb = props as u32;
            if pb >= 225 {
                return Err(error::Error::LZMAError(format!(
                    "LZMA2 invalid properties: {} must be < 225",
                    pb
                )));
            }

            lc = pb % 9;
            pb /= 9;
            lp = pb % 5;
            pb /= 5;

            if lc + lp > 4 {
                return Err(error::Error::LZMAError(format!(
                    "LZMA2 invalid properties: lc + lp ({} + {}) must be <= 4",
                    lc, lp
                )));
            }

            lzma_info!("Properties {{ lc: {}, lp: {}, pb: {} }}", lc, lp, pb);
        } else {
            lc = decoder.lc;
            lp = decoder.lp;
            pb = decoder.pb;
        }

        decoder.reset_state(lc, lp, pb);
    }

    decoder.set_unpacked_size(Some(unpacked_size));

    let mut taken = input.take(packed_size);
    let mut rangecoder = rangecoder::RangeDecoder::new(&mut taken).or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA input too short: {}",
            e
        )))
    })?;
    decoder.process(&mut rangecoder)
}

fn parse_uncompressed<'a, R, W>(
    decoder: &mut lzma::DecoderState<lzbuffer::LZAccumBuffer<'a, W>>,
    input: &mut R,
    reset_dict: bool,
) -> error::Result<()>
where
    R: io::BufRead,
    W: io::Write,
{
    let unpacked_size = input.read_u16::<BigEndian>().or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA2 expected unpacked size: {}",
            e
        )))
    })?;
    let unpacked_size = (unpacked_size as usize) + 1;

    lzma_info!(
        "LZMA2 uncompressed block {{ unpacked_size: {}, reset_dict: {} }}",
        unpacked_size,
        reset_dict
    );

    if reset_dict {
        decoder.output.reset()?;
    }

    let mut buf = vec![0; unpacked_size];
    input.read_exact(buf.as_mut_slice()).or_else(|e| {
        Err(error::Error::LZMAError(format!(
            "LZMA2 expected {} uncompressed bytes: {}",
            unpacked_size, e
        )))
    })?;
    decoder.output.append_bytes(buf.as_slice());

    Ok(())
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct RafDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> RafDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> RafDecoder<'a> {
    RafDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for RafDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let raw = fetch_ifd!(&self.tiff, Tag::RafOffsets);
    let (width,height) = if raw.has_entry(Tag::RafImageWidth) {
      (fetch_tag!(raw, Tag::RafImageWidth).get_u32(0),
       fetch_tag!(raw, Tag::RafImageLength).get_u32(0))
    } else {
      let sizes = fetch_tag!(raw, Tag::ImageWidth);
      (sizes.get_u32(1), sizes.get_u32(0))
    };
    let offset = fetch_tag!(raw, Tag::RafOffsets).get_u32(0) as usize + raw.start_offset();
    let bps = match raw.find_entry(Tag::RafBitsPerSample) {
      Some(val) => val.get_u32(0),
      None      => 16,
    };
    let src = &self.buffer[offset..];

    let image = match bps {
      12 => decode_12le(src, width as usize, height as usize),
      14 => decode_14le_unpacked(src, width as usize, height as usize),
      16 => decode_16le(src, width as usize, height as usize),
      _ => {return Err(format!("RAF: Don't know how to decode bps {}", bps).to_string());},
    };

    if camera.find_hint("fuji_rotation") {
      let (width, height, image) = RafDecoder::rotate_image(&image, camera, width as usize, height as usize);
      Ok(Image {
        make: camera.make.clone(),
        model: camera.model.clone(),
        canonical_make: camera.canonical_make.clone(),
        canonical_model: camera.canonical_model.clone(),
        width: width as usize,
        height: height as usize,
        wb_coeffs: try!(self.get_wb()),
        data: image.into_boxed_slice(),
        blacklevels: camera.blacklevels,
        whitelevels: camera.whitelevels,
        color_matrix: camera.color_matrix,
        cfa: camera.cfa.clone(),
        crops: [0,0,0,0],
      })
    } else {
      ok_image(camera, width, height, try!(self.get_wb()), image)
    }
  }
}

impl<'a> RafDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    match self.tiff.find_entry(Tag::RafWBGRB) {
      Some(levels) => Ok([levels.get_f32(1), levels.get_f32(0), levels.get_f32(2), NAN]),
      None => {
        let levels = fetch_tag!(self.tiff, Tag::RafOldWB);
        Ok([levels.get_f32(1), levels.get_f32(0), levels.get_f32(3), NAN])
      },
    }
  }

  fn rotate_image(src: &[u16], camera: &Camera, width: usize, height: usize) -> (usize, usize, Vec<u16>) {
    let x = camera.crops[3] as usize;
    let y = camera.crops[0] as usize;
    let cropwidth = width - (camera.crops[1] as usize) - x;
    let cropheight = height - (camera.crops[2] as usize) - y;

    let rotatedwidth = cropwidth + cropheight/2;
    let rotatedheight = rotatedwidth-1;

    let mut out: Vec<u16> = vec![0; (rotatedwidth*rotatedheight) as usize];
    for row in 0..cropheight {
      let inb = &src[row*width+x..];
      for col in 0..cropwidth {
        let out_row = cropwidth - 1 - col + (row>>1);
        let out_col = ((row+1) >> 1) + col;
        out[out_row*rotatedwidth+out_col] = inb[col];
      }
    }

    (rotatedwidth, rotatedheight, out)
  }
}
<commit_msg>RAF: speed up and thread the rotation code<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct RafDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> RafDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> RafDecoder<'a> {
    RafDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for RafDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let raw = fetch_ifd!(&self.tiff, Tag::RafOffsets);
    let (width,height) = if raw.has_entry(Tag::RafImageWidth) {
      (fetch_tag!(raw, Tag::RafImageWidth).get_u32(0),
       fetch_tag!(raw, Tag::RafImageLength).get_u32(0))
    } else {
      let sizes = fetch_tag!(raw, Tag::ImageWidth);
      (sizes.get_u32(1), sizes.get_u32(0))
    };
    let offset = fetch_tag!(raw, Tag::RafOffsets).get_u32(0) as usize + raw.start_offset();
    let bps = match raw.find_entry(Tag::RafBitsPerSample) {
      Some(val) => val.get_u32(0),
      None      => 16,
    };
    let src = &self.buffer[offset..];

    let image = match bps {
      12 => decode_12le(src, width as usize, height as usize),
      14 => decode_14le_unpacked(src, width as usize, height as usize),
      16 => decode_16le(src, width as usize, height as usize),
      _ => {return Err(format!("RAF: Don't know how to decode bps {}", bps).to_string());},
    };

    if camera.find_hint("fuji_rotation") {
      let (width, height, image) = RafDecoder::rotate_image(&image, camera, width as usize, height as usize);
      Ok(Image {
        make: camera.make.clone(),
        model: camera.model.clone(),
        canonical_make: camera.canonical_make.clone(),
        canonical_model: camera.canonical_model.clone(),
        width: width as usize,
        height: height as usize,
        wb_coeffs: try!(self.get_wb()),
        data: image.into_boxed_slice(),
        blacklevels: camera.blacklevels,
        whitelevels: camera.whitelevels,
        color_matrix: camera.color_matrix,
        cfa: camera.cfa.clone(),
        crops: [0,0,0,0],
      })
    } else {
      ok_image(camera, width, height, try!(self.get_wb()), image)
    }
  }
}

impl<'a> RafDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    match self.tiff.find_entry(Tag::RafWBGRB) {
      Some(levels) => Ok([levels.get_f32(1), levels.get_f32(0), levels.get_f32(2), NAN]),
      None => {
        let levels = fetch_tag!(self.tiff, Tag::RafOldWB);
        Ok([levels.get_f32(1), levels.get_f32(0), levels.get_f32(3), NAN])
      },
    }
  }

  fn rotate_image(src: &[u16], camera: &Camera, width: usize, height: usize) -> (usize, usize, Vec<u16>) {
    let x = camera.crops[3] as usize;
    let y = camera.crops[0] as usize;
    let cropwidth = width - (camera.crops[1] as usize) - x;
    let cropheight = height - (camera.crops[2] as usize) - y;

    let rotatedwidth = cropwidth + cropheight/2;
    let rotatedheight = rotatedwidth-1;

    // Doing the rotation by iterating the output instead of the input results in stranger
    // code that is ~30% faster including threading. In absolute terms it's not a large
    // improvement though so going back to the simpler code may make sense in case of bugs
    let out = decode_threaded(rotatedwidth, rotatedheight, &(|out: &mut [u16], row| {
      let startcol = if row < cropwidth { cropwidth - 1 - row } else { row + 1 - cropwidth };
      let endcol = if (row + cropwidth) < rotatedwidth {
        row + cropwidth
      } else {
        (rotatedwidth - 1) - (row + cropwidth - rotatedwidth) - 1
      };

      for (i,col) in (startcol..endcol+1).enumerate() {
        let (in_row, in_col) = if row < cropwidth {
          (y+i, (x+cropwidth-1) - row + i/2)
        } else {
          (y + (row-cropwidth+1)*2 + i, x + i/2)
        };
        out[col] = src[in_row*width + in_col];
      }
    }));

    (rotatedwidth, rotatedheight, out)
  }
}
<|endoftext|>


<commit_before>use core::fmt;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::ptr;

/// Number of words a piece of `Data` can hold.
///
/// Three words should be enough for the majority of cases. For example, you can fit inside it the
/// function pointer together with a fat pointer representing an object that needs to be destroyed.
const DATA_WORDS: usize = 3;

/// Some space to keep a `FnOnce()` object on the stack.
type Data = [usize; DATA_WORDS];

/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap.
///
/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure.
pub(super) struct Deferred {
    call: unsafe fn(*mut u8),
    data: Data,
    _marker: PhantomData<*mut ()>, // !Send + !Sync
}

impl fmt::Debug for Deferred {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.pad("Deferred { .. }")
    }
}

unsafe fn call_raw<F: FnOnce()>(raw: *mut u8) {
    let f: F = ptr::read(raw as *mut F);
    f();
}

unsafe fn call_raw_box<F: FnOnce()>(raw: *mut u8) {
    // It's safe to cast `raw` from `*mut u8` to `*mut Box<F>`, because `raw` is
    // originally derived from `*mut Box<F>`.
    #[allow(clippy::cast_ptr_alignment)]
    let b: Box<F> = ptr::read(raw as *mut Box<F>);
    (*b)();
}

impl Deferred {
    /// Constructs a new `Deferred` from a `FnOnce()`.
    pub(super) fn new<F: FnOnce()>(f: F) -> Self {
        let size = mem::size_of::<F>();
        let align = mem::align_of::<F>();

        unsafe {
            if size <= mem::size_of::<Data>()
                && align <= mem::align_of::<Data>()
            {
                let mut data = MaybeUninit::<Data>::uninit();
                ptr::write(data.as_mut_ptr() as *mut F, f);

                Deferred {
                    call: call_raw::<F>,
                    data: data.assume_init(),
                    _marker: PhantomData,
                }
            } else {
                let b: Box<F> = Box::new(f);
                let mut data = MaybeUninit::<Data>::uninit();
                ptr::write(data.as_mut_ptr() as *mut Box<F>, b);

                Deferred {
                    call: call_raw_box::<F>,
                    data: data.assume_init(),
                    _marker: PhantomData,
                }
            }
        }
    }

    /// Calls the function.
    #[inline]
    pub(super) fn call(mut self) {
        let call = self.call;
        #[allow(trivial_casts)]
        unsafe {
            call(&mut self.data as *mut Data as *mut u8)
        };
    }
}

#[cfg(test)]
mod tests {
    use super::Deferred;
    use std::cell::Cell;

    #[test]
    fn on_stack() {
        let fired = &Cell::new(false);
        let a = [0_usize; 1];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn on_heap() {
        let fired = &Cell::new(false);
        let a = [0_usize; 10];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn string() {
        let a = "hello".to_string();
        let d = Deferred::new(move || assert_eq!(a, "hello"));
        d.call();
    }

    #[test]
    fn boxed_slice_i32() {
        let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice();
        let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7]));
        d.call();
    }

    #[test]
    fn long_slice_usize() {
        let a: [usize; 5] = [2, 3, 5, 7, 11];
        let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11]));
        d.call();
    }
}
<commit_msg>Prevent UB with `assume_init` on uninit bytes<commit_after>use core::fmt;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::ptr;

/// Number of words a piece of `Data` can hold.
///
/// Three words should be enough for the majority of cases. For example, you can fit inside it the
/// function pointer together with a fat pointer representing an object that needs to be destroyed.
const DATA_WORDS: usize = 3;

/// Some space to keep a `FnOnce()` object on the stack.
type Data = MaybeUninit<[usize; DATA_WORDS]>;

/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap.
///
/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure.
pub(super) struct Deferred {
    call: unsafe fn(*mut u8),
    data: Data,
    _marker: PhantomData<*mut ()>, // !Send + !Sync
}

impl fmt::Debug for Deferred {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.pad("Deferred { .. }")
    }
}

unsafe fn call_raw<F: FnOnce()>(raw: *mut u8) {
    let f: F = ptr::read(raw as *mut F);
    f();
}

unsafe fn call_raw_box<F: FnOnce()>(raw: *mut u8) {
    // It's safe to cast `raw` from `*mut u8` to `*mut Box<F>`, because `raw` is
    // originally derived from `*mut Box<F>`.
    #[allow(clippy::cast_ptr_alignment)]
    let b: Box<F> = ptr::read(raw as *mut Box<F>);
    (*b)();
}

impl Deferred {
    /// Constructs a new `Deferred` from a `FnOnce()`.
    pub(super) fn new<F: FnOnce()>(f: F) -> Self {
        let size = mem::size_of::<F>();
        let align = mem::align_of::<F>();

        unsafe {
            if size <= mem::size_of::<Data>()
                && align <= mem::align_of::<Data>()
            {
                let mut data = Data::uninit();
                ptr::write(data.as_mut_ptr() as *mut F, f);

                Deferred {
                    call: call_raw::<F>,
                    data,
                    _marker: PhantomData,
                }
            } else {
                let b: Box<F> = Box::new(f);
                let mut data = Data::uninit();
                ptr::write(data.as_mut_ptr() as *mut Box<F>, b);

                Deferred {
                    call: call_raw_box::<F>,
                    data,
                    _marker: PhantomData,
                }
            }
        }
    }

    /// Calls the function.
    #[inline]
    pub(super) fn call(mut self) {
        let call = self.call;
        #[allow(trivial_casts)]
        unsafe {
            call(self.data.as_mut_ptr().cast())
        };
    }
}

#[cfg(test)]
mod tests {
    use super::Deferred;
    use std::cell::Cell;

    #[test]
    fn on_stack() {
        let fired = &Cell::new(false);
        let a = [0_usize; 1];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn on_heap() {
        let fired = &Cell::new(false);
        let a = [0_usize; 10];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn string() {
        let a = "hello".to_string();
        let d = Deferred::new(move || assert_eq!(a, "hello"));
        d.call();
    }

    #[test]
    fn boxed_slice_i32() {
        let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice();
        let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7]));
        d.call();
    }

    #[test]
    fn long_slice_usize() {
        let a: [usize; 5] = [2, 3, 5, 7, 11];
        let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11]));
        d.call();
    }
}
<|endoftext|>