diff --git a/.travis.yml b/.travis.yml index 82072d146a..6cd994d026 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ matrix: - clang-3.8 env: COMPILER_NAME=clang-3.8 CXX=clang++-3.8 CC=clang-3.8 - os: osx - osx_image: xcode7.3 + osx_image: xcode8 script: - xcodebuild -target RetroArch -configuration Release -project pkg/apple/RetroArch.xcodeproj - os: osx diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 2e6b11d97a..eec6a8bb70 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -29,7 +29,9 @@ "includePath": [ "/usr/include", "/usr/local/include", - "${workspaceRoot}" + "${workspaceRoot}", + "${workspaceFolder}/libretro-common/include", + "${workspaceRoot}/libretro-common/include" ], "defines": [], "intelliSenseMode": "clang-x64", @@ -50,7 +52,8 @@ "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt", "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared", "C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt", - "${workspaceRoot}" + "${workspaceRoot}", + "${workspaceFolder}/libretro-common/include" ], "defines": [ "_DEBUG", diff --git a/.vscode/settings.json b/.vscode/settings.json index 148f4b83ea..c44832dca4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,7 @@ "terminal.integrated.cursorBlinking": true, "editor.tabSize": 3, + "editor.detectIndentation": false, "editor.renderWhitespace": "all", "editor.insertSpaces": true, "files.associations": { @@ -22,7 +23,24 @@ "ios": "c", "list": "c", "input_driver.h": "c", - "video_driver.h": "c" + "video_driver.h": "c", + "menu_driver.h": "c", + "file_path.h": "c", + "unordered_map": "c", + "unordered_set": "c", + "sstream": "cpp", + "hash_map": "c", + "hash_set": "c", + "initializer_list": "c", + "string_view": "c", + "utility": "c", + "menu_input.h": "c", + "tasks_internal.h": "c", + "ozone.h": "c", + "ozone_theme.h": "c", + "ozone_texture.h": "c", + "string_list.h": "c", + "core_info.h": "c" }, "C_Cpp.dimInactiveRegions": false, } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b271c66e8f..a90e515b1b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,12 +4,49 @@ "version": "2.0.0", "tasks": [ { - "taskName": "msys2-mingw64 build", + "label": "linux clean build", + "type": "shell", + "group": "build", + "command": "make clean && ./configure && make -j12" + }, + { + "label": "linux clean", + "type": "shell", + "group": "build", + "command": "make clean" + }, + { + "label": "linux build with debug symbols", + "type": "shell", + "group": "build", + "command": "DEBUG=1 make -j12" + }, + { + "label": "linux build", + "type": "shell", + "group": "build", + "command": "make -j12" + }, + { + "label": "linux build and run", + "type": "shell", + "group": "build", + "command": "make -j12 && ./retroarch -v" + }, + { + "label": "linux build and run with debug symbols", + "type": "shell", + "group": "build", + "command": "DEBUG=1 make -j12 && ./retroarch -v" + }, + { + "label": "msys2-mingw64 build", "type": "shell", "group": { "kind": "build", - "isDefault": true }, + "isDefault": true + }, "command": "./configure; make -j2", "options": { @@ -20,9 +57,9 @@ ] } } - } + }, { - "taskName": "msys2-mingw64 build with debug symbols", + "label": "msys2-mingw64 build with debug symbols", "type": "shell", "group": "build", @@ -36,9 +73,9 @@ ] } } - } + }, { - "taskName": "msys2-mingw64 rebuild", + "label": "msys2-mingw64 rebuild", "type": "shell", "group": "build", @@ -52,9 +89,9 @@ ] } } - } + }, { - "taskName": "msys2-mingw64 clean", + "label": "msys2-mingw64 clean", "type": "shell", "group": "build", @@ -68,9 +105,9 @@ ] } } - } + }, { - "taskName": "msys2-mingw64 run", + "label": "msys2-mingw64 run", "type": "shell", "group": { diff --git a/CHANGES.md b/CHANGES.md index 6aaebd3bde..2621139e06 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,13 +1,21 @@ # 1.7.6 (future) +- CPU FILTERS: Add Normal2x filter. - DATE: Add Date / Time style options. - MIDI: Add a Linux ALSA driver for MIDI. +- LOCALIZATION: Add Greek translation. - LOCALIZATION: Update German translation. - LOCALIZATION: Update Italian translation. - LOCALIZATION: Update Simplified Chinese translation. - LOCALIZATION: Update Japanese translation. +- MENU: Only show CRT SwitchRes if video display server is implemented (Windows/Linux for now) +- MENU: User Interface -> Appearance -> 'Menu Font Green/Blue Color' settings now work properly. - SCANNER: Fix GDI disc scanning. - SWITCH/LIBNX: Improve touch scaling calculation. - SWITCH: Proper button labels. +- VULKAN: Fix RGUI crashing at startup. +- VULKAN: Fix secondary screens in overlays not working. +- WINDOWS/WSA: Network Information info is blank until first network operation. +- WIIU: Initial netplay peer-to-peer support. Network information working. # 1.7.5 - CAMERA: Fix Video4Linux2 driver that broke years ago. diff --git a/Makefile.classic_armv7_a7 b/Makefile.classic_armv7_a7 new file mode 100644 index 0000000000..34dc715cb5 --- /dev/null +++ b/Makefile.classic_armv7_a7 @@ -0,0 +1,110 @@ +# This build was put together and is maintained by ModMyClassic.com for Libretro. +# The purpose is to give Libretro a proper "official" build platform for classic consoles. +# If you need any help in building for the classics or have any questions then please visit +# https://modmyclassic.com/comp and we will help in any way possible! + +# Building Prerequisites ############## +# arm-linux-gnueabihf-gcc-8 +# arm-linux-gnueabihf-g++-8 +# arm-linux-gnueabihf-as +# arm-linux-gnueabihf-strip +# patchelf +# bc + +# Classic Readme Variables ############ +CLASSIC_MODS_VER := Official_Retroarch_v1_7_5c_COptimised +CLASSIC_MODS_NAME := RetroArch v1.7.5c (Official Classic Optimised) +CLASSIC_VERSION := 1.7.5c \(Classic+\) +MOD_CREATOR := Libretro + ModMyClassic +MOD_CATEGORY := RetroArch +GIT_COMMIT := $(shell echo "`git rev-parse --short HEAD``git diff-index --quiet HEAD -- || echo '-dirty'`") + +# Platform dependant Variables ######## +HAKCHI_DIR := RA_Platform-Hakchi +HAKCHI_GIT := https://github.com/Classicmods/RA_Platform-Hakchi + +# General Shared Variables ############ +TARGET := retroarch +CC_V = arm-linux-gnueabihf-gcc-8 +CXX_V = arm-linux-gnueabihf-g++-8 +AS_V = arm-linux-gnueabihf-as +CC_AS_V = arm-linux-gnueabihf-gcc-8 + +# Libretro Defines #################### +#HAVE_CLASSIC = Classic Hook, disable some features +#HAVE_C_A7A7 = Classic Armv7 Cortex A7 optimisation override +#HAVE_HAKCHI = Hakchi Hook, change default configurations etc (TODO) + +all: $(TARGET) + +retroarch: + #Backup vanilla version files + ammend version + cp version.all version_BACKUP.all && cp version.dtd version_BACKUP.dtd + sed -i -e 's/RARCH_VERSION="[^"]*"/RARCH_VERSION="$(CLASSIC_VERSION)"/g' version.all + sed -i -e 's/PACKAGE_VERSION "[^"]*"/PACKAGE_VERSION "$(CLASSIC_VERSION)"/g' version.all + sed -i -e 's/ENTITY version "[^"]*"/ENTITY version "$(CLASSIC_VERSION)"/g' version.dtd + #Build the RetroArch Binary for cross platform classics (ARMv7 Cortex A7) + patchelf --version #Check if you have patchelf installed... (sudo apt-get install patchelf) + ./configure --host=arm-linux-gnueabihf --enable-mali_fbdev --disable-freetype --enable-opengles --enable-udev --enable-alsa --enable-neon --enable-floathard --disable-discord + make CC=$(CC_V) CXX=$(CXX_V) AS=$(AS_V) CC_AS=$(CC_AS_V) LDFLAGS_SDL=-lSDL2 HAVE_CLASSIC=1 HAVE_C_A7A7=1 HAVE_HAKCHI=1 -j #Cook it + arm-linux-gnueabihf-strip -v retroarch + patchelf --replace-needed libSDL2-2.0.so.0 libSDL2.so retroarch #libSDL2-2.0.so.0 sym link doesn't exist on native build. Just patch the binary... + + #HAKCHI BUILD (NESC, SNESC) + #FYI this build was originally known as RetroArch 'Neo' for Hakchi. + @echo "** BUILDING CLASSIC_MODS HAKCHI - $(CLASSIC_MODS_VER) HMOD PACKAGE **" + rm -fr /tmp/$(HAKCHI_DIR) + cd /tmp/; git clone $(HAKCHI_GIT) + cp retroarch /tmp/$(HAKCHI_DIR)/bin/retroarch + echo $$(echo "Built by: " $$USER @ $$(date) \\\\\\ Git Commit: $(GIT_COMMIT)) > /tmp/$(HAKCHI_DIR)/etc/libretro/retroarch_version + cp /tmp/$(HAKCHI_DIR)/readme.md /tmp/$(HAKCHI_DIR)/readme_COPY.md + printf "%s\n" \ + "---" \ + "Name: $(CLASSIC_MODS_NAME)" \ + "Creator: $(MOD_CREATOR)" \ + "Category: $(MOD_CATEGORY)" \ + "Version: $(CLASSIC_MODS_VER)" \ + "Built on: $(shell date)" \ + "Git commit: $(GIT_COMMIT)" \ + "---" > /tmp/$(HAKCHI_DIR)/readme.md + cat /tmp/$(HAKCHI_DIR)/readme_COPY.md >> /tmp/$(HAKCHI_DIR)/readme.md + rm /tmp/$(HAKCHI_DIR)/readme_COPY.md + @echo "** COMPRESSING $(CLASSIC_MODS_VER) HMOD PACKAGE **" + cd /tmp/$(HAKCHI_DIR)/; tar -czvf "$(CLASSIC_MODS_VER).hmod" * + mv /tmp/$(HAKCHI_DIR)/$(CLASSIC_MODS_VER).hmod . + @echo "** BUILT CLASSIC_MODS HAKCHI - $(CLASSIC_MODS_VER) HMOD PACKAGE **" + rm -fr /tmp/$(HAKCHI_DIR) #clean up tmp + + #COMMODORE 64 MINI BUILD (WIP) + + #Clean down dirty files + rm -f version.all version.dtd + mv version_BACKUP.all version.all && mv version_BACKUP.dtd version.dtd + @echo "*********************************************************************" + @echo "*** Classic ARM7 Cortex A7 build and packages built successfully! ***" + @echo "****************** Winner, Winner, Chicken Dinner! ******************" + @echo "*********************************************************************" +clean: + rm -rf obj-unix + rm -f *.d + rm -f *.o + rm -f audio/*.o + rm -f conf/*.o + rm -f gfx/*.o + rm -f gfx/drivers_font/*.o + rm -f gfx/drivers_font_renderer/*.o + rm -f gfx/drivers_context/*.o + rm -f gfx/py_state/*.o + rm -f compat/*.o + rm -f record/*.o + rm -f input/*.o + rm -f tools/*.o + rm -f $(BINDIR)/retroarch + rm -f $(BINDIR)/retroarch-joyconfig + rm -f $(PNDDIR)/readme.html + rm -f retroarch + rm -f $(CLASSIC_MODS_VER).hmod + rm -f version.all version.dtd + mv -f version_BACKUP.all version.all || echo "Backup Doesn't Exist - Ignoring..." + mv -f version_BACKUP.dtd version.dtd || echo "Backup Doesn't Exist - Ignoring..." + rm -f *_BACKUP* diff --git a/Makefile.common b/Makefile.common index bc1ea2b9f9..ae3d10b3e4 100644 --- a/Makefile.common +++ b/Makefile.common @@ -4,11 +4,7 @@ LIBRETRO_COMM_DIR := $(ROOT_DIR)/libretro-common WANT_WGL = 0 ifeq ($(HAVE_STACK_USAGE), 1) -CFLAGS += -fstack-usage -endif - -ifeq ($(HAVE_HAKCHI), 1) -CFLAGS += -DHAVE_HAKCHI + CFLAGS += -fstack-usage endif ifeq ($(HAVE_GL_CONTEXT),) @@ -32,16 +28,16 @@ ifeq ($(HAVE_LIBRETRODB),) endif ifeq ($(HAVE_VIDEO_PROCESSOR), 1) - DEFINES += -DHAVE_VIDEO_PROCESSOR + DEFINES += -DHAVE_VIDEO_PROCESSOR endif ifeq ($(HAVE_MENU), 1) - DEFINES += -DHAVE_MENU - HAVE_MENU_COMMON = 1 + DEFINES += -DHAVE_MENU + HAVE_MENU_COMMON = 1 endif ifeq ($(HAVE_SOCKET_LEGACY), 1) - DEFINES += -DHAVE_SOCKET_LEGACY + DEFINES += -DHAVE_SOCKET_LEGACY endif ifeq ($(HAVE_HID), 1) @@ -53,7 +49,7 @@ ifeq ($(HAVE_LIBRETRODB), 1) endif ifeq ($(HAVE_VITA2D), 1) - DEFINES += -DHAVE_VITA2D + DEFINES += -DHAVE_VITA2D endif ifeq ($(HAVE_DYLIB), 1) @@ -64,7 +60,6 @@ ifeq ($(SCALER_NO_SIMD), 1) DEFINES += -DSCALER_NO_SIMD endif - ifeq ($(HAVE_PRESERVE_DYLIB),1) DEFINES += -DNO_DLCLOSE endif @@ -98,6 +93,10 @@ endif CFLAGS += -I$(LIBRETRO_COMM_DIR)/include -I$(DEPS_DIR) # Switches +# +ifeq ($(HAVE_NETPLAYDISCOVERY), 1) + CFLAGS += -DHAVE_NETPLAYDISCOVERY +endif ifeq ($(HAVE_NETLOGGER), 1) CFLAGS += -DHAVE_LOGGER @@ -109,7 +108,7 @@ endif ifneq ($(findstring BSD,$(OS)),) BSD_LOCAL_INC += -I/usr/local/include - HAVE_UNIX = 1 + HAVE_UNIX = 1 endif ifneq ($(findstring Darwin,$(OS)),) @@ -121,7 +120,7 @@ endif ifneq ($(findstring Haiku,$(OS)),) LIBS += -lroot -lnetwork - HAVE_UNIX = 1 + HAVE_UNIX = 1 else LIBS += -lm endif @@ -131,15 +130,15 @@ ifneq ($(findstring Linux,$(OS)),) OBJ += input/drivers/linuxraw_input.o \ input/common/linux_common.o \ input/drivers_joypad/linuxraw_joypad.o - HAVE_UNIX = 1 + HAVE_UNIX = 1 endif ifeq ($(HAVE_UNIX), 1) - OBJ += frontend/drivers/platform_unix.o + OBJ += frontend/drivers/platform_unix.o endif ifeq ($(TARGET), retroarch_3ds) - OBJ += frontend/drivers/platform_ctr.o + OBJ += frontend/drivers/platform_ctr.o endif # Git @@ -165,8 +164,8 @@ OBJ += frontend/frontend.o \ ui/drivers/null/ui_null_application.o \ core_impl.o \ retroarch.o \ - dirs.o \ - paths.o \ + dirs.o \ + paths.o \ command.o \ msg_hash.o \ intl/msg_hash_us.o \ @@ -191,7 +190,7 @@ OBJ += frontend/frontend.o \ $(LIBRETRO_COMM_DIR)/lists/string_list.o \ $(LIBRETRO_COMM_DIR)/string/stdstring.o \ $(LIBRETRO_COMM_DIR)/memmap/memalign.o \ - setting_list.o \ + setting_list.o \ list_special.o \ $(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.o \ $(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.o \ @@ -206,13 +205,13 @@ OBJ += frontend/frontend.o \ $(LIBRETRO_COMM_DIR)/audio/audio_mixer.o \ input/common/input_common.o \ input/input_driver.o \ - input/input_mapper.o \ + input/input_mapper.o \ led/led_driver.o \ led/drivers/led_null.o \ gfx/video_coord_array.o \ gfx/video_display_server.o \ gfx/video_driver.o \ - gfx/video_crt_switch.o \ + gfx/video_crt_switch.o \ camera/camera_driver.o \ wifi/wifi_driver.o \ location/location_driver.o \ @@ -222,11 +221,11 @@ OBJ += frontend/frontend.o \ dynamic.o \ cores/dynamic_dummy.o \ $(LIBRETRO_COMM_DIR)/queues/message_queue.o \ - managers/core_manager.o \ + managers/core_manager.o \ managers/state_manager.o \ gfx/drivers_font_renderer/bitmapfont.o \ tasks/task_autodetect.o \ - input/input_autodetect_builtin.o \ + input/input_autodetect_builtin.o \ input/input_keymaps.o \ input/input_remapping.o \ $(LIBRETRO_COMM_DIR)/queues/fifo_queue.o \ @@ -252,7 +251,7 @@ OBJ += frontend/frontend.o \ $(LIBRETRO_COMM_DIR)/audio/resampler/drivers/sinc_resampler.o \ $(LIBRETRO_COMM_DIR)/audio/resampler/drivers/nearest_resampler.o \ $(LIBRETRO_COMM_DIR)/audio/resampler/drivers/null_resampler.o \ - $(LIBRETRO_COMM_DIR)/utils/md5.o \ + $(LIBRETRO_COMM_DIR)/utils/md5.o \ location/drivers/nulllocation.o \ camera/drivers/nullcamera.o \ wifi/drivers/nullwifi.o \ @@ -273,220 +272,218 @@ OBJ += frontend/frontend.o \ midi/drivers/null_midi.o ifeq ($(HAVE_RUNAHEAD), 1) -DEFINES += -DHAVE_RUNAHEAD -OBJ += runahead/copy_load_info.o \ - runahead/dirty_input.o \ - runahead/mem_util.o \ - runahead/mylist.o \ - runahead/run_ahead.o \ - runahead/secondary_core.o + DEFINES += -DHAVE_RUNAHEAD + OBJ += runahead/copy_load_info.o \ + runahead/dirty_input.o \ + runahead/mem_util.o \ + runahead/mylist.o \ + runahead/run_ahead.o \ + runahead/secondary_core.o endif - - ifeq ($(HAVE_CC_RESAMPLER), 1) -DEFINES += -DHAVE_CC_RESAMPLER -OBJ += audio/drivers_resampler/cc_resampler.o + DEFINES += -DHAVE_CC_RESAMPLER + OBJ += audio/drivers_resampler/cc_resampler.o endif ifeq ($(HAVE_LANGEXTRA), 1) -DEFINES += -DHAVE_LANGEXTRA -DEFINES += -finput-charset=UTF-8 - -OBJ += intl/msg_hash_de.o \ - intl/msg_hash_eo.o \ - intl/msg_hash_es.o \ - intl/msg_hash_fr.o \ - intl/msg_hash_it.o \ - intl/msg_hash_ja.o \ - intl/msg_hash_ko.o \ - intl/msg_hash_nl.o \ - intl/msg_hash_pl.o \ - intl/msg_hash_pt_br.o \ - intl/msg_hash_pt_pt.o \ - intl/msg_hash_ru.o \ - intl/msg_hash_vn.o \ - intl/msg_hash_chs.o \ - intl/msg_hash_cht.o \ - intl/msg_hash_ar.o + DEFINES += -DHAVE_LANGEXTRA + DEFINES += -finput-charset=UTF-8 + OBJ += intl/msg_hash_de.o \ + intl/msg_hash_eo.o \ + intl/msg_hash_es.o \ + intl/msg_hash_fr.o \ + intl/msg_hash_it.o \ + intl/msg_hash_ja.o \ + intl/msg_hash_ko.o \ + intl/msg_hash_nl.o \ + intl/msg_hash_pl.o \ + intl/msg_hash_pt_br.o \ + intl/msg_hash_pt_pt.o \ + intl/msg_hash_ru.o \ + intl/msg_hash_vn.o \ + intl/msg_hash_chs.o \ + intl/msg_hash_cht.o \ + intl/msg_hash_ar.o \ + intl/msg_hash_el.o endif ifneq ($(HAVE_GETOPT_LONG), 1) -OBJ += $(LIBRETRO_COMM_DIR)/compat/compat_getopt.o + OBJ += $(LIBRETRO_COMM_DIR)/compat/compat_getopt.o endif ifneq ($(HAVE_STRCASESTR), 1) -OBJ += $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.o + OBJ += $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.o endif ifneq ($(HAVE_STRL), 1) -OBJ += $(LIBRETRO_COMM_DIR)/compat/compat_strl.o + OBJ += $(LIBRETRO_COMM_DIR)/compat/compat_strl.o endif OBJ += $(LIBRETRO_COMM_DIR)/formats/image_texture.o ifeq ($(HAVE_IMAGEVIEWER), 1) -DEFINES += -DHAVE_IMAGEVIEWER -OBJ += cores/libretro-imageviewer/image_core.o + DEFINES += -DHAVE_IMAGEVIEWER + OBJ += cores/libretro-imageviewer/image_core.o endif # Qt WIMP GUI ifeq ($(HAVE_OPENSSL), 1) -DEFINES += $(OPENSSL_CFLAGS) -LIBS += $(OPENSSL_LIBS) + DEFINES += $(OPENSSL_CFLAGS) + LIBS += $(OPENSSL_LIBS) endif ifeq ($(HAVE_QT), 1) -OBJ += ui/drivers/ui_qt.o \ - ui/drivers/qt/ui_qt_application.o \ - ui/drivers/qt/ui_qt_window.o \ - ui/drivers/qt/ui_qt_browser_window.o \ - ui/drivers/qt/ui_qt_load_core_window.o \ - ui/drivers/qt/ui_qt_msg_window.o \ - ui/drivers/qt/flowlayout.o \ - ui/drivers/qt/shaderparamsdialog.o \ - ui/drivers/qt/coreoptionsdialog.o \ - ui/drivers/qt/filedropwidget.o \ - ui/drivers/qt/coreinfodialog.o \ - ui/drivers/qt/playlistentrydialog.o \ - ui/drivers/qt/viewoptionsdialog.o \ - ui/drivers/qt/playlist.o \ - ui/drivers/qt/updateretroarch.o \ - ui/drivers/qt/thumbnaildownload.o \ - ui/drivers/qt/thumbnailpackdownload.o \ - ui/drivers/qt/playlistthumbnaildownload.o + OBJ += ui/drivers/ui_qt.o \ + ui/drivers/qt/ui_qt_application.o \ + ui/drivers/qt/ui_qt_window.o \ + ui/drivers/qt/ui_qt_browser_window.o \ + ui/drivers/qt/ui_qt_load_core_window.o \ + ui/drivers/qt/ui_qt_msg_window.o \ + ui/drivers/qt/flowlayout.o \ + ui/drivers/qt/shaderparamsdialog.o \ + ui/drivers/qt/coreoptionsdialog.o \ + ui/drivers/qt/filedropwidget.o \ + ui/drivers/qt/coreinfodialog.o \ + ui/drivers/qt/playlistentrydialog.o \ + ui/drivers/qt/viewoptionsdialog.o \ + ui/drivers/qt/playlist.o \ + ui/drivers/qt/updateretroarch.o \ + ui/drivers/qt/thumbnaildownload.o \ + ui/drivers/qt/thumbnailpackdownload.o \ + ui/drivers/qt/playlistthumbnaildownload.o -MOC_HEADERS += ui/drivers/ui_qt.h \ - ui/drivers/qt/ui_qt_load_core_window.h \ - ui/drivers/qt/flowlayout.h \ - ui/drivers/qt/shaderparamsdialog.h \ - ui/drivers/qt/coreoptionsdialog.h \ - ui/drivers/qt/filedropwidget.h \ - ui/drivers/qt/coreinfodialog.h \ - ui/drivers/qt/playlistentrydialog.h \ - ui/drivers/qt/viewoptionsdialog.h + MOC_HEADERS += ui/drivers/ui_qt.h \ + ui/drivers/qt/ui_qt_load_core_window.h \ + ui/drivers/qt/flowlayout.h \ + ui/drivers/qt/shaderparamsdialog.h \ + ui/drivers/qt/coreoptionsdialog.h \ + ui/drivers/qt/filedropwidget.h \ + ui/drivers/qt/coreinfodialog.h \ + ui/drivers/qt/playlistentrydialog.h \ + ui/drivers/qt/viewoptionsdialog.h -DEFINES += $(QT5CORE_CFLAGS) $(QT5GUI_CFLAGS) $(QT5WIDGETS_CFLAGS) $(QT5CONCURRENT_CFLAGS) $(QT5NETWORK_CFLAGS) -DHAVE_MAIN -#DEFINES += $(QT5WEBENGINE_CFLAGS) -LIBS += $(QT5CORE_LIBS) $(QT5GUI_LIBS) $(QT5WIDGETS_LIBS) $(QT5CONCURRENT_LIBS) $(QT5NETWORK_LIBS) -#LIBS += $(QT5WEBENGINE_LIBS) -NEED_CXX_LINKER = 1 + DEFINES += $(QT5CORE_CFLAGS) $(QT5GUI_CFLAGS) $(QT5WIDGETS_CFLAGS) $(QT5CONCURRENT_CFLAGS) $(QT5NETWORK_CFLAGS) -DHAVE_MAIN + #DEFINES += $(QT5WEBENGINE_CFLAGS) + LIBS += $(QT5CORE_LIBS) $(QT5GUI_LIBS) $(QT5WIDGETS_LIBS) $(QT5CONCURRENT_LIBS) $(QT5NETWORK_LIBS) + #LIBS += $(QT5WEBENGINE_LIBS) + NEED_CXX_LINKER = 1 -ifneq ($(findstring Linux,$(OS)),) -DEFINES += -fPIC -endif + ifneq ($(findstring Linux,$(OS)),) + DEFINES += -fPIC + endif endif ifeq ($(HAVE_SSA),1) -LIBS += $(SSA_LIBS) + LIBS += $(SSA_LIBS) endif # LibretroDB ifeq ($(HAVE_LIBRETRODB), 1) -OBJ += libretro-db/bintree.o \ - libretro-db/libretrodb.o \ - libretro-db/query.o \ - libretro-db/rmsgpack.o \ - libretro-db/rmsgpack_dom.o \ - database_info.o \ - tasks/task_database.o \ - tasks/task_database_cue.o + OBJ += libretro-db/bintree.o \ + libretro-db/libretrodb.o \ + libretro-db/query.o \ + libretro-db/rmsgpack.o \ + libretro-db/rmsgpack_dom.o \ + database_info.o \ + tasks/task_database.o \ + tasks/task_database_cue.o endif ifneq ($(C89_BUILD), 1) -HAVE_GTKPLUS = 0 + HAVE_GTKPLUS = 0 -ifeq ($(HAVE_SSL), 1) -ifeq ($(HAVE_NETWORKING), 1) -DEFINES += -DHAVE_SSL + ifeq ($(HAVE_SSL), 1) + ifeq ($(HAVE_NETWORKING), 1) + DEFINES += -DHAVE_SSL -ifeq ($(DEBUG), 1) - DEFINES += -DMBEDTLS_SSL_DEBUG_ALL -endif + ifeq ($(DEBUG), 1) + DEFINES += -DMBEDTLS_SSL_DEBUG_ALL + endif -# MinGW requires this for some reason, even though the include paths are relative to the source -INCLUDE_DIRS += -Ideps/mbedtls + # MinGW requires this for some reason, even though the include paths are relative to the source + INCLUDE_DIRS += -Ideps/mbedtls -OBJS_TLS_CRYPTO = deps/mbedtls/aes.o \ - deps/mbedtls/aesni.o \ - deps/mbedtls/arc4.o \ - deps/mbedtls/asn1parse.o \ - deps/mbedtls/asn1write.o \ - deps/mbedtls/base64.o \ - deps/mbedtls/bignum.o \ - deps/mbedtls/blowfish.o \ - deps/mbedtls/camellia.o \ - deps/mbedtls/ccm.o \ - deps/mbedtls/cipher.o \ - deps/mbedtls/cipher_wrap.o \ - deps/mbedtls/cmac.o \ - deps/mbedtls/ctr_drbg.o \ - deps/mbedtls/des.o \ - deps/mbedtls/dhm.o \ - deps/mbedtls/ecdh.o \ - deps/mbedtls/ecdsa.o \ - deps/mbedtls/ecjpake.o \ - deps/mbedtls/ecp.o \ - deps/mbedtls/ecp_curves.o \ - deps/mbedtls/entropy.o \ - deps/mbedtls/entropy_poll.o \ - deps/mbedtls/error.o \ - deps/mbedtls/gcm.o \ - deps/mbedtls/havege.o \ - deps/mbedtls/hmac_drbg.o \ - deps/mbedtls/md.o \ - deps/mbedtls/md2.o \ - deps/mbedtls/md4.o \ - deps/mbedtls/md5.o \ - deps/mbedtls/md_wrap.o \ - deps/mbedtls/memory_buffer_alloc.o \ - deps/mbedtls/oid.o \ - deps/mbedtls/padlock.o \ - deps/mbedtls/pem.o \ - deps/mbedtls/pk.o \ - deps/mbedtls/pk_wrap.o \ - deps/mbedtls/pkcs12.o \ - deps/mbedtls/pkcs5.o \ - deps/mbedtls/pkparse.o \ - deps/mbedtls/pkwrite.o \ - deps/mbedtls/platform.o \ - deps/mbedtls/ripemd160.o \ - deps/mbedtls/rsa.o \ - deps/mbedtls/sha1.o \ - deps/mbedtls/sha256.o \ - deps/mbedtls/sha512.o \ - deps/mbedtls/threading.o \ - deps/mbedtls/timing.o \ - deps/mbedtls/version.o \ - deps/mbedtls/version_features.o \ - deps/mbedtls/xtea.o + OBJS_TLS_CRYPTO = deps/mbedtls/aes.o \ + deps/mbedtls/aesni.o \ + deps/mbedtls/arc4.o \ + deps/mbedtls/asn1parse.o \ + deps/mbedtls/asn1write.o \ + deps/mbedtls/base64.o \ + deps/mbedtls/bignum.o \ + deps/mbedtls/blowfish.o \ + deps/mbedtls/camellia.o \ + deps/mbedtls/ccm.o \ + deps/mbedtls/cipher.o \ + deps/mbedtls/cipher_wrap.o \ + deps/mbedtls/cmac.o \ + deps/mbedtls/ctr_drbg.o \ + deps/mbedtls/des.o \ + deps/mbedtls/dhm.o \ + deps/mbedtls/ecdh.o \ + deps/mbedtls/ecdsa.o \ + deps/mbedtls/ecjpake.o \ + deps/mbedtls/ecp.o \ + deps/mbedtls/ecp_curves.o \ + deps/mbedtls/entropy.o \ + deps/mbedtls/entropy_poll.o \ + deps/mbedtls/error.o \ + deps/mbedtls/gcm.o \ + deps/mbedtls/havege.o \ + deps/mbedtls/hmac_drbg.o \ + deps/mbedtls/md.o \ + deps/mbedtls/md2.o \ + deps/mbedtls/md4.o \ + deps/mbedtls/md5.o \ + deps/mbedtls/md_wrap.o \ + deps/mbedtls/memory_buffer_alloc.o \ + deps/mbedtls/oid.o \ + deps/mbedtls/padlock.o \ + deps/mbedtls/pem.o \ + deps/mbedtls/pk.o \ + deps/mbedtls/pk_wrap.o \ + deps/mbedtls/pkcs12.o \ + deps/mbedtls/pkcs5.o \ + deps/mbedtls/pkparse.o \ + deps/mbedtls/pkwrite.o \ + deps/mbedtls/platform.o \ + deps/mbedtls/ripemd160.o \ + deps/mbedtls/rsa.o \ + deps/mbedtls/sha1.o \ + deps/mbedtls/sha256.o \ + deps/mbedtls/sha512.o \ + deps/mbedtls/threading.o \ + deps/mbedtls/timing.o \ + deps/mbedtls/version.o \ + deps/mbedtls/version_features.o \ + deps/mbedtls/xtea.o -OBJS_TLS_X509 = deps/mbedtls/certs.o \ - deps/mbedtls/pkcs11.o \ - deps/mbedtls/x509.o \ - deps/mbedtls/x509_create.o \ - deps/mbedtls/x509_crl.o \ - deps/mbedtls/x509_crt.o \ - deps/mbedtls/x509_csr.o \ - deps/mbedtls/x509write_crt.o \ - deps/mbedtls/x509write_csr.o + OBJS_TLS_X509 = deps/mbedtls/certs.o \ + deps/mbedtls/pkcs11.o \ + deps/mbedtls/x509.o \ + deps/mbedtls/x509_create.o \ + deps/mbedtls/x509_crl.o \ + deps/mbedtls/x509_crt.o \ + deps/mbedtls/x509_csr.o \ + deps/mbedtls/x509write_crt.o \ + deps/mbedtls/x509write_csr.o -OBJS_TLS = deps/mbedtls/debug.o \ - deps/mbedtls/net_sockets.o \ - deps/mbedtls/ssl_cache.o \ - deps/mbedtls/ssl_ciphersuites.o \ - deps/mbedtls/ssl_cli.o \ - deps/mbedtls/ssl_cookie.o \ - deps/mbedtls/ssl_srv.o \ - deps/mbedtls/ssl_ticket.o \ - deps/mbedtls/ssl_tls.o + OBJS_TLS = deps/mbedtls/debug.o \ + deps/mbedtls/net_sockets.o \ + deps/mbedtls/ssl_cache.o \ + deps/mbedtls/ssl_ciphersuites.o \ + deps/mbedtls/ssl_cli.o \ + deps/mbedtls/ssl_cookie.o \ + deps/mbedtls/ssl_srv.o \ + deps/mbedtls/ssl_ticket.o \ + deps/mbedtls/ssl_tls.o -OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS) -endif -endif + OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS) + endif + endif endif # Miscellaneous @@ -502,19 +499,19 @@ ifeq ($(HAVE_PYTHON), 1) endif ifeq ($(HAVE_EMSCRIPTEN), 1) -OBJ += frontend/drivers/platform_emscripten.o \ - input/drivers/rwebinput_input.o \ - input/drivers_joypad/rwebpad_joypad.o \ - audio/drivers/rwebaudio.o \ - camera/drivers/rwebcam.o + OBJ += frontend/drivers/platform_emscripten.o \ + input/drivers/rwebinput_input.o \ + input/drivers_joypad/rwebpad_joypad.o \ + audio/drivers/rwebaudio.o \ + camera/drivers/rwebcam.o endif ifeq ($(HAVE_LAKKA), 1) -OBJ += wifi/drivers/connmanctl.o + OBJ += wifi/drivers/connmanctl.o endif # Audio -# + ifeq ($(HAVE_COREAUDIO), 1) OBJ += audio/drivers/coreaudio.o LIBS += -framework CoreServices -framework CoreAudio -framework AudioUnit @@ -525,11 +522,11 @@ ifeq ($(HAVE_CORETEXT), 1) endif ifeq ($(TARGET), retroarch_3ds) - OBJ += gfx/drivers_font/ctr_font.o + OBJ += gfx/drivers_font/ctr_font.o endif ifeq ($(HAVE_LIBNX), 1) - OBJ += gfx/drivers_font/switch_font.o + OBJ += gfx/drivers_font/switch_font.o endif ifeq ($(HAVE_OSS), 1) @@ -539,24 +536,25 @@ else ifeq ($(HAVE_OSS_BSD), 1) endif ifeq ($(TARGET), retroarch_3ds) - OBJ += audio/drivers/ctr_csnd_audio.o \ - audio/drivers/ctr_dsp_audio.o + OBJ += audio/drivers/ctr_csnd_audio.o \ + audio/drivers/ctr_dsp_audio.o endif ifeq ($(HAVE_ALSA), 1) OBJ += audio/drivers/alsa.o OBJ += midi/drivers/alsa_midi.o -ifeq ($(HAVE_THREADS), 1) - OBJ += audio/drivers/alsathread.o -endif + ifeq ($(HAVE_THREADS), 1) + OBJ += audio/drivers/alsathread.o + endif + LIBS += $(ALSA_LIBS) DEFINES += $(ALSA_CFLAGS) endif ifeq ($(HAVE_TINYALSA), 1) - OBJ += audio/drivers/tinyalsa.o - DEFINES += -DHAVE_TINYALSA + OBJ += audio/drivers/tinyalsa.o + DEFINES += -DHAVE_TINYALSA endif ifeq ($(HAVE_ROAR), 1) @@ -603,7 +601,7 @@ endif ifeq ($(HAVE_DSOUND), 1) OBJ += audio/drivers/dsound.o DEFINES += -DHAVE_DSOUND - HAVE_DX_COMMON = 1 + HAVE_DX_COMMON = 1 LIBS += -ldsound endif @@ -631,13 +629,13 @@ ifeq ($(HAVE_NEON),1) OBJ += $(LIBRETRO_COMM_DIR)/audio/resampler/drivers/sinc_resampler_neon.o \ audio/drivers_resampler/cc_resampler_neon.o \ memory/neon/memcpy-neon.o - DEFINES += -DHAVE_NEON + DEFINES += -DHAVE_NEON endif OBJ += $(LIBRETRO_COMM_DIR)/audio/conversion/s16_to_float.o \ - $(LIBRETRO_COMM_DIR)/audio/conversion/float_to_s16.o \ - $(LIBRETRO_COMM_DIR)/audio/audio_mix.o \ - $(LIBRETRO_COMM_DIR)/formats/wav/rwav.o + $(LIBRETRO_COMM_DIR)/audio/conversion/float_to_s16.o \ + $(LIBRETRO_COMM_DIR)/audio/audio_mix.o \ + $(LIBRETRO_COMM_DIR)/formats/wav/rwav.o ifeq ($(HAVE_NEON),1) OBJ += $(LIBRETRO_COMM_DIR)/audio/conversion/s16_to_float_neon.o \ @@ -647,19 +645,19 @@ endif HW_CONTEXT_MENU_DRIVERS=$(HAVE_RGUI) ifeq ($(HW_CONTEXT_MENU_DRIVERS),0) -ifeq ($(HAVE_GL_CONTEXT),1) - HW_CONTEXT_MENU_DRIVERS=1 -endif -ifeq ($(HAVE_VULKAN),1) - HW_CONTEXT_MENU_DRIVERS=1 -endif + ifeq ($(HAVE_GL_CONTEXT),1) + HW_CONTEXT_MENU_DRIVERS=1 + endif + ifeq ($(HAVE_VULKAN),1) + HW_CONTEXT_MENU_DRIVERS=1 + endif endif # XMB and MaterialUI are always enabled if supported and not explicitly disabled ifeq ($(HW_CONTEXT_MENU_DRIVERS), 1) - ifeq ($(HAVE_ZARCH),) - HAVE_ZARCH = 1 - endif + #ifeq ($(HAVE_ZARCH),) + #HAVE_ZARCH = 1 + #endif ifeq ($(HAVE_MATERIALUI),) HAVE_MATERIALUI = 1 @@ -673,38 +671,42 @@ ifeq ($(HW_CONTEXT_MENU_DRIVERS), 1) HAVE_XMB = 1 endif - ifeq ($(HAVE_STRIPES),) - HAVE_STRIPES = 1 + #ifeq ($(HAVE_STRIPES),) + #HAVE_STRIPES = 1 + #endif + + ifeq ($(HAVE_OZONE),) + HAVE_OZONE = 1 endif else - HAVE_ZARCH ?= 0 + HAVE_ZARCH ?= 0 HAVE_MATERIALUI ?= 0 - #HAVE_NUKLEAR ?= 0 - HAVE_XMB ?= 0 - HAVE_STRIPES ?= 0 + HAVE_NUKLEAR ?= 0 + HAVE_XMB ?= 0 + HAVE_STRIPES ?= 0 + HAVE_OZONE ?= 0 endif ifeq ($(HAVE_RGUI), 1) OBJ += menu/drivers/rgui.o DEFINES += -DHAVE_MENU -DHAVE_RGUI HAVE_MENU_COMMON = 1 -ifeq ($(HAVE_MATERIALUI), 1) - OBJ += menu/drivers/materialui.o - DEFINES += -DHAVE_MATERIALUI - HAVE_MENU_COMMON = 1 -endif -ifeq ($(HAVE_NUKLEAR), 1) - OBJ += menu/drivers/nuklear/nk_common.o - OBJ += menu/drivers/nuklear/nk_menu.o - OBJ += menu/drivers/nuklear/nk_wnd_debug.o - OBJ += menu/drivers/nuklear.o - DEFINES += -DHAVE_NUKLEAR -endif -ifeq ($(HAVE_ZARCH), 1) - OBJ += menu/drivers/zarch.o - DEFINES += -DHAVE_ZARCH -endif - + ifeq ($(HAVE_MATERIALUI), 1) + OBJ += menu/drivers/materialui.o + DEFINES += -DHAVE_MATERIALUI + HAVE_MENU_COMMON = 1 + endif + ifeq ($(HAVE_NUKLEAR), 1) + OBJ += menu/drivers/nuklear/nk_common.o + OBJ += menu/drivers/nuklear/nk_menu.o + OBJ += menu/drivers/nuklear/nk_wnd_debug.o + OBJ += menu/drivers/nuklear.o + DEFINES += -DHAVE_NUKLEAR + endif + ifeq ($(HAVE_ZARCH), 1) + OBJ += menu/drivers/zarch.o + DEFINES += -DHAVE_ZARCH + endif endif ifeq ($(HAVE_XMB), 1) @@ -713,6 +715,17 @@ ifeq ($(HAVE_XMB), 1) HAVE_MENU_COMMON = 1 endif +ifeq ($(HAVE_OZONE), 1) + OBJ += menu/drivers/ozone/ozone.o + OBJ += menu/drivers/ozone/ozone_entries.o + OBJ += menu/drivers/ozone/ozone_display.o + OBJ += menu/drivers/ozone/ozone_texture.o + OBJ += menu/drivers/ozone/ozone_theme.o + OBJ += menu/drivers/ozone/ozone_sidebar.o + DEFINES += -DHAVE_OZONE + HAVE_MENU_COMMON = 1 +endif + ifeq ($(HAVE_STRIPES), 1) OBJ += menu/drivers/stripes.o DEFINES += -DHAVE_STRIPES @@ -734,12 +747,12 @@ ifeq ($(HAVE_MENU_COMMON), 1) menu/menu_setting.o \ menu/menu_networking.o \ menu/menu_shader.o \ - menu/widgets/menu_filebrowser.o \ - menu/widgets/menu_dialog.o \ - menu/widgets/menu_input_dialog.o \ - menu/widgets/menu_input_bind_dialog.o \ + menu/widgets/menu_filebrowser.o \ + menu/widgets/menu_dialog.o \ + menu/widgets/menu_input_dialog.o \ + menu/widgets/menu_input_bind_dialog.o \ menu/widgets/menu_entry.o \ - menu/widgets/menu_osk.o \ + menu/widgets/menu_osk.o \ menu/menu_cbs.o \ menu/cbs/menu_cbs_ok.o \ menu/cbs/menu_cbs_cancel.o \ @@ -767,8 +780,7 @@ endif ifeq ($(HAVE_OVERLAY), 1) DEFINES += -DHAVE_OVERLAY - OBJ += \ - tasks/task_overlay.o \ + OBJ += tasks/task_overlay.o \ input/input_overlay.o \ led/drivers/led_overlay.o endif @@ -800,70 +812,70 @@ ifeq ($(HAVE_THREAD_STORAGE), 1) endif ifeq ($(HAVE_VITA2D), 1) - OBJ += $(DEPS_DIR)/libvita2d/source/vita2d.o \ - $(DEPS_DIR)/libvita2d/source/vita2d_texture.o \ - $(DEPS_DIR)/libvita2d/source/vita2d_draw.o \ - $(DEPS_DIR)/libvita2d/source/utils.o + OBJ += $(DEPS_DIR)/libvita2d/source/vita2d.o \ + $(DEPS_DIR)/libvita2d/source/vita2d_texture.o \ + $(DEPS_DIR)/libvita2d/source/vita2d_draw.o \ + $(DEPS_DIR)/libvita2d/source/utils.o - OBJ += $(DEPS_DIR)/libvita2d/shader/clear_v_gxp.o \ - $(DEPS_DIR)/libvita2d/shader/clear_f_gxp.o \ - $(DEPS_DIR)/libvita2d/shader/color_v_gxp.o \ - $(DEPS_DIR)/libvita2d/shader/color_f_gxp.o \ - $(DEPS_DIR)/libvita2d/shader/texture_v_gxp.o \ - $(DEPS_DIR)/libvita2d/shader/texture_f_gxp.o \ - $(DEPS_DIR)/libvita2d/shader/texture_tint_f_gxp.o + OBJ += $(DEPS_DIR)/libvita2d/shader/clear_v_gxp.o \ + $(DEPS_DIR)/libvita2d/shader/clear_f_gxp.o \ + $(DEPS_DIR)/libvita2d/shader/color_v_gxp.o \ + $(DEPS_DIR)/libvita2d/shader/color_f_gxp.o \ + $(DEPS_DIR)/libvita2d/shader/texture_v_gxp.o \ + $(DEPS_DIR)/libvita2d/shader/texture_f_gxp.o \ + $(DEPS_DIR)/libvita2d/shader/texture_tint_f_gxp.o -ifeq ($(HAVE_MENU),1) - OBJ += menu/drivers_display/menu_display_vita2d.o -endif + ifeq ($(HAVE_MENU),1) + OBJ += menu/drivers_display/menu_display_vita2d.o + endif - OBJ += gfx/drivers/vita2d_gfx.o \ - gfx/drivers_font/vita2d_font.o + OBJ += gfx/drivers/vita2d_gfx.o \ + gfx/drivers_font/vita2d_font.o - CFLAGS += -I$(DEPS_DIR)/libvita2d/include + CFLAGS += -I$(DEPS_DIR)/libvita2d/include endif ifeq ($(TARGET), retroarch_3ds) - OBJ += gfx/drivers/ctr_gfx.o \ - menu/drivers_display/menu_display_ctr.o \ - input/drivers/ctr_input.o \ - input/drivers_joypad/ctr_joypad.o + OBJ += gfx/drivers/ctr_gfx.o \ + menu/drivers_display/menu_display_ctr.o \ + input/drivers/ctr_input.o \ + input/drivers_joypad/ctr_joypad.o endif ifeq ($(TARGET), retroarch_switch) - ifeq ($(HAVE_LIBNX), 1) - OBJ += menu/drivers_display/menu_display_switch.o \ - gfx/drivers/switch_nx_gfx.o + ifeq ($(HAVE_LIBNX), 1) + OBJ += menu/drivers_display/menu_display_switch.o \ + gfx/drivers/switch_nx_gfx.o ifeq ($(HAVE_OPENGL), 1) - OBJ += gfx/drivers_context/switch_ctx.o + OBJ += gfx/drivers_context/switch_ctx.o endif ifeq ($(HAVE_THREADS), 1) - OBJ += $(LIBRETRO_COMM_DIR)/rthreads/switch_pthread.o + OBJ += $(LIBRETRO_COMM_DIR)/rthreads/switch_pthread.o endif - else - OBJ += gfx/drivers/switch_gfx.o - endif - OBJ += audio/drivers/switch_audio.o \ - audio/drivers/switch_thread_audio.o \ - input/drivers/switch_input.o \ - input/drivers_joypad/switch_joypad.o \ - frontend/drivers/platform_switch.o + else + OBJ += gfx/drivers/switch_gfx.o + endif + OBJ += audio/drivers/switch_audio.o \ + audio/drivers/switch_thread_audio.o \ + input/drivers/switch_input.o \ + input/drivers_joypad/switch_joypad.o \ + frontend/drivers/platform_switch.o endif ifeq ($(HAVE_WAYLAND), 1) - OBJ += gfx/drivers_context/wayland_ctx.o \ - input/drivers/wayland_input.o - ifeq ($(HAVE_EGL), 1) - LIBS += $(EGL_LIBS) - endif - DEFINES += $(WAYLAND_CFLAGS) $(WAYLAND_CURSOR_CFLAGS) - LIBS += $(WAYLAND_LIBS) $(WAYLAND_CURSOR_LIBS) + OBJ += gfx/drivers_context/wayland_ctx.o \ + input/drivers/wayland_input.o + ifeq ($(HAVE_EGL), 1) + LIBS += $(EGL_LIBS) + endif + DEFINES += $(WAYLAND_CFLAGS) $(WAYLAND_CURSOR_CFLAGS) + LIBS += $(WAYLAND_LIBS) $(WAYLAND_CURSOR_LIBS) endif #Input ifeq ($(HAVE_DINPUT), 1) - HAVE_DX_COMMON = 1 + HAVE_DX_COMMON = 1 LIBS += -ldinput8 -lole32 DEFINES += -DHAVE_DINPUT OBJ += input/drivers/dinput.o \ @@ -890,12 +902,12 @@ ifeq ($(HAVE_X11), 1) LIBS += $(X11_LIBS) $(XEXT_LIBS) $(XF86VM_LIBS) $(XINERAMA_LIBS) DEFINES += -DHAVE_X11 $(X11_CFLAGS) $(XEXT_CFLAGS) $(XF86VM_CFLAGS) $(XINERAMA_CFLAGS) -ifeq ($(HAVE_XCB),1) - LIBS += -lX11-xcb -endif -ifneq ($(HAVE_OPENGLES), 1) - OBJ += gfx/drivers_context/x_ctx.o -endif + ifeq ($(HAVE_XCB),1) + LIBS += -lX11-xcb + endif + ifneq ($(HAVE_OPENGLES), 1) + OBJ += gfx/drivers_context/x_ctx.o + endif endif ifeq ($(HAVE_XCB),1) @@ -910,9 +922,9 @@ ifeq ($(HAVE_XKBCOMMON), 1) endif ifeq ($(HAVE_DBUS), 1) - LIBS += $(DBUS_LIBS) - CFLAGS += $(DBUS_CFLAGS) - OBJ += gfx/common/dbus_common.o + LIBS += $(DBUS_LIBS) + CFLAGS += $(DBUS_CFLAGS) + OBJ += gfx/common/dbus_common.o endif ifeq ($(HAVE_UDEV), 1) @@ -923,25 +935,25 @@ ifeq ($(HAVE_UDEV), 1) endif ifeq ($(HAVE_LIBUSB), 1) -ifeq ($(HAVE_THREADS), 1) -ifeq ($(HAVE_HID), 1) - DEFINES += -DHAVE_LIBUSB - OBJ += input/drivers_hid/libusb_hid.o - ifneq ($(findstring BSD,$(OS)),) - LIBS += -lusb - else - LIBS += -lusb-1.0 + ifeq ($(HAVE_THREADS), 1) + ifeq ($(HAVE_HID), 1) + DEFINES += -DHAVE_LIBUSB + OBJ += input/drivers_hid/libusb_hid.o + ifneq ($(findstring BSD,$(OS)),) + LIBS += -lusb + else + LIBS += -lusb-1.0 + endif + endif endif endif -endif -endif ifeq ($(HAVE_IOHIDMANAGER), 1) -ifeq ($(HAVE_HID), 1) - DEFINES += -DHAVE_IOHIDMANAGER - OBJ += input/drivers_hid/iohidmanager_hid.o - LIBS += -framework IOKit -endif + ifeq ($(HAVE_HID), 1) + DEFINES += -DHAVE_IOHIDMANAGER + OBJ += input/drivers_hid/iohidmanager_hid.o + LIBS += -framework IOKit + endif endif ifeq ($(HAVE_CORELOCATION), 1) @@ -951,17 +963,17 @@ endif ifeq ($(HAVE_HID), 1) DEFINES += -DHAVE_HID - OBJ += input/drivers_joypad/hid_joypad.o \ - input/connect/joypad_connection.o \ - input/connect/connect_ps2adapter.o \ - input/connect/connect_psxadapter.o \ - input/connect/connect_ps3.o \ - input/connect/connect_ps4.o \ - input/connect/connect_wii.o \ - input/connect/connect_nesusb.o \ - input/connect/connect_snesusb.o \ - input/connect/connect_wiiupro.o \ - input/connect/connect_wiiugca.o + OBJ += input/drivers_joypad/hid_joypad.o \ + input/connect/joypad_connection.o \ + input/connect/connect_ps2adapter.o \ + input/connect/connect_psxadapter.o \ + input/connect/connect_ps3.o \ + input/connect/connect_ps4.o \ + input/connect/connect_wii.o \ + input/connect/connect_nesusb.o \ + input/connect/connect_snesusb.o \ + input/connect/connect_wiiupro.o \ + input/connect/connect_wiiugca.o endif ifeq ($(HAVE_PARPORT), 1) @@ -975,11 +987,11 @@ endif # Companion UI ifneq ($(findstring Win32,$(OS)),) -OBJ += ui/drivers/ui_win32.o \ - ui/drivers/win32/ui_win32_window.o \ - ui/drivers/win32/ui_win32_browser_window.o \ - ui/drivers/win32/ui_win32_msg_window.o \ - ui/drivers/win32/ui_win32_application.o + OBJ += ui/drivers/ui_win32.o \ + ui/drivers/win32/ui_win32_window.o \ + ui/drivers/win32/ui_win32_browser_window.o \ + ui/drivers/win32/ui_win32_msg_window.o \ + ui/drivers/win32/ui_win32_application.o endif # Video @@ -1025,8 +1037,8 @@ endif ifeq ($(HAVE_GL_CONTEXT), 1) DEFINES += -DHAVE_OPENGL -DHAVE_GLSL OBJ += gfx/drivers/gl.o \ - gfx/drivers_renderchain/gl2_renderchain.o \ - $(LIBRETRO_COMM_DIR)/gfx/gl_capabilities.o \ + gfx/drivers_renderchain/gl2_renderchain.o \ + $(LIBRETRO_COMM_DIR)/gfx/gl_capabilities.o \ gfx/common/gl_common.o \ gfx/drivers_font/gl_raster_font.o \ $(LIBRETRO_COMM_DIR)/glsym/rglgen.o @@ -1064,38 +1076,40 @@ ifeq ($(HAVE_GL_CONTEXT), 1) LIBS += $(EGL_LIBS) endif endif + ifeq ($(HAVE_OSMESA), 1) OBJ += gfx/drivers_context/osmesa_ctx.o LIBS += -lOSMesa endif -ifeq ($(HAVE_FFMPEG), 1) -ifneq ($(C89_BUILD), 1) -ifneq ($(HAVE_OPENGLES), 1) - OBJ += cores/libretro-ffmpeg/ffmpeg_fft.o - DEFINES += -I$(DEPS_DIR) -DHAVE_GL_FFT -endif -endif -endif -ifeq ($(HAVE_METAL), 1) - DEFINES += -DHAVE_METAL - OBJ += gfx/common/metal/Context.o \ - gfx/common/metal/Filter.o \ - gfx/common/metal/RendererCommon.o \ - gfx/common/metal/View.o \ - gfx/common/metal/TexturedView.o \ - gfx/common/metal/MenuDisplay.o \ - gfx/common/metal_common.o \ - gfx/drivers/metal.o \ - menu/drivers_display/menu_display_metal.o \ - gfx/drivers_font/metal_raster_font.o -endif + ifeq ($(HAVE_FFMPEG), 1) + ifneq ($(C89_BUILD), 1) + ifneq ($(HAVE_OPENGLES), 1) + OBJ += cores/libretro-ffmpeg/ffmpeg_fft.o + DEFINES += -I$(DEPS_DIR) -DHAVE_GL_FFT + endif + endif + endif -ifeq ($(HAVE_MPV), 1) - OBJ += cores/libretro-mpv/mpv-libretro.o - DEFINES += -I$(DEPS_DIR) -DHAVE_MPV - LIBS += -lmpv -endif + ifeq ($(HAVE_METAL), 1) + DEFINES += -DHAVE_METAL + OBJ += gfx/common/metal/Context.o \ + gfx/common/metal/Filter.o \ + gfx/common/metal/RendererCommon.o \ + gfx/common/metal/View.o \ + gfx/common/metal/TexturedView.o \ + gfx/common/metal/MenuDisplay.o \ + gfx/common/metal_common.o \ + gfx/drivers/metal.o \ + menu/drivers_display/menu_display_metal.o \ + gfx/drivers_font/metal_raster_font.o + endif + + ifeq ($(HAVE_MPV), 1) + OBJ += cores/libretro-mpv/mpv-libretro.o + DEFINES += -I$(DEPS_DIR) -DHAVE_MPV + LIBS += -lmpv + endif ifeq ($(HAVE_OPENGLES), 1) LIBS += $(OPENGLES_LIBS) @@ -1243,19 +1257,19 @@ ifeq ($(HAVE_CG), 1) endif ifeq ($(HAVE_D3D9), 1) - HAVE_D3D_COMMON = 1 - HAVE_D3DX = 1 + HAVE_D3D_COMMON = 1 + HAVE_D3DX = 1 DEFINES += -DHAVE_D3D9 -ifeq ($(HAVE_D3DX), 1) - DEFINES += -DHAVE_D3DX -endif -ifneq ($(HAVE_DYLIB), 1) - LIBS += -ld3d9 -ifeq ($(HAVE_D3DX), 1) - LIBS += -ld3dx9 -endif -endif - HAVE_DX_COMMON = 1 + ifeq ($(HAVE_D3DX), 1) + DEFINES += -DHAVE_D3DX + endif + ifneq ($(HAVE_DYLIB), 1) + LIBS += -ld3d9 + ifeq ($(HAVE_D3DX), 1) + LIBS += -ld3dx9 + endif + endif + HAVE_DX_COMMON = 1 OBJ += gfx/drivers_font/d3d_w32_font.o ifeq ($(HAVE_CG), 1) LIBS += -lcgD3D9 @@ -1269,17 +1283,17 @@ endif ifeq ($(HAVE_D3D10), 1) OBJ += gfx/drivers/d3d10.o \ - gfx/common/d3d10_common.o \ - gfx/drivers_font/d3d10_font.o \ - menu/drivers_display/menu_display_d3d10.o + gfx/common/d3d10_common.o \ + gfx/drivers_font/d3d10_font.o \ + menu/drivers_display/menu_display_d3d10.o DEFINES += -DHAVE_D3D10 endif ifeq ($(HAVE_D3D11), 1) OBJ += gfx/drivers/d3d11.o \ - gfx/common/d3d11_common.o \ - gfx/drivers_font/d3d11_font.o \ - menu/drivers_display/menu_display_d3d11.o + gfx/common/d3d11_common.o \ + gfx/drivers_font/d3d11_font.o \ + menu/drivers_display/menu_display_d3d11.o DEFINES += -DHAVE_D3D11 HAVE_SLANG = 1 HAVE_GLSLANG = 1 @@ -1288,9 +1302,9 @@ endif ifeq ($(HAVE_D3D12), 1) OBJ += gfx/drivers/d3d12.o \ - gfx/common/d3d12_common.o \ - gfx/drivers_font/d3d12_font.o \ - menu/drivers_display/menu_display_d3d12.o + gfx/common/d3d12_common.o \ + gfx/drivers_font/d3d12_font.o \ + menu/drivers_display/menu_display_d3d12.o DEFINES += -DHAVE_D3D12 HAVE_SLANG = 1 HAVE_GLSLANG = 1 @@ -1300,49 +1314,49 @@ endif ifneq ($(findstring 1, $(HAVE_D3D10) $(HAVE_D3D11) $(HAVE_D3D12)),) INCLUDE_DIRS += -isystemgfx/include/dxsdk OBJ += gfx/common/d3dcompiler_common.o \ - gfx/common/dxgi_common.o + gfx/common/dxgi_common.o CFLAGS += -Wno-unknown-pragmas endif ifeq ($(HAVE_D3D8), 1) - HAVE_D3D_COMMON = 1 + HAVE_D3D_COMMON = 1 HAVE_DX_COMMON = 1 DEFINES += -DHAVE_D3D8 -ifneq ($(HAVE_DYLIB), 1) - LIBS += -ld3d8 -ifeq ($(HAVE_D3DX), 1) - LIBS += -ld3dx8 -endif -endif + ifneq ($(HAVE_DYLIB), 1) + LIBS += -ld3d8 + ifeq ($(HAVE_D3DX), 1) + LIBS += -ld3dx8 + endif + endif endif ifeq ($(HAVE_DX_COMMON), 1) - LIBS += -ldxguid + LIBS += -ldxguid endif ifeq ($(HAVE_D3D8), 1) - DEFINES += -DHAVE_D3D8 - OBJ += gfx/drivers/d3d8.o - OBJ += gfx/common/d3d8_common.o + DEFINES += -DHAVE_D3D8 + OBJ += gfx/drivers/d3d8.o + OBJ += gfx/common/d3d8_common.o -ifeq ($(HAVE_MENU_COMMON), 1) - OBJ += menu/drivers_display/menu_display_d3d8.o -endif + ifeq ($(HAVE_MENU_COMMON), 1) + OBJ += menu/drivers_display/menu_display_d3d8.o + endif endif ifeq ($(HAVE_D3D9), 1) - DEFINES += -DHAVE_D3D9 - OBJ += gfx/drivers/d3d9.o - OBJ += gfx/common/d3d9_common.o + DEFINES += -DHAVE_D3D9 + OBJ += gfx/drivers/d3d9.o + OBJ += gfx/common/d3d9_common.o -ifeq ($(HAVE_MENU_COMMON), 1) - OBJ += menu/drivers_display/menu_display_d3d9.o -endif + ifeq ($(HAVE_MENU_COMMON), 1) + OBJ += menu/drivers_display/menu_display_d3d9.o + endif endif ifeq ($(HAVE_D3D_COMMON), 1) - DEFINES += -DHAVE_D3D - OBJ += gfx/common/d3d_common.o + DEFINES += -DHAVE_D3D + OBJ += gfx/common/d3d_common.o endif ifeq ($(HAVE_SLANG),1) @@ -1354,7 +1368,7 @@ ifeq ($(HAVE_SLANG),1) endif ifeq ($(HAVE_GLSLANG), 1) - DEFINES += -DHAVE_GLSLANG + DEFINES += -DHAVE_GLSLANG ifneq ($(findstring Win32,$(OS)),) GLSLANG_PLATFORM := Windows @@ -1380,17 +1394,16 @@ ifeq ($(HAVE_GLSLANG), 1) $(wildcard $(DEPS_DIR)/glslang/glslang/glslang/MachineIndependent/preprocessor/*.cpp) \ $(wildcard $(DEPS_DIR)/glslang/glslang/glslang/OSDependent/$(GLSLANG_PLATFORM)/*.cpp) -ifneq ($(findstring Win32,$(OS)),) -DEFINES += -DENABLE_HLSL -GLSLANG_SOURCES += $(wildcard $(DEPS_DIR)/glslang/glslang/hlsl/*.cpp) -endif - + ifneq ($(findstring Win32,$(OS)),) + DEFINES += -DENABLE_HLSL + GLSLANG_SOURCES += $(wildcard $(DEPS_DIR)/glslang/glslang/hlsl/*.cpp) + endif OBJ += $(GLSLANG_SOURCES:.cpp=.o) endif ifeq ($(HAVE_SPIRV_CROSS), 1) - DEFINES += -DHAVE_SPIRV_CROSS + DEFINES += -DHAVE_SPIRV_CROSS INCLUDE_DIRS += -I$(DEPS_DIR)/SPIRV-Cross OBJ += $(DEPS_DIR)/SPIRV-Cross/spirv_cross.o OBJ += $(DEPS_DIR)/SPIRV-Cross/spirv_cfg.o @@ -1400,7 +1413,7 @@ ifeq ($(HAVE_SPIRV_CROSS), 1) endif ifeq ($(WANT_WGL), 1) - OBJ += gfx/drivers_context/wgl_ctx.o + OBJ += gfx/drivers_context/wgl_ctx.o LIBS += -lcomctl32 endif @@ -1434,9 +1447,9 @@ ifeq ($(HAVE_7ZIP),1) $(DEPS_DIR)/7zip/Bcj2.o \ $(DEPS_DIR)/7zip/7zCrc.o \ $(DEPS_DIR)/7zip/Lzma2Dec.o \ - $(DEPS_DIR)/7zip/7zBuf.o + $(DEPS_DIR)/7zip/7zBuf.o OBJ += $(LIBRETRO_COMM_DIR)/file/archive_file_7z.o \ - $(7ZOBJ) + $(7ZOBJ) endif ifeq ($(HAVE_IBXM), 1) @@ -1446,8 +1459,8 @@ endif ifeq ($(HAVE_BUILTINFLAC),1) HAVE_FLAC = 1 - DEFINES += -DHAVE_DR_FLAC -I$(DEPS_DIR) - CFLAGS += -DHAVE_DR_FLAC + DEFINES += -DHAVE_DR_FLAC -I$(DEPS_DIR) + CFLAGS += -DHAVE_DR_FLAC CFLAGS += -DHAVE_FLAC -I$(DEPS_DIR)/libFLAC/include DEFINES += -DHAVE_STDINT_H -DHAVE_LROUND -DFLAC__HAS_OGG=0 \ -DFLAC_PACKAGE_VERSION="\"retroarch\"" @@ -1507,7 +1520,7 @@ endif ifeq ($(HAVE_CHD), 1) CFLAGS += -I$(LIBRETRO_COMM_DIR)/formats/libchdr - DEFINES += -DHAVE_CHD -DWANT_SUBCODE -DWANT_RAW_DATA_SECTOR + DEFINES += -DHAVE_CHD -DWANT_SUBCODE -DWANT_RAW_DATA_SECTOR OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_bitstream.o \ $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_cdrom.o \ $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_chd.o \ @@ -1516,7 +1529,7 @@ ifeq ($(HAVE_CHD), 1) ifeq ($(HAVE_FLAC), 1) OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_flac.o \ - $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_flac_codec.o + $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_flac_codec.o endif ifeq ($(HAVE_7ZIP), 1) @@ -1562,14 +1575,13 @@ endif ifeq ($(HAVE_V4L2),1) OBJ += camera/drivers/video4linux2.o -ifeq ($(HAVE_VIDEO_PROCESSOR),1) - OBJ += cores/libretro-video-processor/video_processor_v4l2.o -endif + ifeq ($(HAVE_VIDEO_PROCESSOR),1) + OBJ += cores/libretro-video-processor/video_processor_v4l2.o + endif DEFINES += -DHAVE_V4L2 LIBS += $(V4L2_LIBS) endif - # Things that depend on network availability ifeq ($(HAVE_NETWORKING), 1) @@ -1578,25 +1590,25 @@ ifeq ($(HAVE_NETWORKING), 1) $(LIBRETRO_COMM_DIR)/net/net_http.o \ $(LIBRETRO_COMM_DIR)/net/net_http_parse.o \ $(LIBRETRO_COMM_DIR)/net/net_socket.o \ - $(LIBRETRO_COMM_DIR)/net/net_natt.o \ - network/net_http_special.o \ - tasks/task_http.o \ - tasks/task_netplay_lan_scan.o \ - tasks/task_netplay_nat_traversal.o \ - tasks/task_wifi.o \ - tasks/task_netplay_find_content.o + $(LIBRETRO_COMM_DIR)/net/net_natt.o \ + network/net_http_special.o \ + tasks/task_http.o \ + tasks/task_netplay_lan_scan.o \ + tasks/task_netplay_nat_traversal.o \ + tasks/task_wifi.o \ + tasks/task_netplay_find_content.o ifeq ($(HAVE_SSL), 1) - OBJ += $(LIBRETRO_COMM_DIR)/net/net_socket_ssl.o + OBJ += $(LIBRETRO_COMM_DIR)/net/net_socket_ssl.o endif ifneq ($(HAVE_SOCKET_LEGACY),1) - OBJ += $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o + OBJ += $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o endif ifeq ($(WANT_IFADDRS), 1) - DEFINES += -DWANT_IFADDRS - OBJ += $(LIBRETRO_COMM_DIR)/compat/compat_ifaddrs.o + DEFINES += -DWANT_IFADDRS + OBJ += $(LIBRETRO_COMM_DIR)/compat/compat_ifaddrs.o endif ifneq ($(findstring Win32,$(OS)),) @@ -1606,91 +1618,89 @@ ifeq ($(HAVE_NETWORKING), 1) # Netplay DEFINES += -DHAVE_NETWORK_CMD OBJ += network/netplay/netplay_delta.o \ - network/netplay/netplay_frontend.o \ - network/netplay/netplay_handshake.o \ - network/netplay/netplay_init.o \ - network/netplay/netplay_io.o \ - network/netplay/netplay_keyboard.o \ - network/netplay/netplay_sync.o \ - network/netplay/netplay_discovery.o \ - network/netplay/netplay_buf.o \ - network/netplay/netplay_room_parse.o + network/netplay/netplay_frontend.o \ + network/netplay/netplay_handshake.o \ + network/netplay/netplay_init.o \ + network/netplay/netplay_io.o \ + network/netplay/netplay_keyboard.o \ + network/netplay/netplay_sync.o \ + network/netplay/netplay_discovery.o \ + network/netplay/netplay_buf.o \ + network/netplay/netplay_room_parse.o # Retro Achievements ifeq ($(HAVE_CHEEVOS), 1) DEFINES += -DHAVE_CHEEVOS - OBJ += cheevos/cheevos.o \ - cheevos/badges.o \ - cheevos/var.o \ - cheevos/cond.o + OBJ += cheevos/cheevos.o \ + cheevos/badges.o \ + cheevos/var.o \ + cheevos/cond.o - - ifeq ($(HAVE_LUA), 1) - DEFINES += -DHAVE_LUA \ - -DLUA_32BITS \ - -Ideps/lua/src - OBJ += deps/lua/src/lapi.o \ - deps/lua/src/lcode.o \ - deps/lua/src/lctype.o \ - deps/lua/src/ldebug.o \ - deps/lua/src/ldo.o \ - deps/lua/src/ldump.o \ - deps/lua/src/lfunc.o \ - deps/lua/src/lgc.o \ - deps/lua/src/llex.o \ - deps/lua/src/lmem.o \ - deps/lua/src/lobject.o \ - deps/lua/src/lopcodes.o \ - deps/lua/src/lparser.o \ - deps/lua/src/lstate.o \ - deps/lua/src/lstring.o \ - deps/lua/src/ltable.o \ - deps/lua/src/ltm.o \ - deps/lua/src/lundump.o \ - deps/lua/src/lvm.o \ - deps/lua/src/lzio.o \ - deps/lua/src/lauxlib.o \ - deps/lua/src/lbaselib.o \ - deps/lua/src/lbitlib.o \ - deps/lua/src/lcorolib.o \ - deps/lua/src/ldblib.o \ - deps/lua/src/liolib.o \ - deps/lua/src/lmathlib.o \ - deps/lua/src/loslib.o \ - deps/lua/src/lstrlib.o \ - deps/lua/src/ltablib.o \ - deps/lua/src/lutf8lib.o \ - deps/lua/src/loadlib.o \ - deps/lua/src/linit.o - else - DEFINES += -DRC_DISABLE_LUA + ifeq ($(HAVE_LUA), 1) + DEFINES += -DHAVE_LUA \ + -DLUA_32BITS \ + -Ideps/lua/src + OBJ += deps/lua/src/lapi.o \ + deps/lua/src/lcode.o \ + deps/lua/src/lctype.o \ + deps/lua/src/ldebug.o \ + deps/lua/src/ldo.o \ + deps/lua/src/ldump.o \ + deps/lua/src/lfunc.o \ + deps/lua/src/lgc.o \ + deps/lua/src/llex.o \ + deps/lua/src/lmem.o \ + deps/lua/src/lobject.o \ + deps/lua/src/lopcodes.o \ + deps/lua/src/lparser.o \ + deps/lua/src/lstate.o \ + deps/lua/src/lstring.o \ + deps/lua/src/ltable.o \ + deps/lua/src/ltm.o \ + deps/lua/src/lundump.o \ + deps/lua/src/lvm.o \ + deps/lua/src/lzio.o \ + deps/lua/src/lauxlib.o \ + deps/lua/src/lbaselib.o \ + deps/lua/src/lbitlib.o \ + deps/lua/src/lcorolib.o \ + deps/lua/src/ldblib.o \ + deps/lua/src/liolib.o \ + deps/lua/src/lmathlib.o \ + deps/lua/src/loslib.o \ + deps/lua/src/lstrlib.o \ + deps/lua/src/ltablib.o \ + deps/lua/src/lutf8lib.o \ + deps/lua/src/loadlib.o \ + deps/lua/src/linit.o + else + DEFINES += -DRC_DISABLE_LUA + endif endif - endif - ifeq ($(HAVE_DISCORD), 1) NEED_CXX_LINKER = 1 DEFINES += -DHAVE_DISCORD DEFINES += -Ideps/discord-rpc/include/ -Ideps/discord-rpc/thirdparty/rapidjson-1.1.0/include/ OBJ += deps/discord-rpc/src/discord_rpc.o \ - deps/discord-rpc/src/rpc_connection.o \ - deps/discord-rpc/src/serialization.o \ - discord/discord.o -ifneq ($(findstring Win32,$(OS)),) - OBJ += deps/discord-rpc/src/discord_register_win.o \ - deps/discord-rpc/src/connection_win.o - LIBS += -lpsapi -ladvapi32 -endif -ifneq ($(findstring Linux,$(OS)),) - OBJ += deps/discord-rpc/src/discord_register_linux.o \ - deps/discord-rpc/src/connection_unix.o -endif -ifneq ($(findstring Darwin,$(OS)),) - OBJ += deps/discord-rpc/src/discord_register_osx.o \ - deps/discord-rpc/src/connection_unix.o -endif + deps/discord-rpc/src/rpc_connection.o \ + deps/discord-rpc/src/serialization.o \ + discord/discord.o + ifneq ($(findstring Win32,$(OS)),) + OBJ += deps/discord-rpc/src/discord_register_win.o \ + deps/discord-rpc/src/connection_win.o + LIBS += -lpsapi -ladvapi32 + endif + ifneq ($(findstring Linux,$(OS)),) + OBJ += deps/discord-rpc/src/discord_register_linux.o \ + deps/discord-rpc/src/connection_unix.o + endif + ifneq ($(findstring Darwin,$(OS)),) + OBJ += deps/discord-rpc/src/discord_register_osx.o \ + deps/discord-rpc/src/connection_unix.o + endif endif ifeq ($(HAVE_NETWORKGAMEPAD), 1) @@ -1735,12 +1745,12 @@ ifneq ($(findstring Win32,$(OS)),) endif ifeq ($(HAVE_AVFOUNDATION), 1) -ifeq ($(HAVE_COCOA), 1) - DEFINES += -DHAVE_AVFOUNDATION - LIBS += -framework AVFoundation - LIBS += -framework CoreVideo - LIBS += -framework CoreMedia -endif + ifeq ($(HAVE_COCOA), 1) + DEFINES += -DHAVE_AVFOUNDATION + LIBS += -framework AVFoundation + LIBS += -framework CoreVideo + LIBS += -framework CoreMedia + endif endif # Record @@ -1749,13 +1759,11 @@ ifeq ($(HAVE_FFMPEG), 1) OBJ += record/drivers/record_ffmpeg.o \ cores/libretro-ffmpeg/ffmpeg_core.o - LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS) DEFINES += $(AVCODEC_CFLAGS) $(AVFORMAT_CFLAGS) $(AVUTIL_CFLAGS) $(SWSCALE_CFLAGS) $(SWRESAMPLE_CFLAGS) DEFINES += -Wno-deprecated-declarations -DHAVE_FFMPEG -Iffmpeg endif - ifeq ($(HAVE_COMPRESSION), 1) DEFINES += -DHAVE_COMPRESSION OBJ += tasks/task_decompress.o @@ -1764,20 +1772,23 @@ endif ifeq ($(HAVE_COCOA),1) DEFINES += -DHAVE_MAIN OBJ += input/drivers/cocoa_input.o \ - input/drivers_keyboard/keyboard_event_apple.o \ - ui/drivers/ui_cocoa.o \ - ui/drivers/cocoa/ui_cocoa_window.o \ - ui/drivers/cocoa/ui_cocoa_browser_window.o \ - ui/drivers/cocoa/ui_cocoa_msg_window.o \ - ui/drivers/cocoa/ui_cocoa_application.o \ - ui/drivers/cocoa/cocoa_common.o \ - gfx/drivers_context/cocoa_gl_ctx.o + input/drivers_keyboard/keyboard_event_apple.o \ + ui/drivers/ui_cocoa.o \ + ui/drivers/cocoa/ui_cocoa_window.o \ + ui/drivers/cocoa/ui_cocoa_browser_window.o \ + ui/drivers/cocoa/ui_cocoa_msg_window.o \ + ui/drivers/cocoa/ui_cocoa_application.o \ + ui/drivers/cocoa/cocoa_common.o \ + gfx/drivers_context/cocoa_gl_ctx.o endif ifneq ($(findstring DOS,$(OS)),) - OBJ += gfx/drivers/vga_gfx.o gfx/drivers_font/vga_font.o \ - input/drivers/dos_input.o input/drivers_joypad/dos_joypad.o \ - frontend/drivers/platform_dos.o input/drivers_keyboard/keyboard_event_dos.o + OBJ += gfx/drivers/vga_gfx.o \ + gfx/drivers_font/vga_font.o \ + input/drivers/dos_input.o \ + input/drivers_joypad/dos_joypad.o \ + frontend/drivers/platform_dos.o \ + input/drivers_keyboard/keyboard_event_dos.o ifeq ($(HAVE_MENU_COMMON), 1) OBJ += menu/drivers_display/menu_display_vga.o @@ -1785,52 +1796,89 @@ ifneq ($(findstring DOS,$(OS)),) endif ifeq ($(HAVE_STATIC_VIDEO_FILTERS), 1) -OBJ += gfx/video_filters/2xsai.o \ - gfx/video_filters/super2xsai.o \ - gfx/video_filters/supereagle.o \ - gfx/video_filters/2xbr.o \ - gfx/video_filters/darken.o \ - gfx/video_filters/epx.o \ - gfx/video_filters/scale2x.o \ - gfx/video_filters/blargg_ntsc_snes.o \ - gfx/video_filters/lq2x.o \ - gfx/video_filters/phosphor2x.o + OBJ += gfx/video_filters/2xsai.o \ + gfx/video_filters/super2xsai.o \ + gfx/video_filters/supereagle.o \ + gfx/video_filters/2xbr.o \ + gfx/video_filters/darken.o \ + gfx/video_filters/epx.o \ + gfx/video_filters/scale2x.o \ + gfx/video_filters/blargg_ntsc_snes.o \ + gfx/video_filters/lq2x.o \ + gfx/video_filters/phosphor2x.o \ + gfx/video_filters/normal2x.o endif ifeq ($(WANT_IOSUHAX), 1) -DEFINES += -I$(DEPS_DIR)/libiosuhax -CFLAGS += -I$(DEPS_DIR)/libiosuhax -OBJ += $(DEPS_DIR)/libiosuhax/iosuhax.o \ - $(DEPS_DIR)/libiosuhax/iosuhax_devoptab.o \ - $(DEPS_DIR)/libiosuhax/iosuhax_disc_interface.o + DEFINES += -I$(DEPS_DIR)/libiosuhax + CFLAGS += -I$(DEPS_DIR)/libiosuhax + OBJ += $(DEPS_DIR)/libiosuhax/iosuhax.o \ + $(DEPS_DIR)/libiosuhax/iosuhax_devoptab.o \ + $(DEPS_DIR)/libiosuhax/iosuhax_disc_interface.o endif ifeq ($(WANT_LIBFAT), 1) -DEFINES += -I$(DEPS_DIR)/libfat/include -CFLAGS += -I$(DEPS_DIR)/libfat/include -OBJ += $(DEPS_DIR)/libfat/cache.o \ - $(DEPS_DIR)/libfat/directory.o \ - $(DEPS_DIR)/libfat/disc.o \ - $(DEPS_DIR)/libfat/fatdir.o \ - $(DEPS_DIR)/libfat/fatfile.o \ - $(DEPS_DIR)/libfat/file_allocation_table.o \ - $(DEPS_DIR)/libfat/filetime.o \ - $(DEPS_DIR)/libfat/libfat.o \ - $(DEPS_DIR)/libfat/lock.o \ - $(DEPS_DIR)/libfat/partition.o + DEFINES += -I$(DEPS_DIR)/libfat/include + CFLAGS += -I$(DEPS_DIR)/libfat/include + OBJ += $(DEPS_DIR)/libfat/cache.o \ + $(DEPS_DIR)/libfat/directory.o \ + $(DEPS_DIR)/libfat/disc.o \ + $(DEPS_DIR)/libfat/fatdir.o \ + $(DEPS_DIR)/libfat/fatfile.o \ + $(DEPS_DIR)/libfat/file_allocation_table.o \ + $(DEPS_DIR)/libfat/filetime.o \ + $(DEPS_DIR)/libfat/libfat.o \ + $(DEPS_DIR)/libfat/lock.o \ + $(DEPS_DIR)/libfat/partition.o endif ifeq ($(HAVE_STATIC_AUDIO_FILTERS), 1) -OBJ += libretro-common/audio/dsp_filters/echo.o \ - libretro-common/audio/dsp_filters/eq.o \ - libretro-common/audio/dsp_filters/chorus.o \ - libretro-common/audio/dsp_filters/iir.o \ - libretro-common/audio/dsp_filters/panning.o \ - libretro-common/audio/dsp_filters/phaser.o \ - libretro-common/audio/dsp_filters/reverb.o \ - libretro-common/audio/dsp_filters/wahwah.o + OBJ += libretro-common/audio/dsp_filters/echo.o \ + libretro-common/audio/dsp_filters/eq.o \ + libretro-common/audio/dsp_filters/chorus.o \ + libretro-common/audio/dsp_filters/iir.o \ + libretro-common/audio/dsp_filters/panning.o \ + libretro-common/audio/dsp_filters/phaser.o \ + libretro-common/audio/dsp_filters/reverb.o \ + libretro-common/audio/dsp_filters/wahwah.o endif ifeq ($(HAVE_RPILED), 1) OBJ += led/drivers/led_rpi.o endif + +################################## +### Classic Platform specifics ### +###############WIP################ +# Help at https://modmyclassic.com/comp + +ifeq ($(HAVE_CLASSIC), 1) + CFLAGS += -DHAVE_CLASSIC +endif + +ifeq ($(HAVE_C_A7A7), 1) + C_A7A7_OPT = -Ofast \ + -fno-lto \ + -fdata-sections -ffunction-sections -Wl,--gc-sections \ + -fno-stack-protector -fno-ident -fomit-frame-pointer \ + -falign-functions=1 -falign-jumps=1 -falign-loops=1 \ + -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \ + -fmerge-all-constants -fno-math-errno \ + -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard + CFLAGS += $(C_A7A7_OPT) + CXXFLAGS += $(C_A7A7_OPT) + ifeq ($(shell echo `$(CC) -dumpversion` "< 4.9" | bc -l), 1) + CFLAGS += -march=armv7-a + else + CFLAGS += -march=armv7ve + # If gcc is 5.0 or later + ifeq ($(shell echo `$(CC) -dumpversion` ">= 5" | bc -l), 1) + LDFLAGS += -static-libgcc -static-libstdc++ + endif + endif +endif + +ifeq ($(HAVE_HAKCHI), 1) + CFLAGS += -DHAVE_HAKCHI +endif +################################## diff --git a/Makefile.griffin b/Makefile.griffin index 0249e2b8e5..03d6d22d8d 100644 --- a/Makefile.griffin +++ b/Makefile.griffin @@ -320,6 +320,7 @@ else ifeq ($(platform), windows_msvc6_x86) HAVE_7ZIP := 1 HAVE_NETWORKING := 0 HAVE_NETWORK_CMD := 1 + HAVE_NETPLAYDISCOVERY := 1 HAVE_OVERLAY := 1 HAVE_MATERIALUI := 1 HAVE_XMB := 1 @@ -361,6 +362,7 @@ else ifeq ($(platform), windows_msvc2003_x86) HAVE_7ZIP := 1 HAVE_NETWORKING := 1 HAVE_NETWORK_CMD := 1 + HAVE_NETPLAYDISCOVERY := 1 HAVE_OVERLAY := 1 HAVE_MATERIALUI := 1 HAVE_XMB := 1 @@ -407,6 +409,7 @@ else ifeq ($(platform), windows_msvc2005_x86) HAVE_7ZIP := 1 HAVE_NETWORKING := 1 HAVE_NETWORK_CMD := 1 + HAVE_NETPLAYDISCOVERY := 1 HAVE_OVERLAY := 1 HAVE_MATERIALUI := 1 HAVE_XMB := 1 @@ -454,6 +457,7 @@ else ifneq (,$(findstring windows_msvc2010,$(platform))) HAVE_7ZIP := 1 HAVE_NETWORKING := 1 HAVE_NETWORK_CMD := 1 + HAVE_NETPLAYDISCOVERY := 1 HAVE_OVERLAY := 1 HAVE_MATERIALUI := 1 HAVE_XMB := 1 @@ -524,6 +528,7 @@ else ifneq (,$(findstring windows_msvc2012,$(platform))) HAVE_7ZIP := 1 HAVE_NETWORKING := 1 HAVE_NETWORK_CMD := 1 + HAVE_NETPLAYDISCOVERY := 1 HAVE_OVERLAY := 1 HAVE_MATERIALUI := 1 HAVE_XMB := 1 @@ -598,6 +603,7 @@ else ifneq (,$(findstring windows_msvc2013,$(platform))) HAVE_7ZIP := 1 HAVE_NETWORKING := 1 HAVE_NETWORK_CMD := 1 + HAVE_NETPLAYDISCOVERY := 1 HAVE_OVERLAY := 1 HAVE_MATERIALUI := 1 HAVE_XMB := 1 @@ -672,6 +678,7 @@ else ifneq (,$(findstring windows_msvc2015,$(platform))) HAVE_7ZIP := 1 HAVE_NETWORKING := 1 HAVE_NETWORK_CMD := 1 + HAVE_NETPLAYDISCOVERY := 1 HAVE_OVERLAY := 1 HAVE_MATERIALUI := 1 HAVE_XMB := 1 @@ -857,6 +864,10 @@ ifeq ($(HAVE_NETWORKING), 1) CFLAGS += -DHAVE_NETWORKING endif +ifeq ($(HAVE_NETPLAYDISCOVERY), 1) + CFLAGS += -DHAVE_NETPLAYDISCOVERY +endif + ifeq ($(RARCH_CONSOLE), 1) CFLAGS += -DRARCH_CONSOLE endif diff --git a/Makefile.libnx b/Makefile.libnx index 00343d6b1c..b9f482b563 100644 --- a/Makefile.libnx +++ b/Makefile.libnx @@ -36,6 +36,7 @@ HAVE_STATIC_AUDIO_FILTERS = 1 HAVE_MENU = 1 HAVE_RUNAHEAD = 1 HAVE_NETWORKING = 1 +HAVE_NETPLAYDISCOVERY = 1 HAVE_STB_FONT = 1 HAVE_CHEEVOS = 1 @@ -55,9 +56,8 @@ ifeq ($(HAVE_OPENGL), 1) HAVE_RGUI = 1 HAVE_MATERIALUI = 1 - HAVE_ZARCH = 0 HAVE_XMB = 1 - HAVE_STRIPES = 0 + HAVE_OZONE = 1 HAVE_OVERLAY = 1 else @@ -66,11 +66,12 @@ else HAVE_ZARCH = 0 HAVE_MATERIALUI = 0 HAVE_XMB = 0 + HAVE_OZONE = 0 HAVE_STRIPES = 0 endif include Makefile.common -BLACKLIST := $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o +BLACKLIST := OBJ := $(filter-out $(BLACKLIST),$(OBJ)) @@ -221,7 +222,8 @@ ifneq ($(ROMFS),) export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) endif -DEPENDS := $(OFILES:.o=.d) +DEPENDS_TMP := $(OFILES:.o=.d) +DEPENDS := $(filter-out libretro_libnx.a,$(DEPENDS_TMP)) .PHONY: clean all @@ -243,7 +245,7 @@ endif $(OUTPUT).elf : $(OBJ) clean: - rm -f $(OBJ) $(OUTPUT).pfs0 $(OUTPUT).nro $(OUTPUT).elf + rm -f $(DEPENDS) $(OBJ) $(OUTPUT).pfs0 $(OUTPUT).nro $(OUTPUT).elf #--------------------------------------------------------------------------------- # you need a rule like this for each extension you use as binary data diff --git a/Makefile.nintendoc b/Makefile.nintendoc deleted file mode 100644 index 4f971984a4..0000000000 --- a/Makefile.nintendoc +++ /dev/null @@ -1,62 +0,0 @@ -# Hakchi version added to ease confusion amongst Hakchi community due to messy past... -# -# Make sure you have readelf installed (sudo apt-get install readelf) to patch the binary -# Might not be needed for your build but it's a useful tool and for safety it should be -# run anyway to ensure the SDL2 link isn't broken... - -HAKCHI_VER := Hakchi_Retroarch_Neo_v1_7_3b -HAKCHI_NAME := "Hakchi RetroArch 'Neo' v1.7.3b -MOD_CREATOR := TheOtherGuys -MOD_CATEGORY := RetroArch - -HAKCHI_DIR := hakchi -TARGET := retroarch -GIT_COMMIT := $(shell echo "`git rev-parse --short HEAD``git diff-index --quiet HEAD -- || echo '-dirty'`") - -all: $(TARGET) - -retroarch: - readelf -v #Check if you have readelf installed... (sudo apt-get install readelf) - ./configure --host=arm-linux-gnueabihf --disable-freetype --enable-opengles --enable-udev --enable-alsa --enable-neon --enable-floathard - make -f Makefile -j HAVE_HAKCHI=1 - patchelf --replace-needed libSDL2-2.0.so.0 libSDL2.so retroarch #libSDL2-2.0.so.0 sym link doesn't exist on native build. Just patch the binary... - #/usr/bin/arm-linux-gnueabihf-strip retroarch - rm -f $(HAKCHI_DIR)/bin/retroarch - cp retroarch $(HAKCHI_DIR)/bin/retroarch - echo $$(echo "Built by: " $$USER @ $$(date) \\\\\\ Git Commit: $(GIT_COMMIT)) > $(HAKCHI_DIR)/etc/libretro/retroarch_version - cp $(HAKCHI_DIR)/readme.md $(HAKCHI_DIR)/readme_COPY.md - printf "%s\n" \ - "---" \ - "Name: $(HAKCHI_VER)" \ - "Creator: $(MOD_CREATOR)" \ - "Category: $(MOD_CATEGORY)" \ - "Version: $(HAKCHI_VER)" \ - "Built on: $(shell date)" \ - "Git commit: $(GIT_COMMIT)" \ - "---" > $(HAKCHI_DIR)/readme.md - cat $(HAKCHI_DIR)/readme_COPY.md >> $(HAKCHI_DIR)/readme.md - rm $(HAKCHI_DIR)/readme_COPY.md - @echo "** BUILDING HAKCHI $(HAKCHI_VER) HMOD PACKAGE **" - cd $(HAKCHI_DIR)/; tar -czvf "$(HAKCHI_VER).hmod" * - mv $(HAKCHI_DIR)/$(HAKCHI_VER).hmod . - @echo "** BUILT HAKCHI $(HAKCHI_VER) HMOD PACKAGE **" -clean: - rm -f *.o - rm -f audio/*.o - rm -f conf/*.o - rm -f gfx/*.o - rm -f gfx/drivers_font/*.o - rm -f gfx/drivers_font_renderer/*.o - rm -f gfx/drivers_context/*.o - rm -f gfx/py_state/*.o - rm -f compat/*.o - rm -f record/*.o - rm -f input/*.o - rm -f tools/*.o - rm -f $(BINDIR)/retroarch - rm -f $(BINDIR)/retroarch-joyconfig - rm -f $(PNDDIR)/readme.html - rm -f retroarch - rm -f $(HAKCHI_DIR)/bin/retroarch - rm -f $(HAKCHI_VER).hmod - rm -f $(HAKCHI_DIR)/etc/libretro/retroarch_version diff --git a/Makefile.ps2 b/Makefile.ps2 new file mode 100644 index 0000000000..cbd9a5c556 --- /dev/null +++ b/Makefile.ps2 @@ -0,0 +1,105 @@ +BUILD_PRX = 0 +DEBUG = 1 +HAVE_KERNEL_PRX = 0 +HAVE_LOGGER = 0 +HAVE_FILE_LOGGER = 0 +HAVE_THREADS = 0 +BIG_STACK = 0 +WHOLE_ARCHIVE_LINK = 0 +PS2_IP = 192.168.1.150 + +#Configuration for IRX +EE_BIN2O = bin2o +IRX_DIR = $(PS2SDK)/iop/irx + +TARGET = retroarchps2.elf + +ifeq ($(DEBUG), 1) + OPTIMIZE_LV := -O0 -g + RARCH_DEFINES += -DDEBUG +else + OPTIMIZE_LV := -O2 +endif + +ifeq ($(WHOLE_ARCHIVE_LINK), 1) + WHOLE_START := -Wl,--whole-archive + WHOLE_END := -Wl,--no-whole-archive +endif + +INCDIR = -I$(PS2SDK)/ports/include -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/iop/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/common/include +INCDIR += -Ips2 -Ips2/include -Ilibretro-common/include +INCDIR += -Ideps -Ideps/stb -Ideps/libz -Ideps/7zip -Ideps/pthreads -Ideps/pthreads/platform/ps2 -Ideps/pthreads/platform/helper +GPVAL = -G0 +CFLAGS = $(OPTIMIZE_LV) -ffast-math -fsingle-precision-constant +ASFLAGS = $(CFLAGS) + +RARCH_DEFINES += -DPS2 -DUSE_IOP_CTYPE_MACRO -D_MIPS_ARCH_R5900 -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DWANT_ZLIB +RARCH_DEFINES += -DHAVE_GRIFFIN=1 -DRARCH_INTERNAL -DRARCH_CONSOLE -DHAVE_MENU -DHAVE_RGUI -DHAVE_FILTERS_BUILTIN -DHAVE_7ZIP -DHAVE_CC_RESAMPLER + +LIBDIR = +LDFLAGS = -L$(PS2SDK)/ports/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ee/lib -L. +#LIBS = $(WHOLE_START) -lretro_ps2 $(WHOLE_END) -lstdc++ -lm -lz -lgskit -ldmakit -lpng -laudsrv -lpad -lcdvd -lmad -lfileXio -lpatches +LIBS += $(WHOLE_START) -lretro_ps2 $(WHOLE_END) +LIBS += -lm -lg -lz -ldebug -lfileXio -laudsrv -lpatches -lpoweroff -ldma -lgskit -ldmakit -lpad -lsdl + +#IRX modules +# IRX modules - modules have to be in IRX_DIR +IRX = iomanX.irx fileXio.irx usbd.irx usbhdfsd.irx freesd.irx audsrv.irx poweroff.irx ps2dev9.irx ps2atad.irx ps2hdd.irx ps2fs.irx +IRX_OBJ = $(IRX:.irx=.o) +EE_OBJS += $(IRX_OBJ) + +ifeq ($(HAVE_THREADS), 1) +RARCH_DEFINES += -DHAVE_THREADS +endif + +ifeq ($(HAVE_FILE_LOGGER), 1) +CFLAGS += -DHAVE_FILE_LOGGER +endif + +ifeq ($(HAVE_KERNEL_PRX), 1) +CFLAGS += -DHAVE_KERNEL_PRX +endif + +ifeq ($(BIG_STACK), 1) +CFLAGS += -DBIG_STACK +endif + +CFLAGS += $(RARCH_DEFINES) + +# Missing objecst on the PS2SDK +EE_OBJS += ps2/compat_ctype.o + +#EE_OBJS = griffin/griffin.o bootstrap/ps2/kernel_functions.o +EE_OBJS += griffin/griffin.o + +EE_CFLAGS = $(CFLAGS) +EE_LDFLAGS = $(LDFLAGS) +EE_LIBS = $(LIBS) +EE_ASFLAGS = $(ASFLAGS) +EE_INCS = $(INCDIR) +EE_IRX_OBJ = $(IRX_OBJ) +EE_BIN = $(TARGET) +EE_GPVAL = $(GPVAL) + +all: $(EE_IRX_OBJ) $(EE_BIN) + +clean: + rm -f $(EE_BIN) $(EE_OBJS) + +prepare: + ps2client -h $(PS2_IP) reset + ps2client -h $(PS2_IP) netdump + +run: + ps2client -h $(PS2_IP) execee host:$(EE_BIN) + +debug: clean prepare all run + +#Specific file name and output per IRX Module +$(EE_IRX_OBJ): + $(EE_BIN2O) $(EE_GPVAL) $(IRX_DIR)/$(@:.o=.irx) $@ $(@:.o=_irx) + +#Include preferences +include $(PS2SDK)/samples/Makefile.pref +include $(PS2SDK)/samples/Makefile.eeglobal + \ No newline at end of file diff --git a/Makefile.wiiu b/Makefile.wiiu index 83c890e2a8..e77be12ea9 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -105,7 +105,7 @@ endif OBJ += griffin/griffin.o DEFINES += -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_LIBRETRODB DEFINES += -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DWANT_ZLIB -DHAVE_CC_RESAMPLER - DEFINES += -DHAVE_STB_FONT -DHAVE_STB_VORBIS -DHAVE_LANGEXTRA -DHAVE_LIBRETRODB -DHAVE_NETWORKING + DEFINES += -DHAVE_STB_FONT -DHAVE_STB_VORBIS -DHAVE_LANGEXTRA -DHAVE_LIBRETRODB -DHAVE_NETWORKING -DHAVE_NETPLAYDISCOVERY # DEFINES += -DWANT_IFADDRS # DEFINES += -DHAVE_FREETYPE DEFINES += -DHAVE_XMB -DHAVE_MATERIALUI @@ -128,6 +128,7 @@ endif HAVE_LANGEXTRA = 1 HAVE_LIBRETRODB = 1 HAVE_NETWORKING = 1 + HAVE_NETPLAYDISCOVERY = 1 HAVE_CHEEVOS = 1 # WANT_IFADDRS = 1 HAVE_OVERLAY = 1 @@ -137,8 +138,6 @@ endif WANT_IOSUHAX = 1 include Makefile.common - BLACKLIST := $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o - OBJ := $(filter-out $(BLACKLIST),$(OBJ)) OBJ += gfx/drivers/gx2_gfx.o OBJ += gfx/drivers_font/wiiu_font.o diff --git a/Makefile.win b/Makefile.win index 932d0f896f..02d70bde7f 100644 --- a/Makefile.win +++ b/Makefile.win @@ -8,6 +8,7 @@ HAVE_OPENGL = 1 HAVE_DYLIB = 1 HAVE_D3D9 = 1 HAVE_NETWORKING = 1 +HAVE_NETPLAYDISCOVERY = 1 HAVE_STDIN_CMD = 1 HAVE_COMMAND = 1 HAVE_THREADS = 1 diff --git a/README.md b/README.md index 1e4105cc53..c7fcf261c5 100644 --- a/README.md +++ b/README.md @@ -189,46 +189,46 @@ The default super resolution is 2560. It is displayed just under the CRT switch If native resolutions are activated you will need a whole new set of modelines: -- 512 x 240 @ 50.006977 SNESpal +- 256 x 240 @ 50.006977 SNESpal +- 256 x 448 @ 50.006977 SNESpal - 512 x 224 @ 50.006977 SNESpal +- 512 x 240 @ 50.006977 SNESpal - 512 x 448 @ 50.006977 SNESpal +- 256 x 240 @ 60.098812 SNESntsc +- 256 x 448 @ 60.098812 SNESntsc - 512 x 240 @ 60.098812 SNESntsc - 512 x 224 @ 60.098812 SNESntsc - 512 x 448 @ 60.098812 SNESntsc -- 256 x 240 @ 50.006977 SNESpal -- 256 x 448 @ 50.006977 SNESpal -- 256 x 240 @ 60.098812 SNESntsc -- 256 x 448 @ 60.098812 SNESntsc -- 320 x 240 @ 59.922745 MDntsc -- 320 x 448 @ 59.922745 MDntp -- 320 x 480 @ 59.922745 MDntsc - 256 x 192 @ 59.922745 MDntsc -- 320 x 224 @ 59.922745 MDntsc - 256 x 224 @ 59.922745 MDntsc -- 320 x 288 @ 49.701458 MDpal -- 320 x 576 @ 49.701458 MDpal +- 320 x 224 @ 59.922745 MDntsc +- 320 x 240 @ 59.922745 MDntsc +- 320 x 448 @ 59.922745 MDntsc +- 320 x 480 @ 59.922745 MDntsc - 256 x 192 @ 49.701458 MDpal +- 256 x 224 @ 49.701458 MDpal - 320 x 224 @ 49.701458 MDpal - 320 x 240 @ 49.701458 MDpal +- 320 x 288 @ 49.701458 MDpal - 320 x 448 @ 49.701458 MDpal - 320 x 480 @ 49.701458 MDpal -- 256 x 224 @ 49.701458 MDpal +- 320 x 576 @ 49.701458 MDpal - 256 x 288 @ 49.701458 MSYSpal - 256 x 240 @ 60.098812 NESntsc - 256 x 240 @ 50.006977 NESpal -- 640 x 480 @ 60.130001 N64ntsc - 640 x 237 @ 60.130001 N64ntsc - 640 x 240 @ 60.130001 N64ntsc +- 640 x 480 @ 60.130001 N64ntsc +- 640 x 288 @ 50.000000 N64pal - 640 x 480 @ 50.000000 N64pal -- 640 x 576 @ 50.000000 n64pal -- 640 x 288 @ 50.000000 n64pal +- 640 x 576 @ 50.000000 N64pal - 256 x 252 @ 49.759998 PSXpal -- 384 x 252 @ 49.759998 PSXpal -- 640 x 540 @ 49.759998 PSXpal - 320 x 252 @ 49.759998 PSXpal +- 384 x 252 @ 49.759998 PSXpal - 640 x 252 @ 49.759998 PSXpal +- 640 x 540 @ 49.759998 PSXpal - 384 x 240 @ 59.941002 PSXntsc - 256 x 480 @ 59.941002 PSXntsc diff --git a/audio/audio_driver.c b/audio/audio_driver.c index d0cc9d6497..cae227e790 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -796,6 +796,9 @@ size_t audio_driver_sample_batch(const int16_t *data, size_t frames) **/ void audio_driver_sample_rewind(int16_t left, int16_t right) { + if (audio_driver_rewind_ptr == 0) + return; + audio_driver_rewind_buf[--audio_driver_rewind_ptr] = right; audio_driver_rewind_buf[--audio_driver_rewind_ptr] = left; } @@ -819,7 +822,10 @@ size_t audio_driver_sample_batch_rewind(const int16_t *data, size_t frames) size_t samples = frames << 1; for (i = 0; i < samples; i++) - audio_driver_rewind_buf[--audio_driver_rewind_ptr] = data[i]; + { + if (audio_driver_rewind_ptr > 0) + audio_driver_rewind_buf[--audio_driver_rewind_ptr] = data[i]; + } return frames; } @@ -905,11 +911,13 @@ void audio_driver_setup_rewind(void) for (i = 0; i < audio_driver_data_ptr; i += 2) { - audio_driver_rewind_buf[--audio_driver_rewind_ptr] = - audio_driver_output_samples_conv_buf[i + 1]; + if (audio_driver_rewind_ptr > 0) + audio_driver_rewind_buf[--audio_driver_rewind_ptr] = + audio_driver_output_samples_conv_buf[i + 1]; - audio_driver_rewind_buf[--audio_driver_rewind_ptr] = - audio_driver_output_samples_conv_buf[i + 0]; + if (audio_driver_rewind_ptr > 0) + audio_driver_rewind_buf[--audio_driver_rewind_ptr] = + audio_driver_output_samples_conv_buf[i + 0]; } audio_driver_data_ptr = 0; diff --git a/audio/audio_driver.h b/audio/audio_driver.h index 1d67fa0768..c90db9873c 100644 --- a/audio/audio_driver.h +++ b/audio/audio_driver.h @@ -335,6 +335,7 @@ extern audio_driver_t audio_ps3; extern audio_driver_t audio_gx; extern audio_driver_t audio_ax; extern audio_driver_t audio_psp; +extern audio_driver_t audio_ps2; extern audio_driver_t audio_ctr_csnd; extern audio_driver_t audio_ctr_dsp; extern audio_driver_t audio_switch; diff --git a/audio/drivers/wasapi.c b/audio/drivers/wasapi.c index 593a377082..d711fd7141 100644 --- a/audio/drivers/wasapi.c +++ b/audio/drivers/wasapi.c @@ -29,6 +29,19 @@ #include #include +#ifdef _MSC_VER +/* IID_IAudioClient 1CB9AD4C-DBFA-4c32-B178-C2F568A703B2 */ +static const GUID IID_IAudioClient = { 0x1CB9AD4C, 0xDBFA, 0xB178, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2 }; +/* IID_IAudioRenderClient F294ACFC-3146-4483-A7BF-ADDCA7C260E2 */ +static const GUID IID_IAudioRenderClient = { 0xF294ACFC, 0x3146, 0x4483, 0xA7BF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2 }; +/* IID_IMMDeviceEnumerator A95664D2-9614-4F35-A746-DE8DB63617E6 */ +static const GUID IID_IMMDeviceEnumerator = { 0xA95664D2, 0x9614, 0x4F35, 0xA746, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6 }; +/* CLSID_MMDeviceEnumerator BCDE0395-E52F-467C-8E3D-C4579291692E */ +static const GUID CLSID_MMDeviceEnumerator = { 0xBCDE0395, 0xE52F, 0x467C, 0x8E3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E }; +/* KSDATAFORMAT_SUBTYPE_IEEE_FLOAT 00000003-0000-0010-8000-00aa00389b71 */ +static const GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, 0x8000, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; +#endif + #include #include diff --git a/cheevos-new/cheevos.c b/cheevos-new/cheevos.c index e67af93c59..78d7d0d6ab 100644 --- a/cheevos-new/cheevos.c +++ b/cheevos-new/cheevos.c @@ -1743,7 +1743,10 @@ found: { settings_t *settings = config_get_ptr(); - if (!string_is_equal(settings->arrays.menu_driver, "xmb") || + if (!( + string_is_equal(settings->arrays.menu_driver, "xmb") || + string_is_equal(settings->arrays.menu_driver, "ozone") + ) || !settings->bools.cheevos_badges_enable) CORO_RET(); } diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index d6d1b36325..c4f637255f 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -1,3735 +1,3738 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2015-2018 - Andre Leiradella - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#ifdef HAVE_MENU -#include "../menu/menu_driver.h" -#include "../menu/menu_entries.h" -#endif - -#ifdef HAVE_THREADS -#include -#endif - -#include "badges.h" -#include "cheevos.h" -#include "var.h" -#include "cond.h" - -#include "../file_path_special.h" -#include "../paths.h" -#include "../command.h" -#include "../dynamic.h" -#include "../configuration.h" -#include "../performance_counters.h" -#include "../msg_hash.h" -#include "../retroarch.h" -#include "../core.h" - -#include "../network/net_http_special.h" -#include "../tasks/tasks_internal.h" - -#include "../verbosity.h" - -/* Define this macro to prevent cheevos from being deactivated. */ -#undef CHEEVOS_DONT_DEACTIVATE - -/* Define this macro to log URLs (will log the user token). */ -#undef CHEEVOS_LOG_URLS - -/* Define this macro to dump all cheevos' addresses. */ -#undef CHEEVOS_DUMP_ADDRS - -/* Define this macro to remove HTTP timeouts. */ -#undef CHEEVOS_NO_TIMEOUT - -/* Define this macro to load a JSON file from disk instead of downloading - * from retroachievements.org. */ -#undef CHEEVOS_JSON_OVERRIDE - -/* Define this macro with a string to save the JSON file to disk with - * that name. */ -#undef CHEEVOS_SAVE_JSON - -/* Define this macro to have the password and token logged. THIS WILL DISCLOSE - * THE USER'S PASSWORD, TAKE CARE! */ -#undef CHEEVOS_LOG_PASSWORD - -/* Define this macro to log downloaded badge images. */ -#undef CHEEVOS_LOG_BADGES - -/* C89 wants only int values in enums. */ -#define CHEEVOS_JSON_KEY_GAMEID 0xb4960eecU -#define CHEEVOS_JSON_KEY_ACHIEVEMENTS 0x69749ae1U -#define CHEEVOS_JSON_KEY_ID 0x005973f2U -#define CHEEVOS_JSON_KEY_MEMADDR 0x1e76b53fU -#define CHEEVOS_JSON_KEY_TITLE 0x0e2a9a07U -#define CHEEVOS_JSON_KEY_DESCRIPTION 0xe61a1f69U -#define CHEEVOS_JSON_KEY_POINTS 0xca8fce22U -#define CHEEVOS_JSON_KEY_AUTHOR 0xa804edb8U -#define CHEEVOS_JSON_KEY_MODIFIED 0xdcea4fe6U -#define CHEEVOS_JSON_KEY_CREATED 0x3a84721dU -#define CHEEVOS_JSON_KEY_BADGENAME 0x887685d9U -#define CHEEVOS_JSON_KEY_CONSOLE_ID 0x071656e5U -#define CHEEVOS_JSON_KEY_TOKEN 0x0e2dbd26U -#define CHEEVOS_JSON_KEY_FLAGS 0x0d2e96b2U -#define CHEEVOS_JSON_KEY_LEADERBOARDS 0xf1247d2dU -#define CHEEVOS_JSON_KEY_MEM 0x0b8807e4U -#define CHEEVOS_JSON_KEY_FORMAT 0xb341208eU -#define CHEEVOS_JSON_KEY_SUCCESS 0x110461deU -#define CHEEVOS_JSON_KEY_ERROR 0x0d2011cfU - -typedef struct -{ - cheevos_cond_t *conds; - unsigned count; -} cheevos_condset_t; - -typedef struct -{ - cheevos_condset_t *condsets; - unsigned count; -} cheevos_condition_t; - -typedef struct -{ - unsigned id; - const char *title; - const char *description; - const char *author; - const char *badge; - unsigned points; - unsigned dirty; - int active; - int last; - int modified; - - cheevos_condition_t condition; -} cheevo_t; - -typedef struct -{ - cheevo_t *cheevos; - unsigned count; -} cheevoset_t; - -typedef struct -{ - int is_element; - int mode; -} cheevos_deactivate_t; - -typedef struct -{ - unsigned key_hash; - int is_key; - const char *value; - size_t length; -} cheevos_getvalueud_t; - -typedef struct -{ - int in_cheevos; - int in_lboards; - uint32_t field_hash; - unsigned core_count; - unsigned unofficial_count; - unsigned lboard_count; -} cheevos_countud_t; - -typedef struct -{ - const char *string; - size_t length; -} cheevos_field_t; - -typedef struct -{ - int in_cheevos; - int in_lboards; - int is_console_id; - unsigned core_count; - unsigned unofficial_count; - unsigned lboard_count; - - cheevos_field_t *field; - cheevos_field_t id, memaddr, title, desc, points, author; - cheevos_field_t modified, created, badge, flags, format; -} cheevos_readud_t; - -typedef struct -{ - int label; - const char *name; - const uint32_t *ext_hashes; -} cheevos_finder_t; - -typedef struct -{ - cheevos_var_t var; - double multiplier; - bool compare_next; -} cheevos_term_t; - -typedef struct -{ - cheevos_term_t *terms; - unsigned count; - unsigned compare_count; -} cheevos_expr_t; - -typedef struct -{ - unsigned id; - unsigned format; - const char *title; - const char *description; - int active; - int last_value; - - cheevos_condition_t start; - cheevos_condition_t cancel; - cheevos_condition_t submit; - cheevos_expr_t value; -} cheevos_leaderboard_t; - -typedef struct -{ - retro_task_t* task; -#ifdef HAVE_THREADS - slock_t* task_lock; -#endif - - cheevos_console_t console_id; - bool core_supports; - bool addrs_patched; - int add_buffer; - int add_hits; - - cheevoset_t core; - cheevoset_t unofficial; - cheevos_leaderboard_t *leaderboards; - unsigned lboard_count; - - char token[32]; - - retro_ctx_memory_info_t meminfo[4]; -} cheevos_locals_t; - -typedef struct -{ - uint8_t id[4]; /* NES^Z */ - uint8_t rom_size; - uint8_t vrom_size; - uint8_t rom_type; - uint8_t rom_type2; - uint8_t reserve[8]; -} cheevos_nes_header_t; - -static cheevos_locals_t cheevos_locals = -{ - /* task */ NULL, -#ifdef HAVE_THREADS - /* task_lock */ NULL, -#endif - - /* console_id */ CHEEVOS_CONSOLE_NONE, - /* core_supports */ true, - /* addrs_patched */ false, - /* add_buffer */ 0, - /* add_hits */ 0, - - /* core */ {NULL, 0}, - /* unofficial */ {NULL, 0}, - /* leaderboards */ NULL, - /* lboard_count */ 0, - - /* token */ {0}, - - { - /* meminfo[0] */ {NULL, 0, 0}, - /* meminfo[1] */ {NULL, 0, 0}, - /* meminfo[2] */ {NULL, 0, 0}, - /* meminfo[3] */ {NULL, 0, 0} - } -}; - -bool cheevos_loaded = false; -bool cheevos_hardcore_active = false; -bool cheevos_hardcore_paused = false; -bool cheevos_state_loaded_flag = false; -int cheats_are_enabled = 0; -int cheats_were_enabled = 0; - -#ifdef HAVE_THREADS -#define CHEEVOS_LOCK(l) do { slock_lock(l); } while (0) -#define CHEEVOS_UNLOCK(l) do { slock_unlock(l); } while (0) -#else -#define CHEEVOS_LOCK(l) -#define CHEEVOS_UNLOCK(l) -#endif - -/***************************************************************************** -Supporting functions. -*****************************************************************************/ - -#ifndef CHEEVOS_VERBOSE - -void cheevos_log(const char *fmt, ...) -{ - (void)fmt; -} - -#endif - -static unsigned size_in_megabytes(unsigned val) -{ - return (val * 1024 * 1024); -} - -#ifdef CHEEVOS_LOG_URLS -static void cheevos_log_url(const char* format, const char* url) -{ -#ifdef CHEEVOS_LOG_PASSWORD - CHEEVOS_LOG(format, url); -#else - char copy[256]; - char* aux = NULL; - char* next = NULL; - - if (!string_is_empty(url)) - strlcpy(copy, url, sizeof(copy)); - - aux = strstr(copy, "?p="); - - if (!aux) - aux = strstr(copy, "&p="); - - if (aux) - { - aux += 3; - next = strchr(aux, '&'); - - if (next) - { - do - { - *aux++ = *next++; - }while (next[-1] != 0); - } - else - *aux = 0; - } - - aux = strstr(copy, "?t="); - - if (!aux) - aux = strstr(copy, "&t="); - - if (aux) - { - aux += 3; - next = strchr(aux, '&'); - - if (next) - { - do - { - *aux++ = *next++; - }while (next[-1] != 0); - } - else - *aux = 0; - } - - CHEEVOS_LOG(format, copy); -#endif -} -#endif - -static uint32_t cheevos_djb2(const char* str, size_t length) -{ - const unsigned char *aux = (const unsigned char*)str; - const unsigned char *end = aux + length; - uint32_t hash = 5381; - - while (aux < end) - hash = (hash << 5) + hash + *aux++; - - return hash; -} - -static int cheevos_getvalue__json_key(void *userdata, - const char *name, size_t length) -{ - cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; - - if (ud) - ud->is_key = cheevos_djb2(name, length) == ud->key_hash; - return 0; -} - -static int cheevos_getvalue__json_string(void *userdata, - const char *string, size_t length) -{ - cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; - - if (ud && ud->is_key) - { - ud->value = string; - ud->length = length; - ud->is_key = 0; - } - - return 0; -} - -static int cheevos_getvalue__json_boolean(void *userdata, int istrue) -{ - cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; - - if (ud && ud->is_key) - { - if (istrue) - { - ud->value = "true"; - ud->length = 4; - } - else - { - ud->value = "false"; - ud->length = 5; - } - ud->is_key = 0; - } - - return 0; -} - -static int cheevos_getvalue__json_null(void *userdata) -{ - cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; - - if (ud && ud->is_key ) - { - ud->value = "null"; - ud->length = 4; - ud->is_key = 0; - } - - return 0; -} - -static int cheevos_get_value(const char *json, unsigned key_hash, - char *value, size_t length) -{ - static const jsonsax_handlers_t handlers = - { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - cheevos_getvalue__json_key, - NULL, - cheevos_getvalue__json_string, - cheevos_getvalue__json_string, /* number */ - cheevos_getvalue__json_boolean, - cheevos_getvalue__json_null - }; - - cheevos_getvalueud_t ud; - - ud.key_hash = key_hash; - ud.is_key = 0; - ud.value = NULL; - ud.length = 0; - *value = 0; - - if ((jsonsax_parse(json, &handlers, (void*)&ud) == JSONSAX_OK) - && ud.value && ud.length < length) - { - if (!string_is_empty(ud.value)) - strlcpy(value, ud.value, ud.length + 1); - return 0; - } - - return -1; -} - -/***************************************************************************** -Count number of achievements in a JSON file. -*****************************************************************************/ - -static int cheevos_count__json_end_array(void *userdata) -{ - cheevos_countud_t* ud = (cheevos_countud_t*)userdata; - - if (ud) - { - ud->in_cheevos = 0; - ud->in_lboards = 0; - } - - return 0; -} - -static int cheevos_count__json_key(void *userdata, - const char *name, size_t length) -{ - cheevos_countud_t* ud = (cheevos_countud_t*)userdata; - - if (ud) - { - ud->field_hash = cheevos_djb2(name, length); - if (ud->field_hash == CHEEVOS_JSON_KEY_ACHIEVEMENTS) - ud->in_cheevos = 1; - else if (ud->field_hash == CHEEVOS_JSON_KEY_LEADERBOARDS) - ud->in_lboards = 1; - } - - return 0; -} - -static int cheevos_count__json_number(void *userdata, - const char *number, size_t length) -{ - cheevos_countud_t* ud = (cheevos_countud_t*)userdata; - - if (ud) - { - if (ud->in_cheevos && ud->field_hash == CHEEVOS_JSON_KEY_FLAGS) - { - long flags = strtol(number, NULL, 10); - - if (flags == 3) - ud->core_count++; /* Core achievements */ - else if (flags == 5) - ud->unofficial_count++; /* Unofficial achievements */ - } - else if (ud->in_lboards && ud->field_hash == CHEEVOS_JSON_KEY_ID) - ud->lboard_count++; - } - - return 0; -} - -static int cheevos_count_cheevos(const char *json, - unsigned *core_count, unsigned *unofficial_count, - unsigned *lboard_count) -{ - static const jsonsax_handlers_t handlers = - { - NULL, - NULL, - NULL, - NULL, - NULL, - cheevos_count__json_end_array, - cheevos_count__json_key, - NULL, - NULL, - cheevos_count__json_number, - NULL, - NULL - }; - - int res; - cheevos_countud_t ud; - ud.in_cheevos = 0; - ud.in_lboards = 0; - ud.core_count = 0; - ud.unofficial_count = 0; - ud.lboard_count = 0; - - res = jsonsax_parse(json, &handlers, (void*)&ud); - - *core_count = ud.core_count; - *unofficial_count = ud.unofficial_count; - *lboard_count = ud.lboard_count; - - return res; -} - -/***************************************************************************** -Parse the MemAddr field. -*****************************************************************************/ - -static unsigned cheevos_count_cond_sets(const char *memaddr) -{ - cheevos_cond_t cond; - unsigned count = 0; - - for (;;) - { - count++; - - for (;;) - { - cheevos_cond_parse(&cond, &memaddr); - - if (*memaddr != '_') - break; - - memaddr++; - } - - if (*memaddr != 'S') - break; - - memaddr++; - } - - return count; -} - -static int cheevos_parse_condition( - cheevos_condition_t *condition, - const char* memaddr) -{ - if (!condition) - return 0; - - condition->count = cheevos_count_cond_sets(memaddr); - - if (condition->count) - { - unsigned set = 0; - const cheevos_condset_t* end = NULL; - cheevos_condset_t *conds = NULL; - cheevos_condset_t *condset = NULL; - cheevos_condset_t *condsets = (cheevos_condset_t*) - calloc(condition->count, sizeof(cheevos_condset_t)); - - (void)conds; - - if (!condsets) - return -1; - - condition->condsets = condsets; - end = condition->condsets + condition->count; - - for (condset = condition->condsets; condset < end; condset++, set++) - { - condset->count = - cheevos_cond_count_in_set(memaddr, set); - condset->conds = NULL; - - CHEEVOS_LOG("[CHEEVOS]: set %p (index=%u)\n", condset, set); - CHEEVOS_LOG("[CHEEVOS]: conds: %u\n", condset->count); - - if (condset->count) - { - cheevos_cond_t *conds = (cheevos_cond_t*) - calloc(condset->count, sizeof(cheevos_cond_t)); - - if (!conds) - { - while (--condset >= condition->condsets) - { - if ((void*)condset->conds) - free((void*)condset->conds); - } - - return -1; - } - - condset->conds = conds; - cheevos_cond_parse_in_set(condset->conds, memaddr, set); - } - } - } - - return 0; -} - -static void cheevos_free_condition(cheevos_condition_t* condition) -{ - unsigned i; - - if (!condition) - return; - - if (condition->condsets) - { - for (i = 0; i < condition->count; i++) - { - if (condition->condsets[i].conds) - { - free(condition->condsets[i].conds); - condition->condsets[i].conds = NULL; - } - } - - if (condition->condsets) - { - free(condition->condsets); - condition->condsets = NULL; - } - } -} - -/***************************************************************************** -Parse the Mem field of leaderboards. -*****************************************************************************/ - -static int cheevos_parse_expression(cheevos_expr_t *expr, const char* mem) -{ - unsigned i; - const char *aux; - cheevos_term_t *terms = NULL; - char *end = NULL; - - if (!expr) - return -1; - - expr->count = 1; - expr->compare_count = 1; - - for (aux = mem;; aux++) - { - if (*aux == '"' || *aux == ':') - break; - expr->count += *aux == '_'; - } - - if (expr->count > 0) - terms = (cheevos_term_t*) - calloc(expr->count, sizeof(cheevos_term_t)); - - if (!terms) - return -1; - - expr->terms = terms; - - for (i = 0; i < expr->count; i++) - { - expr->terms[i].compare_next = false; - expr->terms[i].multiplier = 1; - } - - for (i = 0, aux = mem; i < expr->count;) - { - cheevos_var_parse(&expr->terms[i].var, &aux); - - if (*aux != '*') - { - /* expression has no multiplier */ - if (*aux == '_') - { - aux++; - i++; - } - else if (*aux == '$') - { - expr->terms[i].compare_next = true; - expr->compare_count++; - aux++; - i++; - } - - /* no multiplier at end of string */ - else if (*aux == '\0' || *aux == '"' || *aux == ',') - return 0; - - /* invalid character in expression */ - else - { - if (expr->terms) - { - free(expr->terms); - expr->terms = NULL; - } - return -1; - } - } - else - { - if (aux[1] == 'h' || aux[1] == 'H') - expr->terms[i].multiplier = (double)strtol(aux + 2, &end, 16); - else - expr->terms[i].multiplier = strtod(aux + 1, &end); - aux = end; - - if (*aux == '$') - { - aux++; - expr->terms[i].compare_next = true; - expr->compare_count++; - } - else - expr->terms[i].compare_next = false; - - aux++; - i++; - } - } - return 0; -} - -static int cheevos_parse_mem(cheevos_leaderboard_t *lb, const char* mem) -{ - lb->start.condsets = NULL; - lb->cancel.condsets = NULL; - lb->submit.condsets = NULL; - lb->value.terms = NULL; - - for (;;) - { - if (*mem == 'S' && mem[1] == 'T' && mem[2] == 'A' && mem[3] == ':') - { - if (cheevos_parse_condition(&lb->start, mem + 4)) - goto error; - } - else if (*mem == 'C' && mem[1] == 'A' && mem[2] == 'N' && mem[3] == ':') - { - if (cheevos_parse_condition(&lb->cancel, mem + 4)) - goto error; - } - else if (*mem == 'S' && mem[1] == 'U' && mem[2] == 'B' && mem[3] == ':') - { - if (cheevos_parse_condition(&lb->submit, mem + 4)) - goto error; - } - else if (*mem == 'V' && mem[1] == 'A' && mem[2] == 'L' && mem[3] == ':') - { - if (cheevos_parse_expression(&lb->value, mem + 4)) - goto error; - } - - for (mem += 4;; mem++) - { - if (*mem == ':' && mem[1] == ':') - { - mem += 2; - break; - } - else if (*mem == '"') - return 0; - } - } - -error: - cheevos_free_condition(&lb->start); - cheevos_free_condition(&lb->cancel); - cheevos_free_condition(&lb->submit); - if (lb->value.terms) - { - free((void*)lb->value.terms); - lb->value.terms = NULL; - } - return -1; -} - -/***************************************************************************** -Load achievements from a JSON string. -*****************************************************************************/ - -static INLINE const char *cheevos_dupstr(const cheevos_field_t *field) -{ - char *string = (char*)malloc(field->length + 1); - - if (!string) - return NULL; - - memcpy ((void*)string, (void*)field->string, field->length); - string[field->length] = 0; - - return string; -} - -static int cheevos_new_cheevo(cheevos_readud_t *ud) -{ - cheevo_t *cheevo = NULL; - long flags = strtol(ud->flags.string, NULL, 10); - - if (flags == 3) - cheevo = cheevos_locals.core.cheevos + ud->core_count++; - else if (flags == 5) - cheevo = cheevos_locals.unofficial.cheevos + ud->unofficial_count++; - else - return 0; - - cheevo->id = (unsigned)strtol(ud->id.string, NULL, 10); - cheevo->title = cheevos_dupstr(&ud->title); - cheevo->description = cheevos_dupstr(&ud->desc); - cheevo->author = cheevos_dupstr(&ud->author); - cheevo->badge = cheevos_dupstr(&ud->badge); - cheevo->points = (unsigned)strtol(ud->points.string, NULL, 10); - cheevo->dirty = 0; - cheevo->active = CHEEVOS_ACTIVE_SOFTCORE | CHEEVOS_ACTIVE_HARDCORE; - cheevo->last = 1; - cheevo->modified = 0; - - if ( !cheevo->title || - !cheevo->description || - !cheevo->author || - !cheevo->badge) - goto error; - - if (cheevos_parse_condition(&cheevo->condition, ud->memaddr.string)) - goto error; - - return 0; - -error: - if (cheevo->title) - { - free((void*)cheevo->title); - cheevo->title = NULL; - } - if (cheevo->description) - { - free((void*)cheevo->description); - cheevo->description = NULL; - } - if (cheevo->author) - { - free((void*)cheevo->author); - cheevo->author = NULL; - } - if (cheevo->badge) - { - free((void*)cheevo->badge); - cheevo->badge = NULL; - } - return -1; -} - -/***************************************************************************** -Helper functions for displaying leaderboard values. -*****************************************************************************/ - -static void cheevos_format_value(const unsigned value, const unsigned type, - char* formatted_value, size_t formatted_size) -{ - unsigned mins, secs, millis; - - switch(type) - { - case CHEEVOS_FORMAT_VALUE: - snprintf(formatted_value, formatted_size, "%u", value); - break; - - case CHEEVOS_FORMAT_SCORE: - snprintf(formatted_value, formatted_size, - "%06upts", value); - break; - - case CHEEVOS_FORMAT_FRAMES: - mins = value / 3600; - secs = (value % 3600) / 60; - millis = (int) (value % 60) * (10.00 / 6.00); - snprintf(formatted_value, formatted_size, - "%02u:%02u.%02u", mins, secs, millis); - break; - - case CHEEVOS_FORMAT_MILLIS: - mins = value / 6000; - secs = (value % 6000) / 100; - millis = (int) (value % 100); - snprintf(formatted_value, formatted_size, - "%02u:%02u.%02u", mins, secs, millis); - break; - - case CHEEVOS_FORMAT_SECS: - mins = value / 60; - secs = value % 60; - snprintf(formatted_value, formatted_size, - "%02u:%02u", mins, secs); - break; - - default: - snprintf(formatted_value, formatted_size, - "%u (?)", value); - } -} - -unsigned cheevos_parse_format(cheevos_field_t* format) -{ - /* Most likely */ - if (strncmp(format->string, "VALUE", format->length) == 0) - return CHEEVOS_FORMAT_VALUE; - else if (strncmp(format->string, "TIME", format->length) == 0) - return CHEEVOS_FORMAT_FRAMES; - else if (strncmp(format->string, "SCORE", format->length) == 0) - return CHEEVOS_FORMAT_SCORE; - - /* Less likely */ - else if (strncmp(format->string, "MILLISECS", format->length) == 0) - return CHEEVOS_FORMAT_MILLIS; - else if (strncmp(format->string, "TIMESECS", format->length) == 0) - return CHEEVOS_FORMAT_SECS; - - /* Rare (RPS only) */ - else if (strncmp(format->string, "POINTS", format->length) == 0) - return CHEEVOS_FORMAT_SCORE; - else if (strncmp(format->string, "FRAMES", format->length) == 0) - return CHEEVOS_FORMAT_FRAMES; - else - return CHEEVOS_FORMAT_OTHER; -} - -static int cheevos_new_lboard(cheevos_readud_t *ud) -{ - cheevos_leaderboard_t *lboard = NULL; - cheevos_leaderboard_t *ldb = cheevos_locals.leaderboards; - - if (!ldb || !ud) - return -1; - - lboard = ldb + ud->lboard_count++; - - lboard->id = (unsigned)strtol(ud->id.string, NULL, 10); - lboard->format = cheevos_parse_format(&ud->format); - lboard->title = cheevos_dupstr(&ud->title); - lboard->description = cheevos_dupstr(&ud->desc); - - if (!lboard->title || !lboard->description) - goto error; - - if (cheevos_parse_mem(lboard, ud->memaddr.string)) - goto error; - - return 0; - -error: - if ((void*)lboard->title) - free((void*)lboard->title); - if ((void*)lboard->description) - free((void*)lboard->description); - return -1; -} - -static int cheevos_read__json_key( void *userdata, - const char *name, size_t length) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud) - { - int common = ud->in_cheevos || ud->in_lboards; - uint32_t hash = cheevos_djb2(name, length); - ud->field = NULL; - - switch (hash) - { - case CHEEVOS_JSON_KEY_ACHIEVEMENTS: - ud->in_cheevos = 1; - break; - case CHEEVOS_JSON_KEY_LEADERBOARDS: - ud->in_lboards = 1; - break; - case CHEEVOS_JSON_KEY_CONSOLE_ID: - ud->is_console_id = 1; - break; - case CHEEVOS_JSON_KEY_ID: - if (common) - ud->field = &ud->id; - break; - case CHEEVOS_JSON_KEY_MEMADDR: - if (ud->in_cheevos) - ud->field = &ud->memaddr; - break; - case CHEEVOS_JSON_KEY_MEM: - if (ud->in_lboards) - ud->field = &ud->memaddr; - break; - case CHEEVOS_JSON_KEY_TITLE: - if (common) - ud->field = &ud->title; - break; - case CHEEVOS_JSON_KEY_DESCRIPTION: - if (common) - ud->field = &ud->desc; - break; - case CHEEVOS_JSON_KEY_POINTS: - if (ud->in_cheevos) - ud->field = &ud->points; - break; - case CHEEVOS_JSON_KEY_AUTHOR: - if (ud->in_cheevos) - ud->field = &ud->author; - break; - case CHEEVOS_JSON_KEY_MODIFIED: - if (ud->in_cheevos) - ud->field = &ud->modified; - break; - case CHEEVOS_JSON_KEY_CREATED: - if (ud->in_cheevos) - ud->field = &ud->created; - break; - case CHEEVOS_JSON_KEY_BADGENAME: - if (ud->in_cheevos) - ud->field = &ud->badge; - break; - case CHEEVOS_JSON_KEY_FLAGS: - if (ud->in_cheevos) - ud->field = &ud->flags; - break; - case CHEEVOS_JSON_KEY_FORMAT: - if (ud->in_lboards) - ud->field = &ud->format; - break; - default: - break; - } - } - - return 0; -} - -static int cheevos_read__json_string(void *userdata, - const char *string, size_t length) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud && ud->field) - { - ud->field->string = string; - ud->field->length = length; - } - - return 0; -} - -static int cheevos_read__json_number(void *userdata, - const char *number, size_t length) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud) - { - if (ud->field) - { - ud->field->string = number; - ud->field->length = length; - } - else if (ud->is_console_id) - { - cheevos_locals.console_id = (cheevos_console_t) - strtol(number, NULL, 10); - ud->is_console_id = 0; - } - } - - return 0; -} - -static int cheevos_read__json_end_object(void *userdata) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud) - { - if (ud->in_cheevos) - return cheevos_new_cheevo(ud); - if (ud->in_lboards) - return cheevos_new_lboard(ud); - } - - return 0; -} - -static int cheevos_read__json_end_array(void *userdata) -{ - cheevos_readud_t *ud = (cheevos_readud_t*)userdata; - - if (ud) - { - ud->in_cheevos = 0; - ud->in_lboards = 0; - } - - return 0; -} - -static int cheevos_parse(const char *json) -{ - static const jsonsax_handlers_t handlers = - { - NULL, - NULL, - NULL, - cheevos_read__json_end_object, - NULL, - cheevos_read__json_end_array, - cheevos_read__json_key, - NULL, - cheevos_read__json_string, - cheevos_read__json_number, - NULL, - NULL - }; - - cheevos_readud_t ud; - unsigned core_count, unofficial_count, lboard_count; - /* Count the number of achievements in the JSON file. */ - int res = cheevos_count_cheevos(json, &core_count, &unofficial_count, - &lboard_count); - - if (res != JSONSAX_OK) - return -1; - - /* Allocate the achievements. */ - - cheevos_locals.core.cheevos = (cheevo_t*) - calloc(core_count, sizeof(cheevo_t)); - cheevos_locals.core.count = core_count; - - cheevos_locals.unofficial.cheevos = (cheevo_t*) - calloc(unofficial_count, sizeof(cheevo_t)); - cheevos_locals.unofficial.count = unofficial_count; - - cheevos_locals.leaderboards = (cheevos_leaderboard_t*) - calloc(lboard_count, sizeof(cheevos_leaderboard_t)); - cheevos_locals.lboard_count = lboard_count; - - if ( !cheevos_locals.core.cheevos || - !cheevos_locals.unofficial.cheevos || - !cheevos_locals.leaderboards) - { - if ((void*)cheevos_locals.core.cheevos) - free((void*)cheevos_locals.core.cheevos); - if ((void*)cheevos_locals.unofficial.cheevos) - free((void*)cheevos_locals.unofficial.cheevos); - if ((void*)cheevos_locals.leaderboards) - free((void*)cheevos_locals.leaderboards); - cheevos_locals.core.count = cheevos_locals.unofficial.count = - cheevos_locals.lboard_count = 0; - - return -1; - } - - /* Load the achievements. */ - ud.in_cheevos = 0; - ud.in_lboards = 0; - ud.is_console_id = 0; - ud.field = NULL; - ud.core_count = 0; - ud.unofficial_count = 0; - ud.lboard_count = 0; - - if (jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK) - goto error; - - return 0; - -error: - cheevos_unload(); - - return -1; -} - -/***************************************************************************** -Test all the achievements (call once per frame). -*****************************************************************************/ - -static int cheevos_test_condition(cheevos_cond_t *cond) -{ - unsigned sval = 0; - unsigned tval = 0; - - if (!cond) - return 0; - - sval = cheevos_var_get_value(&cond->source) + - cheevos_locals.add_buffer; - tval = cheevos_var_get_value(&cond->target); - - switch (cond->op) - { - case CHEEVOS_COND_OP_EQUALS: - return (sval == tval); - case CHEEVOS_COND_OP_LESS_THAN: - return (sval < tval); - case CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL: - return (sval <= tval); - case CHEEVOS_COND_OP_GREATER_THAN: - return (sval > tval); - case CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL: - return (sval >= tval); - case CHEEVOS_COND_OP_NOT_EQUAL_TO: - return (sval != tval); - default: - break; - } - - return 1; -} - -static int cheevos_test_pause_cond_set(const cheevos_condset_t *condset, - int *dirty_conds, int *reset_conds, int process_pause) -{ - int cond_valid = 0; - int set_valid = 1; /* must start true so AND logic works */ - cheevos_cond_t *cond = NULL; - const cheevos_cond_t *end = condset->conds + condset->count; - - cheevos_locals.add_buffer = 0; - cheevos_locals.add_hits = 0; - - for (cond = condset->conds; cond < end; cond++) - { - if (cond->pause != process_pause) - continue; - - if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE) - { - cheevos_locals.add_buffer += cheevos_var_get_value(&cond->source); - continue; - } - - if (cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE) - { - cheevos_locals.add_buffer -= cheevos_var_get_value(&cond->source); - continue; - } - - if (cond->type == CHEEVOS_COND_TYPE_ADD_HITS) - { - if (cheevos_test_condition(cond)) - { - cond->curr_hits++; - *dirty_conds = 1; - } - - cheevos_locals.add_hits += cond->curr_hits; - continue; - } - - /* always evaluate the condition to ensure delta values get tracked correctly */ - cond_valid = cheevos_test_condition(cond); - - /* if the condition has a target hit count that has already been met, - * it's automatically true, even if not currently true. */ - if ( (cond->req_hits != 0) && - (cond->curr_hits + cheevos_locals.add_hits) >= cond->req_hits) - { - cond_valid = 1; - } - else if (cond_valid) - { - cond->curr_hits++; - *dirty_conds = 1; - - /* Process this logic, if this condition is true: */ - if (cond->req_hits == 0) - ; /* Not a hit-based requirement: ignore any additional logic! */ - else if ((cond->curr_hits + cheevos_locals.add_hits) < cond->req_hits) - cond_valid = 0; /* HitCount target has not yet been met, condition is not yet valid. */ - } - - cheevos_locals.add_buffer = 0; - cheevos_locals.add_hits = 0; - - if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF) - { - /* as soon as we find a PauseIf that evaluates to true, - * stop processing the rest of the group. */ - if (cond_valid) - return 1; - - /* if we make it to the end of the function, make sure we are - * indicating nothing matched. if we do find a later PauseIf match, - * it'll automatically return true via the previous condition. */ - set_valid = 0; - - if (cond->req_hits == 0) - { - /* PauseIf didn't evaluate true, and doesn't have a HitCount, - * reset the HitCount to indicate the condition didn't match. */ - if (cond->curr_hits != 0) - { - cond->curr_hits = 0; - *dirty_conds = 1; - } - } - else - { - /* PauseIf has a HitCount that hasn't been met, ignore it for now. */ - } - } - else if (cond->type == CHEEVOS_COND_TYPE_RESET_IF) - { - if (cond_valid) - { - *reset_conds = 1; /* Resets all hits found so far */ - set_valid = 0; /* Cannot be valid if we've hit a reset condition. */ - } - } - else /* Sequential or non-sequential? */ - set_valid &= cond_valid; - } - - return set_valid; -} - -static int cheevos_test_cond_set(const cheevos_condset_t *condset, - int *dirty_conds, int *reset_conds) -{ - int in_pause = 0; - int has_pause = 0; - cheevos_cond_t *cond = NULL; - - if (!condset) - return 1; /* important: empty group must evaluate true */ - - /* the ints below are used for Pause conditions and their dependent AddSource/AddHits. */ - - /* this loop needs to go backwards to check AddSource/AddHits */ - cond = condset->conds + condset->count - 1; - for (; cond >= condset->conds; cond--) - { - if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF) - { - has_pause = 1; - in_pause = 1; - cond->pause = 1; - } - else if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE || - cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE || - cond->type == CHEEVOS_COND_TYPE_ADD_HITS) - { - cond->pause = in_pause; - } - else - { - in_pause = 0; - cond->pause = 0; - } - } - - if (has_pause) - { /* one or more Pause conditions exists, if any of them are true, - * stop processing this group. */ - if (cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 1)) - return 0; - } - - /* process the non-Pause conditions to see if the group is true */ - return cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 0); -} - -static int cheevos_reset_cond_set(cheevos_condset_t *condset, int deltas) -{ - int dirty = 0; - const cheevos_cond_t *end = NULL; - - if (!condset) - return 0; - - end = condset->conds + condset->count; - - if (deltas) - { - cheevos_cond_t *cond = NULL; - for (cond = condset->conds; cond < end; cond++) - { - dirty |= cond->curr_hits != 0; - - cond->curr_hits = 0; - - cond->source.previous = cond->source.value; - cond->target.previous = cond->target.value; - } - } - else - { - cheevos_cond_t *cond = NULL; - for (cond = condset->conds; cond < end; cond++) - { - dirty |= cond->curr_hits != 0; - cond->curr_hits = 0; - } - } - - return dirty; -} - -static int cheevos_test_cheevo(cheevo_t *cheevo) -{ - int dirty_conds = 0; - int reset_conds = 0; - int ret_val = 0; - int ret_val_sub_cond = 0; - cheevos_condset_t *condset = NULL; - cheevos_condset_t *end = NULL; - - if (!cheevo) - return 0; - - ret_val_sub_cond = cheevo->condition.count == 1; - condset = cheevo->condition.condsets; - - if (!condset) - return 0; - - end = condset + cheevo->condition.count; - - if (condset < end) - { - ret_val = cheevos_test_cond_set(condset, &dirty_conds, &reset_conds); - condset++; - } - - while (condset < end) - { - ret_val_sub_cond |= cheevos_test_cond_set( - condset, &dirty_conds, &reset_conds); - condset++; - } - - if (dirty_conds) - cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS; - - if (reset_conds) - { - int dirty = 0; - - for (condset = cheevo->condition.condsets; condset < end; condset++) - dirty |= cheevos_reset_cond_set(condset, 0); - - if (dirty) - cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS; - } - - return (ret_val && ret_val_sub_cond); -} - -static void cheevos_url_encode(const char *str, char *encoded, size_t len) -{ - if (!str) - return; - - while (*str) - { - if ( isalnum((unsigned char)*str) || *str == '-' - || *str == '_' || *str == '.' - || *str == '~') - { - if (len >= 2) - { - *encoded++ = *str++; - len--; - } - else - break; - } - else - { - if (len >= 4) - { - snprintf(encoded, len, "%%%02x", (uint8_t)*str); - encoded += 3; - str++; - len -= 3; - } - else - break; - } - } - - *encoded = 0; -} - -static void cheevos_make_unlock_url(const cheevo_t *cheevo, - char* url, size_t url_size) -{ - settings_t *settings = config_get_ptr(); - - if (!settings) - return; - - snprintf( - url, url_size, - "http://retroachievements.org/dorequest.php?r=awardachievement&u=%s&t=%s&a=%u&h=%d", - settings->arrays.cheevos_username, - cheevos_locals.token, - cheevo->id, - settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused ? 1 : 0 - ); - - url[url_size - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to award the cheevo: %s\n", url); -#endif -} - -static void cheevos_unlocked(void *task_data, void *user_data, - const char *error) -{ - cheevo_t *cheevo = (cheevo_t *)user_data; - - if (!error) - { - CHEEVOS_LOG("[CHEEVOS]: awarded achievement %u.\n", cheevo->id); - } - else - { - char url[256]; - url[0] = '\0'; - - CHEEVOS_ERR("[CHEEVOS]: error awarding achievement %u, retrying...\n", cheevo->id); - - cheevos_make_unlock_url(cheevo, url, sizeof(url)); - task_push_http_transfer(url, true, NULL, cheevos_unlocked, cheevo); - } -} - -static void cheevos_test_cheevo_set(const cheevoset_t *set) -{ - settings_t *settings = config_get_ptr(); - int mode = CHEEVOS_ACTIVE_SOFTCORE; - cheevo_t *cheevo = NULL; - const cheevo_t *end = NULL; - - if (!set) - return; - - end = set->cheevos + set->count; - - if (settings && settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) - mode = CHEEVOS_ACTIVE_HARDCORE; - - for (cheevo = set->cheevos; cheevo < end; cheevo++) - { - if (cheevo->active & mode) - { - int valid = cheevos_test_cheevo(cheevo); - - if (cheevo->last) - { - cheevos_condset_t* condset = cheevo->condition.condsets; - const cheevos_condset_t* end = cheevo->condition.condsets - + cheevo->condition.count; - - for (; condset < end; condset++) - cheevos_reset_cond_set(condset, 0); - } - else if (valid) - { - char msg[256]; - char url[256]; - msg[0] = url[0] = '\0'; - - cheevo->active &= ~mode; - - if (mode == CHEEVOS_ACTIVE_HARDCORE) - cheevo->active &= ~CHEEVOS_ACTIVE_SOFTCORE; - - CHEEVOS_LOG("[CHEEVOS]: awarding cheevo %u: %s (%s).\n", - cheevo->id, cheevo->title, cheevo->description); - - snprintf(msg, sizeof(msg), "Achievement Unlocked: %s", - cheevo->title); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); - runloop_msg_queue_push(cheevo->description, 0, 3 * 60, false); - - cheevos_make_unlock_url(cheevo, url, sizeof(url)); - task_push_http_transfer(url, true, NULL, - cheevos_unlocked, cheevo); - - if (settings && settings->bools.cheevos_auto_screenshot) - { - char shotname[256]; - - snprintf(shotname, sizeof(shotname), "%s/%s-cheevo-%u", - settings->paths.directory_screenshot, - path_basename(path_get(RARCH_PATH_BASENAME)), - cheevo->id); - shotname[sizeof(shotname) - 1] = '\0'; - - if (take_screenshot(shotname, true, - video_driver_cached_frame_has_valid_framebuffer(), false, true)) - CHEEVOS_LOG("[CHEEVOS]: got a screenshot for cheevo %u\n", cheevo->id); - else - CHEEVOS_LOG("[CHEEVOS]: failed to get screenshot for cheevo %u\n", cheevo->id); - } - } - - cheevo->last = valid; - } - } -} - -static int cheevos_test_lboard_condition(const cheevos_condition_t* condition) -{ - int dirty_conds = 0; - int reset_conds = 0; - int ret_val = 0; - int ret_val_sub_cond = 0; - cheevos_condset_t *condset = NULL; - const cheevos_condset_t *end = NULL; - - if (!condition) - return 0; - - ret_val_sub_cond = condition->count == 1; - condset = condition->condsets; - end = condset + condition->count; - - if (condset < end) - { - ret_val = cheevos_test_cond_set( - condset, &dirty_conds, &reset_conds); - condset++; - } - - while (condset < end) - { - ret_val_sub_cond |= cheevos_test_cond_set( - condset, &dirty_conds, &reset_conds); - condset++; - } - - if (reset_conds) - { - for (condset = condition->condsets; condset < end; condset++) - cheevos_reset_cond_set(condset, 0); - } - - return (ret_val && ret_val_sub_cond); -} - -static int cheevos_expr_value(cheevos_expr_t* expr) -{ - unsigned i; - int values[16]; - /* Separate possible values with '$' operator, submit the largest */ - unsigned current_value = 0; - cheevos_term_t* term = NULL; - - if (!expr) - return 0; - - term = expr->terms; - - if (!term) - return 0; - - if (expr->compare_count >= ARRAY_SIZE(values)) - { - CHEEVOS_ERR("[CHEEVOS]: too many values in the leaderboard expression: %u\n", expr->compare_count); - return 0; - } - - memset(values, 0, sizeof values); - - for (i = expr->count; i != 0; i--, term++) - { - if (current_value >= ARRAY_SIZE(values)) - { - CHEEVOS_ERR("[CHEEVOS]: too many values in the leaderboard expression: %u\n", current_value); - return 0; - } - - values[current_value] += - cheevos_var_get_value(&term->var) * term->multiplier; - - if (term->compare_next) - current_value++; - } - - if (expr->compare_count > 1) - { - unsigned j; - int maximum = values[0]; - - for (j = 1; j < expr->compare_count; j++) - maximum = values[j] > maximum ? values[j] : maximum; - - return maximum; - } - else - return values[0]; -} - -static void cheevos_make_lboard_url(const cheevos_leaderboard_t *lboard, - char* url, size_t url_size) -{ - MD5_CTX ctx; - uint8_t hash[16]; - char signature[64]; - settings_t *settings = config_get_ptr(); - - hash[0] = '\0'; - - snprintf(signature, sizeof(signature), "%u%s%u", lboard->id, - settings->arrays.cheevos_username, - lboard->id); - - MD5_Init(&ctx); - MD5_Update(&ctx, (void*)signature, strlen(signature)); - MD5_Final(hash, &ctx); - - snprintf( - url, url_size, - "http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d" - "&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - settings->arrays.cheevos_username, - cheevos_locals.token, - lboard->id, - lboard->last_value, - hash[ 0], hash[ 1], hash[ 2], hash[ 3], - hash[ 4], hash[ 5], hash[ 6], hash[ 7], - hash[ 8], hash[ 9], hash[10], hash[11], - hash[12], hash[13], hash[14], hash[15] - ); - - url[url_size - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to submit the leaderboard: %s\n", url); -#endif -} - -static void cheevos_lboard_submit(void *task_data, void *user_data, - const char *error) -{ - cheevos_leaderboard_t *lboard = (cheevos_leaderboard_t *)user_data; - - if (!lboard) - return; - - if (!error) - { - CHEEVOS_ERR("[CHEEVOS]: error submitting leaderboard %u\n", lboard->id); - return; - } - - CHEEVOS_LOG("[CHEEVOS]: submitted leaderboard %u.\n", lboard->id); -} - -static void cheevos_test_leaderboards(void) -{ - unsigned i; - cheevos_leaderboard_t* lboard = cheevos_locals.leaderboards; - - if (!lboard) - return; - - for (i = cheevos_locals.lboard_count; i != 0; i--, lboard++) - { - if (lboard->active) - { - int value = cheevos_expr_value(&lboard->value); - - if (value != lboard->last_value) - { - CHEEVOS_LOG("[CHEEVOS]: value lboard %s %u\n", - lboard->title, value); - lboard->last_value = value; - } - - if (cheevos_test_lboard_condition(&lboard->submit)) - { - lboard->active = 0; - - /* failsafe for improper LBs */ - if (value == 0) - { - CHEEVOS_LOG("[CHEEVOS]: error: lboard %s tried to submit 0\n", - lboard->title); - runloop_msg_queue_push("Leaderboard attempt cancelled!", - 0, 2 * 60, false); - } - else - { - char url[256]; - char msg[256]; - char formatted_value[16]; - - cheevos_make_lboard_url(lboard, url, sizeof(url)); - task_push_http_transfer(url, true, NULL, - cheevos_lboard_submit, lboard); - CHEEVOS_LOG("[CHEEVOS]: submit lboard %s\n", lboard->title); - - cheevos_format_value(value, lboard->format, - formatted_value, sizeof(formatted_value)); - snprintf(msg, sizeof(msg), "Submitted %s for %s", - formatted_value, lboard->title); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); - } - } - - if (cheevos_test_lboard_condition(&lboard->cancel)) - { - CHEEVOS_LOG("[CHEEVOS]: cancel lboard %s\n", lboard->title); - lboard->active = 0; - runloop_msg_queue_push("Leaderboard attempt cancelled!", - 0, 2 * 60, false); - } - } - else - { - if (cheevos_test_lboard_condition(&lboard->start)) - { - char msg[256]; - - CHEEVOS_LOG("[CHEEVOS]: start lboard %s\n", lboard->title); - lboard->active = 1; - lboard->last_value = -1; - - snprintf(msg, sizeof(msg), - "Leaderboard Active: %s", lboard->title); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 2 * 60, false); - runloop_msg_queue_push(lboard->description, 0, 3*60, false); - } - } - } -} - -/***************************************************************************** -Free the loaded achievements. -*****************************************************************************/ - -static void cheevos_free_condset(const cheevos_condset_t *set) -{ - if (set && set->conds) - free((void*)set->conds); -} - -static void cheevos_free_cheevo(const cheevo_t *cheevo) -{ - if (!cheevo) - return; - - if (cheevo->title) - free((void*)cheevo->title); - if (cheevo->description) - free((void*)cheevo->description); - if (cheevo->author) - free((void*)cheevo->author); - if (cheevo->badge) - free((void*)cheevo->badge); - cheevos_free_condset(cheevo->condition.condsets); -} - -static void cheevos_free_cheevo_set(const cheevoset_t *set) -{ - const cheevo_t *cheevo = NULL; - const cheevo_t *end = NULL; - - if (!set) - return; - - cheevo = set->cheevos; - end = cheevo + set->count; - - while (cheevo < end) - cheevos_free_cheevo(cheevo++); - - if (set->cheevos) - free((void*)set->cheevos); -} - -#ifndef CHEEVOS_DONT_DEACTIVATE -static int cheevos_deactivate__json_index(void *userdata, unsigned int index) -{ - cheevos_deactivate_t *ud = (cheevos_deactivate_t*)userdata; - - if (ud) - ud->is_element = 1; - - return 0; -} - -static int cheevos_deactivate__json_number(void *userdata, - const char *number, size_t length) -{ - long id; - int found; - cheevo_t* cheevo = NULL; - const cheevo_t* end = NULL; - cheevos_deactivate_t *ud = (cheevos_deactivate_t*)userdata; - - if (ud && ud->is_element) - { - ud->is_element = 0; - id = strtol(number, NULL, 10); - found = 0; - cheevo = cheevos_locals.core.cheevos; - end = cheevo + cheevos_locals.core.count; - - for (; cheevo < end; cheevo++) - { - if (cheevo->id == (unsigned)id) - { - cheevo->active &= ~ud->mode; - found = 1; - break; - } - } - - if (!found) - { - cheevo = cheevos_locals.unofficial.cheevos; - end = cheevo + cheevos_locals.unofficial.count; - - for (; cheevo < end; cheevo++) - { - if (cheevo->id == (unsigned)id) - { - cheevo->active &= ~ud->mode; - found = 1; - break; - } - } - } - - if (found) - CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked cheevo %u (%s).\n", - cheevo->id, cheevo->title); - else - CHEEVOS_ERR("[CHEEVOS]: unknown cheevo to deactivate: %u.\n", id); - } - - return 0; -} - -static int cheevos_deactivate_unlocks(const char* json, unsigned mode) -{ - static const jsonsax_handlers_t handlers = - { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - cheevos_deactivate__json_index, - NULL, - cheevos_deactivate__json_number, - NULL, - NULL - }; - - cheevos_deactivate_t ud; - - ud.is_element = 0; - ud.mode = mode; - return jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK; -} -#endif - -void cheevos_reset_game(void) -{ - cheevo_t *end = NULL; - cheevo_t *cheevo = cheevos_locals.core.cheevos; - - if (!cheevo) - return; - - end = cheevo + cheevos_locals.core.count; - - for (; cheevo < end; cheevo++) - cheevo->last = 1; - - cheevo = cheevos_locals.unofficial.cheevos; - end = cheevo + cheevos_locals.unofficial.count; - - for (; cheevo < end; cheevo++) - cheevo->last = 1; -} - -void cheevos_populate_menu(void *data) -{ -#ifdef HAVE_MENU - unsigned i = 0; - unsigned items_found = 0; - settings_t *settings = config_get_ptr(); - menu_displaylist_info_t *info = (menu_displaylist_info_t*)data; - cheevo_t *end = NULL; - cheevo_t *cheevo = cheevos_locals.core.cheevos; - end = cheevo + cheevos_locals.core.count; - - if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable - && cheevos_loaded) - { - if (!cheevos_hardcore_paused) - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE), - msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE), - MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE, - MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0); - else - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME), - msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME), - MENU_ENUM_LABEL_ACHIEVEMENT_RESUME, - MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0); - } - - if (cheevo) - { - for (i = 0; cheevo < end; i++, cheevo++) - { - if (!(cheevo->active & CHEEVOS_ACTIVE_HARDCORE)) - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_HARDCORE)); - } - else if (!(cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)) - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); - } - else - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); - } - items_found++; - } - } - - cheevo = cheevos_locals.unofficial.cheevos; - - if (cheevo && settings->bools.cheevos_test_unofficial) - { - end = cheevo + cheevos_locals.unofficial.count; - - for (i = items_found; cheevo < end; i++, cheevo++) - { - if (!(cheevo->active & CHEEVOS_ACTIVE_HARDCORE)) - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_HARDCORE)); - } - else if (!(cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)) - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); - } - else - { - menu_entries_append_enum(info->list, cheevo->title, - cheevo->description, - MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, - MENU_SETTINGS_CHEEVOS_START + i, 0, 0); - set_badge_info(&badges_ctx, i, cheevo->badge, - (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); - } - items_found++; - } - } - - if (items_found == 0) - { - menu_entries_append_enum(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY), - msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY), - MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY, - FILE_TYPE_NONE, 0, 0); - } -#endif -} - -bool cheevos_get_description(cheevos_ctx_desc_t *desc) -{ - if (!desc) - return false; - - if (cheevos_loaded) - { - cheevo_t *cheevos = cheevos_locals.core.cheevos; - - if (!cheevos) - return false; - - if (desc->idx >= cheevos_locals.core.count) - { - cheevos = cheevos_locals.unofficial.cheevos; - desc->idx -= cheevos_locals.core.count; - } - - if (!string_is_empty(cheevos[desc->idx].description)) - strlcpy(desc->s, cheevos[desc->idx].description, desc->len); - } - else - *desc->s = 0; - - return true; -} - -bool cheevos_apply_cheats(bool *data_bool) -{ - cheats_are_enabled = *data_bool; - cheats_were_enabled |= cheats_are_enabled; - - return true; -} - -bool cheevos_unload(void) -{ - bool running; - CHEEVOS_LOCK(cheevos_locals.task_lock); - running = cheevos_locals.task != NULL; - CHEEVOS_UNLOCK(cheevos_locals.task_lock); - - if (running) - { - CHEEVOS_LOG("[CHEEVOS]: Asked the load thread to terminate\n"); - task_queue_cancel_task(cheevos_locals.task); - -#ifdef HAVE_THREADS - do - { - CHEEVOS_LOCK(cheevos_locals.task_lock); - running = cheevos_locals.task != NULL; - CHEEVOS_UNLOCK(cheevos_locals.task_lock); - } - while (running); -#endif - } - - if (cheevos_loaded) - { - cheevos_free_cheevo_set(&cheevos_locals.core); - cheevos_free_cheevo_set(&cheevos_locals.unofficial); - } - - cheevos_locals.core.cheevos = NULL; - cheevos_locals.unofficial.cheevos = NULL; - cheevos_locals.core.count = 0; - cheevos_locals.unofficial.count = 0; - - cheevos_loaded = false; - cheevos_hardcore_paused = false; - - return true; -} - -bool cheevos_toggle_hardcore_mode(void) -{ - settings_t *settings = config_get_ptr(); - - if (!settings) - return false; - - /* reset and deinit rewind to avoid cheat the score */ - if (settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) - { - const char *msg = msg_hash_to_str( - MSG_CHEEVOS_HARDCORE_MODE_ENABLE); - - /* send reset core cmd to avoid any user - * savestate previusly loaded. */ - command_event(CMD_EVENT_RESET, NULL); - - if (settings->bools.rewind_enable) - command_event(CMD_EVENT_REWIND_DEINIT, NULL); - - CHEEVOS_LOG("%s\n", msg); - runloop_msg_queue_push(msg, 0, 3 * 60, true); - } - else - { - if (settings->bools.rewind_enable) - command_event(CMD_EVENT_REWIND_INIT, NULL); - } - - return true; -} - -static void cheevos_patch_addresses(cheevoset_t* set) -{ - unsigned i; - cheevo_t* cheevo = NULL; - - if (!set) - return; - - cheevo = set->cheevos; - - if (!cheevo) - return; - - for (i = set->count; i != 0; i--, cheevo++) - { - unsigned j; - cheevos_condset_t* condset = cheevo->condition.condsets; - - for (j = cheevo->condition.count; j != 0; j--, condset++) - { - unsigned k; - cheevos_cond_t* cond = condset->conds; - - for (k = condset->count; k != 0; k--, cond++) - { - switch (cond->source.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&cond->source, - cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", - cond->source.bank_id + 1, cond->source.value); -#endif - break; - - default: - break; - } - - switch (cond->target.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&cond->target, - cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: t-var %03d:%08X\n", - cond->target.bank_id + 1, cond->target.value); -#endif - break; - - default: - break; - } - } - } - } -} - -static void cheevos_patch_lb_conditions(cheevos_condition_t* condition) -{ - unsigned i; - cheevos_condset_t* condset = NULL; - - if (!condition) - return; - - condset = condition->condsets; - - for (i = condition->count; i != 0; i--, condset++) - { - unsigned j; - cheevos_cond_t* cond = condset->conds; - - for (j = condset->count; j != 0; j--, cond++) - { - switch (cond->source.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&cond->source, - cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", - cond->source.bank_id + 1, cond->source.value); -#endif - break; - default: - break; - } - switch (cond->target.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&cond->target, - cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: t-var %03d:%08X\n", - cond->target.bank_id + 1, cond->target.value); -#endif - break; - default: - break; - } - } - } -} - -static void cheevos_patch_lb_expressions(cheevos_expr_t* expression) -{ - unsigned i; - cheevos_term_t* term = NULL; - - if (!expression) - return; - - term = expression->terms; - - for (i = expression->count; i != 0; i--, term++) - { - switch (term->var.type) - { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_var_patch_addr(&term->var, cheevos_locals.console_id); -#ifdef CHEEVOS_DUMP_ADDRS - CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", - term->var.bank_id + 1, term->var.value); -#endif - break; - default: - break; - } - } -} - -static void cheevos_patch_lbs(cheevos_leaderboard_t *leaderboard) -{ - unsigned i; - - for (i = 0; i < cheevos_locals.lboard_count; i++) - { - cheevos_condition_t *start = &leaderboard[i].start; - cheevos_condition_t *cancel = &leaderboard[i].cancel; - cheevos_condition_t *submit = &leaderboard[i].submit; - cheevos_expr_t *value = &leaderboard[i].value; - - cheevos_patch_lb_conditions(start); - cheevos_patch_lb_conditions(cancel); - cheevos_patch_lb_conditions(submit); - cheevos_patch_lb_expressions(value); - } -} - -void cheevos_test(void) -{ - settings_t *settings = config_get_ptr(); - - if (!cheevos_locals.addrs_patched) - { - cheevos_patch_addresses(&cheevos_locals.core); - cheevos_patch_addresses(&cheevos_locals.unofficial); - cheevos_patch_lbs(cheevos_locals.leaderboards); - - cheevos_locals.addrs_patched = true; - } - - cheevos_test_cheevo_set(&cheevos_locals.core); - - if (settings) - { - if (settings->bools.cheevos_test_unofficial) - cheevos_test_cheevo_set(&cheevos_locals.unofficial); - - if (settings->bools.cheevos_hardcore_mode_enable && - settings->bools.cheevos_leaderboards_enable && - !cheevos_hardcore_paused) - cheevos_test_leaderboards(); - } -} - -bool cheevos_set_cheats(void) -{ - cheats_were_enabled = cheats_are_enabled; - return true; -} - -void cheevos_set_support_cheevos(bool state) -{ - cheevos_locals.core_supports = state; -} - -bool cheevos_get_support_cheevos(void) -{ - return cheevos_locals.core_supports; -} - -cheevos_console_t cheevos_get_console(void) -{ - return cheevos_locals.console_id; -} - -#include "coro.h" - -/* Uncomment the following two lines to debug cheevos_iterate, this will - * disable the coroutine yielding. - * - * The code is very easy to understand. It's meant to be like BASIC: - * CORO_GOTO will jump execution to another label, CORO_GOSUB will - * call another label, and CORO_RET will return from a CORO_GOSUB. - * - * This coroutine code is inspired in a very old pure C implementation - * that runs everywhere: - * - * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html - */ -/*#undef CORO_YIELD -#define CORO_YIELD()*/ - -typedef struct -{ - /* variables used in the co-routine */ - char badge_name[16]; - char url[256]; - char badge_basepath[PATH_MAX_LENGTH]; - char badge_fullpath[PATH_MAX_LENGTH]; - unsigned char hash[16]; - bool round; - unsigned gameid; - unsigned i; - unsigned j; - unsigned k; - size_t bytes; - size_t count; - size_t offset; - size_t len; - size_t size; - MD5_CTX md5; - cheevos_nes_header_t header; - retro_time_t t0; - struct retro_system_info sysinfo; - void *data; - char *json; - const char *path; - const char *ext; - intfstream_t *stream; - cheevo_t *cheevo; - settings_t *settings; - struct http_connection_t *conn; - struct http_t *http; - const cheevo_t *cheevo_end; - - /* co-routine required fields */ - CORO_FIELDS -} coro_t; - -enum -{ - /* Negative values because CORO_SUB generates positive values */ - SNES_MD5 = -1, - GENESIS_MD5 = -2, - LYNX_MD5 = -3, - NES_MD5 = -4, - GENERIC_MD5 = -5, - FILENAME_MD5 = -6, - EVAL_MD5 = -7, - FILL_MD5 = -8, - GET_GAMEID = -9, - GET_CHEEVOS = -10, - GET_BADGES = -11, - LOGIN = -12, - HTTP_GET = -13, - DEACTIVATE = -14, - PLAYING = -15, - DELAY = -16 -}; - -static int cheevos_iterate(coro_t *coro) -{ - ssize_t num_read = 0; - size_t to_read = 4096; - uint8_t *buffer = NULL; - const char *end = NULL; - - static const uint32_t genesis_exts[] = - { - 0x0b888feeU, /* mdx */ - 0x005978b6U, /* md */ - 0x0b88aa89U, /* smd */ - 0x0b88767fU, /* gen */ - 0x0b8861beU, /* bin */ - 0x0b886782U, /* cue */ - 0x0b8880d0U, /* iso */ - 0x0b88aa98U, /* sms */ - 0x005977f3U, /* gg */ - 0x0059797fU, /* sg */ - 0 - }; - - static const uint32_t snes_exts[] = - { - 0x0b88aa88U, /* smc */ - 0x0b8872bbU, /* fig */ - 0x0b88a9a1U, /* sfc */ - 0x0b887623U, /* gd3 */ - 0x0b887627U, /* gd7 */ - 0x0b886bf3U, /* dx2 */ - 0x0b886312U, /* bsx */ - 0x0b88abd2U, /* swc */ - 0 - }; - - static const uint32_t lynx_exts[] = - { - 0x0b888cf7U, /* lnx */ - 0 - }; - - static cheevos_finder_t finders[] = - { - {SNES_MD5, "SNES (8Mb padding)", snes_exts}, - {GENESIS_MD5, "Genesis (6Mb padding)", genesis_exts}, - {LYNX_MD5, "Atari Lynx (only first 512 bytes)", lynx_exts}, - {NES_MD5, "NES (discards VROM)", NULL}, - {GENERIC_MD5, "Generic (plain content)", NULL}, - {FILENAME_MD5, "Generic (filename)", NULL} - }; - - CORO_ENTER(); - - - - cheevos_locals.addrs_patched = false; - - coro->settings = config_get_ptr(); - - cheevos_locals.meminfo[0].id = RETRO_MEMORY_SYSTEM_RAM; - core_get_memory(&cheevos_locals.meminfo[0]); - - cheevos_locals.meminfo[1].id = RETRO_MEMORY_SAVE_RAM; - core_get_memory(&cheevos_locals.meminfo[1]); - - cheevos_locals.meminfo[2].id = RETRO_MEMORY_VIDEO_RAM; - core_get_memory(&cheevos_locals.meminfo[2]); - - cheevos_locals.meminfo[3].id = RETRO_MEMORY_RTC; - core_get_memory(&cheevos_locals.meminfo[3]); - - CHEEVOS_LOG("[CHEEVOS]: system RAM: %p %u\n", - cheevos_locals.meminfo[0].data, - cheevos_locals.meminfo[0].size); - CHEEVOS_LOG("[CHEEVOS]: save RAM: %p %u\n", - cheevos_locals.meminfo[1].data, - cheevos_locals.meminfo[1].size); - CHEEVOS_LOG("[CHEEVOS]: video RAM: %p %u\n", - cheevos_locals.meminfo[2].data, - cheevos_locals.meminfo[2].size); - CHEEVOS_LOG("[CHEEVOS]: RTC: %p %u\n", - cheevos_locals.meminfo[3].data, - cheevos_locals.meminfo[3].size); - - /* Bail out if cheevos are disabled. - * But set the above anyways, - * command_read_ram needs it. */ - if (!coro->settings->bools.cheevos_enable) - CORO_STOP(); - - /* Load the content into memory, or copy it - * over to our own buffer */ - if (!coro->data) - { - coro->stream = intfstream_open_file( - coro->path, - RETRO_VFS_FILE_ACCESS_READ, - RETRO_VFS_FILE_ACCESS_HINT_NONE); - - if (!coro->stream) - CORO_STOP(); - - CORO_YIELD(); - coro->len = 0; - coro->count = intfstream_get_size(coro->stream); - - /* size limit */ - if (coro->count > size_in_megabytes(64)) - coro->count = size_in_megabytes(64); - - coro->data = malloc(coro->count); - - if (!coro->data) - { - intfstream_close(coro->stream); - free(coro->stream); - CORO_STOP(); - } - - for (;;) - { - buffer = (uint8_t*)coro->data + coro->len; - to_read = 4096; - - if (to_read > coro->count) - to_read = coro->count; - - num_read = intfstream_read(coro->stream, - (void*)buffer, to_read); - - if (num_read <= 0) - break; - - coro->len += num_read; - coro->count -= num_read; - - if (coro->count == 0) - break; - - CORO_YIELD(); - } - - intfstream_close(coro->stream); - free(coro->stream); - } - - /* Use the supported extensions as a hint - * to what method we should use. */ - core_get_system_info(&coro->sysinfo); - - for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++) - { - if (finders[coro->i].ext_hashes) - { - coro->ext = coro->sysinfo.valid_extensions; - - while (coro->ext) - { - unsigned hash; - end = strchr(coro->ext, '|'); - - if (end) - { - hash = cheevos_djb2( - coro->ext, end - coro->ext); - coro->ext = end + 1; - } - else - { - hash = cheevos_djb2( - coro->ext, strlen(coro->ext)); - coro->ext = NULL; - } - - for (coro->j = 0; finders[coro->i].ext_hashes[coro->j]; coro->j++) - { - if (finders[coro->i].ext_hashes[coro->j] == hash) - { - CHEEVOS_LOG("[CHEEVOS]: testing %s.\n", - finders[coro->i].name); - - /* - * Inputs: CHEEVOS_VAR_INFO - * Outputs: CHEEVOS_VAR_GAMEID, the game was found if it's different from 0 - */ - CORO_GOSUB(finders[coro->i].label); - - if (coro->gameid != 0) - goto found; - - coro->ext = NULL; /* force next finder */ - break; - } - } - } - } - } - - for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++) - { - if (finders[coro->i].ext_hashes) - continue; - - CHEEVOS_LOG("[CHEEVOS]: testing %s.\n", - finders[coro->i].name); - - /* - * Inputs: CHEEVOS_VAR_INFO - * Outputs: CHEEVOS_VAR_GAMEID - */ - CORO_GOSUB(finders[coro->i].label); - - if (coro->gameid != 0) - goto found; - } - - CHEEVOS_LOG("[CHEEVOS]: this game doesn't feature achievements.\n"); - CORO_STOP(); - -found: - -#ifdef CHEEVOS_JSON_OVERRIDE - { - size_t size = 0; - FILE *file = fopen(CHEEVOS_JSON_OVERRIDE, "rb"); - - fseek(file, 0, SEEK_END); - size = ftell(file); - fseek(file, 0, SEEK_SET); - - coro->json = (char*)malloc(size + 1); - fread((void*)coro->json, 1, size, file); - - fclose(file); - coro->json[size] = 0; - } -#else - CORO_GOSUB(GET_CHEEVOS); - - if (!coro->json) - { - runloop_msg_queue_push("Error loading achievements.", 0, 5 * 60, false); - CHEEVOS_ERR("[CHEEVOS]: error loading achievements.\n"); - CORO_STOP(); - } -#endif - -#ifdef CHEEVOS_SAVE_JSON - { - FILE *file = fopen(CHEEVOS_SAVE_JSON, "w"); - fwrite((void*)coro->json, 1, strlen(coro->json), file); - fclose(file); - } -#endif - if (cheevos_parse(coro->json)) - { - if ((void*)coro->json) - free((void*)coro->json); - CORO_STOP(); - } - - if ((void*)coro->json) - free((void*)coro->json); - - if ( cheevos_locals.core.count == 0 - && cheevos_locals.unofficial.count == 0 - && cheevos_locals.lboard_count == 0) - { - runloop_msg_queue_push( - "This game has no achievements.", - 0, 5 * 60, false); - - cheevos_free_cheevo_set(&cheevos_locals.core); - cheevos_free_cheevo_set(&cheevos_locals.unofficial); - - cheevos_locals.core.cheevos = NULL; - cheevos_locals.unofficial.cheevos = NULL; - cheevos_locals.core.count = 0; - cheevos_locals.unofficial.count = 0; - - cheevos_loaded = false; - cheevos_hardcore_paused = false; - CORO_STOP(); - } - - cheevos_loaded = true; - - /* - * Inputs: CHEEVOS_VAR_GAMEID - * Outputs: - */ - CORO_GOSUB(DEACTIVATE); - - /* - * Inputs: CHEEVOS_VAR_GAMEID - * Outputs: - */ - CORO_GOSUB(PLAYING); - - if (coro->settings->bools.cheevos_verbose_enable && cheevos_locals.core.count > 0) - { - char msg[256]; - int mode = CHEEVOS_ACTIVE_SOFTCORE; - const cheevo_t* cheevo = cheevos_locals.core.cheevos; - const cheevo_t* end = cheevo + cheevos_locals.core.count; - int number_of_unlocked = cheevos_locals.core.count; - - if (coro->settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) - mode = CHEEVOS_ACTIVE_HARDCORE; - - for (; cheevo < end; cheevo++) - if (cheevo->active & mode) - number_of_unlocked--; - - snprintf(msg, sizeof(msg), - "You have %d of %d achievements unlocked.", - number_of_unlocked, cheevos_locals.core.count); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 6 * 60, false); - } - - CORO_GOSUB(GET_BADGES); - CORO_STOP(); - - /************************************************************************** - * Info Tries to identify a SNES game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(SNES_MD5) - - MD5_Init(&coro->md5); - - coro->offset = 0; - coro->count = 0; - - CORO_GOSUB(EVAL_MD5); - - if (coro->count == 0) - { - MD5_Final(coro->hash, &coro->md5); - coro->gameid = 0; - CORO_RET(); - } - - if (coro->count < size_in_megabytes(8)) - { - /* - * Inputs: CHEEVOS_VAR_MD5, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT - * Outputs: CHEEVOS_VAR_MD5 - */ - coro->offset = 0; - coro->count = size_in_megabytes(8) - coro->count; - CORO_GOSUB(FILL_MD5); - } - - MD5_Final(coro->hash, &coro->md5); - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify a Genesis game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(GENESIS_MD5) - - MD5_Init(&coro->md5); - - coro->offset = 0; - coro->count = 0; - CORO_GOSUB(EVAL_MD5); - - if (coro->count == 0) - { - MD5_Final(coro->hash, &coro->md5); - coro->gameid = 0; - CORO_RET(); - } - - if (coro->count < size_in_megabytes(6)) - { - coro->offset = 0; - coro->count = size_in_megabytes(6) - coro->count; - CORO_GOSUB(FILL_MD5); - } - - MD5_Final(coro->hash, &coro->md5); - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify an Atari Lynx game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(LYNX_MD5) - - if (coro->len < 0x0240) - { - coro->gameid = 0; - CORO_RET(); - } - - MD5_Init(&coro->md5); - - coro->offset = 0x0040; - coro->count = 0x0200; - CORO_GOSUB(EVAL_MD5); - - MD5_Final(coro->hash, &coro->md5); - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify a NES game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(NES_MD5) - - /* Note about the references to the FCEU emulator below. There is no - * core-specific code in this function, it's rather Retro Achievements - * specific code that must be followed to the letter so we compute - * the correct ROM hash. Retro Achievements does indeed use some - * FCEU related method to compute the hash, since its NES emulator - * is based on it. */ - - if (coro->len < sizeof(coro->header)) - { - coro->gameid = 0; - CORO_RET(); - } - - memcpy((void*)&coro->header, coro->data, - sizeof(coro->header)); - - if ( coro->header.id[0] != 'N' - || coro->header.id[1] != 'E' - || coro->header.id[2] != 'S' - || coro->header.id[3] != 0x1a) - { - coro->gameid = 0; - CORO_RET(); - } - - { - size_t romsize = 256; - /* from FCEU core - compute size using the cart mapper */ - int mapper = (coro->header.rom_type >> 4) | (coro->header.rom_type2 & 0xF0); - - if (coro->header.rom_size) - romsize = next_pow2(coro->header.rom_size); - - /* for games not to the power of 2, so we just read enough - * PRG rom from it, but we have to keep ROM_size to the power of 2 - * since PRGCartMapping wants ROM_size to be to the power of 2 - * so instead if not to power of 2, we just use head.ROM_size when - * we use FCEU_read. */ - coro->round = mapper != 53 && mapper != 198 && mapper != 228; - coro->bytes = coro->round ? romsize : coro->header.rom_size; - } - - /* from FCEU core - check if Trainer included in ROM data */ - MD5_Init(&coro->md5); - coro->offset = sizeof(coro->header) + (coro->header.rom_type & 4 - ? sizeof(coro->header) : 0); - coro->count = 0x4000 * coro->bytes; - CORO_GOSUB(EVAL_MD5); - - if (coro->count < 0x4000 * coro->bytes) - { - coro->offset = 0xff; - coro->count = 0x4000 * coro->bytes - coro->count; - CORO_GOSUB(FILL_MD5); - } - - MD5_Final(coro->hash, &coro->md5); - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify a "generic" game - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(GENERIC_MD5) - - MD5_Init(&coro->md5); - - coro->offset = 0; - coro->count = 0; - CORO_GOSUB(EVAL_MD5); - - MD5_Final(coro->hash, &coro->md5); - - if (coro->count == 0) - CORO_RET(); - - CORO_GOTO(GET_GAMEID); - - /************************************************************************** - * Info Tries to identify a game based on its filename (with no extension) - * Input CHEEVOS_VAR_INFO the content info - * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found - *************************************************************************/ - CORO_SUB(FILENAME_MD5) - if (!string_is_empty(coro->path)) - { - char base_noext[PATH_MAX_LENGTH]; - fill_pathname_base_noext(base_noext, coro->path, sizeof(base_noext)); - - MD5_Init(&coro->md5); - MD5_Update(&coro->md5, (void*)base_noext, strlen(base_noext)); - MD5_Final(coro->hash, &coro->md5); - - CORO_GOTO(GET_GAMEID); - } - CORO_RET(); - - /************************************************************************** - * Info Evaluates the CHEEVOS_VAR_MD5 hash - * Inputs CHEEVOS_VAR_INFO, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT - * Outputs CHEEVOS_VAR_MD5, CHEEVOS_VAR_COUNT - *************************************************************************/ - CORO_SUB(EVAL_MD5) - - if (coro->count == 0) - coro->count = coro->len; - - if (coro->len - coro->offset < coro->count) - coro->count = coro->len - coro->offset; - - /* size limit */ - if (coro->count > size_in_megabytes(64)) - coro->count = size_in_megabytes(64); - - MD5_Update(&coro->md5, - (void*)((uint8_t*)coro->data + coro->offset), - coro->count); - CORO_RET(); - - /************************************************************************** - * Info Updates the CHEEVOS_VAR_MD5 hash with a repeated value - * Inputs CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT - * Outputs CHEEVOS_VAR_MD5 - *************************************************************************/ - CORO_SUB(FILL_MD5) - - { - char buffer[4096]; - - while (coro->count > 0) - { - size_t len = sizeof(buffer); - - if (len > coro->count) - len = coro->count; - - memset((void*)buffer, coro->offset, len); - MD5_Update(&coro->md5, (void*)buffer, len); - coro->count -= len; - } - } - - CORO_RET(); - - /************************************************************************** - * Info Gets the achievements from Retro Achievements - * Inputs coro->hash - * Outputs CHEEVOS_VAR_GAMEID - *************************************************************************/ - CORO_SUB(GET_GAMEID) - - { - char gameid[16]; - - CHEEVOS_LOG( - "[CHEEVOS]: getting game id for hash %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", - coro->hash[ 0], coro->hash[ 1], coro->hash[ 2], coro->hash[ 3], - coro->hash[ 4], coro->hash[ 5], coro->hash[ 6], coro->hash[ 7], - coro->hash[ 8], coro->hash[ 9], coro->hash[10], coro->hash[11], - coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15] - ); - - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=gameid&m=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - coro->hash[ 0], coro->hash[ 1], coro->hash[ 2], coro->hash[ 3], - coro->hash[ 4], coro->hash[ 5], coro->hash[ 6], coro->hash[ 7], - coro->hash[ 8], coro->hash[ 9], coro->hash[10], coro->hash[11], - coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15] - ); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to get the game's id: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (!coro->json) - CORO_RET(); - - if (cheevos_get_value(coro->json, - CHEEVOS_JSON_KEY_GAMEID, gameid, sizeof(gameid))) - { - if ((void*)coro->json) - free((void*)coro->json); - CHEEVOS_ERR("[CHEEVOS]: error getting game_id.\n"); - CORO_RET(); - } - - if ((void*)coro->json) - free((void*)coro->json); - CHEEVOS_LOG("[CHEEVOS]: got game id %s.\n", gameid); - coro->gameid = (unsigned)strtol(gameid, NULL, 10); - CORO_RET(); - } - - /************************************************************************** - * Info Gets the achievements from Retro Achievements - * Inputs CHEEVOS_VAR_GAMEID - * Outputs CHEEVOS_VAR_JSON - *************************************************************************/ - CORO_SUB(GET_CHEEVOS) - - CORO_GOSUB(LOGIN); - - snprintf(coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=patch&g=%u&u=%s&t=%s", - coro->gameid, - coro->settings->arrays.cheevos_username, - cheevos_locals.token); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to get the list of cheevos: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (!coro->json) - { - CHEEVOS_ERR("[CHEEVOS]: error getting achievements for game id %u.\n", coro->gameid); - CORO_STOP(); - } - - CHEEVOS_LOG("[CHEEVOS]: got achievements for game id %u.\n", coro->gameid); - CORO_RET(); - - /************************************************************************** - * Info Gets the achievements from Retro Achievements - * Inputs CHEEVOS_VAR_GAMEID - * Outputs CHEEVOS_VAR_JSON - *************************************************************************/ - CORO_SUB(GET_BADGES) - - badges_ctx = new_badges_ctx; - - { - settings_t *settings = config_get_ptr(); - if (!string_is_equal(settings->arrays.menu_driver, "xmb") || - !settings->bools.cheevos_badges_enable) - CORO_RET(); - } - - coro->cheevo = cheevos_locals.core.cheevos; - coro->cheevo_end = cheevos_locals.core.cheevos + cheevos_locals.core.count; - - for (; coro->cheevo < coro->cheevo_end; coro->cheevo++) - { - for (coro->j = 0 ; coro->j < 2; coro->j++) - { - coro->badge_fullpath[0] = '\0'; - fill_pathname_application_special( - coro->badge_fullpath, - sizeof(coro->badge_fullpath), - APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES); - - if (!path_is_directory(coro->badge_fullpath)) - path_mkdir(coro->badge_fullpath); - CORO_YIELD(); - if (coro->j == 0) - snprintf(coro->badge_name, - sizeof(coro->badge_name), - "%s.png", coro->cheevo->badge); - else - snprintf(coro->badge_name, - sizeof(coro->badge_name), - "%s_lock.png", coro->cheevo->badge); - - fill_pathname_join( - coro->badge_fullpath, - coro->badge_fullpath, - coro->badge_name, - sizeof(coro->badge_fullpath)); - - if (!badge_exists(coro->badge_fullpath)) - { -#ifdef CHEEVOS_LOG_BADGES - CHEEVOS_LOG( - "[CHEEVOS]: downloading badge %s\n", - coro->badge_fullpath); -#endif - snprintf(coro->url, - sizeof(coro->url), - "http://i.retroachievements.org/Badge/%s", - coro->badge_name); - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - if (!filestream_write_file(coro->badge_fullpath, - coro->json, coro->k)) - CHEEVOS_ERR("[CHEEVOS]: error writing badge %s\n", coro->badge_fullpath); - else - free(coro->json); - } - } - } - } - - CORO_RET(); - - /************************************************************************** - * Info Logs in the user at Retro Achievements - *************************************************************************/ - CORO_SUB(LOGIN) - - if (cheevos_locals.token[0]) - CORO_RET(); - - { - char urle_user[64]; - char urle_login[64]; - const char *username = coro ? coro->settings->arrays.cheevos_username : NULL; - const char *login = NULL; - bool via_token = false; - - if (coro) - { - if (string_is_empty(coro->settings->arrays.cheevos_password)) - { - via_token = true; - login = coro->settings->arrays.cheevos_token; - } - else - login = coro->settings->arrays.cheevos_password; - } - else - login = NULL; - - if (string_is_empty(username) || string_is_empty(login)) - { - runloop_msg_queue_push( - "Missing RetroAchievements account information.", - 0, 5 * 60, false); - runloop_msg_queue_push( - "Please fill in your account information in Settings.", - 0, 5 * 60, false); - CHEEVOS_ERR("[CHEEVOS]: login info not informed.\n"); - CORO_STOP(); - } - - cheevos_url_encode(username, urle_user, sizeof(urle_user)); - cheevos_url_encode(login, urle_login, sizeof(urle_login)); - - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=login&u=%s&%c=%s", - urle_user, via_token ? 't' : 'p', urle_login - ); - - coro->url[sizeof(coro->url) - 1] = 0; - } - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to login: %s\n", - coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - char error_response[64]; - char error_message[256]; - - cheevos_get_value( - coro->json, - CHEEVOS_JSON_KEY_ERROR, - error_response, - sizeof(error_response) - ); - - /* No error, continue with login */ - if (string_is_empty(error_response)) - { - int res = cheevos_get_value( - coro->json, - CHEEVOS_JSON_KEY_TOKEN, - cheevos_locals.token, - sizeof(cheevos_locals.token)); - - if ((void*)coro->json) - free((void*)coro->json); - - if (!res) - { - if (coro->settings->bools.cheevos_verbose_enable) - { - char msg[256]; - snprintf(msg, sizeof(msg), - "RetroAchievements: Logged in as \"%s\".", - coro->settings->arrays.cheevos_username); - msg[sizeof(msg) - 1] = 0; - runloop_msg_queue_push(msg, 0, 3 * 60, false); - } - - /* Save token to config and clear pass on success */ - *coro->settings->arrays.cheevos_password = '\0'; - strncpy( - coro->settings->arrays.cheevos_token, - cheevos_locals.token, sizeof(cheevos_locals.token) - ); - CORO_RET(); - } - } - - if ((void*)coro->json) - free((void*)coro->json); - - /* Site returned error, display it */ - snprintf(error_message, sizeof(error_message), - "RetroAchievements: %s", - error_response); - error_message[sizeof(error_message) - 1] = 0; - runloop_msg_queue_push(error_message, 0, 5 * 60, false); - *coro->settings->arrays.cheevos_token = '\0'; - - CORO_STOP(); - } - - runloop_msg_queue_push("RetroAchievements: Error contacting server.", 0, 5 * 60, false); - CHEEVOS_ERR("[CHEEVOS]: error getting user token.\n"); - - CORO_STOP(); - - /************************************************************************** - * Info Pauses execution for five seconds - *************************************************************************/ - CORO_SUB(DELAY) - - { - retro_time_t t1; - coro->t0 = cpu_features_get_time_usec(); - - do - { - CORO_YIELD(); - t1 = cpu_features_get_time_usec(); - }while ((t1 - coro->t0) < 3000000); - } - - CORO_RET(); - - /************************************************************************** - * Info Makes a HTTP GET request - * Inputs CHEEVOS_VAR_URL - * Outputs CHEEVOS_VAR_JSON - *************************************************************************/ - CORO_SUB(HTTP_GET) - - for (coro->k = 0; coro->k < 5; coro->k++) - { - if (coro->k != 0) - CHEEVOS_LOG("[CHEEVOS]: Retrying HTTP request: %u of 5\n", coro->k + 1); - - coro->json = NULL; - coro->conn = net_http_connection_new( - coro->url, "GET", NULL); - - if (!coro->conn) - { - CORO_GOSUB(DELAY); - continue; - } - - /* Don't bother with timeouts here, it's just a string scan. */ - while (!net_http_connection_iterate(coro->conn)) {} - - /* Error finishing the connection descriptor. */ - if (!net_http_connection_done(coro->conn)) - { - net_http_connection_free(coro->conn); - continue; - } - - coro->http = net_http_new(coro->conn); - - /* Error connecting to the endpoint. */ - if (!coro->http) - { - net_http_connection_free(coro->conn); - CORO_GOSUB(DELAY); - continue; - } - - while (!net_http_update(coro->http, NULL, NULL)) - CORO_YIELD(); - - { - size_t length; - uint8_t *data = net_http_data(coro->http, - &length, false); - - if (data) - { - coro->json = (char*)malloc(length + 1); - - if (coro->json) - { - memcpy((void*)coro->json, (void*)data, length); - free(data); - coro->json[length] = 0; - } - - coro->k = (unsigned)length; - net_http_delete(coro->http); - net_http_connection_free(coro->conn); - CORO_RET(); - } - } - - net_http_delete(coro->http); - net_http_connection_free(coro->conn); - } - - CHEEVOS_LOG("[CHEEVOS]: Couldn't connect to server after 5 tries\n"); - CORO_RET(); - - /************************************************************************** - * Info Deactivates the achievements already awarded - * Inputs CHEEVOS_VAR_GAMEID - * Outputs - *************************************************************************/ - CORO_SUB(DEACTIVATE) - -#ifndef CHEEVOS_DONT_DEACTIVATE - CORO_GOSUB(LOGIN); - - /* Deactivate achievements in softcore mode. */ - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=0", - coro->settings->arrays.cheevos_username, - cheevos_locals.token, coro->gameid - ); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to get the list of unlocked cheevos in softcore: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - if (!cheevos_deactivate_unlocks(coro->json, CHEEVOS_ACTIVE_SOFTCORE)) - CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked achievements in softcore mode.\n"); - else - CHEEVOS_ERR("[CHEEVOS]: error deactivating unlocked achievements in softcore mode.\n"); - - if ((void*)coro->json) - free((void*)coro->json); - } - else - CHEEVOS_ERR("[CHEEVOS]: error retrieving list of unlocked achievements in softcore mode.\n"); - - /* Deactivate achievements in hardcore mode. */ - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=1", - coro->settings->arrays.cheevos_username, - cheevos_locals.token, coro->gameid - ); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to get the list of unlocked cheevos in hardcore: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - if (!cheevos_deactivate_unlocks(coro->json, CHEEVOS_ACTIVE_HARDCORE)) - CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked achievements in hardcore mode.\n"); - else - CHEEVOS_ERR("[CHEEVOS]: error deactivating unlocked achievements in hardcore mode.\n"); - - if ((void*)coro->json) - free((void*)coro->json); - } - else - CHEEVOS_ERR("[CHEEVOS]: error retrieving list of unlocked achievements in hardcore mode.\n"); - -#endif - CORO_RET(); - - /************************************************************************** - * Info Posts the "playing" activity to Retro Achievements - * Inputs CHEEVOS_VAR_GAMEID - * Outputs - *************************************************************************/ - CORO_SUB(PLAYING) - - snprintf( - coro->url, sizeof(coro->url), - "http://retroachievements.org/dorequest.php?r=postactivity&u=%s&t=%s&a=3&m=%u", - coro->settings->arrays.cheevos_username, - cheevos_locals.token, coro->gameid - ); - - coro->url[sizeof(coro->url) - 1] = 0; - -#ifdef CHEEVOS_LOG_URLS - cheevos_log_url("[CHEEVOS]: url to post the 'playing' activity: %s\n", coro->url); -#endif - - CORO_GOSUB(HTTP_GET); - - if (coro->json) - { - CHEEVOS_LOG("[CHEEVOS]: posted playing activity.\n"); - if ((void*)coro->json) - free((void*)coro->json); - } - else - CHEEVOS_ERR("[CHEEVOS]: error posting playing activity.\n"); - - CHEEVOS_LOG("[CHEEVOS]: posted playing activity.\n"); - CORO_RET(); - - CORO_LEAVE(); -} - -static void cheevos_task_handler(retro_task_t *task) -{ - coro_t *coro = (coro_t*)task->state; - - if (!coro) - return; - - if (!cheevos_iterate(coro) || task_get_cancelled(task)) - { - task_set_finished(task, true); - - CHEEVOS_LOCK(cheevos_locals.task_lock); - cheevos_locals.task = NULL; - CHEEVOS_UNLOCK(cheevos_locals.task_lock); - - if (task_get_cancelled(task)) - { - CHEEVOS_LOG("[CHEEVOS]: Load task cancelled\n"); - } - else - { - CHEEVOS_LOG("[CHEEVOS]: Load task finished\n"); - } - - if (coro->data) - free(coro->data); - - if ((void*)coro->path) - free((void*)coro->path); - - free((void*)coro); - } -} - -bool cheevos_load(const void *data) -{ - retro_task_t *task; - const struct retro_game_info *info = NULL; - coro_t *coro = NULL; - - cheevos_loaded = false; - cheevos_hardcore_paused = false; - - if (!cheevos_locals.core_supports || !data) - return false; - - coro = (coro_t*)calloc(1, sizeof(*coro)); - - if (!coro) - return false; - - task = (retro_task_t*)calloc(1, sizeof(*task)); - - if (!task) - { - if ((void*)coro) - free((void*)coro); - return false; - } - - CORO_SETUP(); - - info = (const struct retro_game_info*)data; - - if (info->data) - { - coro->len = info->size; - - /* size limit */ - if (coro->len > size_in_megabytes(64)) - coro->len = size_in_megabytes(64); - - coro->data = malloc(coro->len); - - if (!coro->data) - { - if ((void*)task) - free((void*)task); - if ((void*)coro) - free((void*)coro); - return false; - } - - memcpy(coro->data, info->data, coro->len); - coro->path = NULL; - } - else - { - coro->data = NULL; - coro->path = strdup(info->path); - } - - task->handler = cheevos_task_handler; - task->state = (void*)coro; - task->mute = true; - task->callback = NULL; - task->user_data = NULL; - task->progress = 0; - task->title = NULL; - -#ifdef HAVE_THREADS - if (cheevos_locals.task_lock == NULL) - { - cheevos_locals.task_lock = slock_new(); - } -#endif - - CHEEVOS_LOCK(cheevos_locals.task_lock); - cheevos_locals.task = task; - CHEEVOS_UNLOCK(cheevos_locals.task_lock); - - task_queue_push(task); - - return true; -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2015-2018 - Andre Leiradella + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#ifdef HAVE_MENU +#include "../menu/menu_driver.h" +#include "../menu/menu_entries.h" +#endif + +#ifdef HAVE_THREADS +#include +#endif + +#include "badges.h" +#include "cheevos.h" +#include "var.h" +#include "cond.h" + +#include "../file_path_special.h" +#include "../paths.h" +#include "../command.h" +#include "../dynamic.h" +#include "../configuration.h" +#include "../performance_counters.h" +#include "../msg_hash.h" +#include "../retroarch.h" +#include "../core.h" + +#include "../network/net_http_special.h" +#include "../tasks/tasks_internal.h" + +#include "../verbosity.h" + +/* Define this macro to prevent cheevos from being deactivated. */ +#undef CHEEVOS_DONT_DEACTIVATE + +/* Define this macro to log URLs (will log the user token). */ +#undef CHEEVOS_LOG_URLS + +/* Define this macro to dump all cheevos' addresses. */ +#undef CHEEVOS_DUMP_ADDRS + +/* Define this macro to remove HTTP timeouts. */ +#undef CHEEVOS_NO_TIMEOUT + +/* Define this macro to load a JSON file from disk instead of downloading + * from retroachievements.org. */ +#undef CHEEVOS_JSON_OVERRIDE + +/* Define this macro with a string to save the JSON file to disk with + * that name. */ +#undef CHEEVOS_SAVE_JSON + +/* Define this macro to have the password and token logged. THIS WILL DISCLOSE + * THE USER'S PASSWORD, TAKE CARE! */ +#undef CHEEVOS_LOG_PASSWORD + +/* Define this macro to log downloaded badge images. */ +#undef CHEEVOS_LOG_BADGES + +/* C89 wants only int values in enums. */ +#define CHEEVOS_JSON_KEY_GAMEID 0xb4960eecU +#define CHEEVOS_JSON_KEY_ACHIEVEMENTS 0x69749ae1U +#define CHEEVOS_JSON_KEY_ID 0x005973f2U +#define CHEEVOS_JSON_KEY_MEMADDR 0x1e76b53fU +#define CHEEVOS_JSON_KEY_TITLE 0x0e2a9a07U +#define CHEEVOS_JSON_KEY_DESCRIPTION 0xe61a1f69U +#define CHEEVOS_JSON_KEY_POINTS 0xca8fce22U +#define CHEEVOS_JSON_KEY_AUTHOR 0xa804edb8U +#define CHEEVOS_JSON_KEY_MODIFIED 0xdcea4fe6U +#define CHEEVOS_JSON_KEY_CREATED 0x3a84721dU +#define CHEEVOS_JSON_KEY_BADGENAME 0x887685d9U +#define CHEEVOS_JSON_KEY_CONSOLE_ID 0x071656e5U +#define CHEEVOS_JSON_KEY_TOKEN 0x0e2dbd26U +#define CHEEVOS_JSON_KEY_FLAGS 0x0d2e96b2U +#define CHEEVOS_JSON_KEY_LEADERBOARDS 0xf1247d2dU +#define CHEEVOS_JSON_KEY_MEM 0x0b8807e4U +#define CHEEVOS_JSON_KEY_FORMAT 0xb341208eU +#define CHEEVOS_JSON_KEY_SUCCESS 0x110461deU +#define CHEEVOS_JSON_KEY_ERROR 0x0d2011cfU + +typedef struct +{ + cheevos_cond_t *conds; + unsigned count; +} cheevos_condset_t; + +typedef struct +{ + cheevos_condset_t *condsets; + unsigned count; +} cheevos_condition_t; + +typedef struct +{ + unsigned id; + const char *title; + const char *description; + const char *author; + const char *badge; + unsigned points; + unsigned dirty; + int active; + int last; + int modified; + + cheevos_condition_t condition; +} cheevo_t; + +typedef struct +{ + cheevo_t *cheevos; + unsigned count; +} cheevoset_t; + +typedef struct +{ + int is_element; + int mode; +} cheevos_deactivate_t; + +typedef struct +{ + unsigned key_hash; + int is_key; + const char *value; + size_t length; +} cheevos_getvalueud_t; + +typedef struct +{ + int in_cheevos; + int in_lboards; + uint32_t field_hash; + unsigned core_count; + unsigned unofficial_count; + unsigned lboard_count; +} cheevos_countud_t; + +typedef struct +{ + const char *string; + size_t length; +} cheevos_field_t; + +typedef struct +{ + int in_cheevos; + int in_lboards; + int is_console_id; + unsigned core_count; + unsigned unofficial_count; + unsigned lboard_count; + + cheevos_field_t *field; + cheevos_field_t id, memaddr, title, desc, points, author; + cheevos_field_t modified, created, badge, flags, format; +} cheevos_readud_t; + +typedef struct +{ + int label; + const char *name; + const uint32_t *ext_hashes; +} cheevos_finder_t; + +typedef struct +{ + cheevos_var_t var; + double multiplier; + bool compare_next; +} cheevos_term_t; + +typedef struct +{ + cheevos_term_t *terms; + unsigned count; + unsigned compare_count; +} cheevos_expr_t; + +typedef struct +{ + unsigned id; + unsigned format; + const char *title; + const char *description; + int active; + int last_value; + + cheevos_condition_t start; + cheevos_condition_t cancel; + cheevos_condition_t submit; + cheevos_expr_t value; +} cheevos_leaderboard_t; + +typedef struct +{ + retro_task_t* task; +#ifdef HAVE_THREADS + slock_t* task_lock; +#endif + + cheevos_console_t console_id; + bool core_supports; + bool addrs_patched; + int add_buffer; + int add_hits; + + cheevoset_t core; + cheevoset_t unofficial; + cheevos_leaderboard_t *leaderboards; + unsigned lboard_count; + + char token[32]; + + retro_ctx_memory_info_t meminfo[4]; +} cheevos_locals_t; + +typedef struct +{ + uint8_t id[4]; /* NES^Z */ + uint8_t rom_size; + uint8_t vrom_size; + uint8_t rom_type; + uint8_t rom_type2; + uint8_t reserve[8]; +} cheevos_nes_header_t; + +static cheevos_locals_t cheevos_locals = +{ + /* task */ NULL, +#ifdef HAVE_THREADS + /* task_lock */ NULL, +#endif + + /* console_id */ CHEEVOS_CONSOLE_NONE, + /* core_supports */ true, + /* addrs_patched */ false, + /* add_buffer */ 0, + /* add_hits */ 0, + + /* core */ {NULL, 0}, + /* unofficial */ {NULL, 0}, + /* leaderboards */ NULL, + /* lboard_count */ 0, + + /* token */ {0}, + + { + /* meminfo[0] */ {NULL, 0, 0}, + /* meminfo[1] */ {NULL, 0, 0}, + /* meminfo[2] */ {NULL, 0, 0}, + /* meminfo[3] */ {NULL, 0, 0} + } +}; + +bool cheevos_loaded = false; +bool cheevos_hardcore_active = false; +bool cheevos_hardcore_paused = false; +bool cheevos_state_loaded_flag = false; +int cheats_are_enabled = 0; +int cheats_were_enabled = 0; + +#ifdef HAVE_THREADS +#define CHEEVOS_LOCK(l) do { slock_lock(l); } while (0) +#define CHEEVOS_UNLOCK(l) do { slock_unlock(l); } while (0) +#else +#define CHEEVOS_LOCK(l) +#define CHEEVOS_UNLOCK(l) +#endif + +/***************************************************************************** +Supporting functions. +*****************************************************************************/ + +#ifndef CHEEVOS_VERBOSE + +void cheevos_log(const char *fmt, ...) +{ + (void)fmt; +} + +#endif + +static unsigned size_in_megabytes(unsigned val) +{ + return (val * 1024 * 1024); +} + +#ifdef CHEEVOS_LOG_URLS +static void cheevos_log_url(const char* format, const char* url) +{ +#ifdef CHEEVOS_LOG_PASSWORD + CHEEVOS_LOG(format, url); +#else + char copy[256]; + char* aux = NULL; + char* next = NULL; + + if (!string_is_empty(url)) + strlcpy(copy, url, sizeof(copy)); + + aux = strstr(copy, "?p="); + + if (!aux) + aux = strstr(copy, "&p="); + + if (aux) + { + aux += 3; + next = strchr(aux, '&'); + + if (next) + { + do + { + *aux++ = *next++; + }while (next[-1] != 0); + } + else + *aux = 0; + } + + aux = strstr(copy, "?t="); + + if (!aux) + aux = strstr(copy, "&t="); + + if (aux) + { + aux += 3; + next = strchr(aux, '&'); + + if (next) + { + do + { + *aux++ = *next++; + }while (next[-1] != 0); + } + else + *aux = 0; + } + + CHEEVOS_LOG(format, copy); +#endif +} +#endif + +static uint32_t cheevos_djb2(const char* str, size_t length) +{ + const unsigned char *aux = (const unsigned char*)str; + const unsigned char *end = aux + length; + uint32_t hash = 5381; + + while (aux < end) + hash = (hash << 5) + hash + *aux++; + + return hash; +} + +static int cheevos_getvalue__json_key(void *userdata, + const char *name, size_t length) +{ + cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; + + if (ud) + ud->is_key = cheevos_djb2(name, length) == ud->key_hash; + return 0; +} + +static int cheevos_getvalue__json_string(void *userdata, + const char *string, size_t length) +{ + cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; + + if (ud && ud->is_key) + { + ud->value = string; + ud->length = length; + ud->is_key = 0; + } + + return 0; +} + +static int cheevos_getvalue__json_boolean(void *userdata, int istrue) +{ + cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; + + if (ud && ud->is_key) + { + if (istrue) + { + ud->value = "true"; + ud->length = 4; + } + else + { + ud->value = "false"; + ud->length = 5; + } + ud->is_key = 0; + } + + return 0; +} + +static int cheevos_getvalue__json_null(void *userdata) +{ + cheevos_getvalueud_t* ud = (cheevos_getvalueud_t*)userdata; + + if (ud && ud->is_key ) + { + ud->value = "null"; + ud->length = 4; + ud->is_key = 0; + } + + return 0; +} + +static int cheevos_get_value(const char *json, unsigned key_hash, + char *value, size_t length) +{ + static const jsonsax_handlers_t handlers = + { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + cheevos_getvalue__json_key, + NULL, + cheevos_getvalue__json_string, + cheevos_getvalue__json_string, /* number */ + cheevos_getvalue__json_boolean, + cheevos_getvalue__json_null + }; + + cheevos_getvalueud_t ud; + + ud.key_hash = key_hash; + ud.is_key = 0; + ud.value = NULL; + ud.length = 0; + *value = 0; + + if ((jsonsax_parse(json, &handlers, (void*)&ud) == JSONSAX_OK) + && ud.value && ud.length < length) + { + if (!string_is_empty(ud.value)) + strlcpy(value, ud.value, ud.length + 1); + return 0; + } + + return -1; +} + +/***************************************************************************** +Count number of achievements in a JSON file. +*****************************************************************************/ + +static int cheevos_count__json_end_array(void *userdata) +{ + cheevos_countud_t* ud = (cheevos_countud_t*)userdata; + + if (ud) + { + ud->in_cheevos = 0; + ud->in_lboards = 0; + } + + return 0; +} + +static int cheevos_count__json_key(void *userdata, + const char *name, size_t length) +{ + cheevos_countud_t* ud = (cheevos_countud_t*)userdata; + + if (ud) + { + ud->field_hash = cheevos_djb2(name, length); + if (ud->field_hash == CHEEVOS_JSON_KEY_ACHIEVEMENTS) + ud->in_cheevos = 1; + else if (ud->field_hash == CHEEVOS_JSON_KEY_LEADERBOARDS) + ud->in_lboards = 1; + } + + return 0; +} + +static int cheevos_count__json_number(void *userdata, + const char *number, size_t length) +{ + cheevos_countud_t* ud = (cheevos_countud_t*)userdata; + + if (ud) + { + if (ud->in_cheevos && ud->field_hash == CHEEVOS_JSON_KEY_FLAGS) + { + long flags = strtol(number, NULL, 10); + + if (flags == 3) + ud->core_count++; /* Core achievements */ + else if (flags == 5) + ud->unofficial_count++; /* Unofficial achievements */ + } + else if (ud->in_lboards && ud->field_hash == CHEEVOS_JSON_KEY_ID) + ud->lboard_count++; + } + + return 0; +} + +static int cheevos_count_cheevos(const char *json, + unsigned *core_count, unsigned *unofficial_count, + unsigned *lboard_count) +{ + static const jsonsax_handlers_t handlers = + { + NULL, + NULL, + NULL, + NULL, + NULL, + cheevos_count__json_end_array, + cheevos_count__json_key, + NULL, + NULL, + cheevos_count__json_number, + NULL, + NULL + }; + + int res; + cheevos_countud_t ud; + ud.in_cheevos = 0; + ud.in_lboards = 0; + ud.core_count = 0; + ud.unofficial_count = 0; + ud.lboard_count = 0; + + res = jsonsax_parse(json, &handlers, (void*)&ud); + + *core_count = ud.core_count; + *unofficial_count = ud.unofficial_count; + *lboard_count = ud.lboard_count; + + return res; +} + +/***************************************************************************** +Parse the MemAddr field. +*****************************************************************************/ + +static unsigned cheevos_count_cond_sets(const char *memaddr) +{ + cheevos_cond_t cond; + unsigned count = 0; + + for (;;) + { + count++; + + for (;;) + { + cheevos_cond_parse(&cond, &memaddr); + + if (*memaddr != '_') + break; + + memaddr++; + } + + if (*memaddr != 'S') + break; + + memaddr++; + } + + return count; +} + +static int cheevos_parse_condition( + cheevos_condition_t *condition, + const char* memaddr) +{ + if (!condition) + return 0; + + condition->count = cheevos_count_cond_sets(memaddr); + + if (condition->count) + { + unsigned set = 0; + const cheevos_condset_t* end = NULL; + cheevos_condset_t *conds = NULL; + cheevos_condset_t *condset = NULL; + cheevos_condset_t *condsets = (cheevos_condset_t*) + calloc(condition->count, sizeof(cheevos_condset_t)); + + (void)conds; + + if (!condsets) + return -1; + + condition->condsets = condsets; + end = condition->condsets + condition->count; + + for (condset = condition->condsets; condset < end; condset++, set++) + { + condset->count = + cheevos_cond_count_in_set(memaddr, set); + condset->conds = NULL; + + CHEEVOS_LOG("[CHEEVOS]: set %p (index=%u)\n", condset, set); + CHEEVOS_LOG("[CHEEVOS]: conds: %u\n", condset->count); + + if (condset->count) + { + cheevos_cond_t *conds = (cheevos_cond_t*) + calloc(condset->count, sizeof(cheevos_cond_t)); + + if (!conds) + { + while (--condset >= condition->condsets) + { + if ((void*)condset->conds) + free((void*)condset->conds); + } + + return -1; + } + + condset->conds = conds; + cheevos_cond_parse_in_set(condset->conds, memaddr, set); + } + } + } + + return 0; +} + +static void cheevos_free_condition(cheevos_condition_t* condition) +{ + unsigned i; + + if (!condition) + return; + + if (condition->condsets) + { + for (i = 0; i < condition->count; i++) + { + if (condition->condsets[i].conds) + { + free(condition->condsets[i].conds); + condition->condsets[i].conds = NULL; + } + } + + if (condition->condsets) + { + free(condition->condsets); + condition->condsets = NULL; + } + } +} + +/***************************************************************************** +Parse the Mem field of leaderboards. +*****************************************************************************/ + +static int cheevos_parse_expression(cheevos_expr_t *expr, const char* mem) +{ + unsigned i; + const char *aux; + cheevos_term_t *terms = NULL; + char *end = NULL; + + if (!expr) + return -1; + + expr->count = 1; + expr->compare_count = 1; + + for (aux = mem;; aux++) + { + if (*aux == '"' || *aux == ':') + break; + expr->count += *aux == '_'; + } + + if (expr->count > 0) + terms = (cheevos_term_t*) + calloc(expr->count, sizeof(cheevos_term_t)); + + if (!terms) + return -1; + + expr->terms = terms; + + for (i = 0; i < expr->count; i++) + { + expr->terms[i].compare_next = false; + expr->terms[i].multiplier = 1; + } + + for (i = 0, aux = mem; i < expr->count;) + { + cheevos_var_parse(&expr->terms[i].var, &aux); + + if (*aux != '*') + { + /* expression has no multiplier */ + if (*aux == '_') + { + aux++; + i++; + } + else if (*aux == '$') + { + expr->terms[i].compare_next = true; + expr->compare_count++; + aux++; + i++; + } + + /* no multiplier at end of string */ + else if (*aux == '\0' || *aux == '"' || *aux == ',') + return 0; + + /* invalid character in expression */ + else + { + if (expr->terms) + { + free(expr->terms); + expr->terms = NULL; + } + return -1; + } + } + else + { + if (aux[1] == 'h' || aux[1] == 'H') + expr->terms[i].multiplier = (double)strtol(aux + 2, &end, 16); + else + expr->terms[i].multiplier = strtod(aux + 1, &end); + aux = end; + + if (*aux == '$') + { + aux++; + expr->terms[i].compare_next = true; + expr->compare_count++; + } + else + expr->terms[i].compare_next = false; + + aux++; + i++; + } + } + return 0; +} + +static int cheevos_parse_mem(cheevos_leaderboard_t *lb, const char* mem) +{ + lb->start.condsets = NULL; + lb->cancel.condsets = NULL; + lb->submit.condsets = NULL; + lb->value.terms = NULL; + + for (;;) + { + if (*mem == 'S' && mem[1] == 'T' && mem[2] == 'A' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->start, mem + 4)) + goto error; + } + else if (*mem == 'C' && mem[1] == 'A' && mem[2] == 'N' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->cancel, mem + 4)) + goto error; + } + else if (*mem == 'S' && mem[1] == 'U' && mem[2] == 'B' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->submit, mem + 4)) + goto error; + } + else if (*mem == 'V' && mem[1] == 'A' && mem[2] == 'L' && mem[3] == ':') + { + if (cheevos_parse_expression(&lb->value, mem + 4)) + goto error; + } + + for (mem += 4;; mem++) + { + if (*mem == ':' && mem[1] == ':') + { + mem += 2; + break; + } + else if (*mem == '"') + return 0; + } + } + +error: + cheevos_free_condition(&lb->start); + cheevos_free_condition(&lb->cancel); + cheevos_free_condition(&lb->submit); + if (lb->value.terms) + { + free((void*)lb->value.terms); + lb->value.terms = NULL; + } + return -1; +} + +/***************************************************************************** +Load achievements from a JSON string. +*****************************************************************************/ + +static INLINE const char *cheevos_dupstr(const cheevos_field_t *field) +{ + char *string = (char*)malloc(field->length + 1); + + if (!string) + return NULL; + + memcpy ((void*)string, (void*)field->string, field->length); + string[field->length] = 0; + + return string; +} + +static int cheevos_new_cheevo(cheevos_readud_t *ud) +{ + cheevo_t *cheevo = NULL; + long flags = strtol(ud->flags.string, NULL, 10); + + if (flags == 3) + cheevo = cheevos_locals.core.cheevos + ud->core_count++; + else if (flags == 5) + cheevo = cheevos_locals.unofficial.cheevos + ud->unofficial_count++; + else + return 0; + + cheevo->id = (unsigned)strtol(ud->id.string, NULL, 10); + cheevo->title = cheevos_dupstr(&ud->title); + cheevo->description = cheevos_dupstr(&ud->desc); + cheevo->author = cheevos_dupstr(&ud->author); + cheevo->badge = cheevos_dupstr(&ud->badge); + cheevo->points = (unsigned)strtol(ud->points.string, NULL, 10); + cheevo->dirty = 0; + cheevo->active = CHEEVOS_ACTIVE_SOFTCORE | CHEEVOS_ACTIVE_HARDCORE; + cheevo->last = 1; + cheevo->modified = 0; + + if ( !cheevo->title || + !cheevo->description || + !cheevo->author || + !cheevo->badge) + goto error; + + if (cheevos_parse_condition(&cheevo->condition, ud->memaddr.string)) + goto error; + + return 0; + +error: + if (cheevo->title) + { + free((void*)cheevo->title); + cheevo->title = NULL; + } + if (cheevo->description) + { + free((void*)cheevo->description); + cheevo->description = NULL; + } + if (cheevo->author) + { + free((void*)cheevo->author); + cheevo->author = NULL; + } + if (cheevo->badge) + { + free((void*)cheevo->badge); + cheevo->badge = NULL; + } + return -1; +} + +/***************************************************************************** +Helper functions for displaying leaderboard values. +*****************************************************************************/ + +static void cheevos_format_value(const unsigned value, const unsigned type, + char* formatted_value, size_t formatted_size) +{ + unsigned mins, secs, millis; + + switch(type) + { + case CHEEVOS_FORMAT_VALUE: + snprintf(formatted_value, formatted_size, "%u", value); + break; + + case CHEEVOS_FORMAT_SCORE: + snprintf(formatted_value, formatted_size, + "%06upts", value); + break; + + case CHEEVOS_FORMAT_FRAMES: + mins = value / 3600; + secs = (value % 3600) / 60; + millis = (int) (value % 60) * (10.00 / 6.00); + snprintf(formatted_value, formatted_size, + "%02u:%02u.%02u", mins, secs, millis); + break; + + case CHEEVOS_FORMAT_MILLIS: + mins = value / 6000; + secs = (value % 6000) / 100; + millis = (int) (value % 100); + snprintf(formatted_value, formatted_size, + "%02u:%02u.%02u", mins, secs, millis); + break; + + case CHEEVOS_FORMAT_SECS: + mins = value / 60; + secs = value % 60; + snprintf(formatted_value, formatted_size, + "%02u:%02u", mins, secs); + break; + + default: + snprintf(formatted_value, formatted_size, + "%u (?)", value); + } +} + +unsigned cheevos_parse_format(cheevos_field_t* format) +{ + /* Most likely */ + if (strncmp(format->string, "VALUE", format->length) == 0) + return CHEEVOS_FORMAT_VALUE; + else if (strncmp(format->string, "TIME", format->length) == 0) + return CHEEVOS_FORMAT_FRAMES; + else if (strncmp(format->string, "SCORE", format->length) == 0) + return CHEEVOS_FORMAT_SCORE; + + /* Less likely */ + else if (strncmp(format->string, "MILLISECS", format->length) == 0) + return CHEEVOS_FORMAT_MILLIS; + else if (strncmp(format->string, "TIMESECS", format->length) == 0) + return CHEEVOS_FORMAT_SECS; + + /* Rare (RPS only) */ + else if (strncmp(format->string, "POINTS", format->length) == 0) + return CHEEVOS_FORMAT_SCORE; + else if (strncmp(format->string, "FRAMES", format->length) == 0) + return CHEEVOS_FORMAT_FRAMES; + else + return CHEEVOS_FORMAT_OTHER; +} + +static int cheevos_new_lboard(cheevos_readud_t *ud) +{ + cheevos_leaderboard_t *lboard = NULL; + cheevos_leaderboard_t *ldb = cheevos_locals.leaderboards; + + if (!ldb || !ud) + return -1; + + lboard = ldb + ud->lboard_count++; + + lboard->id = (unsigned)strtol(ud->id.string, NULL, 10); + lboard->format = cheevos_parse_format(&ud->format); + lboard->title = cheevos_dupstr(&ud->title); + lboard->description = cheevos_dupstr(&ud->desc); + + if (!lboard->title || !lboard->description) + goto error; + + if (cheevos_parse_mem(lboard, ud->memaddr.string)) + goto error; + + return 0; + +error: + if ((void*)lboard->title) + free((void*)lboard->title); + if ((void*)lboard->description) + free((void*)lboard->description); + return -1; +} + +static int cheevos_read__json_key( void *userdata, + const char *name, size_t length) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud) + { + int common = ud->in_cheevos || ud->in_lboards; + uint32_t hash = cheevos_djb2(name, length); + ud->field = NULL; + + switch (hash) + { + case CHEEVOS_JSON_KEY_ACHIEVEMENTS: + ud->in_cheevos = 1; + break; + case CHEEVOS_JSON_KEY_LEADERBOARDS: + ud->in_lboards = 1; + break; + case CHEEVOS_JSON_KEY_CONSOLE_ID: + ud->is_console_id = 1; + break; + case CHEEVOS_JSON_KEY_ID: + if (common) + ud->field = &ud->id; + break; + case CHEEVOS_JSON_KEY_MEMADDR: + if (ud->in_cheevos) + ud->field = &ud->memaddr; + break; + case CHEEVOS_JSON_KEY_MEM: + if (ud->in_lboards) + ud->field = &ud->memaddr; + break; + case CHEEVOS_JSON_KEY_TITLE: + if (common) + ud->field = &ud->title; + break; + case CHEEVOS_JSON_KEY_DESCRIPTION: + if (common) + ud->field = &ud->desc; + break; + case CHEEVOS_JSON_KEY_POINTS: + if (ud->in_cheevos) + ud->field = &ud->points; + break; + case CHEEVOS_JSON_KEY_AUTHOR: + if (ud->in_cheevos) + ud->field = &ud->author; + break; + case CHEEVOS_JSON_KEY_MODIFIED: + if (ud->in_cheevos) + ud->field = &ud->modified; + break; + case CHEEVOS_JSON_KEY_CREATED: + if (ud->in_cheevos) + ud->field = &ud->created; + break; + case CHEEVOS_JSON_KEY_BADGENAME: + if (ud->in_cheevos) + ud->field = &ud->badge; + break; + case CHEEVOS_JSON_KEY_FLAGS: + if (ud->in_cheevos) + ud->field = &ud->flags; + break; + case CHEEVOS_JSON_KEY_FORMAT: + if (ud->in_lboards) + ud->field = &ud->format; + break; + default: + break; + } + } + + return 0; +} + +static int cheevos_read__json_string(void *userdata, + const char *string, size_t length) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud && ud->field) + { + ud->field->string = string; + ud->field->length = length; + } + + return 0; +} + +static int cheevos_read__json_number(void *userdata, + const char *number, size_t length) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud) + { + if (ud->field) + { + ud->field->string = number; + ud->field->length = length; + } + else if (ud->is_console_id) + { + cheevos_locals.console_id = (cheevos_console_t) + strtol(number, NULL, 10); + ud->is_console_id = 0; + } + } + + return 0; +} + +static int cheevos_read__json_end_object(void *userdata) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud) + { + if (ud->in_cheevos) + return cheevos_new_cheevo(ud); + if (ud->in_lboards) + return cheevos_new_lboard(ud); + } + + return 0; +} + +static int cheevos_read__json_end_array(void *userdata) +{ + cheevos_readud_t *ud = (cheevos_readud_t*)userdata; + + if (ud) + { + ud->in_cheevos = 0; + ud->in_lboards = 0; + } + + return 0; +} + +static int cheevos_parse(const char *json) +{ + static const jsonsax_handlers_t handlers = + { + NULL, + NULL, + NULL, + cheevos_read__json_end_object, + NULL, + cheevos_read__json_end_array, + cheevos_read__json_key, + NULL, + cheevos_read__json_string, + cheevos_read__json_number, + NULL, + NULL + }; + + cheevos_readud_t ud; + unsigned core_count, unofficial_count, lboard_count; + /* Count the number of achievements in the JSON file. */ + int res = cheevos_count_cheevos(json, &core_count, &unofficial_count, + &lboard_count); + + if (res != JSONSAX_OK) + return -1; + + /* Allocate the achievements. */ + + cheevos_locals.core.cheevos = (cheevo_t*) + calloc(core_count, sizeof(cheevo_t)); + cheevos_locals.core.count = core_count; + + cheevos_locals.unofficial.cheevos = (cheevo_t*) + calloc(unofficial_count, sizeof(cheevo_t)); + cheevos_locals.unofficial.count = unofficial_count; + + cheevos_locals.leaderboards = (cheevos_leaderboard_t*) + calloc(lboard_count, sizeof(cheevos_leaderboard_t)); + cheevos_locals.lboard_count = lboard_count; + + if ( !cheevos_locals.core.cheevos || + !cheevos_locals.unofficial.cheevos || + !cheevos_locals.leaderboards) + { + if ((void*)cheevos_locals.core.cheevos) + free((void*)cheevos_locals.core.cheevos); + if ((void*)cheevos_locals.unofficial.cheevos) + free((void*)cheevos_locals.unofficial.cheevos); + if ((void*)cheevos_locals.leaderboards) + free((void*)cheevos_locals.leaderboards); + cheevos_locals.core.count = cheevos_locals.unofficial.count = + cheevos_locals.lboard_count = 0; + + return -1; + } + + /* Load the achievements. */ + ud.in_cheevos = 0; + ud.in_lboards = 0; + ud.is_console_id = 0; + ud.field = NULL; + ud.core_count = 0; + ud.unofficial_count = 0; + ud.lboard_count = 0; + + if (jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK) + goto error; + + return 0; + +error: + cheevos_unload(); + + return -1; +} + +/***************************************************************************** +Test all the achievements (call once per frame). +*****************************************************************************/ + +static int cheevos_test_condition(cheevos_cond_t *cond) +{ + unsigned sval = 0; + unsigned tval = 0; + + if (!cond) + return 0; + + sval = cheevos_var_get_value(&cond->source) + + cheevos_locals.add_buffer; + tval = cheevos_var_get_value(&cond->target); + + switch (cond->op) + { + case CHEEVOS_COND_OP_EQUALS: + return (sval == tval); + case CHEEVOS_COND_OP_LESS_THAN: + return (sval < tval); + case CHEEVOS_COND_OP_LESS_THAN_OR_EQUAL: + return (sval <= tval); + case CHEEVOS_COND_OP_GREATER_THAN: + return (sval > tval); + case CHEEVOS_COND_OP_GREATER_THAN_OR_EQUAL: + return (sval >= tval); + case CHEEVOS_COND_OP_NOT_EQUAL_TO: + return (sval != tval); + default: + break; + } + + return 1; +} + +static int cheevos_test_pause_cond_set(const cheevos_condset_t *condset, + int *dirty_conds, int *reset_conds, int process_pause) +{ + int cond_valid = 0; + int set_valid = 1; /* must start true so AND logic works */ + cheevos_cond_t *cond = NULL; + const cheevos_cond_t *end = condset->conds + condset->count; + + cheevos_locals.add_buffer = 0; + cheevos_locals.add_hits = 0; + + for (cond = condset->conds; cond < end; cond++) + { + if (cond->pause != process_pause) + continue; + + if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE) + { + cheevos_locals.add_buffer += cheevos_var_get_value(&cond->source); + continue; + } + + if (cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE) + { + cheevos_locals.add_buffer -= cheevos_var_get_value(&cond->source); + continue; + } + + if (cond->type == CHEEVOS_COND_TYPE_ADD_HITS) + { + if (cheevos_test_condition(cond)) + { + cond->curr_hits++; + *dirty_conds = 1; + } + + cheevos_locals.add_hits += cond->curr_hits; + continue; + } + + /* always evaluate the condition to ensure delta values get tracked correctly */ + cond_valid = cheevos_test_condition(cond); + + /* if the condition has a target hit count that has already been met, + * it's automatically true, even if not currently true. */ + if ( (cond->req_hits != 0) && + (cond->curr_hits + cheevos_locals.add_hits) >= cond->req_hits) + { + cond_valid = 1; + } + else if (cond_valid) + { + cond->curr_hits++; + *dirty_conds = 1; + + /* Process this logic, if this condition is true: */ + if (cond->req_hits == 0) + ; /* Not a hit-based requirement: ignore any additional logic! */ + else if ((cond->curr_hits + cheevos_locals.add_hits) < cond->req_hits) + cond_valid = 0; /* HitCount target has not yet been met, condition is not yet valid. */ + } + + cheevos_locals.add_buffer = 0; + cheevos_locals.add_hits = 0; + + if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF) + { + /* as soon as we find a PauseIf that evaluates to true, + * stop processing the rest of the group. */ + if (cond_valid) + return 1; + + /* if we make it to the end of the function, make sure we are + * indicating nothing matched. if we do find a later PauseIf match, + * it'll automatically return true via the previous condition. */ + set_valid = 0; + + if (cond->req_hits == 0) + { + /* PauseIf didn't evaluate true, and doesn't have a HitCount, + * reset the HitCount to indicate the condition didn't match. */ + if (cond->curr_hits != 0) + { + cond->curr_hits = 0; + *dirty_conds = 1; + } + } + else + { + /* PauseIf has a HitCount that hasn't been met, ignore it for now. */ + } + } + else if (cond->type == CHEEVOS_COND_TYPE_RESET_IF) + { + if (cond_valid) + { + *reset_conds = 1; /* Resets all hits found so far */ + set_valid = 0; /* Cannot be valid if we've hit a reset condition. */ + } + } + else /* Sequential or non-sequential? */ + set_valid &= cond_valid; + } + + return set_valid; +} + +static int cheevos_test_cond_set(const cheevos_condset_t *condset, + int *dirty_conds, int *reset_conds) +{ + int in_pause = 0; + int has_pause = 0; + cheevos_cond_t *cond = NULL; + + if (!condset) + return 1; /* important: empty group must evaluate true */ + + /* the ints below are used for Pause conditions and their dependent AddSource/AddHits. */ + + /* this loop needs to go backwards to check AddSource/AddHits */ + cond = condset->conds + condset->count - 1; + for (; cond >= condset->conds; cond--) + { + if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF) + { + has_pause = 1; + in_pause = 1; + cond->pause = 1; + } + else if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE || + cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE || + cond->type == CHEEVOS_COND_TYPE_ADD_HITS) + { + cond->pause = in_pause; + } + else + { + in_pause = 0; + cond->pause = 0; + } + } + + if (has_pause) + { /* one or more Pause conditions exists, if any of them are true, + * stop processing this group. */ + if (cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 1)) + return 0; + } + + /* process the non-Pause conditions to see if the group is true */ + return cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 0); +} + +static int cheevos_reset_cond_set(cheevos_condset_t *condset, int deltas) +{ + int dirty = 0; + const cheevos_cond_t *end = NULL; + + if (!condset) + return 0; + + end = condset->conds + condset->count; + + if (deltas) + { + cheevos_cond_t *cond = NULL; + for (cond = condset->conds; cond < end; cond++) + { + dirty |= cond->curr_hits != 0; + + cond->curr_hits = 0; + + cond->source.previous = cond->source.value; + cond->target.previous = cond->target.value; + } + } + else + { + cheevos_cond_t *cond = NULL; + for (cond = condset->conds; cond < end; cond++) + { + dirty |= cond->curr_hits != 0; + cond->curr_hits = 0; + } + } + + return dirty; +} + +static int cheevos_test_cheevo(cheevo_t *cheevo) +{ + int dirty_conds = 0; + int reset_conds = 0; + int ret_val = 0; + int ret_val_sub_cond = 0; + cheevos_condset_t *condset = NULL; + cheevos_condset_t *end = NULL; + + if (!cheevo) + return 0; + + ret_val_sub_cond = cheevo->condition.count == 1; + condset = cheevo->condition.condsets; + + if (!condset) + return 0; + + end = condset + cheevo->condition.count; + + if (condset < end) + { + ret_val = cheevos_test_cond_set(condset, &dirty_conds, &reset_conds); + condset++; + } + + while (condset < end) + { + ret_val_sub_cond |= cheevos_test_cond_set( + condset, &dirty_conds, &reset_conds); + condset++; + } + + if (dirty_conds) + cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS; + + if (reset_conds) + { + int dirty = 0; + + for (condset = cheevo->condition.condsets; condset < end; condset++) + dirty |= cheevos_reset_cond_set(condset, 0); + + if (dirty) + cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS; + } + + return (ret_val && ret_val_sub_cond); +} + +static void cheevos_url_encode(const char *str, char *encoded, size_t len) +{ + if (!str) + return; + + while (*str) + { + if ( isalnum((unsigned char)*str) || *str == '-' + || *str == '_' || *str == '.' + || *str == '~') + { + if (len >= 2) + { + *encoded++ = *str++; + len--; + } + else + break; + } + else + { + if (len >= 4) + { + snprintf(encoded, len, "%%%02x", (uint8_t)*str); + encoded += 3; + str++; + len -= 3; + } + else + break; + } + } + + *encoded = 0; +} + +static void cheevos_make_unlock_url(const cheevo_t *cheevo, + char* url, size_t url_size) +{ + settings_t *settings = config_get_ptr(); + + if (!settings) + return; + + snprintf( + url, url_size, + "http://retroachievements.org/dorequest.php?r=awardachievement&u=%s&t=%s&a=%u&h=%d", + settings->arrays.cheevos_username, + cheevos_locals.token, + cheevo->id, + settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused ? 1 : 0 + ); + + url[url_size - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to award the cheevo: %s\n", url); +#endif +} + +static void cheevos_unlocked(void *task_data, void *user_data, + const char *error) +{ + cheevo_t *cheevo = (cheevo_t *)user_data; + + if (!error) + { + CHEEVOS_LOG("[CHEEVOS]: awarded achievement %u.\n", cheevo->id); + } + else + { + char url[256]; + url[0] = '\0'; + + CHEEVOS_ERR("[CHEEVOS]: error awarding achievement %u, retrying...\n", cheevo->id); + + cheevos_make_unlock_url(cheevo, url, sizeof(url)); + task_push_http_transfer(url, true, NULL, cheevos_unlocked, cheevo); + } +} + +static void cheevos_test_cheevo_set(const cheevoset_t *set) +{ + settings_t *settings = config_get_ptr(); + int mode = CHEEVOS_ACTIVE_SOFTCORE; + cheevo_t *cheevo = NULL; + const cheevo_t *end = NULL; + + if (!set) + return; + + end = set->cheevos + set->count; + + if (settings && settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) + mode = CHEEVOS_ACTIVE_HARDCORE; + + for (cheevo = set->cheevos; cheevo < end; cheevo++) + { + if (cheevo->active & mode) + { + int valid = cheevos_test_cheevo(cheevo); + + if (cheevo->last) + { + cheevos_condset_t* condset = cheevo->condition.condsets; + const cheevos_condset_t* end = cheevo->condition.condsets + + cheevo->condition.count; + + for (; condset < end; condset++) + cheevos_reset_cond_set(condset, 0); + } + else if (valid) + { + char msg[256]; + char url[256]; + msg[0] = url[0] = '\0'; + + cheevo->active &= ~mode; + + if (mode == CHEEVOS_ACTIVE_HARDCORE) + cheevo->active &= ~CHEEVOS_ACTIVE_SOFTCORE; + + CHEEVOS_LOG("[CHEEVOS]: awarding cheevo %u: %s (%s).\n", + cheevo->id, cheevo->title, cheevo->description); + + snprintf(msg, sizeof(msg), "Achievement Unlocked: %s", + cheevo->title); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 2 * 60, false); + runloop_msg_queue_push(cheevo->description, 0, 3 * 60, false); + + cheevos_make_unlock_url(cheevo, url, sizeof(url)); + task_push_http_transfer(url, true, NULL, + cheevos_unlocked, cheevo); + + if (settings && settings->bools.cheevos_auto_screenshot) + { + char shotname[256]; + + snprintf(shotname, sizeof(shotname), "%s/%s-cheevo-%u", + settings->paths.directory_screenshot, + path_basename(path_get(RARCH_PATH_BASENAME)), + cheevo->id); + shotname[sizeof(shotname) - 1] = '\0'; + + if (take_screenshot(shotname, true, + video_driver_cached_frame_has_valid_framebuffer(), false, true)) + CHEEVOS_LOG("[CHEEVOS]: got a screenshot for cheevo %u\n", cheevo->id); + else + CHEEVOS_LOG("[CHEEVOS]: failed to get screenshot for cheevo %u\n", cheevo->id); + } + } + + cheevo->last = valid; + } + } +} + +static int cheevos_test_lboard_condition(const cheevos_condition_t* condition) +{ + int dirty_conds = 0; + int reset_conds = 0; + int ret_val = 0; + int ret_val_sub_cond = 0; + cheevos_condset_t *condset = NULL; + const cheevos_condset_t *end = NULL; + + if (!condition) + return 0; + + ret_val_sub_cond = condition->count == 1; + condset = condition->condsets; + end = condset + condition->count; + + if (condset < end) + { + ret_val = cheevos_test_cond_set( + condset, &dirty_conds, &reset_conds); + condset++; + } + + while (condset < end) + { + ret_val_sub_cond |= cheevos_test_cond_set( + condset, &dirty_conds, &reset_conds); + condset++; + } + + if (reset_conds) + { + for (condset = condition->condsets; condset < end; condset++) + cheevos_reset_cond_set(condset, 0); + } + + return (ret_val && ret_val_sub_cond); +} + +static int cheevos_expr_value(cheevos_expr_t* expr) +{ + unsigned i; + int values[16]; + /* Separate possible values with '$' operator, submit the largest */ + unsigned current_value = 0; + cheevos_term_t* term = NULL; + + if (!expr) + return 0; + + term = expr->terms; + + if (!term) + return 0; + + if (expr->compare_count >= ARRAY_SIZE(values)) + { + CHEEVOS_ERR("[CHEEVOS]: too many values in the leaderboard expression: %u\n", expr->compare_count); + return 0; + } + + memset(values, 0, sizeof values); + + for (i = expr->count; i != 0; i--, term++) + { + if (current_value >= ARRAY_SIZE(values)) + { + CHEEVOS_ERR("[CHEEVOS]: too many values in the leaderboard expression: %u\n", current_value); + return 0; + } + + values[current_value] += + cheevos_var_get_value(&term->var) * term->multiplier; + + if (term->compare_next) + current_value++; + } + + if (expr->compare_count > 1) + { + unsigned j; + int maximum = values[0]; + + for (j = 1; j < expr->compare_count; j++) + maximum = values[j] > maximum ? values[j] : maximum; + + return maximum; + } + else + return values[0]; +} + +static void cheevos_make_lboard_url(const cheevos_leaderboard_t *lboard, + char* url, size_t url_size) +{ + MD5_CTX ctx; + uint8_t hash[16]; + char signature[64]; + settings_t *settings = config_get_ptr(); + + hash[0] = '\0'; + + snprintf(signature, sizeof(signature), "%u%s%u", lboard->id, + settings->arrays.cheevos_username, + lboard->id); + + MD5_Init(&ctx); + MD5_Update(&ctx, (void*)signature, strlen(signature)); + MD5_Final(hash, &ctx); + + snprintf( + url, url_size, + "http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d" + "&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + settings->arrays.cheevos_username, + cheevos_locals.token, + lboard->id, + lboard->last_value, + hash[ 0], hash[ 1], hash[ 2], hash[ 3], + hash[ 4], hash[ 5], hash[ 6], hash[ 7], + hash[ 8], hash[ 9], hash[10], hash[11], + hash[12], hash[13], hash[14], hash[15] + ); + + url[url_size - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to submit the leaderboard: %s\n", url); +#endif +} + +static void cheevos_lboard_submit(void *task_data, void *user_data, + const char *error) +{ + cheevos_leaderboard_t *lboard = (cheevos_leaderboard_t *)user_data; + + if (!lboard) + return; + + if (!error) + { + CHEEVOS_ERR("[CHEEVOS]: error submitting leaderboard %u\n", lboard->id); + return; + } + + CHEEVOS_LOG("[CHEEVOS]: submitted leaderboard %u.\n", lboard->id); +} + +static void cheevos_test_leaderboards(void) +{ + unsigned i; + cheevos_leaderboard_t* lboard = cheevos_locals.leaderboards; + + if (!lboard) + return; + + for (i = cheevos_locals.lboard_count; i != 0; i--, lboard++) + { + if (lboard->active) + { + int value = cheevos_expr_value(&lboard->value); + + if (value != lboard->last_value) + { + CHEEVOS_LOG("[CHEEVOS]: value lboard %s %u\n", + lboard->title, value); + lboard->last_value = value; + } + + if (cheevos_test_lboard_condition(&lboard->submit)) + { + lboard->active = 0; + + /* failsafe for improper LBs */ + if (value == 0) + { + CHEEVOS_LOG("[CHEEVOS]: error: lboard %s tried to submit 0\n", + lboard->title); + runloop_msg_queue_push("Leaderboard attempt cancelled!", + 0, 2 * 60, false); + } + else + { + char url[256]; + char msg[256]; + char formatted_value[16]; + + cheevos_make_lboard_url(lboard, url, sizeof(url)); + task_push_http_transfer(url, true, NULL, + cheevos_lboard_submit, lboard); + CHEEVOS_LOG("[CHEEVOS]: submit lboard %s\n", lboard->title); + + cheevos_format_value(value, lboard->format, + formatted_value, sizeof(formatted_value)); + snprintf(msg, sizeof(msg), "Submitted %s for %s", + formatted_value, lboard->title); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 2 * 60, false); + } + } + + if (cheevos_test_lboard_condition(&lboard->cancel)) + { + CHEEVOS_LOG("[CHEEVOS]: cancel lboard %s\n", lboard->title); + lboard->active = 0; + runloop_msg_queue_push("Leaderboard attempt cancelled!", + 0, 2 * 60, false); + } + } + else + { + if (cheevos_test_lboard_condition(&lboard->start)) + { + char msg[256]; + + CHEEVOS_LOG("[CHEEVOS]: start lboard %s\n", lboard->title); + lboard->active = 1; + lboard->last_value = -1; + + snprintf(msg, sizeof(msg), + "Leaderboard Active: %s", lboard->title); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 2 * 60, false); + runloop_msg_queue_push(lboard->description, 0, 3*60, false); + } + } + } +} + +/***************************************************************************** +Free the loaded achievements. +*****************************************************************************/ + +static void cheevos_free_condset(const cheevos_condset_t *set) +{ + if (set && set->conds) + free((void*)set->conds); +} + +static void cheevos_free_cheevo(const cheevo_t *cheevo) +{ + if (!cheevo) + return; + + if (cheevo->title) + free((void*)cheevo->title); + if (cheevo->description) + free((void*)cheevo->description); + if (cheevo->author) + free((void*)cheevo->author); + if (cheevo->badge) + free((void*)cheevo->badge); + cheevos_free_condset(cheevo->condition.condsets); +} + +static void cheevos_free_cheevo_set(const cheevoset_t *set) +{ + const cheevo_t *cheevo = NULL; + const cheevo_t *end = NULL; + + if (!set) + return; + + cheevo = set->cheevos; + end = cheevo + set->count; + + while (cheevo < end) + cheevos_free_cheevo(cheevo++); + + if (set->cheevos) + free((void*)set->cheevos); +} + +#ifndef CHEEVOS_DONT_DEACTIVATE +static int cheevos_deactivate__json_index(void *userdata, unsigned int index) +{ + cheevos_deactivate_t *ud = (cheevos_deactivate_t*)userdata; + + if (ud) + ud->is_element = 1; + + return 0; +} + +static int cheevos_deactivate__json_number(void *userdata, + const char *number, size_t length) +{ + long id; + int found; + cheevo_t* cheevo = NULL; + const cheevo_t* end = NULL; + cheevos_deactivate_t *ud = (cheevos_deactivate_t*)userdata; + + if (ud && ud->is_element) + { + ud->is_element = 0; + id = strtol(number, NULL, 10); + found = 0; + cheevo = cheevos_locals.core.cheevos; + end = cheevo + cheevos_locals.core.count; + + for (; cheevo < end; cheevo++) + { + if (cheevo->id == (unsigned)id) + { + cheevo->active &= ~ud->mode; + found = 1; + break; + } + } + + if (!found) + { + cheevo = cheevos_locals.unofficial.cheevos; + end = cheevo + cheevos_locals.unofficial.count; + + for (; cheevo < end; cheevo++) + { + if (cheevo->id == (unsigned)id) + { + cheevo->active &= ~ud->mode; + found = 1; + break; + } + } + } + + if (found) + CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked cheevo %u (%s).\n", + cheevo->id, cheevo->title); + else + CHEEVOS_ERR("[CHEEVOS]: unknown cheevo to deactivate: %u.\n", id); + } + + return 0; +} + +static int cheevos_deactivate_unlocks(const char* json, unsigned mode) +{ + static const jsonsax_handlers_t handlers = + { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + cheevos_deactivate__json_index, + NULL, + cheevos_deactivate__json_number, + NULL, + NULL + }; + + cheevos_deactivate_t ud; + + ud.is_element = 0; + ud.mode = mode; + return jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK; +} +#endif + +void cheevos_reset_game(void) +{ + cheevo_t *end = NULL; + cheevo_t *cheevo = cheevos_locals.core.cheevos; + + if (!cheevo) + return; + + end = cheevo + cheevos_locals.core.count; + + for (; cheevo < end; cheevo++) + cheevo->last = 1; + + cheevo = cheevos_locals.unofficial.cheevos; + end = cheevo + cheevos_locals.unofficial.count; + + for (; cheevo < end; cheevo++) + cheevo->last = 1; +} + +void cheevos_populate_menu(void *data) +{ +#ifdef HAVE_MENU + unsigned i = 0; + unsigned items_found = 0; + settings_t *settings = config_get_ptr(); + menu_displaylist_info_t *info = (menu_displaylist_info_t*)data; + cheevo_t *end = NULL; + cheevo_t *cheevo = cheevos_locals.core.cheevos; + end = cheevo + cheevos_locals.core.count; + + if(settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable + && cheevos_loaded) + { + if (!cheevos_hardcore_paused) + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE), + msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE), + MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE, + MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0); + else + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME), + msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME), + MENU_ENUM_LABEL_ACHIEVEMENT_RESUME, + MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0); + } + + if (cheevo) + { + for (i = 0; cheevo < end; i++, cheevo++) + { + if (!(cheevo->active & CHEEVOS_ACTIVE_HARDCORE)) + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_HARDCORE)); + } + else if (!(cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)) + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); + } + else + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); + } + items_found++; + } + } + + cheevo = cheevos_locals.unofficial.cheevos; + + if (cheevo && settings->bools.cheevos_test_unofficial) + { + end = cheevo + cheevos_locals.unofficial.count; + + for (i = items_found; cheevo < end; i++, cheevo++) + { + if (!(cheevo->active & CHEEVOS_ACTIVE_HARDCORE)) + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY_HARDCORE, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_HARDCORE)); + } + else if (!(cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)) + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_UNLOCKED_ENTRY, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); + } + else + { + menu_entries_append_enum(info->list, cheevo->title, + cheevo->description, + MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY, + MENU_SETTINGS_CHEEVOS_START + i, 0, 0); + set_badge_info(&badges_ctx, i, cheevo->badge, + (cheevo->active & CHEEVOS_ACTIVE_SOFTCORE)); + } + items_found++; + } + } + + if (items_found == 0) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY), + msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY), + MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY, + FILE_TYPE_NONE, 0, 0); + } +#endif +} + +bool cheevos_get_description(cheevos_ctx_desc_t *desc) +{ + if (!desc) + return false; + + if (cheevos_loaded) + { + cheevo_t *cheevos = cheevos_locals.core.cheevos; + + if (!cheevos) + return false; + + if (desc->idx >= cheevos_locals.core.count) + { + cheevos = cheevos_locals.unofficial.cheevos; + desc->idx -= cheevos_locals.core.count; + } + + if (!string_is_empty(cheevos[desc->idx].description)) + strlcpy(desc->s, cheevos[desc->idx].description, desc->len); + } + else + *desc->s = 0; + + return true; +} + +bool cheevos_apply_cheats(bool *data_bool) +{ + cheats_are_enabled = *data_bool; + cheats_were_enabled |= cheats_are_enabled; + + return true; +} + +bool cheevos_unload(void) +{ + bool running; + CHEEVOS_LOCK(cheevos_locals.task_lock); + running = cheevos_locals.task != NULL; + CHEEVOS_UNLOCK(cheevos_locals.task_lock); + + if (running) + { + CHEEVOS_LOG("[CHEEVOS]: Asked the load thread to terminate\n"); + task_queue_cancel_task(cheevos_locals.task); + +#ifdef HAVE_THREADS + do + { + CHEEVOS_LOCK(cheevos_locals.task_lock); + running = cheevos_locals.task != NULL; + CHEEVOS_UNLOCK(cheevos_locals.task_lock); + } + while (running); +#endif + } + + if (cheevos_loaded) + { + cheevos_free_cheevo_set(&cheevos_locals.core); + cheevos_free_cheevo_set(&cheevos_locals.unofficial); + } + + cheevos_locals.core.cheevos = NULL; + cheevos_locals.unofficial.cheevos = NULL; + cheevos_locals.core.count = 0; + cheevos_locals.unofficial.count = 0; + + cheevos_loaded = false; + cheevos_hardcore_paused = false; + + return true; +} + +bool cheevos_toggle_hardcore_mode(void) +{ + settings_t *settings = config_get_ptr(); + + if (!settings) + return false; + + /* reset and deinit rewind to avoid cheat the score */ + if (settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) + { + const char *msg = msg_hash_to_str( + MSG_CHEEVOS_HARDCORE_MODE_ENABLE); + + /* send reset core cmd to avoid any user + * savestate previusly loaded. */ + command_event(CMD_EVENT_RESET, NULL); + + if (settings->bools.rewind_enable) + command_event(CMD_EVENT_REWIND_DEINIT, NULL); + + CHEEVOS_LOG("%s\n", msg); + runloop_msg_queue_push(msg, 0, 3 * 60, true); + } + else + { + if (settings->bools.rewind_enable) + command_event(CMD_EVENT_REWIND_INIT, NULL); + } + + return true; +} + +static void cheevos_patch_addresses(cheevoset_t* set) +{ + unsigned i; + cheevo_t* cheevo = NULL; + + if (!set) + return; + + cheevo = set->cheevos; + + if (!cheevo) + return; + + for (i = set->count; i != 0; i--, cheevo++) + { + unsigned j; + cheevos_condset_t* condset = cheevo->condition.condsets; + + for (j = cheevo->condition.count; j != 0; j--, condset++) + { + unsigned k; + cheevos_cond_t* cond = condset->conds; + + for (k = condset->count; k != 0; k--, cond++) + { + switch (cond->source.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&cond->source, + cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", + cond->source.bank_id + 1, cond->source.value); +#endif + break; + + default: + break; + } + + switch (cond->target.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&cond->target, + cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: t-var %03d:%08X\n", + cond->target.bank_id + 1, cond->target.value); +#endif + break; + + default: + break; + } + } + } + } +} + +static void cheevos_patch_lb_conditions(cheevos_condition_t* condition) +{ + unsigned i; + cheevos_condset_t* condset = NULL; + + if (!condition) + return; + + condset = condition->condsets; + + for (i = condition->count; i != 0; i--, condset++) + { + unsigned j; + cheevos_cond_t* cond = condset->conds; + + for (j = condset->count; j != 0; j--, cond++) + { + switch (cond->source.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&cond->source, + cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", + cond->source.bank_id + 1, cond->source.value); +#endif + break; + default: + break; + } + switch (cond->target.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&cond->target, + cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: t-var %03d:%08X\n", + cond->target.bank_id + 1, cond->target.value); +#endif + break; + default: + break; + } + } + } +} + +static void cheevos_patch_lb_expressions(cheevos_expr_t* expression) +{ + unsigned i; + cheevos_term_t* term = NULL; + + if (!expression) + return; + + term = expression->terms; + + for (i = expression->count; i != 0; i--, term++) + { + switch (term->var.type) + { + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_var_patch_addr(&term->var, cheevos_locals.console_id); +#ifdef CHEEVOS_DUMP_ADDRS + CHEEVOS_LOG("[CHEEVOS]: s-var %03d:%08X\n", + term->var.bank_id + 1, term->var.value); +#endif + break; + default: + break; + } + } +} + +static void cheevos_patch_lbs(cheevos_leaderboard_t *leaderboard) +{ + unsigned i; + + for (i = 0; i < cheevos_locals.lboard_count; i++) + { + cheevos_condition_t *start = &leaderboard[i].start; + cheevos_condition_t *cancel = &leaderboard[i].cancel; + cheevos_condition_t *submit = &leaderboard[i].submit; + cheevos_expr_t *value = &leaderboard[i].value; + + cheevos_patch_lb_conditions(start); + cheevos_patch_lb_conditions(cancel); + cheevos_patch_lb_conditions(submit); + cheevos_patch_lb_expressions(value); + } +} + +void cheevos_test(void) +{ + settings_t *settings = config_get_ptr(); + + if (!cheevos_locals.addrs_patched) + { + cheevos_patch_addresses(&cheevos_locals.core); + cheevos_patch_addresses(&cheevos_locals.unofficial); + cheevos_patch_lbs(cheevos_locals.leaderboards); + + cheevos_locals.addrs_patched = true; + } + + cheevos_test_cheevo_set(&cheevos_locals.core); + + if (settings) + { + if (settings->bools.cheevos_test_unofficial) + cheevos_test_cheevo_set(&cheevos_locals.unofficial); + + if (settings->bools.cheevos_hardcore_mode_enable && + settings->bools.cheevos_leaderboards_enable && + !cheevos_hardcore_paused) + cheevos_test_leaderboards(); + } +} + +bool cheevos_set_cheats(void) +{ + cheats_were_enabled = cheats_are_enabled; + return true; +} + +void cheevos_set_support_cheevos(bool state) +{ + cheevos_locals.core_supports = state; +} + +bool cheevos_get_support_cheevos(void) +{ + return cheevos_locals.core_supports; +} + +cheevos_console_t cheevos_get_console(void) +{ + return cheevos_locals.console_id; +} + +#include "coro.h" + +/* Uncomment the following two lines to debug cheevos_iterate, this will + * disable the coroutine yielding. + * + * The code is very easy to understand. It's meant to be like BASIC: + * CORO_GOTO will jump execution to another label, CORO_GOSUB will + * call another label, and CORO_RET will return from a CORO_GOSUB. + * + * This coroutine code is inspired in a very old pure C implementation + * that runs everywhere: + * + * https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html + */ +/*#undef CORO_YIELD +#define CORO_YIELD()*/ + +typedef struct +{ + /* variables used in the co-routine */ + char badge_name[16]; + char url[256]; + char badge_basepath[PATH_MAX_LENGTH]; + char badge_fullpath[PATH_MAX_LENGTH]; + unsigned char hash[16]; + bool round; + unsigned gameid; + unsigned i; + unsigned j; + unsigned k; + size_t bytes; + size_t count; + size_t offset; + size_t len; + size_t size; + MD5_CTX md5; + cheevos_nes_header_t header; + retro_time_t t0; + struct retro_system_info sysinfo; + void *data; + char *json; + const char *path; + const char *ext; + intfstream_t *stream; + cheevo_t *cheevo; + settings_t *settings; + struct http_connection_t *conn; + struct http_t *http; + const cheevo_t *cheevo_end; + + /* co-routine required fields */ + CORO_FIELDS +} coro_t; + +enum +{ + /* Negative values because CORO_SUB generates positive values */ + SNES_MD5 = -1, + GENESIS_MD5 = -2, + LYNX_MD5 = -3, + NES_MD5 = -4, + GENERIC_MD5 = -5, + FILENAME_MD5 = -6, + EVAL_MD5 = -7, + FILL_MD5 = -8, + GET_GAMEID = -9, + GET_CHEEVOS = -10, + GET_BADGES = -11, + LOGIN = -12, + HTTP_GET = -13, + DEACTIVATE = -14, + PLAYING = -15, + DELAY = -16 +}; + +static int cheevos_iterate(coro_t *coro) +{ + ssize_t num_read = 0; + size_t to_read = 4096; + uint8_t *buffer = NULL; + const char *end = NULL; + + static const uint32_t genesis_exts[] = + { + 0x0b888feeU, /* mdx */ + 0x005978b6U, /* md */ + 0x0b88aa89U, /* smd */ + 0x0b88767fU, /* gen */ + 0x0b8861beU, /* bin */ + 0x0b886782U, /* cue */ + 0x0b8880d0U, /* iso */ + 0x0b88aa98U, /* sms */ + 0x005977f3U, /* gg */ + 0x0059797fU, /* sg */ + 0 + }; + + static const uint32_t snes_exts[] = + { + 0x0b88aa88U, /* smc */ + 0x0b8872bbU, /* fig */ + 0x0b88a9a1U, /* sfc */ + 0x0b887623U, /* gd3 */ + 0x0b887627U, /* gd7 */ + 0x0b886bf3U, /* dx2 */ + 0x0b886312U, /* bsx */ + 0x0b88abd2U, /* swc */ + 0 + }; + + static const uint32_t lynx_exts[] = + { + 0x0b888cf7U, /* lnx */ + 0 + }; + + static cheevos_finder_t finders[] = + { + {SNES_MD5, "SNES (8Mb padding)", snes_exts}, + {GENESIS_MD5, "Genesis (6Mb padding)", genesis_exts}, + {LYNX_MD5, "Atari Lynx (only first 512 bytes)", lynx_exts}, + {NES_MD5, "NES (discards VROM)", NULL}, + {GENERIC_MD5, "Generic (plain content)", NULL}, + {FILENAME_MD5, "Generic (filename)", NULL} + }; + + CORO_ENTER(); + + + + cheevos_locals.addrs_patched = false; + + coro->settings = config_get_ptr(); + + cheevos_locals.meminfo[0].id = RETRO_MEMORY_SYSTEM_RAM; + core_get_memory(&cheevos_locals.meminfo[0]); + + cheevos_locals.meminfo[1].id = RETRO_MEMORY_SAVE_RAM; + core_get_memory(&cheevos_locals.meminfo[1]); + + cheevos_locals.meminfo[2].id = RETRO_MEMORY_VIDEO_RAM; + core_get_memory(&cheevos_locals.meminfo[2]); + + cheevos_locals.meminfo[3].id = RETRO_MEMORY_RTC; + core_get_memory(&cheevos_locals.meminfo[3]); + + CHEEVOS_LOG("[CHEEVOS]: system RAM: %p %u\n", + cheevos_locals.meminfo[0].data, + cheevos_locals.meminfo[0].size); + CHEEVOS_LOG("[CHEEVOS]: save RAM: %p %u\n", + cheevos_locals.meminfo[1].data, + cheevos_locals.meminfo[1].size); + CHEEVOS_LOG("[CHEEVOS]: video RAM: %p %u\n", + cheevos_locals.meminfo[2].data, + cheevos_locals.meminfo[2].size); + CHEEVOS_LOG("[CHEEVOS]: RTC: %p %u\n", + cheevos_locals.meminfo[3].data, + cheevos_locals.meminfo[3].size); + + /* Bail out if cheevos are disabled. + * But set the above anyways, + * command_read_ram needs it. */ + if (!coro->settings->bools.cheevos_enable) + CORO_STOP(); + + /* Load the content into memory, or copy it + * over to our own buffer */ + if (!coro->data) + { + coro->stream = intfstream_open_file( + coro->path, + RETRO_VFS_FILE_ACCESS_READ, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (!coro->stream) + CORO_STOP(); + + CORO_YIELD(); + coro->len = 0; + coro->count = intfstream_get_size(coro->stream); + + /* size limit */ + if (coro->count > size_in_megabytes(64)) + coro->count = size_in_megabytes(64); + + coro->data = malloc(coro->count); + + if (!coro->data) + { + intfstream_close(coro->stream); + free(coro->stream); + CORO_STOP(); + } + + for (;;) + { + buffer = (uint8_t*)coro->data + coro->len; + to_read = 4096; + + if (to_read > coro->count) + to_read = coro->count; + + num_read = intfstream_read(coro->stream, + (void*)buffer, to_read); + + if (num_read <= 0) + break; + + coro->len += num_read; + coro->count -= num_read; + + if (coro->count == 0) + break; + + CORO_YIELD(); + } + + intfstream_close(coro->stream); + free(coro->stream); + } + + /* Use the supported extensions as a hint + * to what method we should use. */ + core_get_system_info(&coro->sysinfo); + + for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++) + { + if (finders[coro->i].ext_hashes) + { + coro->ext = coro->sysinfo.valid_extensions; + + while (coro->ext) + { + unsigned hash; + end = strchr(coro->ext, '|'); + + if (end) + { + hash = cheevos_djb2( + coro->ext, end - coro->ext); + coro->ext = end + 1; + } + else + { + hash = cheevos_djb2( + coro->ext, strlen(coro->ext)); + coro->ext = NULL; + } + + for (coro->j = 0; finders[coro->i].ext_hashes[coro->j]; coro->j++) + { + if (finders[coro->i].ext_hashes[coro->j] == hash) + { + CHEEVOS_LOG("[CHEEVOS]: testing %s.\n", + finders[coro->i].name); + + /* + * Inputs: CHEEVOS_VAR_INFO + * Outputs: CHEEVOS_VAR_GAMEID, the game was found if it's different from 0 + */ + CORO_GOSUB(finders[coro->i].label); + + if (coro->gameid != 0) + goto found; + + coro->ext = NULL; /* force next finder */ + break; + } + } + } + } + } + + for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++) + { + if (finders[coro->i].ext_hashes) + continue; + + CHEEVOS_LOG("[CHEEVOS]: testing %s.\n", + finders[coro->i].name); + + /* + * Inputs: CHEEVOS_VAR_INFO + * Outputs: CHEEVOS_VAR_GAMEID + */ + CORO_GOSUB(finders[coro->i].label); + + if (coro->gameid != 0) + goto found; + } + + CHEEVOS_LOG("[CHEEVOS]: this game doesn't feature achievements.\n"); + CORO_STOP(); + +found: + +#ifdef CHEEVOS_JSON_OVERRIDE + { + size_t size = 0; + FILE *file = fopen(CHEEVOS_JSON_OVERRIDE, "rb"); + + fseek(file, 0, SEEK_END); + size = ftell(file); + fseek(file, 0, SEEK_SET); + + coro->json = (char*)malloc(size + 1); + fread((void*)coro->json, 1, size, file); + + fclose(file); + coro->json[size] = 0; + } +#else + CORO_GOSUB(GET_CHEEVOS); + + if (!coro->json) + { + runloop_msg_queue_push("Error loading achievements.", 0, 5 * 60, false); + CHEEVOS_ERR("[CHEEVOS]: error loading achievements.\n"); + CORO_STOP(); + } +#endif + +#ifdef CHEEVOS_SAVE_JSON + { + FILE *file = fopen(CHEEVOS_SAVE_JSON, "w"); + fwrite((void*)coro->json, 1, strlen(coro->json), file); + fclose(file); + } +#endif + if (cheevos_parse(coro->json)) + { + if ((void*)coro->json) + free((void*)coro->json); + CORO_STOP(); + } + + if ((void*)coro->json) + free((void*)coro->json); + + if ( cheevos_locals.core.count == 0 + && cheevos_locals.unofficial.count == 0 + && cheevos_locals.lboard_count == 0) + { + runloop_msg_queue_push( + "This game has no achievements.", + 0, 5 * 60, false); + + cheevos_free_cheevo_set(&cheevos_locals.core); + cheevos_free_cheevo_set(&cheevos_locals.unofficial); + + cheevos_locals.core.cheevos = NULL; + cheevos_locals.unofficial.cheevos = NULL; + cheevos_locals.core.count = 0; + cheevos_locals.unofficial.count = 0; + + cheevos_loaded = false; + cheevos_hardcore_paused = false; + CORO_STOP(); + } + + cheevos_loaded = true; + + /* + * Inputs: CHEEVOS_VAR_GAMEID + * Outputs: + */ + CORO_GOSUB(DEACTIVATE); + + /* + * Inputs: CHEEVOS_VAR_GAMEID + * Outputs: + */ + CORO_GOSUB(PLAYING); + + if (coro->settings->bools.cheevos_verbose_enable && cheevos_locals.core.count > 0) + { + char msg[256]; + int mode = CHEEVOS_ACTIVE_SOFTCORE; + const cheevo_t* cheevo = cheevos_locals.core.cheevos; + const cheevo_t* end = cheevo + cheevos_locals.core.count; + int number_of_unlocked = cheevos_locals.core.count; + + if (coro->settings->bools.cheevos_hardcore_mode_enable && !cheevos_hardcore_paused) + mode = CHEEVOS_ACTIVE_HARDCORE; + + for (; cheevo < end; cheevo++) + if (cheevo->active & mode) + number_of_unlocked--; + + snprintf(msg, sizeof(msg), + "You have %d of %d achievements unlocked.", + number_of_unlocked, cheevos_locals.core.count); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 6 * 60, false); + } + + CORO_GOSUB(GET_BADGES); + CORO_STOP(); + + /************************************************************************** + * Info Tries to identify a SNES game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(SNES_MD5) + + MD5_Init(&coro->md5); + + coro->offset = 0; + coro->count = 0; + + CORO_GOSUB(EVAL_MD5); + + if (coro->count == 0) + { + MD5_Final(coro->hash, &coro->md5); + coro->gameid = 0; + CORO_RET(); + } + + if (coro->count < size_in_megabytes(8)) + { + /* + * Inputs: CHEEVOS_VAR_MD5, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT + * Outputs: CHEEVOS_VAR_MD5 + */ + coro->offset = 0; + coro->count = size_in_megabytes(8) - coro->count; + CORO_GOSUB(FILL_MD5); + } + + MD5_Final(coro->hash, &coro->md5); + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify a Genesis game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(GENESIS_MD5) + + MD5_Init(&coro->md5); + + coro->offset = 0; + coro->count = 0; + CORO_GOSUB(EVAL_MD5); + + if (coro->count == 0) + { + MD5_Final(coro->hash, &coro->md5); + coro->gameid = 0; + CORO_RET(); + } + + if (coro->count < size_in_megabytes(6)) + { + coro->offset = 0; + coro->count = size_in_megabytes(6) - coro->count; + CORO_GOSUB(FILL_MD5); + } + + MD5_Final(coro->hash, &coro->md5); + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify an Atari Lynx game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(LYNX_MD5) + + if (coro->len < 0x0240) + { + coro->gameid = 0; + CORO_RET(); + } + + MD5_Init(&coro->md5); + + coro->offset = 0x0040; + coro->count = 0x0200; + CORO_GOSUB(EVAL_MD5); + + MD5_Final(coro->hash, &coro->md5); + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify a NES game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(NES_MD5) + + /* Note about the references to the FCEU emulator below. There is no + * core-specific code in this function, it's rather Retro Achievements + * specific code that must be followed to the letter so we compute + * the correct ROM hash. Retro Achievements does indeed use some + * FCEU related method to compute the hash, since its NES emulator + * is based on it. */ + + if (coro->len < sizeof(coro->header)) + { + coro->gameid = 0; + CORO_RET(); + } + + memcpy((void*)&coro->header, coro->data, + sizeof(coro->header)); + + if ( coro->header.id[0] != 'N' + || coro->header.id[1] != 'E' + || coro->header.id[2] != 'S' + || coro->header.id[3] != 0x1a) + { + coro->gameid = 0; + CORO_RET(); + } + + { + size_t romsize = 256; + /* from FCEU core - compute size using the cart mapper */ + int mapper = (coro->header.rom_type >> 4) | (coro->header.rom_type2 & 0xF0); + + if (coro->header.rom_size) + romsize = next_pow2(coro->header.rom_size); + + /* for games not to the power of 2, so we just read enough + * PRG rom from it, but we have to keep ROM_size to the power of 2 + * since PRGCartMapping wants ROM_size to be to the power of 2 + * so instead if not to power of 2, we just use head.ROM_size when + * we use FCEU_read. */ + coro->round = mapper != 53 && mapper != 198 && mapper != 228; + coro->bytes = coro->round ? romsize : coro->header.rom_size; + } + + /* from FCEU core - check if Trainer included in ROM data */ + MD5_Init(&coro->md5); + coro->offset = sizeof(coro->header) + (coro->header.rom_type & 4 + ? sizeof(coro->header) : 0); + coro->count = 0x4000 * coro->bytes; + CORO_GOSUB(EVAL_MD5); + + if (coro->count < 0x4000 * coro->bytes) + { + coro->offset = 0xff; + coro->count = 0x4000 * coro->bytes - coro->count; + CORO_GOSUB(FILL_MD5); + } + + MD5_Final(coro->hash, &coro->md5); + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify a "generic" game + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(GENERIC_MD5) + + MD5_Init(&coro->md5); + + coro->offset = 0; + coro->count = 0; + CORO_GOSUB(EVAL_MD5); + + MD5_Final(coro->hash, &coro->md5); + + if (coro->count == 0) + CORO_RET(); + + CORO_GOTO(GET_GAMEID); + + /************************************************************************** + * Info Tries to identify a game based on its filename (with no extension) + * Input CHEEVOS_VAR_INFO the content info + * Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found + *************************************************************************/ + CORO_SUB(FILENAME_MD5) + if (!string_is_empty(coro->path)) + { + char base_noext[PATH_MAX_LENGTH]; + fill_pathname_base_noext(base_noext, coro->path, sizeof(base_noext)); + + MD5_Init(&coro->md5); + MD5_Update(&coro->md5, (void*)base_noext, strlen(base_noext)); + MD5_Final(coro->hash, &coro->md5); + + CORO_GOTO(GET_GAMEID); + } + CORO_RET(); + + /************************************************************************** + * Info Evaluates the CHEEVOS_VAR_MD5 hash + * Inputs CHEEVOS_VAR_INFO, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT + * Outputs CHEEVOS_VAR_MD5, CHEEVOS_VAR_COUNT + *************************************************************************/ + CORO_SUB(EVAL_MD5) + + if (coro->count == 0) + coro->count = coro->len; + + if (coro->len - coro->offset < coro->count) + coro->count = coro->len - coro->offset; + + /* size limit */ + if (coro->count > size_in_megabytes(64)) + coro->count = size_in_megabytes(64); + + MD5_Update(&coro->md5, + (void*)((uint8_t*)coro->data + coro->offset), + coro->count); + CORO_RET(); + + /************************************************************************** + * Info Updates the CHEEVOS_VAR_MD5 hash with a repeated value + * Inputs CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT + * Outputs CHEEVOS_VAR_MD5 + *************************************************************************/ + CORO_SUB(FILL_MD5) + + { + char buffer[4096]; + + while (coro->count > 0) + { + size_t len = sizeof(buffer); + + if (len > coro->count) + len = coro->count; + + memset((void*)buffer, coro->offset, len); + MD5_Update(&coro->md5, (void*)buffer, len); + coro->count -= len; + } + } + + CORO_RET(); + + /************************************************************************** + * Info Gets the achievements from Retro Achievements + * Inputs coro->hash + * Outputs CHEEVOS_VAR_GAMEID + *************************************************************************/ + CORO_SUB(GET_GAMEID) + + { + char gameid[16]; + + CHEEVOS_LOG( + "[CHEEVOS]: getting game id for hash %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + coro->hash[ 0], coro->hash[ 1], coro->hash[ 2], coro->hash[ 3], + coro->hash[ 4], coro->hash[ 5], coro->hash[ 6], coro->hash[ 7], + coro->hash[ 8], coro->hash[ 9], coro->hash[10], coro->hash[11], + coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15] + ); + + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=gameid&m=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + coro->hash[ 0], coro->hash[ 1], coro->hash[ 2], coro->hash[ 3], + coro->hash[ 4], coro->hash[ 5], coro->hash[ 6], coro->hash[ 7], + coro->hash[ 8], coro->hash[ 9], coro->hash[10], coro->hash[11], + coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15] + ); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to get the game's id: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (!coro->json) + CORO_RET(); + + if (cheevos_get_value(coro->json, + CHEEVOS_JSON_KEY_GAMEID, gameid, sizeof(gameid))) + { + if ((void*)coro->json) + free((void*)coro->json); + CHEEVOS_ERR("[CHEEVOS]: error getting game_id.\n"); + CORO_RET(); + } + + if ((void*)coro->json) + free((void*)coro->json); + CHEEVOS_LOG("[CHEEVOS]: got game id %s.\n", gameid); + coro->gameid = (unsigned)strtol(gameid, NULL, 10); + CORO_RET(); + } + + /************************************************************************** + * Info Gets the achievements from Retro Achievements + * Inputs CHEEVOS_VAR_GAMEID + * Outputs CHEEVOS_VAR_JSON + *************************************************************************/ + CORO_SUB(GET_CHEEVOS) + + CORO_GOSUB(LOGIN); + + snprintf(coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=patch&g=%u&u=%s&t=%s", + coro->gameid, + coro->settings->arrays.cheevos_username, + cheevos_locals.token); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to get the list of cheevos: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (!coro->json) + { + CHEEVOS_ERR("[CHEEVOS]: error getting achievements for game id %u.\n", coro->gameid); + CORO_STOP(); + } + + CHEEVOS_LOG("[CHEEVOS]: got achievements for game id %u.\n", coro->gameid); + CORO_RET(); + + /************************************************************************** + * Info Gets the achievements from Retro Achievements + * Inputs CHEEVOS_VAR_GAMEID + * Outputs CHEEVOS_VAR_JSON + *************************************************************************/ + CORO_SUB(GET_BADGES) + + badges_ctx = new_badges_ctx; + + { + settings_t *settings = config_get_ptr(); + if (!( + string_is_equal(settings->arrays.menu_driver, "xmb") || + string_is_equal(settings->arrays.menu_driver, "ozone") + ) || + !settings->bools.cheevos_badges_enable) + CORO_RET(); + } + + coro->cheevo = cheevos_locals.core.cheevos; + coro->cheevo_end = cheevos_locals.core.cheevos + cheevos_locals.core.count; + + for (; coro->cheevo < coro->cheevo_end; coro->cheevo++) + { + for (coro->j = 0 ; coro->j < 2; coro->j++) + { + coro->badge_fullpath[0] = '\0'; + fill_pathname_application_special( + coro->badge_fullpath, + sizeof(coro->badge_fullpath), + APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES); + + if (!path_is_directory(coro->badge_fullpath)) + path_mkdir(coro->badge_fullpath); + CORO_YIELD(); + if (coro->j == 0) + snprintf(coro->badge_name, + sizeof(coro->badge_name), + "%s.png", coro->cheevo->badge); + else + snprintf(coro->badge_name, + sizeof(coro->badge_name), + "%s_lock.png", coro->cheevo->badge); + + fill_pathname_join( + coro->badge_fullpath, + coro->badge_fullpath, + coro->badge_name, + sizeof(coro->badge_fullpath)); + + if (!badge_exists(coro->badge_fullpath)) + { +#ifdef CHEEVOS_LOG_BADGES + CHEEVOS_LOG( + "[CHEEVOS]: downloading badge %s\n", + coro->badge_fullpath); +#endif + snprintf(coro->url, + sizeof(coro->url), + "http://i.retroachievements.org/Badge/%s", + coro->badge_name); + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + if (!filestream_write_file(coro->badge_fullpath, + coro->json, coro->k)) + CHEEVOS_ERR("[CHEEVOS]: error writing badge %s\n", coro->badge_fullpath); + else + free(coro->json); + } + } + } + } + + CORO_RET(); + + /************************************************************************** + * Info Logs in the user at Retro Achievements + *************************************************************************/ + CORO_SUB(LOGIN) + + if (cheevos_locals.token[0]) + CORO_RET(); + + { + char urle_user[64]; + char urle_login[64]; + const char *username = coro ? coro->settings->arrays.cheevos_username : NULL; + const char *login = NULL; + bool via_token = false; + + if (coro) + { + if (string_is_empty(coro->settings->arrays.cheevos_password)) + { + via_token = true; + login = coro->settings->arrays.cheevos_token; + } + else + login = coro->settings->arrays.cheevos_password; + } + else + login = NULL; + + if (string_is_empty(username) || string_is_empty(login)) + { + runloop_msg_queue_push( + "Missing RetroAchievements account information.", + 0, 5 * 60, false); + runloop_msg_queue_push( + "Please fill in your account information in Settings.", + 0, 5 * 60, false); + CHEEVOS_ERR("[CHEEVOS]: login info not informed.\n"); + CORO_STOP(); + } + + cheevos_url_encode(username, urle_user, sizeof(urle_user)); + cheevos_url_encode(login, urle_login, sizeof(urle_login)); + + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=login&u=%s&%c=%s", + urle_user, via_token ? 't' : 'p', urle_login + ); + + coro->url[sizeof(coro->url) - 1] = 0; + } + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to login: %s\n", + coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + char error_response[64]; + char error_message[256]; + + cheevos_get_value( + coro->json, + CHEEVOS_JSON_KEY_ERROR, + error_response, + sizeof(error_response) + ); + + /* No error, continue with login */ + if (string_is_empty(error_response)) + { + int res = cheevos_get_value( + coro->json, + CHEEVOS_JSON_KEY_TOKEN, + cheevos_locals.token, + sizeof(cheevos_locals.token)); + + if ((void*)coro->json) + free((void*)coro->json); + + if (!res) + { + if (coro->settings->bools.cheevos_verbose_enable) + { + char msg[256]; + snprintf(msg, sizeof(msg), + "RetroAchievements: Logged in as \"%s\".", + coro->settings->arrays.cheevos_username); + msg[sizeof(msg) - 1] = 0; + runloop_msg_queue_push(msg, 0, 3 * 60, false); + } + + /* Save token to config and clear pass on success */ + *coro->settings->arrays.cheevos_password = '\0'; + strncpy( + coro->settings->arrays.cheevos_token, + cheevos_locals.token, sizeof(cheevos_locals.token) + ); + CORO_RET(); + } + } + + if ((void*)coro->json) + free((void*)coro->json); + + /* Site returned error, display it */ + snprintf(error_message, sizeof(error_message), + "RetroAchievements: %s", + error_response); + error_message[sizeof(error_message) - 1] = 0; + runloop_msg_queue_push(error_message, 0, 5 * 60, false); + *coro->settings->arrays.cheevos_token = '\0'; + + CORO_STOP(); + } + + runloop_msg_queue_push("RetroAchievements: Error contacting server.", 0, 5 * 60, false); + CHEEVOS_ERR("[CHEEVOS]: error getting user token.\n"); + + CORO_STOP(); + + /************************************************************************** + * Info Pauses execution for five seconds + *************************************************************************/ + CORO_SUB(DELAY) + + { + retro_time_t t1; + coro->t0 = cpu_features_get_time_usec(); + + do + { + CORO_YIELD(); + t1 = cpu_features_get_time_usec(); + }while ((t1 - coro->t0) < 3000000); + } + + CORO_RET(); + + /************************************************************************** + * Info Makes a HTTP GET request + * Inputs CHEEVOS_VAR_URL + * Outputs CHEEVOS_VAR_JSON + *************************************************************************/ + CORO_SUB(HTTP_GET) + + for (coro->k = 0; coro->k < 5; coro->k++) + { + if (coro->k != 0) + CHEEVOS_LOG("[CHEEVOS]: Retrying HTTP request: %u of 5\n", coro->k + 1); + + coro->json = NULL; + coro->conn = net_http_connection_new( + coro->url, "GET", NULL); + + if (!coro->conn) + { + CORO_GOSUB(DELAY); + continue; + } + + /* Don't bother with timeouts here, it's just a string scan. */ + while (!net_http_connection_iterate(coro->conn)) {} + + /* Error finishing the connection descriptor. */ + if (!net_http_connection_done(coro->conn)) + { + net_http_connection_free(coro->conn); + continue; + } + + coro->http = net_http_new(coro->conn); + + /* Error connecting to the endpoint. */ + if (!coro->http) + { + net_http_connection_free(coro->conn); + CORO_GOSUB(DELAY); + continue; + } + + while (!net_http_update(coro->http, NULL, NULL)) + CORO_YIELD(); + + { + size_t length; + uint8_t *data = net_http_data(coro->http, + &length, false); + + if (data) + { + coro->json = (char*)malloc(length + 1); + + if (coro->json) + { + memcpy((void*)coro->json, (void*)data, length); + free(data); + coro->json[length] = 0; + } + + coro->k = (unsigned)length; + net_http_delete(coro->http); + net_http_connection_free(coro->conn); + CORO_RET(); + } + } + + net_http_delete(coro->http); + net_http_connection_free(coro->conn); + } + + CHEEVOS_LOG("[CHEEVOS]: Couldn't connect to server after 5 tries\n"); + CORO_RET(); + + /************************************************************************** + * Info Deactivates the achievements already awarded + * Inputs CHEEVOS_VAR_GAMEID + * Outputs + *************************************************************************/ + CORO_SUB(DEACTIVATE) + +#ifndef CHEEVOS_DONT_DEACTIVATE + CORO_GOSUB(LOGIN); + + /* Deactivate achievements in softcore mode. */ + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=0", + coro->settings->arrays.cheevos_username, + cheevos_locals.token, coro->gameid + ); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to get the list of unlocked cheevos in softcore: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + if (!cheevos_deactivate_unlocks(coro->json, CHEEVOS_ACTIVE_SOFTCORE)) + CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked achievements in softcore mode.\n"); + else + CHEEVOS_ERR("[CHEEVOS]: error deactivating unlocked achievements in softcore mode.\n"); + + if ((void*)coro->json) + free((void*)coro->json); + } + else + CHEEVOS_ERR("[CHEEVOS]: error retrieving list of unlocked achievements in softcore mode.\n"); + + /* Deactivate achievements in hardcore mode. */ + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=unlocks&u=%s&t=%s&g=%u&h=1", + coro->settings->arrays.cheevos_username, + cheevos_locals.token, coro->gameid + ); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to get the list of unlocked cheevos in hardcore: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + if (!cheevos_deactivate_unlocks(coro->json, CHEEVOS_ACTIVE_HARDCORE)) + CHEEVOS_LOG("[CHEEVOS]: deactivated unlocked achievements in hardcore mode.\n"); + else + CHEEVOS_ERR("[CHEEVOS]: error deactivating unlocked achievements in hardcore mode.\n"); + + if ((void*)coro->json) + free((void*)coro->json); + } + else + CHEEVOS_ERR("[CHEEVOS]: error retrieving list of unlocked achievements in hardcore mode.\n"); + +#endif + CORO_RET(); + + /************************************************************************** + * Info Posts the "playing" activity to Retro Achievements + * Inputs CHEEVOS_VAR_GAMEID + * Outputs + *************************************************************************/ + CORO_SUB(PLAYING) + + snprintf( + coro->url, sizeof(coro->url), + "http://retroachievements.org/dorequest.php?r=postactivity&u=%s&t=%s&a=3&m=%u", + coro->settings->arrays.cheevos_username, + cheevos_locals.token, coro->gameid + ); + + coro->url[sizeof(coro->url) - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("[CHEEVOS]: url to post the 'playing' activity: %s\n", coro->url); +#endif + + CORO_GOSUB(HTTP_GET); + + if (coro->json) + { + CHEEVOS_LOG("[CHEEVOS]: posted playing activity.\n"); + if ((void*)coro->json) + free((void*)coro->json); + } + else + CHEEVOS_ERR("[CHEEVOS]: error posting playing activity.\n"); + + CHEEVOS_LOG("[CHEEVOS]: posted playing activity.\n"); + CORO_RET(); + + CORO_LEAVE(); +} + +static void cheevos_task_handler(retro_task_t *task) +{ + coro_t *coro = (coro_t*)task->state; + + if (!coro) + return; + + if (!cheevos_iterate(coro) || task_get_cancelled(task)) + { + task_set_finished(task, true); + + CHEEVOS_LOCK(cheevos_locals.task_lock); + cheevos_locals.task = NULL; + CHEEVOS_UNLOCK(cheevos_locals.task_lock); + + if (task_get_cancelled(task)) + { + CHEEVOS_LOG("[CHEEVOS]: Load task cancelled\n"); + } + else + { + CHEEVOS_LOG("[CHEEVOS]: Load task finished\n"); + } + + if (coro->data) + free(coro->data); + + if ((void*)coro->path) + free((void*)coro->path); + + free((void*)coro); + } +} + +bool cheevos_load(const void *data) +{ + retro_task_t *task; + const struct retro_game_info *info = NULL; + coro_t *coro = NULL; + + cheevos_loaded = false; + cheevos_hardcore_paused = false; + + if (!cheevos_locals.core_supports || !data) + return false; + + coro = (coro_t*)calloc(1, sizeof(*coro)); + + if (!coro) + return false; + + task = (retro_task_t*)calloc(1, sizeof(*task)); + + if (!task) + { + if ((void*)coro) + free((void*)coro); + return false; + } + + CORO_SETUP(); + + info = (const struct retro_game_info*)data; + + if (info->data) + { + coro->len = info->size; + + /* size limit */ + if (coro->len > size_in_megabytes(64)) + coro->len = size_in_megabytes(64); + + coro->data = malloc(coro->len); + + if (!coro->data) + { + if ((void*)task) + free((void*)task); + if ((void*)coro) + free((void*)coro); + return false; + } + + memcpy(coro->data, info->data, coro->len); + coro->path = NULL; + } + else + { + coro->data = NULL; + coro->path = strdup(info->path); + } + + task->handler = cheevos_task_handler; + task->state = (void*)coro; + task->mute = true; + task->callback = NULL; + task->user_data = NULL; + task->progress = 0; + task->title = NULL; + +#ifdef HAVE_THREADS + if (cheevos_locals.task_lock == NULL) + { + cheevos_locals.task_lock = slock_new(); + } +#endif + + CHEEVOS_LOCK(cheevos_locals.task_lock); + cheevos_locals.task = task; + CHEEVOS_UNLOCK(cheevos_locals.task_lock); + + task_queue_push(task); + + return true; +} diff --git a/cheevos/cheevos.h b/cheevos/cheevos.h index 0e53cc0021..ec25ae0019 100644 --- a/cheevos/cheevos.h +++ b/cheevos/cheevos.h @@ -98,7 +98,8 @@ typedef enum CHEEVOS_CONSOLE_VIRTUAL_BOY = 28, CHEEVOS_CONSOLE_MSX = 29, CHEEVOS_CONSOLE_COMMODORE_64 = 30, - CHEEVOS_CONSOLE_ZX81 = 31 + CHEEVOS_CONSOLE_ZX81 = 31, + CHEEVOS_CONSOLE_ATARI_7800 = 51 } cheevos_console_t; enum diff --git a/command.c b/command.c index f52fcee785..a87a52e1e4 100644 --- a/command.c +++ b/command.c @@ -1278,6 +1278,7 @@ static bool event_init_content(void) { bool contentless = false; bool is_inited = false; + settings_t *settings = config_get_ptr(); content_get_status(&contentless, &is_inited); @@ -1304,7 +1305,18 @@ static bool event_init_content(void) RARCH_LOG("%s.\n", msg_hash_to_str(MSG_SKIPPING_SRAM_LOAD)); +/* + Since the operations are asynchronouse we can't guarantee users will not use auto_load_state to cheat on + achievements so we forbid auto_load_state from happening if cheevos_enable and cheevos_hardcode_mode_enable + are true +*/ +#ifdef HAVE_CHEEVOS + if (!settings->bools.cheevos_enable || !settings->bools.cheevos_hardcore_mode_enable) + command_event_load_auto_state(); +#else command_event_load_auto_state(); +#endif + command_event(CMD_EVENT_BSV_MOVIE_INIT, NULL); command_event(CMD_EVENT_NETPLAY_INIT, NULL); @@ -2433,17 +2445,12 @@ TODO: Add a setting for these tweaks */ break; case CMD_EVENT_ADD_TO_FAVORITES: { - global_t *global = global_get_ptr(); - rarch_system_info_t *sys_info = runloop_get_system_info(); - const char *core_name = NULL; - const char *core_path = NULL; - const char *label = NULL; - - if (sys_info) - { - core_name = sys_info->info.library_name; - core_path = path_get(RARCH_PATH_CORE); - } + /* TODO/FIXME - does path_get(RARCH_PATH_CORE) depend on the system info struct? Investigate */ + global_t *global = global_get_ptr(); + struct retro_system_info *system = runloop_get_libretro_system_info(); + const char *label = NULL; + const char *core_path = system ? path_get(RARCH_PATH_CORE) : NULL; + const char *core_name = system ? system->library_name : NULL; if (!string_is_empty(global->name.label)) label = global->name.label; diff --git a/config.def.h b/config.def.h index e9cadb4165..f0ee60d58b 100644 --- a/config.def.h +++ b/config.def.h @@ -188,7 +188,7 @@ static const bool video_threaded = false; #endif #if defined(HAVE_THREADS) -#if defined(GEKKO) || defined(PSP) +#if defined(GEKKO) || defined(PSP) || defined(PS2) /* For single-core consoles right now it's better to have this be disabled. */ static const bool threaded_data_runloop_enable = false; #else @@ -266,6 +266,12 @@ static const float default_input_overlay_opacity = 0.7f; static bool default_block_config_read = true; +#ifdef HAVE_LIBNX +static bool menu_use_preferred_system_color_theme = true; +#else +static bool menu_use_preferred_system_color_theme = false; +#endif + static bool quick_menu_show_take_screenshot = true; static bool quick_menu_show_save_load_state = true; static bool quick_menu_show_undo_save_load_state = true; @@ -472,6 +478,11 @@ static const float crt_refresh_rate = 60/1.001; * Used for setups where one manually rotates the monitor. */ static const bool allow_rotate = true; +#ifdef _3DS +/* Enable bottom LCD screen */ +static const bool video_3ds_lcd_bottom = true; +#endif + /* AUDIO */ /* Will enable audio or not. */ @@ -725,7 +736,7 @@ static const bool desktop_menu_enable = true; #if defined(__QNX__) || defined(_XBOX1) || defined(_XBOX360) || defined(__CELLOS_LV2__) || (defined(__MACH__) && defined(IOS)) || defined(ANDROID) || defined(WIIU) || defined(HAVE_NEON) || defined(GEKKO) || defined(__ARM_NEON__) static enum resampler_quality audio_resampler_quality_level = RESAMPLER_QUALITY_LOWER; -#elif defined(PSP) || defined(_3DS) || defined(VITA) +#elif defined(PSP) || defined(_3DS) || defined(VITA) || defined(PS2) static enum resampler_quality audio_resampler_quality_level = RESAMPLER_QUALITY_LOWEST; #else static enum resampler_quality audio_resampler_quality_level = RESAMPLER_QUALITY_NORMAL; @@ -811,4 +822,6 @@ static char buildbot_server_url[] = ""; static char buildbot_assets_server_url[] = "http://buildbot.libretro.com/assets/"; +static char default_discord_app_id[] = "475456035851599874"; + #endif diff --git a/config.features.h b/config.features.h index 93062366f4..f3e0d85b50 100644 --- a/config.features.h +++ b/config.features.h @@ -308,7 +308,7 @@ static const bool _python_supp = true; static const bool _python_supp = false; #endif -#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) +#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) static const bool _cocoa_supp = true; #else static const bool _cocoa_supp = false; diff --git a/configuration.c b/configuration.c index 4759929212..299f475e99 100644 --- a/configuration.c +++ b/configuration.c @@ -148,6 +148,7 @@ enum video_driver_enum VIDEO_XENON360, VIDEO_PSP1, VIDEO_VITA2D, + VIDEO_PS2, VIDEO_CTR, VIDEO_SWITCH, VIDEO_D3D8, @@ -191,6 +192,7 @@ enum audio_driver_enum AUDIO_WIIU, AUDIO_RWEBAUDIO, AUDIO_PSP, + AUDIO_PS2, AUDIO_CTR, AUDIO_SWITCH, AUDIO_NULL @@ -214,6 +216,7 @@ enum input_driver_enum INPUT_DINPUT, INPUT_PS3, INPUT_PSP, + INPUT_PS2, INPUT_CTR, INPUT_SWITCH, INPUT_XENON360, @@ -237,6 +240,7 @@ enum joypad_driver_enum JOYPAD_WIIU, JOYPAD_XDK, JOYPAD_PSP, + JOYPAD_PS2, JOYPAD_CTR, JOYPAD_SWITCH, JOYPAD_DINPUT, @@ -288,6 +292,7 @@ enum menu_driver_enum MENU_XMB, MENU_STRIPES, MENU_NUKLEAR, + MENU_OZONE, MENU_NULL }; @@ -324,6 +329,8 @@ static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_VG; static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_VITA2D; #elif defined(PSP) static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_PSP1; +#elif defined(PS2) +static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_PS2; #elif defined(_3DS) static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_CTR; #elif defined(SWITCH) @@ -354,6 +361,8 @@ static enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_WII; static enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_WIIU; #elif defined(PSP) || defined(VITA) static enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_PSP; +#elif defined(PS2) +static enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_PS2; #elif defined(_3DS) static enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_CTR; #elif defined(SWITCH) @@ -434,6 +443,8 @@ static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_DINPUT; static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_PS3; #elif defined(PSP) || defined(VITA) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_PSP; +#elif defined(PS2) +static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_PS2; #elif defined(_3DS) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_CTR; #elif defined(SWITCH) @@ -450,7 +461,7 @@ static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_UDEV; static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_LINUXRAW; #elif defined(HAVE_WAYLAND) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_WAYLAND; -#elif defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) +#elif defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_COCOA; #elif defined(__QNX__) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_QNX; @@ -476,6 +487,8 @@ static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_WIIU; static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_XDK; #elif defined(PSP) || defined(VITA) static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_PSP; +#elif defined(PS2) +static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_PS2; #elif defined(_3DS) static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_CTR; #elif defined(SWITCH) @@ -510,7 +523,7 @@ static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_V4L2; static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_RWEBCAM; #elif defined(ANDROID) static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_ANDROID; -#elif defined(HAVE_AVFOUNDATION) && (defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH)) +#elif defined(HAVE_AVFOUNDATION) && (defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL)) static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_AVFOUNDATION; #else static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_NULL; @@ -524,7 +537,7 @@ static enum wifi_driver_enum WIFI_DEFAULT_DRIVER = WIFI_NULL; #if defined(ANDROID) static enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_ANDROID; -#elif defined(HAVE_CORELOCATION) && (defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH)) +#elif defined(HAVE_CORELOCATION) && (defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL)) static enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_CORELOCATION; #else static enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_NULL; @@ -534,6 +547,8 @@ static enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_NULL; static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_XUI; #elif defined(HAVE_MATERIALUI) && defined(RARCH_MOBILE) static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_MATERIALUI; +#elif defined(HAVE_OZONE) && defined(HAVE_LIBNX) +static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_OZONE; #elif defined(HAVE_XMB) && !defined(_XBOX) static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_XMB; #elif defined(HAVE_RGUI) @@ -660,6 +675,8 @@ const char *config_get_default_audio(void) #else return "psp"; #endif + case AUDIO_PS2: + return "ps2"; case AUDIO_CTR: return "csnd"; case AUDIO_SWITCH: @@ -755,6 +772,8 @@ const char *config_get_default_video(void) return "d3d12"; case VIDEO_PSP1: return "psp1"; + case VIDEO_PS2: + return "ps2"; case VIDEO_VITA2D: return "vita2d"; case VIDEO_CTR: @@ -815,6 +834,8 @@ const char *config_get_default_input(void) #else return "psp"; #endif + case INPUT_PS2: + return "ps2"; case INPUT_CTR: return "ctr"; case INPUT_SWITCH: @@ -885,6 +906,8 @@ const char *config_get_default_joypad(void) #else return "psp"; #endif + case JOYPAD_PS2: + return "ps2"; case JOYPAD_CTR: return "ctr"; case JOYPAD_SWITCH: @@ -1028,6 +1051,8 @@ const char *config_get_default_menu(void) return "rgui"; case MENU_XUI: return "xui"; + case MENU_OZONE: + return "ozone"; case MENU_MATERIALUI: return "glui"; case MENU_XMB: @@ -1111,7 +1136,7 @@ static struct config_array_setting *populate_settings_array(settings_t *settings SETTING_ARRAY("midi_input", settings->arrays.midi_input, true, midi_input, true); SETTING_ARRAY("midi_output", settings->arrays.midi_output, true, midi_output, true); SETTING_ARRAY("youtube_stream_key", settings->arrays.youtube_stream_key, true, NULL, true); - SETTING_ARRAY("twitch_stream_key", settings->arrays.twitch_stream_key, true, NULL, true); + SETTING_ARRAY("discord_app_id", settings->arrays.discord_app_id, true, default_discord_app_id, true); *size = count; return tmp; @@ -1382,6 +1407,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("quick_menu_show_save_content_dir_overrides", &settings->bools.quick_menu_show_save_content_dir_overrides, true, quick_menu_show_save_content_dir_overrides, false); SETTING_BOOL("quick_menu_show_information", &settings->bools.quick_menu_show_information, true, quick_menu_show_information, false); SETTING_BOOL("kiosk_mode_enable", &settings->bools.kiosk_mode_enable, true, kiosk_mode_enable, false); + SETTING_BOOL("menu_use_preferred_system_color_theme", &settings->bools.menu_use_preferred_system_color_theme, true, menu_use_preferred_system_color_theme, false); SETTING_BOOL("content_show_settings", &settings->bools.menu_content_show_settings, true, content_show_settings, false); SETTING_BOOL("content_show_favorites", &settings->bools.menu_content_show_favorites, true, content_show_favorites, false); #ifdef HAVE_IMAGEVIEWER @@ -1491,6 +1517,10 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("sustained_performance_mode", &settings->bools.sustained_performance_mode, true, sustained_performance_mode, false); +#ifdef _3DS + SETTING_BOOL("video_3ds_lcd_bottom", &settings->bools.video_3ds_lcd_bottom, true, video_3ds_lcd_bottom, false); +#endif + *size = count; return tmp; @@ -1575,6 +1605,16 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, SETTING_UINT("dpi_override_value", &settings->uints.menu_dpi_override_value, true, menu_dpi_override_value, false); SETTING_UINT("menu_thumbnails", &settings->uints.menu_thumbnails, true, menu_thumbnails_default, false); SETTING_UINT("menu_timedate_style", &settings->uints.menu_timedate_style, true, menu_timedate_style, false); +#ifdef HAVE_LIBNX + SETTING_UINT("split_joycon_p1", &settings->uints.input_split_joycon[0], true, 0, false); + SETTING_UINT("split_joycon_p2", &settings->uints.input_split_joycon[1], true, 0, false); + SETTING_UINT("split_joycon_p3", &settings->uints.input_split_joycon[2], true, 0, false); + SETTING_UINT("split_joycon_p4", &settings->uints.input_split_joycon[3], true, 0, false); + SETTING_UINT("split_joycon_p5", &settings->uints.input_split_joycon[4], true, 0, false); + SETTING_UINT("split_joycon_p6", &settings->uints.input_split_joycon[5], true, 0, false); + SETTING_UINT("split_joycon_p7", &settings->uints.input_split_joycon[6], true, 0, false); + SETTING_UINT("split_joycon_p8", &settings->uints.input_split_joycon[7], true, 0, false); +#endif #ifdef HAVE_XMB SETTING_UINT("menu_left_thumbnails", &settings->uints.menu_left_thumbnails, true, menu_left_thumbnails_default, false); SETTING_UINT("xmb_alpha_factor", &settings->uints.menu_xmb_alpha_factor, true, xmb_alpha_factor, false); @@ -1588,6 +1628,9 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, #endif SETTING_UINT("materialui_menu_color_theme", &settings->uints.menu_materialui_color_theme, true, MATERIALUI_THEME_BLUE, false); SETTING_UINT("menu_shader_pipeline", &settings->uints.menu_xmb_shader_pipeline, true, menu_shader_pipeline, false); +#ifdef HAVE_OZONE + SETTING_UINT("ozone_menu_color_theme", &settings->uints.menu_ozone_color_theme, true, 0, false); +#endif #endif SETTING_UINT("audio_out_rate", &settings->uints.audio_out_rate, true, out_rate, false); SETTING_UINT("custom_viewport_width", &settings->video_viewport_custom.width, false, 0 /* TODO */, false); @@ -1804,6 +1847,9 @@ void config_set_defaults(void) *settings->paths.path_menu_xmb_font = '\0'; #endif + strlcpy(settings->arrays.discord_app_id, + default_discord_app_id, sizeof(settings->arrays.discord_app_id)); + #ifdef HAVE_MATERIALUI if (g_defaults.menu.materialui.menu_color_theme_enable) settings->uints.menu_materialui_color_theme = g_defaults.menu.materialui.menu_color_theme; @@ -2349,7 +2395,8 @@ static bool check_menu_driver_compatibility(void) char *menu_driver = settings->arrays.menu_driver; if (string_is_equal (menu_driver, "rgui") || - string_is_equal(menu_driver, "null")) + string_is_equal(menu_driver, "null") || + string_is_equal(video_driver, "null")) return true; /* TODO/FIXME - maintenance hazard */ @@ -2357,11 +2404,13 @@ static bool check_menu_driver_compatibility(void) string_is_equal(video_driver, "d3d10") || string_is_equal(video_driver, "d3d11") || string_is_equal(video_driver, "d3d12") || + string_is_equal(video_driver, "gdi") || string_is_equal(video_driver, "gl") || string_is_equal(video_driver, "gx2") || string_is_equal(video_driver, "vulkan") || string_is_equal(video_driver, "metal") || - string_is_equal(video_driver, "vita")) + string_is_equal(video_driver, "ctr") || + string_is_equal(video_driver, "vita2d")) return true; return false; diff --git a/configuration.h b/configuration.h index 28f599ff87..5ca67844fb 100644 --- a/configuration.h +++ b/configuration.h @@ -104,6 +104,7 @@ typedef struct settings bool video_statistics_show; bool video_framecount_show; bool video_msg_bgcolor_enable; + bool video_3ds_lcd_bottom; /* Audio */ bool audio_enable; @@ -175,6 +176,8 @@ typedef struct settings bool menu_content_show_history; bool menu_content_show_add; bool menu_content_show_playlists; + bool menu_use_preferred_system_color_theme; + bool menu_preferred_system_color_theme_set; bool menu_unified_controls; bool quick_menu_show_take_screenshot; bool quick_menu_show_save_load_state; @@ -407,6 +410,7 @@ typedef struct settings unsigned menu_xmb_theme; unsigned menu_xmb_color_theme; unsigned menu_materialui_color_theme; + unsigned menu_ozone_color_theme; unsigned menu_font_color_red; unsigned menu_font_color_green; unsigned menu_font_color_blue; @@ -482,6 +486,8 @@ typedef struct settings char youtube_stream_key[PATH_MAX_LENGTH]; char twitch_stream_key[PATH_MAX_LENGTH]; + + char discord_app_id[PATH_MAX_LENGTH]; } arrays; struct diff --git a/core_impl.c b/core_impl.c index eb4b2fffd0..a8a5acb949 100644 --- a/core_impl.c +++ b/core_impl.c @@ -396,7 +396,9 @@ bool core_unload(void) { video_driver_set_cached_frame_ptr(NULL); - current_core.retro_deinit(); + if (current_core.inited) + current_core.retro_deinit(); + return true; } @@ -407,9 +409,11 @@ bool core_unload_game(void) video_driver_set_cached_frame_ptr(NULL); - current_core.retro_unload_game(); - - current_core.game_loaded = false; + if (current_core.game_loaded) + { + current_core.retro_unload_game(); + current_core.game_loaded = false; + } audio_driver_stop(); diff --git a/core_info.c b/core_info.c index 18c8caf448..d7ea70ed91 100644 --- a/core_info.c +++ b/core_info.c @@ -205,7 +205,7 @@ static bool core_info_list_iterate( current_path, info_path_base_size); -#if defined(RARCH_MOBILE) || (defined(RARCH_CONSOLE) && !defined(PSP) && !defined(_3DS) && !defined(VITA) && !defined(HW_WUP)) +#if defined(RARCH_MOBILE) || (defined(RARCH_CONSOLE) && !defined(PSP) && !defined(_3DS) && !defined(VITA) && !defined(PS2) && !defined(HW_WUP)) substr = strrchr(info_path_base, '_'); if (substr) *substr = '\0'; diff --git a/cores/libretro-video-processor/Makefile b/cores/libretro-video-processor/Makefile index 6323f9a53d..319723a941 100644 --- a/cores/libretro-video-processor/Makefile +++ b/cores/libretro-video-processor/Makefile @@ -109,7 +109,7 @@ else SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T -Wl,--no-undefined endif -LDFLAGS += $(LIBV4L2) $(LIBASOUND) $(LIBUDEV) +LDFLAGS += $(LIBV4L2) $(LIBASOUND) $(LIBUDEV) -lm ifeq ($(DEBUG), 1) CFLAGS += -O0 -g diff --git a/cores/libretro-video-processor/video_processor_v4l2.c b/cores/libretro-video-processor/video_processor_v4l2.c index d5f0813f19..15cbe0d02b 100644 --- a/cores/libretro-video-processor/video_processor_v4l2.c +++ b/cores/libretro-video-processor/video_processor_v4l2.c @@ -26,12 +26,13 @@ #define LIBRARY_NAME "V4L2" #define LIBRARY_VERSION "0.0.2" -#define VIDEO_BUFFERS 2 +#define VIDEO_BUFFERS_MAX 2 #define AUDIO_SAMPLE_RATE 48000 #define AUDIO_BUFSIZE 64 #define ENVVAR_BUFLEN 1024 #include +#include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include @@ -61,7 +63,7 @@ #include -struct video_buffer +struct v4l2_capbuf { void *start; size_t len; @@ -70,12 +72,42 @@ struct video_buffer /* * Video capture state */ -static int video_fd = -1; -static struct v4l2_format video_format; -static struct v4l2_standard video_standard; -static struct video_buffer video_buffer[VIDEO_BUFFERS]; -static size_t video_nbuffers; -static uint16_t *conv_data; +static int video_device_fd = -1; +static char video_device[ENVVAR_BUFLEN]; +static char audio_device[ENVVAR_BUFLEN]; + +static struct v4l2_format video_format; +static struct v4l2_standard video_standard; +static struct v4l2_buffer video_buf; + +static uint8_t v4l2_ncapbuf_target; +static size_t v4l2_ncapbuf; +static struct v4l2_capbuf v4l2_capbuf[VIDEO_BUFFERS_MAX]; + +static float dummy_pos=0; + +static int video_half_feed_rate=0; // for interlaced captures +static uint32_t video_cap_width; +static uint32_t video_cap_height; +static uint32_t video_out_height; +static char video_capture_mode[ENVVAR_BUFLEN]; +static char video_output_mode[ENVVAR_BUFLEN]; +static char video_frame_times[ENVVAR_BUFLEN]; + +static uint8_t *frame_cap; +static uint32_t *frame_out; +static uint32_t *frames[4]; +static uint32_t *frame_prev1; +static uint32_t *frame_prev2; +static uint32_t *frame_prev3; +static uint32_t *frame_curr; + + +// Frametime debug messages +struct timeval ft_prevtime = { 0 }, ft_prevtime2 = { 0 }; +char *ft_info = NULL, *ft_info2 = NULL; +double ft_favg, ft_ftime; +int ft_fcount; /* * Audio capture state @@ -196,6 +228,7 @@ enumerate_video_devices(char *buf, size_t buflen) /* Just return a few options. We'll fail later if the device is not found. */ appendstr(buf, "/dev/video0|/dev/video1|/dev/video2|/dev/video3", buflen); #endif + } static void @@ -239,20 +272,28 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_environment)(retro_environment_t { char video_devices[ENVVAR_BUFLEN]; char audio_devices[ENVVAR_BUFLEN]; - struct retro_variable envvars[3] = {{NULL}}; + struct retro_variable envvars[] = { + { "videoproc_videodev", NULL }, + { "videoproc_audiodev", NULL }, + { "videoproc_capture_mode", "Capture mode; alternate|interlaced|top|bottom|alternate_hack" }, + { "videoproc_output_mode","Output mode; progressive|deinterlaced|interlaced" }, + { "videoproc_frame_times","Print frame times to terminal (v4l2 only); Off|On" }, + { NULL, NULL } + }; VIDEOPROC_CORE_PREFIX(environment_cb) = cb; -#ifdef HAVE_ALSA - struct retro_audio_callback audio_cb; - audio_cb.callback = audio_callback; - audio_cb.set_state = audio_set_state; - VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, &audio_cb); -#endif + // Allows retroarch to seed the previous values + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_VARIABLES, envvars); + // Enumerate all real devices enumerate_video_devices(video_devices, sizeof(video_devices)); enumerate_audio_devices(audio_devices, sizeof(audio_devices)); + // Add the dummy device + appendstr(video_devices, "|dummy", ENVVAR_BUFLEN); + + // Registers available devices list (still respects saved device if it exists) envvars[0].key = "videoproc_videodev"; envvars[0].value = video_devices; envvars[1].key = "videoproc_audiodev"; @@ -301,6 +342,10 @@ static bool open_devices(void) VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev); VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &audiodev); + if (strcmp(videodev.value, "dummy") == 0) { + return true; + } + /* Video device is required */ if (videodev.value == NULL) { @@ -309,19 +354,19 @@ static bool open_devices(void) } /* Open the V4L2 device */ - video_fd = v4l2_open(videodev.value, O_RDWR, 0); - if (video_fd == -1) + video_device_fd = v4l2_open(videodev.value, O_RDWR, 0); + if (video_device_fd == -1) { printf("Couldn't open %s: %s\n", videodev.value, strerror(errno)); return false; } /* Query V4L2 device capabilities */ - error = v4l2_ioctl(video_fd, VIDIOC_QUERYCAP, &caps); + error = v4l2_ioctl(video_device_fd, VIDIOC_QUERYCAP, &caps); if (error != 0) { printf("VIDIOC_QUERYCAP failed: %s\n", strerror(errno)); - v4l2_close(video_fd); + v4l2_close(video_device_fd); return false; } @@ -339,7 +384,7 @@ static bool open_devices(void) unsigned int rate; /* - * Open the audio capture device and configure it for 48kHz, 16-bit stereo + * Open the audio capture device and configure it for 44kHz, 16-bit stereo */ error = snd_pcm_open(&audio_handle, audiodev.value, SND_PCM_STREAM_CAPTURE, 0); if (error < 0) @@ -422,10 +467,10 @@ static void close_devices(void) } #endif - if (video_fd != -1) + if (video_device_fd != -1) { - v4l2_close(video_fd); - video_fd = -1; + v4l2_close(video_device_fd); + video_device_fd = -1; } } @@ -450,27 +495,49 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_get_system_info)(struct retro_system_ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_get_system_av_info)(struct retro_system_av_info *info) { + struct retro_variable videodev = { "videoproc_videodev", NULL }; struct v4l2_cropcap cc; int error; - /* - * Query the device cropping limits. If available, we can use this to find the capture pixel aspect. - */ - memset(&cc, 0, sizeof(cc)); - cc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - error = v4l2_ioctl(video_fd, VIDIOC_CROPCAP, &cc); - if (error == 0) - info->geometry.aspect_ratio = (double)cc.pixelaspect.denominator - / (double)cc.pixelaspect.numerator; + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev); - info->geometry.base_width = info->geometry.max_width = video_format.fmt.pix.width; - info->geometry.base_height = info->geometry.max_height = video_format.fmt.pix.height; - info->timing.fps = (double)video_standard.frameperiod.denominator / - (double)video_standard.frameperiod.numerator; - info->timing.sample_rate = AUDIO_SAMPLE_RATE; + if (strcmp(videodev.value, "dummy") == 0) { + info->geometry.aspect_ratio = 4.0/3.0; + info->geometry.base_width = info->geometry.max_width = video_cap_width; + info->geometry.base_height = video_cap_height; //out? + info->geometry.max_height = video_out_height; + info->timing.fps = 60; + info->timing.sample_rate = AUDIO_SAMPLE_RATE; + } else { + /* + * Query the device cropping limits. If available, we can use this to find the capture pixel aspect. + */ + memset(&cc, 0, sizeof(cc)); + cc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + error = v4l2_ioctl(video_device_fd, VIDIOC_CROPCAP, &cc); - printf("Resolution %ux%u %f fps\n", info->geometry.base_width, - info->geometry.base_height, info->timing.fps); + info->geometry.base_width = info->geometry.max_width = video_format.fmt.pix.width; + info->geometry.base_height = video_format.fmt.pix.height; + //TODO Only double if frames are NOT fields (interlaced, full resolution) + info->geometry.max_height = video_format.fmt.pix.height * 2; + //TODO Only double if frames ARE fields (progressive or deinterlaced, full framerate) + // *2 for fields + info->timing.fps = ((double)(video_standard.frameperiod.denominator*2)) / + (double)video_standard.frameperiod.numerator; + info->timing.sample_rate = AUDIO_SAMPLE_RATE; + + if (error == 0) { + //TODO Allow for fixed 4:3 and 16:9 modes + info->geometry.aspect_ratio = (double)info->geometry.base_width / (double)info->geometry.max_height /\ + ((double)cc.pixelaspect.numerator / (double)cc.pixelaspect.denominator); + } + } + + printf("Aspect ratio: %f\n",info->geometry.aspect_ratio); + printf("Buffer Resolution %ux%u %f fps\n", info->geometry.base_width, + info->geometry.base_height, info->timing.fps); + printf("Buffer Max Resolution %ux%u\n", info->geometry.max_width, + info->geometry.max_height); } RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_controller_port_device)(unsigned port, unsigned device) @@ -483,23 +550,99 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_reset)(void) open_devices(); } -RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) -{ - struct v4l2_buffer buf; - uint8_t *src; - uint16_t *dst; - int i, error; +//TODO improve this mess and make it generic enough for use with dummy mode +void v4l2_frame_times(struct v4l2_buffer buf) { + if (strcmp("Off", video_frame_times) == 0) + return; - VIDEOPROC_CORE_PREFIX(input_poll_cb)(); + if (ft_info == NULL) + ft_info = calloc(5000, sizeof(char)); - if (video_fd == -1) - return; + if ( (buf.timestamp.tv_sec - ft_prevtime.tv_sec >= 1) && \ + (buf.timestamp.tv_usec + 1000000 - ft_prevtime2.tv_usec) >= 1000000) { + double csec = ((double) buf.timestamp.tv_sec) + (buf.timestamp.tv_usec/1000000); + double psec = ((double) ft_prevtime.tv_sec) + (ft_prevtime.tv_usec/1000000); + printf("Fields last %.2f seconds: %d\n", csec - psec, ft_fcount); + printf("Average frame times: %.3fms\n", ft_favg/(1000*ft_fcount)); + printf("Fields timestampdiffs last second:\n%s\n", ft_info); + free(ft_info); + ft_info = calloc(5000, sizeof(char)); + ft_fcount = 0; + ft_favg = 0; + ft_prevtime = buf.timestamp; + } + ft_fcount++; + ft_info2 = strdup(ft_info); + ft_ftime = (double) (buf.timestamp.tv_usec + ((buf.timestamp.tv_sec - ft_prevtime2.tv_sec >= 1) ? 1000000 : 0) - ft_prevtime2.tv_usec); + ft_favg += ft_ftime; + snprintf(ft_info, 5000 * sizeof(char), "%s %6.d %d %d %.2fms%s", ft_info2, buf.sequence, buf.index, buf.field, ft_ftime/1000, (!(ft_fcount % 7)) ? "\n" : ""); + free(ft_info2); - memset(&buf, 0, sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; + ft_prevtime2 = buf.timestamp; +} - error = v4l2_ioctl(video_fd, VIDIOC_DQBUF, &buf); +void source_dummy(int width, int height) { + int i, triangpos, triangpos_t=0, triangpos_b=0, offset=0; + bool field_ahead = false; + uint8_t *src = frame_cap; + float step = M_PI/64; + + if (video_buf.field == V4L2_FIELD_TOP) { + offset=0; + } else if (video_buf.field == V4L2_FIELD_BOTTOM) { + offset=1; + } + + dummy_pos += step; + //dummy_pos = M_PI/4; step = 0; // no animation + triangpos = (sinf(dummy_pos)+1)/2*width; + if (video_buf.field == V4L2_FIELD_INTERLACED) { + if (video_half_feed_rate == 0) + video_half_feed_rate = 1; + triangpos_t = (sinf(dummy_pos)+1)/2*width; + dummy_pos += step; + triangpos_b = (sinf(dummy_pos)+1)/2*width; + } + + for (i = 0; i < width * height; i+=1, src+=3) { + float color = (clamp_float((float)(triangpos - (i%width) + offset)/10, -1, 1)+1)/2; + src[0] = 0x10 + color*0xE0; + src[1] = 0x10 + color*0xE0; + src[2] = 0x10 + color*0xE0; + + // End of a line + if ( ((i+1) % width) == 0 ) { + triangpos -= 2; //offset should be half of this? + triangpos_t -= 1; + triangpos_b -= 1; + if (video_buf.field == V4L2_FIELD_INTERLACED) { + if (field_ahead) { + triangpos = triangpos_b; + field_ahead = false; + } else { + triangpos = triangpos_t; + field_ahead = true; + } + } + } + } + + if(video_buf.field == V4L2_FIELD_TOP) + video_buf.field = V4L2_FIELD_BOTTOM; + else if (video_buf.field == V4L2_FIELD_BOTTOM) + video_buf.field = V4L2_FIELD_TOP; +} + +void source_v4l2_normal(int width, int height) { + struct v4l2_buffer bufcp; + + int error; + + // Wait until v4l2 dequees a buffer + memset(&video_buf, 0, sizeof(struct v4l2_buffer)); + video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + video_buf.memory = V4L2_MEMORY_MMAP; + error = v4l2_ioctl(video_device_fd, VIDIOC_DQBUF, &video_buf); if (error != 0) { printf("VIDIOC_DQBUF failed: %s\n", strerror(errno)); @@ -507,19 +650,329 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) return; } - src = (uint8_t*)video_buffer[buf.index].start; - dst = (uint16_t*)conv_data; - - /* RGB24 to RGB565 */ - for (i = 0; i < video_format.fmt.pix.width * video_format.fmt.pix.height; i++, src += 3, dst += 1) - *dst = ((src[0] >> 3) << 11) | ((src[1] >> 2) << 5) | ((src[2] >> 3) << 0); - - error = v4l2_ioctl(video_fd, VIDIOC_QBUF, &buf); + bufcp = video_buf; + memcpy( (uint32_t*) frame_cap, (uint8_t*) v4l2_capbuf[video_buf.index].start, video_format.fmt.pix.width * video_format.fmt.pix.height * 3); + + error = v4l2_ioctl(video_device_fd, VIDIOC_QBUF, &video_buf); if (error != 0) printf("VIDIOC_QBUF failed: %s\n", strerror(errno)); - VIDEOPROC_CORE_PREFIX(video_refresh_cb)(conv_data, video_format.fmt.pix.width, - video_format.fmt.pix.height, video_format.fmt.pix.width * 2); + v4l2_frame_times(bufcp); +} + + +void source_v4l2_alternate_hack(int width, int height) { + struct v4l2_buffer bufcp; + struct v4l2_format fmt; + struct v4l2_requestbuffers reqbufs; + enum v4l2_buf_type type; + + int error; + uint32_t index; + + // For later, saving time + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + error = v4l2_ioctl(video_device_fd, VIDIOC_G_FMT, &fmt); + if (error != 0) + { + printf("VIDIOC_G_FMT failed: %s\n", strerror(errno)); + } + + // Wait until v4l2 dequees a buffer + memset(&video_buf, 0, sizeof(struct v4l2_buffer)); + video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + video_buf.memory = V4L2_MEMORY_MMAP; + error = v4l2_ioctl(video_device_fd, VIDIOC_DQBUF, &video_buf); + if (error != 0) + { + printf("VIDIOC_DQBUF failed: %s\n", strerror(errno)); + VIDEOPROC_CORE_PREFIX(video_refresh_cb)(NULL, 0, 0, 0); + return; + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2_ioctl(video_device_fd, VIDIOC_STREAMOFF, &type); + + //Let's get the data as fast as possible! + bufcp = video_buf; + memcpy( (uint32_t*) frame_cap, (uint8_t*) v4l2_capbuf[video_buf.index].start, video_format.fmt.pix.width * video_format.fmt.pix.height * 3); + + v4l2_munmap(v4l2_capbuf[0].start, v4l2_capbuf[0].len); + + if (video_buf.field == V4L2_FIELD_TOP) + fmt.fmt.pix.field = V4L2_FIELD_BOTTOM; + else + fmt.fmt.pix.field = V4L2_FIELD_TOP; + + error = v4l2_ioctl(video_device_fd, VIDIOC_S_FMT, &fmt); + if (error != 0) + { + printf("VIDIOC_S_FMT failed: %s\n", strerror(errno)); + } + + video_format = fmt; + + memset(&reqbufs, 0, sizeof(reqbufs)); + reqbufs.count = v4l2_ncapbuf_target; + reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbufs.memory = V4L2_MEMORY_MMAP; + + error = v4l2_ioctl(video_device_fd, VIDIOC_REQBUFS, &reqbufs); + if (error != 0) + { + printf("VIDIOC_REQBUFS failed: %s\n", strerror(errno)); + } + v4l2_ncapbuf = reqbufs.count; + //printf("GOT v4l2_ncapbuf=%ld\n", v4l2_ncapbuf); + + index = 0; + memset(&video_buf, 0, sizeof(struct v4l2_buffer)); + video_buf.index = index; + video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + video_buf.memory = V4L2_MEMORY_MMAP; + + v4l2_ioctl(video_device_fd, VIDIOC_QUERYBUF, &video_buf); + v4l2_capbuf[index].len = video_buf.length; + v4l2_capbuf[index].start = v4l2_mmap(NULL, video_buf.length, + PROT_READ|PROT_WRITE, MAP_SHARED, video_device_fd, video_buf.m.offset); + memset(&video_buf, 0, sizeof(struct v4l2_buffer)); + + video_buf.index = index; + video_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + video_buf.memory = V4L2_MEMORY_MMAP; + + v4l2_ioctl(video_device_fd, VIDIOC_QBUF,& video_buf); + + //error = v4l2_ioctl(video_device_fd, VIDIOC_QBUF, &video_buf); + //if (error != 0) + // printf("VIDIOC_QBUF failed: %s\n", strerror(errno)); + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + error = v4l2_ioctl(video_device_fd, VIDIOC_STREAMON, &type); + if (error != 0) + { + printf("VIDIOC_STREAMON failed: %s\n", strerror(errno)); + } + + v4l2_frame_times(bufcp); +} + +void processing_heal(uint8_t *src, int width, int height) { + uint32_t *fp1 = frame_prev1; + for (int i = 0; i < width * height; i+=1, src += 3, ++fp1) { + // Tries to filter a bunch of blanked out scanline sections my capture cards spits out with this crazy hack + // Since the blanked out scanlines are set to a black value bellow anything that can be captued, it's quite + //easy to select the scanlines... + if (src[0] <= 0 && src[1] <= 0 && src[2] <= 0 && i >= width && i <= width * height - width) { + if (*(src + 0 - width*3) >= ((*fp1>> 0&0xFF)-6) && \ + *(src + 1 - width*3) >= ((*fp1>> 8&0xFF)-6) && \ + *(src + 2 - width*3) >= ((*fp1>>16&0xFF)-6) && \ + *(src + 0 - width*3) <= ((*fp1>> 0&0xFF)+6) && \ + *(src + 1 - width*3) <= ((*fp1>> 8&0xFF)+6) && \ + *(src + 2 - width*3) <= ((*fp1>>16&0xFF)+6)) { + src[0] = (*fp1>> 0&0xFF); + src[1] = (*fp1>> 8&0xFF); + src[2] = (*fp1>>16&0xFF); + } else { + src[0] = (*(fp1+i+width)>> 0&0xFF); + src[1] = (*(fp1+i+width)>> 8&0xFF); + src[2] = (*(fp1+i+width)>>16&0xFF); + } + } + } +} + +void processing_deinterlacing_crap(uint32_t *src, uint32_t *dst, int width, int height, enum v4l2_field field, int skip_lines_src) { + int i, targetrow=0; + uint32_t pixacul=0; + uint32_t *fp1 = frame_prev1, *fp2 = frame_prev2, *fp3 = frame_prev3; + + // Helps pointing to the pixel in the adjacent row + if (field == V4L2_FIELD_TOP) + targetrow = width; + else + targetrow = width*-1; + + // Starts from the even scanline if frame contains bottom fields + //On progressive sources, should only skip the destination lines, since all lines the source are the same fields + //On interlaced sources, should skip both the source and the destination lines, since only half the lines in the source are the same fields (must also skip fields later) + if (field == V4L2_FIELD_BOTTOM) { + dst += width; + if (skip_lines_src == 1) { + src += width; + fp1 += width; + fp2 += width; + fp3 += width; + } + } + + for (i = 0; i < width * height; i+=1, src += 1, dst += 1, ++fp1, ++fp2, ++fp3) { + // Will fill the current destination line with current field + //The masking is used to prserve some information set by the + //deinterlacing process, uses the alpha channel to tell if a + //pixel needs further processing... + *(dst) = (*(src) & 0x00FFFFFF) | (*dst & 0xFF000000); + + // Crappy deinterlacing + if (i >= width && i <= (width*height-width)) { + pixacul=((((*(dst)>> 0&0xFF) + (pixacul>> 0&0xFF))>>1<<0 |\ + ((*(dst)>> 8&0xFF) + (pixacul>> 8&0xFF))>>1<<8 |\ + ((*(dst)>>16&0xFF) + (pixacul>>16&0xFF))>>1<<16) \ + & 0x00FFFFFF) | 0xFE000000; + + if ( ((*(dst ) & 0xFF000000) == 0xFE000000) ||\ + ((*(dst+targetrow) & 0xFF000000) == 0xFE000000) ) { + *dst = pixacul | 0xFF000000; + *(dst+targetrow) = pixacul | 0xFF000000; + } else { + if (!(((*(src+0)>> 0&0xFF) >= ((*(fp2+0)>> 0&0xFF)-9) ) &&\ + ((*(src+0)>> 8&0xFF) >= ((*(fp2+0)>> 8&0xFF)-9) ) &&\ + ((*(src+0)>>16&0xFF) >= ((*(fp2+0)>>16&0xFF)-9) ) &&\ + ((*(src+0)>> 0&0xFF) <= ((*(fp2+0)>> 0&0xFF)+9) ) &&\ + ((*(src+0)>> 8&0xFF) <= ((*(fp2+0)>> 8&0xFF)+9) ) &&\ + ((*(src+0)>>16&0xFF) <= ((*(fp2+0)>>16&0xFF)+9) )) ) { + *(dst+targetrow) = pixacul; + } else if (!(((*fp3>> 0&0xFF) >= ((*fp1>> 0&0xFF)-9) ) &&\ + ((*fp3>> 8&0xFF) >= ((*fp1>> 8&0xFF)-9) ) &&\ + ((*fp3>>16&0xFF) >= ((*fp1>>16&0xFF)-9) ) &&\ + ((*fp3>> 0&0xFF) <= ((*fp1>> 0&0xFF)+9) ) &&\ + ((*fp3>> 8&0xFF) <= ((*fp1>> 8&0xFF)+9) ) &&\ + ((*fp3>>16&0xFF) <= ((*fp1>>16&0xFF)+9) ))) { + *(dst+targetrow) = pixacul; + } + } + } + + // Skips a scanline if we reach the end of the current one + //On progressive sources, should only skip the destination lines, + //On interlaced sources, should skip both the source and the destination lines + if ( ((i+1) % width) == 0 ) { + dst += width; + if (skip_lines_src == 1) { + src += width; + fp1 += width; + fp2 += width; + fp3 += width; + } + } + } +} + +void processing_bgr_xrgb(uint8_t *src, uint32_t *dst, int width, int height) { + /* BGR24 to XRGB8888 conversion */ + for (int i = 0; i < width * height; i+=1, src += 3, dst += 1) { + *dst = 0xFF << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; + } +} + +RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void) +{ + uint32_t *aux; + struct retro_variable videodev = { "videoproc_videodev", NULL }; + struct retro_variable audiodev = { "videoproc_audiodev", NULL }; + struct retro_variable capturemode = { "videoproc_capture_mode", NULL }; + struct retro_variable outputmode = { "videoproc_output_mode", NULL }; + struct retro_variable frametimes = { "videoproc_frame_times", NULL }; + bool updated = false; + + if (VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) { + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &audiodev); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &capturemode); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &outputmode); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &frametimes); + // Video or Audio device(s) has(ve) been changed + //TODO We may get away without reseting devices when changing output mode... + if ((videodev.value && (strcmp(video_device, videodev.value) != 0)) ||\ + (audiodev.value && (strcmp(audio_device, audiodev.value) != 0)) ||\ + (capturemode.value && (strcmp(video_capture_mode, capturemode.value) != 0)) ||\ + (outputmode.value && (strcmp(video_output_mode, outputmode.value) != 0))) { + VIDEOPROC_CORE_PREFIX(retro_unload_game)(); + // This core does not cares for the retro_game_info * argument? + VIDEOPROC_CORE_PREFIX(retro_load_game)(NULL); + } + + if (frametimes.value != NULL) { + strncpy(video_frame_times, frametimes.value, ENVVAR_BUFLEN-1); + } + } + + VIDEOPROC_CORE_PREFIX(input_poll_cb)(); + + //printf("%d %d %d %s\n", video_cap_width, video_cap_height, video_buf.field, video_output_mode); + //TODO pass frame_curr to source_* functions + //half_feed_rate allows interlaced intput to be fed at half the calls to this function + //where the same frame is then read by the deinterlacer twice, for each field + if (video_half_feed_rate == 0) { + // Capture + if (strcmp(video_device, "dummy") == 0) { + source_dummy(video_cap_width, video_cap_height); + } else { + if (strcmp(video_capture_mode, "alternate_hack") == 0) { + source_v4l2_alternate_hack(video_cap_width, video_cap_height); + processing_heal(frame_cap, video_cap_width, video_cap_height); + } else { + source_v4l2_normal(video_cap_width, video_cap_height); + } + } + + if (video_buf.field == V4L2_FIELD_INTERLACED) + video_half_feed_rate = 1; + } else { + video_half_feed_rate = 0; + } + + // Converts from bgr to xrgb, deinterlacing, final copy to the outpuit buffer (frame_out) + //Every frame except frame_cap shall be encoded in xrgb + //Every frame except frame_out shall have the same height + if (strcmp(video_output_mode, "deinterlaced") == 0) { + processing_bgr_xrgb(frame_cap, frame_curr, video_cap_width, video_cap_height); + // When deinterlacing a interlaced intput, we need to process both fields of a frame, + //one at a time (retro_run needs to be called twice, vide_half_feed_rate prevents the + //source from being read twice... + if (strcmp(video_capture_mode, "interlaced") == 0) { + enum v4l2_field field_read; + if (video_half_feed_rate == 0) + field_read = V4L2_FIELD_TOP; + else + field_read = V4L2_FIELD_BOTTOM; + //video_half_feed_rate will allow us to capture the interlaced frame once and run the + //deinterlacing algo twice, extracting a given field for each run. + processing_deinterlacing_crap(frame_curr, frame_out, video_cap_width, video_cap_height/2, field_read, 1); + } else { + processing_deinterlacing_crap(frame_curr, frame_out, video_cap_width, video_cap_height, video_buf.field, 0); + } + aux = frame_prev3; + frame_prev3 = frame_prev2; + frame_prev2 = frame_prev1; + frame_prev1 = frame_curr; + frame_curr = aux; + + VIDEOPROC_CORE_PREFIX(video_refresh_cb)(frame_out, video_cap_width, + video_out_height, video_cap_width * sizeof(uint32_t)); + } else if (strcmp(video_capture_mode, "alternate_hack") == 0) { + // Case where alternate_hack without deinterlacing would not generate previous frame for processing_heal + processing_bgr_xrgb(frame_cap, frame_curr, video_cap_width, video_cap_height); + aux = frame_prev3; + frame_prev3 = frame_prev2; + frame_prev2 = frame_prev1; + frame_prev1 = frame_curr; + frame_curr = aux; + + aux = frame_out; + frame_out = frame_curr; + + VIDEOPROC_CORE_PREFIX(video_refresh_cb)(frame_out, video_cap_width, + video_out_height, video_cap_width * sizeof(uint32_t)); + + frame_out = aux; + } else { + processing_bgr_xrgb(frame_cap, frame_out, video_cap_width, video_out_height); + + VIDEOPROC_CORE_PREFIX(video_refresh_cb)(frame_out, video_cap_width, + video_out_height, video_cap_width * sizeof(uint32_t)); + } } RETRO_API size_t VIDEOPROC_CORE_PREFIX(retro_serialize_size)(void) @@ -545,8 +998,26 @@ RETRO_API void VIDEOPROC_CORE_PREFIX(retro_cheat_set)(unsigned index, bool enabl { } +static void videoinput_set_control_v4l2( uint32_t id, double val ) +{ + //struct v4l2_queryctrl query; + + //query.id = id; + //if( ioctl( video_device_fd, VIDIOC_QUERYCTRL, &query ) >= 0 && !(query.flags & V4L2_CTRL_FLAG_DISABLED) ) { + // struct v4l2_control control; + // control.id = id; + // control.value = query.minimum + ((int) ((val * ((double) (query.maximum - query.minimum))) + 0.5)); + // ioctl( video_device_fd, VIDIOC_S_CTRL, &control ); + //} +} + RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_info *game) { + struct retro_variable videodev = { "videoproc_videodev", NULL }; + struct retro_variable audiodev = { "videoproc_audiodev", NULL }; + struct retro_variable capture_mode = { "videoproc_capture_mode", NULL }; + struct retro_variable output_mode = { "videoproc_output_mode", NULL }; + struct retro_variable frame_times = { "videoproc_frame_times", NULL }; enum retro_pixel_format pixel_format; struct v4l2_standard std; struct v4l2_requestbuffers reqbufs; @@ -565,154 +1036,323 @@ RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_in return false; } - memset(&fmt, 0, sizeof(fmt)); - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +#ifdef HAVE_ALSA + if (audio_handle != NULL) { + struct retro_audio_callback audio_cb; + audio_cb.callback = audio_callback; + audio_cb.set_state = audio_set_state; + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, &audio_cb); + } +#endif - error = v4l2_ioctl(video_fd, VIDIOC_G_FMT, &fmt); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev); + if (videodev.value == NULL) { + close_devices(); + return false; + } + strncpy(video_device, videodev.value, ENVVAR_BUFLEN-1); - if (error != 0) - { - printf("VIDIOC_G_FMT failed: %s\n", strerror(errno)); - return false; + // Audio device is optional... + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &audiodev); + if (audiodev.value != NULL) { + strncpy(audio_device, audiodev.value, ENVVAR_BUFLEN-1); } - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; - error = v4l2_ioctl(video_fd, VIDIOC_S_FMT, &fmt); - if (error != 0) - { - printf("VIDIOC_S_FMT failed: %s\n", strerror(errno)); - return false; + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &capture_mode); + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &output_mode); + if (capture_mode.value == NULL || output_mode.value == NULL) { + close_devices(); + return false; + } + strncpy(video_capture_mode, capture_mode.value, ENVVAR_BUFLEN-1); + strncpy(video_output_mode, output_mode.value, ENVVAR_BUFLEN-1); + + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &frame_times); + if (frame_times.value != NULL) { + strncpy(video_frame_times, frame_times.value, ENVVAR_BUFLEN-1); } - error = v4l2_ioctl(video_fd, VIDIOC_G_STD, &std_id); - if (error != 0) - { - printf("VIDIOC_G_STD failed: %s\n", strerror(errno)); - return false; - } - for (index = 0, std_found = false; ; index++) - { - memset(&std, 0, sizeof(std)); - std.index = index; - error = v4l2_ioctl(video_fd, VIDIOC_ENUMSTD, &std); - if (error) - break; - if (std.id == std_id) - { - video_standard = std; - std_found = true; + if (strcmp(video_device, "dummy") == 0) { + if (strcmp(video_capture_mode, "interlaced") == 0) { + video_format.fmt.pix.height = 480; + video_cap_height = 480; + video_buf.field = V4L2_FIELD_INTERLACED; + } else if (strcmp(video_capture_mode, "alternate") == 0 ||\ + strcmp(video_capture_mode, "top") == 0 ||\ + strcmp(video_capture_mode, "bottom") == 0 ||\ + strcmp(video_capture_mode, "alternate_hack") == 0) { + video_format.fmt.pix.height = 240; + video_cap_height = 240; + video_buf.field = V4L2_FIELD_TOP; } - printf("VIDIOC_ENUMSTD[%u]: %s%s\n", index, std.name, std.id == std_id ? " [*]" : ""); - } - if (!std_found) - { - printf("VIDIOC_ENUMSTD did not contain std ID %08x\n", (unsigned)std_id); - return false; - } - video_format = fmt; + dummy_pos=0; + video_format.fmt.pix.width = 640; + video_cap_width = 640; + } else { + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memset(&reqbufs, 0, sizeof(reqbufs)); - reqbufs.count = VIDEO_BUFFERS; - reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - reqbufs.memory = V4L2_MEMORY_MMAP; + error = v4l2_ioctl(video_device_fd, VIDIOC_G_FMT, &fmt); - error = v4l2_ioctl(video_fd, VIDIOC_REQBUFS, &reqbufs); - if (error != 0) - { - printf("VIDIOC_REQBUFS failed: %s\n", strerror(errno)); - return false; - } - video_nbuffers = reqbufs.count; - - for (index = 0; index < video_nbuffers; index++) - { - memset(&buf, 0, sizeof(buf)); - buf.index = index; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - - error = v4l2_ioctl(video_fd, VIDIOC_QUERYBUF, &buf); if (error != 0) { - printf("VIDIOC_QUERYBUF failed for %u: %s\n", index, strerror(errno)); + printf("VIDIOC_G_FMT failed: %s\n", strerror(errno)); return false; } - video_buffer[index].len = buf.length; - video_buffer[index].start = v4l2_mmap(NULL, buf.length, - PROT_READ|PROT_WRITE, MAP_SHARED, video_fd, buf.m.offset); - if (video_buffer[index].start == MAP_FAILED) - { - printf("v4l2_mmap failed: %s\n", strerror(errno)); - return false; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24; + fmt.fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + fmt.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + fmt.fmt.pix.quantization = V4L2_QUANTIZATION_LIM_RANGE; + + fmt.fmt.pix.height = 240; + fmt.fmt.pix.field = V4L2_FIELD_TOP; + + //TODO Query the size and FPS + if (strcmp(video_capture_mode, "interlaced") == 0) { + v4l2_ncapbuf_target = 2; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + video_format.fmt.pix.height = 480; + video_cap_height = 480; + } else { + v4l2_ncapbuf_target = 2; + video_format.fmt.pix.height = 240; + video_cap_height = 240; + if (strcmp(video_capture_mode, "alternate") == 0) + fmt.fmt.pix.field = V4L2_FIELD_ALTERNATE; + else if (strcmp(video_capture_mode, "top") == 0) + fmt.fmt.pix.field = V4L2_FIELD_TOP; + else if (strcmp(video_capture_mode, "bottom") == 0) + fmt.fmt.pix.field = V4L2_FIELD_BOTTOM; + else if (strcmp(video_capture_mode, "alternate_hack") == 0) { + fmt.fmt.pix.field = V4L2_FIELD_TOP; + v4l2_ncapbuf_target = 1; + } } - } - for (index = 0; index < video_nbuffers; index++) - { - memset(&buf, 0, sizeof(buf)); - buf.index = index; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; + video_format.fmt.pix.width = 720; + video_cap_width = 720; - error = v4l2_ioctl(video_fd, VIDIOC_QBUF, &buf); + error = v4l2_ioctl(video_device_fd, VIDIOC_S_FMT, &fmt); if (error != 0) { - printf("VIDIOC_QBUF failed for %u: %s\n", index, strerror(errno)); + printf("VIDIOC_S_FMT failed: %s\n", strerror(errno)); return false; } + + error = v4l2_ioctl(video_device_fd, VIDIOC_G_STD, &std_id); + if (error != 0) + { + printf("VIDIOC_G_STD failed: %s\n", strerror(errno)); + return false; + } + for (index = 0, std_found = false; ; index++) + { + memset(&std, 0, sizeof(std)); + std.index = index; + error = v4l2_ioctl(video_device_fd, VIDIOC_ENUMSTD, &std); + if (error) + break; + if (std.id == std_id) + { + video_standard = std; + std_found = true; + } + printf("VIDIOC_ENUMSTD[%u]: %s%s\n", index, std.name, std.id == std_id ? " [*]" : ""); + } + if (!std_found) + { + printf("VIDIOC_ENUMSTD did not contain std ID %08x\n", (unsigned)std_id); + return false; + } + + video_format = fmt; + //TODO Check if what we got is indeed what we asked for + + memset(&reqbufs, 0, sizeof(reqbufs)); + reqbufs.count = v4l2_ncapbuf_target; + reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbufs.memory = V4L2_MEMORY_MMAP; + + error = v4l2_ioctl(video_device_fd, VIDIOC_REQBUFS, &reqbufs); + if (error != 0) + { + printf("VIDIOC_REQBUFS failed: %s\n", strerror(errno)); + return false; + } + v4l2_ncapbuf = reqbufs.count; + printf("GOT v4l2_ncapbuf=%ld\n", v4l2_ncapbuf); + + for (index = 0; index < v4l2_ncapbuf; index++) + { + memset(&buf, 0, sizeof(buf)); + buf.index = index; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + error = v4l2_ioctl(video_device_fd, VIDIOC_QUERYBUF, &buf); + if (error != 0) + { + printf("VIDIOC_QUERYBUF failed for %u: %s\n", index, strerror(errno)); + return false; + } + + v4l2_capbuf[index].len = buf.length; + v4l2_capbuf[index].start = v4l2_mmap(NULL, buf.length, + PROT_READ|PROT_WRITE, MAP_SHARED, video_device_fd, buf.m.offset); + if (v4l2_capbuf[index].start == MAP_FAILED) + { + printf("v4l2_mmap failed: %s\n", strerror(errno)); + return false; + } + } + + for (index = 0; index < v4l2_ncapbuf; index++) + { + memset(&buf, 0, sizeof(buf)); + buf.index = index; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + error = v4l2_ioctl(video_device_fd, VIDIOC_QBUF, &buf); + if (error != 0) + { + printf("VIDIOC_QBUF failed for %u: %s\n", index, strerror(errno)); + return false; + } + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + error = v4l2_ioctl(video_device_fd, VIDIOC_STREAMON, &type); + if (error != 0) + { + printf("VIDIOC_STREAMON failed: %s\n", strerror(errno)); + return false; + } + + //videoinput_set_control_v4l2(V4L2_CID_HUE, (double) 0.4f); } - conv_data = (uint16_t*)calloc(1, - video_format.fmt.pix.width * video_format.fmt.pix.height * 2); - if (!conv_data) + //TODO Framerates? + // Each frame should combine both fields into a full frame (if not already captured interlaced), half frame-rate + if (strcmp(video_output_mode, "interlaced") == 0) { + if (strcmp(video_capture_mode, "interlaced") == 0) { + video_out_height = video_cap_height; + } else { + printf("WARNING: Capture mode %s with output mode %s is not properly supported yet... (Is this even usefull?)\n", \ + video_capture_mode, video_output_mode); + video_out_height = video_cap_height*2; + } + // Each frame has one field, full frame-rate + } else if (strcmp(video_output_mode, "progressive") == 0) { + video_out_height = video_cap_height; + // Each frame has one or both field to be deinterlaced into a full frame (double the lines if one field), full frame-rate + } else if (strcmp(video_output_mode, "deinterlaced") == 0) { + if (strcmp(video_capture_mode, "interlaced") == 0) + video_out_height = video_cap_height; + else + video_out_height = video_cap_height*2; + } else + video_out_height = video_cap_height; + + printf("Capture Resolution %ux%u\n", video_cap_width, video_cap_height); + printf("Output Resolution %ux%u\n", video_cap_width, video_out_height); + + frame_cap = calloc(1, video_cap_width * video_cap_height * sizeof(uint8_t) * 3); + frame_out = calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); + //TODO: Only allocate frames if we are going to use it (for deinterlacing or other filters?) + frames[0] = calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); + frames[1] = calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); + frames[2] = calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); + frames[3] = calloc(1, video_cap_width * video_out_height * sizeof(uint32_t)); + + frame_curr = frames[0]; + frame_prev1 = frames[1]; + frame_prev2 = frames[2]; + frame_prev3 = frames[3]; + + //TODO: Check frames[] allocation + if (!frame_out || !frame_cap) { - printf("Cannot allocate conversion buffer\n"); + printf("Cannot allocate buffers\n"); return false; } - printf("Allocated %u byte conversion buffer\n", - video_format.fmt.pix.width * video_format.fmt.pix.height * 2); + printf("Allocated %lu byte conversion buffer\n", + video_cap_width * video_cap_height * sizeof(uint32_t)); - pixel_format = RETRO_PIXEL_FORMAT_RGB565; + pixel_format = RETRO_PIXEL_FORMAT_XRGB8888; if (!VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &pixel_format)) { printf("Cannot set pixel format\n"); return false; } - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - error = v4l2_ioctl(video_fd, VIDIOC_STREAMON, &type); - if (error != 0) - { - printf("VIDIOC_STREAMON failed: %s\n", strerror(errno)); - return false; - } - return true; } RETRO_API void VIDEOPROC_CORE_PREFIX(retro_unload_game)(void) { + struct v4l2_requestbuffers reqbufs; - if (video_fd != -1) +#ifdef HAVE_ALSA + if (audio_handle != NULL) { + VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, NULL); + } +#endif + + if ((strcmp(video_device, "dummy") != 0) && (video_device_fd != -1)) { uint32_t index; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - int error = v4l2_ioctl(video_fd, VIDIOC_STREAMOFF, &type); + int error = v4l2_ioctl(video_device_fd, VIDIOC_STREAMOFF, &type); if (error != 0) printf("VIDIOC_STREAMOFF failed: %s\n", strerror(errno)); - for (index = 0; index < video_nbuffers; index++) - v4l2_munmap(video_buffer[index].start, video_buffer[index].len); + for (index = 0; index < v4l2_ncapbuf; index++) + v4l2_munmap(v4l2_capbuf[index].start, v4l2_capbuf[index].len); + + reqbufs.count = 0; + reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbufs.memory = V4L2_MEMORY_MMAP; + error = v4l2_ioctl(video_device_fd, VIDIOC_REQBUFS, &reqbufs); + if (error != 0) + printf("VIDIOC_REQBUFS failed: %s\n", strerror(errno)); + } - if (conv_data) - free(conv_data); - conv_data = NULL; + if (frame_out) + free(frame_out); + frame_out = NULL; + + if (frame_cap) + free(frame_cap); + frame_cap = NULL; + + for (int i=0; i<4; ++i) { + if (frames[i]) + free(frames[i]); + frames[i] = NULL; + } + frame_curr = NULL; + frame_prev1 = NULL; + frame_prev2 = NULL; + frame_prev3 = NULL; + + if (ft_info) { + free(ft_info); + ft_info = NULL; + } + + if (ft_info2) { + free(ft_info2); + ft_info2 = NULL; + } close_devices(); + video_device[0] = '\0'; + audio_device[0] = '\0'; } RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game_special)(unsigned game_type, diff --git a/deps/discord-rpc/src/discord_register_win.cpp b/deps/discord-rpc/src/discord_register_win.cpp index e441318dd5..60b1db3e08 100644 --- a/deps/discord-rpc/src/discord_register_win.cpp +++ b/deps/discord-rpc/src/discord_register_win.cpp @@ -77,22 +77,22 @@ static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* comma wchar_t openCommand[1024]; if (command && command[0]) { - StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command); + StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", command); } else { // StringCbCopyW(openCommand, sizeof(openCommand), exeFilePath); - StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath); + StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", exeFilePath); } wchar_t protocolName[64]; - StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId); + StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%S", applicationId); wchar_t protocolDescription[128]; StringCbPrintfW( - protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId); + protocolDescription, sizeof(protocolDescription), L"URL:Run game %S protocol", applicationId); wchar_t urlProtocol = 0; wchar_t keyName[256]; - StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName); + StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%S", protocolName); HKEY key; auto status = RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr); diff --git a/deps/mbedtls/asn1write.c b/deps/mbedtls/asn1write.c index 69b61b205f..d7a1e33f7e 100644 --- a/deps/mbedtls/asn1write.c +++ b/deps/mbedtls/asn1write.c @@ -345,7 +345,7 @@ mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data return( NULL ); cur->oid.len = oid_len; - cur->oid.p = mbedtls_calloc( 1, oid_len ); + cur->oid.p = (unsigned char*)(unsigned char*)(unsigned char*)(unsigned char*)(unsigned char*)(unsigned char*)(unsigned char*)(unsigned char*)(unsigned char*)mbedtls_calloc( 1, oid_len ); if( cur->oid.p == NULL ) { mbedtls_free( cur ); @@ -355,7 +355,7 @@ mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data memcpy( cur->oid.p, oid, oid_len ); cur->val.len = val_len; - cur->val.p = mbedtls_calloc( 1, val_len ); + cur->val.p = (unsigned char*)mbedtls_calloc( 1, val_len ); if( cur->val.p == NULL ) { mbedtls_free( cur->oid.p ); @@ -378,7 +378,7 @@ mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data return( NULL ); mbedtls_free( cur->val.p ); - cur->val.p = p; + cur->val.p = (unsigned char*)p; cur->val.len = val_len; } diff --git a/deps/mbedtls/blowfish.c b/deps/mbedtls/blowfish.c index 5f97f77122..e11f186067 100644 --- a/deps/mbedtls/blowfish.c +++ b/deps/mbedtls/blowfish.c @@ -73,7 +73,264 @@ static const uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2] = { }; /* declarations of data at the end of this file */ -static const uint32_t S[4][256]; +static const uint32_t S[4][256] = { + { 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, + 0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, + 0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, + 0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, + 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, + 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, + 0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, + 0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, + 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, + 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, + 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, + 0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, + 0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, + 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, + 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, + 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, + 0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, + 0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, + 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, + 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, + 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, + 0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, + 0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, + 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, + 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, + 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, + 0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, + 0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, + 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, + 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, + 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, + 0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, + 0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, + 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, + 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, + 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, + 0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, + 0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, + 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, + 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, + 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, + 0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, + 0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, + 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, + 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, + 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, + 0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, + 0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, + 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, + 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, + 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, + 0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, + 0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, + 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, + 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, + 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, + 0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, + 0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, + 0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, + 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, + 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, + 0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, + 0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, + 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL }, + { 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, + 0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, + 0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, + 0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, + 0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, + 0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, + 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, + 0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, + 0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, + 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, + 0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, + 0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, + 0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, + 0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, + 0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, + 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, + 0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, + 0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, + 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, + 0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, + 0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, + 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, + 0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, + 0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, + 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, + 0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, + 0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, + 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, + 0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, + 0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, + 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, + 0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, + 0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, + 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, + 0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, + 0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, + 0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, + 0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, + 0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, + 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, + 0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, + 0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, + 0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, + 0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, + 0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, + 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, + 0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, + 0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, + 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, + 0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, + 0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, + 0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, + 0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, + 0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, + 0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, + 0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, + 0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, + 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, + 0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, + 0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, + 0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, + 0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, + 0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, + 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L }, + { 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, + 0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, + 0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, + 0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, + 0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, + 0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, + 0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, + 0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, + 0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, + 0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, + 0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, + 0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, + 0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, + 0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, + 0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, + 0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, + 0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, + 0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, + 0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, + 0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, + 0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, + 0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, + 0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, + 0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, + 0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, + 0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, + 0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, + 0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, + 0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, + 0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, + 0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, + 0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, + 0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, + 0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, + 0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, + 0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, + 0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, + 0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, + 0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, + 0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, + 0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, + 0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, + 0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, + 0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, + 0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, + 0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, + 0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, + 0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, + 0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, + 0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, + 0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, + 0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, + 0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, + 0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, + 0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, + 0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, + 0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, + 0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, + 0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, + 0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, + 0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, + 0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, + 0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, + 0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L }, + { 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, + 0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, + 0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, + 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, + 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, + 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, + 0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, + 0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, + 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, + 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, + 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, + 0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, + 0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, + 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, + 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, + 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, + 0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, + 0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, + 0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, + 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, + 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, + 0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, + 0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, + 0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, + 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, + 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, + 0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, + 0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, + 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, + 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, + 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, + 0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, + 0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, + 0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, + 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, + 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, + 0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, + 0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, + 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, + 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, + 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, + 0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, + 0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, + 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, + 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, + 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, + 0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, + 0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, + 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, + 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, + 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, + 0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, + 0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, + 0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, + 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, + 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, + 0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, + 0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, + 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, + 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, + 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, + 0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, + 0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, + 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L } +}; static uint32_t F( mbedtls_blowfish_context *ctx, uint32_t x ) { @@ -390,264 +647,6 @@ int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, } #endif /* MBEDTLS_CIPHER_MODE_CTR */ -static const uint32_t S[4][256] = { - { 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, - 0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, - 0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, - 0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, - 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, - 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, - 0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, - 0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, - 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, - 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, - 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, - 0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, - 0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, - 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, - 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, - 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, - 0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, - 0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, - 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, - 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, - 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, - 0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, - 0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, - 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, - 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, - 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, - 0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, - 0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, - 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, - 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, - 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, - 0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, - 0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, - 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, - 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, - 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, - 0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, - 0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, - 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, - 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, - 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, - 0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, - 0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, - 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, - 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, - 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, - 0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, - 0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, - 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, - 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, - 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, - 0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, - 0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, - 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, - 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, - 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, - 0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, - 0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, - 0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, - 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, - 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, - 0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, - 0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, - 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL }, - { 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, - 0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, - 0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, - 0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, - 0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, - 0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, - 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, - 0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, - 0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, - 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, - 0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, - 0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, - 0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, - 0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, - 0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, - 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, - 0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, - 0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, - 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, - 0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, - 0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, - 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, - 0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, - 0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, - 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, - 0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, - 0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, - 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, - 0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, - 0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, - 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, - 0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, - 0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, - 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, - 0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, - 0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, - 0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, - 0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, - 0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, - 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, - 0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, - 0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, - 0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, - 0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, - 0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, - 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, - 0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, - 0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, - 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, - 0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, - 0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, - 0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, - 0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, - 0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, - 0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, - 0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, - 0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, - 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, - 0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, - 0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, - 0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, - 0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, - 0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, - 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L }, - { 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, - 0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, - 0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, - 0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, - 0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, - 0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, - 0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, - 0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, - 0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, - 0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, - 0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, - 0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, - 0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, - 0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, - 0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, - 0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, - 0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, - 0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, - 0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, - 0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, - 0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, - 0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, - 0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, - 0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, - 0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, - 0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, - 0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, - 0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, - 0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, - 0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, - 0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, - 0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, - 0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, - 0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, - 0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, - 0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, - 0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, - 0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, - 0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, - 0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, - 0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, - 0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, - 0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, - 0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, - 0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, - 0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, - 0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, - 0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, - 0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, - 0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, - 0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, - 0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, - 0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, - 0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, - 0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, - 0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, - 0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, - 0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, - 0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, - 0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, - 0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, - 0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, - 0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, - 0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L }, - { 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, - 0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, - 0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, - 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, - 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, - 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, - 0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, - 0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, - 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, - 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, - 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, - 0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, - 0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, - 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, - 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, - 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, - 0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, - 0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, - 0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, - 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, - 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, - 0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, - 0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, - 0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, - 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, - 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, - 0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, - 0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, - 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, - 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, - 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, - 0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, - 0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, - 0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, - 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, - 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, - 0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, - 0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, - 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, - 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, - 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, - 0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, - 0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, - 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, - 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, - 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, - 0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, - 0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, - 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, - 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, - 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, - 0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, - 0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, - 0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, - 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, - 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, - 0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, - 0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, - 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, - 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, - 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, - 0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, - 0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, - 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L } -}; #endif /* !MBEDTLS_BLOWFISH_ALT */ #endif /* MBEDTLS_BLOWFISH_C */ diff --git a/deps/mbedtls/cipher_wrap.c b/deps/mbedtls/cipher_wrap.c index dc76af8ff4..dabc7a25d4 100644 --- a/deps/mbedtls/cipher_wrap.c +++ b/deps/mbedtls/cipher_wrap.c @@ -87,8 +87,8 @@ static void *gcm_ctx_alloc( void ) static void gcm_ctx_free( void *ctx ) { - mbedtls_gcm_free( ctx ); - mbedtls_free( ctx ); + mbedtls_gcm_free((mbedtls_gcm_context*)ctx); + mbedtls_free(ctx); } #endif /* MBEDTLS_GCM_C */ @@ -106,7 +106,7 @@ static void *ccm_ctx_alloc( void ) static void ccm_ctx_free( void *ctx ) { - mbedtls_ccm_free( ctx ); + mbedtls_ccm_free((mbedtls_ccm_context*)ctx); mbedtls_free( ctx ); } #endif /* MBEDTLS_CCM_C */ @@ -162,7 +162,7 @@ static int aes_setkey_enc_wrap( void *ctx, const unsigned char *key, static void * aes_ctx_alloc( void ) { - mbedtls_aes_context *aes = mbedtls_calloc( 1, sizeof( mbedtls_aes_context ) ); + mbedtls_aes_context *aes = (mbedtls_aes_context*)mbedtls_calloc( 1, sizeof( mbedtls_aes_context ) ); if( aes == NULL ) return( NULL ); @@ -518,8 +518,8 @@ static int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key, static void * camellia_ctx_alloc( void ) { - mbedtls_camellia_context *ctx; - ctx = mbedtls_calloc( 1, sizeof( mbedtls_camellia_context ) ); + mbedtls_camellia_context *ctx = (mbedtls_camellia_context*) + mbedtls_calloc( 1, sizeof( mbedtls_camellia_context ) ); if( ctx == NULL ) return( NULL ); @@ -906,7 +906,8 @@ static int des3_set3key_enc_wrap( void *ctx, const unsigned char *key, static void * des_ctx_alloc( void ) { - mbedtls_des_context *des = mbedtls_calloc( 1, sizeof( mbedtls_des_context ) ); + mbedtls_des_context *des = (mbedtls_des_context*) + mbedtls_calloc( 1, sizeof( mbedtls_des_context ) ); if( des == NULL ) return( NULL ); @@ -924,8 +925,7 @@ static void des_ctx_free( void *ctx ) static void * des3_ctx_alloc( void ) { - mbedtls_des3_context *des3; - des3 = mbedtls_calloc( 1, sizeof( mbedtls_des3_context ) ); + mbedtls_des3_context *des3 = (mbedtls_des3_context*)mbedtls_calloc( 1, sizeof( mbedtls_des3_context ) ); if( des3 == NULL ) return( NULL ); @@ -1123,8 +1123,7 @@ static int blowfish_setkey_wrap( void *ctx, const unsigned char *key, static void * blowfish_ctx_alloc( void ) { - mbedtls_blowfish_context *ctx; - ctx = mbedtls_calloc( 1, sizeof( mbedtls_blowfish_context ) ); + mbedtls_blowfish_context *ctx = (mbedtls_blowfish_context*)mbedtls_calloc( 1, sizeof( mbedtls_blowfish_context ) ); if( ctx == NULL ) return( NULL ); @@ -1233,8 +1232,7 @@ static int arc4_setkey_wrap( void *ctx, const unsigned char *key, static void * arc4_ctx_alloc( void ) { - mbedtls_arc4_context *ctx; - ctx = mbedtls_calloc( 1, sizeof( mbedtls_arc4_context ) ); + mbedtls_arc4_context *ctx = (mbedtls_arc4_context*)mbedtls_calloc( 1, sizeof( mbedtls_arc4_context ) ); if( ctx == NULL ) return( NULL ); diff --git a/deps/mbedtls/hmac_drbg.c b/deps/mbedtls/hmac_drbg.c index a32052b724..a8ed885c82 100644 --- a/deps/mbedtls/hmac_drbg.c +++ b/deps/mbedtls/hmac_drbg.c @@ -447,7 +447,7 @@ static size_t test_offset; static int hmac_drbg_self_test_entropy( void *data, unsigned char *buf, size_t len ) { - const unsigned char *p = data; + const unsigned char *p = (const unsigned char*)data; memcpy( buf, p + test_offset, len ); test_offset += len; return( 0 ); diff --git a/deps/mbedtls/pem.c b/deps/mbedtls/pem.c index 37e857e92c..2995d7fd70 100644 --- a/deps/mbedtls/pem.c +++ b/deps/mbedtls/pem.c @@ -323,7 +323,7 @@ int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER ) return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); - if( ( buf = mbedtls_calloc( 1, len ) ) == NULL ) + if( ( buf = (unsigned char*)mbedtls_calloc( 1, len ) ) == NULL ) return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) @@ -409,7 +409,7 @@ int mbedtls_pem_write_buffer( const char *header, const char *footer, return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); } - if( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) + if( ( encode_buf = (unsigned char*)mbedtls_calloc( 1, use_len ) ) == NULL ) return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data, diff --git a/deps/mbedtls/ssl_tls.c b/deps/mbedtls/ssl_tls.c index e417d1915a..6c136351c9 100644 --- a/deps/mbedtls/ssl_tls.c +++ b/deps/mbedtls/ssl_tls.c @@ -163,7 +163,7 @@ static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session { int ret; - dst->peer_cert = mbedtls_calloc( 1, sizeof(mbedtls_x509_crt) ); + dst->peer_cert = (mbedtls_x509_crt*)mbedtls_calloc( 1, sizeof(mbedtls_x509_crt) ); if( dst->peer_cert == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); @@ -182,7 +182,7 @@ static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) if( src->ticket != NULL ) { - dst->ticket = mbedtls_calloc( 1, src->ticket_len ); + dst->ticket = (unsigned char*)mbedtls_calloc( 1, src->ticket_len ); if( dst->ticket == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); @@ -2471,14 +2471,15 @@ static int ssl_flight_append( mbedtls_ssl_context *ssl ) mbedtls_ssl_flight_item *msg; /* Allocate space for current message */ - if( ( msg = mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL ) + if( ( msg = (mbedtls_ssl_flight_item*) + mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", sizeof( mbedtls_ssl_flight_item ) ) ); return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); } - if( ( msg->p = mbedtls_calloc( 1, ssl->out_msglen ) ) == NULL ) + if( ( msg->p = (unsigned char*)mbedtls_calloc( 1, ssl->out_msglen ) ) == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", ssl->out_msglen ) ); mbedtls_free( msg ); @@ -2950,7 +2951,7 @@ static int ssl_reassemble_dtls_handshake( mbedtls_ssl_context *ssl ) /* The bitmask needs one bit per byte of message excluding header */ alloc_len = 12 + msg_len + msg_len / 8 + ( msg_len % 8 != 0 ); - ssl->handshake->hs_msg = mbedtls_calloc( 1, alloc_len ); + ssl->handshake->hs_msg = (unsigned char*)mbedtls_calloc( 1, alloc_len ); if( ssl->handshake->hs_msg == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", alloc_len ) ); @@ -4453,7 +4454,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) mbedtls_free( ssl->session_negotiate->peer_cert ); } - if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1, + if( ( ssl->session_negotiate->peer_cert = (mbedtls_x509_crt*)mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ) ) == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", @@ -5506,17 +5507,17 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) */ if( ssl->transform_negotiate == NULL ) { - ssl->transform_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); + ssl->transform_negotiate = (mbedtls_ssl_transform*)mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); } if( ssl->session_negotiate == NULL ) { - ssl->session_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_session) ); + ssl->session_negotiate = (mbedtls_ssl_session*)mbedtls_calloc( 1, sizeof(mbedtls_ssl_session) ); } if( ssl->handshake == NULL ) { - ssl->handshake = mbedtls_calloc( 1, sizeof(mbedtls_ssl_handshake_params) ); + ssl->handshake = (mbedtls_ssl_handshake_params*)mbedtls_calloc( 1, sizeof(mbedtls_ssl_handshake_params) ); } /* All pointers should exist and can be directly freed without issue */ @@ -5610,8 +5611,8 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, /* * Prepare base structures */ - if( ( ssl-> in_buf = mbedtls_calloc( 1, len ) ) == NULL || - ( ssl->out_buf = mbedtls_calloc( 1, len ) ) == NULL ) + if( ( ssl-> in_buf = (unsigned char*)mbedtls_calloc( 1, len ) ) == NULL || + ( ssl->out_buf = (unsigned char*)mbedtls_calloc( 1, len ) ) == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", len ) ); mbedtls_free( ssl->in_buf ); @@ -5936,27 +5937,26 @@ static int ssl_append_key_cert( mbedtls_ssl_key_cert **head, mbedtls_x509_crt *cert, mbedtls_pk_context *key ) { - mbedtls_ssl_key_cert *new; - - new = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); - if( new == NULL ) + mbedtls_ssl_key_cert *keycert = (mbedtls_ssl_key_cert*) + mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); + if( keycert == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); - new->cert = cert; - new->key = key; - new->next = NULL; + keycert->cert = cert; + keycert->key = key; + keycert->next = NULL; /* Update head is the list was null, else add to the end */ if( *head == NULL ) { - *head = new; + *head = keycert; } else { mbedtls_ssl_key_cert *cur = *head; while( cur->next != NULL ) cur = cur->next; - cur->next = new; + cur->next = keycert; } return( 0 ); @@ -6054,8 +6054,8 @@ int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, conf->psk_identity = NULL; } - if( ( conf->psk = mbedtls_calloc( 1, psk_len ) ) == NULL || - ( conf->psk_identity = mbedtls_calloc( 1, psk_identity_len ) ) == NULL ) + if( ( conf->psk = (unsigned char*)mbedtls_calloc( 1, psk_len ) ) == NULL || + ( conf->psk_identity = (unsigned char*)mbedtls_calloc( 1, psk_identity_len ) ) == NULL ) { mbedtls_free( conf->psk ); mbedtls_free( conf->psk_identity ); @@ -6085,7 +6085,8 @@ int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, if( ssl->handshake->psk != NULL ) mbedtls_free( ssl->handshake->psk ); - if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) + if( ( ssl->handshake->psk = (unsigned char*) + mbedtls_calloc( 1, psk_len ) ) == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); ssl->handshake->psk_len = psk_len; @@ -6185,7 +6186,7 @@ int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ) if( hostname_len > MBEDTLS_SSL_MAX_HOST_NAME_LEN ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - ssl->hostname = mbedtls_calloc( 1, hostname_len + 1 ); + ssl->hostname = (char*)mbedtls_calloc( 1, hostname_len + 1 ); if( ssl->hostname == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); diff --git a/discord/discord.c b/discord/discord.c index 0a33824fa5..0efe85e036 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -16,8 +16,10 @@ #include #include "discord.h" +#include "discord_register.h" #include "../retroarch.h" +#include "../configuration.h" #include "../core.h" #include "../core_info.h" #include "../paths.h" @@ -35,7 +37,6 @@ #include "../cheevos/cheevos.h" #endif -static const char* APPLICATION_ID = "475456035851599874"; static int FrustrationLevel = 0; static int64_t start_time = 0; @@ -211,6 +212,7 @@ void discord_update(enum discord_presence presence) void discord_init(void) { + settings_t *settings = config_get_ptr(); DiscordEventHandlers handlers; RARCH_LOG("[Discord] initializing ..\n"); @@ -224,7 +226,11 @@ void discord_init(void) handlers.spectateGame = handle_discord_spectate; handlers.joinRequest = handle_discord_join_request; - Discord_Initialize(APPLICATION_ID, &handlers, 1, NULL); + /* To-Do: Add the arguments RetroArch was started with to the register URI*/ + const char command[256] = "retroarch"; + + Discord_Initialize(settings->arrays.discord_app_id, &handlers, 0, NULL); + Discord_Register(settings->arrays.discord_app_id, NULL); discord_ready = true; } diff --git a/driver.c b/driver.c index 68f5b314d7..a282df040c 100644 --- a/driver.c +++ b/driver.c @@ -18,8 +18,6 @@ #include #include -#include