Newer
Older
ddhx / src / searcher.d
@dd86k dd86k on 11 Aug 2020 3 KB Fixes
/**
 * Search module.
 */
module searcher;

import std.stdio;
import std.encoding : transcode;
import ddhx;
import utils : unformat;
import utils;

/// File search chunk buffer size
private enum CHUNK_SIZE = 4096;

private struct search_t {
	union {
		ubyte[2] a16;
		short i16;
		ubyte[4] a32;
		int i32;
		ubyte[8] a64;
		long i64;
	}
}

/**
 * Search an UTF-8/ASCII string
 * Params: s = string
 */
void search_utf8(const char[] s) {
	search_arr(cast(ubyte[])s, "string");
}

/**
 * Search an UTF-16 string
 * Params:
 *   s = string
 */
void search_utf16(const char[] s) {
	wstring ws;
	transcode(s, ws);
	ubyte[1024] buf = void;
	wchar* p = cast(wchar*)buf;
	size_t l;
	foreach (const wchar c; ws) {
		p[l++] = c;
	}
	search_arr(buf[0..l], "wstring");
}

/**
 * Search an UTF-32 string
 * Params:
 *   s = string
 */
void search_utf32(const char[] s) {
	dstring ds;
	transcode(s, ds);
	ubyte[1024] buf = void;
	dchar* p = cast(dchar*)buf;
	size_t l;
	foreach (const dchar c; ds) {
		p[l++] = c;
	}
	search_arr(buf[0..l], "dstring");
}

/**
 * Search a byte
 * Params: b = ubyte
 */
void search_u8(const ubyte b) {
	ddhx_msglow("Searching byte...");
	ubyte[1] a = void;
	a[0] = b;
	search_arr(a, "byte");
}

/**
 * Search for a 16-bit value.
 * Params:
 *   input = Input
 *   invert = Invert endianness
 */
void search_u16(string input, bool invert = false) {
	long l = void;
	if (unformat(input, l) == false) {
		ddhx_msglow("Could not parse number");
		return;
	}
	search_t s = void;
	s.i32 = invert ? bswap16(cast(short)l) : cast(short)l;
	search_arr(s.a16, "u16");
}

/**
 * Search for a 32-bit value.
 * Params:
 *   input = Input
 *   invert = Invert endianness
 */
void search_u32(string input, bool invert = false) {
	long l = void;
	if (unformat(input, l) == false) {
		ddhx_msglow("Could not parse number");
		return;
	}
	search_t s = void;
	s.i32 = invert ? bswap32(cast(int)l) : cast(int)l;
	search_arr(s.a32, "u32");
}

/**
 * Search for a 64-bit value.
 * Params:
 *   input = Input
 *   invert = Invert endianness
 */
void search_u64(string input, bool invert = false) {
	long l = void;
	if (unformat(input, l) == false) {
		ddhx_msglow("Could not parse number");
		return;
	}
	search_t s = void;
	s.i64 = invert ? bswap64(l) : l;
	search_arr(s.a64, "u64");
}

private void search_arr(ubyte[] data, string type) {
	ddhx_msglow(" Searching %s...", type);
	const ubyte firstbyte = data[0];
	const size_t datalen = data.length;
	size_t pos = cast(size_t)fpos + 1; // do not affect file position itself
	size_t posmax = pos + CHUNK_SIZE;

	ubyte[] buf = void;
	outer: do {
		buf = cast(ubyte[])CFile[pos..posmax];
		const size_t buflen = buf.length;
		for (size_t i; i < buflen; ++i) {
			if (buf[i] != firstbyte) continue;

			const size_t ilen = i + datalen;
			if (ilen < buflen) { // Within CHUNK
				if (buf[i..i + datalen] == data) {
S_FOUND:
					ddhx_seek(pos + i);
					return;
				}
			} else if (ilen < fsize) { // Out-of-chunk
				if (cast(ubyte[])CFile[i..i+datalen] == data) {
					goto S_FOUND;
				}
			} else break outer;
		}

		pos = posmax; posmax += CHUNK_SIZE;
	} while (pos < fsize);
	ddhx_msglow(" Not found (%s)", type);
}