Newer
Older
ddhx / src / searcher.d
/**
 * 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;

/**
 * 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) {
	msgalt("Searching byte...");
	ubyte[1] a = [ b ];
	search_arr(a, "byte");
	msgalt("Byte not found");
}

/**
 * Search for a 16-bit value.
 * Params:
 *   s = Input
 *   invert = Invert endianness
 */
void search_u16(string s, bool invert = false) {
	long l = void;
	if (unformat(s, l) == false) {
		msgalt("Could not parse number");
		return;
	}
	const ushort u16 = invert ? bswap16(cast(ushort)l) : cast(ushort)l;
	ubyte[2] la = void;
	*(cast(ushort*)la) = u16;
	search_arr(la, "u16");
}

/**
 * Search for a 32-bit value.
 * Params:
 *   s = Input
 *   invert = Invert endianness
 */
void search_u32(string s, bool invert = false) {
	long l = void;
	if (unformat(s, l) == false) {
		msgalt("Could not parse number");
		return;
	}
	const uint u32 = invert ? bswap32(cast(uint)l) : cast(uint)l;
	ubyte[4] la = void;
	*(cast(uint*)la) = u32;
	search_arr(la, "u32");
}

/**
 * Search for a 64-bit value.
 * Params:
 *   s = Input
 *   invert = Invert endianness
 */
void search_u64(string s, bool invert = false) {
	long l = void;
	if (unformat(s, l) == false) {
		msgalt("Could not parse number");
		return;
	}
	if (invert) l = bswap64(l);
	ubyte[8] la = void;
	*(cast(long*)la) = l;
	search_arr(la, "u64");
}

private void search_arr(ubyte[] data, string type) {
	msgalt(" 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:
					hxgoto_c(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);
	msgalt(" Not found (%s)", type);
}