DOS header parser in Rust











up vote
1
down vote

favorite












Looking for feedback mostly on the from() and printf() implementations but I included everything for context. Please do not suggest crates, this was an exercise for me to better learn the primitives in Rust (including bitwise ops). Also, please do not suggest unsafe Rust! I need the code to use only safe Rust constructs. I can't help but want to create a struct of Results and use it in place of all of the individual vars in the from() func.



use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::str;
use std::mem::size_of;
use std::convert::From;
use std::fmt::{Display, Formatter, Result};
// TODO: Parse LONG from vec of bytes



fn main() -> io::Result<()> {
let mut f = File::open("HashMyFiles.exe")?;
let mut reader = BufReader::new(f);

let read_result = parse_bytes::read_n(&mut reader, size_of::<IMAGE_DOS_HEADER>()); // Ok means Vec<u8>

match read_result
{
Ok(r) =>
{
let idh = IMAGE_DOS_HEADER::from(&r);
idh.printf();

},
Err(e) => println!("Error: {}", e)
}


Ok(())
}
/// Reads n bytes (arg1) from T: Read (arg2) and returns them in a u8 vector Result
/// Note: The number of bytes to read is controlled by the vector size for read_exact
fn read_n<T>(n: usize, reader: &mut T) -> io::Result<Vec<u8>>
where T: Read
{
let mut buf = vec![0; n];
let result = reader.read_exact(&mut buf);
match result
{
Ok(_) => return Ok(buf),
Err(e) => return Err(e)
}
}
type WORD = u16; // aka USHORT
type DWORD = u32;
type CHAR = u8;
type BYTE = u8;
type LONG = i32; // signed

///Size: First 64 bytes of valid PE file
#[derive(PartialEq, Debug)]
struct IMAGE_DOS_HEADER
{
e_magic: WORD,
e_cblp: WORD,
e_cp: WORD,
e_crlc: WORD,
e_cparhdr: WORD,
e_minalloc: WORD,
e_maxalloc: WORD,
e_ss: WORD,
e_sp: WORD,
e_csum: WORD,
e_ip: WORD,
e_cs: WORD,
e_lfarlc: WORD,
e_ovno: WORD,
e_res: [WORD; 4],
e_oemid: WORD,
e_oeminfo: WORD,
e_res2: [WORD; 10],
e_lfanew: LONG
}

impl IMAGE_DOS_HEADER
{
fn new<T>(br: T)
where T: BufRead
{

}
fn printf(&self)
{
println!("struct IMAGE_DOS_HEADER");
println!("te_magic: ");
parse_bytes::print_word(self.e_magic);

println!("te_cblp: {:X}", self.e_cblp);
println!("te_cblp: {:X}", self.e_cblp);
println!("te_cp: {:X}", self.e_cp);
println!("te_crlc: {:X}", self.e_crlc);
println!("te_cparhdr: {:X}", self.e_cparhdr);
println!("te_minalloc: {:X}", self.e_minalloc);
println!("te_maxalloc: {:X}", self.e_maxalloc);
println!("te_ss: {:X}", self.e_ss);
println!("te_sp: {:X}", self.e_sp);
println!("te_csum: {:X}", self.e_csum);
println!("te_ip: {:X}", self.e_ip);
println!("te_cs: {:X}", self.e_cs);
println!("te_lfarlc: {:X}", self.e_lfarlc);
println!("te_ovno: {:X}", self.e_ovno);
println!("te_res: ");
for b in self.e_res.iter()
{
print!("{:X}", b);
}
println!("te_oemid: {:X}", self.e_oemid);
println!("te_oeminfo: {:X}", self.e_oeminfo);
println!("te_res2: ");
for b in self.e_res2.iter()
{
print!("{:X}", b);
}
println!("te_lfanew: {:X}", self.e_lfanew);



}

}

