Newer
Older
ddhx / src / Searcher.d
/**
 * Search module.
 */
module searcher;

import std.stdio;
import core.stdc.string : memcpy;
import std.encoding : transcode;
import ddhx;
import utils : unformat;
import std.range : chunks;
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
 *   invert = Invert endianness
 */
void search_utf16(const char[] s, bool invert = false) {
	//TODO: See if we can use proper UTF-16 conversion
	wstring ws;
	transcode(s, ws);
	size_t l;
	wchar* wp = cast(wchar*)ws;
	while (*wp != 0xFFFF) { ++wp; ++l; }
	l *= 2;
	ubyte[] buf = new ubyte[l];
	memcpy(cast(byte*)buf, cast(byte*)ws, l);
	//TODO: invert
	search_arr(buf, "wstring");
}

/**
 * Search an UTF-32 string
 * Params:
 *   s = string
 *   invert = Invert endianness
 */
void search_utf32(const char[] s, bool invert = false) {
	//TODO: See if we can use proper UTF-32 conversion
	dstring ds;
	transcode(s, ds);
	size_t l;
	wchar* dp = cast(wchar*)ds;
	while (*dp != 0xFFFF) { ++dp; ++l; }
	l *= 4;
	ubyte[] buf = new ubyte[l];
	memcpy(cast(byte*)buf, cast(byte*)ds, l);
	//TODO: invert
	search_arr(buf, "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)) {
		const ushort u16 = invert ? bswap16(cast(ushort)l) : cast(ushort)l;
		ubyte[2] la = void;
		*(cast(ushort*)la) = u16;
		search_arr(la, "u16");
	} else
		msgalt("Could not parse number");
}

/**
 * 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)) {
		const uint u32 = invert ? bswap32(cast(uint)l) : cast(uint)l;
		ubyte[4] la = void;
		*(cast(uint*)la) = u32;
		search_arr(la, "u32");
	} else
		msgalt("Could not parse number");
}

/**
 * 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)) {
		if (invert) l = bswap64(l);
		ubyte[8] la = void;
		*(cast(long*)la) = l;
		search_arr(la, "u64");
	} else
		msgalt("Could not parse number");
}

private void search_arr(ubyte[] data, string type) {
	msgalt(" Searching %s", type);
	const ubyte firstbyte = data[0];
	const size_t datal = data.length;
	long pos = fpos + 1; // To not affect file position itself

	outer: foreach (const ubyte[] buf; (cast(ubyte[])MMFile[]).chunks(CHUNK_SIZE)) {
		const size_t bufl = buf.length;
		inner: for (size_t i; i < bufl; ++i) {
			if (buf[i] != firstbyte) break inner;

			const size_t ilen = i + datal;
			if (ilen < bufl) { // Within CHUNK
				if (buf[i..i+datal] == data) {
					hxgoto_c(pos + i);
					return;
				}
			} else if (ilen < fsize) { // Out-of-chunk
			//TODO:
				/*CurrentFile.seek(pos + i);
				if (CurrentFile.byChunk(len).front == input) {
					goto S_FOUND;
				}*/
			} else
				break outer; // EOF otherwise, can't continue
		}
		pos += CHUNK_SIZE;
	}
	msgalt(" Not found (%s)", type);
}