smart-patcher 0.7.0

Patcher based on rules
Documentation
use anyhow::bail;
use mlua::{Function, Lua, Table};
use std::env;
use std::path::Path;

pub fn find_by(
  patch_dir: &Path,
  path: &Path,
  content: &str,
  start_pos: Option<usize>,
  end_pos: Option<usize>,
) -> anyhow::Result<(usize, usize, bool)> {
  let patch_path = patch_dir.to_path_buf().join(path);

  if !patch_path.is_file() {
    bail!("Lua script path ({:?}) has to be a file.", patch_path)
  }
  let module_name = patch_path.file_stem().unwrap();
  let mut root_dir = patch_path.canonicalize()?;
  root_dir.pop();

  let rev = env::current_dir()?;
  env::set_current_dir(patch_dir)?;

  let lua = Lua::new();

  let package = lua.globals().get::<Table>("package")?;
  let mut path_str = package.get::<String>("path")?;
  path_str.push_str(&format!(";{}/?.lua", root_dir.display()));
  package.set("path", path_str)?;

  let module: Table = lua
    .load(format!("return require('{}')", module_name.to_string_lossy()))
    .eval()?;
  let find_fn: Function = module.get("find")?;

  let result: (usize, usize, bool) = find_fn.call((content, start_pos, end_pos))?;

  env::set_current_dir(rev)?;

  Ok(result)
}

pub fn replace_by(patch_dir: &Path, path: &Path, content: &str) -> anyhow::Result<String> {
  let patch_path = patch_dir.to_path_buf().join(path);

  if !patch_path.is_file() {
    bail!("Lua script path ({:?}) has to be a file.", patch_path)
  }
  let module_name = patch_path.file_stem().unwrap();
  let mut root_dir = patch_path.canonicalize()?;
  root_dir.pop();

  let rev = env::current_dir()?;
  env::set_current_dir(patch_dir)?;

  let lua = Lua::new();

  let package = lua.globals().get::<Table>("package")?;
  let mut path_str = package.get::<String>("path")?;
  path_str.push_str(&format!(";{}/?.lua", root_dir.display()));
  package.set("path", path_str)?;

  let module: Table = lua
    .load(format!("return require('{}')", module_name.to_string_lossy()))
    .eval()?;
  let find_fn: Function = module.get("replace")?;

  let result: String = find_fn.call(content)?;

  env::set_current_dir(rev)?;

  Ok(result)
}

pub fn decode_by(patch_dir: &Path, path: &Path, content: &[u8]) -> anyhow::Result<String> {
  let patch_path = patch_dir.to_path_buf().join(path);

  if !patch_path.is_file() {
    bail!("Lua script path ({:?}) has to be a file.", patch_path)
  }
  let module_name = patch_path.file_stem().unwrap();
  let mut root_dir = patch_path.canonicalize()?;
  root_dir.pop();

  let rev = env::current_dir()?;
  env::set_current_dir(patch_dir)?;

  let lua = Lua::new();

  let package = lua.globals().get::<Table>("package")?;
  let mut path_str = package.get::<String>("path")?;
  path_str.push_str(&format!(";{}/?.lua", root_dir.display()));
  package.set("path", path_str)?;

  let module: Table = lua
    .load(format!("return require('{}')", module_name.to_string_lossy()))
    .eval()?;
  let find_fn: Function = module.get("decode")?;

  let result: String = find_fn.call(content)?;

  env::set_current_dir(rev)?;

  Ok(result)
}

pub fn encode_by(patch_dir: &Path, path: &Path, content: &str) -> anyhow::Result<Vec<u8>> {
  let patch_path = patch_dir.to_path_buf().join(path);

  if !patch_path.is_file() {
    bail!("Lua script path ({:?}) has to be a file.", patch_path)
  }
  let module_name = patch_path.file_stem().unwrap();
  let mut root_dir = patch_path.canonicalize()?;
  root_dir.pop();

  let rev = env::current_dir()?;
  env::set_current_dir(patch_dir)?;

  let lua = Lua::new();

  let package = lua.globals().get::<Table>("package")?;
  let mut path_str = package.get::<String>("path")?;
  path_str.push_str(&format!(";{}/?.lua", root_dir.display()));
  package.set("path", path_str)?;

  let module: Table = lua
    .load(format!("return require('{}')", module_name.to_string_lossy()))
    .eval()?;
  let find_fn: Function = module.get("encode")?;

  let result: Vec<u8> = find_fn.call(content)?;

  env::set_current_dir(rev)?;

  Ok(result)
}