BRIDGE: added DbgScriptGetBranchInfo
DBG: added branch info DBG: fixed a bug with comments in scripts DBG: fixed a bug with prepended spaces in scripts DBG: added script command 'nop' GUI: separate class RichTextPainter GUI: script syntax highlighting (jumps+calls+rets+comments) GUI: backgroundColor property in AbstractTableView GUI: added keyPressEvent handler (enter follows jumps & arrows select next command) in ScriptView
This commit is contained in:
parent
9b36423cdc
commit
5f9f3f88f9
|
@ -534,6 +534,11 @@ BRIDGE_IMPEXP void DbgScriptSetIp(int line)
|
|||
_dbg_sendmessage(DBG_SCRIPT_SETIP, (void*)(duint)line, 0);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool DbgScriptGetBranchInfo(int line, SCRIPTBRANCH* info)
|
||||
{
|
||||
return (bool)(duint)_dbg_sendmessage(DBG_SCRIPT_GETBRANCHINFO, (void*)(duint)line, info);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP void DbgSymbolEnum(duint base, CBSYMBOLENUM cbSymbolEnum, void* user)
|
||||
{
|
||||
SYMBOLCBINFO cbInfo;
|
||||
|
|
|
@ -117,6 +117,7 @@ enum DBGMSG
|
|||
DBG_SCRIPT_ABORT, // param1=unused, param2=unused
|
||||
DBG_SCRIPT_GETLINETYPE, // param1=int line, param2=unused
|
||||
DBG_SCRIPT_SETIP, // param1=int line, param2=unused
|
||||
DBG_SCRIPT_GETBRANCHINFO, // param1=int line, param2=SCRIPTBRANCH* info
|
||||
DBG_SYMBOL_ENUM, // param1=SYMBOLCBINFO* cbInfo, param2=unused
|
||||
DBG_ASSEMBLE_AT, // param1=duint addr, param2=const char* instruction
|
||||
DBG_MODBASE_FROM_NAME, // param1=const char* modname, param2=unused
|
||||
|
@ -137,6 +138,19 @@ enum SCRIPTLINETYPE
|
|||
lineempty,
|
||||
};
|
||||
|
||||
enum SCRIPTBRANCHTYPE
|
||||
{
|
||||
scriptnobranch,
|
||||
scriptjmp,
|
||||
scriptjnejnz,
|
||||
scriptjejz,
|
||||
scriptjbjl,
|
||||
scriptjajg,
|
||||
scriptjbejle,
|
||||
scriptjaejge,
|
||||
scriptcall
|
||||
};
|
||||
|
||||
enum DISASM_INSTRTYPE
|
||||
{
|
||||
instr_normal,
|
||||
|
@ -414,6 +428,13 @@ struct BASIC_INSTRUCTION_INFO
|
|||
bool branch; //jumps/calls
|
||||
};
|
||||
|
||||
struct SCRIPTBRANCH
|
||||
{
|
||||
SCRIPTBRANCHTYPE type;
|
||||
int dest;
|
||||
char branchlabel[256];
|
||||
};
|
||||
|
||||
//Debugger functions
|
||||
BRIDGE_IMPEXP const char* DbgInit();
|
||||
BRIDGE_IMPEXP bool DbgMemRead(duint va, unsigned char* dest, duint size);
|
||||
|
@ -454,6 +475,7 @@ BRIDGE_IMPEXP bool DbgScriptCmdExec(const char* command);
|
|||
BRIDGE_IMPEXP void DbgScriptAbort();
|
||||
BRIDGE_IMPEXP SCRIPTLINETYPE DbgScriptGetLineType(int line);
|
||||
BRIDGE_IMPEXP void DbgScriptSetIp(int line);
|
||||
BRIDGE_IMPEXP bool DbgScriptGetBranchInfo(int line, SCRIPTBRANCH* info);
|
||||
BRIDGE_IMPEXP void DbgSymbolEnum(duint base, CBSYMBOLENUM cbSymbolEnum, void* user);
|
||||
BRIDGE_IMPEXP bool DbgAssembleAt(duint addr, const char* instruction);
|
||||
BRIDGE_IMPEXP duint DbgModBaseFromName(const char* name);
|
||||
|
|
|
@ -596,6 +596,12 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
}
|
||||
break;
|
||||
|
||||
case DBG_SCRIPT_GETBRANCHINFO:
|
||||
{
|
||||
return (duint)scriptgetbranchinfo((int)(duint)param1, (SCRIPTBRANCH*)param2);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_SYMBOL_ENUM:
|
||||
{
|
||||
SYMBOLCBINFO* cbInfo=(SYMBOLCBINFO*)param1;
|
||||
|
@ -716,7 +722,7 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par
|
|||
int hEntry=(int)(uint)param1;
|
||||
pluginmenucall(hEntry);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -49,9 +49,19 @@ static int scriptlabelfind(const char* labelname)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int scriptinternalstep(int fromIp) //internal step routine
|
||||
{
|
||||
int maxIp=linemap.size(); //maximum ip
|
||||
if(fromIp>=maxIp) //script end
|
||||
return fromIp;
|
||||
while((linemap.at(fromIp).type==lineempty or linemap.at(fromIp).type==linecomment or linemap.at(fromIp).type==linelabel) and fromIp<maxIp) //skip empty lines
|
||||
fromIp++;
|
||||
fromIp++;
|
||||
return fromIp;
|
||||
}
|
||||
|
||||
static bool scriptcreatelinemap(const char* filename)
|
||||
{
|
||||
DWORD ticks=GetTickCount();
|
||||
HANDLE hFile=CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
||||
if(hFile==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
|
@ -80,7 +90,10 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
if(filedata[i]=='\r' and filedata[i+1]=='\n') //windows file
|
||||
{
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
strcpy(entry.raw, temp);
|
||||
int add=0;
|
||||
while(temp[add]==' ')
|
||||
add++;
|
||||
strcpy(entry.raw, temp+add);
|
||||
*temp=0;
|
||||
j=0;
|
||||
i++;
|
||||
|
@ -89,7 +102,10 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
else if(filedata[i]=='\n') //other file
|
||||
{
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
strcpy(entry.raw, temp);
|
||||
int add=0;
|
||||
while(temp[add]==' ')
|
||||
add++;
|
||||
strcpy(entry.raw, temp+add);
|
||||
*temp=0;
|
||||
j=0;
|
||||
linemap.push_back(entry);
|
||||
|
@ -97,7 +113,10 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
else if(j>=254)
|
||||
{
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
strcpy(entry.raw, temp);
|
||||
int add=0;
|
||||
while(temp[add]==' ')
|
||||
add++;
|
||||
strcpy(entry.raw, temp+add);
|
||||
*temp=0;
|
||||
j=0;
|
||||
linemap.push_back(entry);
|
||||
|
@ -113,7 +132,7 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
}
|
||||
efree(filedata, "createlinemap:filedata");
|
||||
unsigned int linemapsize=linemap.size();
|
||||
while(!*linemap.at(linemapsize-1).raw) //remove empty lines
|
||||
while(!*linemap.at(linemapsize-1).raw) //remove empty lines from the end
|
||||
{
|
||||
linemapsize--;
|
||||
linemap.pop_back();
|
||||
|
@ -121,6 +140,24 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
for(unsigned int i=0; i<linemapsize; i++)
|
||||
{
|
||||
LINEMAPENTRY cur=linemap.at(i);
|
||||
|
||||
//temp. remove comments from the raw line
|
||||
char line_comment[256]="";
|
||||
char* comment=strstr(&cur.raw[0], "//");
|
||||
if(comment && comment!=cur.raw) //only when the line doesnt start with a comment
|
||||
{
|
||||
if(*(comment-1)==' ') //space before comment
|
||||
{
|
||||
strcpy(line_comment, comment);
|
||||
*(comment-1)='\0';
|
||||
}
|
||||
else //no space before comment
|
||||
{
|
||||
strcpy(line_comment, comment);
|
||||
*comment=0;
|
||||
}
|
||||
}
|
||||
|
||||
int rawlen=strlen(cur.raw);
|
||||
if(!strlen(cur.raw)) //empty
|
||||
{
|
||||
|
@ -173,25 +210,30 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
else
|
||||
{
|
||||
cur.type=linecommand;
|
||||
const char* comment=strstr(cur.raw, "//"); //find comment
|
||||
if(comment)
|
||||
strncpy(cur.u.command, cur.raw, comment-cur.raw);
|
||||
else
|
||||
strcpy(cur.u.command, cur.raw);
|
||||
strcpy(cur.u.command, cur.raw);
|
||||
}
|
||||
|
||||
//append the comment to the raw line again
|
||||
if(*line_comment)
|
||||
sprintf(cur.raw+rawlen, " %s", line_comment);
|
||||
linemap.at(i)=cur;
|
||||
}
|
||||
linemapsize=linemap.size();
|
||||
for(unsigned int i=0; i<linemapsize; i++)
|
||||
{
|
||||
LINEMAPENTRY cur=linemap.at(i);
|
||||
if(cur.type==linebranch and !scriptlabelfind(cur.u.branch.branchlabel)) //invalid branch label
|
||||
if(linemap.at(i).type==linebranch) //invalid branch label
|
||||
{
|
||||
char message[256]="";
|
||||
sprintf(message, "Invalid branch label \"%s\" detected on line %d!", cur.u.branch.branchlabel, i+1);
|
||||
GuiScriptError(0, message);
|
||||
std::vector<LINEMAPENTRY>().swap(linemap);
|
||||
return false;
|
||||
int labelline=scriptlabelfind(linemap.at(i).u.branch.branchlabel);
|
||||
if(!labelline) //invalid branch label
|
||||
{
|
||||
char message[256]="";
|
||||
sprintf(message, "Invalid branch label \"%s\" detected on line %d!", linemap.at(i).u.branch.branchlabel, i+1);
|
||||
GuiScriptError(0, message);
|
||||
std::vector<LINEMAPENTRY>().swap(linemap);
|
||||
return false;
|
||||
}
|
||||
else //set the branch destination line
|
||||
linemap.at(i).u.branch.dest=scriptinternalstep(labelline);
|
||||
}
|
||||
}
|
||||
if(linemap.at(linemapsize-1).type==linecomment or linemap.at(linemapsize-1).type==linelabel) //label/comment on the end
|
||||
|
@ -202,21 +244,9 @@ static bool scriptcreatelinemap(const char* filename)
|
|||
strcpy(entry.u.command, "ret");
|
||||
linemap.push_back(entry);
|
||||
}
|
||||
dprintf("%ums to parse the script\n", GetTickCount()-ticks);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int scriptinternalstep(int fromIp) //internal step routine
|
||||
{
|
||||
int maxIp=linemap.size(); //maximum ip
|
||||
if(fromIp>=maxIp) //script end
|
||||
return fromIp;
|
||||
while((linemap.at(fromIp).type==lineempty or linemap.at(fromIp).type==linecomment or linemap.at(fromIp).type==linelabel) and fromIp<maxIp) //skip empty lines
|
||||
fromIp++;
|
||||
fromIp++;
|
||||
return fromIp;
|
||||
}
|
||||
|
||||
static bool scriptinternalbpget(int line) //internal bpget routine
|
||||
{
|
||||
int bpcount=scriptbplist.size();
|
||||
|
@ -304,6 +334,8 @@ static CMDRESULT scriptinternalcmdexec(const char* cmd)
|
|||
return STATUS_ERROR;
|
||||
else if(scriptisinternalcommand(cmd, "pause")) //pause the script
|
||||
return STATUS_PAUSE;
|
||||
else if(scriptisinternalcommand(cmd, "nop")) //do nothing
|
||||
return STATUS_CONTINUE;
|
||||
char command[deflen]="";
|
||||
strcpy(command, cmd);
|
||||
argformat(command);
|
||||
|
@ -591,6 +623,16 @@ void scriptreset()
|
|||
scriptsetip(0);
|
||||
}
|
||||
|
||||
bool scriptgetbranchinfo(int line, SCRIPTBRANCH* info)
|
||||
{
|
||||
if(!info or !line or line>(int)linemap.size()) //invalid line
|
||||
return false;
|
||||
if(linemap.at(line-1).type!=linebranch) //no branch
|
||||
return false;
|
||||
memcpy(info, &linemap.at(line-1).u.branch, sizeof(SCRIPTBRANCH));
|
||||
return true;
|
||||
}
|
||||
|
||||
CMDRESULT cbScriptLoad(int argc, char* argv[])
|
||||
{
|
||||
if(argc<2)
|
||||
|
|
|
@ -3,20 +3,6 @@
|
|||
|
||||
#include "command.h"
|
||||
|
||||
//enums
|
||||
enum SCRIPTBRANCHTYPE
|
||||
{
|
||||
scriptnobranch,
|
||||
scriptjmp,
|
||||
scriptjnejnz,
|
||||
scriptjejz,
|
||||
scriptjbjl,
|
||||
scriptjajg,
|
||||
scriptjbejle,
|
||||
scriptjaejge,
|
||||
scriptcall
|
||||
};
|
||||
|
||||
//structures
|
||||
struct SCRIPTBP
|
||||
{
|
||||
|
@ -24,12 +10,6 @@ struct SCRIPTBP
|
|||
bool silent; //do not show in GUI
|
||||
};
|
||||
|
||||
struct SCRIPTBRANCH
|
||||
{
|
||||
SCRIPTBRANCHTYPE type;
|
||||
char branchlabel[256];
|
||||
};
|
||||
|
||||
struct LINEMAPENTRY
|
||||
{
|
||||
SCRIPTLINETYPE type;
|
||||
|
@ -55,6 +35,7 @@ void scriptabort();
|
|||
SCRIPTLINETYPE scriptgetlinetype(int line);
|
||||
void scriptsetip(int line);
|
||||
void scriptreset();
|
||||
bool scriptgetbranchinfo(int line, SCRIPTBRANCH* info);
|
||||
|
||||
//script commands
|
||||
CMDRESULT cbScriptLoad(int argc, char* argv[]);
|
||||
|
|
|
@ -61,7 +61,8 @@ SOURCES += \
|
|||
Src/Gui/SettingsDialog.cpp \
|
||||
Src/Gui/ExceptionRangeDialog.cpp \
|
||||
Src/Gui/tabbar.cpp \
|
||||
Src/Gui/tabwidget.cpp
|
||||
Src/Gui/tabwidget.cpp \
|
||||
Src/BasicView/RichTextPainter.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
|
@ -103,7 +104,9 @@ HEADERS += \
|
|||
Src/Gui/SettingsDialog.h \
|
||||
Src/Gui/ExceptionRangeDialog.h \
|
||||
Src/Gui/tabbar.h \
|
||||
Src/Gui/tabwidget.h
|
||||
Src/Gui/tabwidget.h \
|
||||
Src/BasicView/RichTextPainter.h
|
||||
|
||||
|
||||
INCLUDEPATH += \
|
||||
Src \
|
||||
|
|
|
@ -19,6 +19,7 @@ AbstractTableView::AbstractTableView(QWidget *parent) : QAbstractScrollArea(pare
|
|||
font.setStyleHint(QFont::Monospace);
|
||||
this->setFont(font);
|
||||
|
||||
backgroundColor=QColor(255, 251, 240);
|
||||
|
||||
int wRowsHeight = QFontMetrics(this->font()).height();
|
||||
wRowsHeight = (wRowsHeight * 105) / 100;
|
||||
|
@ -75,7 +76,7 @@ void AbstractTableView::paintEvent(QPaintEvent* event)
|
|||
}
|
||||
|
||||
// Paints background
|
||||
wPainter.fillRect(wPainter.viewport(), QBrush(QColor(255, 251, 240)));
|
||||
wPainter.fillRect(wPainter.viewport(), QBrush(backgroundColor));
|
||||
|
||||
// Paints header
|
||||
if(mHeader.isVisible == true)
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <qdebug.h>
|
||||
#include <NewTypes.h>
|
||||
|
||||
|
||||
class AbstractTableView : public QAbstractScrollArea
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -144,6 +143,9 @@ private:
|
|||
bool mShouldReload;
|
||||
|
||||
ScrollBar64_t mScrollBarAttributes;
|
||||
|
||||
protected:
|
||||
QColor backgroundColor;
|
||||
};
|
||||
|
||||
#endif // ABSTRACTTABLEVIEW_H
|
||||
|
|
|
@ -37,55 +37,6 @@ Disassembly::Disassembly(QWidget *parent) : AbstractTableView(parent)
|
|||
connect(Bridge::getBridge(), SIGNAL(repaintGui()), this, SLOT(reloadData()));
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Private Functions
|
||||
************************************************************************************/
|
||||
|
||||
void Disassembly::paintRichText(QPainter* painter, int x, int y, int w, int h, int xinc, const QList<CustomRichText_t>* richText)
|
||||
{
|
||||
int len=richText->size();
|
||||
int charwidth=QFontMetrics(this->font()).width(QChar(' '));
|
||||
for(int i=0; i<len; i++)
|
||||
{
|
||||
CustomRichText_t curRichText=richText->at(i);
|
||||
int curRichTextLength=curRichText.text.length();
|
||||
int backgroundWidth=charwidth*curRichTextLength;
|
||||
if(backgroundWidth+xinc>w)
|
||||
backgroundWidth=w-xinc;
|
||||
if(backgroundWidth<=0) //stop drawing when going outside the specified width
|
||||
break;
|
||||
switch(curRichText.flags)
|
||||
{
|
||||
case FlagNone: //defaults
|
||||
painter->drawText(QRect(x+xinc, y, w-xinc, h), 0, curRichText.text);
|
||||
break;
|
||||
case FlagColor: //color only
|
||||
painter->save();
|
||||
painter->setPen(QPen(curRichText.textColor));
|
||||
painter->drawText(QRect(x+xinc, y, w-xinc, h), 0, curRichText.text);
|
||||
painter->restore();
|
||||
break;
|
||||
case FlagBackground: //background only
|
||||
painter->save();
|
||||
if(backgroundWidth>0)
|
||||
painter->fillRect(QRect(x+xinc, y, backgroundWidth, h), QBrush(curRichText.textBackground));
|
||||
painter->drawText(QRect(x+xinc, y, w-xinc, h), 0, curRichText.text);
|
||||
painter->restore();
|
||||
break;
|
||||
case FlagAll: //color+background
|
||||
painter->save();
|
||||
if(backgroundWidth>0)
|
||||
painter->fillRect(QRect(x+xinc, y, backgroundWidth, h), QBrush(curRichText.textBackground));
|
||||
painter->setPen(QPen(curRichText.textColor));
|
||||
painter->drawText(QRect(x+xinc, y, w-xinc, h), 0, curRichText.text);
|
||||
painter->restore();
|
||||
break;
|
||||
}
|
||||
xinc+=charwidth*curRichTextLength;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
Reimplemented Functions
|
||||
************************************************************************************/
|
||||
|
@ -286,7 +237,7 @@ QString Disassembly::paintContent(QPainter* painter, int_t rowBase, int rowOffse
|
|||
|
||||
QList<CustomRichText_t> richText;
|
||||
BeaHighlight::PrintRtfInstruction(&richText, &mInstBuffer.at(rowOffset).disasm);
|
||||
Disassembly::paintRichText(painter, x + loopsize, y, getColumnWidth(col) - loopsize, getRowHeight(), 4, &richText);
|
||||
RichTextPainter::paintRichText(painter, x + loopsize, y, getColumnWidth(col) - loopsize, getRowHeight(), 4, &richText, QFontMetrics(this->font()).width(QChar(' ')));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "AbstractTableView.h"
|
||||
#include "QBeaEngine.h"
|
||||
#include "BeaHighlight.h"
|
||||
#include "RichTextPainter.h"
|
||||
|
||||
class Disassembly : public AbstractTableView
|
||||
{
|
||||
|
@ -15,9 +16,6 @@ class Disassembly : public AbstractTableView
|
|||
public:
|
||||
explicit Disassembly(QWidget *parent = 0);
|
||||
|
||||
// Private Functions
|
||||
void paintRichText(QPainter* painter, int x, int y, int w, int h, int xinc, const QList<CustomRichText_t>* richText);
|
||||
|
||||
// Reimplemented Functions
|
||||
QString paintContent(QPainter* painter, int_t rowBase, int rowOffset, int col, int x, int y, int w, int h);
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#include "RichTextPainter.h"
|
||||
|
||||
void RichTextPainter::paintRichText(QPainter* painter, int x, int y, int w, int h, int xinc, const QList<CustomRichText_t>* richText, int charwidth)
|
||||
{
|
||||
int len=richText->size();
|
||||
for(int i=0; i<len; i++)
|
||||
{
|
||||
CustomRichText_t curRichText=richText->at(i);
|
||||
int curRichTextLength=curRichText.text.length();
|
||||
int backgroundWidth=charwidth*curRichTextLength;
|
||||
if(backgroundWidth+xinc>w)
|
||||
backgroundWidth=w-xinc;
|
||||
if(backgroundWidth<=0) //stop drawing when going outside the specified width
|
||||
break;
|
||||
switch(curRichText.flags)
|
||||
{
|
||||
case FlagNone: //defaults
|
||||
painter->drawText(QRect(x+xinc, y, w-xinc, h), 0, curRichText.text);
|
||||
break;
|
||||
case FlagColor: //color only
|
||||
painter->save();
|
||||
painter->setPen(QPen(curRichText.textColor));
|
||||
painter->drawText(QRect(x+xinc, y, w-xinc, h), 0, curRichText.text);
|
||||
painter->restore();
|
||||
break;
|
||||
case FlagBackground: //background only
|
||||
painter->save();
|
||||
if(backgroundWidth>0)
|
||||
painter->fillRect(QRect(x+xinc, y, backgroundWidth, h), QBrush(curRichText.textBackground));
|
||||
painter->drawText(QRect(x+xinc, y, w-xinc, h), 0, curRichText.text);
|
||||
painter->restore();
|
||||
break;
|
||||
case FlagAll: //color+background
|
||||
painter->save();
|
||||
if(backgroundWidth>0)
|
||||
painter->fillRect(QRect(x+xinc, y, backgroundWidth, h), QBrush(curRichText.textBackground));
|
||||
painter->setPen(QPen(curRichText.textColor));
|
||||
painter->drawText(QRect(x+xinc, y, w-xinc, h), 0, curRichText.text);
|
||||
painter->restore();
|
||||
break;
|
||||
}
|
||||
xinc+=charwidth*curRichTextLength;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef RICHTEXTPAINTER_H
|
||||
#define RICHTEXTPAINTER_H
|
||||
|
||||
#include <QList>
|
||||
#include <QPainter>
|
||||
|
||||
//structures
|
||||
enum CustomRichTextFlags
|
||||
{
|
||||
FlagNone,
|
||||
FlagColor,
|
||||
FlagBackground,
|
||||
FlagAll
|
||||
};
|
||||
|
||||
typedef struct _CustomRichText_t
|
||||
{
|
||||
QString text;
|
||||
QColor textColor;
|
||||
QColor textBackground;
|
||||
CustomRichTextFlags flags;
|
||||
} CustomRichText_t;
|
||||
|
||||
class RichTextPainter
|
||||
{
|
||||
public:
|
||||
//functions
|
||||
static void paintRichText(QPainter* painter, int x, int y, int w, int h, int xinc, const QList<CustomRichText_t>* richText, int charwidth);
|
||||
};
|
||||
|
||||
#endif // RICHTEXTPAINTER_H
|
|
@ -67,17 +67,150 @@ QString ScriptView::paintContent(QPainter* painter, int_t rowBase, int rowOffset
|
|||
|
||||
case 1: //command
|
||||
{
|
||||
//initialize
|
||||
painter->save();
|
||||
if(linetype==linecomment || linetype==linelabel)
|
||||
painter->setPen(QPen(QColor("#808080"))); //grey text
|
||||
if(linetype!=linelabel)
|
||||
returnString=QString(" ") + getCellContent(rowBase+rowOffset, col);
|
||||
else //label
|
||||
int charwidth=QFontMetrics(this->font()).width(QChar(' '));
|
||||
int xadd=charwidth; //for testing
|
||||
QList<CustomRichText_t> richText;
|
||||
CustomRichText_t newRichText;
|
||||
QString command=getCellContent(rowBase+rowOffset, col);
|
||||
|
||||
//handle comments
|
||||
int comment_idx=command.indexOf("//"); //find the index of the space
|
||||
QString comment="";
|
||||
if(comment_idx!=-1 && command.at(0)!=QChar('/')) //there is a comment
|
||||
{
|
||||
returnString=getCellContent(rowBase+rowOffset, col);
|
||||
painter->drawLine(QPoint(x+2, y+h-2), QPoint(x+w-4, y+h-2));
|
||||
comment=command.right(command.length()-comment_idx);
|
||||
if(command.at(comment_idx-1)==QChar(' '))
|
||||
command.truncate(comment_idx-1);
|
||||
else
|
||||
command.truncate(comment_idx);
|
||||
}
|
||||
painter->drawText(QRect(x+1, y , w , h), Qt::AlignVCenter | Qt::AlignLeft, returnString);
|
||||
|
||||
//setup the richText list
|
||||
switch(linetype)
|
||||
{
|
||||
case linecommand:
|
||||
{
|
||||
if(isScriptCommand(command, "ret"))
|
||||
{
|
||||
newRichText.flags=FlagBackground;
|
||||
newRichText.textBackground=QColor(0,255,255);
|
||||
newRichText.text="ret";
|
||||
richText.push_back(newRichText);
|
||||
QString remainder=command.right(command.length()-3);
|
||||
if(remainder.length())
|
||||
{
|
||||
newRichText.flags=FlagNone;
|
||||
newRichText.text=remainder;
|
||||
richText.push_back(newRichText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newRichText.flags=FlagNone;
|
||||
newRichText.text=command;
|
||||
richText.push_back(newRichText);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case linebranch:
|
||||
{
|
||||
SCRIPTBRANCH branchinfo;
|
||||
DbgScriptGetBranchInfo(line, &branchinfo);
|
||||
//jumps
|
||||
int i=command.indexOf(" "); //find the index of the space
|
||||
switch(branchinfo.type)
|
||||
{
|
||||
case scriptjmp: //unconditional jumps
|
||||
newRichText.flags=FlagBackground;
|
||||
newRichText.textBackground=QColor(255,255,0);
|
||||
break;
|
||||
|
||||
case scriptjnejnz: //conditional jumps
|
||||
case scriptjejz:
|
||||
case scriptjbjl:
|
||||
case scriptjajg:
|
||||
case scriptjbejle:
|
||||
case scriptjaejge:
|
||||
newRichText.flags=FlagAll;
|
||||
newRichText.textBackground=QColor(255,255,0);
|
||||
newRichText.textColor=QColor(255,0,0);
|
||||
break;
|
||||
|
||||
case scriptcall: //calls
|
||||
newRichText.flags=FlagBackground;
|
||||
newRichText.textBackground=QColor(0,255,255);
|
||||
break;
|
||||
|
||||
default:
|
||||
newRichText.flags=FlagNone;
|
||||
break;
|
||||
}
|
||||
newRichText.text=command.left(i);
|
||||
richText.push_back(newRichText);
|
||||
//space
|
||||
newRichText.flags=FlagNone;
|
||||
newRichText.text=" ";
|
||||
richText.push_back(newRichText);
|
||||
//label
|
||||
QString label=branchinfo.branchlabel;
|
||||
newRichText.flags=FlagBackground;
|
||||
newRichText.textBackground=QColor(255,255,0);
|
||||
newRichText.text=label;
|
||||
richText.push_back(newRichText);
|
||||
//remainder
|
||||
QString remainder=command.right(command.length()-command.indexOf(label)-label.length());
|
||||
if(remainder.length())
|
||||
{
|
||||
newRichText.flags=FlagNone;
|
||||
newRichText.text=remainder;
|
||||
richText.push_back(newRichText);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case linelabel:
|
||||
{
|
||||
newRichText.flags=FlagColor;
|
||||
newRichText.textColor=QColor("#808080");
|
||||
newRichText.text=command;
|
||||
richText.push_back(newRichText);
|
||||
painter->drawLine(QPoint(x+xadd+2, y+h-2), QPoint(x+w-4, y+h-2));
|
||||
}
|
||||
break;
|
||||
|
||||
case linecomment:
|
||||
{
|
||||
newRichText.flags=FlagColor;
|
||||
newRichText.textColor=QColor("#808080");
|
||||
newRichText.text=command;
|
||||
richText.push_back(newRichText);
|
||||
}
|
||||
break;
|
||||
|
||||
case lineempty:
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//append the comment (when present)
|
||||
if(comment.length())
|
||||
{
|
||||
CustomRichText_t newRichText;
|
||||
newRichText.flags=FlagNone;
|
||||
newRichText.text=" ";
|
||||
richText.push_back(newRichText); //space
|
||||
newRichText.flags=FlagColor;
|
||||
newRichText.textColor=QColor("#808080");
|
||||
newRichText.text=comment;
|
||||
richText.push_back(newRichText); //comment
|
||||
}
|
||||
|
||||
//paint the rich text
|
||||
RichTextPainter::paintRichText(painter, x+1, y, w, h, xadd, &richText, charwidth);
|
||||
painter->restore();
|
||||
returnString="";
|
||||
}
|
||||
|
@ -119,6 +252,41 @@ void ScriptView::mouseDoubleClickEvent(QMouseEvent* event)
|
|||
newIp();
|
||||
}
|
||||
|
||||
void ScriptView::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
int key = event->key();
|
||||
if(key == Qt::Key_Up || key == Qt::Key_Down)
|
||||
{
|
||||
int_t botRVA = getTableOffset();
|
||||
int_t topRVA = botRVA + getNbrOfLineToPrint() - 1;
|
||||
if(key == Qt::Key_Up)
|
||||
selectPrevious();
|
||||
else
|
||||
selectNext();
|
||||
if(getInitialSelection() < botRVA)
|
||||
{
|
||||
setTableOffset(getInitialSelection());
|
||||
}
|
||||
else if(getInitialSelection() >= topRVA)
|
||||
{
|
||||
setTableOffset(getInitialSelection() - getNbrOfLineToPrint() + 2);
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
else if(key == Qt::Key_Return || key == Qt::Key_Enter)
|
||||
{
|
||||
int line=getInitialSelection()+1;
|
||||
SCRIPTBRANCH branchinfo;
|
||||
memset(&branchinfo, 0, sizeof(SCRIPTBRANCH));
|
||||
if(DbgScriptGetBranchInfo(line, &branchinfo))
|
||||
setSelection(branchinfo.dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
AbstractTableView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptView::setupContextMenu()
|
||||
{
|
||||
mLoadMenu = new QMenu("Load Script", this);
|
||||
|
@ -178,6 +346,19 @@ void ScriptView::setupContextMenu()
|
|||
connect(mScriptNewIp, SIGNAL(triggered()), this, SLOT(newIp()));
|
||||
}
|
||||
|
||||
bool ScriptView::isScriptCommand(QString text, QString cmd)
|
||||
{
|
||||
int len=text.length();
|
||||
int cmdlen=cmd.length();
|
||||
if(cmdlen>len)
|
||||
return false;
|
||||
else if(cmdlen==len)
|
||||
return (text.compare(cmd, Qt::CaseInsensitive)==0);
|
||||
else if(text.at(cmdlen)==' ')
|
||||
return (text.left(cmdlen).compare(cmd, Qt::CaseInsensitive)==0);
|
||||
return false;
|
||||
}
|
||||
|
||||
//slots
|
||||
void ScriptView::add(int count, const char** lines)
|
||||
{
|
||||
|
@ -215,6 +396,21 @@ void ScriptView::setIp(int line)
|
|||
reloadData(); //repaint
|
||||
}
|
||||
|
||||
void ScriptView::setSelection(int line)
|
||||
{
|
||||
int offset=line-1;
|
||||
if(!isValidIndex(offset, 0))
|
||||
return;
|
||||
int rangefrom=getTableOffset();
|
||||
int rangeto=rangefrom+getViewableRowsCount()-1;
|
||||
if(offset<rangefrom) //ip lays before the current view
|
||||
setTableOffset(offset);
|
||||
else if(offset>(rangeto-1)) //ip lays after the current view
|
||||
setTableOffset(offset-getViewableRowsCount()+2);
|
||||
setSingleSelection(offset);
|
||||
reloadData(); //repaint
|
||||
}
|
||||
|
||||
void ScriptView::error(int line, QString message)
|
||||
{
|
||||
QString title;
|
||||
|
|
|
@ -20,6 +20,7 @@ public:
|
|||
QString paintContent(QPainter* painter, int_t rowBase, int rowOffset, int col, int x, int y, int w, int h);
|
||||
void contextMenuEvent(QContextMenuEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
public slots:
|
||||
void add(int count, const char** lines);
|
||||
|
@ -43,6 +44,8 @@ public slots:
|
|||
private:
|
||||
//private functions
|
||||
void setupContextMenu();
|
||||
void setSelection(int line);
|
||||
bool isScriptCommand(QString text, QString cmd);
|
||||
|
||||
//private variables
|
||||
int mIpLine;
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
#include "BeaHighlight.h"
|
||||
|
||||
BeaHighlight::BeaHighlight()
|
||||
{
|
||||
}
|
||||
|
||||
SEGMENTREG BeaHighlight::ConvertBeaSeg(int beaSeg)
|
||||
{
|
||||
switch(beaSeg)
|
||||
|
|
|
@ -2,27 +2,11 @@
|
|||
#define BEAHIGHLIGHT_H
|
||||
|
||||
#include "QBeaEngine.h"
|
||||
|
||||
enum CustomRichTextFlags
|
||||
{
|
||||
FlagNone,
|
||||
FlagColor,
|
||||
FlagBackground,
|
||||
FlagAll
|
||||
};
|
||||
|
||||
typedef struct _CustomRichText_t
|
||||
{
|
||||
QString text;
|
||||
QColor textColor;
|
||||
QColor textBackground;
|
||||
CustomRichTextFlags flags;
|
||||
} CustomRichText_t;
|
||||
#include "RichTextPainter.h"
|
||||
|
||||
class BeaHighlight
|
||||
{
|
||||
public:
|
||||
BeaHighlight();
|
||||
static void PrintRtfInstruction(QList<CustomRichText_t>* richText, const DISASM* MyDisasm);
|
||||
private:
|
||||
static SEGMENTREG ConvertBeaSeg(int beaSeg);
|
||||
|
|
Loading…
Reference in New Issue