/**************************************************************************** * * * Project64 - A Nintendo 64 emulator. * * http://www.pj64-emu.com/ * * Copyright (C) 2012 Project64. All rights reserved. * * * * License: * * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ #include "stdafx.h" #include "MemoryScanner.h" CMixed::TypeNameEntry CMixed::TypeNames[] = { { "uint8", ValueType_uint8 }, { "int8", ValueType_int8 }, { "uint16", ValueType_uint16 }, { "int16", ValueType_int16 }, { "uint32", ValueType_uint32 }, { "int32", ValueType_int32 }, { "uint64", ValueType_uint64 }, { "int64", ValueType_int64 }, { "float", ValueType_float }, { "double", ValueType_double }, { "char", ValueType_string }, { "char", ValueType_unkstring }, { "char", ValueType_unkstring }, { NULL, ValueType_invalid} }; const char* CMixed::GetTypeName(void) { switch (m_Type) { case ValueType_uint8: return "uint8"; case ValueType_int8: return "int8"; case ValueType_uint16: return "uint16"; case ValueType_int16: return "int16"; case ValueType_uint32: return "uint32"; case ValueType_int32: return "int32"; case ValueType_uint64: return "uint64"; case ValueType_int64: return "int64"; case ValueType_float: return "float"; case ValueType_double: return "double"; case ValueType_string: case ValueType_istring: case ValueType_unkstring: return "char"; } return NULL; } ValueType CMixed::GetTypeFromString(const char* name, int* charArrayLength) { for (int i = 0; TypeNames[i].name != NULL; i++) { if (strcmp(name, TypeNames[i].name) == 0) { *charArrayLength = 0; return TypeNames[i].type; } } if (sscanf(name, "char[%d]", charArrayLength) != 0) { return ValueType_string; } return ValueType_invalid; } int CMixed::GetTypeSize(void) { switch (m_Type) { case ValueType_uint8: return sizeof(uint8_t); case ValueType_int8: return sizeof(int8_t); case ValueType_uint16: return sizeof(uint16_t); case ValueType_int16: return sizeof(int16_t); case ValueType_uint32: return sizeof(uint32_t); case ValueType_int32: return sizeof(int32_t); case ValueType_uint64: return sizeof(uint64_t); case ValueType_int64: return sizeof(int64_t); case ValueType_float: return sizeof(float); case ValueType_double: return sizeof(double); case ValueType_string: case ValueType_istring: case ValueType_unkstring: return m_StrLength; default: return 0; } } bool CMixed::IsStringType(void) { switch (m_Type) { case ValueType_string: case ValueType_istring: case ValueType_unkstring: return true; } return false; } int CMixed::ToString(char* buffer, bool bHex, size_t size) { if (bHex) { switch (m_Type) { case ValueType_uint8: case ValueType_int8: return snprintf(buffer, size, "0x%02X", m_Value._uint8); case ValueType_uint16: case ValueType_int16: return snprintf(buffer, size, "0x%04X", m_Value._uint16); case ValueType_uint32: case ValueType_int32: case ValueType_float: return snprintf(buffer, size, "0x%08X", m_Value._uint32); case ValueType_uint64: case ValueType_int64: case ValueType_double: return snprintf(buffer, size, "0x%016llX", m_Value._uint64); default: return snprintf(buffer, size, "?"); } } switch (m_Type) { case ValueType_uint8: return snprintf(buffer, size, "%d", m_Value._uint8); case ValueType_int8: return snprintf(buffer, size, "%d", m_Value._sint8); case ValueType_uint16: return snprintf(buffer, size, "%d", m_Value._uint16); case ValueType_int16: return snprintf(buffer, size, "%d", m_Value._sint16); case ValueType_uint32: return snprintf(buffer, size, "%lu", m_Value._uint32); case ValueType_int32: return snprintf(buffer, size, "%d", m_Value._sint32); case ValueType_uint64: return snprintf(buffer, size, "%llu", m_Value._uint64); case ValueType_int64: return snprintf(buffer, size, "%lld", m_Value._sint64); case ValueType_float: return snprintf(buffer, size, "%f", m_Value._float); case ValueType_double: return snprintf(buffer, size, "%f", m_Value._double); default: return snprintf(buffer, size, "?"); } } CScanResult::CScanResult(AddressType addressType, DisplayFormat displayFormat) : m_AddressType(addressType), m_Address(0), m_DisplayFormat(displayFormat), m_bSelected(false), m_Description(NULL) { } CScanResult::~CScanResult(void) { } void CScanResult::SetDescription(char* str) { if (m_Description != NULL) { free(m_Description); } size_t len = strlen(str); m_Description = (char*)malloc(len + 1); strcpy(m_Description, str); m_Description[len] = '\0'; } void CScanResult::DeleteDescription(void) { if (m_Description != NULL) { free(m_Description); m_Description = NULL; } } const char* CScanResult::GetDescription(void) { if (m_Description == NULL) { return ""; } return m_Description; } int CScanResult::GetValueString(char *buffer, size_t size) { bool bHex = (m_DisplayFormat == DisplayHex); return ToString(buffer, bHex, size); } bool CScanResult::GetMemoryValue(CMixed* v) { if (g_MMU == NULL) { return false; } uint32_t paddr = m_Address & 0x1FFFFFFF; if (!CMemoryScanner::PAddrValid(paddr)) { return false; } uint8_t* mem = CMemoryScanner::GetMemoryPool(paddr); uint64_t raw64 = 0; if (GetTypeSize() == 8) { raw64 = ((uint64_t)*(uint32_t*)&mem[paddr] << 32) | *(uint32_t*)&mem[paddr + 4]; } switch (m_Type) { case ValueType_uint8: v->Set(*(uint8_t*) &mem[paddr ^ 3]); break; case ValueType_int8: v->Set(*(int8_t*) &mem[paddr ^ 3]); break; case ValueType_uint16: v->Set(*(uint16_t*)&mem[paddr ^ 2]); break; case ValueType_int16: v->Set(*(int16_t*) &mem[paddr ^ 2]); break; case ValueType_uint32: v->Set(*(uint32_t*)&mem[paddr]); break; case ValueType_int32: v->Set(*(int32_t*)&mem[paddr]); break; case ValueType_uint64: v->Set(*(uint64_t*)&raw64); break; case ValueType_int64: v->Set(*(int64_t*)&raw64); break; case ValueType_float: v->Set(*(float*)&mem[paddr]); break; case ValueType_double: v->Set(*(double*)&raw64); break; default: return false; // (primitives only) } return true; } int CScanResult::GetMemoryValueString(char* buffer, size_t size) { if (g_MMU == NULL) { sprintf(buffer, "?"); return 1; } bool bHex = (m_DisplayFormat == DisplayHex); uint32_t paddr = m_Address & 0x1FFFFFFF; if (!CMemoryScanner::PAddrValid(paddr)) { return sprintf(buffer, "?"); } uint8_t* mem = CMemoryScanner::GetMemoryPool(paddr); if (m_Type == ValueType_istring || m_Type == ValueType_string || m_Type == ValueType_unkstring) { if (bHex) { char* out = buffer; for (int i = 0; i < m_StrLength; i++) { uint32_t ipaddr = (paddr + i) ^ 3; if (i != 0) out += sprintf(out, " "); out += sprintf(out, "%02X", mem[ipaddr]); } *out = '\0'; return out - buffer; } else { for (int i = 0; i < m_StrLength; i++) { uint32_t ipaddr = (paddr + i) ^ 3; buffer[i] = mem[ipaddr]; } buffer[m_StrLength] = '\0'; return m_StrLength; } } CMixed memVal; if (!GetMemoryValue(&memVal)) { return 0; } return memVal.ToString(buffer, bHex, size); } int CScanResult::GetAddressString(char *buffer) { return sprintf(buffer, "0x%08X", m_Address); } uint32_t CScanResult::GetVirtualAddress(void) { if (m_AddressType == AddressType_Virtual) { return m_Address; } else { // convert physical to virtual kseg0 return (m_Address | 0x80000000); } } bool CScanResult::SetMemoryValueFromString(char* str) { if (g_MMU == NULL) { //sprintf(buffer, "?"); return false; } bool bHex = (m_DisplayFormat == DisplayHex); uint32_t paddr = m_Address & 0x1FFFFFFF; if (!CMemoryScanner::PAddrValid(paddr)) { return false; } uint8_t* mem = CMemoryScanner::GetMemoryPool(m_Address & 0x1FFFFFFF); char* endptr; uint64_t intVal = strtoull(str, &endptr, 0); double doubleVal = strtod(str, &endptr); switch (m_Type) { case ValueType_uint8: case ValueType_int8: mem[paddr ^ 3] = intVal & 0xFF; break; case ValueType_uint16: case ValueType_int16: *(uint16_t*)&mem[paddr ^ 2] = intVal & 0xFFFF; break; case ValueType_uint32: case ValueType_int32: *(uint32_t*)&mem[paddr] = intVal & 0xFFFFFFFF; break; case ValueType_uint64: case ValueType_int64: *(uint64_t*)&mem[paddr] = (intVal << 32) | (intVal >> 32); break; case ValueType_float: if (bHex) { *(uint32_t*)&mem[paddr] = intVal & 0xFFFFFFFF; break; } *(float*)&mem[paddr] = (float)doubleVal; break; case ValueType_double: if (bHex) { *(uint64_t*)&mem[paddr] = (intVal << 32) | (intVal >> 32); break; } intVal = *(uint64_t*)&doubleVal; *(uint64_t*)&mem[paddr] = (intVal << 32) | (intVal >> 32); break; case ValueType_string: case ValueType_istring: case ValueType_unkstring: if (bHex) { int size = CMemoryScanner::ParseHexString(NULL, str); if (size == 0) { return false; } char* buff = new char[size]; CMemoryScanner::ParseHexString(buff, str); for (int i = 0; i < m_StrLength; i++) { uint32_t ipaddr = (paddr + i) ^ 3; mem[ipaddr] = buff[i]; } delete[] buff; } else { for (int i = 0; i < m_StrLength; i++) { uint32_t ipaddr = (paddr + i) ^ 3; mem[ipaddr] = str[i]; } } break; } return true; } bool CScanResult::SetAddressSafe(uint32_t address) { uint32_t ramSize = g_MMU->RdramSize(); uint32_t romSize = g_Rom->GetRomSize(); uint32_t paddrStart = address & 0x1FFFFFFF; uint32_t paddrEnd = (paddrStart + GetTypeSize()) - 1; if (m_AddressType == AddressType_Virtual) { if (!CMemoryScanner::AddrCheck(address, 0x80000000, 0xBFFFFFFF)) { return false; } } if (!CMemoryScanner::PAddrRangeValid(paddrStart, paddrEnd)) { return false; } if (!CMemoryScanner::RangeCheck(paddrStart, paddrEnd, 0x00000000, ramSize - 1) && !CMemoryScanner::RangeCheck(paddrStart, paddrEnd, 0x10000000, 0x10000000 + romSize - 1) && !CMemoryScanner::RangeCheck(paddrStart, paddrEnd, 0x04000000, 0x04001FFF)) { return false; } m_Address = address; return true; } bool CScanResult::SetStrLengthSafe(int length) { uint32_t ramSize = g_MMU->RdramSize(); uint32_t romSize = g_Rom->GetRomSize(); uint32_t paddrStart = m_Address & 0x1FFFFFFF; uint32_t paddrEnd = (paddrStart + length) - 1; if (!CMemoryScanner::RangeCheck(paddrStart, paddrEnd, 0x00000000, ramSize - 1) && !CMemoryScanner::RangeCheck(paddrStart, paddrEnd, 0x10000000, 0x10000000 + romSize - 1) && !CMemoryScanner::RangeCheck(paddrStart, paddrEnd, 0x04000000, 0x04001FFF)) { return false; } m_StrLength = length; return true; } //bool CScanResult::IsSelected(void) //{ // return m_bSelected; //} // //void CScanResult::SetSelected(bool bSelected) //{ // m_bSelected = bSelected; //} /*********************/ CMemoryScanner::CMemoryScanner(void) : m_DidFirstScan(false), m_ValueType(ValueType_uint8), m_StringValueLength(false), m_bDataTypePrimitive(true), m_SearchType(SearchType_ExactValue), m_AddressType(AddressType_Virtual), m_VAddrBits(0x80000000), m_Memory(NULL) { m_Value._uint64 = 0; SetAddressRange(0x80000000, 0x803FFFFF); } bool CMemoryScanner::RangeCheck(uint32_t addrStart, uint32_t addrEnd, uint32_t rangeStart, uint32_t rangeEnd) { return (addrStart <= addrEnd) && (addrStart >= rangeStart) && (addrEnd <= rangeEnd); } bool CMemoryScanner::AddrCheck(uint32_t addr, uint32_t rangeStart, uint32_t rangeEnd) { return (addr >= rangeStart) && (addr <= rangeEnd); } bool CMemoryScanner::PAddrValid(uint32_t physAddr) { if (g_MMU == NULL || g_Rom == NULL) { g_Notify->BreakPoint(__FILE__, __LINE__); } uint32_t ramSize = g_MMU->RdramSize(); uint32_t romSize = g_Rom->GetRomSize(); return (AddrCheck(physAddr, 0x00000000, 0x00000000 + ramSize - 1) || AddrCheck(physAddr, 0x10000000, 0x10000000 + romSize - 1) || AddrCheck(physAddr, 0x04000000, 0x04001FFF)); } bool CMemoryScanner::PAddrRangeValid(uint32_t physAddrStart, uint32_t physAddrEnd) { return (RangeCheck(physAddrStart, physAddrEnd, 0x00000000, g_MMU->RdramSize()) || RangeCheck(physAddrStart, physAddrEnd, 0x04000000, 0x04001FFF) || RangeCheck(physAddrStart, physAddrEnd, 0x10000000, 0x15FFFFFF)); } void CMemoryScanner::SetAddressType(AddressType addressType) { m_AddressType = addressType; } void CMemoryScanner::Reset(void) { m_DidFirstScan = false; m_ValueType = ValueType_uint8; m_SearchType = SearchType_ExactValue; m_Results.clear(); } bool CMemoryScanner::SetAddressRange(uint32_t startAddress, uint32_t endAddress) { if(m_DidFirstScan) { return false; } if (m_AddressType == AddressType_Virtual) { m_VAddrBits = startAddress & 0xE0000000; // don't allow TLB if (!RangeCheck(startAddress, endAddress, 0x80000000, 0xBFFFFFFF)) { return false; } // use physical addresses internally startAddress = startAddress & 0x1FFFFFFF; endAddress = endAddress & 0x1FFFFFFF; } else { m_VAddrBits = 0; } if (RangeCheck(startAddress, endAddress, 0x00000000, 0x007FFFFF)) { if (endAddress >= g_MMU->RdramSize()) { return false; } m_Memory = g_MMU->Rdram(); } else if (RangeCheck(startAddress, endAddress, 0x04000000, 0x04001FFF)) { m_Memory = g_MMU->Rdram(); } else if (RangeCheck(startAddress, endAddress, 0x10000000, 0x10FFFFFF)) { if ((endAddress - 0x10000000) >= g_Rom->GetRomSize()) { return false; } m_Memory = (g_Rom->GetRomAddress() - 0x10000000); } else { return false; // invalid range } m_Memory = GetMemoryPool(startAddress); m_RangeStartAddress = startAddress; m_RangeEndAddress = endAddress; return true; } uint8_t* CMemoryScanner::GetMemoryPool(uint32_t physAddr) { if ((physAddr >= 0x00000000 && physAddr < g_MMU->RdramSize()) || (physAddr >= 0x04000000 && physAddr <= 0x04001FFF)) { return g_MMU->Rdram(); } else if (physAddr >= 0x10000000 && physAddr <= 0x18000000) { return (g_Rom->GetRomAddress() - 0x10000000); } else { return NULL; } } bool CMemoryScanner::SetValueType(ValueType type) { if(m_DidFirstScan) { return false; } switch(type) { case ValueType_string: case ValueType_istring: case ValueType_unkstring: m_bDataTypePrimitive = false; break; default: m_bDataTypePrimitive = true; break; } m_ValueType = type; return true; } void CMemoryScanner::SetStringValueLength(int length) { m_StringValueLength = length; } bool CMemoryScanner::SetSearchType(SearchType searchType) { if(!m_bDataTypePrimitive) { return false; } switch(searchType) { case SearchType_UnknownValue: case SearchType_JalTo: if (m_DidFirstScan) { return false; } break; case SearchType_ChangedValue: case SearchType_UnchangedValue: case SearchType_IncreasedValue: case SearchType_DecreasedValue: if(!m_DidFirstScan) { return false; } break; } m_SearchType = searchType; return true; } bool CMemoryScanner::DidFirstScan(void) { return m_DidFirstScan; } size_t CMemoryScanner::GetNumResults(void) { return m_Results.size(); } CScanResult* CMemoryScanner::GetResult(size_t index) { if (index >= m_Results.size()) { return NULL; } return &m_Results[index]; } void CMemoryScanner::RemoveResult(size_t index) { if (index >= m_Results.size()) { return; } m_Results.erase(m_Results.begin() + index); } // scan for text or hex array void CMemoryScanner::FirstScanLoopString(DisplayFormat resultDisplayFormat) { int length = m_StringValueLength; uint32_t startAddr = m_RangeStartAddress; uint32_t endAddr = (m_RangeEndAddress - length) + 1; CScanResult result(m_AddressType, resultDisplayFormat); result.SetStrLength(length); for (uint32_t addr = startAddr; addr <= endAddr; addr++) { for (int i = 0; i < length; i++) { uint32_t leAddr = (addr + i) ^ 3; if (m_Value._string[i] != m_Memory[leAddr]) { goto next_addr; } } result.m_Address = addr | m_VAddrBits; result.Set((const char*)NULL); m_Results.push_back(result); next_addr:; } } // scan for text (case-insensitive) void CMemoryScanner::FirstScanLoopIString(DisplayFormat resultDisplayFormat) { int length = m_StringValueLength; uint32_t startAddr = m_RangeStartAddress; uint32_t endAddr = m_RangeEndAddress - length; CScanResult result(m_AddressType, resultDisplayFormat); result.SetStrLength(length); for (uint32_t addr = startAddr; addr <= endAddr; addr++) { for (int i = 0; i < length; i++) { uint32_t leAddr = (addr + i) ^ 3; if (toupper(m_Value._string[i]) != toupper(m_Memory[leAddr])) { goto next_addr; } } result.m_Address = addr | m_VAddrBits; result.Set((const char*)NULL); m_Results.push_back(result); next_addr:; } } // scan for text of unknown single-byte encoding void CMemoryScanner::FirstScanLoopUnkString(void) { const char *str = m_Value._string; int length = m_StringValueLength; uint32_t startAddr = m_RangeStartAddress; uint32_t endAddr = m_RangeEndAddress - length; CScanResult result(m_AddressType, DisplayHex); result.SetStrLength(length); for (uint32_t addr = startAddr; addr <= endAddr; addr++) { uint32_t leAddr = addr ^ 3; char numberDiff = 0, lowercaseDiff = 0, uppercaseDiff = 0; bool haveNumberDiff = false, haveLowercaseDiff = false, haveUppercaseDiff = false; for (int i = 0; i < length; i++) { leAddr = (addr + i) ^ 3; if (!isalnum(str[i])) { continue; } if (str[i] >= 'a' && str[i] <= 'z') { if (!haveLowercaseDiff) { lowercaseDiff = str[i] - m_Memory[leAddr]; haveLowercaseDiff = true; } else if (m_Memory[leAddr] + lowercaseDiff != str[i]) { goto next_addr; } } else if (str[i] >= 'A' && str[i] <= 'Z') { if (!haveUppercaseDiff) { uppercaseDiff = str[i] - m_Memory[leAddr]; haveUppercaseDiff = true; } else if (m_Memory[leAddr] + uppercaseDiff != str[i]) { goto next_addr; } } else if (str[i] >= '0' && str[i] <= '9') { if (!haveNumberDiff) { numberDiff = str[i] - m_Memory[leAddr]; haveNumberDiff = true; } else if (m_Memory[leAddr] + numberDiff != str[i]) { goto next_addr; } } } result.m_Address = addr | m_VAddrBits; result.Set((const char*)NULL); m_Results.push_back(result); next_addr:; } } #define _FirstScanLoopPrimitive(T, Compare, resDisplayFormat) FirstScanLoopPrimitive(Compare, resDisplayFormat) #define _FirstScanLoopPrimitive64(T, Compare, resDisplayFormat) FirstScanLoopPrimitive64(Compare, resDisplayFormat) #define FIRST_SCAN_PRIMITIVES(CompareFunc) \ switch(m_ValueType) \ { \ case ValueType_uint8: _FirstScanLoopPrimitive(uint8_t, CompareFunc, resDisplayFormat); break; \ case ValueType_int8: _FirstScanLoopPrimitive(int8_t, CompareFunc, resDisplayFormat); break; \ case ValueType_uint16: _FirstScanLoopPrimitive(uint16_t, CompareFunc, resDisplayFormat); break; \ case ValueType_int16: _FirstScanLoopPrimitive(int16_t, CompareFunc, resDisplayFormat); break; \ case ValueType_uint32: _FirstScanLoopPrimitive(uint32_t, CompareFunc, resDisplayFormat); break; \ case ValueType_int32: _FirstScanLoopPrimitive(int32_t, CompareFunc, resDisplayFormat); break; \ case ValueType_uint64: _FirstScanLoopPrimitive64(uint64_t, CompareFunc, resDisplayFormat); break; \ case ValueType_int64: _FirstScanLoopPrimitive64(int64_t, CompareFunc, resDisplayFormat); break; \ case ValueType_float: _FirstScanLoopPrimitive(float, CompareFunc, resDisplayFormat); break; \ case ValueType_double: _FirstScanLoopPrimitive64(double, CompareFunc, resDisplayFormat); break; \ } bool CMemoryScanner::FirstScan(DisplayFormat resDisplayFormat) { if (!g_MMU) { return false; } if (m_bDataTypePrimitive) { switch (m_SearchType) { case SearchType_UnknownValue: FIRST_SCAN_PRIMITIVES(NoCompare); break; case SearchType_ExactValue: FIRST_SCAN_PRIMITIVES(CompareEqual); break; case SearchType_JalTo: m_Value._uint32 = 0x0C000000 | ((m_Value._uint32 & 0x3FFFFFF) >> 2); FIRST_SCAN_PRIMITIVES(CompareEqual); break; case SearchType_LessThanValue: FIRST_SCAN_PRIMITIVES(CompareLessThan); break; case SearchType_GreaterThanValue: FIRST_SCAN_PRIMITIVES(CompareGreaterThan); break; case SearchType_LessThanOrEqualToValue: FIRST_SCAN_PRIMITIVES(CompareLessThanOrEqual); break; case SearchType_GreaterThanOrEqualToValue: FIRST_SCAN_PRIMITIVES(CompareGreaterThanOrEqual); break; } } else { switch (m_ValueType) { case ValueType_string: FirstScanLoopString(resDisplayFormat); break; case ValueType_istring: FirstScanLoopIString(resDisplayFormat); break; case ValueType_unkstring: FirstScanLoopUnkString(); break; } } m_DidFirstScan = true; return true; } #define _NextScanLoopPrimitive(T, Compare) NextScanLoopPrimitive(Compare) #define _NextScanLoopPrimitiveResults(T, Compare) NextScanLoopPrimitiveResults(Compare) #define _NextScanLoopPrimitive64(T, Compare) NextScanLoopPrimitive64(Compare) #define _NextScanLoopPrimitiveResults64(T, Compare) NextScanLoopPrimitiveResults64(Compare) // compare result's current value in memory against m_Value #define NEXT_SCAN_PRIMITIVES_AGAINST_VALUE(CompareFunc) \ switch(m_ValueType) \ { \ case ValueType_uint8: _NextScanLoopPrimitive(uint8_t, CompareFunc); break; \ case ValueType_int8: _NextScanLoopPrimitive(int8_t, CompareFunc); break; \ case ValueType_uint16: _NextScanLoopPrimitive(uint16_t, CompareFunc); break; \ case ValueType_int16: _NextScanLoopPrimitive(int16_t, CompareFunc); break; \ case ValueType_uint32: _NextScanLoopPrimitive(uint32_t, CompareFunc); break; \ case ValueType_int32: _NextScanLoopPrimitive(int32_t, CompareFunc); break; \ case ValueType_uint64: _NextScanLoopPrimitive64(uint64_t, CompareFunc); break; \ case ValueType_int64: _NextScanLoopPrimitive64(int64_t, CompareFunc); break; \ case ValueType_float: _NextScanLoopPrimitive(float, CompareFunc); break; \ case ValueType_double: _NextScanLoopPrimitive64(double, CompareFunc); break; \ } // compare result's current value in memory against result's old value #define NEXT_SCAN_PRIMITIVES_AGAINST_RESULTS(CompareFunc) \ switch(m_ValueType) \ { \ case ValueType_uint8: _NextScanLoopPrimitiveResults(uint8_t, CompareFunc); break; \ case ValueType_int8: _NextScanLoopPrimitiveResults(int8_t, CompareFunc); break; \ case ValueType_uint16: _NextScanLoopPrimitiveResults(uint16_t, CompareFunc); break; \ case ValueType_int16: _NextScanLoopPrimitiveResults(int16_t, CompareFunc); break; \ case ValueType_uint32: _NextScanLoopPrimitiveResults(uint32_t, CompareFunc); break; \ case ValueType_int32: _NextScanLoopPrimitiveResults(int32_t, CompareFunc); break; \ case ValueType_uint64: _NextScanLoopPrimitiveResults64(uint64_t, CompareFunc); break; \ case ValueType_int64: _NextScanLoopPrimitiveResults64(int64_t, CompareFunc); break; \ case ValueType_float: _NextScanLoopPrimitiveResults(float, CompareFunc); break; \ case ValueType_double: _NextScanLoopPrimitiveResults64(double, CompareFunc); break; \ } bool CMemoryScanner::NextScan() { if (!g_MMU || !m_DidFirstScan || !m_bDataTypePrimitive) { // NextScan does not support complex data return false; } switch(m_SearchType) { case SearchType_ExactValue: NEXT_SCAN_PRIMITIVES_AGAINST_VALUE(CompareEqual); break; case SearchType_LessThanValue: NEXT_SCAN_PRIMITIVES_AGAINST_VALUE(CompareLessThan); break; case SearchType_GreaterThanValue: NEXT_SCAN_PRIMITIVES_AGAINST_VALUE(CompareGreaterThan); break; case SearchType_LessThanOrEqualToValue: NEXT_SCAN_PRIMITIVES_AGAINST_VALUE(CompareLessThanOrEqual); break; case SearchType_GreaterThanOrEqualToValue: NEXT_SCAN_PRIMITIVES_AGAINST_VALUE(CompareGreaterThanOrEqual); break; case SearchType_ChangedValue: NEXT_SCAN_PRIMITIVES_AGAINST_RESULTS(CompareNotEqual); break; case SearchType_UnchangedValue: NEXT_SCAN_PRIMITIVES_AGAINST_RESULTS(CompareEqual); break; case SearchType_IncreasedValue: NEXT_SCAN_PRIMITIVES_AGAINST_RESULTS(CompareGreaterThan); break; case SearchType_DecreasedValue: NEXT_SCAN_PRIMITIVES_AGAINST_RESULTS(CompareLessThan); break; } return true; } int CMemoryScanner::HexDigitVal(char c) { if (c >= '0' && c < '9') return (c - '0'); if (c >= 'A' && c < 'F') return (c - 'A') + 0x0A; if (c >= 'a' && c < 'f') return (c - 'a') + 0x0A; return 0; } int CMemoryScanner::ParseHexString(char *dst, char* src) { bool bHiNibble = true; uint8_t curByte = 0; int size = 0; for (int i = 0; src[i] != '\0'; i++) { if (!isxdigit(src[i])) { if (!bHiNibble) { return 0; } if (isspace(src[i])) { continue; } return 0; } if (bHiNibble) { curByte = (HexDigitVal(src[i]) << 4) & 0xF0; bHiNibble = false; } else { curByte |= HexDigitVal(src[i]); if (dst != NULL) { dst[size] = curByte; } size++; bHiNibble = true; } } if (!bHiNibble) { return 0; } return size; }