diff --git a/bsnes/Makefile b/bsnes/Makefile index 7f272a91..3b20cc03 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -65,6 +65,6 @@ clean: -@$(call delete,*.manifest) archive-all: - tar -cjf bsnes.tar.bz2 data gameboy libco nall obj out phoenix ruby snes ui ui-gameboy Makefile cc.bat clean.bat sync.sh + tar -cjf bsnes.tar.bz2 data gameboy libco nall obj out phoenix ruby snes ui ui-gameboy ui-libsnes Makefile cc.bat clean.bat sync.sh help:; diff --git a/bsnes/nall/public_cast.hpp b/bsnes/nall/public_cast.hpp index 35a528c4..dab437c4 100755 --- a/bsnes/nall/public_cast.hpp +++ b/bsnes/nall/public_cast.hpp @@ -2,19 +2,16 @@ #define NALL_PUBLIC_CAST_HPP //this is a proof-of-concept-*only* C++ access-privilege elevation exploit. -//it allows full access to both protected and private member variables, objects and functions -//from the global scope, regardless of inheritance and/or friendship privileges. -//the code itself is 100% legal C++, per C++98 section 14.7.2 paragraph 8: -//"Access checking rules do not apply to names in explicit instantiations." - -//C++0x variadic templates are used simply to allow public_cast name to be used -//on second derived class name for simplification, however the basic idea also -//works on C++98. - +//this code is 100% legal C++, per C++98 section 14.7.2 paragraph 8: +//"access checking rules do not apply to names in explicit instantiations." //usage example: + //struct N { typedef void (Class::*)(); }; -//template class public_cast; -//(class.*public_cast::value)(); +//template class public_cast; +//(class.*public_cast::value); + +//Class::Reference may be public, protected or private +//Class::Reference may be a function, object or variable namespace nall { template struct public_cast; @@ -26,13 +23,10 @@ namespace nall { template typename T::type public_cast::value; template struct public_cast : public_cast { - struct ref_t { - ref_t() { public_cast::value = P; } - }; - static ref_t ref; + static typename T::type value; }; - template typename public_cast::ref_t public_cast::ref; + template typename T::type public_cast::value = public_cast::value = P; } #endif diff --git a/bsnes/phoenix/gtk/hexeditor.cpp b/bsnes/phoenix/gtk/hexeditor.cpp index 3da8f3e1..2705a672 100755 --- a/bsnes/phoenix/gtk/hexeditor.cpp +++ b/bsnes/phoenix/gtk/hexeditor.cpp @@ -116,7 +116,7 @@ HexEditor::HexEditor() { //internal bool HexEditor::keyPress(unsigned scancode) { - if(!onRead && !onWrite) return false; + if(!onRead || !onWrite) return false; unsigned position = cursorPosition(); unsigned lineWidth = 10 + (hexEditor->columns * 3) + 1 + (hexEditor->columns) + 1; diff --git a/bsnes/phoenix/windows/editbox.cpp b/bsnes/phoenix/windows/editbox.cpp index 2d165b3a..06cb3368 100755 --- a/bsnes/phoenix/windows/editbox.cpp +++ b/bsnes/phoenix/windows/editbox.cpp @@ -30,6 +30,10 @@ void EditBox::setText(const string &text) { object->locked = false; } +void EditBox::setCursorPosition(unsigned position) { + Edit_SetSel(widget->window, position, position); +} + void EditBox::setEditable(bool editable) { SendMessage(widget->window, EM_SETREADONLY, editable == false, (LPARAM)0); } diff --git a/bsnes/phoenix/windows/hexeditor.cpp b/bsnes/phoenix/windows/hexeditor.cpp new file mode 100755 index 00000000..96dca950 --- /dev/null +++ b/bsnes/phoenix/windows/hexeditor.cpp @@ -0,0 +1,149 @@ +static LRESULT CALLBACK HexEditor_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + HexEditor &self = *(HexEditor*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch(msg) { + case WM_CHAR: { + if(self.keyPress(wparam)) return 0; + } + } + + return self.hexEditor->windowProc(hwnd, msg, wparam, lparam); +} + +void HexEditor::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) { + widget->window = CreateWindowEx( + WS_EX_CLIENTEDGE, + L"EDIT", L"", + WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, + x, y, width, height, + parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->monospaceFont), 0); + + hexEditor->windowProc = (LRESULT CALLBACK (*)(HWND, UINT, LPARAM, WPARAM))GetWindowLongPtr(widget->window, GWLP_WNDPROC); + SetWindowLongPtr(widget->window, GWLP_WNDPROC, (LONG_PTR)HexEditor_WindowProc); +} + +void HexEditor::setSize(unsigned size) { + hexEditor->size = size; + update(); +} + +void HexEditor::setOffset(unsigned offset) { + hexEditor->offset = offset; + update(); +} + +void HexEditor::setColumns(unsigned columns) { + hexEditor->columns = columns; + update(); +} + +void HexEditor::setRows(unsigned rows) { + hexEditor->rows = rows; + update(); +} + +void HexEditor::update() { + if(!onRead) { + SetWindowText(widget->window, L""); + return; + } + + //modifying text resets cursor position to zero, save position so we can restore it later + unsigned cursorPosition = Edit_GetSel(widget->window); + + string output; + unsigned offset = hexEditor->offset; + for(unsigned row = 0; row < hexEditor->rows; row++) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(unsigned column = 0; column < hexEditor->columns; column++) { + if(offset < hexEditor->size) { + uint8_t data = onRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 }; + ansidata.append(buffer); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= hexEditor->size) break; + if(row != hexEditor->rows - 1) output.append("\r\n"); + } + + SetWindowText(widget->window, utf16_t(output)); + Edit_SetSel(widget->window, LOWORD(cursorPosition), HIWORD(cursorPosition)); +} + +bool HexEditor::keyPress(unsigned scancode) { + if(!onRead || !onWrite) return false; + + unsigned position = LOWORD(Edit_GetSel(widget->window)); + unsigned lineWidth = 10 + (hexEditor->columns * 3) + 1 + (hexEditor->columns) + 2; + unsigned cursorY = position / lineWidth; + unsigned cursorX = position % lineWidth; + + //convert scancode to hex nibble + if(scancode >= '0' && scancode <= '9') scancode = scancode - '0'; + else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10; + else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10; + else return false; + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < hexEditor->columns) { + //not in ANSI region + unsigned offset = hexEditor->offset + (cursorY * hexEditor->columns + cursorX); + + if(offset >= hexEditor->size) return false; //do not edit past end of file + uint8_t data = onRead(offset); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (scancode << 0); + } else { + data = (data & 0x0f) | (scancode << 4); + } + onWrite(offset, data); + + //auto-advance cursor to next nibble/byte + position++; + if(cursorNibble && cursorX != hexEditor->columns - 1) position++; + Edit_SetSel(widget->window, position, position); + + //refresh output to reflect modified data + update(); + } + } + } + + return true; +} + +HexEditor::HexEditor() { + hexEditor = new HexEditor::Data; + hexEditor->windowProc = 0; + hexEditor->size = 0; + hexEditor->offset = 0; + hexEditor->columns = 16; + hexEditor->rows = 16; +} + +HexEditor::~HexEditor() { + delete[] hexEditor; +} diff --git a/bsnes/phoenix/windows/object.cpp b/bsnes/phoenix/windows/object.cpp index 747413eb..861d9204 100755 --- a/bsnes/phoenix/windows/object.cpp +++ b/bsnes/phoenix/windows/object.cpp @@ -53,6 +53,14 @@ struct EditBox::Data { unsigned height; }; +struct HexEditor::Data { + LRESULT CALLBACK (*windowProc)(HWND, UINT, LPARAM, WPARAM); + unsigned size; + unsigned offset; + unsigned columns; + unsigned rows; +}; + struct HorizontalSlider::Data { unsigned position; }; diff --git a/bsnes/phoenix/windows/windows.cpp b/bsnes/phoenix/windows/windows.cpp index 697f8eec..8fa7cde0 100755 --- a/bsnes/phoenix/windows/windows.cpp +++ b/bsnes/phoenix/windows/windows.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -19,6 +20,7 @@ namespace phoenix { #include "checkbox.cpp" #include "combobox.cpp" #include "editbox.cpp" +#include "hexeditor.cpp" #include "horizontalslider.cpp" #include "label.cpp" #include "listbox.cpp" @@ -45,7 +47,7 @@ void OS::initialize() { os = new OS::Data; os->proportionalFont = Font_createFont("Tahoma", 8, false, false); - os->monospaceFont = Font_createFont("Courier New", 8, false, false); + os->monospaceFont = Font_createFont("Lucida Console", 8, false, false); WNDCLASS wc; wc.cbClsExtra = 0; diff --git a/bsnes/phoenix/windows/windows.hpp b/bsnes/phoenix/windows/windows.hpp index cdd701c7..e242dc51 100755 --- a/bsnes/phoenix/windows/windows.hpp +++ b/bsnes/phoenix/windows/windows.hpp @@ -163,6 +163,7 @@ struct EditBox : Widget { void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = ""); nall::string getText(); void setText(const nall::string &text); + void setCursorPosition(unsigned position); void setEditable(bool editable = true); void setWordWrap(bool wordWrap = true); EditBox(); @@ -171,6 +172,23 @@ struct EditBox : Widget { Data *editBox; }; +struct HexEditor : Widget { + nall::function onRead; + nall::function onWrite; + void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height); + void setSize(unsigned size); + void setOffset(unsigned offset); + void setColumns(unsigned columns); + void setRows(unsigned rows); + void update(); + HexEditor(); + ~HexEditor(); +//private: + struct Data; + Data *hexEditor; + bool keyPress(unsigned scancode); +}; + struct HorizontalSlider : Widget { nall::function onChange; void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length); diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index ad2eb638..87042eef 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "075.01"; + static const char Version[] = "075.02"; static const unsigned SerializerVersion = 18; } }