summaryrefslogtreecommitdiff
path: root/scripts/src/libs/buffer.rs
blob: b4cee7774f74c679df391a40322a7e134260c1dc (plain)
use wasmtime::Caller;

use crate::{ScriptManager, WasmScriptState};

use super::{system::_get_memory, LIBRARY_NAME};

fn memory_search(mut caller: Caller<'_, WasmScriptState>, ptr: u32, ch: u32, len: u32) -> u32 {
	let (_, mem_ptr) = _get_memory(&mut caller);
	let len = len as usize;
	let ptr = ptr as usize;
	let ch = ch as u8;
	if (len + ptr) > mem_ptr.len() {
		return 4;
	}

	for i in 0..len {
		if mem_ptr[ptr + i] == ch {
			return (ptr + i) as u32;
		}
	}

	0
}

fn memory_search_last(mut caller: Caller<'_, WasmScriptState>, ptr: u32, ch: u32, len: u32) -> u32 {
	let (_, mem_ptr) = _get_memory(&mut caller);
	let len = len as usize;
	let ptr = ptr as usize;
	let ch = ch as u8;
	if (len + ptr) > mem_ptr.len() {
		return 4;
	}

	for i in 0..len {
		let index = ptr + len - i - 1;
		if mem_ptr[index] == ch {
			return index as u32;
		}
	}

	0
}

fn memory_compare(
	mut caller: Caller<'_, WasmScriptState>,
	lhs: u32,
	rhs: u32,
	len: u32,
) -> (u32, u32) {
	let (_, mem_ptr) = _get_memory(&mut caller);
	let len = len as usize;
	let lhs = lhs as usize;
	let rhs = rhs as usize;
	if (len + lhs) > mem_ptr.len() || (len + rhs) > mem_ptr.len() {
		return (4, 0);
	}

	for i in 0..len {
		let diff = mem_ptr[lhs + i] - mem_ptr[rhs + i];
		if diff != 0 {
			return (0, diff as u32);
		}
	}

	(0, 0)
}

fn memory_fill(mut caller: Caller<'_, WasmScriptState>, dest: u32, ch: u32, len: u32) -> u32 {
	let (_, mem_ptr) = _get_memory(&mut caller);
	let len = len as usize;
	let dest = dest as usize;
	let ch = ch as u8;

	if (len + dest) > mem_ptr.len() {
		return 4;
	}

	for i in 0..len {
		mem_ptr[dest + i] = ch;
	}

	0
}

fn memory_copy(mut caller: Caller<'_, WasmScriptState>, dest: u32, src: u32, len: u32) -> u32 {
	let (_, mem_ptr) = _get_memory(&mut caller);
	let len = len as usize;
	let dest = dest as usize;
	let src = src as usize;
	if (len + dest) > mem_ptr.len() || (len + src) > mem_ptr.len() {
		return 4;
	}

	// check for overlap
	if (dest < src && dest + len > src) || (src < dest && src + len > dest) {
		let src = mem_ptr[src..src + len].to_vec();
		let dest = &mut mem_ptr[dest..dest + len];
		dest.clone_from_slice(&src);
	} else {
		for i in 0..len {
			mem_ptr[dest + i] = mem_ptr[src + i];
		}
	}

	0
}

fn memory_copy_until(
	mut caller: Caller<'_, WasmScriptState>,
	dest: u32,
	src: u32,
	len: u32,
	delimiter: u32,
) -> u32 {
	let (_, mem_ptr) = _get_memory(&mut caller);
	let len = len as usize;
	let dest = dest as usize;
	let src = src as usize;
	let delimiter = delimiter as u8;
	if (len + dest) > mem_ptr.len() || (len + src) > mem_ptr.len() {
		return 4;
	}

	// check for overlap
	if (dest < src && dest + len > src) || (src < dest && src + len > dest) {
		let cloned_src = mem_ptr[src..src + len].to_vec();
		let dest = &mut mem_ptr[dest..dest + len];
		for i in 0..len {
			let ch = cloned_src[i];
			dest[i] = ch;
			if ch == delimiter {
				return (src + i + 1) as u32;
			}
		}
	} else {
		for i in 0..len {
			let ch = mem_ptr[src + i];
			mem_ptr[dest + i] = ch;
			if ch == delimiter {
				return (src + i + 1) as u32;
			}
		}
	}

	0
}

fn memory_concatenate(
	mut caller: Caller<'_, WasmScriptState>,
	dest: u32,
	src: u32,
	dest_len: u32,
	src_len: u32,
) -> u32 {
	let (_, mem_ptr) = _get_memory(&mut caller);
	let dest = dest as usize;
	let src = src as usize;
	let dest_len = dest_len as usize;
	let src_len = src_len as usize;
	if (dest_len + src_len + dest) > mem_ptr.len() || (src_len + src) > mem_ptr.len() {
		return 4;
	}

	let src = mem_ptr[src..src + src_len].to_vec();
	let dest_offset = dest + dest_len;
	let dest = &mut mem_ptr[dest_offset..dest_offset + src_len];
	dest.clone_from_slice(&src);

	0
}

pub fn library(manager: &mut ScriptManager) -> Option<()> {
	manager.add_library_function(LIBRARY_NAME, "memchr", memory_search)?;
	manager.add_library_function(LIBRARY_NAME, "memrchr", memory_search_last)?;
	manager.add_library_function(LIBRARY_NAME, "memcmp", memory_compare)?;
	manager.add_library_function(LIBRARY_NAME, "memset", memory_fill)?;
	manager.add_library_function(LIBRARY_NAME, "memcpy", memory_copy)?;
	manager.add_library_function(LIBRARY_NAME, "memccpy", memory_copy_until)?;
	manager.add_library_function(LIBRARY_NAME, "memcat", memory_concatenate)?;

	Some(())
}