#include "MemoryUtils.h"

auto Utils::Memory::getHandle() -> HANDLE {
    static HANDLE handle = GetModuleHandleA(_("Minecraft.Windows.exe"));
    return handle;
}

auto Utils::Memory::FindPattern(const char* sig) -> void* {
    const char* pattern = sig;
    uintptr_t first_match = 0;
    static MODULEINFO mi_mod_info;
    static bool init = false;
    HANDLE handle = getHandle();
    if (!init) {
        init = true;
        GetModuleInformation(GetCurrentProcess(), reinterpret_cast<HMODULE>((uintptr_t)handle), &mi_mod_info, sizeof(MODULEINFO));
    }

    static const uintptr_t range_end = (uintptr_t)handle + mi_mod_info.SizeOfImage;

    // マクロ展開した部分
    const char* old_pat = pattern;
    unsigned char pat_byte = (
        (((
            ((pattern[0] & (~0x20)) >= 'A' && (pattern[0] & (~0x20)) <= 'F') ?
            ((pattern[0] & (~0x20)) - 'A' + 0xa) :
            ((pattern[0] >= '0' && pattern[0] <= '9') ? (pattern[0] - '0') : 0)
            ) << 4)) |
        (
            ((pattern[1] & (~0x20)) >= 'A' && (pattern[1] & (~0x20)) <= 'F') ?
            ((pattern[1] & (~0x20)) - 'A' + 0xa) :
            ((pattern[1] >= '0' && pattern[1] <= '9') ? (pattern[1] - '0') : 0)
            )
        );

    for (uintptr_t p_cur = (uintptr_t)handle + 0x100000; p_cur < range_end; p_cur++) {
        if (!*pattern) {
            return reinterpret_cast<void*>(first_match);
        }

        while (*(PBYTE)pattern == ' ') {
            pattern++;
        }

        if (!*pattern) {
            return reinterpret_cast<void*>(first_match);
        }

        if (old_pat != pattern) {
            old_pat = pattern;
            if (*(PBYTE)pattern != '\?') {
                pat_byte = (
                    (((
                        ((pattern[0] & (~0x20)) >= 'A' && (pattern[0] & (~0x20)) <= 'F') ?
                        ((pattern[0] & (~0x20)) - 'A' + 0xa) :
                        ((pattern[0] >= '0' && pattern[0] <= '9') ? (pattern[0] - '0') : 0)
                        ) << 4)) |
                    (
                        ((pattern[1] & (~0x20)) >= 'A' && (pattern[1] & (~0x20)) <= 'F') ?
                        ((pattern[1] & (~0x20)) - 'A' + 0xa) :
                        ((pattern[1] >= '0' && pattern[1] <= '9') ? (pattern[1] - '0') : 0)
                        )
                    );
            }
        }

        if (*(PBYTE)pattern == '\?' || *(BYTE*)p_cur == pat_byte) {
            if (!first_match) {
                first_match = p_cur;
            }

            if (!pattern[2]) {
                return reinterpret_cast<void*>(first_match);
            }

            pattern += 2;
        }
        else {
            pattern = sig;
            first_match = 0;
        }
    }

    return 0;
}
