mirror of https://github.com/bsnes-emu/bsnes.git
Update to v095r11 release.
byuu says: Changelog: - SFC: "uint8 read(uint addr)" -> "uint8 read(uint addr, uint8 data)" - hiro: mHorizontalLayout::setGeometry() return value - hiro/GTK: ListView,TreeView::setFocused() does not grab focus of first item Notes: - nall/windows/utf8.hpp needs using uint = unsigned; at the top to compile - sfc/balanced, sfc/performance won't compile yet Seems Cx4 games broke a while back. Not from this WIP, either. I'll go back and find out what's wrong now.
This commit is contained in:
parent
78d49d3873
commit
f2a416aea9
|
@ -7,7 +7,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "095.10";
|
||||
static const string Version = "095.11";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#if defined(Hiro_Object)
|
||||
struct Object : sObject {
|
||||
DeclareSharedObject(Object)
|
||||
using internalType = mObject;
|
||||
|
||||
template<typename T> auto cast() -> T {
|
||||
if(auto pointer = dynamic_cast<typename T::internalType*>(data())) {
|
||||
|
@ -73,14 +74,23 @@ struct Object : sObject {
|
|||
#if defined(Hiro_Group)
|
||||
struct Group : sGroup {
|
||||
DeclareShared(Group)
|
||||
using internalType = mGroup;
|
||||
template<typename... P> Group(P&&... p) : Group() { _append(std::forward<P>(p)...); }
|
||||
|
||||
auto append(sObject object) -> type& { return self().append(object), *this; }
|
||||
auto object(unsigned position) const { return self().object(position); }
|
||||
auto objectCount() const { return self().objectCount(); }
|
||||
auto objects() const { return self().objects(); }
|
||||
//auto objects() const { return self().objects(); }
|
||||
auto remove(sObject object) -> type& { return self().remove(object), *this; }
|
||||
|
||||
template<typename T = Object> auto objects() const -> vector<T> {
|
||||
vector<T> objects;
|
||||
for(auto object : self().objects()) {
|
||||
if(auto cast = object.cast<T>()) objects.append(cast);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
private:
|
||||
auto _append() {}
|
||||
template<typename T, typename... P> auto _append(T* object, P&&... p) {
|
||||
|
@ -93,6 +103,7 @@ private:
|
|||
#if defined(Hiro_Timer)
|
||||
struct Timer : sTimer {
|
||||
DeclareSharedObject(Timer)
|
||||
using internalType = mTimer;
|
||||
|
||||
auto doActivate() const { return self().doActivate(); }
|
||||
auto interval() const { return self().interval(); }
|
||||
|
@ -104,12 +115,14 @@ struct Timer : sTimer {
|
|||
#if defined(Hiro_Action)
|
||||
struct Action : sAction {
|
||||
DeclareSharedAction(Action)
|
||||
using internalType = mAction;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Menu)
|
||||
struct Menu : sMenu {
|
||||
DeclareSharedAction(Menu)
|
||||
using internalType = mMenu;
|
||||
|
||||
auto action(unsigned position) const { return self().action(position); }
|
||||
auto actionCount() const { return self().actionCount(); }
|
||||
|
@ -127,12 +140,14 @@ struct Menu : sMenu {
|
|||
#if defined(Hiro_MenuSeparator)
|
||||
struct MenuSeparator : sMenuSeparator {
|
||||
DeclareSharedAction(MenuSeparator)
|
||||
using internalType = mMenuSeparator;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_MenuItem)
|
||||
struct MenuItem : sMenuItem {
|
||||
DeclareSharedAction(MenuItem)
|
||||
using internalType = mMenuItem;
|
||||
|
||||
auto doActivate() const { return self().doActivate(); }
|
||||
auto image() const { return self().image(); }
|
||||
|
@ -146,6 +161,7 @@ struct MenuItem : sMenuItem {
|
|||
#if defined(Hiro_MenuCheckItem)
|
||||
struct MenuCheckItem : sMenuCheckItem {
|
||||
DeclareSharedAction(MenuCheckItem)
|
||||
using internalType = mMenuCheckItem;
|
||||
|
||||
auto checked() const { return self().checked(); }
|
||||
auto doToggle() const { return self().doToggle(); }
|
||||
|
@ -174,24 +190,28 @@ struct MenuRadioItem : sMenuRadioItem {
|
|||
#if defined(Hiro_Sizable)
|
||||
struct Sizable : sSizable {
|
||||
DeclareSharedSizable(Sizable)
|
||||
using internalType = mSizable;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Layout)
|
||||
struct Layout : sLayout {
|
||||
DeclareSharedLayout(Layout)
|
||||
using internalType = mLayout;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Widget)
|
||||
struct Widget : sWidget {
|
||||
DeclareSharedWidget(Widget)
|
||||
using internalType = mWidget;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Button)
|
||||
struct Button : sButton {
|
||||
DeclareSharedWidget(Button)
|
||||
using internalType = mButton;
|
||||
|
||||
auto bordered() const { return self().bordered(); }
|
||||
auto doActivate() const { return self().doActivate(); }
|
||||
|
@ -209,6 +229,7 @@ struct Button : sButton {
|
|||
#if defined(Hiro_Canvas)
|
||||
struct Canvas : sCanvas {
|
||||
DeclareSharedWidget(Canvas)
|
||||
using internalType = mCanvas;
|
||||
|
||||
auto color() const { return self().color(); }
|
||||
auto data() { return self().data(); }
|
||||
|
@ -237,6 +258,7 @@ struct Canvas : sCanvas {
|
|||
#if defined(Hiro_CheckButton)
|
||||
struct CheckButton : sCheckButton {
|
||||
DeclareSharedWidget(CheckButton)
|
||||
using internalType = mCheckButton;
|
||||
|
||||
auto bordered() const { return self().bordered(); }
|
||||
auto checked() const { return self().checked(); }
|
||||
|
@ -256,6 +278,7 @@ struct CheckButton : sCheckButton {
|
|||
#if defined(Hiro_CheckLabel)
|
||||
struct CheckLabel : sCheckLabel {
|
||||
DeclareSharedWidget(CheckLabel)
|
||||
using internalType = mCheckLabel;
|
||||
|
||||
auto checked() const { return self().checked(); }
|
||||
auto doToggle() const { return self().doToggle(); }
|
||||
|
@ -269,6 +292,7 @@ struct CheckLabel : sCheckLabel {
|
|||
#if defined(Hiro_ComboButton)
|
||||
struct ComboButtonItem : sComboButtonItem {
|
||||
DeclareSharedObject(ComboButtonItem)
|
||||
using internalType = mComboButtonItem;
|
||||
|
||||
auto image() const { return self().image(); }
|
||||
auto selected() const { return self().selected(); }
|
||||
|
@ -282,6 +306,7 @@ struct ComboButtonItem : sComboButtonItem {
|
|||
#if defined(Hiro_ComboButton)
|
||||
struct ComboButton : sComboButton {
|
||||
DeclareSharedWidget(ComboButton)
|
||||
using internalType = mComboButton;
|
||||
|
||||
auto append(sComboButtonItem item) { return self().append(item), *this; }
|
||||
auto doChange() const { return self().doChange(); }
|
||||
|
@ -299,6 +324,7 @@ struct ComboButton : sComboButton {
|
|||
#if defined(Hiro_Console)
|
||||
struct Console : sConsole {
|
||||
DeclareSharedWidget(Console)
|
||||
using internalType = mConsole;
|
||||
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
auto doActivate(string command) const { return self().doActivate(command); }
|
||||
|
@ -316,6 +342,7 @@ struct Console : sConsole {
|
|||
#if defined(Hiro_Frame)
|
||||
struct Frame : sFrame {
|
||||
DeclareSharedWidget(Frame)
|
||||
using internalType = mFrame;
|
||||
|
||||
auto append(sLayout layout) { return self().append(layout), *this; }
|
||||
auto layout() const { return self().layout(); }
|
||||
|
@ -329,6 +356,7 @@ struct Frame : sFrame {
|
|||
#if defined(Hiro_HexEdit)
|
||||
struct HexEdit : sHexEdit {
|
||||
DeclareSharedWidget(HexEdit)
|
||||
using internalType = mHexEdit;
|
||||
|
||||
auto address() const { return self().address(); }
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
|
@ -353,6 +381,7 @@ struct HexEdit : sHexEdit {
|
|||
#if defined(Hiro_HorizontalScrollBar)
|
||||
struct HorizontalScrollBar : sHorizontalScrollBar {
|
||||
DeclareSharedWidget(HorizontalScrollBar)
|
||||
using internalType = mHorizontalScrollBar;
|
||||
|
||||
auto doChange() const { return self().doChange(); }
|
||||
auto length() const { return self().length(); }
|
||||
|
@ -366,6 +395,7 @@ struct HorizontalScrollBar : sHorizontalScrollBar {
|
|||
#if defined(Hiro_HorizontalSlider)
|
||||
struct HorizontalSlider : sHorizontalSlider {
|
||||
DeclareSharedWidget(HorizontalSlider)
|
||||
using internalType = mHorizontalSlider;
|
||||
|
||||
auto doChange() const { return self().doChange(); }
|
||||
auto length() const { return self().length(); }
|
||||
|
@ -379,6 +409,7 @@ struct HorizontalSlider : sHorizontalSlider {
|
|||
#if defined(Hiro_IconView)
|
||||
struct IconViewItem : sIconViewItem {
|
||||
DeclareSharedObject(IconViewItem)
|
||||
using internalType = mIconViewItem;
|
||||
|
||||
auto image() const { return self().image(); }
|
||||
auto selected() const { return self().selected(); }
|
||||
|
@ -392,6 +423,7 @@ struct IconViewItem : sIconViewItem {
|
|||
#if defined(Hiro_IconView)
|
||||
struct IconView : sIconView {
|
||||
DeclareSharedWidget(IconView)
|
||||
using internalType = mIconView;
|
||||
|
||||
auto append(sIconViewItem item) { return self().append(item), *this; }
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
|
@ -424,6 +456,7 @@ struct IconView : sIconView {
|
|||
#if defined(Hiro_Label)
|
||||
struct Label : sLabel {
|
||||
DeclareSharedWidget(Label)
|
||||
using internalType = mLabel;
|
||||
|
||||
auto alignment() const { return self().alignment(); }
|
||||
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
|
||||
|
@ -435,6 +468,7 @@ struct Label : sLabel {
|
|||
#if defined(Hiro_LineEdit)
|
||||
struct LineEdit : sLineEdit {
|
||||
DeclareSharedWidget(LineEdit)
|
||||
using internalType = mLineEdit;
|
||||
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
auto doActivate() const { return self().doActivate(); }
|
||||
|
@ -454,6 +488,7 @@ struct LineEdit : sLineEdit {
|
|||
#if defined(Hiro_ListView)
|
||||
struct ListViewColumn : sListViewColumn {
|
||||
DeclareSharedObject(ListViewColumn)
|
||||
using internalType = mListViewColumn;
|
||||
|
||||
auto active() const { return self().active(); }
|
||||
auto alignment() const { return self().alignment(); }
|
||||
|
@ -485,6 +520,7 @@ struct ListViewColumn : sListViewColumn {
|
|||
#if defined(Hiro_ListView)
|
||||
struct ListViewHeader : sListViewHeader {
|
||||
DeclareSharedObject(ListViewHeader)
|
||||
using internalType = mListViewHeader;
|
||||
|
||||
auto append(sListViewColumn column) { return self().append(column), *this; }
|
||||
auto column(unsigned position) const { return self().column(position); }
|
||||
|
@ -497,6 +533,7 @@ struct ListViewHeader : sListViewHeader {
|
|||
#if defined(Hiro_ListView)
|
||||
struct ListViewCell : sListViewCell {
|
||||
DeclareSharedObject(ListViewCell)
|
||||
using internalType = mListViewCell;
|
||||
|
||||
auto alignment() const { return self().alignment(); }
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
|
@ -518,6 +555,7 @@ struct ListViewCell : sListViewCell {
|
|||
#if defined(Hiro_ListView)
|
||||
struct ListViewItem : sListViewItem {
|
||||
DeclareSharedObject(ListViewItem)
|
||||
using internalType = mListViewItem;
|
||||
|
||||
auto alignment() const { return self().alignment(); }
|
||||
auto append(sListViewCell cell) { return self().append(cell), *this; }
|
||||
|
@ -538,6 +576,7 @@ struct ListViewItem : sListViewItem {
|
|||
#if defined(Hiro_ListView)
|
||||
struct ListView : sListView {
|
||||
DeclareSharedWidget(ListView)
|
||||
using internalType = mListView;
|
||||
|
||||
auto alignment() const { return self().alignment(); }
|
||||
auto append(sListViewHeader header) { return self().append(header), *this; }
|
||||
|
@ -579,6 +618,7 @@ struct ListView : sListView {
|
|||
#if defined(Hiro_ProgressBar)
|
||||
struct ProgressBar : sProgressBar {
|
||||
DeclareSharedWidget(ProgressBar)
|
||||
using internalType = mProgressBar;
|
||||
|
||||
auto position() const { return self().position(); }
|
||||
auto setPosition(unsigned position = 0) { return self().setPosition(position), *this; }
|
||||
|
@ -624,6 +664,7 @@ struct RadioLabel : sRadioLabel {
|
|||
#if defined(Hiro_SourceEdit)
|
||||
struct SourceEdit : sSourceEdit {
|
||||
DeclareSharedWidget(SourceEdit)
|
||||
using internalType = mSourceEdit;
|
||||
|
||||
auto cursor() const { return self().cursor(); }
|
||||
auto doChange() const { return self().doChange(); }
|
||||
|
@ -639,6 +680,7 @@ struct SourceEdit : sSourceEdit {
|
|||
#if defined(Hiro_TabFrame)
|
||||
struct TabFrameItem : sTabFrameItem {
|
||||
DeclareSharedObject(TabFrameItem)
|
||||
using internalType = mTabFrameItem;
|
||||
|
||||
auto append(sLayout layout) { return self().append(layout), *this; }
|
||||
auto closable() const { return self().closable(); }
|
||||
|
@ -660,6 +702,7 @@ struct TabFrameItem : sTabFrameItem {
|
|||
#if defined(Hiro_TabFrame)
|
||||
struct TabFrame : sTabFrame {
|
||||
DeclareSharedWidget(TabFrame)
|
||||
using internalType = mTabFrame;
|
||||
|
||||
auto append(sTabFrameItem item) { return self().append(item), *this; }
|
||||
auto doChange() const { return self().doChange(); }
|
||||
|
@ -682,6 +725,7 @@ struct TabFrame : sTabFrame {
|
|||
#if defined(Hiro_TextEdit)
|
||||
struct TextEdit : sTextEdit {
|
||||
DeclareSharedWidget(TextEdit)
|
||||
using internalType = mTextEdit;
|
||||
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
auto cursor() const { return self().cursor(); }
|
||||
|
@ -705,6 +749,7 @@ struct TextEdit : sTextEdit {
|
|||
#if defined(Hiro_TreeView)
|
||||
struct TreeViewItem : sTreeViewItem {
|
||||
DeclareSharedObject(TreeViewItem)
|
||||
using internalType = mTreeViewItem;
|
||||
|
||||
auto append(sTreeViewItem item) { return self().append(item), *this; }
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
|
@ -733,6 +778,7 @@ struct TreeViewItem : sTreeViewItem {
|
|||
#if defined(Hiro_TreeView)
|
||||
struct TreeView : sTreeView {
|
||||
DeclareSharedWidget(TreeView)
|
||||
using internalType = mTreeView;
|
||||
|
||||
auto append(sTreeViewItem item) { return self().append(item), *this; }
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
|
@ -759,6 +805,7 @@ struct TreeView : sTreeView {
|
|||
#if defined(Hiro_VerticalScrollBar)
|
||||
struct VerticalScrollBar : sVerticalScrollBar {
|
||||
DeclareSharedWidget(VerticalScrollBar)
|
||||
using internalType = mVerticalScrollBar;
|
||||
|
||||
auto doChange() const { return self().doChange(); }
|
||||
auto length() const { return self().length(); }
|
||||
|
@ -772,6 +819,7 @@ struct VerticalScrollBar : sVerticalScrollBar {
|
|||
#if defined(Hiro_VerticalSlider)
|
||||
struct VerticalSlider : sVerticalSlider {
|
||||
DeclareSharedWidget(VerticalSlider)
|
||||
using internalType = mVerticalSlider;
|
||||
|
||||
auto doChange() const { return self().doChange(); }
|
||||
auto length() const { return self().length(); }
|
||||
|
@ -785,6 +833,7 @@ struct VerticalSlider : sVerticalSlider {
|
|||
#if defined(Hiro_Viewport)
|
||||
struct Viewport : sViewport {
|
||||
DeclareSharedWidget(Viewport)
|
||||
using internalType = mViewport;
|
||||
|
||||
auto doDrop(lstring names) const { return self().doDrop(names); }
|
||||
auto doMouseLeave() const { return self().doMouseLeave(); }
|
||||
|
@ -805,6 +854,7 @@ struct Viewport : sViewport {
|
|||
#if defined(Hiro_StatusBar)
|
||||
struct StatusBar : sStatusBar {
|
||||
DeclareSharedObject(StatusBar)
|
||||
using internalType = mStatusBar;
|
||||
|
||||
auto setText(const string& text = "") { return self().setText(text), *this; }
|
||||
auto text() const { return self().text(); }
|
||||
|
@ -814,6 +864,7 @@ struct StatusBar : sStatusBar {
|
|||
#if defined(Hiro_PopupMenu)
|
||||
struct PopupMenu : sPopupMenu {
|
||||
DeclareSharedObject(PopupMenu)
|
||||
using internalType = mPopupMenu;
|
||||
|
||||
auto action(unsigned position) const { return self().action(position); }
|
||||
auto actionCount() const { return self().actionCount(); }
|
||||
|
@ -827,6 +878,7 @@ struct PopupMenu : sPopupMenu {
|
|||
#if defined(Hiro_MenuBar)
|
||||
struct MenuBar : sMenuBar {
|
||||
DeclareSharedObject(MenuBar)
|
||||
using internalType = mMenuBar;
|
||||
|
||||
auto append(sMenu menu) { return self().append(menu), *this; }
|
||||
auto menu(unsigned position) const { return self().menu(position); }
|
||||
|
@ -840,6 +892,7 @@ struct MenuBar : sMenuBar {
|
|||
#if defined(Hiro_Window)
|
||||
struct Window : sWindow {
|
||||
DeclareSharedObject(Window)
|
||||
using internalType = mWindow;
|
||||
|
||||
auto append(sLayout layout) { return self().append(layout), *this; }
|
||||
auto append(sMenuBar menuBar) { return self().append(menuBar), *this; }
|
||||
|
|
|
@ -189,7 +189,6 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
);
|
||||
}
|
||||
|
||||
if(view.items()) view.item(0)->setSelected();
|
||||
Application::processEvents();
|
||||
view.resizeColumns().setFocused().doChange();
|
||||
}
|
||||
|
|
|
@ -116,6 +116,8 @@ auto mHorizontalLayout::setGeometry(Geometry containerGeometry) -> type& {
|
|||
geometry.setX (geometry.x() + child.width + child.spacing);
|
||||
geometry.setWidth(geometry.width() - child.width + child.spacing);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mHorizontalLayout::setMargin(signed margin) -> type& {
|
||||
|
|
|
@ -119,7 +119,13 @@ auto pListView::setBordered(bool bordered) -> void {
|
|||
}
|
||||
|
||||
auto pListView::setFocused() -> void {
|
||||
//gtk_widget_grab_focus() will select the first item if nothing is currently selected
|
||||
//this behavior is undesirable. detect selection state first, and restore if required
|
||||
lock();
|
||||
bool selected = gtk_tree_selection_get_selected(gtkTreeSelection, nullptr, nullptr);
|
||||
gtk_widget_grab_focus(gtkWidgetChild);
|
||||
if(!selected) gtk_tree_selection_unselect_all(gtkTreeSelection);
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto pListView::setFont(const Font& font) -> void {
|
||||
|
|
|
@ -79,6 +79,16 @@ auto pTreeView::setBackgroundColor(Color color) -> void {
|
|||
gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
|
||||
}
|
||||
|
||||
auto pTreeView::setFocused() -> void {
|
||||
//gtk_widget_grab_focus() will select the first item if nothing is currently selected
|
||||
//this behavior is undesirable. detect selection state first, and restore if required
|
||||
lock();
|
||||
bool selected = gtk_tree_selection_get_selected(gtkTreeSelection, nullptr, nullptr);
|
||||
gtk_widget_grab_focus(gtkWidgetChild);
|
||||
if(!selected) gtk_tree_selection_unselect_all(gtkTreeSelection);
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto pTreeView::setForegroundColor(Color color) -> void {
|
||||
auto gdkColor = CreateColor(color);
|
||||
gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
|
||||
|
|
|
@ -8,6 +8,7 @@ struct pTreeView : pWidget {
|
|||
auto append(sTreeViewItem item) -> void;
|
||||
auto remove(sTreeViewItem item) -> void;
|
||||
auto setBackgroundColor(Color color) -> void;
|
||||
auto setFocused() -> void override;
|
||||
auto setForegroundColor(Color color) -> void;
|
||||
|
||||
auto _activatePath(GtkTreePath* gtkPath) -> void;
|
||||
|
|
|
@ -9,70 +9,70 @@
|
|||
namespace nall {
|
||||
|
||||
struct bpsdelta {
|
||||
inline void source(const uint8_t* data, unsigned size);
|
||||
inline void target(const uint8_t* data, unsigned size);
|
||||
inline auto source(const uint8* data, uint size) -> void;
|
||||
inline auto target(const uint8* data, uint size) -> void;
|
||||
|
||||
inline bool source(const string& filename);
|
||||
inline bool target(const string& filename);
|
||||
inline bool create(const string& filename, const string& metadata = "");
|
||||
inline auto source(const string& filename) -> bool;
|
||||
inline auto target(const string& filename) -> bool;
|
||||
inline auto create(const string& filename, const string& metadata = "") -> bool;
|
||||
|
||||
protected:
|
||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||
enum : unsigned { Granularity = 1 };
|
||||
enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||
enum : uint { Granularity = 1 };
|
||||
|
||||
struct Node {
|
||||
unsigned offset = 0;
|
||||
Node* next = nullptr;
|
||||
Node() = default;
|
||||
~Node() { if(next) delete next; }
|
||||
uint offset = 0;
|
||||
Node* next = nullptr;
|
||||
};
|
||||
|
||||
filemap sourceFile;
|
||||
const uint8_t* sourceData;
|
||||
unsigned sourceSize;
|
||||
const uint8* sourceData;
|
||||
uint sourceSize;
|
||||
|
||||
filemap targetFile;
|
||||
const uint8_t* targetData;
|
||||
unsigned targetSize;
|
||||
const uint8* targetData;
|
||||
uint targetSize;
|
||||
};
|
||||
|
||||
void bpsdelta::source(const uint8_t* data, unsigned size) {
|
||||
auto bpsdelta::source(const uint8* data, uint size) -> void {
|
||||
sourceData = data;
|
||||
sourceSize = size;
|
||||
}
|
||||
|
||||
void bpsdelta::target(const uint8_t* data, unsigned size) {
|
||||
auto bpsdelta::target(const uint8* data, uint size) -> void {
|
||||
targetData = data;
|
||||
targetSize = size;
|
||||
}
|
||||
|
||||
bool bpsdelta::source(const string& filename) {
|
||||
auto bpsdelta::source(const string& filename) -> bool {
|
||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
||||
source(sourceFile.data(), sourceFile.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpsdelta::target(const string& filename) {
|
||||
auto bpsdelta::target(const string& filename) -> bool {
|
||||
if(targetFile.open(filename, filemap::mode::read) == false) return false;
|
||||
target(targetFile.data(), targetFile.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpsdelta::create(const string& filename, const string& metadata) {
|
||||
auto bpsdelta::create(const string& filename, const string& metadata) -> bool {
|
||||
file modifyFile;
|
||||
if(modifyFile.open(filename, file::mode::write) == false) return false;
|
||||
|
||||
Hash::CRC32 sourceChecksum, modifyChecksum;
|
||||
unsigned sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
||||
uint sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
||||
|
||||
auto write = [&](uint8_t data) {
|
||||
auto write = [&](uint8 data) {
|
||||
modifyFile.write(data);
|
||||
modifyChecksum.data(data);
|
||||
};
|
||||
|
||||
auto encode = [&](uint64_t data) {
|
||||
auto encode = [&](uint64 data) {
|
||||
while(true) {
|
||||
uint64_t x = data & 0x7f;
|
||||
uint64 x = data & 0x7f;
|
||||
data >>= 7;
|
||||
if(data == 0) {
|
||||
write(0x80 | x);
|
||||
|
@ -91,17 +91,17 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
|||
encode(sourceSize);
|
||||
encode(targetSize);
|
||||
|
||||
unsigned markupSize = metadata.length();
|
||||
uint markupSize = metadata.length();
|
||||
encode(markupSize);
|
||||
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
|
||||
for(uint n = 0; n < markupSize; n++) write(metadata[n]);
|
||||
|
||||
Node* sourceTree[65536];
|
||||
Node* targetTree[65536];
|
||||
for(unsigned n = 0; n < 65536; n++) sourceTree[n] = nullptr, targetTree[n] = nullptr;
|
||||
for(uint n = 0; n < 65536; n++) sourceTree[n] = nullptr, targetTree[n] = nullptr;
|
||||
|
||||
//source tree creation
|
||||
for(unsigned offset = 0; offset < sourceSize; offset++) {
|
||||
uint16_t symbol = sourceData[offset + 0];
|
||||
for(uint offset = 0; offset < sourceSize; offset++) {
|
||||
uint16 symbol = sourceData[offset + 0];
|
||||
sourceChecksum.data(symbol);
|
||||
if(offset < sourceSize - 1) symbol |= sourceData[offset + 1] << 8;
|
||||
Node *node = new Node;
|
||||
|
@ -110,24 +110,24 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
|||
sourceTree[symbol] = node;
|
||||
}
|
||||
|
||||
unsigned targetReadLength = 0;
|
||||
uint targetReadLength = 0;
|
||||
|
||||
auto targetReadFlush = [&]() {
|
||||
if(targetReadLength) {
|
||||
encode(TargetRead | ((targetReadLength - 1) << 2));
|
||||
unsigned offset = outputOffset - targetReadLength;
|
||||
uint offset = outputOffset - targetReadLength;
|
||||
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
|
||||
}
|
||||
};
|
||||
|
||||
while(outputOffset < targetSize) {
|
||||
unsigned maxLength = 0, maxOffset = 0, mode = TargetRead;
|
||||
uint maxLength = 0, maxOffset = 0, mode = TargetRead;
|
||||
|
||||
uint16_t symbol = targetData[outputOffset + 0];
|
||||
uint16 symbol = targetData[outputOffset + 0];
|
||||
if(outputOffset < targetSize - 1) symbol |= targetData[outputOffset + 1] << 8;
|
||||
|
||||
{ //source read
|
||||
unsigned length = 0, offset = outputOffset;
|
||||
uint length = 0, offset = outputOffset;
|
||||
while(offset < sourceSize && offset < targetSize && sourceData[offset] == targetData[offset]) {
|
||||
length++;
|
||||
offset++;
|
||||
|
@ -138,7 +138,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
|||
{ //source copy
|
||||
Node* node = sourceTree[symbol];
|
||||
while(node) {
|
||||
unsigned length = 0, x = node->offset, y = outputOffset;
|
||||
uint length = 0, x = node->offset, y = outputOffset;
|
||||
while(x < sourceSize && y < targetSize && sourceData[x++] == targetData[y++]) length++;
|
||||
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = SourceCopy;
|
||||
node = node->next;
|
||||
|
@ -148,7 +148,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
|||
{ //target copy
|
||||
Node* node = targetTree[symbol];
|
||||
while(node) {
|
||||
unsigned length = 0, x = node->offset, y = outputOffset;
|
||||
uint length = 0, x = node->offset, y = outputOffset;
|
||||
while(y < targetSize && targetData[x++] == targetData[y++]) length++;
|
||||
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = TargetCopy;
|
||||
node = node->next;
|
||||
|
@ -163,7 +163,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
|||
|
||||
{ //target read
|
||||
if(maxLength < 4) {
|
||||
maxLength = min((unsigned)Granularity, targetSize - outputOffset);
|
||||
maxLength = min((uint)Granularity, targetSize - outputOffset);
|
||||
mode = TargetRead;
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
|||
case SourceCopy:
|
||||
case TargetCopy:
|
||||
encode(mode | ((maxLength - 1) << 2));
|
||||
signed relativeOffset;
|
||||
int relativeOffset;
|
||||
if(mode == SourceCopy) {
|
||||
relativeOffset = maxOffset - sourceRelativeOffset;
|
||||
sourceRelativeOffset = maxOffset + maxLength;
|
||||
|
@ -198,11 +198,11 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
|||
|
||||
targetReadFlush();
|
||||
|
||||
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum.value() >> n);
|
||||
uint32_t targetChecksum = Hash::CRC32(targetData, targetSize).value();
|
||||
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
||||
uint32_t outputChecksum = modifyChecksum.value();
|
||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||
for(uint n = 0; n < 32; n += 8) write(sourceChecksum.value() >> n);
|
||||
uint32 targetChecksum = Hash::CRC32(targetData, targetSize).value();
|
||||
for(uint n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
||||
uint32 outputChecksum = modifyChecksum.value();
|
||||
for(uint n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||
|
||||
modifyFile.close();
|
||||
return true;
|
||||
|
|
|
@ -9,63 +9,63 @@
|
|||
namespace nall {
|
||||
|
||||
struct bpslinear {
|
||||
inline void source(const uint8_t* data, unsigned size);
|
||||
inline void target(const uint8_t* data, unsigned size);
|
||||
inline auto source(const uint8* data, uint size) -> void;
|
||||
inline auto target(const uint8* data, uint size) -> void;
|
||||
|
||||
inline bool source(const string& filename);
|
||||
inline bool target(const string& filename);
|
||||
inline bool create(const string& filename, const string& metadata = "");
|
||||
inline auto source(const string& filename) -> bool;
|
||||
inline auto target(const string& filename) -> bool;
|
||||
inline auto create(const string& filename, const string& metadata = "") -> bool;
|
||||
|
||||
protected:
|
||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||
enum : unsigned { Granularity = 1 };
|
||||
enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||
enum : uint { Granularity = 1 };
|
||||
|
||||
filemap sourceFile;
|
||||
const uint8_t* sourceData;
|
||||
unsigned sourceSize;
|
||||
const uint8* sourceData;
|
||||
uint sourceSize;
|
||||
|
||||
filemap targetFile;
|
||||
const uint8_t* targetData;
|
||||
unsigned targetSize;
|
||||
const uint8* targetData;
|
||||
uint targetSize;
|
||||
};
|
||||
|
||||
void bpslinear::source(const uint8_t* data, unsigned size) {
|
||||
auto bpslinear::source(const uint8* data, uint size) -> void {
|
||||
sourceData = data;
|
||||
sourceSize = size;
|
||||
}
|
||||
|
||||
void bpslinear::target(const uint8_t* data, unsigned size) {
|
||||
auto bpslinear::target(const uint8* data, uint size) -> void {
|
||||
targetData = data;
|
||||
targetSize = size;
|
||||
}
|
||||
|
||||
bool bpslinear::source(const string& filename) {
|
||||
auto bpslinear::source(const string& filename) -> bool {
|
||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
||||
source(sourceFile.data(), sourceFile.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpslinear::target(const string& filename) {
|
||||
auto bpslinear::target(const string& filename) -> bool {
|
||||
if(targetFile.open(filename, filemap::mode::read) == false) return false;
|
||||
target(targetFile.data(), targetFile.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpslinear::create(const string& filename, const string& metadata) {
|
||||
auto bpslinear::create(const string& filename, const string& metadata) -> bool {
|
||||
file modifyFile;
|
||||
if(modifyFile.open(filename, file::mode::write) == false) return false;
|
||||
|
||||
Hash::CRC32 modifyChecksum;
|
||||
unsigned targetRelativeOffset = 0, outputOffset = 0;
|
||||
uint targetRelativeOffset = 0, outputOffset = 0;
|
||||
|
||||
auto write = [&](uint8_t data) {
|
||||
auto write = [&](uint8 data) {
|
||||
modifyFile.write(data);
|
||||
modifyChecksum.data(data);
|
||||
};
|
||||
|
||||
auto encode = [&](uint64_t data) {
|
||||
auto encode = [&](uint64 data) {
|
||||
while(true) {
|
||||
uint64_t x = data & 0x7f;
|
||||
uint64 x = data & 0x7f;
|
||||
data >>= 7;
|
||||
if(data == 0) {
|
||||
write(0x80 | x);
|
||||
|
@ -76,12 +76,12 @@ bool bpslinear::create(const string& filename, const string& metadata) {
|
|||
}
|
||||
};
|
||||
|
||||
unsigned targetReadLength = 0;
|
||||
uint targetReadLength = 0;
|
||||
|
||||
auto targetReadFlush = [&]() {
|
||||
if(targetReadLength) {
|
||||
encode(TargetRead | ((targetReadLength - 1) << 2));
|
||||
unsigned offset = outputOffset - targetReadLength;
|
||||
uint offset = outputOffset - targetReadLength;
|
||||
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
|
||||
}
|
||||
};
|
||||
|
@ -94,19 +94,19 @@ bool bpslinear::create(const string& filename, const string& metadata) {
|
|||
encode(sourceSize);
|
||||
encode(targetSize);
|
||||
|
||||
unsigned markupSize = metadata.length();
|
||||
uint markupSize = metadata.length();
|
||||
encode(markupSize);
|
||||
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
|
||||
for(uint n = 0; n < markupSize; n++) write(metadata[n]);
|
||||
|
||||
while(outputOffset < targetSize) {
|
||||
unsigned sourceLength = 0;
|
||||
for(unsigned n = 0; outputOffset + n < min(sourceSize, targetSize); n++) {
|
||||
uint sourceLength = 0;
|
||||
for(uint n = 0; outputOffset + n < min(sourceSize, targetSize); n++) {
|
||||
if(sourceData[outputOffset + n] != targetData[outputOffset + n]) break;
|
||||
sourceLength++;
|
||||
}
|
||||
|
||||
unsigned rleLength = 0;
|
||||
for(unsigned n = 1; outputOffset + n < targetSize; n++) {
|
||||
uint rleLength = 0;
|
||||
for(uint n = 1; outputOffset + n < targetSize; n++) {
|
||||
if(targetData[outputOffset] != targetData[outputOffset + n]) break;
|
||||
rleLength++;
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ bool bpslinear::create(const string& filename, const string& metadata) {
|
|||
|
||||
//copy starting from repetition byte
|
||||
encode(TargetCopy | ((rleLength - 1) << 2));
|
||||
unsigned relativeOffset = (outputOffset - 1) - targetRelativeOffset;
|
||||
uint relativeOffset = (outputOffset - 1) - targetRelativeOffset;
|
||||
encode(relativeOffset << 1);
|
||||
outputOffset += rleLength;
|
||||
targetRelativeOffset = outputOffset - 1;
|
||||
|
@ -135,12 +135,12 @@ bool bpslinear::create(const string& filename, const string& metadata) {
|
|||
|
||||
targetReadFlush();
|
||||
|
||||
uint32_t sourceChecksum = Hash::CRC32(sourceData, sourceSize).value();
|
||||
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
|
||||
uint32_t targetChecksum = Hash::CRC32(targetData, targetSize).value();
|
||||
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
||||
uint32_t outputChecksum = modifyChecksum.value();
|
||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||
uint32 sourceChecksum = Hash::CRC32(sourceData, sourceSize).value();
|
||||
for(uint n = 0; n < 32; n += 8) write(sourceChecksum >> n);
|
||||
uint32 targetChecksum = Hash::CRC32(targetData, targetSize).value();
|
||||
for(uint n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
||||
uint32 outputChecksum = modifyChecksum.value();
|
||||
for(uint n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||
|
||||
modifyFile.close();
|
||||
return true;
|
||||
|
|
|
@ -9,26 +9,26 @@
|
|||
namespace nall {
|
||||
|
||||
struct bpsmetadata {
|
||||
inline bool load(const string& filename);
|
||||
inline bool save(const string& filename, const string& metadata);
|
||||
inline string metadata() const;
|
||||
inline auto load(const string& filename) -> bool;
|
||||
inline auto save(const string& filename, const string& metadata) -> bool;
|
||||
inline auto metadata() const -> string;
|
||||
|
||||
protected:
|
||||
file sourceFile;
|
||||
string metadataString;
|
||||
};
|
||||
|
||||
bool bpsmetadata::load(const string& filename) {
|
||||
auto bpsmetadata::load(const string& filename) -> bool {
|
||||
if(sourceFile.open(filename, file::mode::read) == false) return false;
|
||||
|
||||
auto read = [&]() -> uint8_t {
|
||||
return sourceFile.read();
|
||||
};
|
||||
|
||||
auto decode = [&]() -> uint64_t {
|
||||
uint64_t data = 0, shift = 1;
|
||||
auto decode = [&]() -> uint64 {
|
||||
uint64 data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
uint8 x = read();
|
||||
data += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
|
@ -43,29 +43,29 @@ bool bpsmetadata::load(const string& filename) {
|
|||
if(read() != '1') return false;
|
||||
decode();
|
||||
decode();
|
||||
unsigned metadataSize = decode();
|
||||
uint metadataSize = decode();
|
||||
char data[metadataSize + 1];
|
||||
for(unsigned n = 0; n < metadataSize; n++) data[n] = read();
|
||||
for(uint n = 0; n < metadataSize; n++) data[n] = read();
|
||||
data[metadataSize] = 0;
|
||||
metadataString = (const char*)data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpsmetadata::save(const string& filename, const string& metadata) {
|
||||
auto bpsmetadata::save(const string& filename, const string& metadata) -> bool {
|
||||
file targetFile;
|
||||
if(targetFile.open(filename, file::mode::write) == false) return false;
|
||||
if(sourceFile.open() == false) return false;
|
||||
sourceFile.seek(0);
|
||||
|
||||
auto read = [&]() -> uint8_t {
|
||||
auto read = [&]() -> uint8 {
|
||||
return sourceFile.read();
|
||||
};
|
||||
|
||||
auto decode = [&]() -> uint64_t {
|
||||
uint64_t data = 0, shift = 1;
|
||||
auto decode = [&]() -> uint64 {
|
||||
uint64 data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
uint8 x = read();
|
||||
data += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
|
@ -76,14 +76,14 @@ bool bpsmetadata::save(const string& filename, const string& metadata) {
|
|||
|
||||
Hash::CRC32 checksum;
|
||||
|
||||
auto write = [&](uint8_t data) {
|
||||
auto write = [&](uint8 data) {
|
||||
targetFile.write(data);
|
||||
checksum.data(data);
|
||||
};
|
||||
|
||||
auto encode = [&](uint64_t data) {
|
||||
auto encode = [&](uint64 data) {
|
||||
while(true) {
|
||||
uint64_t x = data & 0x7f;
|
||||
uint64 x = data & 0x7f;
|
||||
data >>= 7;
|
||||
if(data == 0) {
|
||||
write(0x80 | x);
|
||||
|
@ -94,24 +94,24 @@ bool bpsmetadata::save(const string& filename, const string& metadata) {
|
|||
}
|
||||
};
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) write(read());
|
||||
for(uint n = 0; n < 4; n++) write(read());
|
||||
encode(decode());
|
||||
encode(decode());
|
||||
unsigned sourceLength = decode();
|
||||
unsigned targetLength = metadata.length();
|
||||
uint sourceLength = decode();
|
||||
uint targetLength = metadata.length();
|
||||
encode(targetLength);
|
||||
sourceFile.seek(sourceLength, file::index::relative);
|
||||
for(unsigned n = 0; n < targetLength; n++) write(metadata[n]);
|
||||
unsigned length = sourceFile.size() - sourceFile.offset() - 4;
|
||||
for(unsigned n = 0; n < length; n++) write(read());
|
||||
uint32_t outputChecksum = checksum.value();
|
||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||
for(uint n = 0; n < targetLength; n++) write(metadata[n]);
|
||||
uint length = sourceFile.size() - sourceFile.offset() - 4;
|
||||
for(uint n = 0; n < length; n++) write(read());
|
||||
uint32 outputChecksum = checksum.value();
|
||||
for(uint n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||
|
||||
targetFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
string bpsmetadata::metadata() const {
|
||||
auto bpsmetadata::metadata() const -> string {
|
||||
return metadataString;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
namespace nall {
|
||||
|
||||
struct bpsmulti {
|
||||
enum : unsigned {
|
||||
enum : uint {
|
||||
CreatePath = 0,
|
||||
CreateFile = 1,
|
||||
ModifyFile = 2,
|
||||
MirrorFile = 3,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
enum : uint {
|
||||
OriginSource = 0,
|
||||
OriginTarget = 1,
|
||||
};
|
||||
|
||||
bool create(const string& patchName, const string& sourcePath, const string& targetPath, bool delta = false, const string& metadata = "") {
|
||||
auto create(const string& patchName, const string& sourcePath, const string& targetPath, bool delta = false, const string& metadata = "") -> bool {
|
||||
if(fp.open()) fp.close();
|
||||
fp.open(patchName, file::mode::write);
|
||||
checksum.reset();
|
||||
|
@ -46,8 +46,8 @@ struct bpsmulti {
|
|||
bool identical = sp.size() == dp.size();
|
||||
Hash::CRC32 cksum;
|
||||
|
||||
for(unsigned n = 0; n < sp.size(); n++) {
|
||||
uint8_t byte = sp.read();
|
||||
for(uint n = 0; n < sp.size(); n++) {
|
||||
uint8 byte = sp.read();
|
||||
if(identical && byte != dp.read()) identical = false;
|
||||
cksum.data(byte);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ struct bpsmulti {
|
|||
writeString(targetName);
|
||||
auto buffer = file::read({targetPath, targetName});
|
||||
writeNumber(buffer.size());
|
||||
for(auto &byte : buffer) write(byte);
|
||||
for(auto& byte : buffer) write(byte);
|
||||
writeChecksum(Hash::CRC32(buffer.data(), buffer.size()).value());
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ struct bpsmulti {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool apply(const string& patchName, const string& sourcePath, const string& targetPath) {
|
||||
auto apply(const string& patchName, const string& sourcePath, const string& targetPath) -> bool {
|
||||
directory::remove(targetPath); //start with a clean directory
|
||||
directory::create(targetPath);
|
||||
|
||||
|
@ -108,8 +108,8 @@ struct bpsmulti {
|
|||
|
||||
while(fp.offset() < fp.size() - 4) {
|
||||
auto encoding = readNumber();
|
||||
unsigned action = encoding & 3;
|
||||
unsigned targetLength = (encoding >> 2) + 1;
|
||||
uint action = encoding & 3;
|
||||
uint targetLength = (encoding >> 2) + 1;
|
||||
string targetName = readString(targetLength);
|
||||
|
||||
if(action == CreatePath) {
|
||||
|
@ -119,15 +119,15 @@ struct bpsmulti {
|
|||
fp.open({targetPath, targetName}, file::mode::write);
|
||||
auto fileSize = readNumber();
|
||||
while(fileSize--) fp.write(read());
|
||||
uint32_t cksum = readChecksum();
|
||||
uint32 cksum = readChecksum();
|
||||
} else if(action == ModifyFile) {
|
||||
auto encoding = readNumber();
|
||||
string originPath = encoding & 1 ? targetPath : sourcePath;
|
||||
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
||||
auto patchSize = readNumber();
|
||||
vector<uint8_t> buffer;
|
||||
vector<uint8> buffer;
|
||||
buffer.resize(patchSize);
|
||||
for(unsigned n = 0; n < patchSize; n++) buffer[n] = read();
|
||||
for(uint n = 0; n < patchSize; n++) buffer[n] = read();
|
||||
bpspatch patch;
|
||||
patch.modify(buffer.data(), buffer.size());
|
||||
patch.source({originPath, sourceName});
|
||||
|
@ -138,15 +138,15 @@ struct bpsmulti {
|
|||
string originPath = encoding & 1 ? targetPath : sourcePath;
|
||||
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
||||
file::copy({originPath, sourceName}, {targetPath, targetName});
|
||||
uint32_t cksum = readChecksum();
|
||||
uint32 cksum = readChecksum();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t cksum = checksum.value();
|
||||
if(read() != (uint8_t)(cksum >> 0)) return false;
|
||||
if(read() != (uint8_t)(cksum >> 8)) return false;
|
||||
if(read() != (uint8_t)(cksum >> 16)) return false;
|
||||
if(read() != (uint8_t)(cksum >> 24)) return false;
|
||||
uint32 cksum = checksum.value();
|
||||
if(read() != (uint8)(cksum >> 0)) return false;
|
||||
if(read() != (uint8)(cksum >> 8)) return false;
|
||||
if(read() != (uint8)(cksum >> 16)) return false;
|
||||
if(read() != (uint8)(cksum >> 24)) return false;
|
||||
|
||||
fp.close();
|
||||
return true;
|
||||
|
@ -157,7 +157,7 @@ protected:
|
|||
Hash::CRC32 checksum;
|
||||
|
||||
//create() functions
|
||||
void ls(lstring& list, const string& path, const string& basepath) {
|
||||
auto ls(lstring& list, const string& path, const string& basepath) -> void {
|
||||
lstring paths = directory::folders(path);
|
||||
for(auto& pathname : paths) {
|
||||
list.append(string{path, pathname}.ltrim(basepath, 1L));
|
||||
|
@ -170,14 +170,14 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
void write(uint8_t data) {
|
||||
auto write(uint8 data) -> void {
|
||||
fp.write(data);
|
||||
checksum.data(data);
|
||||
}
|
||||
|
||||
void writeNumber(uint64_t data) {
|
||||
auto writeNumber(uint64 data) -> void {
|
||||
while(true) {
|
||||
uint64_t x = data & 0x7f;
|
||||
uint64 x = data & 0x7f;
|
||||
data >>= 7;
|
||||
if(data == 0) {
|
||||
write(0x80 | x);
|
||||
|
@ -188,12 +188,12 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
void writeString(const string& text) {
|
||||
unsigned length = text.length();
|
||||
for(unsigned n = 0; n < length; n++) write(text[n]);
|
||||
auto writeString(const string& text) -> void {
|
||||
uint length = text.length();
|
||||
for(uint n = 0; n < length; n++) write(text[n]);
|
||||
}
|
||||
|
||||
void writeChecksum(uint32_t cksum) {
|
||||
auto writeChecksum(uint32 cksum) -> void {
|
||||
write(cksum >> 0);
|
||||
write(cksum >> 8);
|
||||
write(cksum >> 16);
|
||||
|
@ -201,16 +201,16 @@ protected:
|
|||
}
|
||||
|
||||
//apply() functions
|
||||
uint8_t read() {
|
||||
uint8_t data = fp.read();
|
||||
auto read() -> uint8 {
|
||||
uint8 data = fp.read();
|
||||
checksum.data(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
uint64_t readNumber() {
|
||||
uint64_t data = 0, shift = 1;
|
||||
auto readNumber() -> uint64 {
|
||||
uint64 data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
uint8 x = read();
|
||||
data += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
|
@ -219,7 +219,7 @@ protected:
|
|||
return data;
|
||||
}
|
||||
|
||||
string readString(unsigned length) {
|
||||
auto readString(uint length) -> string {
|
||||
string text;
|
||||
text.resize(length + 1);
|
||||
char* p = text.get();
|
||||
|
@ -227,8 +227,8 @@ protected:
|
|||
return text;
|
||||
}
|
||||
|
||||
uint32_t readChecksum() {
|
||||
uint32_t checksum = 0;
|
||||
auto readChecksum() -> uint32 {
|
||||
uint32 checksum = 0;
|
||||
checksum |= read() << 0;
|
||||
checksum |= read() << 8;
|
||||
checksum |= read() << 16;
|
||||
|
|
|
@ -9,18 +9,18 @@
|
|||
namespace nall {
|
||||
|
||||
struct bpspatch {
|
||||
inline bool modify(const uint8_t* data, unsigned size);
|
||||
inline void source(const uint8_t* data, unsigned size);
|
||||
inline void target(uint8_t* data, unsigned size);
|
||||
inline auto modify(const uint8* data, uint size) -> bool;
|
||||
inline auto source(const uint8* data, uint size) -> void;
|
||||
inline auto target(uint8* data, uint size) -> void;
|
||||
|
||||
inline bool modify(const string& filename);
|
||||
inline bool source(const string& filename);
|
||||
inline bool target(const string& filename);
|
||||
inline auto modify(const string& filename) -> bool;
|
||||
inline auto source(const string& filename) -> bool;
|
||||
inline auto target(const string& filename) -> bool;
|
||||
|
||||
inline string metadata() const;
|
||||
inline unsigned size() const;
|
||||
inline auto metadata() const -> string;
|
||||
inline auto size() const -> uint;
|
||||
|
||||
enum result : unsigned {
|
||||
enum result : uint {
|
||||
unknown,
|
||||
success,
|
||||
patch_too_small,
|
||||
|
@ -32,39 +32,39 @@ struct bpspatch {
|
|||
patch_checksum_invalid,
|
||||
};
|
||||
|
||||
inline result apply();
|
||||
inline auto apply() -> result;
|
||||
|
||||
protected:
|
||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||
enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||
|
||||
filemap modifyFile;
|
||||
const uint8_t* modifyData;
|
||||
unsigned modifySize;
|
||||
const uint8* modifyData;
|
||||
uint modifySize;
|
||||
|
||||
filemap sourceFile;
|
||||
const uint8_t* sourceData;
|
||||
unsigned sourceSize;
|
||||
const uint8* sourceData;
|
||||
uint sourceSize;
|
||||
|
||||
filemap targetFile;
|
||||
uint8_t* targetData;
|
||||
unsigned targetSize;
|
||||
uint8* targetData;
|
||||
uint targetSize;
|
||||
|
||||
unsigned modifySourceSize;
|
||||
unsigned modifyTargetSize;
|
||||
unsigned modifyMarkupSize;
|
||||
uint modifySourceSize;
|
||||
uint modifyTargetSize;
|
||||
uint modifyMarkupSize;
|
||||
string metadataString;
|
||||
};
|
||||
|
||||
bool bpspatch::modify(const uint8_t* data, unsigned size) {
|
||||
auto bpspatch::modify(const uint8* data, uint size) -> bool {
|
||||
if(size < 19) return false;
|
||||
modifyData = data;
|
||||
modifySize = size;
|
||||
|
||||
unsigned offset = 4;
|
||||
auto decode = [&]() -> uint64_t {
|
||||
uint64_t data = 0, shift = 1;
|
||||
uint offset = 4;
|
||||
auto decode = [&]() -> uint64 {
|
||||
uint64 data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = modifyData[offset++];
|
||||
uint8 x = modifyData[offset++];
|
||||
data += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
|
@ -78,35 +78,35 @@ bool bpspatch::modify(const uint8_t* data, unsigned size) {
|
|||
modifyMarkupSize = decode();
|
||||
|
||||
char buffer[modifyMarkupSize + 1];
|
||||
for(unsigned n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++];
|
||||
for(uint n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++];
|
||||
buffer[modifyMarkupSize] = 0;
|
||||
metadataString = (const char*)buffer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bpspatch::source(const uint8_t* data, unsigned size) {
|
||||
auto bpspatch::source(const uint8* data, uint size) -> void {
|
||||
sourceData = data;
|
||||
sourceSize = size;
|
||||
}
|
||||
|
||||
void bpspatch::target(uint8_t* data, unsigned size) {
|
||||
auto bpspatch::target(uint8* data, uint size) -> void {
|
||||
targetData = data;
|
||||
targetSize = size;
|
||||
}
|
||||
|
||||
bool bpspatch::modify(const string& filename) {
|
||||
auto bpspatch::modify(const string& filename) -> bool {
|
||||
if(modifyFile.open(filename, filemap::mode::read) == false) return false;
|
||||
return modify(modifyFile.data(), modifyFile.size());
|
||||
}
|
||||
|
||||
bool bpspatch::source(const string& filename) {
|
||||
auto bpspatch::source(const string& filename) -> bool {
|
||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
||||
source(sourceFile.data(), sourceFile.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bpspatch::target(const string& filename) {
|
||||
auto bpspatch::target(const string& filename) -> bool {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::write) == false) return false;
|
||||
fp.truncate(modifyTargetSize);
|
||||
|
@ -117,30 +117,30 @@ bool bpspatch::target(const string& filename) {
|
|||
return true;
|
||||
}
|
||||
|
||||
string bpspatch::metadata() const {
|
||||
auto bpspatch::metadata() const -> string {
|
||||
return metadataString;
|
||||
}
|
||||
|
||||
unsigned bpspatch::size() const {
|
||||
auto bpspatch::size() const -> uint {
|
||||
return modifyTargetSize;
|
||||
}
|
||||
|
||||
bpspatch::result bpspatch::apply() {
|
||||
auto bpspatch::apply() -> result {
|
||||
if(modifySize < 19) return result::patch_too_small;
|
||||
|
||||
Hash::CRC32 modifyChecksum, targetChecksum;
|
||||
unsigned modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
||||
uint modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
||||
|
||||
auto read = [&]() -> uint8_t {
|
||||
uint8_t data = modifyData[modifyOffset++];
|
||||
auto read = [&]() -> uint8 {
|
||||
uint8 data = modifyData[modifyOffset++];
|
||||
modifyChecksum.data(data);
|
||||
return data;
|
||||
};
|
||||
|
||||
auto decode = [&]() -> uint64_t {
|
||||
uint64_t data = 0, shift = 1;
|
||||
auto decode = [&]() -> uint64 {
|
||||
uint64 data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
uint8 x = read();
|
||||
data += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
|
@ -149,7 +149,7 @@ bpspatch::result bpspatch::apply() {
|
|||
return data;
|
||||
};
|
||||
|
||||
auto write = [&](uint8_t data) {
|
||||
auto write = [&](uint8 data) {
|
||||
targetData[outputOffset++] = data;
|
||||
targetChecksum.data(data);
|
||||
};
|
||||
|
@ -162,14 +162,14 @@ bpspatch::result bpspatch::apply() {
|
|||
modifySourceSize = decode();
|
||||
modifyTargetSize = decode();
|
||||
modifyMarkupSize = decode();
|
||||
for(unsigned n = 0; n < modifyMarkupSize; n++) read();
|
||||
for(uint n = 0; n < modifyMarkupSize; n++) read();
|
||||
|
||||
if(modifySourceSize > sourceSize) return result::source_too_small;
|
||||
if(modifyTargetSize > targetSize) return result::target_too_small;
|
||||
|
||||
while(modifyOffset < modifySize - 12) {
|
||||
unsigned length = decode();
|
||||
unsigned mode = length & 3;
|
||||
uint length = decode();
|
||||
uint mode = length & 3;
|
||||
length = (length >> 2) + 1;
|
||||
|
||||
switch(mode) {
|
||||
|
@ -181,7 +181,7 @@ bpspatch::result bpspatch::apply() {
|
|||
break;
|
||||
case SourceCopy:
|
||||
case TargetCopy:
|
||||
signed offset = decode();
|
||||
int offset = decode();
|
||||
bool negative = offset & 1;
|
||||
offset >>= 1;
|
||||
if(negative) offset = -offset;
|
||||
|
@ -197,13 +197,13 @@ bpspatch::result bpspatch::apply() {
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0;
|
||||
for(unsigned n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n;
|
||||
for(unsigned n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n;
|
||||
uint32_t checksum = modifyChecksum.value();
|
||||
for(unsigned n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n;
|
||||
uint32 modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0;
|
||||
for(uint n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n;
|
||||
for(uint n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n;
|
||||
uint32 checksum = modifyChecksum.value();
|
||||
for(uint n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n;
|
||||
|
||||
uint32_t sourceChecksum = Hash::CRC32(sourceData, modifySourceSize).value();
|
||||
uint32 sourceChecksum = Hash::CRC32(sourceData, modifySourceSize).value();
|
||||
|
||||
if(sourceChecksum != modifySourceChecksum) return result::source_checksum_invalid;
|
||||
if(targetChecksum.value() != modifyTargetChecksum) return result::target_checksum_invalid;
|
||||
|
|
|
@ -7,14 +7,14 @@ namespace nall {
|
|||
|
||||
struct bitvector {
|
||||
bitvector() = default;
|
||||
bitvector(unsigned size) { resize(size); }
|
||||
bitvector(uint size) { resize(size); }
|
||||
bitvector(const bitvector& source) { operator=(source); }
|
||||
bitvector(bitvector&& source) { operator=(move(source)); }
|
||||
~bitvector() { reset(); }
|
||||
|
||||
auto operator=(const bitvector& source) -> bitvector& {
|
||||
bits = source.bits;
|
||||
pool = (uint8_t*)memory::resize(pool, bytes());
|
||||
pool = (uint8*)memory::resize(pool, bytes());
|
||||
memory::copy(pool, source.pool, bytes());
|
||||
return *this;
|
||||
}
|
||||
|
@ -29,10 +29,10 @@ struct bitvector {
|
|||
|
||||
explicit operator bool() const { return bits > 0; }
|
||||
auto empty() const -> bool { return bits == 0; }
|
||||
auto size() const -> unsigned { return bits; }
|
||||
auto bytes() const -> unsigned { return (bits + 7) / 8; }
|
||||
auto data() -> uint8_t* { return pool; }
|
||||
auto data() const -> const uint8_t* { return pool; }
|
||||
auto size() const -> uint { return bits; }
|
||||
auto bytes() const -> uint { return (bits + 7) / 8; }
|
||||
auto data() -> uint8* { return pool; }
|
||||
auto data() const -> const uint8* { return pool; }
|
||||
|
||||
auto reset() -> void {
|
||||
if(pool) free(pool);
|
||||
|
@ -40,15 +40,15 @@ struct bitvector {
|
|||
bits = 0;
|
||||
}
|
||||
|
||||
auto resize(unsigned size) -> void {
|
||||
unsigned from = bits;
|
||||
auto resize(uint size) -> void {
|
||||
uint from = bits;
|
||||
bits = size;
|
||||
for(unsigned n = size; n < from; n++) clear(n); //on reduce
|
||||
pool = (uint8_t*)memory::resize(pool, bytes());
|
||||
for(unsigned n = from; n < size; n++) clear(n); //on expand
|
||||
for(uint n = size; n < from; n++) clear(n); //on reduce
|
||||
pool = (uint8*)memory::resize(pool, bytes());
|
||||
for(uint n = from; n < size; n++) clear(n); //on expand
|
||||
}
|
||||
|
||||
auto get(unsigned position) const -> bool {
|
||||
auto get(uint position) const -> bool {
|
||||
return pool[position >> 3] & (0x80 >> (position & 7));
|
||||
}
|
||||
|
||||
|
@ -58,60 +58,60 @@ struct bitvector {
|
|||
|
||||
auto set() -> void {
|
||||
memory::fill(pool, bytes(), 0xff);
|
||||
for(unsigned n = bits; n < bytes() * 8; n++) clear(n);
|
||||
for(uint n = bits; n < bytes() * 8; n++) clear(n);
|
||||
}
|
||||
|
||||
auto clear(unsigned position) -> void {
|
||||
auto clear(uint position) -> void {
|
||||
pool[position >> 3] &= ~(0x80 >> (position & 7));
|
||||
}
|
||||
|
||||
auto set(unsigned position) -> void {
|
||||
auto set(uint position) -> void {
|
||||
pool[position >> 3] |= (0x80 >> (position & 7));
|
||||
}
|
||||
|
||||
auto invert(unsigned position) -> void {
|
||||
auto invert(uint position) -> void {
|
||||
get(position) ? clear(position) : set(position);
|
||||
}
|
||||
|
||||
auto set(unsigned position, bool value) -> void {
|
||||
auto set(uint position, bool value) -> void {
|
||||
value ? set(position) : clear(position);
|
||||
}
|
||||
|
||||
struct reference {
|
||||
reference(bitvector& self, unsigned position) : self(self), position(position) {}
|
||||
reference(bitvector& self, uint position) : self(self), position(position) {}
|
||||
operator bool() const { return self.get(position); }
|
||||
auto operator=(bool value) -> reference& { self.set(position, value); return *this; }
|
||||
|
||||
protected:
|
||||
bitvector& self;
|
||||
unsigned position;
|
||||
uint position;
|
||||
};
|
||||
|
||||
auto operator[](unsigned position) -> reference {
|
||||
auto operator[](uint position) -> reference {
|
||||
return reference(*this, position);
|
||||
}
|
||||
|
||||
auto operator[](unsigned position) const -> bool {
|
||||
auto operator[](uint position) const -> bool {
|
||||
return get(position);
|
||||
}
|
||||
|
||||
struct iterator {
|
||||
iterator(bitvector& self, unsigned position) : self(self), position(position) {}
|
||||
iterator(bitvector& self, uint position) : self(self), position(position) {}
|
||||
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
|
||||
auto operator++() -> iterator& { position++; return *this; }
|
||||
auto operator*() -> reference { return self.operator[](position); }
|
||||
|
||||
protected:
|
||||
bitvector& self;
|
||||
unsigned position;
|
||||
uint position;
|
||||
};
|
||||
|
||||
auto begin() -> iterator { return iterator(*this, 0); }
|
||||
auto end() -> iterator { return iterator(*this, bits); }
|
||||
|
||||
protected:
|
||||
uint8_t* pool = nullptr;
|
||||
unsigned bits = 0;
|
||||
uint8* pool = nullptr;
|
||||
uint bits = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -7,52 +7,55 @@
|
|||
namespace nall { namespace Decode {
|
||||
|
||||
struct GZIP {
|
||||
string filename;
|
||||
uint8_t* data = nullptr;
|
||||
unsigned size = 0;
|
||||
|
||||
inline bool decompress(const string& filename);
|
||||
inline bool decompress(const uint8_t* data, unsigned size);
|
||||
|
||||
inline GZIP();
|
||||
inline ~GZIP();
|
||||
|
||||
inline auto decompress(const string& filename) -> bool;
|
||||
inline auto decompress(const uint8* data, uint size) -> bool;
|
||||
|
||||
string filename;
|
||||
uint8* data = nullptr;
|
||||
uint size = 0;
|
||||
};
|
||||
|
||||
bool GZIP::decompress(const string& filename) {
|
||||
GZIP::~GZIP() {
|
||||
if(data) delete[] data;
|
||||
}
|
||||
|
||||
auto GZIP::decompress(const string& filename) -> bool {
|
||||
if(auto memory = file::read(filename)) {
|
||||
return decompress(memory.data(), memory.size());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GZIP::decompress(const uint8_t* data, unsigned size) {
|
||||
auto GZIP::decompress(const uint8* data, uint size) -> bool {
|
||||
if(size < 18) return false;
|
||||
if(data[0] != 0x1f) return false;
|
||||
if(data[1] != 0x8b) return false;
|
||||
unsigned cm = data[2];
|
||||
unsigned flg = data[3];
|
||||
unsigned mtime = data[4];
|
||||
uint cm = data[2];
|
||||
uint flg = data[3];
|
||||
uint mtime = data[4];
|
||||
mtime |= data[5] << 8;
|
||||
mtime |= data[6] << 16;
|
||||
mtime |= data[7] << 24;
|
||||
unsigned xfl = data[8];
|
||||
unsigned os = data[9];
|
||||
unsigned p = 10;
|
||||
unsigned isize = data[size - 4];
|
||||
uint xfl = data[8];
|
||||
uint os = data[9];
|
||||
uint p = 10;
|
||||
uint isize = data[size - 4];
|
||||
isize |= data[size - 3] << 8;
|
||||
isize |= data[size - 2] << 16;
|
||||
isize |= data[size - 1] << 24;
|
||||
filename = "";
|
||||
|
||||
if(flg & 0x04) { //FEXTRA
|
||||
unsigned xlen = data[p + 0];
|
||||
uint xlen = data[p + 0];
|
||||
xlen |= data[p + 1] << 8;
|
||||
p += 2 + xlen;
|
||||
}
|
||||
|
||||
if(flg & 0x08) { //FNAME
|
||||
char buffer[PATH_MAX];
|
||||
for(unsigned n = 0; n < PATH_MAX; n++, p++) {
|
||||
for(uint n = 0; n < PATH_MAX; n++, p++) {
|
||||
buffer[n] = data[p];
|
||||
if(data[p] == 0) break;
|
||||
}
|
||||
|
@ -73,13 +76,6 @@ bool GZIP::decompress(const uint8_t* data, unsigned size) {
|
|||
return inflate(this->data, this->size, data + p, size - p - 8);
|
||||
}
|
||||
|
||||
GZIP::GZIP() {
|
||||
}
|
||||
|
||||
GZIP::~GZIP() {
|
||||
if(data) delete[] data;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
namespace nall { namespace Decode {
|
||||
|
||||
namespace puff {
|
||||
inline int puff(
|
||||
inline auto puff(
|
||||
unsigned char* dest, unsigned long* destlen,
|
||||
unsigned char* source, unsigned long* sourcelen
|
||||
);
|
||||
) -> int;
|
||||
}
|
||||
|
||||
inline bool inflate(
|
||||
uint8_t* target, unsigned targetLength,
|
||||
const uint8_t* source, unsigned sourceLength
|
||||
) {
|
||||
inline auto inflate(
|
||||
uint8* target, uint targetLength,
|
||||
const uint8* source, uint sourceLength
|
||||
) -> bool {
|
||||
unsigned long tl = targetLength, sl = sourceLength;
|
||||
int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl);
|
||||
return result == 0;
|
||||
|
@ -23,7 +23,7 @@ inline bool inflate(
|
|||
|
||||
namespace puff {
|
||||
|
||||
enum {
|
||||
enum : uint {
|
||||
MAXBITS = 15,
|
||||
MAXLCODES = 286,
|
||||
MAXDCODES = 30,
|
||||
|
@ -50,7 +50,7 @@ struct huffman {
|
|||
short* symbol;
|
||||
};
|
||||
|
||||
inline int bits(state* s, int need) {
|
||||
inline auto bits(state* s, int need) -> int {
|
||||
long val;
|
||||
|
||||
val = s->bitbuf;
|
||||
|
@ -66,8 +66,8 @@ inline int bits(state* s, int need) {
|
|||
return (int)(val & ((1L << need) - 1));
|
||||
}
|
||||
|
||||
inline int stored(state* s) {
|
||||
unsigned len;
|
||||
inline auto stored(state* s) -> int {
|
||||
uint len;
|
||||
|
||||
s->bitbuf = 0;
|
||||
s->bitcnt = 0;
|
||||
|
@ -91,7 +91,7 @@ inline int stored(state* s) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
inline int decode(state* s, huffman* h) {
|
||||
inline auto decode(state* s, huffman* h) -> int {
|
||||
int len, code, first, count, index, bitbuf, left;
|
||||
short* next;
|
||||
|
||||
|
@ -126,7 +126,7 @@ inline int decode(state* s, huffman* h) {
|
|||
return -10;
|
||||
}
|
||||
|
||||
inline int construct(huffman* h, short* length, int n) {
|
||||
inline auto construct(huffman* h, short* length, int n) -> int {
|
||||
int symbol, len, left;
|
||||
short offs[MAXBITS + 1];
|
||||
|
||||
|
@ -151,9 +151,9 @@ inline int construct(huffman* h, short* length, int n) {
|
|||
return left;
|
||||
}
|
||||
|
||||
inline int codes(state* s, huffman* lencode, huffman* distcode) {
|
||||
inline auto codes(state* s, huffman* lencode, huffman* distcode) -> int {
|
||||
int symbol, len;
|
||||
unsigned dist;
|
||||
uint dist;
|
||||
static const short lens[29] = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
||||
|
@ -213,7 +213,7 @@ inline int codes(state* s, huffman* lencode, huffman* distcode) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
inline int fixed(state* s) {
|
||||
inline auto fixed(state* s) -> int {
|
||||
static int virgin = 1;
|
||||
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
|
||||
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
||||
|
@ -243,7 +243,7 @@ inline int fixed(state* s) {
|
|||
return codes(s, &lencode, &distcode);
|
||||
}
|
||||
|
||||
inline int dynamic(state* s) {
|
||||
inline auto dynamic(state* s) -> int {
|
||||
int nlen, ndist, ncode, index, err;
|
||||
short lengths[MAXCODES];
|
||||
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
|
||||
|
@ -303,10 +303,10 @@ inline int dynamic(state* s) {
|
|||
return codes(s, &lencode, &distcode);
|
||||
}
|
||||
|
||||
inline int puff(
|
||||
inline auto puff(
|
||||
unsigned char* dest, unsigned long* destlen,
|
||||
unsigned char* source, unsigned long* sourcelen
|
||||
) {
|
||||
) -> int {
|
||||
state s;
|
||||
int last, type, err;
|
||||
|
||||
|
|
|
@ -7,75 +7,83 @@
|
|||
namespace nall { namespace Decode {
|
||||
|
||||
struct PNG {
|
||||
inline PNG();
|
||||
inline ~PNG();
|
||||
|
||||
inline auto load(const string& filename) -> bool;
|
||||
inline auto load(const uint8* sourceData, uint sourceSize) -> bool;
|
||||
inline auto readbits(const uint8*& data) -> uint;
|
||||
|
||||
struct Info {
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned bitDepth;
|
||||
uint width;
|
||||
uint height;
|
||||
uint bitDepth;
|
||||
//colorType:
|
||||
//0 = L (luma)
|
||||
//2 = R,G,B
|
||||
//3 = P (palette)
|
||||
//4 = L,A
|
||||
//6 = R,G,B,A
|
||||
unsigned colorType;
|
||||
unsigned compressionMethod;
|
||||
unsigned filterType;
|
||||
unsigned interlaceMethod;
|
||||
uint colorType;
|
||||
uint compressionMethod;
|
||||
uint filterType;
|
||||
uint interlaceMethod;
|
||||
|
||||
unsigned bytesPerPixel;
|
||||
unsigned pitch;
|
||||
uint bytesPerPixel;
|
||||
uint pitch;
|
||||
|
||||
uint8_t palette[256][3];
|
||||
uint8 palette[256][3];
|
||||
} info;
|
||||
|
||||
uint8_t* data = nullptr;
|
||||
unsigned size = 0;
|
||||
uint8* data = nullptr;
|
||||
uint size = 0;
|
||||
|
||||
inline bool load(const string& filename);
|
||||
inline bool load(const uint8_t* sourceData, unsigned sourceSize);
|
||||
inline unsigned readbits(const uint8_t*& data);
|
||||
unsigned bitpos = 0;
|
||||
|
||||
inline PNG();
|
||||
inline ~PNG();
|
||||
uint bitpos = 0;
|
||||
|
||||
protected:
|
||||
enum class FourCC : unsigned {
|
||||
enum class FourCC : uint {
|
||||
IHDR = 0x49484452,
|
||||
PLTE = 0x504c5445,
|
||||
IDAT = 0x49444154,
|
||||
IEND = 0x49454e44,
|
||||
};
|
||||
|
||||
inline unsigned interlace(unsigned pass, unsigned index);
|
||||
inline unsigned inflateSize();
|
||||
inline bool deinterlace(const uint8_t*& inputData, unsigned pass);
|
||||
inline bool filter(uint8_t* outputData, const uint8_t* inputData, unsigned width, unsigned height);
|
||||
inline unsigned read(const uint8_t* data, unsigned length);
|
||||
inline auto interlace(uint pass, uint index) -> uint;
|
||||
inline auto inflateSize() -> uint;
|
||||
inline auto deinterlace(const uint8*& inputData, uint pass) -> bool;
|
||||
inline auto filter(uint8* outputData, const uint8* inputData, uint width, uint height) -> bool;
|
||||
inline auto read(const uint8* data, uint length) -> uint;
|
||||
};
|
||||
|
||||
bool PNG::load(const string& filename) {
|
||||
PNG::PNG() {
|
||||
}
|
||||
|
||||
PNG::~PNG() {
|
||||
if(data) delete[] data;
|
||||
}
|
||||
|
||||
auto PNG::load(const string& filename) -> bool {
|
||||
if(auto memory = file::read(filename)) {
|
||||
return load(memory.data(), memory.size());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
||||
auto PNG::load(const uint8* sourceData, uint sourceSize) -> bool {
|
||||
if(sourceSize < 8) return false;
|
||||
if(read(sourceData + 0, 4) != 0x89504e47) return false;
|
||||
if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false;
|
||||
|
||||
uint8_t* compressedData = nullptr;
|
||||
unsigned compressedSize = 0;
|
||||
uint8* compressedData = nullptr;
|
||||
uint compressedSize = 0;
|
||||
|
||||
unsigned offset = 8;
|
||||
uint offset = 8;
|
||||
while(offset < sourceSize) {
|
||||
unsigned length = read(sourceData + offset + 0, 4);
|
||||
unsigned fourCC = read(sourceData + offset + 4, 4);
|
||||
unsigned checksum = read(sourceData + offset + 8 + length, 4);
|
||||
uint length = read(sourceData + offset + 0, 4);
|
||||
uint fourCC = read(sourceData + offset + 4, 4);
|
||||
uint checksum = read(sourceData + offset + 8 + length, 4);
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IHDR) {
|
||||
if(fourCC == (uint)FourCC::IHDR) {
|
||||
info.width = read(sourceData + offset + 8, 4);
|
||||
info.height = read(sourceData + offset + 12, 4);
|
||||
info.bitDepth = read(sourceData + offset + 16, 1);
|
||||
|
@ -108,30 +116,30 @@ bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
|||
info.pitch = (int)info.width * info.bytesPerPixel;
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::PLTE) {
|
||||
if(fourCC == (uint)FourCC::PLTE) {
|
||||
if(length % 3) return false;
|
||||
for(unsigned n = 0, p = offset + 8; n < length / 3; n++) {
|
||||
for(uint n = 0, p = offset + 8; n < length / 3; n++) {
|
||||
info.palette[n][0] = sourceData[p++];
|
||||
info.palette[n][1] = sourceData[p++];
|
||||
info.palette[n][2] = sourceData[p++];
|
||||
}
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IDAT) {
|
||||
compressedData = (uint8_t*)realloc(compressedData, compressedSize + length);
|
||||
if(fourCC == (uint)FourCC::IDAT) {
|
||||
compressedData = (uint8*)realloc(compressedData, compressedSize + length);
|
||||
memcpy(compressedData + compressedSize, sourceData + offset + 8, length);
|
||||
compressedSize += length;
|
||||
}
|
||||
|
||||
if(fourCC == (unsigned)FourCC::IEND) {
|
||||
if(fourCC == (uint)FourCC::IEND) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += 4 + 4 + length + 4;
|
||||
}
|
||||
|
||||
unsigned interlacedSize = inflateSize();
|
||||
uint8_t *interlacedData = new uint8_t[interlacedSize];
|
||||
uint interlacedSize = inflateSize();
|
||||
uint8 *interlacedData = new uint8[interlacedSize];
|
||||
|
||||
bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6);
|
||||
free(compressedData);
|
||||
|
@ -142,7 +150,7 @@ bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
|||
}
|
||||
|
||||
size = info.width * info.height * info.bytesPerPixel;
|
||||
data = new uint8_t[size];
|
||||
data = new uint8[size];
|
||||
|
||||
if(info.interlaceMethod == 0) {
|
||||
if(filter(data, interlacedData, info.width, info.height) == false) {
|
||||
|
@ -152,8 +160,8 @@ bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
const uint8_t *passData = interlacedData;
|
||||
for(unsigned pass = 0; pass < 7; pass++) {
|
||||
const uint8* passData = interlacedData;
|
||||
for(uint pass = 0; pass < 7; pass++) {
|
||||
if(deinterlace(passData, pass) == false) {
|
||||
delete[] interlacedData;
|
||||
delete[] data;
|
||||
|
@ -167,8 +175,8 @@ bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
|||
return true;
|
||||
}
|
||||
|
||||
unsigned PNG::interlace(unsigned pass, unsigned index) {
|
||||
static const unsigned data[7][4] = {
|
||||
auto PNG::interlace(uint pass, uint index) -> uint {
|
||||
static const uint data[7][4] = {
|
||||
//x-distance, y-distance, x-origin, y-origin
|
||||
{8, 8, 0, 0},
|
||||
{8, 8, 4, 0},
|
||||
|
@ -181,39 +189,39 @@ unsigned PNG::interlace(unsigned pass, unsigned index) {
|
|||
return data[pass][index];
|
||||
}
|
||||
|
||||
unsigned PNG::inflateSize() {
|
||||
auto PNG::inflateSize() -> uint {
|
||||
if(info.interlaceMethod == 0) {
|
||||
return info.width * info.height * info.bytesPerPixel + info.height;
|
||||
}
|
||||
|
||||
unsigned size = 0;
|
||||
for(unsigned pass = 0; pass < 7; pass++) {
|
||||
unsigned xd = interlace(pass, 0), yd = interlace(pass, 1);
|
||||
unsigned xo = interlace(pass, 2), yo = interlace(pass, 3);
|
||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
||||
uint size = 0;
|
||||
for(uint pass = 0; pass < 7; pass++) {
|
||||
uint xd = interlace(pass, 0), yd = interlace(pass, 1);
|
||||
uint xo = interlace(pass, 2), yo = interlace(pass, 3);
|
||||
uint width = (info.width + (xd - xo - 1)) / xd;
|
||||
uint height = (info.height + (yd - yo - 1)) / yd;
|
||||
if(width == 0 || height == 0) continue;
|
||||
size += width * height * info.bytesPerPixel + height;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool PNG::deinterlace(const uint8_t*& inputData, unsigned pass) {
|
||||
unsigned xd = interlace(pass, 0), yd = interlace(pass, 1);
|
||||
unsigned xo = interlace(pass, 2), yo = interlace(pass, 3);
|
||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
||||
auto PNG::deinterlace(const uint8*& inputData, uint pass) -> bool {
|
||||
uint xd = interlace(pass, 0), yd = interlace(pass, 1);
|
||||
uint xo = interlace(pass, 2), yo = interlace(pass, 3);
|
||||
uint width = (info.width + (xd - xo - 1)) / xd;
|
||||
uint height = (info.height + (yd - yo - 1)) / yd;
|
||||
if(width == 0 || height == 0) return true;
|
||||
|
||||
unsigned outputSize = width * height * info.bytesPerPixel;
|
||||
uint8_t* outputData = new uint8_t[outputSize];
|
||||
uint outputSize = width * height * info.bytesPerPixel;
|
||||
uint8* outputData = new uint8[outputSize];
|
||||
bool result = filter(outputData, inputData, width, height);
|
||||
|
||||
const uint8_t* rd = outputData;
|
||||
for(unsigned y = yo; y < info.height; y += yd) {
|
||||
uint8_t* wr = data + y * info.pitch;
|
||||
for(unsigned x = xo; x < info.width; x += xd) {
|
||||
for(unsigned b = 0; b < info.bytesPerPixel; b++) {
|
||||
const uint8* rd = outputData;
|
||||
for(uint y = yo; y < info.height; y += yd) {
|
||||
uint8* wr = data + y * info.pitch;
|
||||
for(uint x = xo; x < info.width; x += xd) {
|
||||
for(uint b = 0; b < info.bytesPerPixel; b++) {
|
||||
wr[x * info.bytesPerPixel + b] = *rd++;
|
||||
}
|
||||
}
|
||||
|
@ -224,12 +232,12 @@ bool PNG::deinterlace(const uint8_t*& inputData, unsigned pass) {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width, unsigned height) {
|
||||
uint8_t* wr = outputData;
|
||||
const uint8_t* rd = inputData;
|
||||
auto PNG::filter(uint8* outputData, const uint8* inputData, uint width, uint height) -> bool {
|
||||
uint8* wr = outputData;
|
||||
const uint8* rd = inputData;
|
||||
int bpp = info.bytesPerPixel, pitch = width * bpp;
|
||||
for(int y = 0; y < height; y++) {
|
||||
uint8_t filter = *rd++;
|
||||
uint8 filter = *rd++;
|
||||
|
||||
switch(filter) {
|
||||
case 0x00: //None
|
||||
|
@ -255,7 +263,7 @@ bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width,
|
|||
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
||||
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
||||
|
||||
wr[x] = rd[x] + (uint8_t)((a + b) / 2);
|
||||
wr[x] = rd[x] + (uint8)((a + b) / 2);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -270,7 +278,7 @@ bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width,
|
|||
short pb = p > b ? p - b : b - p;
|
||||
short pc = p > c ? p - c : c - p;
|
||||
|
||||
uint8_t paeth = (uint8_t)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
|
||||
uint8 paeth = (uint8)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
|
||||
|
||||
wr[x] = rd[x] + paeth;
|
||||
}
|
||||
|
@ -287,14 +295,14 @@ bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width,
|
|||
return true;
|
||||
}
|
||||
|
||||
unsigned PNG::read(const uint8_t* data, unsigned length) {
|
||||
unsigned result = 0;
|
||||
auto PNG::read(const uint8* data, uint length) -> uint {
|
||||
uint result = 0;
|
||||
while(length--) result = (result << 8) | (*data++);
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned PNG::readbits(const uint8_t*& data) {
|
||||
unsigned result = 0;
|
||||
auto PNG::readbits(const uint8*& data) -> uint {
|
||||
uint result = 0;
|
||||
switch(info.bitDepth) {
|
||||
case 1:
|
||||
result = (*data >> bitpos) & 1;
|
||||
|
@ -322,13 +330,6 @@ unsigned PNG::readbits(const uint8_t*& data) {
|
|||
return result;
|
||||
}
|
||||
|
||||
PNG::PNG() {
|
||||
}
|
||||
|
||||
PNG::~PNG() {
|
||||
if(data) delete[] data;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,14 +11,18 @@ namespace nall { namespace Decode {
|
|||
struct ZIP {
|
||||
struct File {
|
||||
string name;
|
||||
const uint8_t* data;
|
||||
unsigned size;
|
||||
unsigned csize;
|
||||
unsigned cmode; //0 = uncompressed, 8 = deflate
|
||||
unsigned crc32;
|
||||
const uint8* data;
|
||||
uint size;
|
||||
uint csize;
|
||||
uint cmode; //0 = uncompressed, 8 = deflate
|
||||
uint crc32;
|
||||
};
|
||||
|
||||
inline bool open(const string& filename) {
|
||||
~ZIP() {
|
||||
close();
|
||||
}
|
||||
|
||||
auto open(const string& filename) -> bool {
|
||||
close();
|
||||
if(fm.open(filename, filemap::mode::read) == false) return false;
|
||||
if(open(fm.data(), fm.size()) == false) {
|
||||
|
@ -28,7 +32,7 @@ struct ZIP {
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool open(const uint8_t* data, unsigned size) {
|
||||
auto open(const uint8* data, uint size) -> bool {
|
||||
if(size < 22) return false;
|
||||
|
||||
filedata = data;
|
||||
|
@ -36,19 +40,19 @@ struct ZIP {
|
|||
|
||||
file.reset();
|
||||
|
||||
const uint8_t* footer = data + size - 22;
|
||||
const uint8* footer = data + size - 22;
|
||||
while(true) {
|
||||
if(footer <= data + 22) return false;
|
||||
if(read(footer, 4) == 0x06054b50) {
|
||||
unsigned commentlength = read(footer + 20, 2);
|
||||
uint commentlength = read(footer + 20, 2);
|
||||
if(footer + 22 + commentlength == data + size) break;
|
||||
}
|
||||
footer--;
|
||||
}
|
||||
const uint8_t* directory = data + read(footer + 16, 4);
|
||||
const uint8* directory = data + read(footer + 16, 4);
|
||||
|
||||
while(true) {
|
||||
unsigned signature = read(directory + 0, 4);
|
||||
uint signature = read(directory + 0, 4);
|
||||
if(signature != 0x02014b50) break;
|
||||
|
||||
File file;
|
||||
|
@ -57,9 +61,9 @@ struct ZIP {
|
|||
file.csize = read(directory + 20, 4);
|
||||
file.size = read(directory + 24, 4);
|
||||
|
||||
unsigned namelength = read(directory + 28, 2);
|
||||
unsigned extralength = read(directory + 30, 2);
|
||||
unsigned commentlength = read(directory + 32, 2);
|
||||
uint namelength = read(directory + 28, 2);
|
||||
uint extralength = read(directory + 30, 2);
|
||||
uint commentlength = read(directory + 32, 2);
|
||||
|
||||
char* filename = new char[namelength + 1];
|
||||
memcpy(filename, directory + 46, namelength);
|
||||
|
@ -67,9 +71,9 @@ struct ZIP {
|
|||
file.name = filename;
|
||||
delete[] filename;
|
||||
|
||||
unsigned offset = read(directory + 42, 4);
|
||||
unsigned offsetNL = read(data + offset + 26, 2);
|
||||
unsigned offsetEL = read(data + offset + 28, 2);
|
||||
uint offset = read(directory + 42, 4);
|
||||
uint offsetNL = read(data + offset + 26, 2);
|
||||
uint offsetEL = read(data + offset + 28, 2);
|
||||
file.data = data + offset + 30 + offsetNL + offsetEL;
|
||||
|
||||
directory += 46 + namelength + extralength + commentlength;
|
||||
|
@ -80,8 +84,8 @@ struct ZIP {
|
|||
return true;
|
||||
}
|
||||
|
||||
inline vector<uint8_t> extract(File& file) {
|
||||
vector<uint8_t> buffer;
|
||||
auto extract(File& file) -> vector<uint8> {
|
||||
vector<uint8> buffer;
|
||||
|
||||
if(file.cmode == 0) {
|
||||
buffer.resize(file.size);
|
||||
|
@ -98,21 +102,17 @@ struct ZIP {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
inline void close() {
|
||||
auto close() -> void {
|
||||
if(fm.open()) fm.close();
|
||||
}
|
||||
|
||||
~ZIP() {
|
||||
close();
|
||||
}
|
||||
|
||||
protected:
|
||||
filemap fm;
|
||||
const uint8_t* filedata;
|
||||
unsigned filesize;
|
||||
const uint8* filedata;
|
||||
uint filesize;
|
||||
|
||||
unsigned read(const uint8_t* data, unsigned size) {
|
||||
unsigned result = 0, shift = 0;
|
||||
auto read(const uint8* data, uint size) -> uint {
|
||||
uint result = 0, shift = 0;
|
||||
while(size--) { result |= *data++ << shift; shift += 8; }
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace nall {
|
|||
|
||||
template<typename T> struct function;
|
||||
|
||||
template<typename R, typename... P> struct function<R (P...)> {
|
||||
template<typename R, typename... P> struct function<auto (P...) -> R> {
|
||||
//value = true if auto L::operator()(P...) -> R exists
|
||||
template<typename L> struct is_compatible {
|
||||
template<typename T> static auto exists(T*) -> const typename is_same<R, decltype(declval<T>().operator()(declval<P>()...))>::type;
|
||||
|
|
|
@ -4,26 +4,24 @@ namespace nall {
|
|||
namespace mosaic {
|
||||
|
||||
struct bitstream {
|
||||
filemap fp;
|
||||
uint8_t* data = nullptr;
|
||||
unsigned size = 0;
|
||||
bool readonly = false;
|
||||
bool endian = 1;
|
||||
~bitstream() {
|
||||
close();
|
||||
}
|
||||
|
||||
bool read(uint64_t addr) const {
|
||||
auto read(uint64 addr) const -> bool {
|
||||
if(data == nullptr || (addr >> 3) >= size) return 0;
|
||||
unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
||||
uint mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
||||
return data[addr >> 3] & mask;
|
||||
}
|
||||
|
||||
void write(uint64_t addr, bool value) {
|
||||
auto write(uint64 addr, bool value) -> void {
|
||||
if(data == nullptr || readonly == true || (addr >> 3) >= size) return;
|
||||
unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
||||
uint mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
||||
if(value == 0) data[addr >> 3] &= ~mask;
|
||||
if(value == 1) data[addr >> 3] |= mask;
|
||||
}
|
||||
|
||||
bool open(const string& filename) {
|
||||
auto open(const string& filename) -> bool {
|
||||
readonly = false;
|
||||
if(fp.open(filename, filemap::mode::readwrite) == false) {
|
||||
readonly = true;
|
||||
|
@ -36,17 +34,16 @@ struct bitstream {
|
|||
return true;
|
||||
}
|
||||
|
||||
void close() {
|
||||
auto close() -> void {
|
||||
fp.close();
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
bitstream() {
|
||||
}
|
||||
|
||||
~bitstream() {
|
||||
close();
|
||||
}
|
||||
filemap fp;
|
||||
uint8* data = nullptr;
|
||||
uint size = 0;
|
||||
bool readonly = false;
|
||||
bool endian = 1;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,54 +4,60 @@ namespace nall {
|
|||
namespace mosaic {
|
||||
|
||||
struct context {
|
||||
unsigned offset;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned count;
|
||||
context() {
|
||||
reset();
|
||||
}
|
||||
|
||||
bool endian; //0 = lsb, 1 = msb
|
||||
bool order; //0 = linear, 1 = planar
|
||||
unsigned depth; //1 - 24bpp
|
||||
|
||||
unsigned blockWidth;
|
||||
unsigned blockHeight;
|
||||
unsigned blockStride;
|
||||
unsigned blockOffset;
|
||||
vector<unsigned> block;
|
||||
|
||||
unsigned tileWidth;
|
||||
unsigned tileHeight;
|
||||
unsigned tileStride;
|
||||
unsigned tileOffset;
|
||||
vector<unsigned> tile;
|
||||
|
||||
unsigned mosaicWidth;
|
||||
unsigned mosaicHeight;
|
||||
unsigned mosaicStride;
|
||||
unsigned mosaicOffset;
|
||||
vector<unsigned> mosaic;
|
||||
|
||||
unsigned paddingWidth;
|
||||
unsigned paddingHeight;
|
||||
unsigned paddingColor;
|
||||
vector<unsigned> palette;
|
||||
|
||||
unsigned objectWidth() const { return blockWidth * tileWidth * mosaicWidth + paddingWidth; }
|
||||
unsigned objectHeight() const { return blockHeight * tileHeight * mosaicHeight + paddingHeight; }
|
||||
unsigned objectSize() const {
|
||||
unsigned size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight
|
||||
+ blockOffset * tileHeight * mosaicWidth * mosaicHeight
|
||||
+ tileStride * mosaicWidth * mosaicHeight
|
||||
+ tileOffset * mosaicHeight;
|
||||
auto objectWidth() const -> uint { return blockWidth * tileWidth * mosaicWidth + paddingWidth; }
|
||||
auto objectHeight() const -> uint { return blockHeight * tileHeight * mosaicHeight + paddingHeight; }
|
||||
auto objectSize() const -> uint {
|
||||
uint size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight
|
||||
+ blockOffset * tileHeight * mosaicWidth * mosaicHeight
|
||||
+ tileStride * mosaicWidth * mosaicHeight
|
||||
+ tileOffset * mosaicHeight;
|
||||
return max(1u, size);
|
||||
}
|
||||
|
||||
unsigned eval(const string& expression) {
|
||||
auto reset() -> void {
|
||||
offset = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
count = 0;
|
||||
|
||||
endian = 1;
|
||||
order = 0;
|
||||
depth = 1;
|
||||
|
||||
blockWidth = 1;
|
||||
blockHeight = 1;
|
||||
blockStride = 0;
|
||||
blockOffset = 0;
|
||||
block.reset();
|
||||
|
||||
tileWidth = 1;
|
||||
tileHeight = 1;
|
||||
tileStride = 0;
|
||||
tileOffset = 0;
|
||||
tile.reset();
|
||||
|
||||
mosaicWidth = 1;
|
||||
mosaicHeight = 1;
|
||||
mosaicStride = 0;
|
||||
mosaicOffset = 0;
|
||||
mosaic.reset();
|
||||
|
||||
paddingWidth = 0;
|
||||
paddingHeight = 0;
|
||||
paddingColor = 0;
|
||||
palette.reset();
|
||||
}
|
||||
|
||||
auto eval(const string& expression) -> uint {
|
||||
if(auto result = Eval::integer(expression)) return result();
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void eval(vector<unsigned>& buffer, const string& expression_) {
|
||||
auto eval(vector<uint>& buffer, const string& expression_) -> void {
|
||||
string expression = expression_;
|
||||
bool function = false;
|
||||
for(auto& c : expression) {
|
||||
|
@ -68,13 +74,13 @@ struct context {
|
|||
lstring part = item.split(") ", 1L);
|
||||
lstring args = part[0].split(";", 3L).strip();
|
||||
|
||||
unsigned length = eval(args(0, "0"));
|
||||
unsigned offset = eval(args(1, "0"));
|
||||
unsigned stride = eval(args(2, "0"));
|
||||
uint length = eval(args(0, "0"));
|
||||
uint offset = eval(args(1, "0"));
|
||||
uint stride = eval(args(2, "0"));
|
||||
if(args.size() < 2) offset = buffer.size();
|
||||
if(args.size() < 3) stride = 1;
|
||||
|
||||
for(unsigned n = 0; n < length; n++) {
|
||||
for(uint n = 0; n < length; n++) {
|
||||
string fn = part[1];
|
||||
fn.replace("n", string{n});
|
||||
fn.replace("o", string{offset});
|
||||
|
@ -84,7 +90,7 @@ struct context {
|
|||
offset += stride;
|
||||
}
|
||||
} else if(item.match("base64*")) {
|
||||
unsigned offset = 0;
|
||||
uint offset = 0;
|
||||
item.ltrim("base64", 1L);
|
||||
if(item.match("(?*) *")) {
|
||||
item.ltrim("(", 1L);
|
||||
|
@ -110,7 +116,7 @@ struct context {
|
|||
}
|
||||
}
|
||||
|
||||
void parse(const string& data) {
|
||||
auto parse(const string& data) -> void {
|
||||
reset();
|
||||
|
||||
lstring lines = data.split("\n");
|
||||
|
@ -154,14 +160,15 @@ struct context {
|
|||
sanitize();
|
||||
}
|
||||
|
||||
bool load(const string& filename) {
|
||||
string filedata = string::read(filename);
|
||||
if(filedata.empty()) return false;
|
||||
parse(filedata);
|
||||
return true;
|
||||
auto load(const string& filename) -> bool {
|
||||
if(auto filedata = string::read(filename)) {
|
||||
parse(filedata);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void sanitize() {
|
||||
auto sanitize() -> void {
|
||||
if(depth < 1) depth = 1;
|
||||
if(depth > 24) depth = 24;
|
||||
|
||||
|
@ -179,43 +186,37 @@ struct context {
|
|||
for(auto& color : palette) color |= 255u << 24;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
offset = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
count = 0;
|
||||
uint offset;
|
||||
uint width;
|
||||
uint height;
|
||||
uint count;
|
||||
|
||||
endian = 1;
|
||||
order = 0;
|
||||
depth = 1;
|
||||
bool endian; //0 = lsb, 1 = msb
|
||||
bool order; //0 = linear, 1 = planar
|
||||
uint depth; //1 - 24bpp
|
||||
|
||||
blockWidth = 1;
|
||||
blockHeight = 1;
|
||||
blockStride = 0;
|
||||
blockOffset = 0;
|
||||
block.reset();
|
||||
uint blockWidth;
|
||||
uint blockHeight;
|
||||
uint blockStride;
|
||||
uint blockOffset;
|
||||
vector<uint> block;
|
||||
|
||||
tileWidth = 1;
|
||||
tileHeight = 1;
|
||||
tileStride = 0;
|
||||
tileOffset = 0;
|
||||
tile.reset();
|
||||
uint tileWidth;
|
||||
uint tileHeight;
|
||||
uint tileStride;
|
||||
uint tileOffset;
|
||||
vector<uint> tile;
|
||||
|
||||
mosaicWidth = 1;
|
||||
mosaicHeight = 1;
|
||||
mosaicStride = 0;
|
||||
mosaicOffset = 0;
|
||||
mosaic.reset();
|
||||
uint mosaicWidth;
|
||||
uint mosaicHeight;
|
||||
uint mosaicStride;
|
||||
uint mosaicOffset;
|
||||
vector<uint> mosaic;
|
||||
|
||||
paddingWidth = 0;
|
||||
paddingHeight = 0;
|
||||
paddingColor = 0;
|
||||
palette.reset();
|
||||
}
|
||||
|
||||
context() {
|
||||
reset();
|
||||
}
|
||||
uint paddingWidth;
|
||||
uint paddingHeight;
|
||||
uint paddingColor;
|
||||
vector<uint> palette;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,77 +4,72 @@ namespace nall {
|
|||
namespace mosaic {
|
||||
|
||||
struct parser {
|
||||
image canvas;
|
||||
|
||||
//export from bitstream to canvas
|
||||
void load(bitstream& stream, uint64_t offset, context& ctx, unsigned width, unsigned height) {
|
||||
auto load(bitstream& stream, uint64 offset, context& ctx, uint width, uint height) -> void {
|
||||
canvas.allocate(width, height);
|
||||
canvas.fill(ctx.paddingColor);
|
||||
parse(1, stream, offset, ctx, width, height);
|
||||
}
|
||||
|
||||
//import from canvas to bitstream
|
||||
bool save(bitstream& stream, uint64_t offset, context& ctx) {
|
||||
auto save(bitstream& stream, uint64_t offset, context& ctx) -> bool {
|
||||
if(stream.readonly) return false;
|
||||
parse(0, stream, offset, ctx, canvas.width(), canvas.height());
|
||||
return true;
|
||||
}
|
||||
|
||||
inline parser() : canvas(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0) {
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t read(unsigned x, unsigned y) const {
|
||||
unsigned addr = y * canvas.width() + x;
|
||||
auto read(uint x, uint y) const -> uint32 {
|
||||
uint addr = y * canvas.width() + x;
|
||||
if(addr >= canvas.width() * canvas.height()) return 0u;
|
||||
uint32_t *buffer = (uint32_t*)canvas.data();
|
||||
auto buffer = (uint32*)canvas.data();
|
||||
return buffer[addr];
|
||||
}
|
||||
|
||||
void write(unsigned x, unsigned y, uint32_t data) {
|
||||
unsigned addr = y * canvas.width() + x;
|
||||
auto write(uint x, uint y, uint32_t data) -> void {
|
||||
uint addr = y * canvas.width() + x;
|
||||
if(addr >= canvas.width() * canvas.height()) return;
|
||||
uint32_t *buffer = (uint32_t*)canvas.data();
|
||||
auto buffer = (uint32*)canvas.data();
|
||||
buffer[addr] = data;
|
||||
}
|
||||
|
||||
void parse(bool load, bitstream& stream, uint64_t offset, context& ctx, unsigned width, unsigned height) {
|
||||
auto parse(bool load, bitstream& stream, uint64 offset, context& ctx, uint width, uint height) -> void {
|
||||
stream.endian = ctx.endian;
|
||||
unsigned canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
|
||||
unsigned canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
|
||||
unsigned bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
|
||||
uint canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
|
||||
uint canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
|
||||
uint bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
|
||||
|
||||
unsigned objectOffset = 0;
|
||||
for(unsigned objectY = 0; objectY < canvasHeight; objectY++) {
|
||||
for(unsigned objectX = 0; objectX < canvasWidth; objectX++) {
|
||||
uint objectOffset = 0;
|
||||
for(uint objectY = 0; objectY < canvasHeight; objectY++) {
|
||||
for(uint objectX = 0; objectX < canvasWidth; objectX++) {
|
||||
if(objectOffset >= ctx.count && ctx.count > 0) break;
|
||||
unsigned objectIX = objectX * ctx.objectWidth();
|
||||
unsigned objectIY = objectY * ctx.objectHeight();
|
||||
uint objectIX = objectX * ctx.objectWidth();
|
||||
uint objectIY = objectY * ctx.objectHeight();
|
||||
objectOffset++;
|
||||
|
||||
unsigned mosaicOffset = 0;
|
||||
for(unsigned mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
|
||||
for(unsigned mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
|
||||
unsigned mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
|
||||
unsigned mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
|
||||
unsigned mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
|
||||
uint mosaicOffset = 0;
|
||||
for(uint mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
|
||||
for(uint mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
|
||||
uint mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
|
||||
uint mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
|
||||
uint mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
|
||||
mosaicOffset++;
|
||||
|
||||
unsigned tileOffset = 0;
|
||||
for(unsigned tileY = 0; tileY < ctx.tileHeight; tileY++) {
|
||||
for(unsigned tileX = 0; tileX < ctx.tileWidth; tileX++) {
|
||||
unsigned tileData = ctx.tile(tileOffset, tileOffset);
|
||||
unsigned tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
|
||||
unsigned tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
|
||||
uint tileOffset = 0;
|
||||
for(uint tileY = 0; tileY < ctx.tileHeight; tileY++) {
|
||||
for(uint tileX = 0; tileX < ctx.tileWidth; tileX++) {
|
||||
uint tileData = ctx.tile(tileOffset, tileOffset);
|
||||
uint tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
|
||||
uint tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
|
||||
tileOffset++;
|
||||
|
||||
unsigned blockOffset = 0;
|
||||
for(unsigned blockY = 0; blockY < ctx.blockHeight; blockY++) {
|
||||
for(unsigned blockX = 0; blockX < ctx.blockWidth; blockX++) {
|
||||
uint blockOffset = 0;
|
||||
for(uint blockY = 0; blockY < ctx.blockHeight; blockY++) {
|
||||
for(uint blockX = 0; blockX < ctx.blockWidth; blockX++) {
|
||||
if(load) {
|
||||
unsigned palette = 0;
|
||||
for(unsigned n = 0; n < ctx.depth; n++) {
|
||||
unsigned index = blockOffset++;
|
||||
uint palette = 0;
|
||||
for(uint n = 0; n < ctx.depth; n++) {
|
||||
uint index = blockOffset++;
|
||||
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
||||
palette |= stream.read(offset + ctx.block(index, index)) << n;
|
||||
}
|
||||
|
@ -90,8 +85,8 @@ private:
|
|||
objectIY + mosaicIY + tileIY + blockY
|
||||
);
|
||||
|
||||
for(unsigned n = 0; n < ctx.depth; n++) {
|
||||
unsigned index = blockOffset++;
|
||||
for(uint n = 0; n < ctx.depth; n++) {
|
||||
uint index = blockOffset++;
|
||||
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
||||
stream.write(offset + ctx.block(index, index), palette & 1);
|
||||
palette >>= 1;
|
||||
|
@ -118,6 +113,8 @@ private:
|
|||
offset += ctx.mosaicOffset;
|
||||
} //objectY
|
||||
}
|
||||
|
||||
image canvas;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -5,17 +5,17 @@ namespace nall {
|
|||
|
||||
#define autostream(...) (*makestream(__VA_ARGS__))
|
||||
|
||||
inline std::unique_ptr<stream> makestream(const string& path) {
|
||||
inline auto makestream(const string& path) -> std::unique_ptr<stream> {
|
||||
if(path.iendsWith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path}));
|
||||
if(path.iendsWith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path}));
|
||||
return std::unique_ptr<stream>(new mmapstream(path));
|
||||
}
|
||||
|
||||
inline std::unique_ptr<stream> makestream(uint8_t* data, unsigned size) {
|
||||
inline auto makestream(uint8* data, uint size) -> std::unique_ptr<stream> {
|
||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
||||
}
|
||||
|
||||
inline std::unique_ptr<stream> makestream(const uint8_t* data, unsigned size) {
|
||||
inline auto makestream(const uint8* data, uint size) -> std::unique_ptr<stream> {
|
||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,18 +9,6 @@ struct filestream : stream {
|
|||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
bool seekable() const { return true; }
|
||||
bool readable() const { return true; }
|
||||
bool writable() const { return pwritable; }
|
||||
bool randomaccess() const { return false; }
|
||||
|
||||
unsigned size() const { return pfile.size(); }
|
||||
unsigned offset() const { return pfile.offset(); }
|
||||
void seek(unsigned offset) const { pfile.seek(offset); }
|
||||
|
||||
uint8_t read() const { return pfile.read(); }
|
||||
void write(uint8_t data) const { pfile.write(data); }
|
||||
|
||||
filestream(const string& filename) {
|
||||
pfile.open(filename, file::mode::readwrite);
|
||||
pwritable = pfile.open();
|
||||
|
@ -32,6 +20,18 @@ struct filestream : stream {
|
|||
pwritable = mode == file::mode::write || mode == file::mode::readwrite;
|
||||
}
|
||||
|
||||
auto seekable() const -> bool { return true; }
|
||||
auto readable() const -> bool { return true; }
|
||||
auto writable() const -> bool { return pwritable; }
|
||||
auto randomaccess() const -> bool { return false; }
|
||||
|
||||
auto size() const -> uint { return pfile.size(); }
|
||||
auto offset() const -> uint { return pfile.offset(); }
|
||||
auto seek(unsigned offset) const -> void { pfile.seek(offset); }
|
||||
|
||||
auto read() const -> uint8 { return pfile.read(); }
|
||||
auto write(uint8_t data) const -> void { pfile.write(data); }
|
||||
|
||||
private:
|
||||
mutable file pfile;
|
||||
bool pwritable;
|
||||
|
|
|
@ -10,14 +10,14 @@ struct gzipstream : memorystream {
|
|||
using stream::write;
|
||||
|
||||
gzipstream(const stream& stream) {
|
||||
unsigned size = stream.size();
|
||||
uint8_t *data = new uint8_t[size];
|
||||
uint size = stream.size();
|
||||
auto data = new uint8[size];
|
||||
stream.read(data, size);
|
||||
|
||||
Decode::GZIP archive;
|
||||
bool result = archive.decompress(data, size);
|
||||
delete[] data;
|
||||
if(result == false) return;
|
||||
if(!result) return;
|
||||
|
||||
psize = archive.size;
|
||||
pdata = new uint8_t[psize];
|
||||
|
|
|
@ -9,37 +9,41 @@ struct memorystream : stream {
|
|||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
bool seekable() const { return true; }
|
||||
bool readable() const { return true; }
|
||||
bool writable() const { return pwritable; }
|
||||
bool randomaccess() const { return true; }
|
||||
memorystream() = default;
|
||||
|
||||
uint8_t* data() const { return pdata; }
|
||||
unsigned size() const { return psize; }
|
||||
unsigned offset() const { return poffset; }
|
||||
void seek(unsigned offset) const { poffset = offset; }
|
||||
|
||||
uint8_t read() const { return pdata[poffset++]; }
|
||||
void write(uint8_t data) const { pdata[poffset++] = data; }
|
||||
|
||||
uint8_t read(unsigned offset) const { return pdata[offset]; }
|
||||
void write(unsigned offset, uint8_t data) const { pdata[offset] = data; }
|
||||
|
||||
memorystream() : pdata(nullptr), psize(0), poffset(0), pwritable(true) {}
|
||||
|
||||
memorystream(uint8_t* data, unsigned size) {
|
||||
pdata = data, psize = size, poffset = 0;
|
||||
memorystream(uint8* data, uint size) {
|
||||
pdata = data;
|
||||
psize = size;
|
||||
pwritable = true;
|
||||
}
|
||||
|
||||
memorystream(const uint8_t* data, unsigned size) {
|
||||
pdata = (uint8_t*)data, psize = size, poffset = 0;
|
||||
memorystream(const uint8* data, uint size) {
|
||||
pdata = (uint8*)data;
|
||||
psize = size;
|
||||
pwritable = false;
|
||||
}
|
||||
|
||||
auto seekable() const -> bool { return true; }
|
||||
auto readable() const -> bool { return true; }
|
||||
auto writable() const -> bool { return pwritable; }
|
||||
auto randomaccess() const -> bool { return true; }
|
||||
|
||||
auto data() const -> uint8* { return pdata; }
|
||||
auto size() const -> uint { return psize; }
|
||||
auto offset() const -> uint { return poffset; }
|
||||
auto seek(uint offset) const -> void { poffset = offset; }
|
||||
|
||||
auto read() const -> uint8 { return pdata[poffset++]; }
|
||||
auto write(uint8 data) const -> void { pdata[poffset++] = data; }
|
||||
|
||||
auto read(uint offset) const -> uint8 { return pdata[offset]; }
|
||||
auto write(uint offset, uint8 data) const -> void { pdata[offset] = data; }
|
||||
|
||||
protected:
|
||||
mutable uint8_t* pdata;
|
||||
mutable unsigned psize, poffset, pwritable;
|
||||
mutable uint8* pdata = nullptr;
|
||||
mutable uint psize = 0;
|
||||
mutable uint poffset = 0;
|
||||
mutable bool pwritable = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -9,32 +9,34 @@ struct mmapstream : stream {
|
|||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
bool seekable() const { return true; }
|
||||
bool readable() const { return true; }
|
||||
bool writable() const { return pwritable; }
|
||||
bool randomaccess() const { return true; }
|
||||
|
||||
unsigned size() const { return pmmap.size(); }
|
||||
unsigned offset() const { return poffset; }
|
||||
void seek(unsigned offset) const { poffset = offset; }
|
||||
|
||||
uint8_t read() const { return pdata[poffset++]; }
|
||||
void write(uint8_t data) const { pdata[poffset++] = data; }
|
||||
|
||||
uint8_t read(unsigned offset) const { return pdata[offset]; }
|
||||
void write(unsigned offset, uint8_t data) const { pdata[offset] = data; }
|
||||
|
||||
mmapstream(const string& filename) {
|
||||
pmmap.open(filename, filemap::mode::readwrite);
|
||||
pwritable = pmmap.open();
|
||||
if(!pwritable) pmmap.open(filename, filemap::mode::read);
|
||||
pdata = pmmap.data(), poffset = 0;
|
||||
pdata = pmmap.data();
|
||||
poffset = 0;
|
||||
}
|
||||
|
||||
auto seekable() const -> bool { return true; }
|
||||
auto readable() const -> bool { return true; }
|
||||
auto writable() const -> bool { return pwritable; }
|
||||
auto randomaccess() const -> bool { return true; }
|
||||
|
||||
auto size() const -> uint { return pmmap.size(); }
|
||||
auto offset() const -> uint { return poffset; }
|
||||
auto seek(unsigned offset) const -> void { poffset = offset; }
|
||||
|
||||
auto read() const -> uint8 { return pdata[poffset++]; }
|
||||
auto write(uint8 data) const -> void { pdata[poffset++] = data; }
|
||||
|
||||
auto read(uint offset) const -> uint8 { return pdata[offset]; }
|
||||
auto write(uint offset, uint8 data) const -> void { pdata[offset] = data; }
|
||||
|
||||
private:
|
||||
mutable filemap pmmap;
|
||||
mutable uint8_t* pdata;
|
||||
mutable unsigned pwritable, poffset;
|
||||
mutable uint8* pdata = nullptr;
|
||||
mutable uint poffset = 0;
|
||||
mutable bool pwritable = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,95 +4,96 @@
|
|||
namespace nall {
|
||||
|
||||
struct stream {
|
||||
virtual bool seekable() const = 0;
|
||||
virtual bool readable() const = 0;
|
||||
virtual bool writable() const = 0;
|
||||
virtual bool randomaccess() const = 0;
|
||||
stream() = default;
|
||||
virtual ~stream() = default;
|
||||
|
||||
virtual uint8_t* data() const { return nullptr; }
|
||||
virtual unsigned size() const = 0;
|
||||
virtual unsigned offset() const = 0;
|
||||
virtual void seek(unsigned offset) const = 0;
|
||||
stream(const stream&) = delete;
|
||||
auto operator=(const stream&) -> stream& = delete;
|
||||
|
||||
virtual uint8_t read() const = 0;
|
||||
virtual void write(uint8_t data) const = 0;
|
||||
virtual auto seekable() const -> bool = 0;
|
||||
virtual auto readable() const -> bool = 0;
|
||||
virtual auto writable() const -> bool = 0;
|
||||
virtual auto randomaccess() const -> bool = 0;
|
||||
|
||||
virtual uint8_t read(unsigned) const { return 0; }
|
||||
virtual void write(unsigned, uint8_t) const {}
|
||||
virtual auto data() const -> uint8* { return nullptr; }
|
||||
virtual auto size() const -> uint = 0;
|
||||
virtual auto offset() const -> uint = 0;
|
||||
virtual auto seek(unsigned offset) const -> void = 0;
|
||||
|
||||
operator bool() const {
|
||||
virtual auto read() const -> uint8 = 0;
|
||||
virtual auto write(uint8_t data) const -> void = 0;
|
||||
|
||||
virtual auto read(uint) const -> uint8 { return 0; }
|
||||
virtual auto write(uint, uint8) const -> void {}
|
||||
|
||||
explicit operator bool() const {
|
||||
return size();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
auto empty() const -> bool {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
bool end() const {
|
||||
auto end() const -> bool {
|
||||
return offset() >= size();
|
||||
}
|
||||
|
||||
uintmax_t readl(unsigned length = 1) const {
|
||||
uintmax_t data = 0, shift = 0;
|
||||
auto readl(uint length = 1) const -> uintmax {
|
||||
uintmax data = 0, shift = 0;
|
||||
while(length--) { data |= read() << shift; shift += 8; }
|
||||
return data;
|
||||
}
|
||||
|
||||
uintmax_t readm(unsigned length = 1) const {
|
||||
uintmax_t data = 0;
|
||||
auto readm(uint length = 1) const -> uintmax {
|
||||
uintmax data = 0;
|
||||
while(length--) data = (data << 8) | read();
|
||||
return data;
|
||||
}
|
||||
|
||||
void read(uint8_t* data, unsigned length) const {
|
||||
auto read(uint8* data, uint length) const -> void {
|
||||
while(length--) *data++ = read();
|
||||
}
|
||||
|
||||
string text() const {
|
||||
auto text() const -> string {
|
||||
string buffer;
|
||||
buffer.resize(size());
|
||||
seek(0);
|
||||
read((uint8_t*)buffer.data(), size());
|
||||
read((uint8*)buffer.get(), size());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void writel(uintmax_t data, unsigned length = 1) const {
|
||||
auto writel(uintmax data, uint length = 1) const -> void {
|
||||
while(length--) {
|
||||
write(data);
|
||||
data >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void writem(uintmax_t data, unsigned length = 1) const {
|
||||
uintmax_t shift = 8 * length;
|
||||
auto writem(uintmax data, uint length = 1) const -> void {
|
||||
uintmax shift = 8 * length;
|
||||
while(length--) {
|
||||
shift -= 8;
|
||||
write(data >> shift);
|
||||
}
|
||||
}
|
||||
|
||||
void write(const uint8_t* data, unsigned length) const {
|
||||
auto write(const uint8* data, uint length) const -> void {
|
||||
while(length--) write(*data++);
|
||||
}
|
||||
|
||||
struct byte {
|
||||
operator uint8_t() const { return s.read(offset); }
|
||||
byte& operator=(uint8_t data) { s.write(offset, data); return *this; }
|
||||
byte(const stream& s, unsigned offset) : s(s), offset(offset) {}
|
||||
byte(const stream& s, uint offset) : s(s), offset(offset) {}
|
||||
operator uint8() const { return s.read(offset); }
|
||||
auto operator=(uint8_t data) -> byte& { s.write(offset, data); return *this; }
|
||||
|
||||
private:
|
||||
const stream& s;
|
||||
const unsigned offset;
|
||||
const uint offset;
|
||||
};
|
||||
|
||||
byte operator[](unsigned offset) const {
|
||||
auto operator[](uint offset) const -> byte {
|
||||
return byte(*this, offset);
|
||||
}
|
||||
|
||||
stream() {}
|
||||
virtual ~stream() {}
|
||||
stream(const stream&) = delete;
|
||||
stream& operator=(const stream&) = delete;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -10,28 +10,29 @@ struct vectorstream : stream {
|
|||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
bool seekable() const { return true; }
|
||||
bool readable() const { return true; }
|
||||
bool writable() const { return pwritable; }
|
||||
bool randomaccess() const { return true; }
|
||||
vectorstream(vector<uint8>& memory) : memory(memory), pwritable(true) {}
|
||||
vectorstream(const vector<uint8>& memory) : memory((vector<uint8>&)memory), pwritable(false) {}
|
||||
|
||||
uint8_t* data() const { return memory.data(); }
|
||||
unsigned size() const { return memory.size(); }
|
||||
unsigned offset() const { return poffset; }
|
||||
void seek(unsigned offset) const { poffset = offset; }
|
||||
auto seekable() const -> bool { return true; }
|
||||
auto readable() const -> bool { return true; }
|
||||
auto writable() const -> bool { return pwritable; }
|
||||
auto randomaccess() const -> bool { return true; }
|
||||
|
||||
uint8_t read() const { return memory[poffset++]; }
|
||||
void write(uint8_t data) const { memory[poffset++] = data; }
|
||||
auto data() const -> uint8* { return memory.data(); }
|
||||
auto size() const -> uint { return memory.size(); }
|
||||
auto offset() const -> uint { return poffset; }
|
||||
auto seek(unsigned offset) const -> void { poffset = offset; }
|
||||
|
||||
uint8_t read(unsigned offset) const { return memory[offset]; }
|
||||
void write(unsigned offset, uint8_t data) const { memory[offset] = data; }
|
||||
auto read() const -> uint8 { return memory[poffset++]; }
|
||||
auto write(uint8 data) const -> void { memory[poffset++] = data; }
|
||||
|
||||
vectorstream(vector<uint8_t>& memory) : memory(memory), poffset(0), pwritable(true) {}
|
||||
vectorstream(const vector<uint8_t>& memory) : memory((vector<uint8_t>&)memory), poffset(0), pwritable(false) {}
|
||||
auto read(uint offset) const -> uint8 { return memory[offset]; }
|
||||
auto write(uint offset, uint8 data) const -> void { memory[offset] = data; }
|
||||
|
||||
protected:
|
||||
vector<uint8_t>& memory;
|
||||
mutable unsigned poffset, pwritable;
|
||||
vector<uint8>& memory;
|
||||
mutable uint poffset = 0;
|
||||
mutable bool pwritable = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ struct zipstream : memorystream {
|
|||
using stream::write;
|
||||
|
||||
zipstream(const stream& stream, const string& filter = "*") {
|
||||
unsigned size = stream.size();
|
||||
uint8_t* data = new uint8_t[size];
|
||||
uint size = stream.size();
|
||||
auto data = new uint8[size];
|
||||
stream.read(data, size);
|
||||
|
||||
Decode::ZIP archive;
|
||||
|
|
|
@ -13,18 +13,18 @@ namespace nall {
|
|||
#define RelNear 1
|
||||
|
||||
struct detour {
|
||||
static bool insert(const string& moduleName, const string& functionName, void*& source, void* target);
|
||||
static bool remove(const string& moduleName, const string& functionName, void*& source);
|
||||
static auto insert(const string& moduleName, const string& functionName, void*& source, void* target) -> bool;
|
||||
static auto remove(const string& moduleName, const string& functionName, void*& source) -> bool;
|
||||
|
||||
protected:
|
||||
static unsigned length(const uint8_t* function);
|
||||
static unsigned mirror(uint8_t* target, const uint8_t* source);
|
||||
static auto length(const uint8* function) -> uint;
|
||||
static auto mirror(uint8* target, const uint8* source) -> uint;
|
||||
|
||||
struct opcode {
|
||||
uint16_t prefix;
|
||||
unsigned length;
|
||||
unsigned mode;
|
||||
uint16_t modify;
|
||||
uint16 prefix;
|
||||
uint length;
|
||||
uint mode;
|
||||
uint16 modify;
|
||||
};
|
||||
static opcode opcodes[];
|
||||
};
|
||||
|
@ -33,61 +33,61 @@ protected:
|
|||
//* fs:, gs: should force another opcode copy
|
||||
//* conditional branches within +5-byte range should fail
|
||||
detour::opcode detour::opcodes[] = {
|
||||
{ 0x50, 1 }, //push eax
|
||||
{ 0x51, 1 }, //push ecx
|
||||
{ 0x52, 1 }, //push edx
|
||||
{ 0x53, 1 }, //push ebx
|
||||
{ 0x54, 1 }, //push esp
|
||||
{ 0x55, 1 }, //push ebp
|
||||
{ 0x56, 1 }, //push esi
|
||||
{ 0x57, 1 }, //push edi
|
||||
{ 0x58, 1 }, //pop eax
|
||||
{ 0x59, 1 }, //pop ecx
|
||||
{ 0x5a, 1 }, //pop edx
|
||||
{ 0x5b, 1 }, //pop ebx
|
||||
{ 0x5c, 1 }, //pop esp
|
||||
{ 0x5d, 1 }, //pop ebp
|
||||
{ 0x5e, 1 }, //pop esi
|
||||
{ 0x5f, 1 }, //pop edi
|
||||
{ 0x64, 1 }, //fs:
|
||||
{ 0x65, 1 }, //gs:
|
||||
{ 0x68, 5 }, //push dword
|
||||
{ 0x6a, 2 }, //push byte
|
||||
{ 0x74, 2, RelNear, 0x0f84 }, //je near -> je far
|
||||
{ 0x75, 2, RelNear, 0x0f85 }, //jne near -> jne far
|
||||
{ 0x89, 2 }, //mov reg,reg
|
||||
{ 0x8b, 2 }, //mov reg,reg
|
||||
{ 0x90, 1 }, //nop
|
||||
{ 0xa1, 5 }, //mov eax,[dword]
|
||||
{ 0xeb, 2, RelNear, 0xe9 }, //jmp near -> jmp far
|
||||
{0x50, 1}, //push eax
|
||||
{0x51, 1}, //push ecx
|
||||
{0x52, 1}, //push edx
|
||||
{0x53, 1}, //push ebx
|
||||
{0x54, 1}, //push esp
|
||||
{0x55, 1}, //push ebp
|
||||
{0x56, 1}, //push esi
|
||||
{0x57, 1}, //push edi
|
||||
{0x58, 1}, //pop eax
|
||||
{0x59, 1}, //pop ecx
|
||||
{0x5a, 1}, //pop edx
|
||||
{0x5b, 1}, //pop ebx
|
||||
{0x5c, 1}, //pop esp
|
||||
{0x5d, 1}, //pop ebp
|
||||
{0x5e, 1}, //pop esi
|
||||
{0x5f, 1}, //pop edi
|
||||
{0x64, 1}, //fs:
|
||||
{0x65, 1}, //gs:
|
||||
{0x68, 5}, //push dword
|
||||
{0x6a, 2}, //push byte
|
||||
{0x74, 2, RelNear, 0x0f84}, //je near -> je far
|
||||
{0x75, 2, RelNear, 0x0f85}, //jne near -> jne far
|
||||
{0x89, 2}, //mov reg,reg
|
||||
{0x8b, 2}, //mov reg,reg
|
||||
{0x90, 1}, //nop
|
||||
{0xa1, 5}, //mov eax,[dword]
|
||||
{0xeb, 2, RelNear, 0xe9}, //jmp near -> jmp far
|
||||
};
|
||||
|
||||
bool detour::insert(const string& moduleName, const string& functionName, void*& source, void* target) {
|
||||
auto detour::insert(const string& moduleName, const string& functionName, void*& source, void* target) -> bool {
|
||||
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
||||
if(!module) return false;
|
||||
|
||||
uint8_t* sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
||||
uint8* sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
||||
if(!sourceData) return false;
|
||||
|
||||
unsigned sourceLength = detour::length(sourceData);
|
||||
uint sourceLength = detour::length(sourceData);
|
||||
if(sourceLength < 5) {
|
||||
//unable to clone enough bytes to insert hook
|
||||
#if 1
|
||||
string output = { "detour::insert(", moduleName, "::", functionName, ") failed: " };
|
||||
for(unsigned n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " ");
|
||||
string output = {"detour::insert(", moduleName, "::", functionName, ") failed: "};
|
||||
for(uint n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " ");
|
||||
output.rtrim(" ", 1L);
|
||||
MessageBoxA(0, output, "nall::detour", MB_OK);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* mirrorData = new uint8_t[512]();
|
||||
auto mirrorData = new uint8[512]();
|
||||
detour::mirror(mirrorData, sourceData);
|
||||
|
||||
DWORD privileges;
|
||||
VirtualProtect((void*)mirrorData, 512, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
uintmax_t address = (uintmax_t)target - ((uintmax_t)sourceData + 5);
|
||||
uintmax address = (uintmax)target - ((uintmax)sourceData + 5);
|
||||
sourceData[0] = 0xe9; //jmp target
|
||||
sourceData[1] = address >> 0;
|
||||
sourceData[2] = address >> 8;
|
||||
|
@ -99,22 +99,22 @@ bool detour::insert(const string& moduleName, const string& functionName, void*&
|
|||
return true;
|
||||
}
|
||||
|
||||
bool detour::remove(const string& moduleName, const string& functionName, void*& source) {
|
||||
auto detour::remove(const string& moduleName, const string& functionName, void*& source) -> bool {
|
||||
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
||||
if(!module) return false;
|
||||
|
||||
uint8_t* sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
||||
auto sourceData = (uint8*)GetProcAddress(module, functionName);
|
||||
if(!sourceData) return false;
|
||||
|
||||
uint8_t* mirrorData = (uint8_t*)source;
|
||||
auto mirrorData = (uint8*)source;
|
||||
if(mirrorData == sourceData) return false; //hook was never installed
|
||||
|
||||
unsigned length = detour::length(256 + mirrorData);
|
||||
uint length = detour::length(256 + mirrorData);
|
||||
if(length < 5) return false;
|
||||
|
||||
DWORD privileges;
|
||||
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
||||
for(unsigned n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n];
|
||||
for(uint n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n];
|
||||
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
|
||||
|
||||
source = (void*)sourceData;
|
||||
|
@ -122,8 +122,8 @@ bool detour::remove(const string& moduleName, const string& functionName, void*&
|
|||
return true;
|
||||
}
|
||||
|
||||
unsigned detour::length(const uint8_t* function) {
|
||||
unsigned length = 0;
|
||||
auto detour::length(const uint8* function) -> uint {
|
||||
uint length = 0;
|
||||
while(length < 5) {
|
||||
detour::opcode *opcode = 0;
|
||||
foreach(op, detour::opcodes) {
|
||||
|
@ -138,13 +138,13 @@ unsigned detour::length(const uint8_t* function) {
|
|||
return length;
|
||||
}
|
||||
|
||||
unsigned detour::mirror(uint8_t* target, const uint8_t* source) {
|
||||
const uint8_t *entryPoint = source;
|
||||
for(unsigned n = 0; n < 256; n++) target[256 + n] = source[n];
|
||||
auto detour::mirror(uint8* target, const uint8* source) -> uint {
|
||||
const uint8* entryPoint = source;
|
||||
for(uint n = 0; n < 256; n++) target[256 + n] = source[n];
|
||||
|
||||
unsigned size = detour::length(source);
|
||||
uint size = detour::length(source);
|
||||
while(size) {
|
||||
detour::opcode *opcode = 0;
|
||||
detour::opcode* opcode = nullptr;
|
||||
foreach(op, detour::opcodes) {
|
||||
if(*source == op.prefix) {
|
||||
opcode = &op;
|
||||
|
@ -154,15 +154,15 @@ unsigned detour::mirror(uint8_t* target, const uint8_t* source) {
|
|||
|
||||
switch(opcode->mode) {
|
||||
case Copy:
|
||||
for(unsigned n = 0; n < opcode->length; n++) *target++ = *source++;
|
||||
for(uint n = 0; n < opcode->length; n++) *target++ = *source++;
|
||||
break;
|
||||
case RelNear: {
|
||||
source++;
|
||||
uintmax_t sourceAddress = (uintmax_t)source + 1 + (int8_t)*source;
|
||||
uintmax sourceAddress = (uintmax)source + 1 + (int8)*source;
|
||||
*target++ = opcode->modify;
|
||||
if(opcode->modify >> 8) *target++ = opcode->modify >> 8;
|
||||
uintmax_t targetAddress = (uintmax_t)target + 4;
|
||||
uintmax_t address = sourceAddress - targetAddress;
|
||||
uintmax targetAddress = (uintmax)target + 4;
|
||||
uintmax address = sourceAddress - targetAddress;
|
||||
*target++ = address >> 0;
|
||||
*target++ = address >> 8;
|
||||
*target++ = address >> 16;
|
||||
|
@ -174,7 +174,7 @@ unsigned detour::mirror(uint8_t* target, const uint8_t* source) {
|
|||
size -= opcode->length;
|
||||
}
|
||||
|
||||
uintmax_t address = (entryPoint + detour::length(entryPoint)) - (target + 5);
|
||||
uintmax address = (entryPoint + detour::length(entryPoint)) - (target + 5);
|
||||
*target++ = 0xe9; //jmp entryPoint
|
||||
*target++ = address >> 0;
|
||||
*target++ = address >> 8;
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
namespace nall {
|
||||
|
||||
//generate unique GUID
|
||||
inline string guid() {
|
||||
inline auto guid() -> string {
|
||||
LinearFeedbackShiftRegisterGenerator lfsr;
|
||||
lfsr.seed(time(nullptr));
|
||||
for(unsigned n = 0; n < 256; n++) lfsr();
|
||||
for(uint n = 0; n < 256; n++) lfsr();
|
||||
|
||||
string output;
|
||||
for(unsigned n = 0; n < 4; n++) output.append(hex(lfsr(), 2L));
|
||||
for(uint n = 0; n < 4; n++) output.append(hex(lfsr(), 2L));
|
||||
output.append("-");
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
output.append("-");
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
output.append("-");
|
||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||
output.append("-");
|
||||
for(unsigned n = 0; n < 6; n++) output.append(hex(lfsr(), 2L));
|
||||
for(uint n = 0; n < 6; n++) output.append(hex(lfsr(), 2L));
|
||||
return {"{", output, "}"};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace nall {
|
|||
|
||||
//launch a new process and inject specified DLL into it
|
||||
|
||||
bool launch(const char* applicationName, const char* libraryName, uint32_t entryPoint) {
|
||||
auto launch(const char* applicationName, const char* libraryName, uint32 entryPoint) -> bool {
|
||||
//if a launcher does not send at least one message, a wait cursor will appear
|
||||
PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
|
||||
MSG msg;
|
||||
|
@ -22,19 +22,19 @@ bool launch(const char* applicationName, const char* libraryName, uint32_t entry
|
|||
);
|
||||
if(result == false) return false;
|
||||
|
||||
uint8_t entryData[1024], entryHook[1024] = {
|
||||
uint8 entryData[1024], entryHook[1024] = {
|
||||
0x68, 0x00, 0x00, 0x00, 0x00, //push libraryName
|
||||
0xb8, 0x00, 0x00, 0x00, 0x00, //mov eax,LoadLibraryW
|
||||
0xff, 0xd0, //call eax
|
||||
0xcd, 0x03, //int 3
|
||||
};
|
||||
|
||||
entryHook[1] = (uint8_t)((entryPoint + 14) >> 0);
|
||||
entryHook[2] = (uint8_t)((entryPoint + 14) >> 8);
|
||||
entryHook[3] = (uint8_t)((entryPoint + 14) >> 16);
|
||||
entryHook[4] = (uint8_t)((entryPoint + 14) >> 24);
|
||||
entryHook[1] = (uint8)((entryPoint + 14) >> 0);
|
||||
entryHook[2] = (uint8)((entryPoint + 14) >> 8);
|
||||
entryHook[3] = (uint8)((entryPoint + 14) >> 16);
|
||||
entryHook[4] = (uint8)((entryPoint + 14) >> 24);
|
||||
|
||||
uint32_t pLoadLibraryW = (uint32_t)GetProcAddress(GetModuleHandleW(L"kernel32"), "LoadLibraryW");
|
||||
auto pLoadLibraryW = (uint32)GetProcAddress(GetModuleHandleW(L"kernel32"), "LoadLibraryW");
|
||||
entryHook[6] = pLoadLibraryW >> 0;
|
||||
entryHook[7] = pLoadLibraryW >> 8;
|
||||
entryHook[8] = pLoadLibraryW >> 16;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
namespace nall {
|
||||
|
||||
struct registry {
|
||||
static bool exists(const string& name) {
|
||||
static auto exists(const string& name) -> bool {
|
||||
lstring part = name.split("/");
|
||||
HKEY handle, rootKey = root(part.take(0));
|
||||
string node = part.take();
|
||||
|
@ -39,7 +39,7 @@ struct registry {
|
|||
return false;
|
||||
}
|
||||
|
||||
static string read(const string& name) {
|
||||
static auto read(const string& name) -> string {
|
||||
lstring part = name.split("/");
|
||||
HKEY handle, rootKey = root(part.take(0));
|
||||
string node = part.take();
|
||||
|
@ -54,12 +54,12 @@ struct registry {
|
|||
return "";
|
||||
}
|
||||
|
||||
static void write(const string& name, const string& data = "") {
|
||||
static auto write(const string& name, const string& data = "") -> void {
|
||||
lstring part = name.split("/");
|
||||
HKEY handle, rootKey = root(part.take(0));
|
||||
string node = part.take(), path;
|
||||
DWORD disposition;
|
||||
for(unsigned n = 0; n < part.size(); n++) {
|
||||
for(uint n = 0; n < part.size(); n++) {
|
||||
path.append(part[n]);
|
||||
if(RegCreateKeyExW(rootKey, utf16_t(path), 0, nullptr, 0, NWR_FLAGS | KEY_ALL_ACCESS, nullptr, &handle, &disposition) == ERROR_SUCCESS) {
|
||||
if(n == part.size() - 1) {
|
||||
|
@ -71,7 +71,7 @@ struct registry {
|
|||
}
|
||||
}
|
||||
|
||||
static bool remove(const string& name) {
|
||||
static auto remove(const string& name) -> bool {
|
||||
lstring part = name.split("/");
|
||||
HKEY rootKey = root(part.take(0));
|
||||
string node = part.take();
|
||||
|
@ -80,7 +80,7 @@ struct registry {
|
|||
return SHDeleteValueW(rootKey, utf16_t(path), utf16_t(node)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static lstring contents(const string& name) {
|
||||
static auto contents(const string& name) -> lstring {
|
||||
lstring part = name.split("/"), result;
|
||||
HKEY handle, rootKey = root(part.take(0));
|
||||
part.remove();
|
||||
|
@ -88,13 +88,13 @@ struct registry {
|
|||
if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) {
|
||||
DWORD folders, nodes;
|
||||
RegQueryInfoKey(handle, nullptr, nullptr, nullptr, &folders, nullptr, nullptr, &nodes, nullptr, nullptr, nullptr, nullptr);
|
||||
for(unsigned n = 0; n < folders; n++) {
|
||||
for(uint n = 0; n < folders; n++) {
|
||||
wchar_t name[NWR_SIZE] = L"";
|
||||
DWORD size = NWR_SIZE * sizeof(wchar_t);
|
||||
RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr);
|
||||
result.append(string{(const char*)utf8_t(name), "/"});
|
||||
}
|
||||
for(unsigned n = 0; n < nodes; n++) {
|
||||
for(uint n = 0; n < nodes; n++) {
|
||||
wchar_t name[NWR_SIZE] = L"";
|
||||
DWORD size = NWR_SIZE * sizeof(wchar_t);
|
||||
RegEnumValueW(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr);
|
||||
|
@ -106,7 +106,7 @@ struct registry {
|
|||
}
|
||||
|
||||
private:
|
||||
static HKEY root(const string& name) {
|
||||
static auto root(const string& name) -> HKEY {
|
||||
if(name == "HKCR") return HKEY_CLASSES_ROOT;
|
||||
if(name == "HKCC") return HKEY_CURRENT_CONFIG;
|
||||
if(name == "HKCU") return HKEY_CURRENT_USER;
|
||||
|
|
|
@ -14,14 +14,14 @@ struct shared_memory {
|
|||
|
||||
explicit operator bool() const { return false; }
|
||||
auto empty() const -> bool { return true; }
|
||||
auto size() const -> unsigned { return 0; }
|
||||
auto size() const -> uint { return 0; }
|
||||
auto acquired() const -> bool { return false; }
|
||||
auto acquire() -> uint8_t* { return nullptr; }
|
||||
auto acquire() -> uint8* { return nullptr; }
|
||||
auto release() -> void {}
|
||||
auto reset() -> void {}
|
||||
auto create(const string& name, unsigned size) -> bool { return false; }
|
||||
auto create(const string& name, uint size) -> bool { return false; }
|
||||
auto remove() -> void {}
|
||||
auto open(const string& name, unsigned size) -> bool { return false; }
|
||||
auto open(const string& name, uint size) -> bool { return false; }
|
||||
auto close() -> void {}
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define NALL_UTF8_HPP
|
||||
|
||||
//UTF-8 <> UTF-16 conversion
|
||||
//used only for Win32; Linux, etc use UTF-8 internally
|
||||
//used only for Win32; every other OS uses UTF-8 internally
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
|
@ -21,17 +21,9 @@
|
|||
namespace nall {
|
||||
//UTF-8 to UTF-16
|
||||
struct utf16_t {
|
||||
operator wchar_t*() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
operator const wchar_t*() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
utf16_t(const char* s = "") {
|
||||
if(!s) s = "";
|
||||
unsigned length = MultiByteToWideChar(CP_UTF8, 0, s, -1, nullptr, 0);
|
||||
uint length = MultiByteToWideChar(CP_UTF8, 0, s, -1, nullptr, 0);
|
||||
buffer = new wchar_t[length + 1]();
|
||||
MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length);
|
||||
}
|
||||
|
@ -40,23 +32,23 @@ namespace nall {
|
|||
delete[] buffer;
|
||||
}
|
||||
|
||||
operator wchar_t*() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
operator const wchar_t*() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
wchar_t* buffer;
|
||||
wchar_t* buffer = nullptr;
|
||||
};
|
||||
|
||||
//UTF-16 to UTF-8
|
||||
struct utf8_t {
|
||||
operator char*() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
operator const char*() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
utf8_t(const wchar_t* s = L"") {
|
||||
if(!s) s = L"";
|
||||
unsigned length = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, nullptr, nullptr);
|
||||
uint length = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, nullptr, nullptr);
|
||||
buffer = new char[length + 1]();
|
||||
WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, nullptr, nullptr);
|
||||
}
|
||||
|
@ -68,14 +60,22 @@ namespace nall {
|
|||
utf8_t(const utf8_t&) = delete;
|
||||
utf8_t& operator=(const utf8_t&) = delete;
|
||||
|
||||
operator char*() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
operator const char*() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
char* buffer;
|
||||
char* buffer = nullptr;
|
||||
};
|
||||
|
||||
inline void utf8_args(int& argc, char**& argv) {
|
||||
inline auto utf8_args(int& argc, char**& argv) -> void {
|
||||
wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
argv = new char*[argc];
|
||||
for(unsigned i = 0; i < argc; i++) {
|
||||
for(uint i = 0; i < argc; i++) {
|
||||
argv[i] = new char[PATH_MAX];
|
||||
strcpy(argv[i], nall::utf8_t(wargv[i]));
|
||||
}
|
||||
|
|
|
@ -29,15 +29,15 @@ struct Cartridge : property<Cartridge> {
|
|||
readonly<bool> hasSufamiTurboSlots;
|
||||
|
||||
struct Mapping {
|
||||
function<uint8 (unsigned)> reader;
|
||||
function<void (unsigned, uint8)> writer;
|
||||
function<auto (uint, uint8) -> uint8> reader;
|
||||
function<auto (uint, uint8) -> void> writer;
|
||||
string addr;
|
||||
unsigned size = 0;
|
||||
unsigned base = 0;
|
||||
unsigned mask = 0;
|
||||
uint size = 0;
|
||||
uint base = 0;
|
||||
uint mask = 0;
|
||||
|
||||
Mapping() = default;
|
||||
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
|
||||
Mapping(const function<uint8 (uint, uint8)>&, const function<void (uint, uint8)>&);
|
||||
Mapping(SuperFamicom::Memory&);
|
||||
};
|
||||
vector<Mapping> mapping;
|
||||
|
|
|
@ -3,7 +3,7 @@ Cartridge::Mapping::Mapping(SuperFamicom::Memory& memory) {
|
|||
this->writer = {&SuperFamicom::Memory::write, &memory};
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)>& reader, const function<void (unsigned, uint8)>& writer) {
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (uint, uint8)>& reader, const function<void (uint, uint8)>& writer) {
|
||||
this->reader = reader;
|
||||
this->writer = writer;
|
||||
}
|
||||
|
@ -217,13 +217,13 @@ auto Cartridge::parseMarkupEvent(Markup::Node root) -> void {
|
|||
}
|
||||
|
||||
if(node["id"].text() == "dr") {
|
||||
Mapping m([](unsigned) -> uint8 { return cpu.regs.mdr; }, {&Event::dr, &event});
|
||||
Mapping m([](uint, uint8 data) -> uint8 { return data; }, {&Event::dr, &event});
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].text() == "sr") {
|
||||
Mapping m({&Event::sr, &event}, [](unsigned, uint8) {});
|
||||
Mapping m({&Event::sr, &event}, [](uint, uint8) {});
|
||||
parseMarkupMap(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, unsigned roms) -> void {
|
||||
auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, uint roms) -> void {
|
||||
hasHitachiDSP = true;
|
||||
|
||||
auto rom = root.find("rom");
|
||||
|
|
|
@ -52,14 +52,14 @@ auto ArmDSP::enter() -> void {
|
|||
auto ArmDSP::step(uint clocks) -> void {
|
||||
if(bridge.timer && --bridge.timer == 0);
|
||||
Coprocessor::step(clocks);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
//MMIO: $00-3f|80-bf:3800-38ff
|
||||
//3800-3807 mirrored throughout
|
||||
//a0 ignored
|
||||
|
||||
auto ArmDSP::mmio_read(uint addr) -> uint8 {
|
||||
auto ArmDSP::mmio_read(uint addr, uint8) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
|
||||
uint8 data = 0x00;
|
||||
|
|
|
@ -14,7 +14,7 @@ struct ArmDSP : Processor::ARM, Coprocessor {
|
|||
auto bus_read(uint mode, uint32 addr) -> uint32 override;
|
||||
auto bus_write(uint mode, uint32 addr, uint32 word) -> void override;
|
||||
|
||||
auto mmio_read(uint addr) -> uint8;
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto init() -> void;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
struct Coprocessor : Thread {
|
||||
alwaysinline auto step(uint clocks) -> void;
|
||||
alwaysinline auto synchronize_cpu() -> void;
|
||||
alwaysinline auto synchronizeCPU() -> void;
|
||||
};
|
||||
|
||||
#include <sfc/coprocessor/icd2/icd2.hpp>
|
||||
|
@ -28,6 +28,6 @@ auto Coprocessor::step(uint clocks) -> void {
|
|||
clock += clocks * (uint64)cpu.frequency;
|
||||
}
|
||||
|
||||
auto Coprocessor::synchronize_cpu() -> void {
|
||||
auto Coprocessor::synchronizeCPU() -> void {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ auto EpsonRTC::enter() -> void {
|
|||
}
|
||||
|
||||
step(1);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ auto EpsonRTC::sync() -> void {
|
|||
resync = true; //alert program that time has changed
|
||||
}
|
||||
|
||||
auto EpsonRTC::read(uint addr) -> uint8 {
|
||||
auto EpsonRTC::read(uint addr, uint8 data) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
addr &= 3;
|
||||
|
||||
|
@ -162,6 +162,8 @@ auto EpsonRTC::read(uint addr) -> uint8 {
|
|||
if(addr == 2) {
|
||||
return ready << 7;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto EpsonRTC::write(uint addr, uint8 data) -> void {
|
||||
|
|
|
@ -11,7 +11,7 @@ struct EpsonRTC : Coprocessor {
|
|||
auto reset() -> void;
|
||||
auto sync() -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
|
|
@ -28,7 +28,7 @@ auto Event::enter() -> void {
|
|||
}
|
||||
|
||||
step(1);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ auto Event::reset() -> void {
|
|||
scoreSecondsRemaining = 0;
|
||||
}
|
||||
|
||||
auto Event::sr(uint) -> uint8 {
|
||||
auto Event::sr(uint, uint8) -> uint8 {
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ auto Event::dr(uint, uint8 data) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto Event::rom_read(uint addr) -> uint8 {
|
||||
auto Event::rom_read(uint addr, uint8 data) -> uint8 {
|
||||
if(board == Board::CampusChallenge92) {
|
||||
uint id = 0;
|
||||
if(select == 0x09) id = 1;
|
||||
|
@ -82,7 +82,7 @@ auto Event::rom_read(uint addr) -> uint8 {
|
|||
|
||||
if(addr & 0x008000) {
|
||||
addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
||||
return rom[id].read(bus.mirror(addr, rom[id].size()));
|
||||
return rom[id].read(bus.mirror(addr, rom[id].size()), data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,21 +95,21 @@ auto Event::rom_read(uint addr) -> uint8 {
|
|||
|
||||
if(addr & 0x400000) {
|
||||
addr &= 0x3fffff;
|
||||
return rom[id].read(bus.mirror(addr, rom[id].size()));
|
||||
return rom[id].read(bus.mirror(addr, rom[id].size()), data);
|
||||
}
|
||||
|
||||
if(addr & 0x008000) {
|
||||
addr &= 0x1fffff;
|
||||
if(id != 2) addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
|
||||
return rom[id].read(bus.mirror(addr, rom[id].size()));
|
||||
return rom[id].read(bus.mirror(addr, rom[id].size()), data);
|
||||
}
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto Event::ram_read(uint addr) -> uint8 {
|
||||
return ram.read(bus.mirror(addr, ram.size()));
|
||||
auto Event::ram_read(uint addr, uint8 data) -> uint8 {
|
||||
return ram.read(bus.mirror(addr, ram.size()), data);
|
||||
}
|
||||
|
||||
auto Event::ram_write(uint addr, uint8 data) -> void {
|
||||
|
|
|
@ -13,10 +13,10 @@ struct Event : Coprocessor {
|
|||
|
||||
auto submitScore() -> void;
|
||||
|
||||
auto sr(uint) -> uint8;
|
||||
auto sr(uint, uint8) -> uint8;
|
||||
auto dr(uint, uint8 data) -> void;
|
||||
auto rom_read(uint addr) -> uint8;
|
||||
auto ram_read(uint addr) -> uint8;
|
||||
auto rom_read(uint addr, uint8) -> uint8;
|
||||
auto ram_read(uint addr, uint8) -> uint8;
|
||||
auto ram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
|
|
@ -16,7 +16,8 @@ auto HitachiDSP::enter() -> void {
|
|||
|
||||
if(mmio.dma) {
|
||||
for(auto n : range(mmio.dma_length)) {
|
||||
bus.write(mmio.dma_target + n, bus.read(mmio.dma_source + n));
|
||||
//todo: access internally, not from Bus
|
||||
bus.write(mmio.dma_target + n, bus.read(mmio.dma_source + n, 0));
|
||||
step(2);
|
||||
}
|
||||
mmio.dma = false;
|
||||
|
@ -25,7 +26,7 @@ auto HitachiDSP::enter() -> void {
|
|||
exec(mmio.program_offset);
|
||||
step(1);
|
||||
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,15 +18,15 @@ struct HitachiDSP : Processor::HG51B, Coprocessor {
|
|||
auto bus_write(uint24 addr, uint8 data) -> void;
|
||||
|
||||
//CPU ROM read/write
|
||||
auto rom_read(uint addr) -> uint8;
|
||||
auto rom_read(uint addr, uint8 data) -> uint8;
|
||||
auto rom_write(uint addr, uint8 data) -> void;
|
||||
|
||||
//CPU RAM read/write
|
||||
auto ram_read(uint addr) -> uint8;
|
||||
auto ram_read(uint addr, uint8 data) -> uint8;
|
||||
auto ram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
//CPU MMIO read/write
|
||||
auto dsp_read(uint addr) -> uint8;
|
||||
auto dsp_read(uint addr, uint8 data) -> uint8;
|
||||
auto dsp_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto firmware() const -> vector<uint8>;
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
auto HitachiDSP::bus_read(uint24 addr) -> uint8 {
|
||||
if((addr & 0x408000) == 0x008000) return bus.read(addr); //$00-3f,80-bf:6000-7fff
|
||||
if((addr & 0xf88000) == 0x700000) return bus.read(addr); //$70-77:0000-7fff
|
||||
//todo: read internally, not from Bus
|
||||
if((addr & 0x408000) == 0x008000) return bus.read(addr, 0); //$00-3f,80-bf:6000-7fff
|
||||
if((addr & 0xf88000) == 0x700000) return bus.read(addr, 0); //$70-77:0000-7fff
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto HitachiDSP::bus_write(uint24 addr, uint8 data) -> void {
|
||||
//todo: write internally, not to Bus
|
||||
if((addr & 0x40e000) == 0x006000) return bus.write(addr, data); //$00-3f,80-bf:6000-7fff
|
||||
if((addr & 0xf88000) == 0x700000) return bus.write(addr, data); //$70-77:0000-7fff
|
||||
}
|
||||
|
||||
auto HitachiDSP::rom_read(uint addr) -> uint8 {
|
||||
auto HitachiDSP::rom_read(uint addr, uint8 data) -> uint8 {
|
||||
if(co_active() == hitachidsp.thread || regs.halt) {
|
||||
addr = bus.mirror(addr, rom.size());
|
||||
//if(Roms == 2 && mmio.r1f52 == 1 && addr >= (bit::round(rom.size()) >> 1)) return 0x00;
|
||||
return rom.read(addr);
|
||||
return rom.read(addr, data);
|
||||
}
|
||||
if((addr & 0x40ffe0) == 0x00ffe0) return mmio.vector[addr & 0x1f];
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto HitachiDSP::rom_write(uint addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
auto HitachiDSP::ram_read(uint addr) -> uint8 {
|
||||
auto HitachiDSP::ram_read(uint addr, uint8 data) -> uint8 {
|
||||
if(ram.size() == 0) return 0x00; //not open bus
|
||||
return ram.read(bus.mirror(addr, ram.size()));
|
||||
return ram.read(bus.mirror(addr, ram.size()), data);
|
||||
}
|
||||
|
||||
auto HitachiDSP::ram_write(uint addr, uint8 data) -> void {
|
||||
|
@ -32,7 +34,7 @@ auto HitachiDSP::ram_write(uint addr, uint8 data) -> void {
|
|||
return ram.write(bus.mirror(addr, ram.size()), data);
|
||||
}
|
||||
|
||||
auto HitachiDSP::dsp_read(uint addr) -> uint8 {
|
||||
auto HitachiDSP::dsp_read(uint addr, uint8) -> uint8 {
|
||||
addr &= 0x1fff;
|
||||
|
||||
//Data RAM
|
||||
|
|
|
@ -24,7 +24,7 @@ auto ICD2::enter() -> void {
|
|||
audio.coprocessor_sample(0x0000, 0x0000);
|
||||
step(1);
|
||||
}
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Coprocessor {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
auto ICD2::read(uint addr) -> uint8 {
|
||||
addr &= 0xffff;
|
||||
auto ICD2::read(uint addr, uint8 data) -> uint8 {
|
||||
addr &= 0x40ffff;
|
||||
|
||||
//LY counter
|
||||
if(addr == 0x6000) {
|
||||
|
@ -9,7 +9,7 @@ auto ICD2::read(uint addr) -> uint8 {
|
|||
|
||||
//command ready port
|
||||
if(addr == 0x6002) {
|
||||
bool data = packetsize > 0;
|
||||
data = packetsize > 0;
|
||||
if(data) {
|
||||
for(auto n : range(16)) r7000[n] = packet[0][n];
|
||||
packetsize--;
|
||||
|
@ -24,13 +24,13 @@ auto ICD2::read(uint addr) -> uint8 {
|
|||
}
|
||||
|
||||
//command port
|
||||
if((addr & 0xfff0) == 0x7000) {
|
||||
if((addr & 0x40fff0) == 0x7000) {
|
||||
return r7000[addr & 15];
|
||||
}
|
||||
|
||||
//VRAM port
|
||||
if(addr == 0x7800) {
|
||||
uint8 data = output[read_bank * 512 + read_addr];
|
||||
data = output[read_bank * 512 + read_addr];
|
||||
read_addr = (read_addr + 1) & 511;
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -28,13 +28,13 @@ auto MCC::reset() -> void {
|
|||
}
|
||||
|
||||
auto MCC::memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8 {
|
||||
if(write == 0) return memory_read(memory, addr);
|
||||
if(write == 0) return memory_read(memory, addr, data);
|
||||
memory_write(memory, addr, data);
|
||||
}
|
||||
|
||||
auto MCC::memory_read(Memory& memory, uint addr) -> uint8 {
|
||||
auto MCC::memory_read(Memory& memory, uint addr, uint8 data) -> uint8 {
|
||||
addr = bus.mirror(addr, memory.size());
|
||||
return memory.read(addr);
|
||||
return memory.read(addr, data);
|
||||
}
|
||||
|
||||
auto MCC::memory_write(Memory& memory, uint addr, uint8 data) -> void {
|
||||
|
@ -86,25 +86,25 @@ auto MCC::mcu_access(bool write, uint addr, uint8 data) -> uint8 {
|
|||
return memory_access(write, memory, addr & 0x7fffff, data);
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto MCC::mcu_read(uint addr) -> uint8 {
|
||||
return mcu_access(0, addr);
|
||||
auto MCC::mcu_read(uint addr, uint8 data) -> uint8 {
|
||||
return mcu_access(0, addr, data);
|
||||
}
|
||||
|
||||
auto MCC::mcu_write(uint addr, uint8 data) -> void {
|
||||
mcu_access(1, addr, data);
|
||||
}
|
||||
|
||||
auto MCC::mmio_read(uint addr) -> uint8 {
|
||||
auto MCC::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
return r[n];
|
||||
}
|
||||
|
||||
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
|
||||
return memory_read(ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
|
||||
return memory_read(ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
|
|
|
@ -12,14 +12,14 @@ struct MCC {
|
|||
auto reset() -> void;
|
||||
|
||||
auto memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8;
|
||||
auto memory_read(Memory& memory, uint addr) -> uint8;
|
||||
auto memory_read(Memory& memory, uint addr, uint8 data) -> uint8;
|
||||
auto memory_write(Memory& memory, uint addr, uint8 data) -> void;
|
||||
|
||||
auto mcu_access(bool write, uint addr, uint8 data = 0x00) -> uint8;
|
||||
auto mcu_read(uint addr) -> uint8;
|
||||
auto mcu_access(bool write, uint addr, uint8 data) -> uint8;
|
||||
auto mcu_read(uint addr, uint8 data) -> uint8;
|
||||
auto mcu_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mmio_read(uint addr) -> uint8;
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
auto mmio_commit() -> void;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ auto MSU1::enter() -> void {
|
|||
|
||||
audio.coprocessor_sample(left, right);
|
||||
step(1);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ auto MSU1::audioOpen() -> void {
|
|||
mmio.audioError = true;
|
||||
}
|
||||
|
||||
auto MSU1::mmioRead(uint addr) -> uint8 {
|
||||
auto MSU1::mmioRead(uint addr, uint8) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
addr = 0x2000 | (addr & 7);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ struct MSU1 : Coprocessor {
|
|||
auto dataOpen() -> void;
|
||||
auto audioOpen() -> void;
|
||||
|
||||
auto mmioRead(uint addr) -> uint8;
|
||||
auto mmioRead(uint addr, uint8 data) -> uint8;
|
||||
auto mmioWrite(uint addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
|
|
@ -15,11 +15,11 @@ auto NECDSP::enter() -> void {
|
|||
|
||||
exec();
|
||||
step(1);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
}
|
||||
|
||||
auto NECDSP::read(uint addr) -> uint8 {
|
||||
auto NECDSP::read(uint addr, uint8) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
if(addr & Select) {
|
||||
return uPD96050::readSR();
|
||||
|
@ -37,7 +37,7 @@ auto NECDSP::write(uint addr, uint8 data) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto NECDSP::readRAM(uint addr) -> uint8 {
|
||||
auto NECDSP::readRAM(uint addr, uint8) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
return uPD96050::readDP(addr);
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ struct NECDSP : Processor::uPD96050, Coprocessor {
|
|||
static auto Enter() -> void;
|
||||
auto enter() -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto readRAM(uint addr) -> uint8;
|
||||
auto readRAM(uint addr, uint8 data) -> uint8;
|
||||
auto writeRAM(uint addr, uint8 data) -> void;
|
||||
|
||||
auto init() -> void;
|
||||
|
|
|
@ -23,11 +23,11 @@ auto NSS::set_dip(uint16 dip) -> void {
|
|||
this->dip = dip;
|
||||
}
|
||||
|
||||
auto NSS::read(uint addr) -> uint8 {
|
||||
auto NSS::read(uint, uint8) -> uint8 {
|
||||
return dip;
|
||||
}
|
||||
|
||||
auto NSS::write(uint addr, uint8 data) -> void {
|
||||
auto NSS::write(uint, uint8) -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ struct NSS {
|
|||
auto reset() -> void;
|
||||
|
||||
auto set_dip(uint16 dip) -> void;
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
uint8 dip = 0x00;
|
||||
|
|
|
@ -24,7 +24,7 @@ auto OBC1::reset() -> void {
|
|||
status.shift = (ramRead(0x1ff6) & 3) << 1;
|
||||
}
|
||||
|
||||
auto OBC1::read(uint addr) -> uint8 {
|
||||
auto OBC1::read(uint addr, uint8) -> uint8 {
|
||||
addr &= 0x1fff;
|
||||
|
||||
switch(addr) {
|
||||
|
|
|
@ -5,7 +5,7 @@ struct OBC1 {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
|
|
@ -4,7 +4,7 @@ auto SA1::CPUIRAM::size() const -> uint {
|
|||
return sa1.iram.size();
|
||||
}
|
||||
|
||||
auto SA1::CPUIRAM::read(uint addr) -> uint8 {
|
||||
auto SA1::CPUIRAM::read(uint addr, uint8) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
return sa1.iram.read(addr & 0x07ff);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ auto SA1::CPUBWRAM::size() const -> uint {
|
|||
return sa1.bwram.size();
|
||||
}
|
||||
|
||||
auto SA1::CPUBWRAM::read(uint addr) -> uint8 {
|
||||
auto SA1::CPUBWRAM::read(uint addr, uint8) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
if(dma) return sa1.dma_cc1_read(addr);
|
||||
return sa1.bwram.read(addr);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
struct CPUIRAM : Memory {
|
||||
auto size() const -> uint;
|
||||
alwaysinline auto read(uint) -> uint8;
|
||||
alwaysinline auto read(uint, uint8 = 0) -> uint8;
|
||||
alwaysinline auto write(uint, uint8) -> void;
|
||||
} cpuiram;
|
||||
|
||||
struct CPUBWRAM : Memory {
|
||||
auto size() const -> uint;
|
||||
alwaysinline auto read(uint) -> uint8;
|
||||
alwaysinline auto read(uint, uint8 = 0) -> uint8;
|
||||
alwaysinline auto write(uint, uint8) -> void;
|
||||
bool dma;
|
||||
} cpubwram;
|
||||
|
|
|
@ -15,13 +15,13 @@ auto SA1::dma_normal() -> void {
|
|||
switch(mmio.sd) {
|
||||
case DMA::SourceROM:
|
||||
if((dsa & 0x408000) == 0x008000 || (dsa & 0xc00000) == 0xc00000) {
|
||||
data = bus_read(dsa);
|
||||
data = bus_read(dsa, data);
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA::SourceBWRAM:
|
||||
if((dsa & 0x40e000) == 0x006000 || (dsa & 0xf00000) == 0x400000) {
|
||||
data = bus_read(dsa);
|
||||
data = bus_read(dsa, data);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
auto SA1::bus_read(uint addr) -> uint8 {
|
||||
auto SA1::bus_read(uint addr, uint8 data) -> uint8 {
|
||||
if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff
|
||||
return mmio_read(addr);
|
||||
return mmio_read(addr, data);
|
||||
}
|
||||
|
||||
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
||||
return mmcrom_read(addr);
|
||||
return mmcrom_read(addr, data);
|
||||
}
|
||||
|
||||
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
|
||||
return mmcrom_read(addr);
|
||||
return mmcrom_read(addr, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||
return mmc_sa1_read(addr);
|
||||
return mmc_sa1_read(addr, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||
synchronize_cpu();
|
||||
return iram.read(addr & 2047);
|
||||
synchronizeCPU();
|
||||
return iram.read(addr & 2047, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||
synchronize_cpu();
|
||||
return iram.read(addr & 2047);
|
||||
synchronizeCPU();
|
||||
return iram.read(addr & 2047, data);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||
synchronize_cpu();
|
||||
return bwram.read(addr & (bwram.size() - 1));
|
||||
synchronizeCPU();
|
||||
return bwram.read(addr & (bwram.size() - 1), data);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
|
||||
synchronize_cpu();
|
||||
return bitmap_read(addr & 0x0fffff);
|
||||
synchronizeCPU();
|
||||
return bitmap_read(addr & 0x0fffff, data);
|
||||
}
|
||||
|
||||
//unmapped region
|
||||
return regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SA1::bus_write(uint addr, uint8 data) -> void {
|
||||
|
@ -49,22 +49,22 @@ auto SA1::bus_write(uint addr, uint8 data) -> void {
|
|||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
return iram.write(addr & 2047, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
return iram.write(addr & 2047, data);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
return bwram.write(addr & (bwram.size() - 1), data);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
return bitmap_write(addr & 0x0fffff, data);
|
||||
}
|
||||
}
|
||||
|
@ -73,29 +73,29 @@ auto SA1::bus_write(uint addr, uint8 data) -> void {
|
|||
//this is used both to keep VBR-reads from accessing MMIO registers, and
|
||||
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
|
||||
//these ports.
|
||||
auto SA1::vbr_read(uint addr) -> uint8 {
|
||||
auto SA1::vbr_read(uint addr, uint8 data) -> uint8 {
|
||||
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
||||
return mmcrom_read(addr);
|
||||
return mmcrom_read(addr, data);
|
||||
}
|
||||
|
||||
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
|
||||
return mmcrom_read(addr);
|
||||
return mmcrom_read(addr, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||
return bwram.read(addr & (bwram.size() - 1));
|
||||
return bwram.read(addr & (bwram.size() - 1), data);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||
return bwram.read(addr & (bwram.size() - 1));
|
||||
return bwram.read(addr & (bwram.size() - 1), data);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||
return iram.read(addr & 2047);
|
||||
return iram.read(addr & 2047, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||
return iram.read(addr & 2047);
|
||||
return iram.read(addr & 2047, data);
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
|
@ -113,7 +113,7 @@ auto SA1::op_io() -> void {
|
|||
auto SA1::op_read(uint addr) -> uint8 {
|
||||
tick();
|
||||
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
|
||||
return bus_read(addr);
|
||||
return bus_read(addr, regs.mdr);
|
||||
}
|
||||
|
||||
auto SA1::op_write(uint addr, uint8 data) -> void {
|
||||
|
@ -122,7 +122,7 @@ auto SA1::op_write(uint addr, uint8 data) -> void {
|
|||
bus_write(addr, regs.mdr = data);
|
||||
}
|
||||
|
||||
auto SA1::mmcrom_read(uint addr) -> uint8 {
|
||||
auto SA1::mmcrom_read(uint addr, uint8) -> uint8 {
|
||||
if((addr & 0xffffe0) == 0x00ffe0) {
|
||||
if(addr == 0xffea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
|
||||
if(addr == 0xffeb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
|
||||
|
@ -180,7 +180,7 @@ auto SA1::mmcrom_read(uint addr) -> uint8 {
|
|||
auto SA1::mmcrom_write(uint addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
auto SA1::mmcbwram_read(uint addr) -> uint8 {
|
||||
auto SA1::mmcbwram_read(uint addr, uint8 data) -> uint8 {
|
||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||
cpu.synchronizeCoprocessors();
|
||||
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
|
||||
|
@ -191,7 +191,7 @@ auto SA1::mmcbwram_read(uint addr) -> uint8 {
|
|||
return cpubwram.read(addr & 0x0fffff);
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SA1::mmcbwram_write(uint addr, uint8 data) -> void {
|
||||
|
@ -206,21 +206,21 @@ auto SA1::mmcbwram_write(uint addr, uint8 data) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto SA1::mmc_sa1_read(uint addr) -> uint8 {
|
||||
synchronize_cpu();
|
||||
auto SA1::mmc_sa1_read(uint addr, uint8 data) -> uint8 {
|
||||
synchronizeCPU();
|
||||
if(mmio.sw46 == 0) {
|
||||
//$40-43:0000-ffff x 32 projection
|
||||
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), bwram.size());
|
||||
return bwram.read(addr);
|
||||
return bwram.read(addr, data);
|
||||
} else {
|
||||
//$60-6f:0000-ffff x 128 projection
|
||||
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000);
|
||||
return bitmap_read(addr);
|
||||
return bitmap_read(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
auto SA1::mmc_sa1_write(uint addr, uint8 data) -> void {
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
if(mmio.sw46 == 0) {
|
||||
//$40-43:0000-ffff x 32 projection
|
||||
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), bwram.size());
|
||||
|
@ -232,7 +232,7 @@ auto SA1::mmc_sa1_write(uint addr, uint8 data) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto SA1::bitmap_read(uint addr) -> uint8 {
|
||||
auto SA1::bitmap_read(uint addr, uint8 data) -> uint8 {
|
||||
if(mmio.bbf == 0) {
|
||||
//4bpp
|
||||
uint shift = addr & 1;
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
auto bus_read(uint addr) -> uint8;
|
||||
auto bus_read(uint addr, uint8 data) -> uint8;
|
||||
auto bus_write(uint addr, uint8 data) -> void;
|
||||
auto vbr_read(uint addr) -> uint8;
|
||||
auto vbr_read(uint addr, uint8 data = 0) -> uint8;
|
||||
|
||||
alwaysinline auto op_io() -> void;
|
||||
alwaysinline auto op_read(uint addr) -> uint8;
|
||||
alwaysinline auto op_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mmcrom_read(uint addr) -> uint8;
|
||||
auto mmcrom_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmcrom_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mmcbwram_read(uint addr) -> uint8;
|
||||
auto mmcbwram_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmcbwram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mmc_sa1_read(uint addr) -> uint8;
|
||||
auto mmc_sa1_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmc_sa1_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto bitmap_read(uint addr) -> uint8;
|
||||
auto bitmap_read(uint addr, uint8 data) -> uint8;
|
||||
auto bitmap_write(uint addr, uint8 data) -> void;
|
||||
|
|
|
@ -445,8 +445,8 @@ auto SA1::mmio_r230e() -> uint8 {
|
|||
return 0x01; //true value unknown
|
||||
}
|
||||
|
||||
auto SA1::mmio_read(uint addr) -> uint8 {
|
||||
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronize_cpu());
|
||||
auto SA1::mmio_read(uint addr, uint8) -> uint8 {
|
||||
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronizeCPU());
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
|
@ -471,7 +471,7 @@ auto SA1::mmio_read(uint addr) -> uint8 {
|
|||
}
|
||||
|
||||
auto SA1::mmio_write(uint addr, uint8 data) -> void {
|
||||
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronize_cpu());
|
||||
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronizeCPU());
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
auto mmio_read(uint addr) -> uint8;
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
struct MMIO {
|
||||
|
|
|
@ -21,7 +21,7 @@ auto SA1::enter() -> void {
|
|||
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||
//SA-1 co-processor is asleep
|
||||
tick();
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ auto SA1::interrupt_pending() -> bool {
|
|||
|
||||
auto SA1::tick() -> void {
|
||||
step(2);
|
||||
if(++status.tick_counter == 0) synchronize_cpu();
|
||||
if(++status.tick_counter == 0) synchronizeCPU();
|
||||
|
||||
//adjust counters:
|
||||
//note that internally, status counters are in clocks;
|
||||
|
|
|
@ -41,11 +41,11 @@ auto SDD1::reset() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto SDD1::read(uint addr) -> uint8 {
|
||||
addr &= 0xffff;
|
||||
auto SDD1::read(uint addr, uint8 data) -> uint8 {
|
||||
addr &= 0x40ffff;
|
||||
|
||||
if((addr & 0x4380) == 0x4300) {
|
||||
return cpu.mmio_read(addr);
|
||||
if((addr & 0x404380) == 0x4300) {
|
||||
return cpu.mmio_read(addr, data);
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
|
@ -55,7 +55,7 @@ auto SDD1::read(uint addr) -> uint8 {
|
|||
case 0x4807: return mmc[3] >> 20;
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SDD1::write(uint addr, uint8 data) -> void {
|
||||
|
@ -107,7 +107,7 @@ auto SDD1::mmc_read(uint addr) -> uint8 {
|
|||
//
|
||||
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
|
||||
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
|
||||
auto SDD1::mcurom_read(uint addr) -> uint8 {
|
||||
auto SDD1::mcurom_read(uint addr, uint8) -> uint8 {
|
||||
if(addr < 0x400000) { //(addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
||||
return rom.read(addr);
|
||||
//addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
||||
|
@ -147,16 +147,16 @@ auto SDD1::mcurom_read(uint addr) -> uint8 {
|
|||
auto SDD1::mcurom_write(uint addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
auto SDD1::mcuram_read(uint addr) -> uint8 {
|
||||
auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 {
|
||||
if((addr & 0x60e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||
return ram.read(addr & 0x1fff);
|
||||
return ram.read(addr & 0x1fff, data);
|
||||
}
|
||||
|
||||
if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff
|
||||
return ram.read(addr & 0x1fff);
|
||||
return ram.read(addr & 0x1fff, data);
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SDD1::mcuram_write(uint addr, uint8 data) -> void {
|
||||
|
|
|
@ -5,15 +5,15 @@ struct SDD1 {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mmc_read(uint addr) -> uint8;
|
||||
|
||||
auto mcurom_read(uint addr) -> uint8;
|
||||
auto mcurom_read(uint addr, uint8 data) -> uint8;
|
||||
auto mcurom_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mcuram_read(uint addr) -> uint8;
|
||||
auto mcuram_read(uint addr, uint8 data) -> uint8;
|
||||
auto mcuram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
|
|
@ -7,11 +7,11 @@ namespace SuperFamicom {
|
|||
#include "serialization.cpp"
|
||||
SharpRTC sharprtc;
|
||||
|
||||
void SharpRTC::Enter() {
|
||||
auto SharpRTC::Enter() -> void {
|
||||
sharprtc.enter();
|
||||
}
|
||||
|
||||
void SharpRTC::enter() {
|
||||
auto SharpRTC::enter() -> void {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
|
@ -20,14 +20,14 @@ void SharpRTC::enter() {
|
|||
tick_second();
|
||||
|
||||
step(1);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
}
|
||||
|
||||
void SharpRTC::init() {
|
||||
auto SharpRTC::init() -> void {
|
||||
}
|
||||
|
||||
void SharpRTC::load() {
|
||||
auto SharpRTC::load() -> void {
|
||||
return;
|
||||
|
||||
second = 0;
|
||||
|
@ -39,20 +39,20 @@ void SharpRTC::load() {
|
|||
weekday = 0;
|
||||
}
|
||||
|
||||
void SharpRTC::unload() {
|
||||
auto SharpRTC::unload() -> void {
|
||||
}
|
||||
|
||||
void SharpRTC::power() {
|
||||
auto SharpRTC::power() -> void {
|
||||
}
|
||||
|
||||
void SharpRTC::reset() {
|
||||
auto SharpRTC::reset() -> void {
|
||||
create(SharpRTC::Enter, 1);
|
||||
|
||||
rtc_state = State::Read;
|
||||
rtc_index = -1;
|
||||
}
|
||||
|
||||
void SharpRTC::sync() {
|
||||
auto SharpRTC::sync() -> void {
|
||||
time_t systime = time(0);
|
||||
tm* timeinfo = localtime(&systime);
|
||||
|
||||
|
@ -65,7 +65,7 @@ void SharpRTC::sync() {
|
|||
weekday = timeinfo->tm_wday;
|
||||
}
|
||||
|
||||
uint8 SharpRTC::read(unsigned addr) {
|
||||
auto SharpRTC::read(uint addr, uint8 data) -> uint8 {
|
||||
addr &= 1;
|
||||
|
||||
if(addr == 0) {
|
||||
|
@ -82,10 +82,10 @@ uint8 SharpRTC::read(unsigned addr) {
|
|||
}
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
void SharpRTC::write(unsigned addr, uint8 data) {
|
||||
auto SharpRTC::write(uint addr, uint8 data) -> void {
|
||||
addr &= 1, data &= 15;
|
||||
|
||||
if(addr == 1) {
|
||||
|
|
|
@ -9,7 +9,7 @@ struct SharpRTC : Coprocessor {
|
|||
auto reset() -> void;
|
||||
auto sync() -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
|
|
@ -34,7 +34,7 @@ auto SPC7110::enter() -> void {
|
|||
|
||||
auto SPC7110::add_clocks(uint clocks) -> void {
|
||||
step(clocks);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
auto SPC7110::init() -> void {
|
||||
|
@ -109,7 +109,7 @@ auto SPC7110::reset() -> void {
|
|||
r4834 = 0x00;
|
||||
}
|
||||
|
||||
auto SPC7110::read(uint addr) -> uint8 {
|
||||
auto SPC7110::read(uint addr, uint8 data) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
if((addr & 0xff0000) == 0x500000) addr = 0x4800;
|
||||
addr = 0x4800 | (addr & 0x3f);
|
||||
|
@ -145,7 +145,7 @@ auto SPC7110::read(uint addr) -> uint8 {
|
|||
//==============
|
||||
|
||||
case 0x4810: {
|
||||
uint8 data = r4810;
|
||||
data = r4810;
|
||||
data_port_increment_4810();
|
||||
return data;
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ auto SPC7110::read(uint addr) -> uint8 {
|
|||
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SPC7110::write(uint addr, uint8 data) -> void {
|
||||
|
@ -264,7 +264,7 @@ auto SPC7110::write(uint addr, uint8 data) -> void {
|
|||
//SPC7110::MCUROM
|
||||
//===============
|
||||
|
||||
auto SPC7110::mcurom_read(uint addr) -> uint8 {
|
||||
auto SPC7110::mcurom_read(uint addr, uint8 data) -> uint8 {
|
||||
uint mask = (1 << (r4834 & 3)) - 1; //8mbit, 16mbit, 32mbit, 64mbit DROM
|
||||
|
||||
if((addr & 0x708000) == 0x008000 //$00-0f|80-8f:8000-ffff
|
||||
|
@ -305,7 +305,7 @@ auto SPC7110::mcurom_read(uint addr) -> uint8 {
|
|||
return datarom_read(addr);
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SPC7110::mcurom_write(uint addr, uint8 data) -> void {
|
||||
|
@ -315,7 +315,7 @@ auto SPC7110::mcurom_write(uint addr, uint8 data) -> void {
|
|||
//SPC7110::MCURAM
|
||||
//===============
|
||||
|
||||
auto SPC7110::mcuram_read(uint addr) -> uint8 {
|
||||
auto SPC7110::mcuram_read(uint addr, uint8) -> uint8 {
|
||||
//$00-3f|80-bf:6000-7fff
|
||||
if(r4830 & 0x80) {
|
||||
uint bank = (addr >> 16) & 0x3f;
|
||||
|
|
|
@ -14,13 +14,13 @@ struct SPC7110 : Coprocessor {
|
|||
|
||||
auto add_clocks(uint clocks) -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mcurom_read(uint addr) -> uint8;
|
||||
auto mcurom_read(uint addr, uint8 data) -> uint8;
|
||||
auto mcurom_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto mcuram_read(uint addr) -> uint8;
|
||||
auto mcuram_read(uint addr, uint8 data) -> uint8;
|
||||
auto mcuram_write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
//ROM / RAM access from the S-CPU
|
||||
|
||||
auto SuperFX::CPUROM::size() const -> unsigned {
|
||||
auto SuperFX::CPUROM::size() const -> uint {
|
||||
return superfx.rom.size();
|
||||
}
|
||||
|
||||
auto SuperFX::CPUROM::read(unsigned addr) -> uint8 {
|
||||
auto SuperFX::CPUROM::read(uint addr, uint8 data) -> uint8 {
|
||||
if(superfx.regs.sfr.g && superfx.regs.scmr.ron) {
|
||||
static const uint8_t data[16] = {
|
||||
static const uint8 vector[16] = {
|
||||
0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01,
|
||||
0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01,
|
||||
};
|
||||
return data[addr & 15];
|
||||
return vector[addr & 15];
|
||||
}
|
||||
return superfx.rom.read(addr);
|
||||
return superfx.rom.read(addr, data);
|
||||
}
|
||||
|
||||
auto SuperFX::CPUROM::write(unsigned addr, uint8 data) -> void {
|
||||
auto SuperFX::CPUROM::write(uint addr, uint8 data) -> void {
|
||||
superfx.rom.write(addr, data);
|
||||
}
|
||||
|
||||
auto SuperFX::CPURAM::size() const -> unsigned {
|
||||
auto SuperFX::CPURAM::size() const -> uint {
|
||||
return superfx.ram.size();
|
||||
}
|
||||
|
||||
auto SuperFX::CPURAM::read(unsigned addr) -> uint8 {
|
||||
if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return cpu.regs.mdr;
|
||||
return superfx.ram.read(addr);
|
||||
auto SuperFX::CPURAM::read(uint addr, uint8 data) -> uint8 {
|
||||
if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return data;
|
||||
return superfx.ram.read(addr, data);
|
||||
}
|
||||
|
||||
auto SuperFX::CPURAM::write(unsigned addr, uint8 data) -> void {
|
||||
auto SuperFX::CPURAM::write(uint addr, uint8 data) -> void {
|
||||
superfx.ram.write(addr, data);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
struct CPUROM : Memory {
|
||||
auto size() const -> unsigned;
|
||||
auto read(unsigned) -> uint8;
|
||||
auto write(unsigned, uint8) -> void;
|
||||
auto size() const -> uint;
|
||||
auto read(uint, uint8) -> uint8;
|
||||
auto write(uint, uint8) -> void;
|
||||
} cpurom;
|
||||
|
||||
struct CPURAM : Memory {
|
||||
auto size() const -> unsigned;
|
||||
auto read(unsigned) -> uint8;
|
||||
auto write(unsigned, uint8) -> void;
|
||||
auto size() const -> uint;
|
||||
auto read(uint, uint8) -> uint8;
|
||||
auto write(uint, uint8) -> void;
|
||||
} cpuram;
|
||||
|
|
|
@ -2,7 +2,7 @@ auto SuperFX::bus_read(unsigned addr) -> uint8 {
|
|||
if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff, $00-3f:8000-ffff
|
||||
while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
step(6);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
return rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & rom_mask);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ auto SuperFX::bus_read(unsigned addr) -> uint8 {
|
|||
if((addr & 0xe00000) == 0x400000) { //$40-5f:0000-ffff
|
||||
while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
step(6);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
return rom.read(addr & rom_mask);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ auto SuperFX::bus_read(unsigned addr) -> uint8 {
|
|||
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
|
||||
while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
step(6);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
return ram.read(addr & ram_mask);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ auto SuperFX::bus_write(unsigned addr, uint8 data) -> void {
|
|||
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
|
||||
while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
step(6);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
return ram.write(addr & ram_mask, data);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
auto SuperFX::mmio_read(unsigned addr) -> uint8 {
|
||||
auto SuperFX::mmio_read(uint addr, uint8) -> uint8 {
|
||||
cpu.synchronizeCoprocessors();
|
||||
addr &= 0xffff;
|
||||
|
||||
|
@ -50,7 +50,7 @@ auto SuperFX::mmio_read(unsigned addr) -> uint8 {
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
auto SuperFX::mmio_write(unsigned addr, uint8 data) -> void {
|
||||
auto SuperFX::mmio_write(uint addr, uint8 data) -> void {
|
||||
cpu.synchronizeCoprocessors();
|
||||
addr &= 0xffff;
|
||||
|
||||
|
@ -59,7 +59,7 @@ auto SuperFX::mmio_write(unsigned addr, uint8 data) -> void {
|
|||
}
|
||||
|
||||
if(addr >= 0x3000 && addr <= 0x301f) {
|
||||
unsigned n = (addr >> 1) & 15;
|
||||
uint n = (addr >> 1) & 15;
|
||||
if((addr & 1) == 0) {
|
||||
regs.r[n] = (regs.r[n] & 0xff00) | data;
|
||||
} else {
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
auto mmio_read(unsigned addr) -> uint8;
|
||||
auto mmio_write(unsigned addr, uint8 data) -> void;
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
|
|
@ -15,7 +15,7 @@ auto SuperFX::step(unsigned clocks) -> void {
|
|||
}
|
||||
|
||||
Coprocessor::step(clocks);
|
||||
synchronize_cpu();
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
||||
auto SuperFX::rombuffer_sync() -> void {
|
||||
|
|
|
@ -78,8 +78,8 @@ auto CPU::enter() -> void {
|
|||
} else if(status.reset_pending) {
|
||||
status.reset_pending = false;
|
||||
add_clocks(186);
|
||||
regs.pc.l = bus.read(0xfffc);
|
||||
regs.pc.h = bus.read(0xfffd);
|
||||
regs.pc.l = bus.read(0xfffc, regs.mdr);
|
||||
regs.pc.h = bus.read(0xfffd, regs.mdr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,8 +93,8 @@ auto CPU::op_step() -> void {
|
|||
}
|
||||
|
||||
auto CPU::enable() -> void {
|
||||
function<uint8 (unsigned)> reader{&CPU::mmio_read, (CPU*)&cpu};
|
||||
function<void (unsigned, uint8)> writer{&CPU::mmio_write, (CPU*)&cpu};
|
||||
function<auto (uint, uint8) -> uint8> reader{&CPU::mmio_read, (CPU*)&cpu};
|
||||
function<auto (uint, uint8) -> void> writer{&CPU::mmio_write, (CPU*)&cpu};
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
|
||||
|
@ -108,8 +108,8 @@ auto CPU::enable() -> void {
|
|||
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
|
||||
|
||||
reader = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
writer = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
reader = [](uint addr, uint8) -> uint8 { return cpu.wram[addr]; };
|
||||
writer = [](uint addr, uint8 data) -> void { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
|
||||
|
|
|
@ -24,7 +24,7 @@ auto CPU::dma_addr_valid(uint32 abus) -> bool {
|
|||
|
||||
auto CPU::dma_read(uint32 abus) -> uint8 {
|
||||
if(dma_addr_valid(abus) == false) return 0x00;
|
||||
return bus.read(abus);
|
||||
return bus.read(abus, regs.mdr);
|
||||
}
|
||||
|
||||
//simulate two-stage pipeline for DMA transfers; example:
|
||||
|
@ -47,7 +47,7 @@ auto CPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) -> void {
|
|||
dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, regs.mdr);
|
||||
} else {
|
||||
dma_add_clocks(4);
|
||||
regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus) : 0x00;
|
||||
regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus, regs.mdr) : 0x00;
|
||||
dma_add_clocks(4);
|
||||
dma_write(dma_addr_valid(abus), abus, regs.mdr);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ auto CPU::op_read(uint32 addr) -> uint8 {
|
|||
status.clock_count = speed(addr);
|
||||
dma_edge();
|
||||
add_clocks(status.clock_count - 4);
|
||||
regs.mdr = bus.read(addr);
|
||||
regs.mdr = bus.read(addr, regs.mdr);
|
||||
add_clocks(4);
|
||||
alu_edge();
|
||||
debugger.op_read(addr, regs.mdr);
|
||||
|
@ -44,5 +44,5 @@ auto CPU::speed(uint addr) const -> uint {
|
|||
}
|
||||
|
||||
auto CPU::disassembler_read(uint32 addr) -> uint8 {
|
||||
return bus.read(addr);
|
||||
return bus.read(addr, regs.mdr);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ auto CPU::joylatch() -> bool {
|
|||
|
||||
//WMDATA
|
||||
auto CPU::mmio_r2180() -> uint8 {
|
||||
return bus.read(0x7e0000 | status.wram_addr++);
|
||||
return bus.read(0x7e0000 | status.wram_addr++, regs.mdr);
|
||||
}
|
||||
|
||||
//WMDATA
|
||||
|
@ -405,7 +405,7 @@ auto CPU::mmio_reset() -> void {
|
|||
alu.shift = 0;
|
||||
}
|
||||
|
||||
auto CPU::mmio_read(uint addr) -> uint8 {
|
||||
auto CPU::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||
addr &= 0xffff;
|
||||
|
||||
//APU
|
||||
|
@ -416,7 +416,7 @@ auto CPU::mmio_read(uint addr) -> uint8 {
|
|||
|
||||
//DMA
|
||||
if((addr & 0xff80) == 0x4300) { //$4300-$437f
|
||||
unsigned i = (addr >> 4) & 7;
|
||||
uint i = (addr >> 4) & 7;
|
||||
switch(addr & 0xf) {
|
||||
case 0x0: return mmio_r43x0(i);
|
||||
case 0x1: return mmio_r43x1(i);
|
||||
|
@ -459,7 +459,7 @@ auto CPU::mmio_read(uint addr) -> uint8 {
|
|||
case 0x421f: return mmio_r421f();
|
||||
}
|
||||
|
||||
return regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto CPU::mmio_write(uint addr, uint8 data) -> void {
|
||||
|
@ -474,7 +474,7 @@ auto CPU::mmio_write(uint addr, uint8 data) -> void {
|
|||
|
||||
//DMA
|
||||
if((addr & 0xff80) == 0x4300) { //$4300-$437f
|
||||
unsigned i = (addr >> 4) & 7;
|
||||
uint i = (addr >> 4) & 7;
|
||||
switch(addr & 0xf) {
|
||||
case 0x0: mmio_w43x0(i, data); return;
|
||||
case 0x1: mmio_w43x1(i, data); return;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
public:
|
||||
auto mmio_read(uint addr) -> uint8;
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
privileged:
|
||||
|
|
|
@ -8,8 +8,8 @@ auto eBoot::init() -> void {
|
|||
}
|
||||
|
||||
auto eBoot::load() -> void {
|
||||
resetVector = bus.read(0xfffc) << 0;
|
||||
resetVector |= bus.read(0xfffd) << 8;
|
||||
resetVector = bus.read(0xfffc, 0x00) << 0;
|
||||
resetVector |= bus.read(0xfffd, 0x00) << 8;
|
||||
|
||||
for(auto& byte : ram) byte = 0xdb;
|
||||
ram[0] = 0x6c; //jmp ($fffc)
|
||||
|
@ -35,12 +35,12 @@ auto eBoot::reset() -> void {
|
|||
booted = false;
|
||||
}
|
||||
|
||||
auto eBoot::read(uint addr) -> uint8 {
|
||||
addr &= 0xffff;
|
||||
auto eBoot::read(uint addr, uint8 data) -> uint8 {
|
||||
addr &= 0x40ffff;
|
||||
if(addr == 0xfffc) return booted ? resetVector >> 0 : 0x84;
|
||||
if(addr == 0xfffd) return booted ? resetVector >> 8 : (booted = true, 0x21);
|
||||
if(addr >= 0x2184 && addr <= 0x21ff) return ram[addr - 0x2184];
|
||||
return 0xdb; //should never occur
|
||||
return data;
|
||||
}
|
||||
|
||||
auto eBoot::write(uint addr, uint8 data) -> void {
|
||||
|
|
|
@ -5,7 +5,7 @@ struct eBoot : Memory {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
|
|
|
@ -22,7 +22,7 @@ auto Satellaview::reset() -> void {
|
|||
memory::fill(®s, sizeof regs);
|
||||
}
|
||||
|
||||
auto Satellaview::read(uint addr) -> uint8 {
|
||||
auto Satellaview::read(uint addr, uint8 data) -> uint8 {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
|
@ -77,7 +77,7 @@ auto Satellaview::read(uint addr) -> uint8 {
|
|||
case 0x2199: return regs.r2199;
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto Satellaview::write(uint addr, uint8 data) -> void {
|
||||
|
|
|
@ -5,7 +5,7 @@ struct Satellaview : Memory {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto read(uint addr) -> uint8;
|
||||
auto read(uint addr, uint8 data) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
//Memory
|
||||
|
||||
auto Memory::size() const -> unsigned { return 0; }
|
||||
auto Memory::size() const -> uint { return 0; }
|
||||
|
||||
//StaticRAM
|
||||
|
||||
StaticRAM::StaticRAM(unsigned n) : size_(n) { data_ = new uint8[size_]; }
|
||||
StaticRAM::StaticRAM(uint n) : size_(n) { data_ = new uint8[size_]; }
|
||||
StaticRAM::~StaticRAM() { delete[] data_; }
|
||||
|
||||
auto StaticRAM::data() -> uint8* { return data_; }
|
||||
auto StaticRAM::size() const -> unsigned { return size_; }
|
||||
auto StaticRAM::size() const -> uint { return size_; }
|
||||
|
||||
auto StaticRAM::read(unsigned addr) -> uint8 { return data_[addr]; }
|
||||
auto StaticRAM::write(unsigned addr, uint8 n) -> void { data_[addr] = n; }
|
||||
auto StaticRAM::operator[](unsigned addr) -> uint8& { return data_[addr]; }
|
||||
auto StaticRAM::operator[](unsigned addr) const -> const uint8& { return data_[addr]; }
|
||||
auto StaticRAM::read(uint addr, uint8) -> uint8 { return data_[addr]; }
|
||||
auto StaticRAM::write(uint addr, uint8 data) -> void { data_[addr] = data; }
|
||||
auto StaticRAM::operator[](uint addr) -> uint8& { return data_[addr]; }
|
||||
auto StaticRAM::operator[](uint addr) const -> const uint8& { return data_[addr]; }
|
||||
|
||||
//MappedRAM
|
||||
|
||||
|
@ -26,7 +26,7 @@ auto MappedRAM::reset() -> void {
|
|||
write_protect_ = false;
|
||||
}
|
||||
|
||||
auto MappedRAM::map(uint8* source, unsigned length) -> void {
|
||||
auto MappedRAM::map(uint8* source, uint length) -> void {
|
||||
reset();
|
||||
data_ = source;
|
||||
size_ = data_ ? length : 0;
|
||||
|
@ -46,18 +46,18 @@ auto MappedRAM::read(const stream& memory) -> void {
|
|||
|
||||
auto MappedRAM::write_protect(bool status) -> void { write_protect_ = status; }
|
||||
auto MappedRAM::data() -> uint8* { return data_; }
|
||||
auto MappedRAM::size() const -> unsigned { return size_; }
|
||||
auto MappedRAM::size() const -> uint { return size_; }
|
||||
|
||||
auto MappedRAM::read(unsigned addr) -> uint8 { return data_[addr]; }
|
||||
auto MappedRAM::write(unsigned addr, uint8 n) -> void { if(!write_protect_) data_[addr] = n; }
|
||||
auto MappedRAM::operator[](unsigned addr) const -> const uint8& { return data_[addr]; }
|
||||
auto MappedRAM::read(uint addr, uint8) -> uint8 { return data_[addr]; }
|
||||
auto MappedRAM::write(uint addr, uint8 data) -> void { if(!write_protect_) data_[addr] = data; }
|
||||
auto MappedRAM::operator[](uint addr) const -> const uint8& { return data_[addr]; }
|
||||
|
||||
//Bus
|
||||
|
||||
auto Bus::mirror(unsigned addr, unsigned size) -> unsigned {
|
||||
auto Bus::mirror(uint addr, uint size) -> uint {
|
||||
if(size == 0) return 0;
|
||||
unsigned base = 0;
|
||||
unsigned mask = 1 << 23;
|
||||
uint base = 0;
|
||||
uint mask = 1 << 23;
|
||||
while(addr >= size) {
|
||||
while(!(addr & mask)) mask >>= 1;
|
||||
addr -= mask;
|
||||
|
@ -70,17 +70,17 @@ auto Bus::mirror(unsigned addr, unsigned size) -> unsigned {
|
|||
return base + addr;
|
||||
}
|
||||
|
||||
auto Bus::reduce(unsigned addr, unsigned mask) -> unsigned {
|
||||
auto Bus::reduce(uint addr, uint mask) -> uint {
|
||||
while(mask) {
|
||||
unsigned bits = (mask & -mask) - 1;
|
||||
uint bits = (mask & -mask) - 1;
|
||||
addr = ((addr >> 1) & ~bits) | (addr & bits);
|
||||
mask = (mask & (mask - 1)) >> 1;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
auto Bus::read(unsigned addr) -> uint8 {
|
||||
uint8 data = reader[lookup[addr]](target[addr]);
|
||||
auto Bus::read(uint addr, uint8 data) -> uint8 {
|
||||
data = reader[lookup[addr]](target[addr], data);
|
||||
|
||||
if(cheat.enable()) {
|
||||
if(auto result = cheat.find(addr, data)) return result();
|
||||
|
@ -89,6 +89,6 @@ auto Bus::read(unsigned addr) -> uint8 {
|
|||
return data;
|
||||
}
|
||||
|
||||
auto Bus::write(unsigned addr, uint8 data) -> void {
|
||||
auto Bus::write(uint addr, uint8 data) -> void {
|
||||
return writer[lookup[addr]](target[addr], data);
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ Bus::~Bus() {
|
|||
}
|
||||
|
||||
auto Bus::reset() -> void {
|
||||
function<uint8 (unsigned)> reader = [](unsigned) { return cpu.regs.mdr; };
|
||||
function<void (unsigned, uint8)> writer = [](unsigned, uint8) {};
|
||||
function<auto (uint, uint8) -> uint8> reader = [](uint, uint8 data) { return data; };
|
||||
function<auto (uint, uint8) -> void> writer = [](uint, uint8) {};
|
||||
|
||||
idcount = 0;
|
||||
map(reader, writer, 0x00, 0xff, 0x0000, 0xffff);
|
||||
|
@ -31,10 +31,10 @@ auto Bus::map() -> void {
|
|||
for(auto& addr : addrs) {
|
||||
lstring bankpart = bank.split("-", 1L);
|
||||
lstring addrpart = addr.split("-", 1L);
|
||||
unsigned banklo = hex(bankpart(0));
|
||||
unsigned bankhi = hex(bankpart(1, bankpart(0)));
|
||||
unsigned addrlo = hex(addrpart(0));
|
||||
unsigned addrhi = hex(addrpart(1, addrpart(0)));
|
||||
uint banklo = hex(bankpart(0));
|
||||
uint bankhi = hex(bankpart(1, bankpart(0)));
|
||||
uint addrlo = hex(addrpart(0));
|
||||
uint addrhi = hex(addrpart(1, addrpart(0)));
|
||||
map(m.reader, m.writer, banklo, bankhi, addrlo, addrhi, m.size, m.base, m.mask);
|
||||
}
|
||||
}
|
||||
|
@ -42,23 +42,22 @@ auto Bus::map() -> void {
|
|||
}
|
||||
|
||||
auto Bus::map(
|
||||
const function<uint8 (unsigned)>& reader,
|
||||
const function<void (unsigned, uint8)>& writer,
|
||||
unsigned banklo, unsigned bankhi,
|
||||
unsigned addrlo, unsigned addrhi,
|
||||
unsigned size, unsigned base, unsigned mask
|
||||
const function<uint8 (uint, uint8)>& reader,
|
||||
const function<void (uint, uint8)>& writer,
|
||||
uint banklo, uint bankhi, uint addrlo, uint addrhi,
|
||||
uint size, uint base, uint mask
|
||||
) -> void {
|
||||
assert(banklo <= bankhi && banklo <= 0xff);
|
||||
assert(addrlo <= addrhi && addrlo <= 0xffff);
|
||||
assert(banklo <= bankhi && bankhi <= 0xff);
|
||||
assert(addrlo <= addrhi && addrhi <= 0xffff);
|
||||
assert(idcount < 255);
|
||||
|
||||
unsigned id = idcount++;
|
||||
uint id = idcount++;
|
||||
this->reader[id] = reader;
|
||||
this->writer[id] = writer;
|
||||
|
||||
for(unsigned bank = banklo; bank <= bankhi; bank++) {
|
||||
for(unsigned addr = addrlo; addr <= addrhi; addr++) {
|
||||
unsigned offset = reduce(bank << 16 | addr, mask);
|
||||
for(uint bank = banklo; bank <= bankhi; bank++) {
|
||||
for(uint addr = addrlo; addr <= addrhi; addr++) {
|
||||
uint offset = reduce(bank << 16 | addr, mask);
|
||||
if(size) offset = base + mirror(offset, size - base);
|
||||
lookup[bank << 16 | addr] = id;
|
||||
target[bank << 16 | addr] = offset;
|
||||
|
|
|
@ -1,72 +1,71 @@
|
|||
struct Memory {
|
||||
virtual inline auto size() const -> unsigned;
|
||||
virtual auto read(unsigned addr) -> uint8 = 0;
|
||||
virtual auto write(unsigned addr, uint8 data) -> void = 0;
|
||||
virtual inline auto size() const -> uint;
|
||||
virtual auto read(uint addr, uint8 data = 0) -> uint8 = 0;
|
||||
virtual auto write(uint addr, uint8 data) -> void = 0;
|
||||
};
|
||||
|
||||
struct StaticRAM : Memory {
|
||||
inline StaticRAM(unsigned size);
|
||||
inline StaticRAM(uint size);
|
||||
inline ~StaticRAM();
|
||||
|
||||
inline auto data() -> uint8*;
|
||||
inline auto size() const -> unsigned;
|
||||
inline auto size() const -> uint;
|
||||
|
||||
inline auto read(unsigned addr) -> uint8;
|
||||
inline auto write(unsigned addr, uint8 n) -> void;
|
||||
inline auto operator[](unsigned addr) -> uint8&;
|
||||
inline auto operator[](unsigned addr) const -> const uint8&;
|
||||
inline auto read(uint addr, uint8 data = 0) -> uint8;
|
||||
inline auto write(uint addr, uint8 data) -> void;
|
||||
inline auto operator[](uint addr) -> uint8&;
|
||||
inline auto operator[](uint addr) const -> const uint8&;
|
||||
|
||||
private:
|
||||
uint8* data_ = nullptr;
|
||||
unsigned size_ = 0;
|
||||
uint size_ = 0;
|
||||
};
|
||||
|
||||
struct MappedRAM : Memory {
|
||||
inline auto reset() -> void;
|
||||
inline auto map(uint8*, unsigned) -> void;
|
||||
inline auto map(uint8*, uint) -> void;
|
||||
inline auto copy(const stream& memory) -> void;
|
||||
inline auto read(const stream& memory) -> void;
|
||||
|
||||
inline auto write_protect(bool status) -> void;
|
||||
inline auto data() -> uint8*;
|
||||
inline auto size() const -> unsigned;
|
||||
inline auto size() const -> uint;
|
||||
|
||||
inline auto read(unsigned addr) -> uint8;
|
||||
inline auto write(unsigned addr, uint8 n) -> void;
|
||||
inline auto operator[](unsigned addr) const -> const uint8&;
|
||||
inline auto read(uint addr, uint8 data = 0) -> uint8;
|
||||
inline auto write(uint addr, uint8 data) -> void;
|
||||
inline auto operator[](uint addr) const -> const uint8&;
|
||||
|
||||
private:
|
||||
uint8* data_ = nullptr;
|
||||
unsigned size_ = 0;
|
||||
uint size_ = 0;
|
||||
bool write_protect_ = false;
|
||||
};
|
||||
|
||||
struct Bus {
|
||||
alwaysinline static auto mirror(unsigned addr, unsigned size) -> unsigned;
|
||||
alwaysinline static auto reduce(unsigned addr, unsigned mask) -> unsigned;
|
||||
alwaysinline static auto mirror(uint addr, uint size) -> uint;
|
||||
alwaysinline static auto reduce(uint addr, uint mask) -> uint;
|
||||
|
||||
Bus();
|
||||
~Bus();
|
||||
|
||||
alwaysinline auto read(unsigned addr) -> uint8;
|
||||
alwaysinline auto write(unsigned addr, uint8 data) -> void;
|
||||
alwaysinline auto read(uint addr, uint8 data) -> uint8;
|
||||
alwaysinline auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
auto reset() -> void;
|
||||
auto map() -> void;
|
||||
auto map(
|
||||
const function<uint8 (unsigned)>& reader,
|
||||
const function<void (unsigned, uint8)>& writer,
|
||||
unsigned banklo, unsigned bankhi,
|
||||
unsigned addrlo, unsigned addrhi,
|
||||
unsigned size = 0, unsigned base = 0, unsigned mask = 0
|
||||
const function<uint8 (uint, uint8)>& reader,
|
||||
const function<void (uint, uint8)>& writer,
|
||||
uint banklo, uint bankhi, uint addrlo, uint addrhi,
|
||||
uint size = 0, uint base = 0, uint mask = 0
|
||||
) -> void;
|
||||
|
||||
uint8* lookup = nullptr;
|
||||
uint32* target = nullptr;
|
||||
|
||||
unsigned idcount = 0;
|
||||
function<uint8 (unsigned)> reader[256];
|
||||
function<void (unsigned, uint8)> writer[256];
|
||||
uint idcount = 0;
|
||||
function<auto (uint, uint8) -> uint8> reader[256];
|
||||
function<auto (uint, uint8) -> void> writer[256];
|
||||
};
|
||||
|
||||
extern Bus bus;
|
||||
|
|
|
@ -788,7 +788,7 @@ auto PPU::mmio_reset() -> void {
|
|||
regs.vcounter = 0;
|
||||
}
|
||||
|
||||
auto PPU::mmio_read(uint addr) -> uint8 {
|
||||
auto PPU::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||
cpu.synchronizePPU();
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
|
@ -824,7 +824,7 @@ auto PPU::mmio_read(uint addr) -> uint8 {
|
|||
case 0x213f: return mmio_r213f(); //STAT78
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto PPU::mmio_write(uint addr, uint8 data) -> void {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
public:
|
||||
auto mmio_read(uint addr) -> uint8;
|
||||
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||
auto mmio_write(uint addr, uint8 data) -> void;
|
||||
|
||||
privileged:
|
||||
|
|
|
@ -94,8 +94,8 @@ auto PPU::add_clocks(uint clocks) -> void {
|
|||
}
|
||||
|
||||
auto PPU::enable() -> void {
|
||||
function<uint8 (unsigned)> reader{&PPU::mmio_read, (PPU*)&ppu};
|
||||
function<void (unsigned, uint8)> writer{&PPU::mmio_write, (PPU*)&ppu};
|
||||
function<auto (uint, uint8) -> uint8> reader{&PPU::mmio_read, (PPU*)&ppu};
|
||||
function<auto (uint, uint8) -> void> writer{&PPU::mmio_write, (PPU*)&ppu};
|
||||
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||
|
|
|
@ -31,12 +31,12 @@ auto SatellaviewCartridge::reset() -> void {
|
|||
memory.write_protect(!regs.write_enable);
|
||||
}
|
||||
|
||||
auto SatellaviewCartridge::size() const -> unsigned {
|
||||
auto SatellaviewCartridge::size() const -> uint {
|
||||
return memory.size();
|
||||
}
|
||||
|
||||
auto SatellaviewCartridge::read(unsigned addr) -> uint8 {
|
||||
if(readonly) return memory.read(bus.mirror(addr, memory.size()));
|
||||
auto SatellaviewCartridge::read(uint addr, uint8 data) -> uint8 {
|
||||
if(readonly) return memory.read(bus.mirror(addr, memory.size()), data);
|
||||
|
||||
if(addr == 0x0002) {
|
||||
if(regs.flash_enable) return 0x80;
|
||||
|
@ -61,10 +61,10 @@ auto SatellaviewCartridge::read(unsigned addr) -> uint8 {
|
|||
}
|
||||
}
|
||||
|
||||
return memory.read(addr);
|
||||
return memory.read(addr, data);
|
||||
}
|
||||
|
||||
auto SatellaviewCartridge::write(unsigned addr, uint8 data) -> void {
|
||||
auto SatellaviewCartridge::write(uint addr, uint8 data) -> void {
|
||||
if(readonly) return;
|
||||
|
||||
if((addr & 0xff0000) == 0) {
|
||||
|
|
|
@ -5,16 +5,16 @@ struct SatellaviewCartridge : Memory {
|
|||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto size() const -> unsigned;
|
||||
auto read(unsigned addr) -> uint8;
|
||||
auto write(unsigned addr, uint8 data) -> void;
|
||||
auto size() const -> uint;
|
||||
auto read(uint addr, uint8) -> uint8;
|
||||
auto write(uint addr, uint8 data) -> void;
|
||||
|
||||
MappedRAM memory;
|
||||
bool readonly;
|
||||
|
||||
private:
|
||||
struct {
|
||||
unsigned command;
|
||||
uint command;
|
||||
uint8 write_old;
|
||||
uint8 write_new;
|
||||
|
||||
|
|
Loading…
Reference in New Issue