extern crate binnpatch;
extern crate data_encoding;
extern crate memmap;

extern crate binnpatch_macro;

use memmap::{Mmap, MmapMut};
use std::fs;
use std::fs::{File, OpenOptions};
use std::ops::{Deref, DerefMut};

use binnpatch::{ApplyPatch, BytesPattern, FindPattern};
use binnpatch_macro::{binnpats, binnvecs};

fn main() {
    let src_file = "Some.dll";
    let dst_file = "Some.dll.patched";
    let pattern =
        binnpats!("40 3E 1D ?? ?? 12 1C 7C 48 ?? 73 6F 02 22 ?? 61 19 4E 13 60 48 45 19 27 5B");
    let replacement =
        binnvecs!("06 5A 18 74 2D 62 12 6A 13 4A 2B 0E 6F 0F 36 7A 28 0A 37 67 0A 4B 01 73 14");

    let file = File::open(src_file).expect("src open");

    let src_map = unsafe { Mmap::map(&file) }.expect("src map");
    let data_src = src_map.deref();

    let offset = data_src.find_pattern_first(&pattern);
    if 0 == offset {
        panic!("src pattern not found");
    }
    println!("found at {:#010X}", offset);

    if replacement.len() > data_src.len() - offset {
        panic!("replace overflow");
    }

    drop(src_map);
    drop(file);

    fs::copy(src_file, dst_file).expect("file copy");

    let file = OpenOptions::new()
        .read(true)
        .write(true)
        .open(dst_file)
        .expect("dst open");
    let mut dst_map = unsafe { MmapMut::map_mut(&file) }.expect("dst map");
    let mut data_dst = dst_map.deref_mut();

    data_dst.apply_patch(offset, &replacement);
    drop(dst_map);

    println!("done");
}