1670 lines
51 KiB
C++
1670 lines
51 KiB
C++
/* FCE Ultra - NES/Famicom Emulator
|
|
*
|
|
* Copyright notice for this file:
|
|
* Copyright (C) 2002 Ben Parnell
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "..\..\types.h"
|
|
#include "..\..\debug.h"
|
|
#include "..\..\fceu.h"
|
|
#include "..\..\cheat.h"
|
|
#include "..\..\cart.h"
|
|
#include "..\..\ines.h"
|
|
#include "memview.h"
|
|
#include "debugger.h"
|
|
#include "cdlogger.h"
|
|
#include "memviewsp.h"
|
|
#include "cheat.h"
|
|
#include <assert.h>
|
|
//#include "string.h"
|
|
|
|
#define MODE_NES_MEMORY 0
|
|
#define MODE_NES_PPU 1
|
|
#define MODE_NES_FILE 2
|
|
|
|
|
|
// This defines all of our right click popup menus
|
|
struct
|
|
{
|
|
int minaddress; //The minimum address where this popup will appear
|
|
int maxaddress; //The maximum address where this popup will appear
|
|
int editingmode; //The editing mode which this popup appears in
|
|
int id; //The menu ID for this popup
|
|
char *text; //the text for the menu item (some of these need to be dynamic)
|
|
}
|
|
popupmenu[] =
|
|
{
|
|
{0,0x2000,0,1,"Freeze/Unfreeze This Address"},
|
|
{0x6000,0x7FFF,0,1,"Freeze/Unfreeze This Address"},
|
|
{0,0xFFFF,0,2,"Add Debugger Read Breakpoint"},
|
|
{0,0x3FFF,1,2,"Add Debugger Read Breakpoint"},
|
|
{0,0xFFFF,0,3,"Add Debugger Write Breakpoint"},
|
|
{0,0x3FFF,1,3,"Add Debugger Write Breakpoint"},
|
|
{0,0xFFFF,0,4,"Add Debugger Execute Breakpoint"},
|
|
{0x8000,0xFFFF,0,5,"Go Here In Rom File"},
|
|
{0x8000,0xFFFF,0,6,"Create Game Genie Code At This Address"},
|
|
//{0,0xFFFFFF,2,7,"Create Game Genie Code At This Address"}
|
|
// ################################## Start of SP CODE ###########################
|
|
{0, 0xFFFF, 0, 20, "Add / Remove bookmark"},
|
|
// ################################## End of SP CODE ###########################
|
|
} ;
|
|
|
|
#define POPUPNUM (sizeof popupmenu / sizeof popupmenu[0])
|
|
|
|
int LoadTableFile();
|
|
void UnloadTableFile();
|
|
void InputData(char *input);
|
|
int GetMemViewData(int i);
|
|
void UpdateCaption();
|
|
int UpdateCheatColorCallB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data); //mbg merge 6/29/06 - added arg
|
|
int DeleteCheatCallB(char *name, uint32 a, uint8 v, int compare,int s,int type); //mbg merge 6/29/06 - added arg
|
|
// ################################## Start of SP CODE ###########################
|
|
void FreezeRam(int address, int mode, int final);
|
|
// ################################## End of SP CODE ###########################
|
|
int GetHexScreenCoordx(int offset);
|
|
int GetHexScreenCoordy(int offset);
|
|
int GetAddyFromCoord(int x,int y);
|
|
void AutoScrollFromCoord(int x,int y);
|
|
LRESULT CALLBACK MemViewCallB(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
BOOL CALLBACK MemFindCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
void FindNext();
|
|
void OpenFindDialog();
|
|
|
|
HWND hMemView, hMemFind;
|
|
HDC mDC;
|
|
//int tempdummy;
|
|
//char dummystr[100];
|
|
HFONT hMemFont;
|
|
int CurOffset;
|
|
int MemFontHeight;
|
|
int MemFontWidth;
|
|
int ClientHeight;
|
|
int NoColors;
|
|
int EditingMode;
|
|
int EditingText;
|
|
int AddyWasText; //used by the GetAddyFromCoord() function.
|
|
int TableFileLoaded;
|
|
|
|
char chartable[256];
|
|
|
|
//SCROLLINFO memsi;
|
|
//HBITMAP HDataBmp;
|
|
//HGDIOBJ HDataObj;
|
|
HDC HDataDC;
|
|
int CursorX=2, CursorY=9;
|
|
int CursorStartAddy, CursorEndAddy=-1;
|
|
int CursorDragPoint;//, CursorShiftPoint = -1;
|
|
//int CursorStartNibble=1, CursorEndNibble; //1 means that only half of the byte is selected
|
|
int TempData=-1;
|
|
int DataAmount;
|
|
int MaxSize;
|
|
|
|
COLORREF *BGColorList;
|
|
COLORREF *TextColorList;
|
|
int *OldValues; //this will be used for a speed hack
|
|
int OldCurOffset;
|
|
|
|
int lbuttondown, lbuttondownx, lbuttondowny;
|
|
int mousex, mousey;
|
|
|
|
int FindAsText;
|
|
int FindDirectionUp;
|
|
char FindTextBox[60];
|
|
|
|
extern iNES_HEADER head;
|
|
|
|
//undo structure
|
|
struct UNDOSTRUCT {
|
|
int addr;
|
|
int size;
|
|
unsigned char *data;
|
|
UNDOSTRUCT *last; //mbg merge 7/18/06 removed struct qualifier
|
|
};
|
|
|
|
struct UNDOSTRUCT *undo_list=0;
|
|
|
|
void ApplyPatch(int addr,int size, uint8* data){
|
|
UNDOSTRUCT *tmp=(UNDOSTRUCT*)malloc(sizeof(UNDOSTRUCT)); //mbg merge 7/18/06 removed struct qualifiers and added cast
|
|
|
|
int i;
|
|
|
|
//while(tmp != 0){tmp=tmp->next;x++;};
|
|
//tmp = malloc(sizeof(struct UNDOSTRUCT));
|
|
//sprintf(str,"%d",x);
|
|
//MessageBox(hMemView,str,"info", MB_OK);
|
|
tmp->addr = addr;
|
|
tmp->size = size;
|
|
tmp->data = (uint8*)malloc(sizeof(uint8)*size);
|
|
tmp->last=undo_list;
|
|
|
|
for(i = 0;i < size;i++){
|
|
tmp->data[i] = GetFileData(addr+i);
|
|
WriteFileData(addr+i,data[i]);
|
|
}
|
|
|
|
undo_list=tmp;
|
|
|
|
//UpdateColorTable();
|
|
return;
|
|
}
|
|
|
|
void UndoLastPatch(){
|
|
struct UNDOSTRUCT *tmp=undo_list;
|
|
int i;
|
|
if(undo_list == 0)return;
|
|
//while(tmp->next != 0){tmp=tmp->next;}; //traverse to the one before the last one
|
|
|
|
for(i = 0;i < tmp->size;i++){
|
|
WriteFileData(tmp->addr+i,tmp->data[i]);
|
|
}
|
|
|
|
undo_list=undo_list->last;
|
|
|
|
ChangeMemViewFocus(2,tmp->addr, -1); //move to the focus to where we are undoing at.
|
|
|
|
free(tmp->data);
|
|
free(tmp);
|
|
return;
|
|
}
|
|
|
|
void FlushUndoBuffer(){
|
|
struct UNDOSTRUCT *tmp;
|
|
while(undo_list!= 0){
|
|
tmp=undo_list;
|
|
undo_list=undo_list->last;
|
|
free(tmp->data);
|
|
free(tmp);
|
|
}
|
|
UpdateColorTable();
|
|
return;
|
|
}
|
|
|
|
|
|
int GetFileData(int offset){
|
|
if(offset < 16) return *((unsigned char *)&head+offset);
|
|
if(offset < 16+PRGsize[0])return PRGptr[0][offset-16];
|
|
if(offset < 16+PRGsize[0]+CHRsize[0])return CHRptr[0][offset-16-PRGsize[0]];
|
|
return -1;
|
|
}
|
|
|
|
int WriteFileData(int addr,int data){
|
|
if (addr < 16)MessageBox(hMemView,"Sorry", "Go bug bbit if you really want to edit the header.", MB_OK);
|
|
if((addr >= 16) && (addr < PRGsize[0]+16)) *(uint8 *)(GetNesPRGPointer(addr-16)) = data;
|
|
if((addr >= PRGsize[0]+16) && (addr < CHRsize[0]+PRGsize[0]+16)) *(uint8 *)(GetNesCHRPointer(addr-16-PRGsize[0])) = data;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int GetRomFileSize(){ //todo: fix or remove this?
|
|
return 0;
|
|
}
|
|
|
|
//should return -1, otherwise returns the line number it had the error on
|
|
int LoadTableFile(){
|
|
char str[50];
|
|
FILE *FP;
|
|
int i, line, charcode1, charcode2;
|
|
|
|
const char filter[]="Table Files (*.TBL)\0*.tbl\0";
|
|
char nameo[2048]; //todo: possibly no need for this? can lpstrfilter point to loadedcdfile instead?
|
|
OPENFILENAME ofn;
|
|
StopSound();
|
|
memset(&ofn,0,sizeof(ofn));
|
|
ofn.lStructSize=sizeof(ofn);
|
|
ofn.hInstance=fceu_hInstance;
|
|
ofn.lpstrTitle="Load Table File...";
|
|
ofn.lpstrFilter=filter;
|
|
nameo[0]=0;
|
|
ofn.lpstrFile=nameo;
|
|
ofn.nMaxFile=256;
|
|
ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
|
|
ofn.hwndOwner = hCDLogger;
|
|
if(!GetOpenFileName(&ofn))return -1;
|
|
|
|
for(i = 0;i < 256;i++){
|
|
chartable[i] = 0;
|
|
}
|
|
|
|
FP = fopen(nameo,"r");
|
|
line = 0;
|
|
while((fgets(str, 45, FP)) != NULL){/* get one line from the file */
|
|
line++;
|
|
|
|
if(strlen(str) < 3)continue;
|
|
|
|
charcode1 = charcode2 = -1;
|
|
|
|
if((str[0] >= 'a') && (str[0] <= 'f')) charcode1 = str[0]-('a'-0xA);
|
|
if((str[0] >= 'A') && (str[0] <= 'F')) charcode1 = str[0]-('A'-0xA);
|
|
if((str[0] >= '0') && (str[0] <= '9')) charcode1 = str[0]-'0';
|
|
|
|
if((str[1] >= 'a') && (str[1] <= 'f')) charcode2 = str[1]-('a'-0xA);
|
|
if((str[1] >= 'A') && (str[1] <= 'F')) charcode2 = str[1]-('A'-0xA);
|
|
if((str[1] >= '0') && (str[1] <= '9')) charcode2 = str[1]-'0';
|
|
|
|
if(charcode1 == -1){
|
|
UnloadTableFile();
|
|
fclose(FP);
|
|
return line; //we have an error getting the first input
|
|
}
|
|
|
|
if(charcode2 != -1) charcode1 = (charcode1<<4)|charcode2;
|
|
|
|
for(i = 0;i < (int)strlen(str);i++)if(str[i] == '=')break;
|
|
|
|
if(i == strlen(str)){
|
|
UnloadTableFile();
|
|
fclose(FP);
|
|
return line; //error no '=' found
|
|
}
|
|
|
|
i++;
|
|
//ORing i with 32 just converts it to lowercase if it isn't
|
|
if(((str[i]|32) == 'r') && ((str[i+1]|32) == 'e') && ((str[i+2]|32) == 't'))
|
|
charcode2 = 0x0D;
|
|
else charcode2 = str[i];
|
|
|
|
chartable[charcode1] = charcode2;
|
|
}
|
|
TableFileLoaded = 1;
|
|
fclose(FP);
|
|
return -1;
|
|
|
|
}
|
|
|
|
void UnloadTableFile(){
|
|
int i, j;
|
|
for(i = 0;i < 256;i++){
|
|
j = i;
|
|
if(j < 0x20)j = 0x2E;
|
|
if(j > 0x7e)j = 0x2E;
|
|
chartable[i] = j;
|
|
}
|
|
TableFileLoaded = 0;
|
|
return;
|
|
}
|
|
void UpdateMemoryView(int draw_all){
|
|
int i, j;
|
|
//LPVOID lpMsgBuf;
|
|
//int curlength;
|
|
char str[100];
|
|
char str2[100];
|
|
if (!hMemView) return;
|
|
|
|
/*
|
|
if(draw_all){
|
|
for(i = CurOffset;i < CurOffset+DataAmount;i+=16){
|
|
MoveToEx(HDataDC,0,MemFontHeight*((i-CurOffset)/16),NULL);
|
|
sprintf(str,"%06X: ",i);
|
|
for(j = 0;j < 16;j++){
|
|
sprintf(str2,"%02X ",GetMem(i+j));
|
|
strcat(str,str2);
|
|
}
|
|
strcat(str," : ");
|
|
k = strlen(str);
|
|
for(j = 0;j < 16;j++){
|
|
str[k+j] = GetMem(i+j);
|
|
if(str[k+j] < 0x20)str[k+j] = 0x2E;
|
|
if(str[k+j] > 0x7e)str[k+j] = 0x2E;
|
|
}
|
|
str[k+16] = 0;
|
|
TextOut(HDataDC,0,0,str,strlen(str));
|
|
}
|
|
} else {*/
|
|
for(i = CurOffset;i < CurOffset+DataAmount;i+=16){
|
|
if((OldCurOffset != CurOffset) || draw_all){
|
|
MoveToEx(HDataDC,0,MemFontHeight*((i-CurOffset)/16),NULL);
|
|
SetTextColor(HDataDC,RGB(0,0,0));
|
|
SetBkColor(HDataDC,RGB(255,255,255));
|
|
sprintf(str,"%06X: ",i);
|
|
TextOut(HDataDC,0,0,str,strlen(str));
|
|
}
|
|
for(j = 0;j < 16;j++){
|
|
if((CursorEndAddy == -1) && (CursorStartAddy == i+j)){ //print up single highlighted text
|
|
sprintf(str,"%02X",GetMemViewData(CursorStartAddy));
|
|
OldValues[i+j-CurOffset] = -1; //set it to redraw this one next time
|
|
MoveToEx(HDataDC,8*MemFontWidth+(j*3*MemFontWidth),MemFontHeight*((i-CurOffset)/16),NULL);
|
|
if(TempData != -1){
|
|
sprintf(str2,"%X",TempData);
|
|
SetBkColor(HDataDC,RGB(255,255,255));
|
|
SetTextColor(HDataDC,RGB(255,0,0));
|
|
TextOut(HDataDC,0,0,str2,1);
|
|
SetTextColor(HDataDC,RGB(255,255,255));
|
|
SetBkColor(HDataDC,RGB(0,0,0));
|
|
TextOut(HDataDC,0,0,&str[1],1);
|
|
} else {
|
|
SetTextColor(HDataDC,RGB(255,255,255));
|
|
SetBkColor(HDataDC,RGB(0,0,0));
|
|
TextOut(HDataDC,0,0,str,1);
|
|
SetTextColor(HDataDC,RGB(0,0,0));
|
|
SetBkColor(HDataDC,RGB(255,255,255));
|
|
TextOut(HDataDC,0,0,&str[1],1);
|
|
}
|
|
TextOut(HDataDC,0,0," ",1);
|
|
|
|
SetTextColor(HDataDC,RGB(255,255,255));
|
|
SetBkColor(HDataDC,RGB(0,0,0));
|
|
MoveToEx(HDataDC,(59+j)*MemFontWidth,MemFontHeight*((i-CurOffset)/16),NULL); //todo: try moving this above the for loop
|
|
str[0] = chartable[GetMemViewData(i+j)];
|
|
if(str[0] < 0x20)str[0] = 0x2E;
|
|
if(str[0] > 0x7e)str[0] = 0x2E;
|
|
str[1] = 0;
|
|
TextOut(HDataDC,0,0,str,1);
|
|
|
|
continue;
|
|
}
|
|
if((OldValues[i+j-CurOffset] != GetMemViewData(i+j)) || draw_all){
|
|
MoveToEx(HDataDC,8*MemFontWidth+(j*3*MemFontWidth),MemFontHeight*((i-CurOffset)/16),NULL);
|
|
SetTextColor(HDataDC,TextColorList[i+j-CurOffset]);//(8+j*3)*MemFontWidth
|
|
SetBkColor(HDataDC,BGColorList[i+j-CurOffset]);
|
|
sprintf(str,"%02X ",GetMemViewData(i+j));
|
|
TextOut(HDataDC,0,0,str,strlen(str));
|
|
|
|
MoveToEx(HDataDC,(59+j)*MemFontWidth,MemFontHeight*((i-CurOffset)/16),NULL); //todo: try moving this above the for loop
|
|
str[0] = chartable[GetMemViewData(i+j)];
|
|
if(str[0] < 0x20)str[0] = 0x2E;
|
|
if(str[0] > 0x7e)str[0] = 0x2E;
|
|
str[1] = 0;
|
|
TextOut(HDataDC,0,0,str,1);
|
|
if(CursorStartAddy != i+j)OldValues[i+j-CurOffset] = GetMemViewData(i+j);
|
|
}
|
|
}
|
|
if(draw_all){
|
|
MoveToEx(HDataDC,56*MemFontWidth,MemFontHeight*((i-CurOffset)/16),NULL);
|
|
SetTextColor(HDataDC,RGB(0,0,0));
|
|
SetBkColor(HDataDC,RGB(255,255,255));
|
|
TextOut(HDataDC,0,0," : ",3);
|
|
}/*
|
|
for(j = 0;j < 16;j++){
|
|
if((OldValues[i+j-CurOffset] != GetMem(i+j)) || draw_all){
|
|
MoveToEx(HDataDC,(59+j)*MemFontWidth,MemFontHeight*((i-CurOffset)/16),NULL); //todo: try moving this above the for loop
|
|
SetTextColor(HDataDC,TextColorList[i+j-CurOffset]);
|
|
SetBkColor(HDataDC,BGColorList[i+j-CurOffset]);
|
|
str[0] = GetMem(i+j);
|
|
if(str[0] < 0x20)str[0] = 0x2E;
|
|
if(str[0] > 0x7e)str[0] = 0x2E;
|
|
str[1] = 0;
|
|
TextOut(HDataDC,0,0,str,1);
|
|
if(CursorStartAddy != i+j)OldValues[i+j-CurOffset] = GetMem(i+j);
|
|
}
|
|
}*/
|
|
}
|
|
// }
|
|
|
|
SetTextColor(HDataDC,RGB(0,0,0));
|
|
SetBkColor(HDataDC,RGB(255,255,255));
|
|
|
|
MoveToEx(HDataDC,0,0,NULL);
|
|
OldCurOffset = CurOffset;
|
|
return;
|
|
}
|
|
|
|
void UpdateCaption(){
|
|
char str[100];
|
|
char EditString[3][20] = {"RAM","PPU Memory","ROM"};
|
|
|
|
if(CursorEndAddy == -1){
|
|
sprintf(str,"Hex Editor - Editing %s Offset 0x%06x",EditString[EditingMode],CursorStartAddy);
|
|
} else {
|
|
sprintf(str,"Hex Editor - Editing %s Offset 0x%06x - 0x%06x, 0x%x bytes selected ",
|
|
EditString[EditingMode],CursorStartAddy,CursorEndAddy,CursorEndAddy-CursorStartAddy+1);
|
|
}
|
|
SetWindowText(hMemView,str);
|
|
return;
|
|
}
|
|
|
|
int GetMemViewData(int i){
|
|
if(EditingMode == 0)return GetMem(i);
|
|
if(EditingMode == 1){
|
|
i &= 0x3FFF;
|
|
if(i < 0x2000)return VPage[(i)>>10][(i)];
|
|
if(i < 0x3F00)return vnapage[(i>>10)&0x3][i&0x3FF];
|
|
return PALRAM[i&0x1F];
|
|
}
|
|
if(EditingMode == 2){ //todo: use getfiledata() here
|
|
if(i < 16) return *((unsigned char *)&head+i);
|
|
if(i < 16+PRGsize[0])return PRGptr[0][i-16];
|
|
if(i < 16+PRGsize[0]+CHRsize[0])return CHRptr[0][i-16-PRGsize[0]];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void UpdateColorTable(){
|
|
UNDOSTRUCT *tmp; //mbg merge 7/18/06 removed struct qualifier
|
|
int i,j;
|
|
if(!hMemView)return;
|
|
for(i = 0;i < DataAmount;i++){
|
|
if((i+CurOffset >= CursorStartAddy) && (i+CurOffset <= CursorEndAddy)){
|
|
BGColorList[i] = RGB(0,0,0);
|
|
TextColorList[i] = RGB(255,255,255);
|
|
continue;
|
|
}
|
|
|
|
BGColorList[i] = RGB(255,255,255);
|
|
TextColorList[i] = RGB(0,0,0);
|
|
}
|
|
|
|
//mbg merge 6/29/06 - added argument
|
|
if(EditingMode == 0)FCEUI_ListCheats(UpdateCheatColorCallB,0);
|
|
|
|
// ################################## Start of SP CODE ###########################
|
|
|
|
for (j=0;j<nextBookmark;j++)
|
|
{
|
|
if((hexBookmarks[j].address >= CurOffset) && (hexBookmarks[j].address < CurOffset+DataAmount))
|
|
TextColorList[hexBookmarks[j].address - CurOffset] = RGB(0,0xCC,0);
|
|
}
|
|
|
|
// ################################## End of SP CODE ###########################
|
|
|
|
if(EditingMode == 2){
|
|
if(cdloggerdata) {
|
|
for(i = 0;i < DataAmount;i++){
|
|
if((CurOffset+i >= 16) && (CurOffset+i < 16+PRGsize[0])) {
|
|
if((cdloggerdata[i+CurOffset-16]&3) == 3)TextColorList[i]=RGB(0,192,0);
|
|
if((cdloggerdata[i+CurOffset-16]&3) == 1)TextColorList[i]=RGB(192,192,0);
|
|
if((cdloggerdata[i+CurOffset-16]&3) == 2)TextColorList[i]=RGB(0,0,192);
|
|
}
|
|
}
|
|
}
|
|
|
|
tmp=undo_list;
|
|
while(tmp!= 0){
|
|
//if((tmp->addr < CurOffset+DataAmount) && (tmp->addr+tmp->size > CurOffset))
|
|
for(i = tmp->addr;i < tmp->addr+tmp->size;i++){
|
|
if((i > CurOffset) && (i < CurOffset+DataAmount))
|
|
TextColorList[i-CurOffset] = RGB(255,0,0);
|
|
}
|
|
tmp=tmp->last;
|
|
}
|
|
}
|
|
|
|
UpdateMemoryView(1); //anytime the colors change, the memory viewer needs to be completely redrawn
|
|
}
|
|
|
|
//mbg merge 6/29/06 - added argument
|
|
int UpdateCheatColorCallB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data) {
|
|
|
|
if((a >= CurOffset) && (a < CurOffset+DataAmount)){
|
|
if(s)TextColorList[a-CurOffset] = RGB(0,0,255);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int addrtodelete; // This is a very ugly hackish method of doing this
|
|
int cheatwasdeleted; // but it works and that is all that matters here.
|
|
int DeleteCheatCallB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data){ //mbg merge 6/29/06 - added arg
|
|
if(cheatwasdeleted == -1)return 1;
|
|
cheatwasdeleted++;
|
|
if(a == addrtodelete){
|
|
FCEUI_DelCheat(cheatwasdeleted-1);
|
|
cheatwasdeleted = -1;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// ################################## Start of SP CODE ###########################
|
|
|
|
void dumpToFile(const char* buffer, unsigned int size)
|
|
{
|
|
char name[257] = {0};
|
|
|
|
OPENFILENAME ofn;
|
|
memset(&ofn, 0, sizeof(ofn));
|
|
ofn.lStructSize=sizeof(ofn);
|
|
ofn.hInstance=fceu_hInstance;
|
|
ofn.lpstrTitle="Save to file ...";
|
|
ofn.lpstrFilter="All files (*.*)\0*.*\0";
|
|
ofn.lpstrFile=name;
|
|
ofn.nMaxFile=256;
|
|
ofn.Flags=OFN_EXPLORER|OFN_HIDEREADONLY;
|
|
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
FILE* memfile = fopen(ofn.lpstrFile, "wb");
|
|
|
|
if (!memfile || fwrite(buffer, 1, size, memfile) != size)
|
|
{
|
|
MessageBox(0, "Saving failed", "Error", 0);
|
|
}
|
|
|
|
if (memfile)
|
|
fclose(memfile);
|
|
}
|
|
}
|
|
|
|
void FreezeRam(int address, int mode, int final){
|
|
// mode: -1 == Unfreeze; 0 == Toggle; 1 == Freeze
|
|
// ################################## End of SP CODE ###########################
|
|
if((address < 0x2000) || ((address >= 0x6000) && (address <= 0x7FFF))){
|
|
addrtodelete = address;
|
|
cheatwasdeleted = 0;
|
|
|
|
// ################################## Start of SP CODE ###########################
|
|
if (mode == 0 || mode == -1)
|
|
{
|
|
//mbg merge 6/29/06 - added argument
|
|
FCEUI_ListCheats(DeleteCheatCallB,0);
|
|
if(mode == 0 && cheatwasdeleted != -1)FCEUI_AddCheat("",address,GetMem(address),-1,1);
|
|
}
|
|
else
|
|
{
|
|
//mbg merge 6/29/06 - added argument
|
|
FCEUI_ListCheats(DeleteCheatCallB,0);
|
|
FCEUI_AddCheat("",address,GetMem(address),-1,1);
|
|
}
|
|
// ################################## End of SP CODE ###########################
|
|
|
|
/*if (final)
|
|
{
|
|
if(hCheat)RedoCheatsLB(hCheat);
|
|
UpdateColorTable();
|
|
}*/
|
|
//mbg merge 6/29/06 - WTF
|
|
}
|
|
}
|
|
|
|
//input is expected to be an ASCII string
|
|
void InputData(char *input){
|
|
//CursorEndAddy = -1;
|
|
int addr, i, j, datasize = 0;
|
|
unsigned char *data;
|
|
char inputc;
|
|
//char str[100];
|
|
//mbg merge 7/18/06 added cast:
|
|
data = (uint8*)malloc(strlen(input)); //it can't be larger than the input string, so use that as the size
|
|
|
|
for(i = 0;input[i] != 0;i++){
|
|
if(!EditingText){
|
|
inputc = -1;
|
|
if((input[i] >= 'a') && (input[i] <= 'f')) inputc = input[i]-('a'-0xA);
|
|
if((input[i] >= 'A') && (input[i] <= 'F')) inputc = input[i]-('A'-0xA);
|
|
if((input[i] >= '0') && (input[i] <= '9')) inputc = input[i]-'0';
|
|
if(inputc == -1)continue;
|
|
|
|
if(TempData != -1){
|
|
data[datasize++] = inputc|(TempData<<4);
|
|
TempData = -1;
|
|
} else {
|
|
TempData = inputc;
|
|
}
|
|
} else {
|
|
for(j = 0;j < 256;j++)if(chartable[j] == input[i])break;
|
|
if(j == 256)continue;
|
|
data[datasize++] = j;
|
|
}
|
|
}
|
|
|
|
if(datasize+CursorStartAddy >= MaxSize){ //too big
|
|
datasize = MaxSize-CursorStartAddy;
|
|
//free(data);
|
|
//return;
|
|
}
|
|
|
|
//its possible for this loop not to get executed at all
|
|
// for(addr = CursorStartAddy;addr < datasize+CursorStartAddy;addr++){
|
|
//sprintf(str,"datasize = %d",datasize);
|
|
//MessageBox(hMemView,str, "debug", MB_OK);
|
|
|
|
for(i = 0;i < datasize;i++){
|
|
addr = CursorStartAddy+i;
|
|
|
|
if(EditingMode == 0)BWrite[addr](addr,data[i]);
|
|
if(EditingMode == 1){
|
|
addr &= 0x3FFF;
|
|
if(addr < 0x2000)VPage[addr>>10][addr] = data[i]; //todo: detect if this is vrom and turn it red if so
|
|
if((addr > 0x2000) && (addr < 0x3F00))vnapage[(addr>>10)&0x3][addr&0x3FF] = data[i]; //todo: this causes 0x3000-0x3f00 to mirror 0x2000-0x2f00, is this correct?
|
|
if((addr > 0x3F00) && (addr < 0x3FFF))PALRAM[addr&0x1F] = data[i];
|
|
}
|
|
if(EditingMode == 2){
|
|
ApplyPatch(addr,datasize,data);
|
|
break;
|
|
}
|
|
}
|
|
CursorStartAddy+=datasize;
|
|
CursorEndAddy=-1;
|
|
if(CursorStartAddy >= MaxSize)CursorStartAddy = MaxSize-1;
|
|
|
|
free(data);
|
|
ChangeMemViewFocus(EditingMode,CursorStartAddy,-1);
|
|
UpdateColorTable();
|
|
return;
|
|
}
|
|
/*
|
|
if(!EditingText){
|
|
if((input >= 'a') && (input <= 'f')) input-=('a'-0xA);
|
|
if((input >= 'A') && (input <= 'F')) input-=('A'-0xA);
|
|
if((input >= '0') && (input <= '9')) input-='0';
|
|
if(input > 0xF)return;
|
|
|
|
if(TempData != -1){
|
|
addr = CursorStartAddy;
|
|
data = input|(TempData<<4);
|
|
if(EditingMode == 0)BWrite[addr](addr,data);
|
|
if(EditingMode == 1){
|
|
addr &= 0x3FFF;
|
|
if(addr < 0x2000)VPage[addr>>10][addr] = data; //todo: detect if this is vrom and turn it red if so
|
|
if((addr > 0x2000) && (addr < 0x3F00))vnapage[(addr>>10)&0x3][addr&0x3FF] = data; //todo: this causes 0x3000-0x3f00 to mirror 0x2000-0x2f00, is this correct?
|
|
if((addr > 0x3F00) && (addr < 0x3FFF))PALRAM[addr&0x1F] = data;
|
|
}
|
|
if(EditingMode == 2)ApplyPatch(addr,1,(uint8 *)&data);
|
|
CursorStartAddy++;
|
|
TempData = -1;
|
|
} else {
|
|
TempData = input;
|
|
}
|
|
} else {
|
|
for(i = 0;i < 256;i++)if(chartable[i] == input)break;
|
|
if(i == 256)return;
|
|
|
|
addr = CursorStartAddy;
|
|
data = i;
|
|
if(EditingMode == 0)BWrite[addr](addr,data);
|
|
if(EditingMode == 2)ApplyPatch(addr,1,(uint8 *)&data);
|
|
CursorStartAddy++;
|
|
}
|
|
*/
|
|
|
|
|
|
void ChangeMemViewFocus(int newEditingMode, int StartOffset,int EndOffset){
|
|
SCROLLINFO si;
|
|
|
|
if (GI->type==GIT_NSF) {
|
|
FCEUD_PrintError("Sorry, you can't yet use the Memory Viewer with NSFs.");
|
|
return;
|
|
}
|
|
|
|
if(!hMemView)DoMemView();
|
|
if(EditingMode != newEditingMode)
|
|
MemViewCallB(hMemView,WM_COMMAND,300+newEditingMode,0); //let the window handler change this for us
|
|
|
|
if((EndOffset == StartOffset) || (EndOffset == -1)){
|
|
CursorEndAddy = -1;
|
|
CursorStartAddy = StartOffset;
|
|
} else {
|
|
CursorStartAddy = min(StartOffset,EndOffset);
|
|
CursorEndAddy = max(StartOffset,EndOffset);
|
|
}
|
|
|
|
|
|
if(min(StartOffset,EndOffset) >= MaxSize)return; //this should never happen
|
|
|
|
if(StartOffset < CurOffset){
|
|
CurOffset = (StartOffset/16)*16;
|
|
}
|
|
|
|
if(StartOffset >= CurOffset+DataAmount){
|
|
CurOffset = ((StartOffset/16)*16)-DataAmount+0x10;
|
|
if(CurOffset < 0)CurOffset = 0;
|
|
}
|
|
|
|
SetFocus(hMemView);
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.fMask = SIF_POS;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
si.nPos = CurOffset/16;
|
|
SetScrollInfo(hMemView,SB_VERT,&si,TRUE);
|
|
UpdateCaption();
|
|
UpdateColorTable();
|
|
return;
|
|
}
|
|
|
|
|
|
int GetHexScreenCoordx(int offset){
|
|
return (8*MemFontWidth)+((offset%16)*3*MemFontWidth); //todo: add Curoffset to this and to below function
|
|
}
|
|
|
|
int GetHexScreenCoordy(int offset){
|
|
return (offset/16)*MemFontHeight;
|
|
}
|
|
|
|
//0000E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
|
|
|
|
//if the mouse is in the text field, this function will set AddyWasText to 1 otherwise it is 0
|
|
//if the mouse wasn't in any range, this function returns -1
|
|
int GetAddyFromCoord(int x,int y){
|
|
if(y < 0)y = 0;
|
|
if(x < 8*MemFontWidth)x = 8*MemFontWidth+1;
|
|
|
|
if(y > DataAmount*MemFontHeight) return -1;
|
|
|
|
if(x < 55*MemFontWidth){
|
|
AddyWasText = 0;
|
|
return ((y/MemFontHeight)*16)+((x-(8*MemFontWidth))/(3*MemFontWidth))+CurOffset;
|
|
}
|
|
|
|
if((x > 59*MemFontWidth) && (x < 75*MemFontWidth)){
|
|
AddyWasText = 1;
|
|
return ((y/MemFontHeight)*16)+((x-(59*MemFontWidth))/(MemFontWidth))+CurOffset;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void AutoScrollFromCoord(int x,int y){
|
|
SCROLLINFO si;
|
|
if(y < 0){
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.fMask = SIF_ALL;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
GetScrollInfo(hMemView,SB_VERT,&si);
|
|
si.nPos += y / 16;
|
|
if (si.nPos < si.nMin) si.nPos = si.nMin;
|
|
if ((si.nPos+si.nPage) > si.nMax) si.nPos = si.nMax-si.nPage;
|
|
CurOffset = si.nPos*16;
|
|
SetScrollInfo(hMemView,SB_VERT,&si,TRUE);
|
|
return;
|
|
}
|
|
|
|
if(y > ClientHeight){
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.fMask = SIF_ALL;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
GetScrollInfo(hMemView,SB_VERT,&si);
|
|
si.nPos -= (ClientHeight-y) / 16;
|
|
if (si.nPos < si.nMin) si.nPos = si.nMin;
|
|
if ((si.nPos+si.nPage) > si.nMax) si.nPos = si.nMax-si.nPage;
|
|
CurOffset = si.nPos*16;
|
|
SetScrollInfo(hMemView,SB_VERT,&si,TRUE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void KillMemView(){
|
|
DeleteObject(hMemFont);
|
|
ReleaseDC(hMemView,mDC);
|
|
DestroyWindow(hMemView);
|
|
UnregisterClass("MEMVIEW",fceu_hInstance);
|
|
hMemView = 0;
|
|
return;
|
|
}
|
|
|
|
LRESULT CALLBACK MemViewCallB(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
|
|
HDC hdc;
|
|
HGLOBAL hGlobal ;
|
|
PTSTR pGlobal ;
|
|
HMENU hMenu;
|
|
MENUITEMINFO MenuInfo;
|
|
POINT point;
|
|
PAINTSTRUCT ps ;
|
|
TEXTMETRIC tm;
|
|
SCROLLINFO si;
|
|
int x, y, i, j;
|
|
|
|
char c[2];
|
|
char str[100];
|
|
// ################################## Start of SP CODE ###########################
|
|
extern int debuggerWasActive;
|
|
// ################################## End of SP CODE ###########################
|
|
|
|
switch (message) {
|
|
case WM_ENTERMENULOOP:StopSound();return 0;
|
|
case WM_INITMENUPOPUP:
|
|
if(undo_list != 0)EnableMenuItem(GetMenu(hMemView),200,MF_BYCOMMAND | MF_ENABLED);
|
|
else EnableMenuItem(GetMenu(hMemView),200,MF_BYCOMMAND | MF_GRAYED);
|
|
|
|
if(TableFileLoaded)EnableMenuItem(GetMenu(hMemView),103,MF_BYCOMMAND | MF_ENABLED);
|
|
else EnableMenuItem(GetMenu(hMemView),103,MF_BYCOMMAND | MF_GRAYED);
|
|
|
|
return 0;
|
|
|
|
case WM_CREATE:
|
|
// ################################## Start of SP CODE ###########################
|
|
debuggerWasActive = 1;
|
|
// ################################## End of SP CODE ###########################
|
|
mDC = GetDC(hwnd);
|
|
HDataDC = mDC;//deleteme
|
|
hMemFont = CreateFont(13,8, /*Height,Width*/
|
|
0,0, /*escapement,orientation*/
|
|
400,FALSE,FALSE,FALSE, /*weight, italic,, underline, strikeout*/
|
|
ANSI_CHARSET,OUT_DEVICE_PRECIS,CLIP_MASK, /*charset, precision, clipping*/
|
|
DEFAULT_QUALITY, DEFAULT_PITCH, /*quality, and pitch*/
|
|
"Courier"); /*font name*/
|
|
SelectObject (HDataDC, hMemFont);
|
|
SetTextAlign(HDataDC,TA_UPDATECP | TA_TOP | TA_LEFT);
|
|
|
|
GetTextMetrics (HDataDC, &tm) ;
|
|
MemFontWidth = 8;
|
|
MemFontHeight = 13;
|
|
|
|
MaxSize = 0x10000;
|
|
//Allocate Memory for color lists
|
|
DataAmount = 0x100;
|
|
//mbg merge 7/18/06 added casts:
|
|
TextColorList = (COLORREF*)malloc(DataAmount*sizeof(COLORREF));
|
|
BGColorList = (COLORREF*)malloc(DataAmount*sizeof(COLORREF));
|
|
OldValues = (int*)malloc(DataAmount*sizeof(int));
|
|
EditingText = EditingMode = CurOffset = 0;
|
|
|
|
//set the default table
|
|
UnloadTableFile();
|
|
UpdateColorTable(); //draw it
|
|
updateBookmarkMenus(GetSubMenu(GetMenu(hwnd), 3));
|
|
return 0;
|
|
case WM_PAINT:
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
EndPaint(hwnd, &ps);
|
|
UpdateMemoryView(1);
|
|
return 0;
|
|
case WM_VSCROLL:
|
|
|
|
StopSound();
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.fMask = SIF_ALL;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
GetScrollInfo(hwnd,SB_VERT,&si);
|
|
switch(LOWORD(wParam)) {
|
|
case SB_ENDSCROLL:
|
|
case SB_TOP:
|
|
case SB_BOTTOM: break;
|
|
case SB_LINEUP: si.nPos--; break;
|
|
case SB_LINEDOWN:si.nPos++; break;
|
|
case SB_PAGEUP: si.nPos-=si.nPage; break;
|
|
case SB_PAGEDOWN: si.nPos+=si.nPage; break;
|
|
case SB_THUMBPOSITION: //break;
|
|
case SB_THUMBTRACK: si.nPos = si.nTrackPos; break;
|
|
}
|
|
if (si.nPos < si.nMin) si.nPos = si.nMin;
|
|
if ((si.nPos+(int)si.nPage) > si.nMax) si.nPos = si.nMax-si.nPage; //mbg merge 7/18/06 added cast
|
|
CurOffset = si.nPos*16;
|
|
SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
|
|
UpdateColorTable();
|
|
return 0;
|
|
case WM_CHAR:
|
|
if(GetKeyState(VK_CONTROL) & 0x8000)return 0; //prevents input when pressing ctrl+c
|
|
c[0] = (char)(wParam&0xFF);
|
|
c[1] = 0;
|
|
//sprintf(str,"c[0] = %c c[1] = %c",c[0],c[1]);
|
|
//MessageBox(hMemView,str, "debug", MB_OK);
|
|
InputData(c);
|
|
UpdateColorTable();
|
|
UpdateCaption();
|
|
return 0;
|
|
|
|
case WM_KEYDOWN:
|
|
//if((wParam >= 0x30) && (wParam <= 0x39))InputData(wParam-0x30);
|
|
//if((wParam >= 0x41) && (wParam <= 0x46))InputData(wParam-0x41+0xA);
|
|
/*if(!((GetKeyState(VK_LSHIFT) & 0x8000) || (GetKeyState(VK_RSHIFT) & 0x8000))){
|
|
//MessageBox(hMemView,"nobody", "mouse wheel dance!", MB_OK);
|
|
CursorShiftPoint = -1;
|
|
}
|
|
if(((GetKeyState(VK_LSHIFT) & 0x8000) || (GetKeyState(VK_RSHIFT) & 0x8000)) &&
|
|
(CursorShiftPoint == -1)){
|
|
CursorShiftPoint = CursorStartAddy;
|
|
//MessageBox(hMemView,"somebody", "mouse wheel dance!", MB_OK);
|
|
}*/
|
|
|
|
if(GetKeyState(VK_CONTROL) & 0x8000){
|
|
|
|
// ################################## Start of SP CODE ###########################
|
|
|
|
if (wParam >= '0' && wParam <= '9')
|
|
{
|
|
int newValue = handleBookmarkMenu(wParam - '0');
|
|
|
|
if (newValue != -1)
|
|
{
|
|
CurOffset = newValue;
|
|
CursorEndAddy = -1;
|
|
CursorStartAddy = hexBookmarks[wParam - '0'].address;
|
|
UpdateColorTable();
|
|
}
|
|
}
|
|
|
|
// ################################## End of SP CODE ###########################
|
|
|
|
switch(wParam){
|
|
case 0x43: //Ctrl+C
|
|
MemViewCallB(hMemView,WM_COMMAND,201,0); //recursion at work
|
|
return 0;
|
|
case 0x56: //Ctrl+V
|
|
MemViewCallB(hMemView,WM_COMMAND,202,0);
|
|
return 0;
|
|
case 0x5a: //Ctrl+Z
|
|
UndoLastPatch();
|
|
}
|
|
}
|
|
|
|
//if(CursorShiftPoint == -1){
|
|
if(wParam == VK_LEFT)CursorStartAddy--;
|
|
if(wParam == VK_RIGHT)CursorStartAddy++;
|
|
if(wParam == VK_UP)CursorStartAddy-=16;
|
|
if(wParam == VK_DOWN)CursorStartAddy+=16;
|
|
/*} else {
|
|
if(wParam == VK_LEFT)CursorShiftPoint--;
|
|
if(wParam == VK_RIGHT)CursorShiftPoint++;
|
|
if(wParam == VK_UP)CursorShiftPoint-=16;
|
|
if(wParam == VK_DOWN)CursorShiftPoint+=16;
|
|
if(CursorShiftPoint < CursorStartAddy){
|
|
if(CursorEndAddy == -1)CursorEndAddy = CursorStartAddy;
|
|
CursorStartAddy = CursorShiftPoint;
|
|
}
|
|
//if(CursorShiftPoint > CursorEndAddy)CursorEndAddy = CursorShiftPoint;
|
|
}*/
|
|
|
|
//if(CursorStartAddy == CursorEndAddy)CursorEndAddy = -1;
|
|
if(CursorStartAddy < 0)CursorStartAddy = 0;
|
|
if(CursorStartAddy >= MaxSize)CursorStartAddy = MaxSize-1; //todo: fix this up when I add support for editing more stuff
|
|
|
|
if((wParam == VK_DOWN) || (wParam == VK_UP) ||
|
|
(wParam == VK_RIGHT) || (wParam == VK_LEFT)){
|
|
CursorEndAddy = -1;
|
|
TempData = -1;
|
|
if(CursorStartAddy < CurOffset) CurOffset = (CursorStartAddy/16)*16;
|
|
if(CursorStartAddy > CurOffset+DataAmount-0x10)CurOffset = ((CursorStartAddy-DataAmount+0x10)/16)*16;
|
|
}
|
|
|
|
if(wParam == VK_PRIOR)CurOffset-=DataAmount;
|
|
if(wParam == VK_NEXT)CurOffset+=DataAmount;
|
|
if(CurOffset < 0)CurOffset = 0;
|
|
if(CurOffset >= MaxSize)CurOffset = MaxSize-1;
|
|
/*
|
|
if((wParam == VK_PRIOR) || (wParam == VK_NEXT)){
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.fMask = SIF_ALL;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
GetScrollInfo(hwnd,SB_VERT,&si);
|
|
if(wParam == VK_PRIOR)si.nPos-=si.nPage;
|
|
if(wParam == VK_NEXT)si.nPos+=si.nPage;
|
|
if (si.nPos < si.nMin) si.nPos = si.nMin;
|
|
if ((si.nPos+si.nPage) > si.nMax) si.nPos = si.nMax-si.nPage;
|
|
CurOffset = si.nPos*16;
|
|
}
|
|
*/
|
|
|
|
//This updates the scroll bar to curoffset
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.fMask = SIF_POS;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
si.nPos = CurOffset/16;
|
|
SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
|
|
UpdateColorTable();
|
|
UpdateCaption();
|
|
return 0;
|
|
/* case WM_KEYUP:
|
|
if((wParam == VK_LSHIFT) || (wParam == VK_RSHIFT)){
|
|
CursorShiftPoint = -1;
|
|
}
|
|
return 0;*/
|
|
case WM_LBUTTONDOWN:
|
|
//CursorShiftPoint = -1;
|
|
SetCapture(hwnd);
|
|
lbuttondown = 1;
|
|
x = GET_X_LPARAM(lParam);
|
|
y = GET_Y_LPARAM(lParam);
|
|
if((i = GetAddyFromCoord(x,y)) == -1)return 0;
|
|
EditingText = AddyWasText;
|
|
lbuttondownx = x;
|
|
lbuttondowny = y;
|
|
CursorStartAddy = CursorDragPoint = i;
|
|
CursorEndAddy = -1;
|
|
UpdateCaption();
|
|
UpdateColorTable();
|
|
return 0;
|
|
case WM_MOUSEMOVE:
|
|
mousex = x = GET_X_LPARAM(lParam);
|
|
mousey = y = GET_Y_LPARAM(lParam);
|
|
if(lbuttondown){
|
|
AutoScrollFromCoord(x,y);
|
|
i = GetAddyFromCoord(x,y);
|
|
if (i >= MaxSize)i = MaxSize-1;
|
|
EditingText = AddyWasText;
|
|
if(i != -1){
|
|
CursorStartAddy = min(i,CursorDragPoint);
|
|
CursorEndAddy = max(i,CursorDragPoint);
|
|
if(CursorEndAddy == CursorStartAddy)CursorEndAddy = -1;
|
|
}
|
|
|
|
UpdateCaption();
|
|
UpdateColorTable();
|
|
}
|
|
//sprintf(str,"%d %d",mousex, mousey);
|
|
//SetWindowText(hMemView,str);
|
|
return 0;
|
|
case WM_LBUTTONUP:
|
|
lbuttondown = 0;
|
|
if(CursorEndAddy == CursorStartAddy)CursorEndAddy = -1;
|
|
if((CursorEndAddy < CursorStartAddy) && (CursorEndAddy != -1)){ //this reverses them if they're not right
|
|
i = CursorStartAddy;
|
|
CursorStartAddy = CursorEndAddy;
|
|
CursorEndAddy = i;
|
|
}
|
|
UpdateCaption();
|
|
UpdateColorTable();
|
|
ReleaseCapture();
|
|
return 0;
|
|
case WM_CONTEXTMENU:
|
|
point.x = x = GET_X_LPARAM(lParam);
|
|
point.y = y = GET_Y_LPARAM(lParam);
|
|
ScreenToClient(hMemView,&point);
|
|
mousex = point.x;
|
|
mousey = point.y;
|
|
j = GetAddyFromCoord(mousex,mousey);
|
|
//sprintf(str,"x = %d, y = %d, j = %d",mousex,mousey,j);
|
|
//MessageBox(hMemView,str, "mouse wheel dance!", MB_OK);
|
|
hMenu = CreatePopupMenu();
|
|
for(i = 0;i < POPUPNUM;i++){
|
|
if((j >= popupmenu[i].minaddress) && (j <= popupmenu[i].maxaddress)
|
|
&& (EditingMode == popupmenu[i].editingmode)){
|
|
memset(&MenuInfo,0,sizeof(MENUITEMINFO));
|
|
switch(popupmenu[i].id){ //this will set the text for the menu dynamically based on the id
|
|
// ################################## Start of SP CODE ###########################
|
|
case 1:
|
|
{
|
|
HMENU sub = CreatePopupMenu();
|
|
AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)sub, "Freeze / Unfreeze Address");
|
|
AppendMenu(sub, MF_STRING, 1, "Toggle state");
|
|
AppendMenu(sub, MF_STRING, 50, "Freeze");
|
|
AppendMenu(sub, MF_STRING, 51, "Unfreeze");
|
|
AppendMenu(sub, MF_SEPARATOR, 52, "-");
|
|
AppendMenu(sub, MF_STRING, 53, "Unfreeze all");
|
|
|
|
continue;
|
|
}
|
|
// ################################## End of SP CODE ###########################
|
|
case 2 : //We want this to give the address to add the read breakpoint for
|
|
if((j <= CursorEndAddy) && (j >= CursorStartAddy))
|
|
sprintf(str,"Add Read Breakpoint For Address 0x%04X-0x%04X",CursorStartAddy,CursorEndAddy);
|
|
else
|
|
sprintf(str,"Add Read Breakpoint For Address 0x%04X",j);
|
|
popupmenu[i].text = str;
|
|
break;
|
|
|
|
case 3 :
|
|
if((j <= CursorEndAddy) && (j >= CursorStartAddy))
|
|
sprintf(str,"Add Write Breakpoint For Address 0x%04X-0x%04X",CursorStartAddy,CursorEndAddy);
|
|
else
|
|
sprintf(str,"Add Write Breakpoint For Address 0x%04X",j);
|
|
popupmenu[i].text = str;
|
|
break;
|
|
case 4 :
|
|
if((j <= CursorEndAddy) && (j >= CursorStartAddy))
|
|
sprintf(str,"Add Execute Breakpoint For Address 0x%04X-0x%04X",CursorStartAddy,CursorEndAddy);
|
|
else
|
|
sprintf(str,"Add Execute Breakpoint For Address 0x%04X",j);
|
|
popupmenu[i].text = str;
|
|
break;
|
|
}
|
|
MenuInfo.cbSize = sizeof(MENUITEMINFO);
|
|
MenuInfo.fMask = MIIM_TYPE | MIIM_ID | MIIM_DATA;
|
|
MenuInfo.fType = MF_STRING;
|
|
MenuInfo.dwTypeData = popupmenu[i].text;
|
|
MenuInfo.cch = strlen(popupmenu[i].text);
|
|
MenuInfo.wID = popupmenu[i].id;
|
|
InsertMenuItem(hMenu,i+1,1,&MenuInfo);
|
|
}
|
|
}
|
|
//InsertMenu(hMenu, 1, MF_STRING, 892, "Test");
|
|
if(i != 0)i = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, x, y, hMemView, NULL);
|
|
switch(i){
|
|
case 1 : //1 = Freeze Ram Address
|
|
// ################################## Start of SP CODE ###########################
|
|
{
|
|
int n;
|
|
for (n=CursorStartAddy;(CursorEndAddy == -1 && n == CursorStartAddy) || n<=CursorEndAddy;n++)
|
|
{
|
|
FreezeRam(n, 0, n == CursorEndAddy);
|
|
}
|
|
break;
|
|
}
|
|
case 50:
|
|
{
|
|
int n;
|
|
for (n=CursorStartAddy;(CursorEndAddy == -1 && n == CursorStartAddy) || n<=CursorEndAddy;n++)
|
|
{
|
|
FreezeRam(n, 1, n == CursorEndAddy);
|
|
}
|
|
break;
|
|
}
|
|
case 51:
|
|
{
|
|
int n;
|
|
for (n=CursorStartAddy;(CursorEndAddy == -1 && n == CursorStartAddy) || n<=CursorEndAddy;n++)
|
|
{
|
|
FreezeRam(n, -1, n == CursorEndAddy);
|
|
}
|
|
break;
|
|
}
|
|
case 53:
|
|
{
|
|
int n;
|
|
for (n=0;n<0x2000;n++)
|
|
{
|
|
FreezeRam(n, -1, 0);
|
|
}
|
|
for (n=0x6000;n<0x8000;n++)
|
|
{
|
|
FreezeRam(n, -1, n == 0x7FFF);
|
|
}
|
|
break;
|
|
}
|
|
// ################################## End of SP CODE ###########################
|
|
break;
|
|
|
|
case 2 : //2 = Add Read Breakpoint
|
|
watchpoint[numWPs].flags = WP_E | WP_R;
|
|
if(EditingMode == 1)watchpoint[numWPs].flags |= BT_P;
|
|
if((j <= CursorEndAddy) && (j >= CursorStartAddy)){
|
|
watchpoint[numWPs].address = CursorStartAddy;
|
|
watchpoint[numWPs].endaddress = CursorEndAddy;
|
|
}
|
|
else{
|
|
watchpoint[numWPs].address = j;
|
|
watchpoint[numWPs].endaddress = 0;
|
|
}
|
|
numWPs++;
|
|
// ################################## Start of SP CODE ###########################
|
|
{ extern int myNumWPs;
|
|
myNumWPs++; }
|
|
// ################################## End of SP CODE ###########################
|
|
if(hDebug)AddBreakList();
|
|
else DoDebug(0);
|
|
break;
|
|
|
|
case 3 : //3 = Add Write Breakpoint
|
|
watchpoint[numWPs].flags = WP_E | WP_W;
|
|
if(EditingMode == 1)watchpoint[numWPs].flags |= BT_P;
|
|
if((j <= CursorEndAddy) && (j >= CursorStartAddy)){
|
|
watchpoint[numWPs].address = CursorStartAddy;
|
|
watchpoint[numWPs].endaddress = CursorEndAddy;
|
|
}
|
|
else{
|
|
watchpoint[numWPs].address = j;
|
|
watchpoint[numWPs].endaddress = 0;
|
|
}
|
|
numWPs++;
|
|
// ################################## Start of SP CODE ###########################
|
|
{ extern int myNumWPs;
|
|
myNumWPs++; }
|
|
// ################################## End of SP CODE ###########################
|
|
if(hDebug)AddBreakList();
|
|
else DoDebug(0);
|
|
break;
|
|
case 4 : //4 = Add Execute Breakpoint
|
|
watchpoint[numWPs].flags = WP_E | WP_X;
|
|
if((j <= CursorEndAddy) && (j >= CursorStartAddy)){
|
|
watchpoint[numWPs].address = CursorStartAddy;
|
|
watchpoint[numWPs].endaddress = CursorEndAddy;
|
|
}
|
|
else{
|
|
watchpoint[numWPs].address = j;
|
|
watchpoint[numWPs].endaddress = 0;
|
|
}
|
|
numWPs++;
|
|
// ################################## Start of SP CODE ###########################
|
|
{ extern int myNumWPs;
|
|
myNumWPs++; }
|
|
// ################################## End of SP CODE ###########################
|
|
if(hDebug)AddBreakList();
|
|
else DoDebug(0);
|
|
break;
|
|
case 5 : //5 = Go Here In Rom File
|
|
ChangeMemViewFocus(2,GetNesFileAddress(j),-1);
|
|
break;
|
|
case 6 : //6 = Create GG Code
|
|
SetGGConvFocus(j,GetMem(j));
|
|
break;
|
|
// ################################## Start of SP CODE ###########################
|
|
case 20:
|
|
{
|
|
if (toggleBookmark(hwnd, CursorStartAddy))
|
|
{
|
|
MessageBox(hDebug, "Can't set more than 64 breakpoints", "Error", MB_OK | MB_ICONERROR);
|
|
}
|
|
else
|
|
{
|
|
updateBookmarkMenus(GetSubMenu(GetMenu(hwnd), 3));
|
|
UpdateColorTable();
|
|
}
|
|
}
|
|
break;
|
|
// ################################## End of SP CODE ###########################
|
|
}
|
|
//6 = Create GG Code
|
|
|
|
return 0;
|
|
case WM_MBUTTONDOWN:
|
|
x = GET_X_LPARAM(lParam);
|
|
y = GET_Y_LPARAM(lParam);
|
|
i = GetAddyFromCoord(x,y);
|
|
if(i == -1)return 0;
|
|
// ################################## Start of SP CODE ###########################
|
|
FreezeRam(i, 0, 1);
|
|
// ################################## End of SP CODE ###########################
|
|
return 0;
|
|
case WM_MOUSEWHEEL:
|
|
i = (short)HIWORD(wParam);///WHEEL_DELTA;
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.fMask = SIF_ALL;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
GetScrollInfo(hwnd,SB_VERT,&si);
|
|
if(i < 0)si.nPos+=si.nPage;
|
|
if(i > 0)si.nPos-=si.nPage;
|
|
if (si.nPos < si.nMin) si.nPos = si.nMin;
|
|
if ((si.nPos+(int)si.nPage) > si.nMax) si.nPos = si.nMax-si.nPage; //added cast
|
|
CurOffset = si.nPos*16;
|
|
SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
|
|
UpdateColorTable();
|
|
return 0;
|
|
|
|
case WM_SIZE:
|
|
StopSound();
|
|
ClientHeight = HIWORD (lParam) ;
|
|
if(DataAmount != ((ClientHeight/MemFontHeight)*16)){
|
|
DataAmount = ((ClientHeight/MemFontHeight)*16);
|
|
if(DataAmount+CurOffset > MaxSize)CurOffset = MaxSize-DataAmount;
|
|
//mbg merge 7/18/06 added casts:
|
|
TextColorList = (COLORREF*)realloc(TextColorList,DataAmount*sizeof(COLORREF));
|
|
BGColorList = (COLORREF*)realloc(BGColorList,DataAmount*sizeof(COLORREF));
|
|
OldValues = (int*)realloc(OldValues,(DataAmount)*sizeof(int));
|
|
for(i = 0;i < DataAmount;i++)OldValues[i] = -1;
|
|
}
|
|
//Set vertical scroll bar range and page size
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.cbSize = sizeof (si) ;
|
|
si.fMask = (SIF_RANGE|SIF_PAGE) ;
|
|
si.nMin = 0 ;
|
|
si.nMax = MaxSize/16 ;
|
|
si.nPage = ClientHeight/MemFontHeight;
|
|
SetScrollInfo (hwnd, SB_VERT, &si, TRUE);
|
|
UpdateColorTable();
|
|
return 0 ;
|
|
|
|
case WM_COMMAND:
|
|
StopSound();
|
|
|
|
// ################################## Start of SP CODE ###########################
|
|
if (wParam >= 30 && wParam <= 39)
|
|
{
|
|
int newValue = handleBookmarkMenu(wParam - 30);
|
|
|
|
if (newValue != -1)
|
|
{
|
|
CurOffset = newValue;
|
|
CursorEndAddy = -1;
|
|
CursorStartAddy = hexBookmarks[wParam - 30].address;
|
|
UpdateColorTable();
|
|
}
|
|
}
|
|
else if (wParam == 400)
|
|
{
|
|
removeAllBookmarks(GetSubMenu(GetMenu(hwnd), 3));
|
|
UpdateColorTable();
|
|
}
|
|
else if (wParam == 600)
|
|
{
|
|
MessageBox(0, "", "", 0);
|
|
}
|
|
// ################################## End of SP CODE ###########################
|
|
|
|
switch(wParam)
|
|
{
|
|
case 100:
|
|
FlushUndoBuffer();
|
|
iNesSave();
|
|
UpdateColorTable();
|
|
return 0;
|
|
|
|
case 101:
|
|
return 0;
|
|
|
|
case 102:
|
|
if((i = LoadTableFile()) != -1){
|
|
sprintf(str,"Error Loading Table File At Line %d",i);
|
|
MessageBox(hMemView,str,"error", MB_OK);
|
|
}
|
|
UpdateColorTable();
|
|
return 0;
|
|
|
|
case 103:
|
|
UnloadTableFile();
|
|
UpdateColorTable();
|
|
return 0;
|
|
|
|
// ################################## Start of SP CODE ###########################
|
|
case 104:
|
|
{
|
|
char bar[0x800];
|
|
unsigned int i;
|
|
for (i=0;i<sizeof(bar);i++) bar[i] = GetMem(i);
|
|
|
|
dumpToFile(bar, sizeof(bar));
|
|
return 0;
|
|
}
|
|
case 105:
|
|
{
|
|
char bar[0x4000];
|
|
unsigned int i;
|
|
for (i=0;i<sizeof(bar);i++)
|
|
{
|
|
// bar[i] = GetPPUMem(i);
|
|
i &= 0x3FFF;
|
|
if(i < 0x2000) bar[i] = VPage[(i)>>10][(i)];
|
|
else if(i < 0x3F00) bar[i] = vnapage[(i>>10)&0x3][i&0x3FF];
|
|
else bar[i] = PALRAM[i&0x1F];
|
|
}
|
|
dumpToFile(bar, sizeof(bar));
|
|
return 0;
|
|
}
|
|
// ################################## End of SP CODE ###########################
|
|
|
|
case 200: //undo
|
|
UndoLastPatch();
|
|
return 0;
|
|
|
|
case 201: //copy
|
|
if(CursorEndAddy == -1)i = 1;
|
|
else i = CursorEndAddy-CursorStartAddy+1;
|
|
|
|
hGlobal = GlobalAlloc (GHND,
|
|
(i*2)+1); //i*2 is two characters per byte, plus terminating null
|
|
|
|
pGlobal = (char*)GlobalLock (hGlobal) ; //mbg merge 7/18/06 added cast
|
|
if(!EditingText){
|
|
for(j = 0;j < i;j++){
|
|
str[0] = 0;
|
|
sprintf(str,"%02X",GetMemViewData(j+CursorStartAddy));
|
|
strcat(pGlobal,str);
|
|
}
|
|
} else {
|
|
for(j = 0;j < i;j++){
|
|
str[0] = 0;
|
|
sprintf(str,"%c",chartable[GetMemViewData(j+CursorStartAddy)]);
|
|
strcat(pGlobal,str);
|
|
}
|
|
}
|
|
GlobalUnlock (hGlobal);
|
|
OpenClipboard (hwnd) ;
|
|
EmptyClipboard () ;
|
|
SetClipboardData (CF_TEXT, hGlobal) ;
|
|
CloseClipboard () ;
|
|
return 0;
|
|
|
|
case 202: //paste
|
|
|
|
OpenClipboard(hwnd);
|
|
hGlobal = GetClipboardData(CF_TEXT);
|
|
if(hGlobal == NULL){
|
|
CloseClipboard();
|
|
return 0;
|
|
}
|
|
pGlobal = (char*)GlobalLock (hGlobal) ; //mbg merge 7/18/06 added cast
|
|
//for(i = 0;pGlobal[i] != 0;i++){
|
|
InputData(pGlobal);
|
|
//}
|
|
GlobalUnlock (hGlobal);
|
|
CloseClipboard();
|
|
return 0;
|
|
return 0;
|
|
|
|
case 203: //find
|
|
OpenFindDialog();
|
|
return 0;
|
|
|
|
|
|
case 300:
|
|
case 301:
|
|
case 302:
|
|
EditingMode = wParam-300;
|
|
for(i = 0;i < 3;i++){
|
|
if(EditingMode == i)CheckMenuItem(GetMenu(hMemView),300+i,MF_CHECKED);
|
|
else CheckMenuItem(GetMenu(hMemView),300+i,MF_UNCHECKED);
|
|
}
|
|
if(EditingMode == 0)MaxSize = 0x10000;
|
|
if(EditingMode == 1)MaxSize = 0x4000;
|
|
if(EditingMode == 2)MaxSize = 16+CHRsize[0]+PRGsize[0]; //todo: add trainer size
|
|
if(DataAmount+CurOffset > MaxSize)CurOffset = MaxSize-DataAmount;
|
|
if(CursorEndAddy > MaxSize)CursorEndAddy = -1;
|
|
if(CursorStartAddy > MaxSize)CursorStartAddy= MaxSize-1;
|
|
|
|
//Set vertical scroll bar range and page size
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.cbSize = sizeof (si) ;
|
|
si.fMask = (SIF_RANGE|SIF_PAGE) ;
|
|
si.nMin = 0 ;
|
|
si.nMax = MaxSize/16 ;
|
|
si.nPage = ClientHeight/MemFontHeight;
|
|
SetScrollInfo (hwnd, SB_VERT, &si, TRUE);
|
|
|
|
for(i = 0;i < DataAmount;i++)OldValues[i] = -1;
|
|
|
|
UpdateColorTable();
|
|
return 0;
|
|
}
|
|
|
|
case WM_MOVE:
|
|
StopSound();
|
|
return 0;
|
|
|
|
case WM_DESTROY :
|
|
KillMemView();
|
|
//ReleaseDC (hwnd, mDC) ;
|
|
//DestroyWindow(hMemView);
|
|
//UnregisterClass("MEMVIEW",fceu_hInstance);
|
|
//hMemView = 0;
|
|
return 0;
|
|
}
|
|
return DefWindowProc (hwnd, message, wParam, lParam) ;
|
|
}
|
|
|
|
|
|
|
|
void DoMemView() {
|
|
WNDCLASSEX wndclass ;
|
|
//static RECT al;
|
|
|
|
if (!GI) {
|
|
FCEUD_PrintError("You must have a game loaded before you can use the Memory Viewer.");
|
|
return;
|
|
}
|
|
if (GI->type==GIT_NSF) {
|
|
FCEUD_PrintError("Sorry, you can't yet use the Memory Viewer with NSFs.");
|
|
return;
|
|
}
|
|
|
|
if (!hMemView){
|
|
memset(&wndclass,0,sizeof(wndclass));
|
|
wndclass.cbSize=sizeof(WNDCLASSEX);
|
|
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
|
|
wndclass.lpfnWndProc = MemViewCallB ;
|
|
wndclass.cbClsExtra = 0 ;
|
|
wndclass.cbWndExtra = 0 ;
|
|
wndclass.hInstance = fceu_hInstance;
|
|
wndclass.hIcon = LoadIcon(fceu_hInstance, "FCEUXD_ICON");
|
|
wndclass.hIconSm = LoadIcon(fceu_hInstance, "FCEUXD_ICON");
|
|
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
|
|
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ;
|
|
wndclass.lpszMenuName = "MEMVIEWMENU" ; //TODO: add a menu
|
|
wndclass.lpszClassName = "MEMVIEW" ;
|
|
|
|
if(!RegisterClassEx(&wndclass)) {FCEUD_PrintError("Error Registering MEMVIEW Window Class."); return;}
|
|
|
|
hMemView = CreateWindowEx(0,"MEMVIEW","Memory Editor",
|
|
//WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS, /* Style */
|
|
WS_SYSMENU|WS_THICKFRAME|WS_VSCROLL,
|
|
CW_USEDEFAULT,CW_USEDEFAULT,625,242, /* X,Y ; Width, Height */
|
|
NULL,NULL,fceu_hInstance,NULL );
|
|
ShowWindow (hMemView, SW_SHOW) ;
|
|
UpdateCaption();
|
|
//hMemView = CreateDialog(fceu_hInstance,"MEMVIEW",NULL,MemViewCallB);
|
|
}
|
|
if (hMemView) {
|
|
SetWindowPos(hMemView,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
|
|
//UpdateMemView(0);
|
|
//MemViewDoBlit();
|
|
}
|
|
}
|
|
|
|
BOOL CALLBACK MemFindCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
|
|
switch(uMsg) {
|
|
case WM_INITDIALOG:
|
|
if(FindDirectionUp) CheckDlgButton(hwndDlg, 1003, BST_CHECKED);
|
|
else CheckDlgButton(hwndDlg, 1004, BST_CHECKED);
|
|
|
|
if(FindAsText) CheckDlgButton(hwndDlg, 1002, BST_CHECKED);
|
|
else CheckDlgButton(hwndDlg, 1001, BST_CHECKED);
|
|
|
|
if(FindTextBox[0])SetDlgItemText(hwndDlg,1000,FindTextBox);
|
|
|
|
SendDlgItemMessage(hwndDlg,1000,EM_SETLIMITTEXT,59,0);
|
|
break;
|
|
case WM_CREATE:
|
|
|
|
break;
|
|
case WM_PAINT:
|
|
break;
|
|
case WM_CLOSE:
|
|
case WM_QUIT:
|
|
GetDlgItemText(hMemFind,1000,FindTextBox,59);
|
|
DestroyWindow(hMemFind);
|
|
hMemFind = 0;
|
|
break;
|
|
case WM_MOVING:
|
|
break;
|
|
case WM_MOVE:
|
|
break;
|
|
case WM_RBUTTONDBLCLK:
|
|
case WM_RBUTTONDOWN:
|
|
break;
|
|
case WM_MOUSEMOVE:
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(HIWORD(wParam)) {
|
|
case BN_CLICKED:
|
|
switch(LOWORD(wParam)) {
|
|
case 1001 :
|
|
FindAsText=0;
|
|
break;
|
|
case 1002 :
|
|
FindAsText=1;
|
|
break;
|
|
|
|
case 1003 :
|
|
FindDirectionUp = 1;
|
|
break;
|
|
case 1004 :
|
|
FindDirectionUp = 0;
|
|
break;
|
|
case 1005 :
|
|
FindNext();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case WM_HSCROLL:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
void FindNext(){
|
|
char str[60];
|
|
unsigned char data[60];
|
|
int datasize = 0, i, j, inputc = -1, found;
|
|
|
|
if(hMemFind) GetDlgItemText(hMemFind,1000,str,59);
|
|
else strcpy(str,FindTextBox);
|
|
|
|
for(i = 0;str[i] != 0;i++){
|
|
if(!FindAsText){
|
|
if(inputc == -1){
|
|
if((str[i] >= 'a') && (str[i] <= 'f')) inputc = str[i]-('a'-0xA);
|
|
if((str[i] >= 'A') && (str[i] <= 'F')) inputc = str[i]-('A'-0xA);
|
|
if((str[i] >= '0') && (str[i] <= '9')) inputc = str[i]-'0';
|
|
} else {
|
|
if((str[i] >= 'a') && (str[i] <= 'f')) inputc = (inputc<<4)|(str[i]-('a'-0xA));
|
|
if((str[i] >= 'A') && (str[i] <= 'F')) inputc = (inputc<<4)|(str[i]-('A'-0xA));
|
|
if((str[i] >= '0') && (str[i] <= '9')) inputc = (inputc<<4)|(str[i]-'0');
|
|
|
|
if(((str[i] >= 'a') && (str[i] <= 'f')) ||
|
|
((str[i] >= 'A') && (str[i] <= 'F')) ||
|
|
((str[i] >= '0') && (str[i] <= '9'))){
|
|
data[datasize++] = inputc;
|
|
inputc = -1;
|
|
}
|
|
}
|
|
} else {
|
|
for(j = 0;j < 256;j++)if(chartable[j] == str[i])break;
|
|
if(j == 256)continue;
|
|
data[datasize++] = j;
|
|
}
|
|
}
|
|
|
|
if(datasize < 1){
|
|
MessageBox(hMemView,"Invalid String","Error", MB_OK);
|
|
return;
|
|
}
|
|
if(!FindDirectionUp){
|
|
for(i = CursorStartAddy+1;i+datasize < MaxSize;i++){
|
|
found = 1;
|
|
for(j = 0;j < datasize;j++){
|
|
if(GetMemViewData(i+j) != data[j])found = 0;
|
|
}
|
|
if(found == 1){
|
|
ChangeMemViewFocus(EditingMode,i, i+datasize-1);
|
|
return;
|
|
}
|
|
}
|
|
for(i = 0;i < CursorStartAddy;i++){
|
|
found = 1;
|
|
for(j = 0;j < datasize;j++){
|
|
if(GetMemViewData(i+j) != data[j])found = 0;
|
|
}
|
|
if(found == 1){
|
|
ChangeMemViewFocus(EditingMode,i, i+datasize-1);
|
|
return;
|
|
}
|
|
}
|
|
} else { //FindDirection is up
|
|
for(i = CursorStartAddy-1;i > 0;i--){
|
|
found = 1;
|
|
for(j = 0;j < datasize;j++){
|
|
if(GetMemViewData(i+j) != data[j])found = 0;
|
|
}
|
|
if(found == 1){
|
|
ChangeMemViewFocus(EditingMode,i, i+datasize-1);
|
|
return;
|
|
}
|
|
}
|
|
for(i = MaxSize-datasize;i > CursorStartAddy;i--){
|
|
found = 1;
|
|
for(j = 0;j < datasize;j++){
|
|
if(GetMemViewData(i+j) != data[j])found = 0;
|
|
}
|
|
if(found == 1){
|
|
ChangeMemViewFocus(EditingMode,i, i+datasize-1);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
MessageBox(hMemView,"String Not Found","Error", MB_OK);
|
|
return;
|
|
}
|
|
|
|
|
|
void OpenFindDialog(){
|
|
if((!hMemView) || (hMemFind))return;
|
|
hMemFind = CreateDialog(fceu_hInstance,"MEMVIEWFIND",hMemView,MemFindCallB);
|
|
return;
|
|
}
|