impl Display for IMAGE_DOS_HEADER
{
fn fmt(&self, f: &mut Formatter) -> Result
{
write!(f, "e_magic: {:X}n
e_cblp: {:X}n", self.e_magic, self.e_cblp)

}
}

impl<'a> From<&'a Vec<u8>> for IMAGE_DOS_HEADER
{
fn from(f: &'a Vec<u8>) -> Self
{
use std::io::Cursor;
let mut buf = Cursor::new(f);
//Not a fan of this below:
let e_magic = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_cblp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_cp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_crlc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_cparhdr = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_minalloc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_maxalloc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_ss = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_sp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_csum = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_ip = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_cs = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_lfarlc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_ovno = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_res = parse_bytes::read_n(&mut buf, std::mem::size_of::<[WORD; 4]>());
let e_oemid = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_oeminfo = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
let e_res2 = parse_bytes::read_n(&mut buf, std::mem::size_of::<[WORD; 10]>());
let e_lfanew = parse_bytes::read_n(&mut buf, std::mem::size_of::<LONG>());

IMAGE_DOS_HEADER
{
e_magic:
{
let v = e_magic.unwrap();

((v[0] as u16) << 8) | v[1] as u16

},

e_cblp:
{
let v = e_cblp.unwrap();

((v[0] as u16) << 8) | v[1] as u16

},
e_cp:
{
let v = e_cp.unwrap();

((v[0] as u16) << 8) | v[1] as u16

},
e_crlc:
{
let v = e_crlc.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_cparhdr:
{

let v = e_cparhdr.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_minalloc:
{

let v = e_minalloc.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_maxalloc:
{

let v = e_maxalloc.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_ss:
{

let v = e_ss.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_sp:
{

let v = e_sp.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_csum:
{

let v = e_csum.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_ip:
{

let v = e_ip.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_cs:
{

let v = e_cs.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_lfarlc:
{

let v = e_lfarlc.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_ovno:
{

let v = e_ovno.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_res:
{

let v = e_res.unwrap();
let mut four_w: [WORD; 4]= [0; 4];
four_w[0] = ((v[0] as u16) << 8) | v[1] as u16;
four_w[1] = ((v[2] as u16) << 8) | v[3] as u16;
four_w[2] = ((v[4] as u16) << 8) | v[5] as u16;
four_w[3] = ((v[6] as u16) << 8) | v[7] as u16;
four_w
},
e_oemid:
{

let v = e_oemid.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_oeminfo:
{

let v = e_oeminfo.unwrap();

((v[0] as u16) << 8) | v[1] as u16
},
e_res2:
{

let v = e_res2.unwrap();

let mut ten_w: [WORD;10]= [0; 10];
ten_w[0] = ((v[0] as u16) << 8) | v[1] as u16;
ten_w[1] = ((v[2] as u16) << 8) | v[3] as u16;
ten_w[2] = ((v[4] as u16) << 8) | v[5] as u16;
ten_w[3] = ((v[6] as u16) << 8) | v[7] as u16;
ten_w[4] = ((v[8] as u16) << 8) | v[9] as u16;
ten_w[5] = ((v[10] as u16) << 8) | v[11] as u16;
ten_w[6] = ((v[12] as u16) << 8) | v[13] as u16;
ten_w[7] = ((v[14] as u16) << 8) | v[15] as u16;
ten_w[8] = ((v[16] as u16) << 8) | v[17] as u16;
ten_w[9] = ((v[18] as u16) << 8) | v[19] as u16;
ten_w
},
e_lfanew:
{
let v = e_lfanew.unwrap();

let temp: i32 = (v[0] as i32)<< 24 as i32;
let temp2: i32 = (v[1] as i32)<< 16 as i32;
let temp3: i32 = (v[2] as i32)<< 8 as i32;
let result = temp | temp2 | temp3 | v[3] as i32;
result
}
}
}
}



mod parse_bytes
{
use std::io::Read;
use std::io::BufRead;
pub fn read_n<T>(br: &mut T, num_bytes: usize) -> Result<Vec<u8>, ::std::io::Error>
where T: BufRead
{
let mut buf = vec![0u8; num_bytes];
let result = br.read_exact(&mut buf);
match result
{
Ok(r) => return Ok(buf.to_vec()),
Err(e) => return Err(e)
}


}

pub fn u8_to_char(u: u8) -> char
{
u as char
}

pub fn print_word(w: u16)
{
let b1 = (w >> 8) as u8; // Grab high aka "first" byte
let b2 = w as u8; // Grab low aka "second" byte (right)
print!("{}{}", u8_to_char(b1), u8_to_char(b2));
}

pub fn be_to_le(be: &mut [u8]) -> Vec<u8>
{
let mut be2: Vec<u8> = vec!;
for i in be.len()..0
{
be2.push(be[i]);
}
be2
}

pub fn print_byte_vec_as_chars(bvec: &[u8])
{
for b in bvec.iter()
{
print!("{}", u8_to_char(*b));
}
}
}









share|improve this question




























    up vote
    1
    down vote

    favorite












    Looking for feedback mostly on the from() and printf() implementations but I included everything for context. Please do not suggest crates, this was an exercise for me to better learn the primitives in Rust (including bitwise ops). Also, please do not suggest unsafe Rust! I need the code to use only safe Rust constructs. I can't help but want to create a struct of Results and use it in place of all of the individual vars in the from() func.



    use std::io;
    use std::io::prelude::*;
    use std::fs::File;
    use std::io::BufRead;
    use std::io::BufReader;
    use std::str;
    use std::mem::size_of;
    use std::convert::From;
    use std::fmt::{Display, Formatter, Result};
    // TODO: Parse LONG from vec of bytes



    fn main() -> io::Result<()> {
    let mut f = File::open("HashMyFiles.exe")?;
    let mut reader = BufReader::new(f);

    let read_result = parse_bytes::read_n(&mut reader, size_of::<IMAGE_DOS_HEADER>()); // Ok means Vec<u8>

    match read_result
    {
    Ok(r) =>
    {
    let idh = IMAGE_DOS_HEADER::from(&r);
    idh.printf();

    },
    Err(e) => println!("Error: {}", e)
    }


    Ok(())
    }
    /// Reads n bytes (arg1) from T: Read (arg2) and returns them in a u8 vector Result
    /// Note: The number of bytes to read is controlled by the vector size for read_exact
    fn read_n<T>(n: usize, reader: &mut T) -> io::Result<Vec<u8>>
    where T: Read
    {
    let mut buf = vec![0; n];
    let result = reader.read_exact(&mut buf);
    match result
    {
    Ok(_) => return Ok(buf),
    Err(e) => return Err(e)
    }
    }
    type WORD = u16; // aka USHORT
    type DWORD = u32;
    type CHAR = u8;
    type BYTE = u8;
    type LONG = i32; // signed

    ///Size: First 64 bytes of valid PE file
    #[derive(PartialEq, Debug)]
    struct IMAGE_DOS_HEADER
    {
    e_magic: WORD,
    e_cblp: WORD,
    e_cp: WORD,
    e_crlc: WORD,
    e_cparhdr: WORD,
    e_minalloc: WORD,
    e_maxalloc: WORD,
    e_ss: WORD,
    e_sp: WORD,
    e_csum: WORD,
    e_ip: WORD,
    e_cs: WORD,
    e_lfarlc: WORD,
    e_ovno: WORD,
    e_res: [WORD; 4],
    e_oemid: WORD,
    e_oeminfo: WORD,
    e_res2: [WORD; 10],
    e_lfanew: LONG
    }

    impl IMAGE_DOS_HEADER
    {
    fn new<T>(br: T)
    where T: BufRead
    {

    }
    fn printf(&self)
    {
    println!("struct IMAGE_DOS_HEADER");
    println!("te_magic: ");
    parse_bytes::print_word(self.e_magic);

    println!("te_cblp: {:X}", self.e_cblp);
    println!("te_cblp: {:X}", self.e_cblp);
    println!("te_cp: {:X}", self.e_cp);
    println!("te_crlc: {:X}", self.e_crlc);
    println!("te_cparhdr: {:X}", self.e_cparhdr);
    println!("te_minalloc: {:X}", self.e_minalloc);
    println!("te_maxalloc: {:X}", self.e_maxalloc);
    println!("te_ss: {:X}", self.e_ss);
    println!("te_sp: {:X}", self.e_sp);
    println!("te_csum: {:X}", self.e_csum);
    println!("te_ip: {:X}", self.e_ip);
    println!("te_cs: {:X}", self.e_cs);
    println!("te_lfarlc: {:X}", self.e_lfarlc);
    println!("te_ovno: {:X}", self.e_ovno);
    println!("te_res: ");
    for b in self.e_res.iter()
    {
    print!("{:X}", b);
    }
    println!("te_oemid: {:X}", self.e_oemid);
    println!("te_oeminfo: {:X}", self.e_oeminfo);
    println!("te_res2: ");
    for b in self.e_res2.iter()
    {
    print!("{:X}", b);
    }
    println!("te_lfanew: {:X}", self.e_lfanew);



    }

    }

    impl Display for IMAGE_DOS_HEADER
    {
    fn fmt(&self, f: &mut Formatter) -> Result
    {
    write!(f, "e_magic: {:X}n
    e_cblp: {:X}n", self.e_magic, self.e_cblp)

    }
    }

    impl<'a> From<&'a Vec<u8>> for IMAGE_DOS_HEADER
    {
    fn from(f: &'a Vec<u8>) -> Self
    {
    use std::io::Cursor;
    let mut buf = Cursor::new(f);
    //Not a fan of this below:
    let e_magic = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_cblp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_cp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_crlc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_cparhdr = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_minalloc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_maxalloc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_ss = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_sp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_csum = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_ip = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_cs = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_lfarlc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_ovno = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_res = parse_bytes::read_n(&mut buf, std::mem::size_of::<[WORD; 4]>());
    let e_oemid = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_oeminfo = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
    let e_res2 = parse_bytes::read_n(&mut buf, std::mem::size_of::<[WORD; 10]>());
    let e_lfanew = parse_bytes::read_n(&mut buf, std::mem::size_of::<LONG>());

    IMAGE_DOS_HEADER
    {
    e_magic:
    {
    let v = e_magic.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16

    },

    e_cblp:
    {
    let v = e_cblp.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16

    },
    e_cp:
    {
    let v = e_cp.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16

    },
    e_crlc:
    {
    let v = e_crlc.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_cparhdr:
    {

    let v = e_cparhdr.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_minalloc:
    {

    let v = e_minalloc.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_maxalloc:
    {

    let v = e_maxalloc.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_ss:
    {

    let v = e_ss.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_sp:
    {

    let v = e_sp.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_csum:
    {

    let v = e_csum.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_ip:
    {

    let v = e_ip.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_cs:
    {

    let v = e_cs.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_lfarlc:
    {

    let v = e_lfarlc.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_ovno:
    {

    let v = e_ovno.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_res:
    {

    let v = e_res.unwrap();
    let mut four_w: [WORD; 4]= [0; 4];
    four_w[0] = ((v[0] as u16) << 8) | v[1] as u16;
    four_w[1] = ((v[2] as u16) << 8) | v[3] as u16;
    four_w[2] = ((v[4] as u16) << 8) | v[5] as u16;
    four_w[3] = ((v[6] as u16) << 8) | v[7] as u16;
    four_w
    },
    e_oemid:
    {

    let v = e_oemid.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_oeminfo:
    {

    let v = e_oeminfo.unwrap();

    ((v[0] as u16) << 8) | v[1] as u16
    },
    e_res2:
    {

    let v = e_res2.unwrap();

    let mut ten_w: [WORD;10]= [0; 10];
    ten_w[0] = ((v[0] as u16) << 8) | v[1] as u16;
    ten_w[1] = ((v[2] as u16) << 8) | v[3] as u16;
    ten_w[2] = ((v[4] as u16) << 8) | v[5] as u16;
    ten_w[3] = ((v[6] as u16) << 8) | v[7] as u16;
    ten_w[4] = ((v[8] as u16) << 8) | v[9] as u16;
    ten_w[5] = ((v[10] as u16) << 8) | v[11] as u16;
    ten_w[6] = ((v[12] as u16) << 8) | v[13] as u16;
    ten_w[7] = ((v[14] as u16) << 8) | v[15] as u16;
    ten_w[8] = ((v[16] as u16) << 8) | v[17] as u16;
    ten_w[9] = ((v[18] as u16) << 8) | v[19] as u16;
    ten_w
    },
    e_lfanew:
    {
    let v = e_lfanew.unwrap();

    let temp: i32 = (v[0] as i32)<< 24 as i32;
    let temp2: i32 = (v[1] as i32)<< 16 as i32;
    let temp3: i32 = (v[2] as i32)<< 8 as i32;
    let result = temp | temp2 | temp3 | v[3] as i32;
    result
    }
    }
    }
    }



    mod parse_bytes
    {
    use std::io::Read;
    use std::io::BufRead;
    pub fn read_n<T>(br: &mut T, num_bytes: usize) -> Result<Vec<u8>, ::std::io::Error>
    where T: BufRead
    {
    let mut buf = vec![0u8; num_bytes];
    let result = br.read_exact(&mut buf);
    match result
    {
    Ok(r) => return Ok(buf.to_vec()),
    Err(e) => return Err(e)
    }


    }

    pub fn u8_to_char(u: u8) -> char
    {
    u as char
    }

    pub fn print_word(w: u16)
    {
    let b1 = (w >> 8) as u8; // Grab high aka "first" byte
    let b2 = w as u8; // Grab low aka "second" byte (right)
    print!("{}{}", u8_to_char(b1), u8_to_char(b2));
    }

    pub fn be_to_le(be: &mut [u8]) -> Vec<u8>
    {
    let mut be2: Vec<u8> = vec!;
    for i in be.len()..0
    {
    be2.push(be[i]);
    }
    be2
    }

    pub fn print_byte_vec_as_chars(bvec: &[u8])
    {
    for b in bvec.iter()
    {
    print!("{}", u8_to_char(*b));
    }
    }
    }









    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      Looking for feedback mostly on the from() and printf() implementations but I included everything for context. Please do not suggest crates, this was an exercise for me to better learn the primitives in Rust (including bitwise ops). Also, please do not suggest unsafe Rust! I need the code to use only safe Rust constructs. I can't help but want to create a struct of Results and use it in place of all of the individual vars in the from() func.



      use std::io;
      use std::io::prelude::*;
      use std::fs::File;
      use std::io::BufRead;
      use std::io::BufReader;
      use std::str;
      use std::mem::size_of;
      use std::convert::From;
      use std::fmt::{Display, Formatter, Result};
      // TODO: Parse LONG from vec of bytes



      fn main() -> io::Result<()> {
      let mut f = File::open("HashMyFiles.exe")?;
      let mut reader = BufReader::new(f);

      let read_result = parse_bytes::read_n(&mut reader, size_of::<IMAGE_DOS_HEADER>()); // Ok means Vec<u8>

      match read_result
      {
      Ok(r) =>
      {
      let idh = IMAGE_DOS_HEADER::from(&r);
      idh.printf();

      },
      Err(e) => println!("Error: {}", e)
      }


      Ok(())
      }
      /// Reads n bytes (arg1) from T: Read (arg2) and returns them in a u8 vector Result
      /// Note: The number of bytes to read is controlled by the vector size for read_exact
      fn read_n<T>(n: usize, reader: &mut T) -> io::Result<Vec<u8>>
      where T: Read
      {
      let mut buf = vec![0; n];
      let result = reader.read_exact(&mut buf);
      match result
      {
      Ok(_) => return Ok(buf),
      Err(e) => return Err(e)
      }
      }
      type WORD = u16; // aka USHORT
      type DWORD = u32;
      type CHAR = u8;
      type BYTE = u8;
      type LONG = i32; // signed

      ///Size: First 64 bytes of valid PE file
      #[derive(PartialEq, Debug)]
      struct IMAGE_DOS_HEADER
      {
      e_magic: WORD,
      e_cblp: WORD,
      e_cp: WORD,
      e_crlc: WORD,
      e_cparhdr: WORD,
      e_minalloc: WORD,
      e_maxalloc: WORD,
      e_ss: WORD,
      e_sp: WORD,
      e_csum: WORD,
      e_ip: WORD,
      e_cs: WORD,
      e_lfarlc: WORD,
      e_ovno: WORD,
      e_res: [WORD; 4],
      e_oemid: WORD,
      e_oeminfo: WORD,
      e_res2: [WORD; 10],
      e_lfanew: LONG
      }

      impl IMAGE_DOS_HEADER
      {
      fn new<T>(br: T)
      where T: BufRead
      {

      }
      fn printf(&self)
      {
      println!("struct IMAGE_DOS_HEADER");
      println!("te_magic: ");
      parse_bytes::print_word(self.e_magic);

      println!("te_cblp: {:X}", self.e_cblp);
      println!("te_cblp: {:X}", self.e_cblp);
      println!("te_cp: {:X}", self.e_cp);
      println!("te_crlc: {:X}", self.e_crlc);
      println!("te_cparhdr: {:X}", self.e_cparhdr);
      println!("te_minalloc: {:X}", self.e_minalloc);
      println!("te_maxalloc: {:X}", self.e_maxalloc);
      println!("te_ss: {:X}", self.e_ss);
      println!("te_sp: {:X}", self.e_sp);
      println!("te_csum: {:X}", self.e_csum);
      println!("te_ip: {:X}", self.e_ip);
      println!("te_cs: {:X}", self.e_cs);
      println!("te_lfarlc: {:X}", self.e_lfarlc);
      println!("te_ovno: {:X}", self.e_ovno);
      println!("te_res: ");
      for b in self.e_res.iter()
      {
      print!("{:X}", b);
      }
      println!("te_oemid: {:X}", self.e_oemid);
      println!("te_oeminfo: {:X}", self.e_oeminfo);
      println!("te_res2: ");
      for b in self.e_res2.iter()
      {
      print!("{:X}", b);
      }
      println!("te_lfanew: {:X}", self.e_lfanew);



      }

      }

      impl Display for IMAGE_DOS_HEADER
      {
      fn fmt(&self, f: &mut Formatter) -> Result
      {
      write!(f, "e_magic: {:X}n
      e_cblp: {:X}n", self.e_magic, self.e_cblp)

      }
      }

      impl<'a> From<&'a Vec<u8>> for IMAGE_DOS_HEADER
      {
      fn from(f: &'a Vec<u8>) -> Self
      {
      use std::io::Cursor;
      let mut buf = Cursor::new(f);
      //Not a fan of this below:
      let e_magic = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_cblp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_cp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_crlc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_cparhdr = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_minalloc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_maxalloc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_ss = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_sp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_csum = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_ip = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_cs = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_lfarlc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_ovno = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_res = parse_bytes::read_n(&mut buf, std::mem::size_of::<[WORD; 4]>());
      let e_oemid = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_oeminfo = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_res2 = parse_bytes::read_n(&mut buf, std::mem::size_of::<[WORD; 10]>());
      let e_lfanew = parse_bytes::read_n(&mut buf, std::mem::size_of::<LONG>());

      IMAGE_DOS_HEADER
      {
      e_magic:
      {
      let v = e_magic.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16

      },

      e_cblp:
      {
      let v = e_cblp.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16

      },
      e_cp:
      {
      let v = e_cp.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16

      },
      e_crlc:
      {
      let v = e_crlc.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_cparhdr:
      {

      let v = e_cparhdr.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_minalloc:
      {

      let v = e_minalloc.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_maxalloc:
      {

      let v = e_maxalloc.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_ss:
      {

      let v = e_ss.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_sp:
      {

      let v = e_sp.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_csum:
      {

      let v = e_csum.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_ip:
      {

      let v = e_ip.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_cs:
      {

      let v = e_cs.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_lfarlc:
      {

      let v = e_lfarlc.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_ovno:
      {

      let v = e_ovno.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_res:
      {

      let v = e_res.unwrap();
      let mut four_w: [WORD; 4]= [0; 4];
      four_w[0] = ((v[0] as u16) << 8) | v[1] as u16;
      four_w[1] = ((v[2] as u16) << 8) | v[3] as u16;
      four_w[2] = ((v[4] as u16) << 8) | v[5] as u16;
      four_w[3] = ((v[6] as u16) << 8) | v[7] as u16;
      four_w
      },
      e_oemid:
      {

      let v = e_oemid.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_oeminfo:
      {

      let v = e_oeminfo.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_res2:
      {

      let v = e_res2.unwrap();

      let mut ten_w: [WORD;10]= [0; 10];
      ten_w[0] = ((v[0] as u16) << 8) | v[1] as u16;
      ten_w[1] = ((v[2] as u16) << 8) | v[3] as u16;
      ten_w[2] = ((v[4] as u16) << 8) | v[5] as u16;
      ten_w[3] = ((v[6] as u16) << 8) | v[7] as u16;
      ten_w[4] = ((v[8] as u16) << 8) | v[9] as u16;
      ten_w[5] = ((v[10] as u16) << 8) | v[11] as u16;
      ten_w[6] = ((v[12] as u16) << 8) | v[13] as u16;
      ten_w[7] = ((v[14] as u16) << 8) | v[15] as u16;
      ten_w[8] = ((v[16] as u16) << 8) | v[17] as u16;
      ten_w[9] = ((v[18] as u16) << 8) | v[19] as u16;
      ten_w
      },
      e_lfanew:
      {
      let v = e_lfanew.unwrap();

      let temp: i32 = (v[0] as i32)<< 24 as i32;
      let temp2: i32 = (v[1] as i32)<< 16 as i32;
      let temp3: i32 = (v[2] as i32)<< 8 as i32;
      let result = temp | temp2 | temp3 | v[3] as i32;
      result
      }
      }
      }
      }



      mod parse_bytes
      {
      use std::io::Read;
      use std::io::BufRead;
      pub fn read_n<T>(br: &mut T, num_bytes: usize) -> Result<Vec<u8>, ::std::io::Error>
      where T: BufRead
      {
      let mut buf = vec![0u8; num_bytes];
      let result = br.read_exact(&mut buf);
      match result
      {
      Ok(r) => return Ok(buf.to_vec()),
      Err(e) => return Err(e)
      }


      }

      pub fn u8_to_char(u: u8) -> char
      {
      u as char
      }

      pub fn print_word(w: u16)
      {
      let b1 = (w >> 8) as u8; // Grab high aka "first" byte
      let b2 = w as u8; // Grab low aka "second" byte (right)
      print!("{}{}", u8_to_char(b1), u8_to_char(b2));
      }

      pub fn be_to_le(be: &mut [u8]) -> Vec<u8>
      {
      let mut be2: Vec<u8> = vec!;
      for i in be.len()..0
      {
      be2.push(be[i]);
      }
      be2
      }

      pub fn print_byte_vec_as_chars(bvec: &[u8])
      {
      for b in bvec.iter()
      {
      print!("{}", u8_to_char(*b));
      }
      }
      }









      share|improve this question















      Looking for feedback mostly on the from() and printf() implementations but I included everything for context. Please do not suggest crates, this was an exercise for me to better learn the primitives in Rust (including bitwise ops). Also, please do not suggest unsafe Rust! I need the code to use only safe Rust constructs. I can't help but want to create a struct of Results and use it in place of all of the individual vars in the from() func.



      use std::io;
      use std::io::prelude::*;
      use std::fs::File;
      use std::io::BufRead;
      use std::io::BufReader;
      use std::str;
      use std::mem::size_of;
      use std::convert::From;
      use std::fmt::{Display, Formatter, Result};
      // TODO: Parse LONG from vec of bytes



      fn main() -> io::Result<()> {
      let mut f = File::open("HashMyFiles.exe")?;
      let mut reader = BufReader::new(f);

      let read_result = parse_bytes::read_n(&mut reader, size_of::<IMAGE_DOS_HEADER>()); // Ok means Vec<u8>

      match read_result
      {
      Ok(r) =>
      {
      let idh = IMAGE_DOS_HEADER::from(&r);
      idh.printf();

      },
      Err(e) => println!("Error: {}", e)
      }


      Ok(())
      }
      /// Reads n bytes (arg1) from T: Read (arg2) and returns them in a u8 vector Result
      /// Note: The number of bytes to read is controlled by the vector size for read_exact
      fn read_n<T>(n: usize, reader: &mut T) -> io::Result<Vec<u8>>
      where T: Read
      {
      let mut buf = vec![0; n];
      let result = reader.read_exact(&mut buf);
      match result
      {
      Ok(_) => return Ok(buf),
      Err(e) => return Err(e)
      }
      }
      type WORD = u16; // aka USHORT
      type DWORD = u32;
      type CHAR = u8;
      type BYTE = u8;
      type LONG = i32; // signed

      ///Size: First 64 bytes of valid PE file
      #[derive(PartialEq, Debug)]
      struct IMAGE_DOS_HEADER
      {
      e_magic: WORD,
      e_cblp: WORD,
      e_cp: WORD,
      e_crlc: WORD,
      e_cparhdr: WORD,
      e_minalloc: WORD,
      e_maxalloc: WORD,
      e_ss: WORD,
      e_sp: WORD,
      e_csum: WORD,
      e_ip: WORD,
      e_cs: WORD,
      e_lfarlc: WORD,
      e_ovno: WORD,
      e_res: [WORD; 4],
      e_oemid: WORD,
      e_oeminfo: WORD,
      e_res2: [WORD; 10],
      e_lfanew: LONG
      }

      impl IMAGE_DOS_HEADER
      {
      fn new<T>(br: T)
      where T: BufRead
      {

      }
      fn printf(&self)
      {
      println!("struct IMAGE_DOS_HEADER");
      println!("te_magic: ");
      parse_bytes::print_word(self.e_magic);

      println!("te_cblp: {:X}", self.e_cblp);
      println!("te_cblp: {:X}", self.e_cblp);
      println!("te_cp: {:X}", self.e_cp);
      println!("te_crlc: {:X}", self.e_crlc);
      println!("te_cparhdr: {:X}", self.e_cparhdr);
      println!("te_minalloc: {:X}", self.e_minalloc);
      println!("te_maxalloc: {:X}", self.e_maxalloc);
      println!("te_ss: {:X}", self.e_ss);
      println!("te_sp: {:X}", self.e_sp);
      println!("te_csum: {:X}", self.e_csum);
      println!("te_ip: {:X}", self.e_ip);
      println!("te_cs: {:X}", self.e_cs);
      println!("te_lfarlc: {:X}", self.e_lfarlc);
      println!("te_ovno: {:X}", self.e_ovno);
      println!("te_res: ");
      for b in self.e_res.iter()
      {
      print!("{:X}", b);
      }
      println!("te_oemid: {:X}", self.e_oemid);
      println!("te_oeminfo: {:X}", self.e_oeminfo);
      println!("te_res2: ");
      for b in self.e_res2.iter()
      {
      print!("{:X}", b);
      }
      println!("te_lfanew: {:X}", self.e_lfanew);



      }

      }

      impl Display for IMAGE_DOS_HEADER
      {
      fn fmt(&self, f: &mut Formatter) -> Result
      {
      write!(f, "e_magic: {:X}n
      e_cblp: {:X}n", self.e_magic, self.e_cblp)

      }
      }

      impl<'a> From<&'a Vec<u8>> for IMAGE_DOS_HEADER
      {
      fn from(f: &'a Vec<u8>) -> Self
      {
      use std::io::Cursor;
      let mut buf = Cursor::new(f);
      //Not a fan of this below:
      let e_magic = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_cblp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_cp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_crlc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_cparhdr = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_minalloc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_maxalloc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_ss = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_sp = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_csum = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_ip = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_cs = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_lfarlc = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_ovno = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_res = parse_bytes::read_n(&mut buf, std::mem::size_of::<[WORD; 4]>());
      let e_oemid = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_oeminfo = parse_bytes::read_n(&mut buf, std::mem::size_of::<WORD>());
      let e_res2 = parse_bytes::read_n(&mut buf, std::mem::size_of::<[WORD; 10]>());
      let e_lfanew = parse_bytes::read_n(&mut buf, std::mem::size_of::<LONG>());

      IMAGE_DOS_HEADER
      {
      e_magic:
      {
      let v = e_magic.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16

      },

      e_cblp:
      {
      let v = e_cblp.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16

      },
      e_cp:
      {
      let v = e_cp.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16

      },
      e_crlc:
      {
      let v = e_crlc.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_cparhdr:
      {

      let v = e_cparhdr.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_minalloc:
      {

      let v = e_minalloc.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_maxalloc:
      {

      let v = e_maxalloc.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_ss:
      {

      let v = e_ss.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_sp:
      {

      let v = e_sp.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_csum:
      {

      let v = e_csum.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_ip:
      {

      let v = e_ip.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_cs:
      {

      let v = e_cs.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_lfarlc:
      {

      let v = e_lfarlc.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_ovno:
      {

      let v = e_ovno.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_res:
      {

      let v = e_res.unwrap();
      let mut four_w: [WORD; 4]= [0; 4];
      four_w[0] = ((v[0] as u16) << 8) | v[1] as u16;
      four_w[1] = ((v[2] as u16) << 8) | v[3] as u16;
      four_w[2] = ((v[4] as u16) << 8) | v[5] as u16;
      four_w[3] = ((v[6] as u16) << 8) | v[7] as u16;
      four_w
      },
      e_oemid:
      {

      let v = e_oemid.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_oeminfo:
      {

      let v = e_oeminfo.unwrap();

      ((v[0] as u16) << 8) | v[1] as u16
      },
      e_res2:
      {

      let v = e_res2.unwrap();

      let mut ten_w: [WORD;10]= [0; 10];
      ten_w[0] = ((v[0] as u16) << 8) | v[1] as u16;
      ten_w[1] = ((v[2] as u16) << 8) | v[3] as u16;
      ten_w[2] = ((v[4] as u16) << 8) | v[5] as u16;
      ten_w[3] = ((v[6] as u16) << 8) | v[7] as u16;
      ten_w[4] = ((v[8] as u16) << 8) | v[9] as u16;
      ten_w[5] = ((v[10] as u16) << 8) | v[11] as u16;
      ten_w[6] = ((v[12] as u16) << 8) | v[13] as u16;
      ten_w[7] = ((v[14] as u16) << 8) | v[15] as u16;
      ten_w[8] = ((v[16] as u16) << 8) | v[17] as u16;
      ten_w[9] = ((v[18] as u16) << 8) | v[19] as u16;
      ten_w
      },
      e_lfanew:
      {
      let v = e_lfanew.unwrap();

      let temp: i32 = (v[0] as i32)<< 24 as i32;
      let temp2: i32 = (v[1] as i32)<< 16 as i32;
      let temp3: i32 = (v[2] as i32)<< 8 as i32;
      let result = temp | temp2 | temp3 | v[3] as i32;
      result
      }
      }
      }
      }



      mod parse_bytes
      {
      use std::io::Read;
      use std::io::BufRead;
      pub fn read_n<T>(br: &mut T, num_bytes: usize) -> Result<Vec<u8>, ::std::io::Error>
      where T: BufRead
      {
      let mut buf = vec![0u8; num_bytes];
      let result = br.read_exact(&mut buf);
      match result
      {
      Ok(r) => return Ok(buf.to_vec()),
      Err(e) => return Err(e)
      }


      }

      pub fn u8_to_char(u: u8) -> char
      {
      u as char
      }

      pub fn print_word(w: u16)
      {
      let b1 = (w >> 8) as u8; // Grab high aka "first" byte
      let b2 = w as u8; // Grab low aka "second" byte (right)
      print!("{}{}", u8_to_char(b1), u8_to_char(b2));
      }

      pub fn be_to_le(be: &mut [u8]) -> Vec<u8>
      {
      let mut be2: Vec<u8> = vec!;
      for i in be.len()..0
      {
      be2.push(be[i]);
      }
      be2
      }

      pub fn print_byte_vec_as_chars(bvec: &[u8])
      {
      for b in bvec.iter()
      {
      print!("{}", u8_to_char(*b));
      }
      }
      }






      parsing rust file-structure






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 18 at 22:23









      200_success

      127k15148411




      127k15148411










      asked Nov 18 at 20:18









      the_endian

      381111




      381111



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207938%2fdos-header-parser-in-rust%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207938%2fdos-header-parser-in-rust%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Сан-Квентин

          Алькесар

          Josef Freinademetz