From 3e10389106bb80698ddb90eec5a5e66ea18d8f8d Mon Sep 17 00:00:00 2001 From: Jesse Talavera-Greenberg Date: Thu, 20 Jul 2023 15:14:30 -0400 Subject: [PATCH 001/574] Create the file where the ffmpeg camera driver will be implemented --- Makefile.common | 5 +++-- Makefile.win | 1 + camera/drivers/ffmpeg.c | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 camera/drivers/ffmpeg.c diff --git a/Makefile.common b/Makefile.common index 3adbecfab3..6d81b6113f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2238,9 +2238,10 @@ ifeq ($(HAVE_FFMPEG), 1) cores/libretro-ffmpeg/ffmpeg_core.o \ cores/libretro-ffmpeg/packet_buffer.o \ cores/libretro-ffmpeg/video_buffer.o \ - $(LIBRETRO_COMM_DIR)/rthreads/tpool.o + $(LIBRETRO_COMM_DIR)/rthreads/tpool.o \ + camera/drivers/ffmpeg.o - LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS) + LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS) $(AVDEVICE_LIBS) DEFINES += -DHAVE_FFMPEG DEF_FLAGS += $(AVCODEC_CFLAGS) $(AVFORMAT_CFLAGS) $(AVUTIL_CFLAGS) $(SWSCALE_CFLAGS) $(SWRESAMPLE_CFLAGS) \ -Wno-deprecated-declarations diff --git a/Makefile.win b/Makefile.win index fcffc10ad9..e7c890d9e1 100644 --- a/Makefile.win +++ b/Makefile.win @@ -89,6 +89,7 @@ AVUTIL_LIBS := -lavutil SWSCALE_LIBS := -lswscale AVFORMAT_LIBS := -lavformat SWRESAMPLE_LIBS := -lswresample +AVDEVICE_LIBS := -lavdevice FFMPEG_LIBS := -lws2_32 -lz endif diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c new file mode 100644 index 0000000000..2a7a27c978 --- /dev/null +++ b/camera/drivers/ffmpeg.c @@ -0,0 +1,20 @@ +/* RetroArch - A frontend for libretro. +* Copyright (C) 2010-2023 - Hans-Kristian Arntzen +* Copyright (C) 2023 - Jesse Talavera-Greenberg +* +* 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 "../camera_driver.h" +#include "../../retroarch.h" From d9207c924e72d555268cd17c067cbe009c359601 Mon Sep 17 00:00:00 2001 From: Jesse Talavera-Greenberg Date: Thu, 20 Jul 2023 15:28:16 -0400 Subject: [PATCH 002/574] Add a stub ffmpeg camera driver --- camera/camera_driver.c | 3 +++ camera/camera_driver.h | 1 + camera/drivers/ffmpeg.c | 37 +++++++++++++++++++++++++++++++++++++ configuration.c | 5 +++++ griffin/griffin.c | 4 ++++ 5 files changed, 50 insertions(+) diff --git a/camera/camera_driver.c b/camera/camera_driver.c index 8609ef4621..56916afc8e 100644 --- a/camera/camera_driver.c +++ b/camera/camera_driver.c @@ -53,6 +53,9 @@ const camera_driver_t *camera_drivers[] = { #endif #ifdef ANDROID &camera_android, +#endif +#ifdef HAVE_FFMPEG + &camera_ffmpeg, #endif &camera_null, NULL, diff --git a/camera/camera_driver.h b/camera/camera_driver.h index 51ecb35d8f..2b81b3142b 100644 --- a/camera/camera_driver.h +++ b/camera/camera_driver.h @@ -65,6 +65,7 @@ extern camera_driver_t camera_v4l2; extern camera_driver_t camera_android; extern camera_driver_t camera_rwebcam; extern camera_driver_t camera_avfoundation; +extern camera_driver_t camera_ffmpeg; /** * config_get_camera_driver_options: diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 2a7a27c978..002faff109 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -18,3 +18,40 @@ #include "../camera_driver.h" #include "../../retroarch.h" + +void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) +{ + return NULL; +} + +void ffmpeg_camera_free(void *data) +{ + +} + +bool ffmpeg_camera_start(void *data) +{ + return false; +} + +void ffmpeg_camera_stop(void *data) +{ + +} + +bool ffmpeg_camera_poll( + void *data, + retro_camera_frame_raw_framebuffer_t frame_raw_cb, + retro_camera_frame_opengl_texture_t frame_gl_cb) +{ + +} + +camera_driver_t camera_ffmpeg = { + ffmpeg_camera_init, + ffmpeg_camera_free, + ffmpeg_camera_start, + ffmpeg_camera_stop, + ffmpeg_camera_poll, + "ffmpeg", +}; diff --git a/configuration.c b/configuration.c index 14ac60819a..d68dc43edd 100644 --- a/configuration.c +++ b/configuration.c @@ -222,6 +222,7 @@ enum camera_driver_enum CAMERA_RWEBCAM, CAMERA_ANDROID, CAMERA_AVFOUNDATION, + CAMERA_FFMPEG, CAMERA_NULL }; @@ -699,6 +700,8 @@ static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_V4L2; static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_RWEBCAM; #elif defined(ANDROID) static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_ANDROID; +#elif defined(HAVE_FFMPEG) +static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_FFMPEG; #else static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_NULL; #endif @@ -1275,6 +1278,8 @@ const char *config_get_default_camera(void) return "android"; case CAMERA_AVFOUNDATION: return "avfoundation"; + case CAMERA_FFMPEG: + return "ffmpeg"; case CAMERA_NULL: break; } diff --git a/griffin/griffin.c b/griffin/griffin.c index 3c194a3e2a..c96216b71e 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -794,6 +794,10 @@ CAMERA #include "../camera/drivers/video4linux2.c" #endif +#ifdef HAVE_FFMPEG +#include "../camera/drivers/ffmpeg.c" +#endif + #ifdef HAVE_VIDEOPROCESSOR #include "../cores/libretro-video-processor/video_processor_v4l2.c" #endif From ed04e1060a0e73a5925b2b4c7e34050d2a738fda Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Sat, 30 Nov 2024 18:59:26 -0500 Subject: [PATCH 003/574] Allocate the ffmpeg camera driver --- camera/drivers/ffmpeg.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 002faff109..c9e7355e44 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -17,25 +17,52 @@ #include #include "../camera_driver.h" -#include "../../retroarch.h" +#include "verbosity.h" + +typedef struct ffmpeg_camera +{ +} ffmpeg_camera_t; void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { - return NULL; + ffmpeg_camera_t *ffmpeg = NULL; + + if ((caps & (UINT64_C(1) << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER)) == 0) + { /* If the core didn't ask for raw framebuffers... */ + RARCH_ERR("[FFMPEG]: Camera driver only supports raw framebuffer output.\n"); + return NULL; + } + + ffmpeg = (ffmpeg_camera_t*)calloc(1, sizeof(*ffmpeg)); + if (!ffmpeg) + { + RARCH_ERR("[FFMPEG]: Failed to allocate memory for camera driver.\n"); + return NULL; + } + + return ffmpeg; } void ffmpeg_camera_free(void *data) { + ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; + if (!ffmpeg) + return; + + free(ffmpeg); } bool ffmpeg_camera_start(void *data) { + ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; + return false; } void ffmpeg_camera_stop(void *data) { + ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; } @@ -44,7 +71,9 @@ bool ffmpeg_camera_poll( retro_camera_frame_raw_framebuffer_t frame_raw_cb, retro_camera_frame_opengl_texture_t frame_gl_cb) { + ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; + return false; } camera_driver_t camera_ffmpeg = { From de3abdb5561fdd753d6834d383272fb8b1e19a0e Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Sun, 1 Dec 2024 18:29:30 -0500 Subject: [PATCH 004/574] Add some new camera_driver functions for retrieving a list of devices - Only ffmpeg will support these right now --- camera/camera_driver.c | 302 +++++++++++++++++----------------- camera/camera_driver.h | 5 + camera/drivers/android.c | 2 + camera/drivers/ffmpeg.c | 21 +++ camera/drivers/rwebcam.c | 2 + camera/drivers/video4linux2.c | 2 + 6 files changed, 185 insertions(+), 149 deletions(-) diff --git a/camera/camera_driver.c b/camera/camera_driver.c index 56916afc8e..5242c352f1 100644 --- a/camera/camera_driver.c +++ b/camera/camera_driver.c @@ -1,149 +1,153 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2021 - Daniel De Matteis - * - * 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 "../configuration.h" -#include "../driver.h" -#include "../list_special.h" -#include "../runloop.h" -#include "../verbosity.h" - -#include "camera_driver.h" - -static void *nullcamera_init(const char *device, uint64_t caps, - unsigned width, unsigned height) { return (void*)-1; } -static void nullcamera_free(void *data) { } -static void nullcamera_stop(void *data) { } -static bool nullcamera_start(void *data) { return true; } -static bool nullcamera_poll(void *a, - retro_camera_frame_raw_framebuffer_t b, - retro_camera_frame_opengl_texture_t c) { return true; } - -static camera_driver_t camera_null = { - nullcamera_init, - nullcamera_free, - nullcamera_start, - nullcamera_stop, - nullcamera_poll, - "null", -}; - -const camera_driver_t *camera_drivers[] = { -#ifdef HAVE_V4L2 - &camera_v4l2, -#endif -#ifdef EMSCRIPTEN - &camera_rwebcam, -#endif -#ifdef ANDROID - &camera_android, -#endif -#ifdef HAVE_FFMPEG - &camera_ffmpeg, -#endif - &camera_null, - NULL, -}; - -static camera_driver_state_t camera_driver_st = {0}; - -camera_driver_state_t *camera_state_get_ptr(void) -{ - return &camera_driver_st; -} - -/** - * config_get_camera_driver_options: - * - * Get an enumerated list of all camera driver names, - * separated by '|'. - * - * Returns: string listing of all camera driver names, - * separated by '|'. - **/ -const char *config_get_camera_driver_options(void) -{ - return char_list_new_special(STRING_LIST_CAMERA_DRIVERS, NULL); -} - -bool driver_camera_start(void) -{ - camera_driver_state_t *camera_st = &camera_driver_st; - if ( camera_st - && camera_st->data - && camera_st->driver - && camera_st->driver->start) - { - settings_t *settings = config_get_ptr(); - bool camera_allow = settings->bools.camera_allow; - if (camera_allow) - return camera_st->driver->start(camera_st->data); - - runloop_msg_queue_push( - "Camera is explicitly disabled.\n", 1, 180, false, - NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - } - return true; -} - -void driver_camera_stop(void) -{ - camera_driver_state_t *camera_st = &camera_driver_st; - if ( camera_st->driver - && camera_st->driver->stop - && camera_st->data) - camera_st->driver->stop(camera_st->data); -} - -bool camera_driver_find_driver(const char *prefix, - bool verbosity_enabled) -{ - settings_t *settings = config_get_ptr(); - camera_driver_state_t - *camera_st = &camera_driver_st; - int i = (int)driver_find_index( - "camera_driver", - settings->arrays.camera_driver); - - if (i >= 0) - camera_st->driver = (const camera_driver_t*)camera_drivers[i]; - else - { - if (verbosity_enabled) - { - unsigned d; - RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix, - settings->arrays.camera_driver); - RARCH_LOG_OUTPUT("Available %ss are:\n", prefix); - for (d = 0; camera_drivers[d]; d++) - { - if (camera_drivers[d]) - { - RARCH_LOG_OUTPUT("\t%s\n", camera_drivers[d]->ident); - } - } - - RARCH_WARN("Going to default to first %s...\n", prefix); - } - - if (!(camera_st->driver = (const camera_driver_t*)camera_drivers[0])) - return false; - } - return true; -} +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2021 - Daniel De Matteis + * + * 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 "../configuration.h" +#include "../driver.h" +#include "../list_special.h" +#include "../runloop.h" +#include "../verbosity.h" + +#include "camera_driver.h" + +static void *nullcamera_init(const char *device, uint64_t caps, + unsigned width, unsigned height) { return (void*)-1; } +static void nullcamera_free(void *data) { } +static void nullcamera_stop(void *data) { } +static bool nullcamera_start(void *data) { return true; } +static bool nullcamera_poll(void *a, + retro_camera_frame_raw_framebuffer_t b, + retro_camera_frame_opengl_texture_t c) { return true; } +static struct string_list *nullcamera_device_list_new(const void *data) { return NULL; } +static void nullcamera_device_list_free(const void *data, struct string_list *devices) {} + +static camera_driver_t camera_null = { + nullcamera_init, + nullcamera_free, + nullcamera_start, + nullcamera_stop, + nullcamera_poll, + nullcamera_device_list_new, + nullcamera_device_list_free, + "null", +}; + +const camera_driver_t *camera_drivers[] = { +#ifdef HAVE_V4L2 + &camera_v4l2, +#endif +#ifdef EMSCRIPTEN + &camera_rwebcam, +#endif +#ifdef ANDROID + &camera_android, +#endif +#ifdef HAVE_FFMPEG + &camera_ffmpeg, +#endif + &camera_null, + NULL, +}; + +static camera_driver_state_t camera_driver_st = {0}; + +camera_driver_state_t *camera_state_get_ptr(void) +{ + return &camera_driver_st; +} + +/** + * config_get_camera_driver_options: + * + * Get an enumerated list of all camera driver names, + * separated by '|'. + * + * Returns: string listing of all camera driver names, + * separated by '|'. + **/ +const char *config_get_camera_driver_options(void) +{ + return char_list_new_special(STRING_LIST_CAMERA_DRIVERS, NULL); +} + +bool driver_camera_start(void) +{ + camera_driver_state_t *camera_st = &camera_driver_st; + if ( camera_st + && camera_st->data + && camera_st->driver + && camera_st->driver->start) + { + settings_t *settings = config_get_ptr(); + bool camera_allow = settings->bools.camera_allow; + if (camera_allow) + return camera_st->driver->start(camera_st->data); + + runloop_msg_queue_push( + "Camera is explicitly disabled.\n", 1, 180, false, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } + return true; +} + +void driver_camera_stop(void) +{ + camera_driver_state_t *camera_st = &camera_driver_st; + if ( camera_st->driver + && camera_st->driver->stop + && camera_st->data) + camera_st->driver->stop(camera_st->data); +} + +bool camera_driver_find_driver(const char *prefix, + bool verbosity_enabled) +{ + settings_t *settings = config_get_ptr(); + camera_driver_state_t + *camera_st = &camera_driver_st; + int i = (int)driver_find_index( + "camera_driver", + settings->arrays.camera_driver); + + if (i >= 0) + camera_st->driver = (const camera_driver_t*)camera_drivers[i]; + else + { + if (verbosity_enabled) + { + unsigned d; + RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix, + settings->arrays.camera_driver); + RARCH_LOG_OUTPUT("Available %ss are:\n", prefix); + for (d = 0; camera_drivers[d]; d++) + { + if (camera_drivers[d]) + { + RARCH_LOG_OUTPUT("\t%s\n", camera_drivers[d]->ident); + } + } + + RARCH_WARN("Going to default to first %s...\n", prefix); + } + + if (!(camera_st->driver = (const camera_driver_t*)camera_drivers[0])) + return false; + } + return true; +} diff --git a/camera/camera_driver.h b/camera/camera_driver.h index 2b81b3142b..30f3cdebad 100644 --- a/camera/camera_driver.h +++ b/camera/camera_driver.h @@ -28,6 +28,8 @@ RETRO_BEGIN_DECLS +struct string_list; + typedef struct camera_driver { /* FIXME: params for initialization - queries for resolution, @@ -47,6 +49,9 @@ typedef struct camera_driver retro_camera_frame_raw_framebuffer_t frame_raw_cb, retro_camera_frame_opengl_texture_t frame_gl_cb); + struct string_list *(*device_list_new)(const void *driver_context); + void (*device_list_free)(const void *driver_context, struct string_list *devices); + const char *ident; } camera_driver_t; diff --git a/camera/drivers/android.c b/camera/drivers/android.c index 4428961096..f16ed6f47f 100644 --- a/camera/drivers/android.c +++ b/camera/drivers/android.c @@ -202,5 +202,7 @@ camera_driver_t camera_android = { android_camera_start, android_camera_stop, android_camera_poll, + NULL, + NULL, "android", }; diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index c9e7355e44..18e8037536 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -17,6 +17,7 @@ #include #include "../camera_driver.h" +#include "lists/string_list.h" #include "verbosity.h" typedef struct ffmpeg_camera @@ -76,11 +77,31 @@ bool ffmpeg_camera_poll( return false; } +static struct string_list *ffmpeg_camera_device_list_new(const void *driver_context) +{ + struct string_list *list = string_list_new(); + + if (!list) + return NULL; + + return list; +} + +static void ffmpeg_camera_device_list_free(const void *driver_context, struct string_list *devices) +{ + struct string_list *sl = (struct string_list*)devices; + + if (sl) + string_list_free(sl); +} + camera_driver_t camera_ffmpeg = { ffmpeg_camera_init, ffmpeg_camera_free, ffmpeg_camera_start, ffmpeg_camera_stop, ffmpeg_camera_poll, + ffmpeg_camera_device_list_new, + ffmpeg_camera_device_list_free, "ffmpeg", }; diff --git a/camera/drivers/rwebcam.c b/camera/drivers/rwebcam.c index 5a08e951ac..8cb9390583 100644 --- a/camera/drivers/rwebcam.c +++ b/camera/drivers/rwebcam.c @@ -65,5 +65,7 @@ camera_driver_t camera_rwebcam = { rwebcam_start, rwebcam_stop, rwebcam_poll, + NULL, + NULL, "rwebcam", }; diff --git a/camera/drivers/video4linux2.c b/camera/drivers/video4linux2.c index d1ff98e4d0..987d43d584 100644 --- a/camera/drivers/video4linux2.c +++ b/camera/drivers/video4linux2.c @@ -415,5 +415,7 @@ camera_driver_t camera_v4l2 = { v4l_start, v4l_stop, v4l_poll, + NULL, + NULL "video4linux2", }; From 29f31b34576af5d4fc706a0169bd71bf1ac7b409 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Mon, 2 Dec 2024 14:11:29 -0500 Subject: [PATCH 005/574] Remove some stray whitespace - Excluding this trivial change from commits is gonna drive me nuts --- camera/camera_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camera/camera_driver.c b/camera/camera_driver.c index 5242c352f1..922565cd68 100644 --- a/camera/camera_driver.c +++ b/camera/camera_driver.c @@ -119,7 +119,7 @@ bool camera_driver_find_driver(const char *prefix, bool verbosity_enabled) { settings_t *settings = config_get_ptr(); - camera_driver_state_t + camera_driver_state_t *camera_st = &camera_driver_st; int i = (int)driver_find_index( "camera_driver", From 4f88c4eb090607fa0e2ec19ecc3c48a50126c5bc Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Mon, 2 Dec 2024 20:41:28 -0500 Subject: [PATCH 006/574] Forgot a comma --- camera/drivers/video4linux2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camera/drivers/video4linux2.c b/camera/drivers/video4linux2.c index 987d43d584..b4d243ff0b 100644 --- a/camera/drivers/video4linux2.c +++ b/camera/drivers/video4linux2.c @@ -416,6 +416,6 @@ camera_driver_t camera_v4l2 = { v4l_stop, v4l_poll, NULL, - NULL + NULL, "video4linux2", }; From 1d618bf232497824578832e8c449e23d145c9752 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Tue, 3 Dec 2024 14:59:14 -0500 Subject: [PATCH 007/574] Mark the `ffmpeg_camera` functions as `static` - Other translation units don't need to worry about them --- camera/drivers/ffmpeg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 18e8037536..f940f84f76 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -24,7 +24,7 @@ typedef struct ffmpeg_camera { } ffmpeg_camera_t; -void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) +static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { ffmpeg_camera_t *ffmpeg = NULL; @@ -44,7 +44,7 @@ void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsi return ffmpeg; } -void ffmpeg_camera_free(void *data) +static void ffmpeg_camera_free(void *data) { ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; @@ -54,20 +54,20 @@ void ffmpeg_camera_free(void *data) free(ffmpeg); } -bool ffmpeg_camera_start(void *data) +static bool ffmpeg_camera_start(void *data) { ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; return false; } -void ffmpeg_camera_stop(void *data) +static void ffmpeg_camera_stop(void *data) { ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; } -bool ffmpeg_camera_poll( +static bool ffmpeg_camera_poll( void *data, retro_camera_frame_raw_framebuffer_t frame_raw_cb, retro_camera_frame_opengl_texture_t frame_gl_cb) From af1c4a3e7f5292aec20cbd83d76cfe7ef12c5b15 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Wed, 11 Dec 2024 21:26:15 -0500 Subject: [PATCH 008/574] First crack at implementing the ffmpeg camera driver --- camera/drivers/ffmpeg.c | 294 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 290 insertions(+), 4 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index f940f84f76..991d8b362e 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -15,18 +15,98 @@ */ #include +#include #include "../camera_driver.h" #include "lists/string_list.h" #include "verbosity.h" +#include +#include +#include + +/* ffmpeg supports a specific range of video devices; + * some video backends are better than others, + * so we'll prioritize those as defaults. + */ +const char *const FFMPEG_CAMERA_DEVICE_TYPE_PRIORITIES[] = { + /* Recommended camera backends */ +#ifdef ANDROID + "android_camera", +#endif +#ifdef __linux__ + "v4l2", +#endif +#ifdef __APPLE__ + "avfoundation", +#endif +#ifdef __WIN32__ + "dshow", + "vfwcap", +#endif + + /* Uncommon backends */ +#ifdef __linux__ + "fbdev", + "kmsgrab", + "x11grab", +#endif +#ifdef __WIN32__ + "gdigrab", +#endif + + "iec61883", /* FireWire */ + "decklink", + "libdc1394", + "lavfi", /* Libavfilter */ + + /* Deprecated backends */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) + "bktr", +#endif + NULL + + /* Unlisted backends lack video support + * or were introduced after this driver was written + * (it's okay, we can still use them if they're available). + */ +}; + + typedef struct ffmpeg_camera { + AVFormatContext *format_context; + AVCodecContext *decoder_context; + const AVCodec *decoder; + const AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ + AVDictionary *demuxer_options; + AVPacket *packet; + AVFrame *frame; + unsigned width; + unsigned height; + uint8_t *video_data[4]; + int video_linesize[4]; + int video_buffer_size; + + /* "name" for the camera device. + * (Not just the reported name, there may be a bit of extra syntax.) */ + char url[512]; } ffmpeg_camera_t; +static void ffmpeg_camera_free(void *data); + +static const AVInputFormat *ffmpeg_camera_choose_format(const char *device) +{ + // TODO: If `device` is not NULL or empty, parse it to get the backend and device name + // TODO: Pick the best backend for the current platform, don't just return the first + return av_input_video_device_next(NULL); +} + +// TODO: device format shall be: "/" static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { ffmpeg_camera_t *ffmpeg = NULL; + AVDictionary *options = NULL; if ((caps & (UINT64_C(1) << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER)) == 0) { /* If the core didn't ask for raw framebuffers... */ @@ -41,49 +121,255 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt return NULL; } + ffmpeg->width = width; + ffmpeg->height = height; + + avdevice_register_all(); + RARCH_LOG("[FFMPEG]: Initialized libavdevice.\n"); + + ffmpeg->input_format = ffmpeg_camera_choose_format(device); + if (!ffmpeg->input_format) + { + RARCH_ERR("[FFMPEG]: No suitable video input devices found.\n"); + goto error; + } + + AVDeviceInfoList *device_list = NULL; + int num_sources = avdevice_list_input_sources(ffmpeg->input_format, NULL, NULL, &device_list); + // TODO: Handle case where zero sources are returned + if (num_sources < 0) + { + RARCH_ERR("[FFMPEG]: Failed to list video input sources: %s\n", av_err2str(num_sources)); + goto error; + } + + RARCH_LOG("[FFMPEG]: Using video input device: %s (%s, flags=0x%x)\n", ffmpeg->input_format->name, ffmpeg->input_format->long_name, ffmpeg->input_format->flags); + snprintf(ffmpeg->url, sizeof(ffmpeg->url), "video=%s", device_list->devices[0]->device_name); + // TODO: this url is specific to dshow, need to generalize it + + avdevice_free_list_devices(&device_list); return ffmpeg; +error: + avdevice_free_list_devices(&device_list); + ffmpeg_camera_free(ffmpeg); + return NULL; } static void ffmpeg_camera_free(void *data) { - ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; + ffmpeg_camera_t *ffmpeg = data; if (!ffmpeg) return; + /* these functions are noops for NULL pointers */ + avcodec_free_context(&ffmpeg->decoder_context); + avformat_close_input(&ffmpeg->format_context); + av_frame_free(&ffmpeg->frame); + av_packet_free(&ffmpeg->packet); + av_dict_free(&ffmpeg->demuxer_options); + av_freep(&ffmpeg->video_data[0]); + free(ffmpeg); } static bool ffmpeg_camera_start(void *data) { - ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; + ffmpeg_camera_t *ffmpeg = data; + int result = 0; + AVStream *stream = NULL; + + if (ffmpeg->format_context) + { // TODO: Check the actual format context, not just the pointer + RARCH_LOG("[FFMPEG]: Camera %s is already started, no action needed.\n", ffmpeg->format_context->url); + return true; + } + + result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, &ffmpeg->demuxer_options); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to open video input device: %s\n", av_err2str(result)); + goto error; + } + + result = avformat_find_stream_info(ffmpeg->format_context, NULL); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to find stream info: %s\n", av_err2str(result)); + goto error; + } + + result = av_find_best_stream(ffmpeg->format_context, AVMEDIA_TYPE_VIDEO, -1, -1, &ffmpeg->decoder, 0); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to find video stream: %s\n", av_err2str(result)); + goto error; + } + stream = ffmpeg->format_context->streams[result]; + + RARCH_LOG("[FFMPEG]: Using video stream #%d with decoder \"%s\" (%s).\n", result, ffmpeg->decoder->name, ffmpeg->decoder->long_name); + + ffmpeg->decoder_context = avcodec_alloc_context3(ffmpeg->decoder); + if (!ffmpeg->decoder_context) + { + RARCH_ERR("[FFMPEG]: Failed to allocate decoder context.\n"); + goto error; + } + + result = avcodec_parameters_to_context(ffmpeg->decoder_context, stream->codecpar); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy codec parameters to decoder context: %s\n", av_err2str(result)); + goto error; + } + + AVDictionary *opts = NULL; + result = avcodec_open2(ffmpeg->decoder_context, ffmpeg->decoder, &opts); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to open decoder: %s\n", av_err2str(result)); + goto error; + } + + ffmpeg->packet = av_packet_alloc(); + if (!ffmpeg->packet) + { + RARCH_ERR("[FFMPEG]: Failed to allocate packet.\n"); + goto error; + } + + ffmpeg->frame = av_frame_alloc(); + if (!ffmpeg->frame) + { + RARCH_ERR("[FFMPEG]: Failed to allocate frame.\n"); + goto error; + } + + result = av_image_alloc(ffmpeg->video_data, ffmpeg->video_linesize, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, ffmpeg->decoder_context->pix_fmt, 1); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to allocate video data: %s\n", av_err2str(result)); + goto error; + } + ffmpeg->video_buffer_size = result; + + RARCH_LOG("[FFMPEG]: Allocated %d bytes for %dx%d %s-formatted video data.\n", + ffmpeg->video_buffer_size, + ffmpeg->decoder_context->width, + ffmpeg->decoder_context->height, + av_get_pix_fmt_name(ffmpeg->decoder_context->pix_fmt) + ); + + return true; +error: + /* these functions are noops for NULL pointers */ + av_freep(&ffmpeg->video_data[0]); + av_frame_free(&ffmpeg->frame); + av_packet_free(&ffmpeg->packet); + avcodec_free_context(&ffmpeg->decoder_context); + avformat_close_input(&ffmpeg->format_context); return false; } static void ffmpeg_camera_stop(void *data) { - ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; + ffmpeg_camera_t *ffmpeg = data; + if (!ffmpeg->format_context) + { + RARCH_LOG("[FFMPEG]: Camera %s is already stopped, no action needed.\n", ffmpeg->url); + return; + } + + int result = avcodec_send_packet(ffmpeg->decoder_context, NULL); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to flush decoder: %s\n", av_err2str(result)); + } + + av_freep(&ffmpeg->video_data[0]); + avcodec_free_context(&ffmpeg->decoder_context); + avformat_close_input(&ffmpeg->format_context); + RARCH_LOG("[FFMPEG]: Closed video input device %s.\n", ffmpeg->url); } +// TODO: Put this in another thread static bool ffmpeg_camera_poll( void *data, retro_camera_frame_raw_framebuffer_t frame_raw_cb, retro_camera_frame_opengl_texture_t frame_gl_cb) { - ffmpeg_camera_t *ffmpeg = (ffmpeg_camera_t*)data; + ffmpeg_camera_t *ffmpeg = data; + int result = 0; + if (!ffmpeg->format_context) + { + RARCH_ERR("[FFMPEG]: Camera is not started, cannot poll.\n"); + return false; + } + + if (!frame_raw_cb) + { + RARCH_ERR("[FFMPEG]: No callback provided, cannot poll.\n"); + return false; + } + + result = av_read_frame(ffmpeg->format_context, ffmpeg->packet); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to read frame: %s\n", av_err2str(result)); + goto error; + } + + result = avcodec_send_packet(ffmpeg->decoder_context, ffmpeg->packet); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to send packet to decoder: %s\n", av_err2str(result)); + goto error; + } + + /* video streams consist of exactly one frame per packet */ + result = avcodec_receive_frame(ffmpeg->decoder_context, ffmpeg->frame); + if (result < 0) + { // TODO: Handle AVERROR_EOF and AVERROR(EAGAIN) + RARCH_ERR("[FFMPEG]: Failed to receive frame from decoder: %s\n", av_err2str(result)); + goto error; + } + + retro_assert(ffmpeg->decoder->type == AVMEDIA_TYPE_VIDEO); + + av_image_copy2(ffmpeg->video_data, ffmpeg->video_linesize, ffmpeg->frame->data, ffmpeg->frame->linesize, ffmpeg->decoder_context->pix_fmt, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height); + + // TODO: Convert the frame to XRGB8888 + // TODO: Send the frame to the callback + + // TODO: Ensure I'm unreferencing the packet correctly (use the return status of the functions that reference them) + av_packet_unref(ffmpeg->packet); + av_frame_unref(ffmpeg->frame); + + return false; +error: + /* must be called when we're done with it */ + av_packet_unref(ffmpeg->packet); return false; } static struct string_list *ffmpeg_camera_device_list_new(const void *driver_context) { + const AVInputFormat *input = NULL; struct string_list *list = string_list_new(); if (!list) return NULL; + for (input = av_input_video_device_next(NULL); input != NULL; input = av_input_video_device_next(input)) + { + // if (input->priv_class && input->priv_class->category == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) + RARCH_LOG("[FFMPEG]: Found input device: %s (%s, %x)\n", input->name, input->long_name, input->flags); + // TODO: Find guide for creating and using a camera + } + return list; } From b1eb37b394f751c7aa4a7485ff7ffd24e5b52123 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Thu, 12 Dec 2024 11:09:31 -0500 Subject: [PATCH 009/574] Capture an image and display it (as tested with 3DEngine) - Still crashes upon closing - Colors are all wrong, too --- camera/drivers/ffmpeg.c | 140 ++++++++++++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 34 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 991d8b362e..a30ef1e425 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -23,6 +23,7 @@ #include #include +#include #include /* ffmpeg supports a specific range of video devices; @@ -81,12 +82,13 @@ typedef struct ffmpeg_camera const AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ AVDictionary *demuxer_options; AVPacket *packet; - AVFrame *frame; - unsigned width; - unsigned height; - uint8_t *video_data[4]; - int video_linesize[4]; - int video_buffer_size; + AVFrame *camera_frame; + AVFrame *target_frame; + unsigned target_width; + unsigned target_height; + uint8_t *target_buffer; + size_t target_buffer_length; + struct SwsContext *scale_context; /* "name" for the camera device. * (Not just the reported name, there may be a bit of extra syntax.) */ @@ -121,8 +123,8 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt return NULL; } - ffmpeg->width = width; - ffmpeg->height = height; + ffmpeg->target_width = width; + ffmpeg->target_height = height; avdevice_register_all(); RARCH_LOG("[FFMPEG]: Initialized libavdevice.\n"); @@ -155,6 +157,7 @@ error: return NULL; } +static void ffmpeg_camera_stop(void *data); static void ffmpeg_camera_free(void *data) { ffmpeg_camera_t *ffmpeg = data; @@ -162,13 +165,17 @@ static void ffmpeg_camera_free(void *data) if (!ffmpeg) return; + ffmpeg_camera_stop(ffmpeg); + /* these functions are noops for NULL pointers */ avcodec_free_context(&ffmpeg->decoder_context); avformat_close_input(&ffmpeg->format_context); - av_frame_free(&ffmpeg->frame); + av_frame_free(&ffmpeg->camera_frame); + av_frame_free(&ffmpeg->target_frame); av_packet_free(&ffmpeg->packet); av_dict_free(&ffmpeg->demuxer_options); - av_freep(&ffmpeg->video_data[0]); + sws_freeContext(ffmpeg->scale_context); + free(ffmpeg->target_buffer); free(ffmpeg); } @@ -223,6 +230,12 @@ static bool ffmpeg_camera_start(void *data) goto error; } + if (!sws_isSupportedInput(ffmpeg->decoder_context->pix_fmt)) + { + RARCH_ERR("[FFMPEG]: Unsupported scaler input pixel format: %s\n", av_get_pix_fmt_name(ffmpeg->decoder_context->pix_fmt)); + goto error; + } + AVDictionary *opts = NULL; result = avcodec_open2(ffmpeg->decoder_context, ffmpeg->decoder, &opts); if (result < 0) @@ -238,36 +251,73 @@ static bool ffmpeg_camera_start(void *data) goto error; } - ffmpeg->frame = av_frame_alloc(); - if (!ffmpeg->frame) + ffmpeg->camera_frame = av_frame_alloc(); + if (!ffmpeg->camera_frame) { - RARCH_ERR("[FFMPEG]: Failed to allocate frame.\n"); + RARCH_ERR("[FFMPEG]: Failed to allocate camera frame.\n"); goto error; } - result = av_image_alloc(ffmpeg->video_data, ffmpeg->video_linesize, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, ffmpeg->decoder_context->pix_fmt, 1); - if (result < 0) + ffmpeg->target_frame = av_frame_alloc(); + if (!ffmpeg->target_frame) { - RARCH_ERR("[FFMPEG]: Failed to allocate video data: %s\n", av_err2str(result)); + RARCH_ERR("[FFMPEG]: Failed to allocate target frame.\n"); + goto error; + } + + int buffer_length = av_image_get_buffer_size(AV_PIX_FMT_ARGB, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, 4); + if (buffer_length < 0) + { + RARCH_ERR("[FFMPEG]: Failed to get buffer size for target frame: %s\n", av_err2str(buffer_length)); + goto error; + } + + ffmpeg->target_buffer_length = buffer_length; + ffmpeg->target_buffer = (uint8_t*)av_malloc(buffer_length); + if (!ffmpeg->target_buffer) + { + RARCH_ERR("[FFMPEG]: Failed to allocate target %d-byte buffer for %dx%d %s-formatted video data.\n", + buffer_length, + ffmpeg->decoder_context->width, + ffmpeg->decoder_context->height, + av_get_pix_fmt_name(AV_PIX_FMT_ARGB) + ); goto error; } - ffmpeg->video_buffer_size = result; RARCH_LOG("[FFMPEG]: Allocated %d bytes for %dx%d %s-formatted video data.\n", - ffmpeg->video_buffer_size, + buffer_length, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, av_get_pix_fmt_name(ffmpeg->decoder_context->pix_fmt) ); + ffmpeg->scale_context = sws_getContext( + ffmpeg->decoder_context->width, + ffmpeg->decoder_context->height, + ffmpeg->decoder_context->pix_fmt, + ffmpeg->target_width ? ffmpeg->target_width : ffmpeg->decoder_context->width, + ffmpeg->target_height ? ffmpeg->target_height : ffmpeg->decoder_context->height, + AV_PIX_FMT_ARGB, + SWS_BILINEAR, + NULL, NULL, NULL + ); + if (!ffmpeg->scale_context) + { + RARCH_ERR("[FFMPEG]: Failed to create scale context.\n"); + goto error; + } + return true; error: /* these functions are noops for NULL pointers */ - av_freep(&ffmpeg->video_data[0]); - av_frame_free(&ffmpeg->frame); + free(ffmpeg->target_buffer); + av_frame_free(&ffmpeg->target_frame); + av_frame_free(&ffmpeg->camera_frame); av_packet_free(&ffmpeg->packet); avcodec_free_context(&ffmpeg->decoder_context); avformat_close_input(&ffmpeg->format_context); + sws_freeContext(ffmpeg->scale_context); return false; } @@ -278,19 +328,24 @@ static void ffmpeg_camera_stop(void *data) if (!ffmpeg->format_context) { - RARCH_LOG("[FFMPEG]: Camera %s is already stopped, no action needed.\n", ffmpeg->url); - return; + RARCH_LOG("[FFMPEG]: Camera %s is already stopped, no flush needed.\n", ffmpeg->url); } - - int result = avcodec_send_packet(ffmpeg->decoder_context, NULL); - if (result < 0) + else { - RARCH_ERR("[FFMPEG]: Failed to flush decoder: %s\n", av_err2str(result)); + int result = avcodec_send_packet(ffmpeg->decoder_context, NULL); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to flush decoder: %s\n", av_err2str(result)); + } } - av_freep(&ffmpeg->video_data[0]); + free(ffmpeg->target_buffer); + ffmpeg->target_buffer = NULL; + ffmpeg->target_buffer_length = 0; avcodec_free_context(&ffmpeg->decoder_context); avformat_close_input(&ffmpeg->format_context); + sws_freeContext(ffmpeg->scale_context); + ffmpeg->scale_context = NULL; RARCH_LOG("[FFMPEG]: Closed video input device %s.\n", ffmpeg->url); } @@ -330,23 +385,40 @@ static bool ffmpeg_camera_poll( } /* video streams consist of exactly one frame per packet */ - result = avcodec_receive_frame(ffmpeg->decoder_context, ffmpeg->frame); + result = avcodec_receive_frame(ffmpeg->decoder_context, ffmpeg->camera_frame); if (result < 0) { // TODO: Handle AVERROR_EOF and AVERROR(EAGAIN) - RARCH_ERR("[FFMPEG]: Failed to receive frame from decoder: %s\n", av_err2str(result)); + RARCH_ERR("[FFMPEG]: Failed to receive camera frame from decoder: %s\n", av_err2str(result)); goto error; } retro_assert(ffmpeg->decoder->type == AVMEDIA_TYPE_VIDEO); - av_image_copy2(ffmpeg->video_data, ffmpeg->video_linesize, ffmpeg->frame->data, ffmpeg->frame->linesize, ffmpeg->decoder_context->pix_fmt, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height); + result = sws_scale_frame(ffmpeg->scale_context, ffmpeg->target_frame, ffmpeg->camera_frame); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to scale frame: %s\n", av_err2str(result)); + goto error; + } - // TODO: Convert the frame to XRGB8888 - // TODO: Send the frame to the callback + result = av_image_copy_to_buffer( + ffmpeg->target_buffer, + ffmpeg->target_buffer_length, + (const uint8_t* const *)ffmpeg->target_frame->data, + ffmpeg->target_frame->linesize, + ffmpeg->target_frame->format, + ffmpeg->target_frame->width, + ffmpeg->target_frame->height, + 4 + ); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy frame to buffer: %s\n", av_err2str(result)); + goto error; + } - // TODO: Ensure I'm unreferencing the packet correctly (use the return status of the functions that reference them) + frame_raw_cb((uint32_t*)ffmpeg->target_buffer, ffmpeg->target_frame->width, ffmpeg->target_frame->height, ffmpeg->target_frame->linesize[0]); av_packet_unref(ffmpeg->packet); - av_frame_unref(ffmpeg->frame); return false; error: From 22301bd3d57ebcd777cb788da19c361161c7cd49 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Thu, 12 Dec 2024 11:25:43 -0500 Subject: [PATCH 010/574] Fix a crash when closing the ffmpeg camera driver - Allocate the target buffer aligned to 4-byte addresses - Consolidate resource cleanup to mitigate similar issues --- camera/drivers/ffmpeg.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index a30ef1e425..3e6c3e478d 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -24,6 +24,7 @@ #include #include #include +#include #include /* ffmpeg supports a specific range of video devices; @@ -175,7 +176,7 @@ static void ffmpeg_camera_free(void *data) av_packet_free(&ffmpeg->packet); av_dict_free(&ffmpeg->demuxer_options); sws_freeContext(ffmpeg->scale_context); - free(ffmpeg->target_buffer); + memalign_free(ffmpeg->target_buffer); free(ffmpeg); } @@ -272,8 +273,9 @@ static bool ffmpeg_camera_start(void *data) goto error; } + /* target buffer aligned to 4 bytes because it's exposed to the core as a uint32_t[] */ ffmpeg->target_buffer_length = buffer_length; - ffmpeg->target_buffer = (uint8_t*)av_malloc(buffer_length); + ffmpeg->target_buffer = memalign_alloc(buffer_length, 4); if (!ffmpeg->target_buffer) { RARCH_ERR("[FFMPEG]: Failed to allocate target %d-byte buffer for %dx%d %s-formatted video data.\n", @@ -310,14 +312,7 @@ static bool ffmpeg_camera_start(void *data) return true; error: - /* these functions are noops for NULL pointers */ - free(ffmpeg->target_buffer); - av_frame_free(&ffmpeg->target_frame); - av_frame_free(&ffmpeg->camera_frame); - av_packet_free(&ffmpeg->packet); - avcodec_free_context(&ffmpeg->decoder_context); - avformat_close_input(&ffmpeg->format_context); - sws_freeContext(ffmpeg->scale_context); + ffmpeg_camera_stop(ffmpeg); return false; } @@ -339,7 +334,8 @@ static void ffmpeg_camera_stop(void *data) } } - free(ffmpeg->target_buffer); + /* these functions are noops for NULL pointers */ + memalign_free(ffmpeg->target_buffer); ffmpeg->target_buffer = NULL; ffmpeg->target_buffer_length = 0; avcodec_free_context(&ffmpeg->decoder_context); From 0bdf6168364c71bd5ec3c4d591b121ef919a3edb Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Thu, 12 Dec 2024 18:13:14 -0500 Subject: [PATCH 011/574] Fix some swapped arguments --- camera/drivers/ffmpeg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 3e6c3e478d..07309622ca 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -275,7 +275,7 @@ static bool ffmpeg_camera_start(void *data) /* target buffer aligned to 4 bytes because it's exposed to the core as a uint32_t[] */ ffmpeg->target_buffer_length = buffer_length; - ffmpeg->target_buffer = memalign_alloc(buffer_length, 4); + ffmpeg->target_buffer = memalign_alloc(4, buffer_length); if (!ffmpeg->target_buffer) { RARCH_ERR("[FFMPEG]: Failed to allocate target %d-byte buffer for %dx%d %s-formatted video data.\n", From 716be2bb22bc2732899167c68b8cafb290cf57fa Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Thu, 12 Dec 2024 18:16:24 -0500 Subject: [PATCH 012/574] Silence some warnings --- camera/drivers/ffmpeg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 07309622ca..f6fe53717f 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -298,8 +298,8 @@ static bool ffmpeg_camera_start(void *data) ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, ffmpeg->decoder_context->pix_fmt, - ffmpeg->target_width ? ffmpeg->target_width : ffmpeg->decoder_context->width, - ffmpeg->target_height ? ffmpeg->target_height : ffmpeg->decoder_context->height, + ffmpeg->target_width ? ffmpeg->target_width : (unsigned)ffmpeg->decoder_context->width, + ffmpeg->target_height ? ffmpeg->target_height : (unsigned)ffmpeg->decoder_context->height, AV_PIX_FMT_ARGB, SWS_BILINEAR, NULL, NULL, NULL From 0e347391e8fe9b60926b8ef1e1bc4ca1dd4f1fd2 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Thu, 12 Dec 2024 18:18:01 -0500 Subject: [PATCH 013/574] Clean up ffmpeg_camera_free - Release resources in the opposite order they were initialized - Don't release resources twice (even for cases of a noop) --- camera/drivers/ffmpeg.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index f6fe53717f..d0fab391e7 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -168,16 +168,6 @@ static void ffmpeg_camera_free(void *data) ffmpeg_camera_stop(ffmpeg); - /* these functions are noops for NULL pointers */ - avcodec_free_context(&ffmpeg->decoder_context); - avformat_close_input(&ffmpeg->format_context); - av_frame_free(&ffmpeg->camera_frame); - av_frame_free(&ffmpeg->target_frame); - av_packet_free(&ffmpeg->packet); - av_dict_free(&ffmpeg->demuxer_options); - sws_freeContext(ffmpeg->scale_context); - memalign_free(ffmpeg->target_buffer); - free(ffmpeg); } @@ -335,13 +325,18 @@ static void ffmpeg_camera_stop(void *data) } /* these functions are noops for NULL pointers */ + sws_freeContext(ffmpeg->scale_context); + ffmpeg->scale_context = NULL; + memalign_free(ffmpeg->target_buffer); ffmpeg->target_buffer = NULL; ffmpeg->target_buffer_length = 0; + + av_frame_free(&ffmpeg->target_frame); + av_frame_free(&ffmpeg->camera_frame); + av_packet_free(&ffmpeg->packet); avcodec_free_context(&ffmpeg->decoder_context); avformat_close_input(&ffmpeg->format_context); - sws_freeContext(ffmpeg->scale_context); - ffmpeg->scale_context = NULL; RARCH_LOG("[FFMPEG]: Closed video input device %s.\n", ffmpeg->url); } @@ -405,7 +400,7 @@ static bool ffmpeg_camera_poll( ffmpeg->target_frame->format, ffmpeg->target_frame->width, ffmpeg->target_frame->height, - 4 + 1 ); if (result < 0) { From 2d2e9d840c6cf1db88faa89153cc14a16d3e3f59 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Thu, 12 Dec 2024 18:54:49 -0500 Subject: [PATCH 014/574] Fix the channels being swapped - Whoops, wrong format --- camera/drivers/ffmpeg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index d0fab391e7..79c3328f8c 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -256,7 +256,7 @@ static bool ffmpeg_camera_start(void *data) goto error; } - int buffer_length = av_image_get_buffer_size(AV_PIX_FMT_ARGB, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, 4); + int buffer_length = av_image_get_buffer_size(AV_PIX_FMT_BGRA, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, 4); if (buffer_length < 0) { RARCH_ERR("[FFMPEG]: Failed to get buffer size for target frame: %s\n", av_err2str(buffer_length)); @@ -272,7 +272,7 @@ static bool ffmpeg_camera_start(void *data) buffer_length, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, - av_get_pix_fmt_name(AV_PIX_FMT_ARGB) + av_get_pix_fmt_name(AV_PIX_FMT_BGRA) ); goto error; } @@ -290,7 +290,7 @@ static bool ffmpeg_camera_start(void *data) ffmpeg->decoder_context->pix_fmt, ffmpeg->target_width ? ffmpeg->target_width : (unsigned)ffmpeg->decoder_context->width, ffmpeg->target_height ? ffmpeg->target_height : (unsigned)ffmpeg->decoder_context->height, - AV_PIX_FMT_ARGB, + AV_PIX_FMT_BGRA, SWS_BILINEAR, NULL, NULL, NULL ); From 391be6636115dccce38d942e787af0831d359e68 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Thu, 12 Dec 2024 18:55:05 -0500 Subject: [PATCH 015/574] Unref the packet and frame correctly --- camera/drivers/ffmpeg.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 79c3328f8c..f44f3e45dc 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -346,6 +346,7 @@ static bool ffmpeg_camera_poll( retro_camera_frame_raw_framebuffer_t frame_raw_cb, retro_camera_frame_opengl_texture_t frame_gl_cb) { + bool ok = false; ffmpeg_camera_t *ffmpeg = data; int result = 0; @@ -378,8 +379,12 @@ static bool ffmpeg_camera_poll( /* video streams consist of exactly one frame per packet */ result = avcodec_receive_frame(ffmpeg->decoder_context, ffmpeg->camera_frame); if (result < 0) - { // TODO: Handle AVERROR_EOF and AVERROR(EAGAIN) - RARCH_ERR("[FFMPEG]: Failed to receive camera frame from decoder: %s\n", av_err2str(result)); + { + if (!(result == AVERROR_EOF || result == AVERROR(EAGAIN))) + { /* these error codes mean no new frame, but not necessarily a problem */ + RARCH_ERR("[FFMPEG]: Failed to receive camera frame from decoder: %s\n", av_err2str(result)); + } + goto error; } @@ -389,7 +394,7 @@ static bool ffmpeg_camera_poll( if (result < 0) { RARCH_ERR("[FFMPEG]: Failed to scale frame: %s\n", av_err2str(result)); - goto error; + goto done; } result = av_image_copy_to_buffer( @@ -405,17 +410,19 @@ static bool ffmpeg_camera_poll( if (result < 0) { RARCH_ERR("[FFMPEG]: Failed to copy frame to buffer: %s\n", av_err2str(result)); - goto error; + goto done; } frame_raw_cb((uint32_t*)ffmpeg->target_buffer, ffmpeg->target_frame->width, ffmpeg->target_frame->height, ffmpeg->target_frame->linesize[0]); + ok = true; +done: + /* must be called when we're done with it */ + av_frame_unref(ffmpeg->camera_frame); +error: + /* every operation in this function needs this packet */ av_packet_unref(ffmpeg->packet); - return false; -error: - /* must be called when we're done with it */ - av_packet_unref(ffmpeg->packet); - return false; + return ok; } static struct string_list *ffmpeg_camera_device_list_new(const void *driver_context) From 2bd45eeb6fa85ff279c0bc6c6bac8be5fdcb9683 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Fri, 13 Dec 2024 14:52:11 -0500 Subject: [PATCH 016/574] Remove an unneeded comment --- camera/drivers/ffmpeg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index f44f3e45dc..34858ff6c8 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -437,7 +437,6 @@ static struct string_list *ffmpeg_camera_device_list_new(const void *driver_cont { // if (input->priv_class && input->priv_class->category == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) RARCH_LOG("[FFMPEG]: Found input device: %s (%s, %x)\n", input->name, input->long_name, input->flags); - // TODO: Find guide for creating and using a camera } return list; From 024fd873ecb4fd81abca03115b6efbebc876be7d Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Sun, 15 Dec 2024 21:21:08 -0500 Subject: [PATCH 017/574] Moved polling in the new ffmpeg camera driver to another thread --- camera/drivers/ffmpeg.c | 185 +++++++++++++++++++++++++--------------- 1 file changed, 116 insertions(+), 69 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 34858ff6c8..4f9a511c6c 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -26,6 +26,7 @@ #include #include #include +#include /* ffmpeg supports a specific range of video devices; * some video backends are better than others, @@ -77,6 +78,7 @@ const char *const FFMPEG_CAMERA_DEVICE_TYPE_PRIORITIES[] = { typedef struct ffmpeg_camera { + sthread_t *poll_thread; AVFormatContext *format_context; AVCodecContext *decoder_context; const AVCodec *decoder; @@ -87,13 +89,17 @@ typedef struct ffmpeg_camera AVFrame *target_frame; unsigned target_width; unsigned target_height; - uint8_t *target_buffer; - size_t target_buffer_length; struct SwsContext *scale_context; /* "name" for the camera device. * (Not just the reported name, there may be a bit of extra syntax.) */ char url[512]; + + uint8_t *target_buffers[2]; + size_t target_buffer_length; + slock_t *target_buffer_lock; + volatile bool done; + uint8_t *active_buffer; } ffmpeg_camera_t; static void ffmpeg_camera_free(void *data); @@ -171,6 +177,8 @@ static void ffmpeg_camera_free(void *data) free(ffmpeg); } +static void ffmpeg_camera_poll_thread(void *data); + static bool ffmpeg_camera_start(void *data) { ffmpeg_camera_t *ffmpeg = data; @@ -265,8 +273,10 @@ static bool ffmpeg_camera_start(void *data) /* target buffer aligned to 4 bytes because it's exposed to the core as a uint32_t[] */ ffmpeg->target_buffer_length = buffer_length; - ffmpeg->target_buffer = memalign_alloc(4, buffer_length); - if (!ffmpeg->target_buffer) + ffmpeg->target_buffers[0] = memalign_alloc(4, buffer_length); + ffmpeg->target_buffers[1] = memalign_alloc(4, buffer_length); + ffmpeg->active_buffer = ffmpeg->target_buffers[0]; + if (!ffmpeg->target_buffers[0] || !ffmpeg->target_buffers[1]) { RARCH_ERR("[FFMPEG]: Failed to allocate target %d-byte buffer for %dx%d %s-formatted video data.\n", buffer_length, @@ -300,6 +310,20 @@ static bool ffmpeg_camera_start(void *data) goto error; } + ffmpeg->target_buffer_lock = slock_new(); + if (!ffmpeg->target_buffer_lock) + { + RARCH_ERR("[FFMPEG]: Failed to create target buffer lock.\n"); + goto error; + } + + ffmpeg->poll_thread = sthread_create(ffmpeg_camera_poll_thread, ffmpeg); + if (!ffmpeg->poll_thread) + { + RARCH_ERR("[FFMPEG]: Failed to create poll thread.\n"); + goto error; + } + return true; error: ffmpeg_camera_stop(ffmpeg); @@ -325,11 +349,21 @@ static void ffmpeg_camera_stop(void *data) } /* these functions are noops for NULL pointers */ + ffmpeg->done = true; + sthread_join(ffmpeg->poll_thread); /* wait for the thread to finish, then free it */ + ffmpeg->poll_thread = NULL; + + slock_free(ffmpeg->target_buffer_lock); + ffmpeg->target_buffer_lock = NULL; + sws_freeContext(ffmpeg->scale_context); ffmpeg->scale_context = NULL; - memalign_free(ffmpeg->target_buffer); - ffmpeg->target_buffer = NULL; + memalign_free(ffmpeg->target_buffers[0]); + memalign_free(ffmpeg->target_buffers[1]); + ffmpeg->active_buffer = NULL; + ffmpeg->target_buffers[0] = NULL; + ffmpeg->target_buffers[1] = NULL; ffmpeg->target_buffer_length = 0; av_frame_free(&ffmpeg->target_frame); @@ -340,15 +374,84 @@ static void ffmpeg_camera_stop(void *data) RARCH_LOG("[FFMPEG]: Closed video input device %s.\n", ffmpeg->url); } -// TODO: Put this in another thread +static void ffmpeg_camera_poll_thread(void *data) +{ + ffmpeg_camera_t *ffmpeg = data; + + if (!ffmpeg) + return; + + while (!ffmpeg->done) + { + int result = av_read_frame(ffmpeg->format_context, ffmpeg->packet); + if (result < 0) + { /* Read the raw data from the camera. If that fails... */ + RARCH_ERR("[FFMPEG]: Failed to read frame: %s\n", av_err2str(result)); + continue; + } + + result = avcodec_send_packet(ffmpeg->decoder_context, ffmpeg->packet); + if (result < 0) + { /* Send the raw data to the decoder. If that fails... */ + RARCH_ERR("[FFMPEG]: Failed to send packet to decoder: %s\n", av_err2str(result)); + continue; + } + + /* video streams consist of exactly one frame per packet */ + result = avcodec_receive_frame(ffmpeg->decoder_context, ffmpeg->camera_frame); + if (result < 0) + { /* Send the decoded data to the camera frame. If that fails... */ + if (!(result == AVERROR_EOF || result == AVERROR(EAGAIN))) + { /* these error codes mean no new frame, but not necessarily a problem */ + RARCH_ERR("[FFMPEG]: Failed to receive camera frame from decoder: %s\n", av_err2str(result)); + } + + goto done_loop; + } + + retro_assert(ffmpeg->decoder->type == AVMEDIA_TYPE_VIDEO); + + result = sws_scale_frame(ffmpeg->scale_context, ffmpeg->target_frame, ffmpeg->camera_frame); + if (result < 0) + { /* Scale and convert the frame to the target format. If that fails... */ + RARCH_ERR("[FFMPEG]: Failed to scale frame: %s\n", av_err2str(result)); + goto done_loop; + } + + slock_lock(ffmpeg->target_buffer_lock); + ffmpeg->active_buffer = ffmpeg->active_buffer == ffmpeg->target_buffers[0] ? ffmpeg->target_buffers[1] : ffmpeg->target_buffers[0]; + // TODO: When should I swap the buffers? + result = av_image_copy_to_buffer( + ffmpeg->active_buffer, + ffmpeg->target_buffer_length, + (const uint8_t *const *)ffmpeg->target_frame->data, + ffmpeg->target_frame->linesize, + ffmpeg->target_frame->format, + ffmpeg->target_frame->width, + ffmpeg->target_frame->height, + 1 + ); + slock_unlock(ffmpeg->target_buffer_lock); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy frame to buffer: %s\n", av_err2str(result)); + goto done_loop; + } + done_loop: + /* must be called when we're done with it */ + av_frame_unref(ffmpeg->camera_frame); + } + + /* every operation in this function needs this packet */ + av_packet_unref(ffmpeg->packet); +} + static bool ffmpeg_camera_poll( void *data, retro_camera_frame_raw_framebuffer_t frame_raw_cb, retro_camera_frame_opengl_texture_t frame_gl_cb) { - bool ok = false; ffmpeg_camera_t *ffmpeg = data; - int result = 0; if (!ffmpeg->format_context) { @@ -362,67 +465,11 @@ static bool ffmpeg_camera_poll( return false; } - result = av_read_frame(ffmpeg->format_context, ffmpeg->packet); - if (result < 0) - { - RARCH_ERR("[FFMPEG]: Failed to read frame: %s\n", av_err2str(result)); - goto error; - } + slock_lock(ffmpeg->target_buffer_lock); + frame_raw_cb((uint32_t*)ffmpeg->active_buffer, ffmpeg->target_frame->width, ffmpeg->target_frame->height, ffmpeg->target_frame->linesize[0]); + slock_unlock(ffmpeg->target_buffer_lock); - result = avcodec_send_packet(ffmpeg->decoder_context, ffmpeg->packet); - if (result < 0) - { - RARCH_ERR("[FFMPEG]: Failed to send packet to decoder: %s\n", av_err2str(result)); - goto error; - } - - /* video streams consist of exactly one frame per packet */ - result = avcodec_receive_frame(ffmpeg->decoder_context, ffmpeg->camera_frame); - if (result < 0) - { - if (!(result == AVERROR_EOF || result == AVERROR(EAGAIN))) - { /* these error codes mean no new frame, but not necessarily a problem */ - RARCH_ERR("[FFMPEG]: Failed to receive camera frame from decoder: %s\n", av_err2str(result)); - } - - goto error; - } - - retro_assert(ffmpeg->decoder->type == AVMEDIA_TYPE_VIDEO); - - result = sws_scale_frame(ffmpeg->scale_context, ffmpeg->target_frame, ffmpeg->camera_frame); - if (result < 0) - { - RARCH_ERR("[FFMPEG]: Failed to scale frame: %s\n", av_err2str(result)); - goto done; - } - - result = av_image_copy_to_buffer( - ffmpeg->target_buffer, - ffmpeg->target_buffer_length, - (const uint8_t* const *)ffmpeg->target_frame->data, - ffmpeg->target_frame->linesize, - ffmpeg->target_frame->format, - ffmpeg->target_frame->width, - ffmpeg->target_frame->height, - 1 - ); - if (result < 0) - { - RARCH_ERR("[FFMPEG]: Failed to copy frame to buffer: %s\n", av_err2str(result)); - goto done; - } - - frame_raw_cb((uint32_t*)ffmpeg->target_buffer, ffmpeg->target_frame->width, ffmpeg->target_frame->height, ffmpeg->target_frame->linesize[0]); - ok = true; -done: - /* must be called when we're done with it */ - av_frame_unref(ffmpeg->camera_frame); -error: - /* every operation in this function needs this packet */ - av_packet_unref(ffmpeg->packet); - - return ok; + return true; } static struct string_list *ffmpeg_camera_device_list_new(const void *driver_context) From 33b574198c0d7f42cbd12479bb909edbcd507b2a Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Sun, 15 Dec 2024 21:39:48 -0500 Subject: [PATCH 018/574] Swap the buffers after copying the most recent camera frame, but only upon success --- camera/drivers/ffmpeg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 4f9a511c6c..754390cfdb 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -419,8 +419,6 @@ static void ffmpeg_camera_poll_thread(void *data) } slock_lock(ffmpeg->target_buffer_lock); - ffmpeg->active_buffer = ffmpeg->active_buffer == ffmpeg->target_buffers[0] ? ffmpeg->target_buffers[1] : ffmpeg->target_buffers[0]; - // TODO: When should I swap the buffers? result = av_image_copy_to_buffer( ffmpeg->active_buffer, ffmpeg->target_buffer_length, @@ -431,6 +429,9 @@ static void ffmpeg_camera_poll_thread(void *data) ffmpeg->target_frame->height, 1 ); + if (result >= 0) { + ffmpeg->active_buffer = ffmpeg->active_buffer == ffmpeg->target_buffers[0] ? ffmpeg->target_buffers[1] : ffmpeg->target_buffers[0]; + } slock_unlock(ffmpeg->target_buffer_lock); if (result < 0) { From c63a8d67056d69262853524a5a9ba0b4a227a262 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Mon, 16 Dec 2024 15:21:56 -0500 Subject: [PATCH 019/574] Check for FFmpeg's constitutent libraries before adding flags for them --- Makefile.common | 61 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/Makefile.common b/Makefile.common index 06c5b447e7..4e3155b862 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2152,6 +2152,65 @@ ifeq ($(HAVE_V4L2),1) LIBS += $(V4L2_LIBS) endif +# FFmpeg + +ifeq ($(HAVE_FFMPEG), 1) + DEFINES += -DHAVE_FFMPEG + INCLUDE_DIRS += -Iffmpeg + DEF_FLAGS += $(FFMPEG_CFLAGS) -Wno-deprecated-declarations + LIBS += $(FFMPEG_LIBS) + + ifeq ($(HAVE_AVCODEC), 1) + DEFINES += -DHAVE_AVCODEC + DEF_FLAGS += $(AVCODEC_CFLAGS) + LIBS += $(AVCODEC_LIBS) + endif + + ifeq ($(HAVE_AVDEVICE), 1) + DEFINES += -DHAVE_AVDEVICE + DEF_FLAGS += $(AVDEVICE_CFLAGS) + LIBS += $(AVDEVICE_LIBS) + endif + + ifeq ($(HAVE_AVFORMAT), 1) + DEFINES += -DHAVE_AVFORMAT + DEF_FLAGS += $(AVFORMAT_CFLAGS) + LIBS += $(AVFORMAT_LIBS) + endif + + ifeq ($(HAVE_AVUTIL), 1) + DEFINES += -DHAVE_AVUTIL + DEF_FLAGS += $(AVUTIL_CFLAGS) + LIBS += $(AVUTIL_LIBS) + endif + + ifeq ($(HAVE_SWSCALE), 1) + DEFINES += -DHAVE_SWSCALE + DEF_FLAGS += $(SWSCALE_CFLAGS) + LIBS += $(SWSCALE_LIBS) + endif + + ifeq ($(HAVE_SWRESAMPLE), 1) + DEFINES += -DHAVE_SWRESAMPLE + DEF_FLAGS += $(SWRESAMPLE_CFLAGS) + LIBS += $(SWRESAMPLE_LIBS) + endif +endif + +ifeq ($(HAVE_FFMPEG), 1) +ifeq ($(HAVE_AVFORMAT), 1) +ifeq ($(HAVE_AVDEVICE), 1) +ifeq ($(HAVE_AVCODEC), 1) +ifeq ($(HAVE_AVUTIL), 1) +ifeq ($(HAVE_SWSCALE), 1) + OBJ += camera/drivers/ffmpeg.o +endif +endif +endif +endif +endif +endif + # Accessibility ifeq ($(HAVE_ACCESSIBILITY), 1) DEFINES += -DHAVE_ACCESSIBILITY @@ -2193,7 +2252,7 @@ ifeq ($(HAVE_NETWORKING), 1) ifneq ($(findstring Linux,$(OS)),) HAVE_CLOUDSYNC = 1 endif - + ifneq ($(findstring Win,$(OS)),) HAVE_CLOUDSYNC = 1 endif From 47e0a163f3d21773f0d62b63611608c21c17a8fd Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Mon, 16 Dec 2024 16:28:34 -0500 Subject: [PATCH 020/574] Don't try to link the ffmpeg camera driver twice - Whoops --- Makefile.common | 3 +-- camera/drivers/ffmpeg.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile.common b/Makefile.common index 4e3155b862..c122598c78 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2445,8 +2445,7 @@ ifeq ($(HAVE_FFMPEG), 1) cores/libretro-ffmpeg/ffmpeg_core.o \ cores/libretro-ffmpeg/packet_buffer.o \ cores/libretro-ffmpeg/video_buffer.o \ - $(LIBRETRO_COMM_DIR)/rthreads/tpool.o \ - camera/drivers/ffmpeg.o + $(LIBRETRO_COMM_DIR)/rthreads/tpool.o LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS) $(AVDEVICE_LIBS) DEFINES += -DHAVE_FFMPEG diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 754390cfdb..84ea257b49 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -32,7 +32,7 @@ * some video backends are better than others, * so we'll prioritize those as defaults. */ -const char *const FFMPEG_CAMERA_DEVICE_TYPE_PRIORITIES[] = { +static const char *const FFMPEG_CAMERA_DEVICE_TYPE_PRIORITIES[] = { /* Recommended camera backends */ #ifdef ANDROID "android_camera", From 7d31c65af13b50e21d35f4316777d1d7ff86fd54 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Mon, 16 Dec 2024 16:38:15 -0500 Subject: [PATCH 021/574] Fix compatibility with libswscale < 6.1.100 - sws_scale_frame was introduced in 6.1.100 - Before this change, the driver wouldn't build on my Ubuntu Jammy VM --- camera/drivers/ffmpeg.c | 85 +++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 84ea257b49..95bbbf19d7 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -86,7 +86,10 @@ typedef struct ffmpeg_camera AVDictionary *demuxer_options; AVPacket *packet; AVFrame *camera_frame; - AVFrame *target_frame; + unsigned requested_width; + unsigned requested_height; + uint8_t *target_planes[4]; + int target_linesizes[4]; unsigned target_width; unsigned target_height; struct SwsContext *scale_context; @@ -130,8 +133,8 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt return NULL; } - ffmpeg->target_width = width; - ffmpeg->target_height = height; + ffmpeg->requested_width = width; + ffmpeg->requested_height = height; avdevice_register_all(); RARCH_LOG("[FFMPEG]: Initialized libavdevice.\n"); @@ -257,29 +260,32 @@ static bool ffmpeg_camera_start(void *data) goto error; } - ffmpeg->target_frame = av_frame_alloc(); - if (!ffmpeg->target_frame) - { - RARCH_ERR("[FFMPEG]: Failed to allocate target frame.\n"); - goto error; - } + ffmpeg->target_width = ffmpeg->requested_width ? ffmpeg->requested_width : (unsigned)ffmpeg->decoder_context->width; + ffmpeg->target_height = ffmpeg->requested_height ? ffmpeg->requested_height : (unsigned)ffmpeg->decoder_context->height; - int buffer_length = av_image_get_buffer_size(AV_PIX_FMT_BGRA, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, 4); - if (buffer_length < 0) + int target_buffer_length = av_image_alloc( + ffmpeg->target_planes, + ffmpeg->target_linesizes, + ffmpeg->target_width, + ffmpeg->target_height, + AV_PIX_FMT_BGRA, + 1 + ); + if (target_buffer_length < 0) { - RARCH_ERR("[FFMPEG]: Failed to get buffer size for target frame: %s\n", av_err2str(buffer_length)); + RARCH_ERR("[FFMPEG]: Failed to allocate target plane: %s\n", av_err2str(target_buffer_length)); goto error; } /* target buffer aligned to 4 bytes because it's exposed to the core as a uint32_t[] */ - ffmpeg->target_buffer_length = buffer_length; - ffmpeg->target_buffers[0] = memalign_alloc(4, buffer_length); - ffmpeg->target_buffers[1] = memalign_alloc(4, buffer_length); + ffmpeg->target_buffer_length = target_buffer_length; + ffmpeg->target_buffers[0] = memalign_alloc(4, target_buffer_length); + ffmpeg->target_buffers[1] = memalign_alloc(4, target_buffer_length); ffmpeg->active_buffer = ffmpeg->target_buffers[0]; if (!ffmpeg->target_buffers[0] || !ffmpeg->target_buffers[1]) { RARCH_ERR("[FFMPEG]: Failed to allocate target %d-byte buffer for %dx%d %s-formatted video data.\n", - buffer_length, + target_buffer_length, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, av_get_pix_fmt_name(AV_PIX_FMT_BGRA) @@ -288,7 +294,7 @@ static bool ffmpeg_camera_start(void *data) } RARCH_LOG("[FFMPEG]: Allocated %d bytes for %dx%d %s-formatted video data.\n", - buffer_length, + target_buffer_length, ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, av_get_pix_fmt_name(ffmpeg->decoder_context->pix_fmt) @@ -298,8 +304,8 @@ static bool ffmpeg_camera_start(void *data) ffmpeg->decoder_context->width, ffmpeg->decoder_context->height, ffmpeg->decoder_context->pix_fmt, - ffmpeg->target_width ? ffmpeg->target_width : (unsigned)ffmpeg->decoder_context->width, - ffmpeg->target_height ? ffmpeg->target_height : (unsigned)ffmpeg->decoder_context->height, + ffmpeg->target_width, + ffmpeg->target_height, AV_PIX_FMT_BGRA, SWS_BILINEAR, NULL, NULL, NULL @@ -365,9 +371,13 @@ static void ffmpeg_camera_stop(void *data) ffmpeg->target_buffers[0] = NULL; ffmpeg->target_buffers[1] = NULL; ffmpeg->target_buffer_length = 0; + ffmpeg->target_width = 0; + ffmpeg->target_height = 0; - av_frame_free(&ffmpeg->target_frame); av_frame_free(&ffmpeg->camera_frame); + av_freep(&ffmpeg->target_buffers[0]); + memset(ffmpeg->target_linesizes, 0, sizeof(ffmpeg->target_linesizes)); + av_packet_free(&ffmpeg->packet); avcodec_free_context(&ffmpeg->decoder_context); avformat_close_input(&ffmpeg->format_context); @@ -393,8 +403,16 @@ static void ffmpeg_camera_poll_thread(void *data) result = avcodec_send_packet(ffmpeg->decoder_context, ffmpeg->packet); if (result < 0) { /* Send the raw data to the decoder. If that fails... */ - RARCH_ERR("[FFMPEG]: Failed to send packet to decoder: %s\n", av_err2str(result)); - continue; + if (result == AVERROR_EOF) + { + RARCH_DBG("[FFMPEG]: Video capture device closed\n"); + } + else + { + RARCH_ERR("[FFMPEG]: Failed to send packet to decoder: %s\n", av_err2str(result)); + } + + goto done_loop; } /* video streams consist of exactly one frame per packet */ @@ -411,7 +429,16 @@ static void ffmpeg_camera_poll_thread(void *data) retro_assert(ffmpeg->decoder->type == AVMEDIA_TYPE_VIDEO); - result = sws_scale_frame(ffmpeg->scale_context, ffmpeg->target_frame, ffmpeg->camera_frame); + /* sws_scale_frame is tidier but isn't as widely available */ + result = sws_scale( + ffmpeg->scale_context, + (const uint8_t *const *)ffmpeg->camera_frame->data, + ffmpeg->camera_frame->linesize, + 0, + ffmpeg->camera_frame->height, + ffmpeg->target_planes, + ffmpeg->target_linesizes + ); if (result < 0) { /* Scale and convert the frame to the target format. If that fails... */ RARCH_ERR("[FFMPEG]: Failed to scale frame: %s\n", av_err2str(result)); @@ -422,11 +449,11 @@ static void ffmpeg_camera_poll_thread(void *data) result = av_image_copy_to_buffer( ffmpeg->active_buffer, ffmpeg->target_buffer_length, - (const uint8_t *const *)ffmpeg->target_frame->data, - ffmpeg->target_frame->linesize, - ffmpeg->target_frame->format, - ffmpeg->target_frame->width, - ffmpeg->target_frame->height, + (const uint8_t *const *)ffmpeg->target_planes, + ffmpeg->target_linesizes, + AV_PIX_FMT_BGRA, + ffmpeg->target_width, + ffmpeg->target_height, 1 ); if (result >= 0) { @@ -467,7 +494,7 @@ static bool ffmpeg_camera_poll( } slock_lock(ffmpeg->target_buffer_lock); - frame_raw_cb((uint32_t*)ffmpeg->active_buffer, ffmpeg->target_frame->width, ffmpeg->target_frame->height, ffmpeg->target_frame->linesize[0]); + frame_raw_cb((uint32_t*)ffmpeg->active_buffer, ffmpeg->target_width, ffmpeg->target_height, ffmpeg->target_linesizes[0]); slock_unlock(ffmpeg->target_buffer_lock); return true; From 3c73b36cca0707922ef970c2a0fa17d0570dcc00 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Mon, 16 Dec 2024 16:45:12 -0500 Subject: [PATCH 022/574] Remove `const` from some fields --- camera/drivers/ffmpeg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 95bbbf19d7..3ef410864a 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -81,8 +81,8 @@ typedef struct ffmpeg_camera sthread_t *poll_thread; AVFormatContext *format_context; AVCodecContext *decoder_context; - const AVCodec *decoder; - const AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ + AVCodec *decoder; + AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ AVDictionary *demuxer_options; AVPacket *packet; AVFrame *camera_frame; From ce1f31af8daf6e1ae56a03d2061d364f2e1f073d Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Mon, 16 Dec 2024 21:53:37 -0500 Subject: [PATCH 023/574] Don't pass in the driver context to `camera_driver::device_list_new` - Unlike some other drivers, the camera driver is only initialized when a core actually asks for it - Therefore, the driver context isn't available when it's time to ask for devices - I could refactor the camera driver to be created earlier, but then I'd need to refactor the other drivers as well - That'll come later in another PR --- camera/camera_driver.c | 4 ++-- camera/camera_driver.h | 4 ++-- camera/drivers/ffmpeg.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/camera/camera_driver.c b/camera/camera_driver.c index 922565cd68..d5794faf49 100644 --- a/camera/camera_driver.c +++ b/camera/camera_driver.c @@ -34,8 +34,8 @@ static bool nullcamera_start(void *data) { return true; } static bool nullcamera_poll(void *a, retro_camera_frame_raw_framebuffer_t b, retro_camera_frame_opengl_texture_t c) { return true; } -static struct string_list *nullcamera_device_list_new(const void *data) { return NULL; } -static void nullcamera_device_list_free(const void *data, struct string_list *devices) {} +static struct string_list *nullcamera_device_list_new() { return NULL; } +static void nullcamera_device_list_free(struct string_list *devices) {} static camera_driver_t camera_null = { nullcamera_init, diff --git a/camera/camera_driver.h b/camera/camera_driver.h index 30f3cdebad..086ce155d5 100644 --- a/camera/camera_driver.h +++ b/camera/camera_driver.h @@ -49,8 +49,8 @@ typedef struct camera_driver retro_camera_frame_raw_framebuffer_t frame_raw_cb, retro_camera_frame_opengl_texture_t frame_gl_cb); - struct string_list *(*device_list_new)(const void *driver_context); - void (*device_list_free)(const void *driver_context, struct string_list *devices); + struct string_list *(*device_list_new)(void); + void (*device_list_free)(struct string_list *devices); const char *ident; } camera_driver_t; diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 3ef410864a..1a68d4c0ba 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -500,7 +500,7 @@ static bool ffmpeg_camera_poll( return true; } -static struct string_list *ffmpeg_camera_device_list_new(const void *driver_context) +static struct string_list *ffmpeg_camera_device_list_new(void) { const AVInputFormat *input = NULL; struct string_list *list = string_list_new(); @@ -517,7 +517,7 @@ static struct string_list *ffmpeg_camera_device_list_new(const void *driver_cont return list; } -static void ffmpeg_camera_device_list_free(const void *driver_context, struct string_list *devices) +static void ffmpeg_camera_device_list_free(struct string_list *devices) { struct string_list *sl = (struct string_list*)devices; From 7b21ed5f934846dfef3684fd4cb0972e2a2bf210 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Tue, 17 Dec 2024 14:37:29 -0500 Subject: [PATCH 024/574] Set options for the camera and accompanying AV structures --- camera/drivers/ffmpeg.c | 55 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 1a68d4c0ba..f6912ab159 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -83,7 +83,7 @@ typedef struct ffmpeg_camera AVCodecContext *decoder_context; AVCodec *decoder; AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ - AVDictionary *demuxer_options; + AVDictionary *options; AVPacket *packet; AVFrame *camera_frame; unsigned requested_width; @@ -147,8 +147,22 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt } AVDeviceInfoList *device_list = NULL; - int num_sources = avdevice_list_input_sources(ffmpeg->input_format, NULL, NULL, &device_list); - // TODO: Handle case where zero sources are returned + + // TODO: Pick the best size for the camera + int result = av_dict_set(&ffmpeg->options, "video_size", "640x480", 0); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to set option: %s\n", av_err2str(result)); + goto error; + } + + int num_sources = avdevice_list_input_sources(ffmpeg->input_format, NULL, ffmpeg->options, &device_list); + if (num_sources == 0) + { + RARCH_ERR("[FFMPEG]: No video input sources found.\n"); + goto error; + } + if (num_sources < 0) { RARCH_ERR("[FFMPEG]: Failed to list video input sources: %s\n", av_err2str(num_sources)); @@ -177,6 +191,8 @@ static void ffmpeg_camera_free(void *data) ffmpeg_camera_stop(ffmpeg); + av_dict_free(&ffmpeg->options); + free(ffmpeg); } @@ -187,6 +203,8 @@ static bool ffmpeg_camera_start(void *data) ffmpeg_camera_t *ffmpeg = data; int result = 0; AVStream *stream = NULL; + AVDictionary *options = NULL; + const AVDictionaryEntry *e = NULL; if (ffmpeg->format_context) { // TODO: Check the actual format context, not just the pointer @@ -194,13 +212,26 @@ static bool ffmpeg_camera_start(void *data) return true; } - result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, &ffmpeg->demuxer_options); + result = av_dict_copy(&options, ffmpeg->options, 0); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy options: %s\n", av_err2str(result)); + goto error; + } + + result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, &options); if (result < 0) { RARCH_ERR("[FFMPEG]: Failed to open video input device: %s\n", av_err2str(result)); goto error; } + while ((e = av_dict_iterate(options, e))) { + RARCH_WARN("[FFMPEG]: Unrecognized option on video input device: %s=%s\n", e->key, e->value); + } + + av_dict_free(&options); + result = avformat_find_stream_info(ffmpeg->format_context, NULL); if (result < 0) { @@ -238,14 +269,26 @@ static bool ffmpeg_camera_start(void *data) goto error; } - AVDictionary *opts = NULL; - result = avcodec_open2(ffmpeg->decoder_context, ffmpeg->decoder, &opts); + result = av_dict_copy(&ffmpeg->options, options, 0); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy options: %s\n", av_err2str(result)); + goto error; + } + + result = avcodec_open2(ffmpeg->decoder_context, ffmpeg->decoder, &options); if (result < 0) { RARCH_ERR("[FFMPEG]: Failed to open decoder: %s\n", av_err2str(result)); goto error; } + while ((e = av_dict_iterate(options, e))) { + RARCH_WARN("[FFMPEG]: Unrecognized option on video input device: %s=%s\n", e->key, e->value); + } + + av_dict_free(&options); + ffmpeg->packet = av_packet_alloc(); if (!ffmpeg->packet) { From 88b6342bb5ee0f7435265fe0f09cfd7ba464d259 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Tue, 17 Dec 2024 14:57:06 -0500 Subject: [PATCH 025/574] Move up some declarations --- camera/drivers/ffmpeg.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index f6912ab159..cadb40a1b7 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -118,7 +118,9 @@ static const AVInputFormat *ffmpeg_camera_choose_format(const char *device) static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { ffmpeg_camera_t *ffmpeg = NULL; - AVDictionary *options = NULL; + AVDeviceInfoList *device_list = NULL; + int result = 0; + int num_sources = 0; if ((caps & (UINT64_C(1) << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER)) == 0) { /* If the core didn't ask for raw framebuffers... */ @@ -146,17 +148,18 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt goto error; } - AVDeviceInfoList *device_list = NULL; + RARCH_LOG("[FFMPEG]: Using default camera backend: %s (%s, flags=0x%x)\n", ffmpeg->input_format->name, ffmpeg->input_format->long_name, ffmpeg->input_format->flags); + // TODO: Pick the best size for the camera - int result = av_dict_set(&ffmpeg->options, "video_size", "640x480", 0); + result = av_dict_set(&ffmpeg->options, "video_size", "640x480", 0); if (result < 0) { RARCH_ERR("[FFMPEG]: Failed to set option: %s\n", av_err2str(result)); goto error; } - int num_sources = avdevice_list_input_sources(ffmpeg->input_format, NULL, ffmpeg->options, &device_list); + num_sources = avdevice_list_input_sources(ffmpeg->input_format, NULL, ffmpeg->options, &device_list); if (num_sources == 0) { RARCH_ERR("[FFMPEG]: No video input sources found.\n"); From 7586ae7dbe00a337e2c2ff828f214102e151e3b0 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Tue, 17 Dec 2024 14:57:36 -0500 Subject: [PATCH 026/574] Remove stray whitespace --- camera/drivers/ffmpeg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index cadb40a1b7..5d344047d4 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -75,7 +75,6 @@ static const char *const FFMPEG_CAMERA_DEVICE_TYPE_PRIORITIES[] = { */ }; - typedef struct ffmpeg_camera { sthread_t *poll_thread; From 4aac4d5b9e2a49374746f56eee437f0bbe5c489c Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Wed, 18 Dec 2024 14:28:49 -0500 Subject: [PATCH 027/574] Forward ffmpeg's logging to RetroArch --- camera/drivers/ffmpeg.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 5d344047d4..aee1600244 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -114,6 +114,35 @@ static const AVInputFormat *ffmpeg_camera_choose_format(const char *device) } // TODO: device format shall be: "/" + +static void ffmpeg_camera_log(void *avcl, int level, const char *fmt, va_list args) +{ + AVClass *class = *(AVClass **)avcl; + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), fmt, args); + + switch (level) + { + case AV_LOG_PANIC: + case AV_LOG_FATAL: + case AV_LOG_ERROR: + RARCH_ERR("[FFMPEG %s]: %s\n", class->class_name, buffer); + break; + case AV_LOG_WARNING: + RARCH_WARN("[FFMPEG %s]: %s\n", class->class_name, buffer); + break; + case AV_LOG_INFO: + RARCH_LOG("[FFMPEG %s]: %s\n", class->class_name, buffer); + break; + case AV_LOG_VERBOSE: + RARCH_DBG("[FFMPEG %s]: %s\n", class->class_name, buffer); + break; + default: + /* AV_LOG_DEBUG isn't useful for RetroArch, and AV_LOG_TRACE is too noisy */ + break; + } +} + static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { ffmpeg_camera_t *ffmpeg = NULL; @@ -137,6 +166,9 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt ffmpeg->requested_width = width; ffmpeg->requested_height = height; + /* Forward ffmpeg's logs to RetroArch */ + av_log_set_callback(ffmpeg_camera_log); + avdevice_register_all(); RARCH_LOG("[FFMPEG]: Initialized libavdevice.\n"); @@ -196,6 +228,8 @@ static void ffmpeg_camera_free(void *data) av_dict_free(&ffmpeg->options); free(ffmpeg); + + av_log_set_callback(av_log_default_callback); } static void ffmpeg_camera_poll_thread(void *data); From 4beb80c290b6c7d7232da45f6407ea4e43476247 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Wed, 18 Dec 2024 14:52:28 -0500 Subject: [PATCH 028/574] Revert "Forward ffmpeg's logging to RetroArch" This reverts commit 4aac4d5b9e2a49374746f56eee437f0bbe5c489c. --- camera/drivers/ffmpeg.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index aee1600244..5d344047d4 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -114,35 +114,6 @@ static const AVInputFormat *ffmpeg_camera_choose_format(const char *device) } // TODO: device format shall be: "/" - -static void ffmpeg_camera_log(void *avcl, int level, const char *fmt, va_list args) -{ - AVClass *class = *(AVClass **)avcl; - char buffer[1024]; - vsnprintf(buffer, sizeof(buffer), fmt, args); - - switch (level) - { - case AV_LOG_PANIC: - case AV_LOG_FATAL: - case AV_LOG_ERROR: - RARCH_ERR("[FFMPEG %s]: %s\n", class->class_name, buffer); - break; - case AV_LOG_WARNING: - RARCH_WARN("[FFMPEG %s]: %s\n", class->class_name, buffer); - break; - case AV_LOG_INFO: - RARCH_LOG("[FFMPEG %s]: %s\n", class->class_name, buffer); - break; - case AV_LOG_VERBOSE: - RARCH_DBG("[FFMPEG %s]: %s\n", class->class_name, buffer); - break; - default: - /* AV_LOG_DEBUG isn't useful for RetroArch, and AV_LOG_TRACE is too noisy */ - break; - } -} - static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { ffmpeg_camera_t *ffmpeg = NULL; @@ -166,9 +137,6 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt ffmpeg->requested_width = width; ffmpeg->requested_height = height; - /* Forward ffmpeg's logs to RetroArch */ - av_log_set_callback(ffmpeg_camera_log); - avdevice_register_all(); RARCH_LOG("[FFMPEG]: Initialized libavdevice.\n"); @@ -228,8 +196,6 @@ static void ffmpeg_camera_free(void *data) av_dict_free(&ffmpeg->options); free(ffmpeg); - - av_log_set_callback(av_log_default_callback); } static void ffmpeg_camera_poll_thread(void *data); From 9ee56da6b01ee1867ac9c40f5b2729076809f896 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Wed, 18 Dec 2024 20:31:44 -0500 Subject: [PATCH 029/574] Prioritize certain backends --- camera/drivers/ffmpeg.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index 5d344047d4..b28b54cb4d 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -106,11 +106,21 @@ typedef struct ffmpeg_camera static void ffmpeg_camera_free(void *data); -static const AVInputFormat *ffmpeg_camera_choose_format(const char *device) +// TODO: Pick a backend based on the settings, too +static const AVInputFormat *ffmpeg_camera_get_default_backend(void) { - // TODO: If `device` is not NULL or empty, parse it to get the backend and device name - // TODO: Pick the best backend for the current platform, don't just return the first - return av_input_video_device_next(NULL); + const AVInputFormat *format = NULL; + for (unsigned i = 0; FFMPEG_CAMERA_DEVICE_TYPE_PRIORITIES[i]; i++) + { + format = av_find_input_format(FFMPEG_CAMERA_DEVICE_TYPE_PRIORITIES[i]); + if (format) + break; + } + + if (!format) + format = av_input_video_device_next(NULL); + + return format; } // TODO: device format shall be: "/" @@ -140,10 +150,10 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt avdevice_register_all(); RARCH_LOG("[FFMPEG]: Initialized libavdevice.\n"); - ffmpeg->input_format = ffmpeg_camera_choose_format(device); + ffmpeg->input_format = ffmpeg_camera_get_default_backend(); if (!ffmpeg->input_format) { - RARCH_ERR("[FFMPEG]: No suitable video input devices found.\n"); + RARCH_ERR("[FFMPEG]: No suitable video input backend found.\n"); goto error; } From b68a588ede905087991b247c6fea051d024d7920 Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Wed, 18 Dec 2024 20:32:19 -0500 Subject: [PATCH 030/574] Split some ffmpeg camera logic into functions --- camera/drivers/ffmpeg.c | 126 +++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 20 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index b28b54cb4d..dcdfc156f1 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -21,6 +21,7 @@ #include "lists/string_list.h" #include "verbosity.h" +#include #include #include #include @@ -80,8 +81,8 @@ typedef struct ffmpeg_camera sthread_t *poll_thread; AVFormatContext *format_context; AVCodecContext *decoder_context; - AVCodec *decoder; - AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ + const AVCodec *decoder; + const AVInputFormat *input_format; /* owned by ffmpeg, don't free it */ AVDictionary *options; AVPacket *packet; AVFrame *camera_frame; @@ -123,7 +124,99 @@ static const AVInputFormat *ffmpeg_camera_get_default_backend(void) return format; } -// TODO: device format shall be: "/" +static int ffmpeg_camera_get_initial_options( + const AVInputFormat *backend, + AVDictionary **options, + uint64_t caps, + unsigned width, + unsigned height +) +{ + int result = 0; + char dimensions[128]; + if (width != 0 && height != 0) + { /* If the core is letting the frontend pick the size... */ + snprintf(dimensions, sizeof(dimensions), "%ux%u", width, height); + + result = av_dict_set(options, "video_size", dimensions, 0); + + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to set option: %s\n", av_err2str(result)); + goto error; + } + } + /* I wanted to list supported formats and pick the most appropriate size + * if the requested size isn't available, + * but ffmpeg doesn't seem to offer a way to do that. + */ + + if (!options) + { + RARCH_DBG("[FFMPEG]: No options set, not allocating a dict (this isn't an error)"); + } + + return result; + +error: + av_dict_free(options); + return result; + +} + +static void ffmpeg_camera_get_source_url(ffmpeg_camera_t *ffmpeg, const AVDeviceInfo *device) +{ + snprintf(ffmpeg->url, sizeof(ffmpeg->url), "video=%s", device->device_description); + // TODO: this url is specific to dshow, need to generalize it +} + +static int ffmpeg_camera_open_device(ffmpeg_camera_t *ffmpeg) +{ + AVDictionaryEntry *e = NULL; + AVDictionary *options = NULL; + int result = ffmpeg->options ? av_dict_copy(&options, ffmpeg->options, 0) : 0; + /* copy the options dict so that other steps in start() can use it, + * as avformat_open_input clears it and adds unrecognized settings */ + + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to copy options: %s\n", av_err2str(result)); + goto done; + } + + result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, &options); + if (result < 0) + { + RARCH_WARN("[FFMPEG]: Failed to open video input device \"%s\": %s\n", ffmpeg->url, av_err2str(result)); + + if (ffmpeg->options) + { /* If we're not already requesting the default format... */ + + result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, NULL); + if (result < 0) + { + RARCH_ERR("[FFMPEG]: Failed to open the same device in its default format: %s\n", av_err2str(result)); + goto done; + } + } + } + +done: + if (options) + { + while ((e = av_dict_iterate(options, e))) { + RARCH_WARN("[FFMPEG]: Unrecognized option on video input device: %s=%s\n", e->key, e->value); + } + } + + av_dict_free(&options); /* noop if NULL */ + if (result == 0) + { + RARCH_LOG("[FFMPEG]: Opened video input device \"%s\".\n", ffmpeg->url); + } + return result; +} + static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { ffmpeg_camera_t *ffmpeg = NULL; @@ -159,12 +252,10 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt RARCH_LOG("[FFMPEG]: Using default camera backend: %s (%s, flags=0x%x)\n", ffmpeg->input_format->name, ffmpeg->input_format->long_name, ffmpeg->input_format->flags); - - // TODO: Pick the best size for the camera - result = av_dict_set(&ffmpeg->options, "video_size", "640x480", 0); + result = ffmpeg_camera_get_initial_options(ffmpeg->input_format, &ffmpeg->options, caps, width, height); if (result < 0) { - RARCH_ERR("[FFMPEG]: Failed to set option: %s\n", av_err2str(result)); + RARCH_ERR("[FFMPEG]: Failed to get initial options: %s\n", av_err2str(result)); goto error; } @@ -181,9 +272,8 @@ static void *ffmpeg_camera_init(const char *device, uint64_t caps, unsigned widt goto error; } + ffmpeg_camera_get_source_url(ffmpeg, device_list->devices[0]); RARCH_LOG("[FFMPEG]: Using video input device: %s (%s, flags=0x%x)\n", ffmpeg->input_format->name, ffmpeg->input_format->long_name, ffmpeg->input_format->flags); - snprintf(ffmpeg->url, sizeof(ffmpeg->url), "video=%s", device_list->devices[0]->device_name); - // TODO: this url is specific to dshow, need to generalize it avdevice_free_list_devices(&device_list); return ffmpeg; @@ -212,6 +302,7 @@ static void ffmpeg_camera_poll_thread(void *data); static bool ffmpeg_camera_start(void *data) { + const settings_t *settings = config_get_ptr(); ffmpeg_camera_t *ffmpeg = data; int result = 0; AVStream *stream = NULL; @@ -224,6 +315,10 @@ static bool ffmpeg_camera_start(void *data) return true; } + result = ffmpeg_camera_open_device(ffmpeg); + if (result < 0) + goto error; + result = av_dict_copy(&options, ffmpeg->options, 0); if (result < 0) { @@ -231,10 +326,10 @@ static bool ffmpeg_camera_start(void *data) goto error; } - result = avformat_open_input(&ffmpeg->format_context, ffmpeg->url, ffmpeg->input_format, &options); + result = avformat_find_stream_info(ffmpeg->format_context, &options); if (result < 0) { - RARCH_ERR("[FFMPEG]: Failed to open video input device: %s\n", av_err2str(result)); + RARCH_ERR("[FFMPEG]: Failed to find stream info: %s\n", av_err2str(result)); goto error; } @@ -242,15 +337,6 @@ static bool ffmpeg_camera_start(void *data) RARCH_WARN("[FFMPEG]: Unrecognized option on video input device: %s=%s\n", e->key, e->value); } - av_dict_free(&options); - - result = avformat_find_stream_info(ffmpeg->format_context, NULL); - if (result < 0) - { - RARCH_ERR("[FFMPEG]: Failed to find stream info: %s\n", av_err2str(result)); - goto error; - } - result = av_find_best_stream(ffmpeg->format_context, AVMEDIA_TYPE_VIDEO, -1, -1, &ffmpeg->decoder, 0); if (result < 0) { From 3cdb95a602b6b4525fee4a68d5dfd7e452a7580d Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Wed, 18 Dec 2024 21:05:30 -0500 Subject: [PATCH 031/574] Construct device URLs differently based on the ffmpeg backend --- camera/drivers/ffmpeg.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/camera/drivers/ffmpeg.c b/camera/drivers/ffmpeg.c index dcdfc156f1..9d0b498386 100644 --- a/camera/drivers/ffmpeg.c +++ b/camera/drivers/ffmpeg.c @@ -28,6 +28,7 @@ #include #include #include +#include /* ffmpeg supports a specific range of video devices; * some video backends are better than others, @@ -164,10 +165,31 @@ error: } +/* Device URL syntax varies by backend. + * See https://ffmpeg.org/ffmpeg-devices.html for details. */ static void ffmpeg_camera_get_source_url(ffmpeg_camera_t *ffmpeg, const AVDeviceInfo *device) { - snprintf(ffmpeg->url, sizeof(ffmpeg->url), "video=%s", device->device_description); - // TODO: this url is specific to dshow, need to generalize it +#ifdef __WIN32__ + if (string_is_equal(ffmpeg->input_format->name, "dshow")) + { + snprintf(ffmpeg->url, sizeof(ffmpeg->url), "video=%s", device->device_description); + return; + } +#elif defined(__APPLE__) + if (string_is_equal(ffmpeg->input_format->name, "avfoundation")) + { + /* we only want video, not audio */ + snprintf(ffmpeg->url, sizeof(ffmpeg->url), "%s:none", device->device_description); + return; + } +#endif + + /* Other backends that support listing available sources use the name as-is; + * some advanced backends have extra syntax (e.g. gdigrab) + * but they don't support listing available sources, + * so players will have to enter them manually. + */ + strlcpy(ffmpeg->url, device->device_description, sizeof(ffmpeg->url)); } static int ffmpeg_camera_open_device(ffmpeg_camera_t *ffmpeg) From f7159c43807f78a37fa1c6f2b0dd6bb1ab2f8b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Via=C4=8Das=C5=82a=C5=AD?= Date: Sun, 5 Jan 2025 05:50:22 +0300 Subject: [PATCH 032/574] Fix Qt5 build (#17346) --- qb/config.libs.sh | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 2c9d020b41..2024d810d0 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -286,6 +286,7 @@ check_enabled CXX DISCORD discord 'The C++ compiler is' false check_enabled CXX QT 'Qt companion' 'The C++ compiler is' false if [ "$HAVE_QT" != 'no' ]; then + _have_qt=$HAVE_QT if [ "$HAVE_CXX17" = 'yes' ]; then check_pkgconf QT6CORE Qt6Core 6.2 check_pkgconf QT6GUI Qt6Gui 6.2 @@ -296,22 +297,25 @@ if [ "$HAVE_QT" != 'no' ]; then # pkg-config is needed to reliably find Qt6 libraries. - check_enabled QT6CORE QT Qt 'Qt6Core is' true - check_enabled QT6GUI QT Qt 'Qt6GUI is' true - check_enabled QT6WIDGETS QT Qt 'Qt6Widgets is' true - check_enabled QT6CONCURRENT QT Qt 'Qt6Concurrent is' true - check_enabled QT6NETWORK QT Qt 'Qt6Network is' true - #check_enabled QT6WEBENGINE QT Qt 'Qt6Webengine is' true + check_enabled QT6CORE QT Qt 'Qt6Core is' user + check_enabled QT6GUI QT Qt 'Qt6GUI is' user + check_enabled QT6WIDGETS QT Qt 'Qt6Widgets is' user + check_enabled QT6CONCURRENT QT Qt 'Qt6Concurrent is' user + check_enabled QT6NETWORK QT Qt 'Qt6Network is' user + #check_enabled QT6WEBENGINE QT Qt 'Qt6Webengine is' user - if [ "$HAVE_QT" != yes ]; then - die : 'Notice: Qt support disabled, required libraries were not found.' - else + if [ "$HAVE_QT6CORE" == 'yes' ] && \ + [ "$HAVE_QT6GUI" == 'yes' ] && \ + [ "$HAVE_QT6WIDGETS" == 'yes' ] && \ + [ "$HAVE_QT6CONCURRENT" == 'yes' ] && \ + [ "$HAVE_QT6NETWORK" == 'yes' ] + then HAVE_QT6='yes' add_define MAKEFILE HAVE_QT6 1 fi fi if [ "$HAVE_QT6" != 'yes' ]; then - HAVE_QT='auto' + HAVE_QT=$_have_qt check_pkgconf QT5CORE Qt5Core 5.2 check_pkgconf QT5GUI Qt5Gui 5.2 check_pkgconf QT5WIDGETS Qt5Widgets 5.2 @@ -327,10 +331,10 @@ if [ "$HAVE_QT" != 'no' ]; then check_enabled QT5CONCURRENT QT Qt 'Qt5Concurrent is' true check_enabled QT5NETWORK QT Qt 'Qt5Network is' true #check_enabled QT5WEBENGINE QT Qt 'Qt5Webengine is' true + fi - if [ "$HAVE_QT" != yes ]; then - die : 'Notice: Qt support disabled, required libraries were not found.' - fi + if [ "$HAVE_QT" != yes ]; then + die : 'Notice: Qt support disabled, required libraries were not found.' fi check_pkgconf OPENSSL openssl 1.0.0 From 091326381799690352e4fde48664b9b0030369cb Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Sun, 5 Jan 2025 04:50:32 +0200 Subject: [PATCH 033/574] Integer Scale Axis sublabel correction (#17345) --- intl/msg_hash_us.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 89118f2329..22555d8ba3 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2599,7 +2599,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Scale only height, or both height and width. Half steps apply to high resolution sources." + "Scale either height or width, or both height and width. Half steps apply only to high resolution sources." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, From ab3b175848fa6cd8b2340809631e30bc0fe1d136 Mon Sep 17 00:00:00 2001 From: zoltanvb <101990835+zoltanvb@users.noreply.github.com> Date: Sun, 5 Jan 2025 03:50:47 +0100 Subject: [PATCH 034/574] Restore missed absolute mouse conversion. (#17343) --- input/drivers/udev_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/input/drivers/udev_input.c b/input/drivers/udev_input.c index 01834f133e..8dcecebf28 100644 --- a/input/drivers/udev_input.c +++ b/input/drivers/udev_input.c @@ -800,8 +800,8 @@ static bool udev_mouse_get_pointer(const udev_input_mouse_t *mouse, { /* mouse coordinates are relative to the full screen; convert them * to be relative to the viewport */ - scaled_x = mouse->x_abs - mouse->x_min; - scaled_y = mouse->y_abs - mouse->y_min; + scaled_x = vp.full_width * (mouse->x_abs - mouse->x_min) / (mouse->x_max - mouse->x_min + 1); + scaled_y = vp.full_height * (mouse->y_abs - mouse->y_min) / (mouse->y_max - mouse->y_min + 1); } else /* mouse coords are viewport relative */ { From 9c6e77249753f29ef264a8959eb7ca61756cd9e7 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 6 Jan 2025 00:15:51 +0000 Subject: [PATCH 035/574] Fetch translations from Crowdin --- intl/msg_hash_be.h | 10 +++++++++- intl/msg_hash_chs.h | 4 ---- intl/msg_hash_cht.h | 4 ---- intl/msg_hash_cs.h | 4 ---- intl/msg_hash_de.h | 4 ---- intl/msg_hash_es.h | 4 ---- intl/msg_hash_fr.h | 2 +- intl/msg_hash_gl.h | 4 ---- intl/msg_hash_hu.h | 4 ---- intl/msg_hash_it.h | 2 +- intl/msg_hash_ko.h | 4 ---- intl/msg_hash_pl.h | 4 ---- intl/msg_hash_ru.h | 2 +- intl/msg_hash_tr.h | 10 +++++++++- intl/msg_hash_uk.h | 2 +- intl/progress.h | 10 +++++----- 16 files changed, 27 insertions(+), 47 deletions(-) diff --git a/intl/msg_hash_be.h b/intl/msg_hash_be.h index 385a270e98..303742356c 100644 --- a/intl/msg_hash_be.h +++ b/intl/msg_hash_be.h @@ -2563,7 +2563,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Змяняць маштаб толькі па вышыні або як па вышыні, так і па шырыні. Паўкрокі прымяняюцца да крыніц з высокай раздзяляльнасцю." + "Змяняць маштаб па вышыні ці па шырыні, або адразу па вышыні ды шырыні. Паўкрокі ўжываюцца толькі на крыніцах з высокай раздзяляльнасцю." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -5386,6 +5386,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "Настройка памеру зон перакрыцця для блока кнопак. Усталюйце на 100% для сіметрыі па 8 напрамках." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Зона перацэнтроўкі аналагавага ўвода" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Увод аналагавы стыку будзе адлічвацца адносна першага дотыку пры націсканні ў гэтай зоне." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Накладка" diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index 56ea51ef5c..84adedb875 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -2529,10 +2529,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "整数缩放轴" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "仅缩放高度,或同时缩放高度和宽度。半步适用于高分辨率信号源。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_SMART, "智能" diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index fa934ddc81..f56af77803 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -2489,10 +2489,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "整數縮放方式" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "設定可以使用高度或同時使用高度和寬度, 高度加半高或寬度加半寬適用於高解析度。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "整數縮放模式" diff --git a/intl/msg_hash_cs.h b/intl/msg_hash_cs.h index 1f97f4d64d..2809bc0818 100644 --- a/intl/msg_hash_cs.h +++ b/intl/msg_hash_cs.h @@ -2481,10 +2481,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Celočíselné škálování" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Měřítko pouze výška, nebo jak výška, tak šířka. Poloviční kroky platí pro zdroje vysokého rozlišení." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_SMART, "Chytrá" diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 43c2b69562..5e76b0a8a1 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -2469,10 +2469,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Ganzzahlige Skalenachse" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Nur Höhe oder Höhe und Breite skalieren. Halbschritte beziehen sich auf die Auflösung der Quellen." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "Ganzzahlige Skalierung" diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index d61b74f182..463d611a5a 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -2545,10 +2545,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Ejes del escalado por números enteros" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Escala solo la altura o también la anchura. Los escalados irregulares se aplicarán a las imágenes en alta resolución." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "Tipo de escalado por números enteros" diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index 0e464c6a37..090edc500b 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -2523,7 +2523,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Mettre à l'échelle la hauteur uniquement, ou la hauteur et la largeur. Les demi-étapes s'appliquent aux sources haute résolution." + "Mettre à l'échelle soit la hauteur ou la largeur, soit la hauteur et la largeur. Les demi-étapes s'appliquent uniquement aux sources haute résolution." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, diff --git a/intl/msg_hash_gl.h b/intl/msg_hash_gl.h index 7667b654e3..0550fe4e52 100644 --- a/intl/msg_hash_gl.h +++ b/intl/msg_hash_gl.h @@ -2525,10 +2525,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Eixo de escala enteira" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Escalar só a altura, ou tanto a altura como o ancho. Os pasos medios aplícanse a fontes de alta resolución." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "Escalado de escala enteira" diff --git a/intl/msg_hash_hu.h b/intl/msg_hash_hu.h index e814a6798f..b4663e24d4 100644 --- a/intl/msg_hash_hu.h +++ b/intl/msg_hash_hu.h @@ -2497,10 +2497,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Egész-szorzós méretezés tengelye" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Méretezés csak a magasság, vagy a magasság és szélesség szerint. A fél lépések a nagyfelbontású forrásokra vonatkoznak." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "Egész-szorzós méretezés" diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 6a2e923698..1e5049dd3f 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -2503,7 +2503,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Scala solo altezza, o entrambi altezza e larghezza. Metà passi si applicano alle sorgenti ad alta risoluzione." + "Scala altezza o larghezza, o entrambe altezza e larghezza. Mezzi passaggi si applicano solo alle sorgenti ad alta risoluzione." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index cfa8f52551..5870e121a2 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -2565,10 +2565,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "정수 단위 조정 기준 축" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "화면 크기를 조정할 때 기준을 높이로 할지, 높이와 너비 모두로 할지 설정합니다. 고해상도 영상에는 절반 단위 조정도 적용됩니다." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "정수 단위 조정 방식" diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index 7ddae92c13..2d576ff01e 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -2505,10 +2505,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Oś skali całkowitej" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Skaluj tylko wysokość lub zarówno wysokość, jak i szerokość. Połowa kroków dotyczy źródeł o wysokiej rozdzielczości." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING_SMART, "Inteligentny" diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 0b2dbe3ed3..022ce3dbfa 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -2563,7 +2563,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Изменять масштаб только по высоте или по высоте и ширине. Значения в полшага применяются к источникам высокого разрешения." + "Изменять масштаб по высоте, ширине или по высоте и ширине. Значения в полшага применяются только к источникам высокого разрешения." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, diff --git a/intl/msg_hash_tr.h b/intl/msg_hash_tr.h index 3e4d310aab..d792ad6690 100644 --- a/intl/msg_hash_tr.h +++ b/intl/msg_hash_tr.h @@ -2539,7 +2539,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Yalnızca yüksekliği veya hem yüksekliği hem de genişliği ölçeklendirin. Yüksek çözünürlüklü kaynaklar için yarım adımlar geçerlidir." + "Yüksekliği veya genişliği ya da hem yüksekliği hem de genişliği ölçeklendirin. Yarım adımlar yalnızca yüksek çözünürlüklü kaynaklara uygulanır." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, @@ -5362,6 +5362,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "Örtüşme hassasiyetini ayarlayın. 8 yönlü simetri için %100'e ayarlayın." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analog Yeniden Yönlendirme Bölgesi" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analog çubuk girişi, bu bölgede basıldığında ilk dokunuşa göre olacaktır." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Kaplama" diff --git a/intl/msg_hash_uk.h b/intl/msg_hash_uk.h index 2e48aadc60..bd97306b82 100644 --- a/intl/msg_hash_uk.h +++ b/intl/msg_hash_uk.h @@ -2563,7 +2563,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, - "Масштабувати лише висоту, або висоту та ширину. Половинні кроки застосовуються до джерел високої роздільної здатності." + "Масштабувати або висоту, або висоту, і ширину. Половина кроків застосовуються лише до джерел високої роздільної здатності." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, diff --git a/intl/progress.h b/intl/progress.h index d48bb1ce41..c1d8901506 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -7,7 +7,7 @@ #define LANGUAGE_PROGRESS_ASTURIAN_APPROVED 9 /* Belarusian */ -#define LANGUAGE_PROGRESS_BELARUSIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_BELARUSIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_BELARUSIAN_APPROVED 0 /* Bulgarian */ @@ -31,7 +31,7 @@ #define LANGUAGE_PROGRESS_DANISH_APPROVED 0 /* German */ -#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_GERMAN_APPROVED 14 /* Greek */ @@ -47,7 +47,7 @@ #define LANGUAGE_PROGRESS_ESPERANTO_APPROVED 0 /* Spanish */ -#define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 100 +#define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 99 #define LANGUAGE_PROGRESS_SPANISH_APPROVED 90 /* Persian */ @@ -135,8 +135,8 @@ #define LANGUAGE_PROGRESS_SWEDISH_APPROVED 47 /* Turkish */ -#define LANGUAGE_PROGRESS_TURKISH_TRANSLATED 99 -#define LANGUAGE_PROGRESS_TURKISH_APPROVED 99 +#define LANGUAGE_PROGRESS_TURKISH_TRANSLATED 100 +#define LANGUAGE_PROGRESS_TURKISH_APPROVED 100 /* Tatar */ #define LANGUAGE_PROGRESS_TATAR_TRANSLATED 0 From 5399faaa9d6e625fd462cb92d7d203c88df2cd10 Mon Sep 17 00:00:00 2001 From: zoltanvb <101990835+zoltanvb@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:45:00 +0100 Subject: [PATCH 036/574] Fix savestate auto-index detection (#17351) --- command.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/command.c b/command.c index 1f33a6a008..8dfe80e471 100644 --- a/command.c +++ b/command.c @@ -1460,7 +1460,8 @@ static void scan_states(settings_t *settings, if (string_is_empty(dir_elem)) continue; - _len = fill_pathname_base(elem_base, dir_elem, sizeof(elem_base)); + _len = strlen(dir_elem); + fill_pathname_base(elem_base, dir_elem, sizeof(elem_base)); /* Only consider files with a '.state' extension * > i.e. Ignore '.state.auto', '.state.bak', etc. */ From 43a2e1003e31241f0fa0e24f0ed1fed0efe35f92 Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Mon, 6 Jan 2025 21:36:57 +0100 Subject: [PATCH 037/574] allow exact sync with shader subframes (#17355) * allow exact sync with shader subframes * Update menu_setting.c --- menu/menu_setting.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 589cbe7f49..7513be0697 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -8670,9 +8670,6 @@ static void general_write_handler(rarch_setting_t *setting) configuration_set_bool(settings, settings->bools.video_frame_delay_auto, 0); - configuration_set_bool(settings, - settings->bools.vrr_runloop_enable, - 0); configuration_set_uint(settings, settings->uints.video_black_frame_insertion, 0); @@ -8698,9 +8695,6 @@ static void general_write_handler(rarch_setting_t *setting) configuration_set_bool(settings, settings->uints.video_black_frame_insertion, 0); - configuration_set_uint(settings, - settings->uints.video_shader_subframes, - 1); #ifdef HAVE_CHEEVOS rcheevos_validate_config_settings(); #endif From 3ba7d88cea19f11d333efafcf506aef07917996e Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 7 Jan 2025 00:14:59 +0000 Subject: [PATCH 038/574] Fetch translations from Crowdin --- intl/msg_hash_de.h | 4 ++++ intl/msg_hash_es.h | 4 ++++ intl/msg_hash_ko.h | 12 ++++++++++++ intl/progress.h | 6 +++--- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 5e76b0a8a1..35917631dd 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -2469,6 +2469,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Ganzzahlige Skalenachse" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, + "Skaliert entweder Höhe oder Breite oder sowohl Höhe als auch Breite. Halbschritte gelten nur für hochauflösende Quellen." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "Ganzzahlige Skalierung" diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 463d611a5a..df0d0519ca 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -2545,6 +2545,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Ejes del escalado por números enteros" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, + "Escala la altura o la anchura. Los escalados irregulares se aplicarán solo a imágenes en alta resolución." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "Tipo de escalado por números enteros" diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index 5870e121a2..5fb5417905 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -2565,6 +2565,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "정수 단위 조정 기준 축" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, + "화면 크기를 조정할 때 기준을 높이로 할지, 너비로 할지, 높이와 너비 모두로 할지 설정합니다. 절반 단위 조정은 고해상도 영상에만 적용됩니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "정수 단위 조정 방식" @@ -5394,6 +5398,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "전면 버튼이 겹치는 부분의 크기를 조절합니다. 100%로 설정하면 8방향 구역의 크기가 모두 같아집니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "아날로그 중심점 재정의 구역 범위" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "지정한 구역 내에서 터치를 시작할 경우 처음 터치한 위치를 아날로그 스틱 입력의 중심점으로 사용합니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "오버레이" diff --git a/intl/progress.h b/intl/progress.h index c1d8901506..957124f02d 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -31,7 +31,7 @@ #define LANGUAGE_PROGRESS_DANISH_APPROVED 0 /* German */ -#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_GERMAN_APPROVED 14 /* Greek */ @@ -47,7 +47,7 @@ #define LANGUAGE_PROGRESS_ESPERANTO_APPROVED 0 /* Spanish */ -#define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 99 +#define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 100 #define LANGUAGE_PROGRESS_SPANISH_APPROVED 90 /* Persian */ @@ -91,7 +91,7 @@ #define LANGUAGE_PROGRESS_JAPANESE_APPROVED 0 /* Korean */ -#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_KOREAN_APPROVED 0 /* Dutch */ From 8a3f25311b3c04ae7baef616fd0630bc65401d58 Mon Sep 17 00:00:00 2001 From: hizzlekizzle Date: Mon, 6 Jan 2025 18:58:53 -0600 Subject: [PATCH 039/574] partial revert of c09fd38 (#17363) which was causing softpatching to break on games with periods/dots in the filename. This restores the previous patch-matching behavior --- runloop.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/runloop.c b/runloop.c index 80c8891cce..0f34c0bec2 100644 --- a/runloop.c +++ b/runloop.c @@ -4849,28 +4849,44 @@ void runloop_path_fill_names(void) return; if (string_is_empty(runloop_st->name.ups)) - fill_pathname(runloop_st->name.ups, + { + size_t len = strlcpy(runloop_st->name.ups, runloop_st->runtime_content_path_basename, - ".ups", sizeof(runloop_st->name.ups)); + strlcpy(runloop_st->name.ups + len, + ".ups", + sizeof(runloop_st->name.ups) - len); + } if (string_is_empty(runloop_st->name.bps)) - fill_pathname(runloop_st->name.bps, + { + size_t len = strlcpy(runloop_st->name.bps, runloop_st->runtime_content_path_basename, - ".bps", sizeof(runloop_st->name.bps)); + strlcpy(runloop_st->name.bps + len, + ".bps", + sizeof(runloop_st->name.bps) - len); + } if (string_is_empty(runloop_st->name.ips)) - fill_pathname(runloop_st->name.ips, + { + size_t len = strlcpy(runloop_st->name.ips, runloop_st->runtime_content_path_basename, - ".ips", sizeof(runloop_st->name.ips)); + strlcpy(runloop_st->name.ips + len, + ".ips", + sizeof(runloop_st->name.ips) - len); + } if (string_is_empty(runloop_st->name.xdelta)) - fill_pathname(runloop_st->name.xdelta, + { + size_t len = strlcpy(runloop_st->name.xdelta, runloop_st->runtime_content_path_basename, - ".xdelta", sizeof(runloop_st->name.xdelta)); + strlcpy(runloop_st->name.xdelta + len, + ".xdelta", + sizeof(runloop_st->name.xdelta) - len); + } } From 69e8be6dc13676ea5217f3bdddcc2c607853119a Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Mon, 6 Jan 2025 20:03:00 -0500 Subject: [PATCH 040/574] iOS: ensure webserver notice can be dismissed (#17356) --- ui/drivers/cocoa/cocoa_common.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/drivers/cocoa/cocoa_common.m b/ui/drivers/cocoa/cocoa_common.m index c760fdf2d4..20569fa709 100644 --- a/ui/drivers/cocoa/cocoa_common.m +++ b/ui/drivers/cocoa/cocoa_common.m @@ -768,7 +768,6 @@ void cocoa_file_load_with_detect_core(const char *filename); static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Welcome to RetroArch" message:[NSString stringWithFormat:@"To transfer files from your computer, go to one of these addresses on your web browser:\n\n%@",servers] preferredStyle:UIAlertControllerStyleAlert]; -#if TARGET_OS_TV [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { rarch_start_draw_observer(); @@ -778,10 +777,11 @@ void cocoa_file_load_with_detect_core(const char *filename); rarch_start_draw_observer(); configuration_set_bool(settings, settings->bools.gcdwebserver_alert, false); }]]; -#elif TARGET_OS_IOS +#if TARGET_OS_IOS [alert addAction:[UIAlertAction actionWithTitle:@"Stop Server" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [[WebServer sharedInstance] webUploader].delegate = nil; [[WebServer sharedInstance] stopServers]; + rarch_start_draw_observer(); }]]; #endif [self presentViewController:alert animated:YES completion:^{ From a98ab483cb6d70562527c238baba5ab1fb71dfc1 Mon Sep 17 00:00:00 2001 From: LibretroAdmin Date: Tue, 7 Jan 2025 02:22:57 +0100 Subject: [PATCH 041/574] Restore archive_file_7z.c --- libretro-common/file/archive_file_7z.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libretro-common/file/archive_file_7z.c b/libretro-common/file/archive_file_7z.c index cb561062a3..adcb15a3bb 100644 --- a/libretro-common/file/archive_file_7z.c +++ b/libretro-common/file/archive_file_7z.c @@ -414,7 +414,6 @@ error: static int sevenzip_parse_file_iterate_step_internal( struct sevenzip_context_t *sevenzip_context, char *s, - size_t len, const uint8_t **cdata, unsigned *cmode, uint32_t *size, @@ -425,7 +424,7 @@ static int sevenzip_parse_file_iterate_step_internal( { if (sevenzip_context->parse_index < sevenzip_context->db.NumFiles) { - size_t len = SzArEx_GetFileNameUtf16(&sevenzip_context->db, + size_t _len = SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->parse_index, NULL); uint64_t compressed_size = 0; @@ -437,21 +436,24 @@ static int sevenzip_parse_file_iterate_step_internal( sevenzip_context->packIndex++; } - if ( (len < PATH_MAX_LENGTH) + if ( (_len < PATH_MAX_LENGTH) && !SzArEx_IsDir(&sevenzip_context->db, sevenzip_context->parse_index)) { + char infile[PATH_MAX_LENGTH]; SRes res = SZ_ERROR_FAIL; - uint16_t *temp = (uint16_t*)malloc(len * sizeof(uint16_t)); + uint16_t *temp = (uint16_t*)malloc(_len * sizeof(uint16_t)); if (!temp) return -1; + infile[0] = '\0'; + SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->parse_index, temp); if (temp) { - res = utf16_to_char_string(temp, s, len) + res = utf16_to_char_string(temp, infile, sizeof(infile)) ? SZ_OK : SZ_ERROR_FAIL; free(temp); } @@ -459,6 +461,8 @@ static int sevenzip_parse_file_iterate_step_internal( if (res != SZ_OK) return -1; + strlcpy(s, infile, PATH_MAX_LENGTH); + *cmode = 0; /* unused for 7zip */ *checksum = sevenzip_context->db.CRCs.Vals[sevenzip_context->parse_index]; *size = (uint32_t)SzArEx_GetFileSize(&sevenzip_context->db, sevenzip_context->parse_index); @@ -492,7 +496,6 @@ static int sevenzip_parse_file_iterate_step(void *context, ret = sevenzip_parse_file_iterate_step_internal(sevenzip_context, userdata->current_file_path, - sizeof(userdata->current_file_path), &cdata, &cmode, &size, &csize, &checksum, &payload, userdata); From e40f405b97f8f401292c963912256d8d38aaf167 Mon Sep 17 00:00:00 2001 From: LibretroAdmin Date: Tue, 7 Jan 2025 02:47:37 +0100 Subject: [PATCH 042/574] Play it on the safe side - go back to some of the code from before --- tasks/task_content.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tasks/task_content.c b/tasks/task_content.c index dc42c731f1..603e0f3fd3 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -581,8 +581,8 @@ static bool content_file_list_set_info( * searching related content. For archived content, * this is the basename of the archive file without * extension */ - fill_pathname(name, path_basename(archive_path), "", - sizeof(name)); + fill_pathname_base(name, archive_path, sizeof(name)); + path_remove_extension(name); file_info->file_in_archive = true; } @@ -595,8 +595,8 @@ static bool content_file_list_set_info( /* For uncompressed content, 'canonical' name/id * is the basename of the content file, without * extension */ - fill_pathname(name, path_basename(path), "", - sizeof(name)); + fill_pathname_base(name, path, sizeof(name)); + path_remove_extension(name); } if (!string_is_empty(dir)) From fc48ecaa1df4539c63d4b30d26b60299c8cf0772 Mon Sep 17 00:00:00 2001 From: LibretroAdmin Date: Tue, 7 Jan 2025 02:57:24 +0100 Subject: [PATCH 043/574] Local 'len' variables need to prefixed with '_', inner-loop len variables need to be prefixed with '__' --- gfx/common/win32_common.c | 18 +++++++++--------- input/common/wayland_common.c | 4 ++-- libretro-common/formats/json/rjson.c | 17 +++++++++-------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index aa84bd7925..3566d418dc 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -1333,14 +1333,14 @@ static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd, break; for (i = 0; i < len1; i = i + 2) { - size_t len2; + size_t __len; char *utf8 = utf16_to_utf8_string_alloc(wstr+i); if (!utf8) continue; - len2 = strlen(utf8) + 1; - if (len2 >= 1 && len2 <= 3) + __len = strlen(utf8) + 1; + if (__len >= 1 && __len <= 3) { - if (len2 >= 2) + if (__len >= 2) utf8[3] = (gcs) | (gcs >> 4); input_keyboard_event(true, 1, *((int*)utf8), 0, RETRO_DEVICE_KEYBOARD); } @@ -2137,7 +2137,7 @@ static void win32_localize_menu(HMENU menu) if (label_enum != MSG_UNKNOWN) { int len; - size_t len2; + size_t __len; #ifndef LEGACY_WIN32 wchar_t* new_label_unicode = NULL; #else @@ -2156,25 +2156,25 @@ static void win32_localize_menu(HMENU menu) MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST) { meta_key_name = "Ctrl+O"; - len2 = STRLEN_CONST("Ctrl+O"); + __len = STRLEN_CONST("Ctrl+O"); } else if (label_enum == MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY) { meta_key_name = "Alt+Enter"; - len2 = STRLEN_CONST("Alt+Enter"); + __len = STRLEN_CONST("Alt+Enter"); } else if (meta_key != 0) { meta_key_name = win32_meta_key_to_name(meta_key); - len2 = strlen(meta_key_name); + __len = strlen(meta_key_name); } /* Append localized name, tab character, and Shortcut Key */ if (meta_key_name && string_is_not_equal(meta_key_name, "nul")) { size_t len1 = strlen(new_label); - size_t buf_size = len1 + len2 + 2; + size_t buf_size = len1 + __len + 2; new_label_text = (char*)malloc(buf_size); if (new_label_text) diff --git a/input/common/wayland_common.c b/input/common/wayland_common.c index 9f5d273735..0be0406c32 100644 --- a/input/common/wayland_common.c +++ b/input/common/wayland_common.c @@ -997,7 +997,7 @@ static void wl_data_device_handle_drop(void *data, int pipefd[2]; void *buffer; size_t length; - size_t len = 0; + size_t _len = 0; ssize_t read = 0; char *line = NULL; char file_list[512][512] = { 0 }; @@ -1030,7 +1030,7 @@ static void wl_data_device_handle_drop(void *data, } RARCH_WARN("[Wayland]: Files opp:\n"); - while ((read = getline(&line, &len, stream)) != -1) + while ((read = getline(&line, &_len, stream)) != -1) { line[strcspn(line, "\r\n")] = 0; RARCH_DBG("[Wayland]: > \"%s\"\n", line); diff --git a/libretro-common/formats/json/rjson.c b/libretro-common/formats/json/rjson.c index 07fcf25814..bb3eaf346c 100644 --- a/libretro-common/formats/json/rjson.c +++ b/libretro-common/formats/json/rjson.c @@ -163,14 +163,15 @@ static INLINE bool _rjson_pushchar(rjson_t *json, _rjson_char_t c) static INLINE bool _rjson_pushchars(rjson_t *json, const unsigned char *from, const unsigned char *to) { - size_t len = json->string_len, new_len = len + (to - from); unsigned char* string; + size_t _len = json->string_len; + size_t new_len = _len + (to - from); while (new_len >= json->string_cap) if (!_rjson_grow_string(json)) return false; string = (unsigned char *)json->string; - while (len != new_len) - string[len++] = *(from++); + while (_len != new_len) + string[_len++] = *(from++); json->string_len = new_len; return true; } @@ -1126,7 +1127,7 @@ enum rjson_type rjson_parse(rjson_t *json, void* context, bool (*null_handler )(void *context)) { bool in_object = false; - size_t len; + size_t _len; const char* string; if (!object_member_handler) object_member_handler = _rjson_nop_string; if (!string_handler ) string_handler = _rjson_nop_string; @@ -1142,16 +1143,16 @@ enum rjson_type rjson_parse(rjson_t *json, void* context, switch (rjson_next(json)) { case RJSON_STRING: - string = rjson_get_string(json, &len); + string = rjson_get_string(json, &_len); if (_rJSON_LIKELY( (in_object && (json->stack_top->count & 1) ? object_member_handler : string_handler) - (context, string, len))) + (context, string, _len))) continue; return RJSON_STRING; case RJSON_NUMBER: - string = rjson_get_string(json, &len); - if (_rJSON_LIKELY(number_handler(context, string, len))) + string = rjson_get_string(json, &_len); + if (_rJSON_LIKELY(number_handler(context, string, _len))) continue; return RJSON_NUMBER; case RJSON_OBJECT: From 839b7654dbf0fe75e1d6ffbac84f9b2ee79b51b5 Mon Sep 17 00:00:00 2001 From: LibretroAdmin Date: Tue, 7 Jan 2025 03:20:39 +0100 Subject: [PATCH 044/574] More standardization of local len variables --- frontend/drivers/platform_darwin.m | 8 +++---- frontend/drivers/platform_dos.c | 6 +++--- frontend/drivers/platform_unix.c | 6 +++--- gfx/common/win32_common.c | 34 ++++++++++++++++-------------- gfx/common/x11_common.c | 8 +++---- gfx/drivers_context/osmesa_ctx.c | 4 ++-- 6 files changed, 34 insertions(+), 32 deletions(-) diff --git a/frontend/drivers/platform_darwin.m b/frontend/drivers/platform_darwin.m index 0e2cd1bcc9..e27c38fccc 100644 --- a/frontend/drivers/platform_darwin.m +++ b/frontend/drivers/platform_darwin.m @@ -273,10 +273,10 @@ static void frontend_darwin_get_name(char *s, size_t len) if (uname(&buffer) == 0) strlcpy(s, buffer.machine, len); #elif defined(OSX) - size_t length = 0; - sysctlbyname("hw.model", NULL, &length, NULL, 0); - if (length) - sysctlbyname("hw.model", s, &length, NULL, 0); + size_t _len = 0; + sysctlbyname("hw.model", NULL, &_len, NULL, 0); + if (_len) + sysctlbyname("hw.model", s, &_len, NULL, 0); #endif } diff --git a/frontend/drivers/platform_dos.c b/frontend/drivers/platform_dos.c index 17d3541f64..fd2c5b06d8 100644 --- a/frontend/drivers/platform_dos.c +++ b/frontend/drivers/platform_dos.c @@ -107,11 +107,11 @@ static void frontend_dos_get_env_settings(int *argc, char *argv[], static void frontend_dos_exec(const char *path, bool should_load_game) { char *newargv[] = { NULL, NULL }; - size_t len = strlen(path); + size_t _len = strlen(path); - newargv[0] = (char*)malloc(len); + newargv[0] = (char*)malloc(_len); - strlcpy(newargv[0], path, len); + strlcpy(newargv[0], path, _len); execv(path, newargv); } diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index 778f54eeda..9cd870655e 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -2353,11 +2353,11 @@ static bool frontend_unix_set_fork(enum frontend_fork fork_mode) static void frontend_unix_exec(const char *path, bool should_load_content) { char *newargv[] = { NULL, NULL }; - size_t len = strlen(path); + size_t _len = strlen(path); - newargv[0] = (char*)malloc(len); + newargv[0] = (char*)malloc(_len); - strlcpy(newargv[0], path, len); + strlcpy(newargv[0], path, _len); execv(path, newargv); } diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index 3566d418dc..4291d4e25f 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -1325,13 +1325,13 @@ static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd, if (gcs) { int i; - wchar_t wstr[4]={0,}; - int len1 = ImmGetCompositionStringW(hIMC, gcs, wstr, 4); - wstr[2] = wstr[1]; - wstr[1] = 0; - if ((len1 <= 0) || (len1 > 4)) + wchar_t wstr[4] = {0,}; + LONG _len = ImmGetCompositionStringW(hIMC, gcs, wstr, 4); + wstr[2] = wstr[1]; + wstr[1] = 0; + if ((_len <= 0) || (_len > 4)) break; - for (i = 0; i < len1; i = i + 2) + for (i = 0; i < _len; i = i + 2) { size_t __len; char *utf8 = utf16_to_utf8_string_alloc(wstr+i); @@ -1373,8 +1373,10 @@ static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd, keysym |= 0x80; /* tell the driver about shift and alt key events */ - if (keysym == 0x2A/*DIK_LSHIFT*/ || keysym == 0x36/*DIK_RSHIFT*/ - || keysym == 0x38/*DIK_LMENU*/ || keysym == 0xB8/*DIK_RMENU*/) + if ( keysym == 0x2A/*DIK_LSHIFT*/ + || keysym == 0x36/*DIK_RSHIFT*/ + || keysym == 0x38/*DIK_LMENU*/ + || keysym == 0xB8/*DIK_RMENU*/) { void* input_data = (void*)(LONG_PTR)GetWindowLongPtr(main_window.hwnd, GWLP_USERDATA); if (input_data && dinput_handle_message(input_data, @@ -2173,21 +2175,21 @@ static void win32_localize_menu(HMENU menu) /* Append localized name, tab character, and Shortcut Key */ if (meta_key_name && string_is_not_equal(meta_key_name, "nul")) { - size_t len1 = strlen(new_label); - size_t buf_size = len1 + __len + 2; + size_t _len = strlen(new_label); + size_t buf_size = _len + __len + 2; new_label_text = (char*)malloc(buf_size); if (new_label_text) { - size_t _len; + size_t __len; new_label2 = new_label_text; - _len = strlcpy(new_label_text, new_label, + __len = strlcpy(new_label_text, new_label, buf_size); - new_label_text[ _len] = '\t'; - new_label_text[++_len] = '\0'; - strlcpy(new_label_text + _len, meta_key_name, buf_size - _len); + new_label_text[ __len] = '\t'; + new_label_text[++__len] = '\0'; + strlcpy(new_label_text + __len, meta_key_name, buf_size - __len); /* Make first character of shortcut name uppercase */ - new_label_text[len1 + 1] = toupper(new_label_text[len1 + 1]); + new_label_text[_len + 1] = toupper(new_label_text[_len + 1]); } } diff --git a/gfx/common/x11_common.c b/gfx/common/x11_common.c index 8a7cc783d6..36efb980be 100644 --- a/gfx/common/x11_common.c +++ b/gfx/common/x11_common.c @@ -813,13 +813,13 @@ bool x11_connect(void) void x11_update_title(void *data) { - size_t len; + size_t _len; char title[128]; - title[0] = '\0'; - len = video_driver_get_window_title(title, sizeof(title)); + title[0] = '\0'; + _len = video_driver_get_window_title(title, sizeof(title)); if (title[0]) XChangeProperty(g_x11_dpy, g_x11_win, XA_WM_NAME, XA_STRING, - 8, PropModeReplace, (const unsigned char*)title, len); + 8, PropModeReplace, (const unsigned char*)title, _len); } bool x11_input_ctx_new(bool true_full) diff --git a/gfx/drivers_context/osmesa_ctx.c b/gfx/drivers_context/osmesa_ctx.c index 77101436f2..5d5b2ab687 100644 --- a/gfx/drivers_context/osmesa_ctx.c +++ b/gfx/drivers_context/osmesa_ctx.c @@ -122,14 +122,14 @@ static void osmesa_fifo_accept(gfx_ctx_osmesa_data_t *osmesa) static void osmesa_fifo_write(gfx_ctx_osmesa_data_t *osmesa) { int i; - size_t len = osmesa->width * osmesa->pixsize; + size_t _len = osmesa->width * osmesa->pixsize; if (osmesa->client < 0) return; for (i = osmesa->height -1; i >= 0; --i) { - int res = send(osmesa->client, osmesa->screen + i * len, len, MSG_NOSIGNAL); + int res = send(osmesa->client, osmesa->screen + i * _len, _len, MSG_NOSIGNAL); if (res < 0) { From 65b9b1cd255fbf9358fa131f36505c59c87ff1b7 Mon Sep 17 00:00:00 2001 From: zoltanvb <101990835+zoltanvb@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:42:25 +0100 Subject: [PATCH 045/574] Fix compile failure (#17366) --- gfx/drivers/vg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gfx/drivers/vg.c b/gfx/drivers/vg.c index 30f0c90e9d..e63ec7cf55 100644 --- a/gfx/drivers/vg.c +++ b/gfx/drivers/vg.c @@ -318,10 +318,10 @@ static void vg_free(void *data) static void vg_calculate_quad(vg_t *vg, unsigned vp_width, unsigned vp_height) { - struct video_viewport_t vp; + video_viewport_t vp; settings_t *settings = config_get_ptr(); bool video_scale_integer = settings->bools.video_scale_integer; - float device_aspect = (float)width / height; + float device_aspect = (float)vp_width / vp_height; vp.x = 0; vp.y = 0; From 9886944f32b7d6e964706c32d0ba5fd48f8903e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Via=C4=8Das=C5=82a=C5=AD?= Date: Tue, 7 Jan 2025 20:31:45 +0300 Subject: [PATCH 046/574] Fix launch app when pipewire service is stopped (#17365) --- audio/common/pipewire.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/audio/common/pipewire.c b/audio/common/pipewire.c index be05b221bf..3dcf25460d 100644 --- a/audio/common/pipewire.c +++ b/audio/common/pipewire.c @@ -162,13 +162,17 @@ bool pipewire_core_init(pipewire_core_t *pw, const char *loop_name) pw_thread_loop_lock(pw->thread_loop); pw->core = pw_context_connect(pw->ctx, NULL, 0); - if(!pw->core) - return false; + if (!pw->core) + goto unlock; if (pw_core_add_listener(pw->core, &pw->core_listener, &core_events, pw) < 0) - return false; + goto unlock; return true; + +unlock: + pw_thread_loop_unlock(pw->thread_loop); + return false; } From 941806698e23713c1cd95185b896afe65f96b71e Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Wed, 8 Jan 2025 18:09:56 -0500 Subject: [PATCH 047/574] Add SSL Support to the information list (#17370) --- config.features.h | 6 ++++++ intl/msg_hash_us.h | 4 ++++ menu/menu_displaylist.c | 3 +++ msg_hash.h | 1 + retroarch.c | 3 +++ 5 files changed, 17 insertions(+) diff --git a/config.features.h b/config.features.h index b0f36bd706..8961c58e66 100644 --- a/config.features.h +++ b/config.features.h @@ -350,6 +350,12 @@ #define SUPPORTS_NETPLAY false #endif +#ifdef HAVE_SSL +#define SUPPORTS_SSL true +#else +#define SUPPORTS_SSL false +#endif + #if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) #define SUPPORTS_COCOA true #else diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 22555d8ba3..0266369fd8 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -918,6 +918,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 Support" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL Support" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb Support" diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 2a7db944af..adb5441356 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -2409,6 +2409,9 @@ static unsigned menu_displaylist_parse_system_info(file_list_t *list) #ifdef HAVE_NETWORKING {SUPPORTS_NETPLAY , MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT}, #endif +#ifdef HAVE_SSL + {SUPPORTS_SSL , MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT}, +#endif #ifdef HAVE_V4L2 {SUPPORTS_V4L2 , MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT}, #endif diff --git a/msg_hash.h b/msg_hash.h index bc9404d5aa..4eaf9aac66 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -3557,6 +3557,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_STB_TRUETYPE_SUPPORT, MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, diff --git a/retroarch.c b/retroarch.c index a7e5f5299f..e4f4b94beb 100644 --- a/retroarch.c +++ b/retroarch.c @@ -6212,6 +6212,9 @@ static void retroarch_print_features(void) #ifdef HAVE_NETWORKING _len += _PSUPP_BUF(buf, _len, SUPPORTS_NETPLAY, "Netplay", "Peer-to-peer netplay"); #endif +#ifdef HAVE_SSL + _len += _PSUPP_BUF(buf, _len, SUPPORTS_SSL, "SSL", "SSL Support"); +#endif #ifdef HAVE_LIBUSB _len += _PSUPP_BUF(buf, _len, SUPPORTS_LIBUSB, "Libusb", "Libusb support"); #endif From 74e7a62e911adb9a7645e7090c4e21e41244653d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 9 Jan 2025 00:14:07 +0000 Subject: [PATCH 048/574] Fetch translations from Crowdin --- intl/progress.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/intl/progress.h b/intl/progress.h index 957124f02d..d27dae83ab 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -7,7 +7,7 @@ #define LANGUAGE_PROGRESS_ASTURIAN_APPROVED 9 /* Belarusian */ -#define LANGUAGE_PROGRESS_BELARUSIAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_BELARUSIAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_BELARUSIAN_APPROVED 0 /* Bulgarian */ @@ -31,7 +31,7 @@ #define LANGUAGE_PROGRESS_DANISH_APPROVED 0 /* German */ -#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_GERMAN_APPROVED 14 /* Greek */ @@ -43,11 +43,11 @@ #define LANGUAGE_PROGRESS_ENGLISH_UNITED_KINGDOM_APPROVED 0 /* Esperanto */ -#define LANGUAGE_PROGRESS_ESPERANTO_TRANSLATED 3 +#define LANGUAGE_PROGRESS_ESPERANTO_TRANSLATED 2 #define LANGUAGE_PROGRESS_ESPERANTO_APPROVED 0 /* Spanish */ -#define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 100 +#define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 99 #define LANGUAGE_PROGRESS_SPANISH_APPROVED 90 /* Persian */ @@ -59,8 +59,8 @@ #define LANGUAGE_PROGRESS_FINNISH_APPROVED 46 /* French */ -#define LANGUAGE_PROGRESS_FRENCH_TRANSLATED 100 -#define LANGUAGE_PROGRESS_FRENCH_APPROVED 100 +#define LANGUAGE_PROGRESS_FRENCH_TRANSLATED 99 +#define LANGUAGE_PROGRESS_FRENCH_APPROVED 99 /* Galician */ #define LANGUAGE_PROGRESS_GALICIAN_TRANSLATED 99 @@ -83,7 +83,7 @@ #define LANGUAGE_PROGRESS_INDONESIAN_APPROVED 0 /* Italian */ -#define LANGUAGE_PROGRESS_ITALIAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_ITALIAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_ITALIAN_APPROVED 0 /* Japanese */ @@ -91,7 +91,7 @@ #define LANGUAGE_PROGRESS_JAPANESE_APPROVED 0 /* Korean */ -#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_KOREAN_APPROVED 0 /* Dutch */ @@ -119,7 +119,7 @@ #define LANGUAGE_PROGRESS_PORTUGUESE_APPROVED 0 /* Russian */ -#define LANGUAGE_PROGRESS_RUSSIAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_RUSSIAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_RUSSIAN_APPROVED 13 /* Slovak */ @@ -135,15 +135,15 @@ #define LANGUAGE_PROGRESS_SWEDISH_APPROVED 47 /* Turkish */ -#define LANGUAGE_PROGRESS_TURKISH_TRANSLATED 100 -#define LANGUAGE_PROGRESS_TURKISH_APPROVED 100 +#define LANGUAGE_PROGRESS_TURKISH_TRANSLATED 99 +#define LANGUAGE_PROGRESS_TURKISH_APPROVED 99 /* Tatar */ #define LANGUAGE_PROGRESS_TATAR_TRANSLATED 0 #define LANGUAGE_PROGRESS_TATAR_APPROVED 0 /* Ukrainian */ -#define LANGUAGE_PROGRESS_UKRAINIAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_UKRAINIAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_UKRAINIAN_APPROVED 7 /* Valencian */ From 6f495dea0433e5298435d88dfd74d3afa45545af Mon Sep 17 00:00:00 2001 From: zoltanvb <101990835+zoltanvb@users.noreply.github.com> Date: Thu, 9 Jan 2025 20:29:15 +0100 Subject: [PATCH 049/574] Replace upload-artifact v3 with v4 (#17378) --- .github/workflows/Android.yml | 2 +- .github/workflows/DOS-DJGPP.yml | 2 +- .github/workflows/MacOS.yml | 2 +- .github/workflows/Miyoo.yml | 2 +- .github/workflows/PS2.yml | 2 +- .github/workflows/PS4-ORBIS.yml | 2 +- .github/workflows/PSP.yml | 2 +- .github/workflows/PSVita.yml | 2 +- .github/workflows/RS90.yml | 2 +- .github/workflows/RetroFW.yml | 2 +- .github/workflows/Switch-libnx.yml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/Android.yml b/.github/workflows/Android.yml index da68bb12d8..dbb0d7ee67 100644 --- a/.github/workflows/Android.yml +++ b/.github/workflows/Android.yml @@ -30,7 +30,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: retroarch-android-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/DOS-DJGPP.yml b/.github/workflows/DOS-DJGPP.yml index d144a2f108..6f5595ce05 100644 --- a/.github/workflows/DOS-DJGPP.yml +++ b/.github/workflows/DOS-DJGPP.yml @@ -31,7 +31,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-DOS-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index 37e6026ee7..10ab355ec3 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -26,7 +26,7 @@ jobs: id: slug run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RetroArch-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/Miyoo.yml b/.github/workflows/Miyoo.yml index 2a7556ba1a..de6018a50a 100644 --- a/.github/workflows/Miyoo.yml +++ b/.github/workflows/Miyoo.yml @@ -31,7 +31,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: retroarch_miyoo_arm32${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/PS2.yml b/.github/workflows/PS2.yml index eba2153e8a..4e60d718f0 100644 --- a/.github/workflows/PS2.yml +++ b/.github/workflows/PS2.yml @@ -36,7 +36,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-PS2-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/PS4-ORBIS.yml b/.github/workflows/PS4-ORBIS.yml index 60773e9bc0..2296eed6d0 100644 --- a/.github/workflows/PS4-ORBIS.yml +++ b/.github/workflows/PS4-ORBIS.yml @@ -37,7 +37,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: bin-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/PSP.yml b/.github/workflows/PSP.yml index d1b3a9b06a..2ae652d0d6 100644 --- a/.github/workflows/PSP.yml +++ b/.github/workflows/PSP.yml @@ -42,7 +42,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-PSP-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/PSVita.yml b/.github/workflows/PSVita.yml index 9be7c3dbfe..87e5933e9e 100644 --- a/.github/workflows/PSVita.yml +++ b/.github/workflows/PSVita.yml @@ -35,7 +35,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-PSVita-dummy-${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/RS90.yml b/.github/workflows/RS90.yml index 1fea310bdf..34332c5ce0 100644 --- a/.github/workflows/RS90.yml +++ b/.github/workflows/RS90.yml @@ -31,7 +31,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: retroarch_rs90_mips32${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/RetroFW.yml b/.github/workflows/RetroFW.yml index 24ec76f2ba..cb57960e1d 100644 --- a/.github/workflows/RetroFW.yml +++ b/.github/workflows/RetroFW.yml @@ -31,7 +31,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: retroarch_retrofw_mips32${{ steps.slug.outputs.sha8 }} path: | diff --git a/.github/workflows/Switch-libnx.yml b/.github/workflows/Switch-libnx.yml index 75a25054f8..df26e01f19 100644 --- a/.github/workflows/Switch-libnx.yml +++ b/.github/workflows/Switch-libnx.yml @@ -30,7 +30,7 @@ jobs: id: slug run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: RA-libnx-dummy-${{ steps.slug.outputs.sha8 }} path: | From 2c57a35055ee805ca1011a8080547172720e834e Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 10 Jan 2025 00:15:03 +0000 Subject: [PATCH 050/574] Fetch translations from Crowdin --- intl/msg_hash_be.h | 4 + intl/msg_hash_de.h | 4 + intl/msg_hash_es.h | 4 + intl/msg_hash_fr.h | 4 + intl/msg_hash_ko.h | 4 + intl/msg_hash_pl.h | 4 + intl/msg_hash_pt_br.h | 8 + intl/msg_hash_ru.h | 4 + intl/msg_hash_sv.h | 380 ++++++++++++++++++++++++++++++++++++++++++ intl/msg_hash_tr.h | 4 + intl/progress.h | 20 +-- 11 files changed, 430 insertions(+), 10 deletions(-) diff --git a/intl/msg_hash_be.h b/intl/msg_hash_be.h index 303742356c..72c3218b7a 100644 --- a/intl/msg_hash_be.h +++ b/intl/msg_hash_be.h @@ -914,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Падтрымка Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Падтрымка SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Падтрымка libusb" diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 35917631dd..ea3fb07a31 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -890,6 +890,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2-Unterstützung" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL-Unterstützung" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb-Unterstützung" diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index df0d0519ca..75bbd10c0c 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -910,6 +910,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Soporte de Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Soporte de SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Soporte de libusb" diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index 090edc500b..3354e36baf 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -906,6 +906,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Prise en charge de Video4Linux2 " ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Prise en charge de SSL " + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Prise en charge de Libusb " diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index 5fb5417905..c265bcf884 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -914,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 지원" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL 지원" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Libusb 지원" diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index 2d576ff01e..28765d046c 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -910,6 +910,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Obsługa Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Wsparcie SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Obsługa libusb" diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 20e36cf6be..b514609d0e 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -806,6 +806,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "Suporte ao PulseAudio" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "Suporte ao PipeWire" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "Suporte ao CoreAudio" @@ -886,6 +890,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Suporte ao Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Suporte ao SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Suporte ao libusb" diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 022ce3dbfa..528e22e9b3 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -914,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Поддержка Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Поддержка SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Поддержка libusb" diff --git a/intl/msg_hash_sv.h b/intl/msg_hash_sv.h index 5f996ad58f..5fd0850100 100644 --- a/intl/msg_hash_sv.h +++ b/intl/msg_hash_sv.h @@ -702,6 +702,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "SDL 2-stöd" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Direct3D 8-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Direct3D 9-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Direct3D 10-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Direct3D 11-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Direct3D 12-stöd" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "GDI-stöd" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Vulkan-stöd" @@ -782,6 +806,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "PulseAudio-stöd" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "PipeWire-stöd" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "CoreAudio-stöd" @@ -862,6 +890,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2-stöd" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL-stöd" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb-stöd" @@ -4479,6 +4511,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_SPEED, "Mushastighet" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG, + "Långt tryck för att dra" + ) /* Settings > On-Screen Display > Video Layout */ @@ -4768,6 +4804,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, "Ändra inställningar för menyskärmens utseende." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_APPICON_SETTINGS, + "Programikon" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_APPICON_SETTINGS, + "Ändra programikon." + ) #ifdef _3DS MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_BOTTOM_SETTINGS, @@ -5095,6 +5139,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_PLAYLISTS, "Visa 'Spellistor'" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_SHOW_PLAYLISTS, + "Visa spellistor. (Omstart krävs på Ozone/XMB)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_EXPLORE, "Visa 'Utforska'" @@ -5314,6 +5362,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, "Visa alternativet 'Lägg till i favoriter'." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_ADD_TO_PLAYLIST, + "Visa 'Lägg till i spellista'" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_SET_CORE_ASSOCIATION, "Visa 'Ställ in kärnassociation'" @@ -5833,6 +5885,10 @@ MSG_HASH( /* Settings > Network */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, + "Använd reläserver" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_MITM_SERVER_LOCATION_1, "Nordamerika (östkusten, USA)" @@ -6234,6 +6290,10 @@ MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, "Filhanterare" ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Ställ in startkatalog för filbläddraren." + ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, "Konfigurationsfiler" @@ -6314,10 +6374,18 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OSK_OVERLAY_DIRECTORY, "Tangentbordsöverlager lagras i denna katalog." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_DIRECTORY, + "Videolayouter" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, "Skärmdumpar" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, + "Skärmbilder lagras i denna katalog." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, "Spelkontrollsprofiler" @@ -7023,6 +7091,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Fusk" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, + "Konfigurera fuskkoder." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, "Skivhantering" @@ -7123,6 +7195,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, "Läs in en fuskfil och ersätt befintliga fusk." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND, + "Läs in fuskfil (lägg till)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, "Spara fuskfil som" @@ -7457,6 +7533,22 @@ MSG_HASH( /* Quick Menu > Shaders > Remove */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_GLOBAL, + "Ta bort globalt förval" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_CORE, + "Ta bort kärnförval" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_PARENT, + "Ta bort förval för innehållskatalog" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_GAME, + "Ta bort spelförval" + ) /* Quick Menu > Shaders > Shader Parameters */ @@ -7487,6 +7579,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OVERRIDE_FILE_SAVE_AS, "Spara aktuell konfiguration som en ny åsidosättningsfil." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OVERRIDE_UNLOAD, + "Läs ur åsidosättning" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERRIDE_UNLOAD, + "Nollställ alla alternativ till globala konfigurationsvärden." + ) /* Quick Menu > Achievements */ @@ -7671,6 +7771,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NONE, "Ingen" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_SHARE_NO_PREFERENCE, + "Ingen inställning" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_TICKER_TYPE_BOUNCE, "Studsa vänster/höger" @@ -7887,6 +7991,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, "Titelskärm" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_LOGOS, + "Innehållslogotyp" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCROLL_FAST, "Snabb" @@ -8597,6 +8705,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_SWITCH_ICONS, "Använd ikoner istället för PÅ/AV-text för att representera 'omkopplare' menyinställningar." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MATERIALUI_PLAYLIST_ICONS_ENABLE, + "Spellistikoner (omstart krävs)" + ) MSG_HASH( MENU_ENUM_SUBLABEL_MATERIALUI_PLAYLIST_ICONS_ENABLE, "Visa systemspecifika ikoner i spellistorna." @@ -8823,6 +8935,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_LOAD_CORE, "&Ladda Kärna..." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_UNLOAD_CORE, + "Läs &ur kärna" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_FILE_EXIT, "&Avsluta" @@ -8859,6 +8975,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY, "Kom ihåg fönstergeometri:" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB, + "Kom ihåg senaste filk i innehållsbläddraren:" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME, "Tema:" @@ -8939,6 +9059,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, "Titelskärm" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_LOGO, + "Logotyp" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, "Alla spellistor" @@ -9147,6 +9271,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_DELETE, "Radera" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_ADD_ENTRY, + "Lägg till post..." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ADD_FILES, "Lägg till fil(er)..." @@ -9167,6 +9295,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_SELECT_FOLDER, "Välj mapp" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE, + "" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_PLEASE_FILL_OUT_REQUIRED_FIELDS, "Fyll i alla nödvändiga fält." @@ -9175,6 +9307,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_NIGHTLY, "Uppdatera RetroArch (nightly)" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FINISHED, + "RetroArch uppdaterades. Starta om programmet för att ändringarna ska ta effekt." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_UPDATE_RETROARCH_FAILED, "Uppdateringen misslyckades." @@ -9258,6 +9394,10 @@ MSG_HASH( /* Unsorted */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, + "Inställningar för kärnuppdateraren" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NO_DISK, "Ingen skiva vald" @@ -9405,6 +9545,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, "Inspelning-stöd" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_PATH, + "Spara utdatainspelning som..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, + "Spara inspelningar i utdatakatalog" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_MATCH_IDX, "Visa träff #" @@ -9429,6 +9577,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_VIEW_MATCHES, "Visa listan över %u träffar" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_CREATE_OPTION, + "Skapa kod från denna matchning" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_OPTION, + "Ta bort denna matchning" + ) MSG_HASH( /* FIXME Still exists in a comment about being removed */ MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, "Sidfots opacitet" @@ -9501,6 +9657,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, "Beskrivning" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_START_SEARCH, + "Starta sökning efter ny fuskkod" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_START_SEARCH, + "Starta sökning efter ett nytt fusk. Antal bitar kan ändras." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_CONTINUE_SEARCH, "Fortsätt sök" @@ -9517,10 +9681,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_DETAILS, "Fuskdetaljer" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_DETAILS, + "Hanterar inställningar för fuskdetaljer." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_SEARCH, "Starta eller fortsätt fusksökning" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_META_CHEAT_SEARCH, + "Starta eller fortsätt en sökning efter fuskkoder." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, + "Öka eller minska antalet fusk." + ) /* Unused (Needs Confirmation) */ @@ -9638,6 +9814,14 @@ MSG_HASH( MSG_NETPLAY_NEED_CONTENT_LOADED, "Innehållet måste läsas in innan netplay kan startas." ) +MSG_HASH( /* FIXME Should be MSG_ */ + MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, + "Kunde inte hitta en lämplig kärna eller innehållsfil, läs in manuellt." + ) +MSG_HASH( /* FIXME Should be MSG_ */ + MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER_FALLBACK, + "Din grafikdrivrutin är inte kompatibel med aktuella videodrivrutinen i RetroArch, faller tillbaka på drivrutinen %s. Starta om RetroArch för att ändringen ska ta effekt." + ) MSG_HASH( /* FIXME Should be MSG_ */ MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_SUCCESS, "Kärninstallation lyckad" @@ -9674,6 +9858,10 @@ MSG_HASH( MSG_NATIVE, "Inbyggd" ) +MSG_HASH( + MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, + "Okänt netplay-kommando togs emot" + ) MSG_HASH( MSG_GOT_CONNECTION_FROM, "Fick anslutning från: \"%s\"" @@ -9682,6 +9870,10 @@ MSG_HASH( MSG_GOT_CONNECTION_FROM_NAME, "Fick anslutning från: \"%s (%s)\"" ) +MSG_HASH( + MSG_PRIVATE_OR_SHARED_ADDRESS, + "Externt nätverk har en privat eller delad adress. Överväg att använda en reläserver." + ) MSG_HASH( MSG_WAITING_FOR_CLIENT, "Väntar på klient..." @@ -9891,6 +10083,14 @@ MSG_HASH( MSG_PLAYLIST_MANAGER_PLAYLIST_CLEANED, "Spellista rensad: " ) +MSG_HASH( + MSG_PLAYLIST_MANAGER_REFRESH_INVALID_SYSTEM_NAME, + "Uppdatering misslyckades - ogiltigt/saknat systemnamn: " + ) +MSG_HASH( + MSG_PLAYLIST_MANAGER_REFRESH_INVALID_CORE, + "Uppdatering misslyckades - ogiltig kärna: " + ) MSG_HASH( MSG_ADDED_TO_FAVORITES, "Tillagd i favoriter" @@ -9903,6 +10103,18 @@ MSG_HASH( MSG_ADDED_TO_PLAYLIST, "Lades till i spellistan" ) +MSG_HASH( + MSG_ADD_TO_PLAYLIST_FAILED, + "Misslyckades med att lägga till i spellista: spellistan är full" + ) +MSG_HASH( + MSG_SET_CORE_ASSOCIATION, + "Kärnuppsättning: " + ) +MSG_HASH( + MSG_APPENDED_DISK, + "Lade till skivan på slutet" + ) MSG_HASH( MSG_FAILED_TO_APPEND_DISK, "Misslyckades med att lägga till skivan" @@ -9911,6 +10123,10 @@ MSG_HASH( MSG_APPLICATION_DIR, "Programkatalog" ) +MSG_HASH( + MSG_APPLYING_CHEAT, + "Tillämpar fuskändringar." + ) MSG_HASH( MSG_APPLYING_PATCH, "Tillämpar patch: %s" @@ -9931,14 +10147,26 @@ MSG_HASH( MSG_AUTOCONFIG_FILE_ERROR_SAVING, "Fel vid sparande av handkontrollerprofil." ) +MSG_HASH( + MSG_AUTOSAVE_FAILED, + "Kunde inte initiera automatisk sparning." + ) MSG_HASH( MSG_AUTO_SAVE_STATE_TO, "Spara status automatiskt till" ) +MSG_HASH( + MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, + "Tar upp kommandogränssnitt på port" + ) MSG_HASH( MSG_COMPILED_AGAINST_API, "Kompilerad mot API" ) +MSG_HASH( + MSG_CONFIG_DIRECTORY_NOT_SET, + "Konfigurationskatalog inte inställd. Kan inte spara ny konfiguration." + ) MSG_HASH( MSG_CONNECTED_TO, "Ansluten till" @@ -9947,6 +10175,10 @@ MSG_HASH( MSG_CONTENT_NETPACKET_CRC32S_DIFFER, "Värden kör ett annat spel." ) +MSG_HASH( + MSG_PING_TOO_HIGH, + "Din pingtid är för hög för denna värd." + ) MSG_HASH( MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, "Kärnan har inget stöd för Spara Statusar." @@ -9967,6 +10199,10 @@ MSG_HASH( MSG_COULD_NOT_OPEN_DATA_TRACK, "Kunde inte öppna dataspåret" ) +MSG_HASH( + MSG_COULD_NOT_READ_CONTENT_FILE, + "Kunde inte läsa innehållsfilen" + ) MSG_HASH( MSG_DECOMPRESSION_FAILED, "Dekomprimeringen misslyckades." @@ -9983,10 +10219,26 @@ MSG_HASH( MSG_ERROR, "Fel" ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, + "Libretros kärna kräver innehåll men ingenting tillhandahölls." + ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, + "Libretros kärna kräver speciellt innehåll men ingenting tillhandahölls." + ) +MSG_HASH( + MSG_ERROR_LIBRETRO_CORE_REQUIRES_VFS, + "Kärnan har inte stöd för VFS och inläsning från lokal kopia misslyckades" + ) MSG_HASH( MSG_ERROR_PARSING_ARGUMENTS, "Fel vid tolkning av argument." ) +MSG_HASH( + MSG_EXTERNAL_APPLICATION_DIR, + "Extern programkatalog" + ) MSG_HASH( MSG_EXTRACTING, "Extraherar" @@ -10015,6 +10267,10 @@ MSG_HASH( MSG_FAILED_TO_APPLY_SHADER_PRESET, "Misslyckades med att tillämpa shader förinställning:" ) +MSG_HASH( + MSG_FAILED_TO_BIND_SOCKET, + "Misslyckades med att binda uttag." + ) MSG_HASH( MSG_FAILED_TO_CREATE_THE_DIRECTORY, "Misslyckades med att skapa katalogen." @@ -10023,6 +10279,10 @@ MSG_HASH( MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, "Misslyckades med att extrahera innehåll från komprimerad fil" ) +MSG_HASH( + MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, + "Misslyckades med att få smeknamn från klient." + ) MSG_HASH( MSG_FAILED_TO_LOAD, "Misslyckades att ladda" @@ -10147,6 +10407,22 @@ MSG_HASH( MSG_INPUT_CHEAT, "Mata in fusk" ) +MSG_HASH( + MSG_INPUT_CHEAT_FILENAME, + "Filnamn för inmatningsfusk" + ) +MSG_HASH( + MSG_INPUT_PRESET_FILENAME, + "Filnamn för inmatningsförval" + ) +MSG_HASH( + MSG_INPUT_OVERRIDE_FILENAME, + "Filnamn för inmatningsåsidosättning" + ) +MSG_HASH( + MSG_INPUT_REMAP_FILENAME, + "Filnamn för inmatningsommappning" + ) MSG_HASH( MSG_INPUT_RENAME_ENTRY, "Döp om titel" @@ -10187,6 +10463,10 @@ MSG_HASH( MSG_LIBRETRO_FRONTEND, "Frontend för libretro" ) +MSG_HASH( + MSG_LOADED_STATE_FROM_SLOT, + "Läste in tillstånd från plats #%d." + ) MSG_HASH( MSG_LOADING, "Laddar" @@ -10259,6 +10539,10 @@ MSG_HASH( MSG_REDIRECTING_SAVESTATE_TO, "Omdirigerar sparad status till" ) +MSG_HASH( + MSG_REMOVING_TEMPORARY_CONTENT_FILE, + "Tar bort temporär innehållsfil" + ) MSG_HASH( MSG_RESET, "Återställ" @@ -10287,6 +10571,10 @@ MSG_HASH( MSG_SAVED_STATE_TO_SLOT_AUTO, "Sparade status till plats #-1 (Auto)." ) +MSG_HASH( + MSG_SAVED_SUCCESSFULLY_TO, + "Sparades till" + ) MSG_HASH( MSG_SAVING_RAM_TYPE, "Sparar RAM-typ" @@ -10295,6 +10583,10 @@ MSG_HASH( MSG_SCANNING, "Skannar" ) +MSG_HASH( + MSG_SCANNING_OF_DIRECTORY_FINISHED, + "Genomsökning av katalog färdig." + ) MSG_HASH( MSG_SENDING_COMMAND, "Skickar kommando" @@ -10411,6 +10703,14 @@ MSG_HASH( MSG_DEVICE_NOT_CONFIGURED_NR, "%s (%u/%u) är inte konfigurerad" ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "inte konfigurerad, faller tillbaka" + ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK_NR, + "%s (%u/%u) inte konfigurerad, faller tillbaka" + ) MSG_HASH( MSG_BLUETOOTH_SCAN_COMPLETE, "Bluetooth-skanning slutförd." @@ -10483,14 +10783,58 @@ MSG_HASH( MSG_CHEAT_SEARCH_ADDED_MATCHES_SUCCESS, "Lade till %u matchningar." ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADD_MATCH_FAIL, + "Misslyckades med att skapa kod." + ) +MSG_HASH( + MSG_CHEAT_SEARCH_ADDED_MATCHES_TOO_MANY, + "Slut på plats. Maximalt antal samtidiga fusk är 100." + ) +MSG_HASH( + MSG_CHEAT_ADD_TOP_SUCCESS, + "Nytt fusk lades till överst i listan." + ) +MSG_HASH( + MSG_CHEAT_ADD_BOTTOM_SUCCESS, + "Nytt fusk lades till nederst i listan." + ) MSG_HASH( MSG_CHEAT_DELETE_ALL_SUCCESS, "Alla fusk borttagna." ) +MSG_HASH( + MSG_CHEAT_ADD_BEFORE_SUCCESS, + "Nytt fusk lades till före denna." + ) +MSG_HASH( + MSG_CHEAT_ADD_AFTER_SUCCESS, + "Nytt fusk lades till efter denna." + ) +MSG_HASH( + MSG_CHEAT_COPY_BEFORE_SUCCESS, + "Fusk kopierat till före denna." + ) +MSG_HASH( + MSG_CHEAT_COPY_AFTER_SUCCESS, + "Fusk kopierat till efter denna." + ) MSG_HASH( MSG_CHEAT_DELETE_SUCCESS, "Fusk raderat." ) +MSG_HASH( + MSG_FAILED_TO_SET_DISK, + "Misslyckades med att ställa in skiva." + ) +MSG_HASH( + MSG_FAILED_TO_SET_INITIAL_DISK, + "Misslyckades med att ställa in sista använda skiva." + ) +MSG_HASH( + MSG_FAILED_TO_CONNECT_TO_CLIENT, + "Misslyckades med att ansluta till klient." + ) MSG_HASH( MSG_FAILED_TO_CONNECT_TO_HOST, "Misslyckades med att ansluta till värd." @@ -10503,6 +10847,10 @@ MSG_HASH( MSG_NETPLAY_BANNED, "Du är bannlyst från denna värd." ) +MSG_HASH( + MSG_FAILED_TO_RECEIVE_HEADER_FROM_HOST, + "Misslyckades med att ta bort rubrik från värd." + ) MSG_HASH( MSG_CHEEVOS_LOGGED_IN_AS_USER, "RetroAchievements: Inloggad som \"%s\"." @@ -10595,6 +10943,10 @@ MSG_HASH( MSG_MANUAL_CONTENT_SCAN_IN_PROGRESS, "Skannar: " ) +MSG_HASH( + MSG_MANUAL_CONTENT_SCAN_END, + "Genomsökning färdig: " + ) MSG_HASH( MSG_CORE_BACKUP_SCANNING_CORE, "Skannar kärna: " @@ -10603,6 +10955,10 @@ MSG_HASH( MSG_BACKING_UP_CORE, "Säkerhetskopierar kärna: " ) +MSG_HASH( + MSG_PRUNING_CORE_BACKUP_HISTORY, + "Tar bort föråldrade säkerhetskopior: " + ) MSG_HASH( MSG_RESTORING_CORE, "Återställer kärna: " @@ -10830,6 +11186,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_CPU_PROFILE, "Överklocka CPU" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_CPU_PROFILE, + "Överklocka Switch CPUn." + ) #endif #ifdef HAVE_LAKKA MSG_HASH( @@ -10840,6 +11200,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, "Tjänster" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, + "Hantera tjänster på operativsystemsnivå." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAMBA_ENABLE, + "Dela nätverksmappar genom SMB-protokollet." + ) MSG_HASH( MENU_ENUM_SUBLABEL_SSH_ENABLE, "Använd SSH för att komma åt kommandoraden utifrån." @@ -10877,6 +11245,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_OC_ENABLE, "Överklocka CPU" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SWITCH_OC_ENABLE, + "Aktivera CPU-överklockningsfrekvenser" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SWITCH_CEC_ENABLE, "CEC-stöd" @@ -10885,6 +11257,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SWITCH_CEC_ENABLE, "Aktivera CPU-handskakning med TV vid dockning" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BLUETOOTH_ERTM_DISABLE, + "Inaktivera Bluetooth ERTM" + ) #endif MSG_HASH( MSG_LOCALAP_SWITCHING_OFF, @@ -10934,6 +11310,10 @@ MSG_HASH( #ifdef UDEV_TOUCH_SUPPORT #endif #ifdef HAVE_ODROIDGO2 +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_RGA_SCALING, + "RGA-skalning" + ) #else #endif #ifdef _3DS diff --git a/intl/msg_hash_tr.h b/intl/msg_hash_tr.h index d792ad6690..3f57d19d63 100644 --- a/intl/msg_hash_tr.h +++ b/intl/msg_hash_tr.h @@ -906,6 +906,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 Desteği" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL Desteği" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb Desteği" diff --git a/intl/progress.h b/intl/progress.h index d27dae83ab..20f0333a4d 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -7,7 +7,7 @@ #define LANGUAGE_PROGRESS_ASTURIAN_APPROVED 9 /* Belarusian */ -#define LANGUAGE_PROGRESS_BELARUSIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_BELARUSIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_BELARUSIAN_APPROVED 0 /* Bulgarian */ @@ -31,7 +31,7 @@ #define LANGUAGE_PROGRESS_DANISH_APPROVED 0 /* German */ -#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_GERMAN_APPROVED 14 /* Greek */ @@ -47,7 +47,7 @@ #define LANGUAGE_PROGRESS_ESPERANTO_APPROVED 0 /* Spanish */ -#define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 99 +#define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 100 #define LANGUAGE_PROGRESS_SPANISH_APPROVED 90 /* Persian */ @@ -59,8 +59,8 @@ #define LANGUAGE_PROGRESS_FINNISH_APPROVED 46 /* French */ -#define LANGUAGE_PROGRESS_FRENCH_TRANSLATED 99 -#define LANGUAGE_PROGRESS_FRENCH_APPROVED 99 +#define LANGUAGE_PROGRESS_FRENCH_TRANSLATED 100 +#define LANGUAGE_PROGRESS_FRENCH_APPROVED 100 /* Galician */ #define LANGUAGE_PROGRESS_GALICIAN_TRANSLATED 99 @@ -91,7 +91,7 @@ #define LANGUAGE_PROGRESS_JAPANESE_APPROVED 0 /* Korean */ -#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_KOREAN_APPROVED 0 /* Dutch */ @@ -119,7 +119,7 @@ #define LANGUAGE_PROGRESS_PORTUGUESE_APPROVED 0 /* Russian */ -#define LANGUAGE_PROGRESS_RUSSIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_RUSSIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_RUSSIAN_APPROVED 13 /* Slovak */ @@ -131,12 +131,12 @@ #define LANGUAGE_PROGRESS_SERBIAN_LATIN_APPROVED 0 /* Swedish */ -#define LANGUAGE_PROGRESS_SWEDISH_TRANSLATED 56 +#define LANGUAGE_PROGRESS_SWEDISH_TRANSLATED 58 #define LANGUAGE_PROGRESS_SWEDISH_APPROVED 47 /* Turkish */ -#define LANGUAGE_PROGRESS_TURKISH_TRANSLATED 99 -#define LANGUAGE_PROGRESS_TURKISH_APPROVED 99 +#define LANGUAGE_PROGRESS_TURKISH_TRANSLATED 100 +#define LANGUAGE_PROGRESS_TURKISH_APPROVED 100 /* Tatar */ #define LANGUAGE_PROGRESS_TATAR_TRANSLATED 0 From 4b45499b975da2b15b88021459fc1dcc5c3c656d Mon Sep 17 00:00:00 2001 From: zoltanvb <101990835+zoltanvb@users.noreply.github.com> Date: Fri, 10 Jan 2025 12:20:46 +0100 Subject: [PATCH 051/574] Changes up to 01-09 (#17379) ...and one minor clarification in previous logs. --- CHANGES.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 8d54800a69..5e9189bc7a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,11 @@ # Future +- AUDIO/PIPEWIRE: Fix app launch when pipewire service is stopped +- GENERAL: Fix save state auto increment +- GENERAL: Fix softpatching with periods/dots in the file name +- GENERAL: Fix compilation with --enable-videocore +- MENU: Add SSL support to the information list +- IOS: Ensure webserver notice can be dismissed +- VIDEO/SHADERS: Allow exact refresh rate sync with shader subframes # 1.20.0 - AUDIO: Fix audio handling in case of RARCH_NETPLAY_CTL_USE_CORE_PACKET_INTERFACE @@ -46,7 +53,7 @@ - INPUT/UDEV: Enable mouse buttons 4 and 5 - INPUT/WAYLAND: Enable horizontal scroll and mouse buttons 4 and 5 - INPUT/WAYLAND: Simulate lightgun input for cores -- INPUT/WAYLAND: Support for cursor-shape-v1 and content-type-v1 protocol +- INPUT/WAYLAND: Support for cursor-shape-v1 protocol - INPUT/X11: Enable mouse buttons 4 and 5 - iOS: Enable vibration by default - iOS: Better handling of physical mice/magic keyboard trackpad @@ -114,6 +121,7 @@ - VIDEO/VULKAN: Fix Vulkan window freezes when swapchain becomes suboptimal - VIDEO/VULKAN: Prefer IMMEDIATE mode without vsync - VIDEO/X11: Support inhibit of Xss screensaver +- VIDEO/WAYLAND: Support for content-type-v1 protocol - VITA: Enable analog L2/R2 triggers when a DS3 controller is used with PS Vita - WAYLAND: Fix segfault when relative pointer is not supported - WAYLAND: Use reverse DNS name for desktop file and icon From 95dd1d8449597ead25f9c5665c229e933d9594b7 Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Fri, 10 Jan 2025 06:21:24 -0500 Subject: [PATCH 052/574] cloud sync: fix windows path issues (#17375) --- tasks/task_cloudsync.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tasks/task_cloudsync.c b/tasks/task_cloudsync.c index ed8549cf8c..e6bbd39917 100644 --- a/tasks/task_cloudsync.c +++ b/tasks/task_cloudsync.c @@ -539,6 +539,7 @@ static void task_cloud_sync_backup_file(struct item_file *file) CS_FILE_KEY(file), sizeof(new_path)); strftime(new_path + len, sizeof(new_path) - len, "-%y%m%d-%H%M%S", &tm_); + pathname_conform_slashes_to_os(new_path); fill_pathname_basedir(new_dir, new_path, sizeof(new_dir)); path_mkdir(new_dir); filestream_rename(file->path, new_path); @@ -583,7 +584,8 @@ static void task_cloud_sync_fetch_server_file(task_cloud_sync_state_t *sync_stat struct string_list *dirlist = task_cloud_sync_directory_map(); struct item_file *server_file = &sync_state->server_manifest->list[sync_state->server_idx]; const char *key = CS_FILE_KEY(server_file); - const char *path = strchr(key, PATH_DEFAULT_SLASH_C()) + 1; + /* the key from the server file is in "portable" format, use '/' */ + const char *path = strchr(key, '/') + 1; settings_t *settings = config_get_ptr(); /* we're just fetching a file the server has, we can update this now */ @@ -604,6 +606,7 @@ static void task_cloud_sync_fetch_server_file(task_cloud_sync_state_t *sync_stat if (!string_starts_with(key, dirlist->elems[i].data)) continue; fill_pathname_join_special(filename, dirlist->elems[i].userdata, path, sizeof(filename)); + pathname_conform_slashes_to_os(filename); break; } if (string_is_empty(filename)) From 17e9aabd256bb4d9ca67fa4179929e7bd6e47783 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Fri, 10 Jan 2025 13:21:33 +0200 Subject: [PATCH 053/574] WINRAW: Invert mouse order (#17376) --- input/drivers/winraw_input.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/input/drivers/winraw_input.c b/input/drivers/winraw_input.c index e04b9d80b2..42e0fefa8a 100644 --- a/input/drivers/winraw_input.c +++ b/input/drivers/winraw_input.c @@ -128,14 +128,14 @@ static void winraw_log_mice_info(winraw_mouse_t *mice, unsigned mouse_cnt) char name[256]; UINT name_size = sizeof(name); - name[0] = '\0'; + name[0] = '\0'; for (i = 0; i < mouse_cnt; ++i) { UINT r = GetRawInputDeviceInfoA(mice[i].hnd, RIDI_DEVICENAME, name, &name_size); if (r == (UINT)-1 || r == 0) - name[0] = '\0'; + name[0] = '\0'; if (name[0]) { @@ -146,7 +146,7 @@ static void winraw_log_mice_info(winraw_mouse_t *mice, unsigned mouse_cnt) if (hhid != INVALID_HANDLE_VALUE) { wchar_t prod_buf[128]; - prod_buf[0] = '\0'; + prod_buf[0] = '\0'; if (HidD_GetProductString(hhid, prod_buf, sizeof(prod_buf))) wcstombs(name, prod_buf, sizeof(name)); } @@ -158,7 +158,7 @@ static void winraw_log_mice_info(winraw_mouse_t *mice, unsigned mouse_cnt) input_config_set_mouse_display_name(i, name); - RARCH_LOG("[WinRaw]: Mouse #%u: \"%s\".\n", i, name); + RARCH_LOG("[WinRaw]: Mouse #%u: \"%s\".\n", i + 1, name); } } @@ -203,19 +203,23 @@ static bool winraw_init_devices(winraw_mouse_t **mice, unsigned *mouse_cnt) } } + *mouse_cnt = mouse_cnt_r; + /* count is already checked, so this is safe */ for (i = mouse_cnt_r = 0; i < dev_cnt; ++i) { if (devs[i].dwType == RIM_TYPEMOUSE) - mice_r[mouse_cnt_r++].hnd = devs[i].hDevice; + { + mouse_cnt_r++; + mice_r[*mouse_cnt - mouse_cnt_r].hnd = devs[i].hDevice; + } } + *mice = mice_r; + winraw_log_mice_info(mice_r, mouse_cnt_r); free(devs); - *mice = mice_r; - *mouse_cnt = mouse_cnt_r; - return true; error: From 1e32a1e5e98fd24380919074f1ed831a4557ef69 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:47:28 +0200 Subject: [PATCH 054/574] Save state logging and label unifications (#17384) --- command.c | 18 +++++++++--------- intl/msg_hash_us.h | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/command.c b/command.c index 8dfe80e471..4e7c72f142 100644 --- a/command.c +++ b/command.c @@ -1275,11 +1275,11 @@ bool command_event_save_auto_state(void) sizeof(savestate_name_auto) - _len); if (content_auto_save_state((const char*)savestate_name_auto)) - RARCH_LOG("%s \"%s\" %s.\n", + RARCH_LOG("[State]: %s \"%s\" %s.\n", msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO), savestate_name_auto, "succeeded"); else - RARCH_LOG("%s \"%s\" %s.\n", + RARCH_LOG("[State]: %s \"%s\" %s.\n", msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO), savestate_name_auto, "failed"); @@ -1582,8 +1582,8 @@ static void scan_states(settings_t *settings, loa_idx = gap_idx - 1; } - RARCH_DBG("[State]: savestate scanning finished, used slots (in range): " - "%d (%d), max:%d, load index %d, gap index %d, delete index %d\n", + RARCH_DBG("[State]: Save state scanning finished, used slots (in range): " + "%d (%d), max:%d, load index %d, gap index %d, delete index %d.\n", cnt, cnt_in_range, max_idx, loa_idx, gap_idx, del_idx); if (last_index) @@ -1636,7 +1636,7 @@ void command_event_set_savestate_auto_index(settings_t *settings) return; scan_states(settings, &max_idx, NULL); configuration_set_int(settings, settings->ints.state_slot, max_idx); - RARCH_LOG("[State]: %s: #%d\n", + RARCH_LOG("[State]: %s: #%d.\n", msg_hash_to_str(MSG_FOUND_LAST_STATE_SLOT), max_idx); } @@ -1658,13 +1658,13 @@ static void command_event_set_savestate_garbage_collect(settings_t *settings) if (!string_is_empty(state_to_delete)) { filestream_delete(state_to_delete); - RARCH_DBG("[State]: garbage collect, deleting \"%s\" \n",state_to_delete); + RARCH_DBG("[State]: Garbage collect, deleting \"%s\".\n",state_to_delete); /* Construct the save state thumbnail name * and delete that one as well. */ i = strlen(state_to_delete); strlcpy(state_to_delete + i,".png",STRLEN_CONST(".png")+1); filestream_delete(state_to_delete); - RARCH_DBG("[State]: garbage collect, deleting \"%s\" \n",state_to_delete); + RARCH_DBG("[State]: Garbage collect, deleting \"%s\".\n",state_to_delete); } } @@ -2137,12 +2137,12 @@ bool command_event_main_state(unsigned cmd) input_driver_state_t *input_st = input_state_get_ptr(); if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_RECORDING) { - RARCH_ERR("[Load] [Movie] Can't undo load state during movie record\n"); + RARCH_ERR("[State]: Can't undo load state during movie record.\n"); return false; } if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_PLAYBACK) { - RARCH_LOG("[Load] [Movie] Undo load state during movie playback, halting playback\n"); + RARCH_LOG("[State]: Undo load state during movie playback, halting playback.\n"); movie_stop(input_st); } #endif diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 0266369fd8..1b6ae4063e 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4629,7 +4629,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Specifies whether to ignore core info savestate capabilities, allowing to experiment with related features (run ahead, rewind, etc)." + "Specifies whether to ignore core info save state capabilities, allowing to experiment with related features (run ahead, rewind, etc)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4873,7 +4873,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatically make a save state when content is closed. RetroArch will automatically load this save state if 'Load State Automatically' is enabled." + "Automatically make a save state when content is closed. This save state is loaded on startup if 'Auto Load State' is enabled." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -14175,10 +14175,6 @@ MSG_HASH( MSG_AUTODETECT, "Autodetect" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto-loading save state from" - ) MSG_HASH( MSG_CAPABILITIES, "Capabilities" @@ -15275,6 +15271,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Failed to close virtual disc tray." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Auto-loading save state from" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Auto-loading save state from \"%s\" failed." @@ -16559,7 +16559,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Display bottom menu font. Enable to display button descriptions on the bottom screen. This excludes the savestate date." + "Display bottom menu font. Enable to display button descriptions on the bottom screen. This excludes the save state date." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, From 857dc8be5a688c255f462ab36da08e4eb5cddde1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 11 Jan 2025 00:14:13 +0000 Subject: [PATCH 055/574] Fetch translations from Crowdin --- intl/msg_hash_ar.h | 12 +- intl/msg_hash_be.h | 14 +- intl/msg_hash_ca.h | 4 - intl/msg_hash_chs.h | 20 +-- intl/msg_hash_cht.h | 20 +-- intl/msg_hash_cs.h | 20 +-- intl/msg_hash_de.h | 20 +-- intl/msg_hash_el.h | 8 +- intl/msg_hash_en.h | 4 - intl/msg_hash_es.h | 10 +- intl/msg_hash_fi.h | 12 +- intl/msg_hash_fr.h | 10 +- intl/msg_hash_gl.h | 20 +-- intl/msg_hash_hu.h | 20 +-- intl/msg_hash_it.h | 24 +-- intl/msg_hash_ja.h | 20 +-- intl/msg_hash_ko.h | 20 +-- intl/msg_hash_nl.h | 4 - intl/msg_hash_pl.h | 18 +- intl/msg_hash_pt_br.h | 16 +- intl/msg_hash_pt_pt.h | 404 +++++++++++++++++++++++++++++++++++++++++- intl/msg_hash_ru.h | 14 +- intl/msg_hash_sv.h | 16 +- intl/msg_hash_tr.h | 10 +- intl/msg_hash_uk.h | 18 +- intl/msg_hash_vn.h | 8 +- intl/progress.h | 12 +- 27 files changed, 523 insertions(+), 255 deletions(-) diff --git a/intl/msg_hash_ar.h b/intl/msg_hash_ar.h index 0cf9004c90..ea253ea31f 100644 --- a/intl/msg_hash_ar.h +++ b/intl/msg_hash_ar.h @@ -8023,10 +8023,6 @@ MSG_HASH( MSG_AUTODETECT, "الكشف التلقائي" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "التحميل التلقائي للحالة من" - ) MSG_HASH( MSG_CAPABILITIES, "القدرات" @@ -8883,6 +8879,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "فشل حساب حجم العرض! سوف يستمر في استخدام البيانات الخام. ربما لن يعمل هذا بشكل صحيح..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "التحميل التلقائي للحالة من" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "فشل التحميل التلقائي لحالة الحفظ من \"%s\"." @@ -9653,10 +9653,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "تمكين الخط" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "عرض خط القائمة السفلية. تمكين عرض أوصاف الأزرار في أسفل الشاشة. يستبعد هذا تاريخ الحفظ." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "لون الخط أحمر" diff --git a/intl/msg_hash_be.h b/intl/msg_hash_be.h index 72c3218b7a..199f4b2420 100644 --- a/intl/msg_hash_be.h +++ b/intl/msg_hash_be.h @@ -4585,7 +4585,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Дазволіць абыход магчымасцяў хуткіх захаванняў ва ўласцівасцях ядра, гэта дазваляе эксперыментаваць са звязанымі функцыямі (забяганне, зваротная перамотка і г. д.)." + "Вызначае, ці варта ігнараваць уласцівасці захавання стану ў звестках ядра, што дазваляе эксперыментаваць з адпаведнымі функцыямі (забяганне, перамотка назад і г. д.)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4829,7 +4829,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Аўтаматычна ствараць захаванне пры зачыненні кантэнту. RetroArch будзе аўтаматычна загружаць дадзенае захаванне, калі ўключана 'Аўтазагрузка захаванняў'." + "Аўтаматычна ствараць захаванне стану падчас закрыцця змесціва. Гэты стан будзе загружаны пры запуску, калі ўключана 'Аўтаматычная загрузка стану'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -13483,10 +13483,6 @@ MSG_HASH( MSG_AUTODETECT, "Аўтавызначэнне" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Аўтазагрузка захавання з" - ) MSG_HASH( MSG_CAPABILITIES, "Магчымасці" @@ -14579,6 +14575,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Не атрымалася зачыніць латок віртуальнага cd-прывада." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Аўтазагрузка захавання з" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Памылка аўтаматычнай загрузкі захавання стану з \"%s\"." @@ -15827,7 +15827,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Паказвае шрыфт ніжняга меню. Уключыце для адлюстравання апісання кнопак на ніжнім экране. Не ўключае даты захаванняў." + "Адлюстроўвае шрыфт ніжняга меню. Уключыце, каб бачыць апісанне кнопак на ніжнім экране. Адкідае даты захаванняў стану." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, diff --git a/intl/msg_hash_ca.h b/intl/msg_hash_ca.h index becf7ef2f3..d69ff5b8ff 100644 --- a/intl/msg_hash_ca.h +++ b/intl/msg_hash_ca.h @@ -3971,10 +3971,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Desat ràpid automàtic" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Crea un desat ràpid automàticament quan es tanca el contingut. El RetroArch carregarà automàticament aquest desat ràpid si l’opció «Carrega el desat ràpid automàticament» està activada." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, "Carrega automàticament el desat ràpid automàtic a l’inici." diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index 84adedb875..a10ae839d1 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -4399,10 +4399,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "绕过核心信息保存状态功能" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "指定是否忽略核心信息保护功能,允许尝试相关的功能 (超前运行,回溯等)。" - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4643,10 +4639,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "自动保存状态" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "关闭游戏时自动保存状态。如果启用了「自动加载状态」,下次打开游戏时,全能模拟器将自动加载此状态。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "自动加载存档" @@ -13247,10 +13239,6 @@ MSG_HASH( MSG_AUTODETECT, "自动检测" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "自动加载状态存储于" - ) MSG_HASH( MSG_CAPABILITIES, "容量" @@ -14347,6 +14335,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "收回虚拟光驱托盘失败。" ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "自动加载状态存储于" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "从 \"%s\" 自动加载状态存档失败。" @@ -15565,10 +15557,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "启用字体" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "显示底部菜单字体。启用以在底部屏幕上显示按钮描述。这不包括保存日期。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "字体颜色红色通道" diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index f56af77803..c0fd296910 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -4419,10 +4419,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "忽略其他支援" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "開啟時執行核心忽略儲存狀態功能, 可用於開啟倒帶、超前執行和搶占幀數等相關功能。" - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4663,10 +4659,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "自動儲存即時存檔" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "「關閉」和「結束復古電玩」時, 自動儲存即時存檔, 儲存的編號為自動(.state.auto)。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "自動載入即時存檔" @@ -13367,10 +13359,6 @@ MSG_HASH( MSG_AUTODETECT, "自動偵測" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "自動載入即時存檔從" - ) MSG_HASH( MSG_CAPABILITIES, "容量" @@ -14455,6 +14443,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "虛擬光碟機托盤無法進入。" ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "自動載入即時存檔從" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "無法自動載入即時存檔, 位置: %s。" @@ -15517,10 +15509,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "顯示文字" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "在下螢幕上顯示按鍵說明, 不包括儲存即時存檔的日期。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "字體顏色 (紅)" diff --git a/intl/msg_hash_cs.h b/intl/msg_hash_cs.h index 2809bc0818..ec2ecb06bf 100644 --- a/intl/msg_hash_cs.h +++ b/intl/msg_hash_cs.h @@ -4251,10 +4251,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Obejít základní informace pro funkce uložených pozic" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Určuje, zda se mají ignorovat základní možnosti ukládání informací, což umožňuje experimentovat se souvisejícími funkcemi (běh dopředu, přetáčení atd.)." - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4487,10 +4483,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Automaticky uložit pozici" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatické vytvoření pozice uložení při zavření obsahu. Pokud je povolena volba 'Automaticky načíst pozici', RetroArch tuto pozici uložení automaticky načte." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Automaticky načíst pozici uložení" @@ -12791,10 +12783,6 @@ MSG_HASH( MSG_AUTODETECT, "Autodetekovat" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Automaticky načíst pozici uložení z" - ) MSG_HASH( MSG_CAPABILITIES, "Schopnosti" @@ -13847,6 +13835,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Nepodařilo se zavřít zásobník virtuálních disků." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Automaticky načíst pozici uložení z" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Automatické načtení uložené pozice z \"%s\"se nezdařilo." @@ -14981,10 +14973,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Povolení písma" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Zobrazení písma spodního menu. Povolit zobrazení popisů tlačítek na spodní obrazovce. To se netýká data uložení." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Červená barva písma" diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index ea3fb07a31..48bb6daff4 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -4455,10 +4455,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Umgehung der Core-Info-Savestates-Funktionen" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Legt fest, ob Savestatefähigkeiten der Core Info ignoriert werden sollen, so dass mit verwandten Funktionen experimentiert werden kann (Run-Ahead, Zurückspulen usw)." - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4699,10 +4695,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Savestate automatisch erstellen" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatisch ein Savestate erstellen, wenn der Inhalt geschlossen wird. RetroArch lädt dieses Savestate automatisch, wenn 'Savestate automatisch laden' aktiviert ist." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Savestate automatisch laden" @@ -13063,10 +13055,6 @@ MSG_HASH( MSG_AUTODETECT, "Automatisch erkennen" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Automatisches Laden des Speicherzustands aus" - ) MSG_HASH( MSG_CAPABILITIES, "Fähigkeiten" @@ -14155,6 +14143,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Virtuelles Laufwerk konnte nicht geschlossen werden." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Automatisches Laden des Speicherzustands aus" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Automatisches Laden des Savestates aus \"%s\" fehlgeschlagen." @@ -15401,10 +15393,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Schrift aktivieren" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Text am unteren Bildschirm einblenden. Aktivieren, um Tastenbeschreibungen auf dem unteren Bildschirm anzuzeigen. Dies schließt das Speicherdatum aus." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Schriftfarbe Rot" diff --git a/intl/msg_hash_el.h b/intl/msg_hash_el.h index 25225c6ca7..8d3d67b4e5 100644 --- a/intl/msg_hash_el.h +++ b/intl/msg_hash_el.h @@ -5391,10 +5391,6 @@ MSG_HASH( MSG_AUTODETECT, "Αυτόματη ανίχνευση" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Αυτόματη φόρτωση κατάστασης αποθήκευσης από" - ) MSG_HASH( MSG_CAPABILITIES, "Ικανότητες" @@ -5607,6 +5603,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "Viewport size calculation failed! Will continue using raw data. This will probably not work right ..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Αυτόματη φόρτωση κατάστασης αποθήκευσης από" + ) MSG_HASH( MSG_DEVICE_CONFIGURED_IN_PORT, "διαμορφώθηκε στην θύρα" diff --git a/intl/msg_hash_en.h b/intl/msg_hash_en.h index bd90872f63..9f90c8b4f0 100644 --- a/intl/msg_hash_en.h +++ b/intl/msg_hash_en.h @@ -2269,10 +2269,6 @@ MSG_HASH( MSG_3DS_BOTTOM_MENU_DEFAULT, "Tap the Touch Screen to go\nto the RetroArch menu" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Display bottom menu font. Enable to display button descriptions on the bottom screen. This excludes the save-state date." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Font Colour Red" diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 75bbd10c0c..53c422c343 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -4805,7 +4805,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Hace un guardado rápido de forma automática al cerrar un contenido. RetroArch lo cargará automáticamente si la opción «Cargar guardado rápido automáticamente» está activada." + "Hace un guardado rápido de forma automática al cerrar un contenido. El guardado rápido se cargará automáticamente si la opción «Cargar guardado rápido automáticamente» está activada." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -13403,10 +13403,6 @@ MSG_HASH( MSG_AUTODETECT, "Detección automática" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Carga automática de guardado rápido en" - ) MSG_HASH( MSG_CAPABILITIES, "Funcionalidades" @@ -14487,6 +14483,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Error al cerrar la bandeja de discos virtual." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Carga automática de guardado rápido en" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Error al cargar automáticamente el guardado rápido «%s»." diff --git a/intl/msg_hash_fi.h b/intl/msg_hash_fi.h index cb5eb0fa01..7f26340947 100644 --- a/intl/msg_hash_fi.h +++ b/intl/msg_hash_fi.h @@ -4183,10 +4183,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Tilan automaattinen tallennus" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Luo tilatallennus automaattisesti kun suljet sisällön. RetroArch lataa automaattisesti tämän tilatallennuksen, jos \"Lataa tilatallennus automaattisesti\" on käytössä." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Tilan automaattinen lataaminen" @@ -12171,10 +12167,6 @@ MSG_HASH( MSG_AUTODETECT, "Havaitse automaattisesti" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Tilan lataaminen kohteesta" - ) MSG_HASH( MSG_CAPABILITIES, "Ominaisuudet" @@ -13231,6 +13223,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Virtuaalisen levyaseman sulkeminen epäonnistui." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Tilan lataaminen kohteesta" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Tilatallennuksen automaattinen lataus kohteesta \"%s\" epäonnistui." diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index 3354e36baf..cea381215b 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -4765,7 +4765,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Créer automatiquement une sauvegarde instantanée à la fermeture de contenu. RetroArch chargera cette sauvegarde instantanée automatiquement si 'Chargement auto des sauvegardes instantanées' est activé." + "Faire automatiquement une sauvegarde instantanée lorsque le contenu est fermé. Cette sauvegarde instantanée est chargée au démarrage si l'option 'Chargement auto des sauvegardes instantanées' est activée." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -13359,10 +13359,6 @@ MSG_HASH( MSG_AUTODETECT, "Détection automatique" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Chargement auto d'une sauvegarde instantanée depuis" - ) MSG_HASH( MSG_CAPABILITIES, "Capacités" @@ -14447,6 +14443,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Impossible de fermer le plateau du lecteur de disque virtuel." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Chargement auto d'une sauvegarde instantanée depuis" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Le chargement d'une sauvegarde automatique depuis \"%s\" a échoué." diff --git a/intl/msg_hash_gl.h b/intl/msg_hash_gl.h index 0550fe4e52..08c35e6c36 100644 --- a/intl/msg_hash_gl.h +++ b/intl/msg_hash_gl.h @@ -4491,10 +4491,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Omite as funcións de gardar estados da información do núcleo" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Especifica se ignorar as capacidades de estado de salvamento da información básica, o que permite probar con funcións relacionadas (adiante, rebobinar, etc.)." - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4735,10 +4731,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Estado de gardado automático" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Fai automaticamente un estado de gardado cando o contido estea pechado. RetroArch cargará automaticamente este estado de gardado se \"Cargar estado automaticamente\" está activado." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Estado de carga automática" @@ -13227,10 +13219,6 @@ MSG_HASH( MSG_AUTODETECT, "Detección automática" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Cargando automaticamente o estado de gardar desde" - ) MSG_HASH( MSG_CAPABILITIES, "Capacidades" @@ -14307,6 +14295,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Produciuse un erro ao pechar a bandexa do disco virtual." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Cargando automaticamente o estado de gardar desde" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Fallou a carga automática do estado de gardado de \"%s\"." @@ -15525,10 +15517,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Activar fonte" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Mostra a fonte do menú inferior. Activar para mostrar as descricións dos botóns na pantalla inferior. Isto exclúe a data do estado de salvación." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Cor da fonte Vermello" diff --git a/intl/msg_hash_hu.h b/intl/msg_hash_hu.h index b4663e24d4..d0ad427d66 100644 --- a/intl/msg_hash_hu.h +++ b/intl/msg_hash_hu.h @@ -4487,10 +4487,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Maginformációs fájl mentési tulajdonságainak átlépése" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "A maginformációs fájl állapotmentési információinak figyelmen kívül hagyása. Így lehet kísérletezni az ezzel összefüggő funkciókkal (runahead, visszatekerés, stb.)." - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4731,10 +4727,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Játékállás automatikus mentése" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "A tartalom bezárásakor automatikusan készít egy mentést a játékállásról. Ha a \"Játékállás automatikus betöltése\" be van kapcsolva, ez fog betöltődni." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Automatikus játékállás betöltés" @@ -13083,10 +13075,6 @@ MSG_HASH( MSG_AUTODETECT, "Automatikus felismerés" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Játékállás automatikus betöltése innen" - ) MSG_HASH( MSG_CAPABILITIES, "Képességek" @@ -14171,6 +14159,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Virtuális lemeztálca becsukása sikertelen." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Játékállás automatikus betöltése innen" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Játékállás automatikus betöltése innen: \"%s\", sikertelen." @@ -15413,10 +15405,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Betűkészlet engedélyezése" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Az alsó menü betűkészlete, a gombleírásokhoz az alsó képernyőn. Nem vonatkozik a játékállás mentés dátumára." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Betűszín, piros komponens" diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 1e5049dd3f..c84c4aa6cf 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -898,6 +898,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Supporto Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Supporto SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Supporto Libusb" @@ -4483,10 +4487,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Supera le informazioni del core per le informazioni del salvataggio di stato" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Specifica se ignorare le funzionalità di salvataggio di stato delle informazioni di base, consentendo di sperimentare con le caratteristiche correlate (Run-Ahead, riavvolgi, ecc)." - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4727,10 +4727,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Stato di salvataggio automatico" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Crea automaticamente uno stato di salvataggio quando il contenuto è chiuso. RetroArch caricherà automaticamente questo stato di salvataggio se 'Carica automaticamente lo stato' è abilitato." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Carica automaticamente i salvataggi" @@ -13203,10 +13199,6 @@ MSG_HASH( MSG_AUTODETECT, "Trovato automaticamente" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Carica automaticamente il salvataggio da" - ) MSG_HASH( MSG_CAPABILITIES, "Funzionalità" @@ -14295,6 +14287,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Chiusura del vassoio del disco virtuale non riuscita." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Carica automaticamente il salvataggio da" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Caricamento automatico dello stato di salvataggio da \"%s\" non riuscito." @@ -15537,10 +15533,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Attiva Font" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Visualizza il carattere del menu inferiore. Abilita per visualizzare le descrizioni dei pulsanti nello schermo inferiore. Questo esclude la data di salvataggio." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Colore rosso del font" diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index df2076520f..a8c01dee56 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -4427,10 +4427,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "コア情報のステートセーブ機能の対応有無を無視" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "コア情報のステートセーブ機能の対応有無を無視するかどうかを指定し、関連する機能 (先行実行、巻き戻しなど) を試すことができます。" - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4671,10 +4667,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "自動ステートセーブ" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "コンテンツを閉じたときに自動的にステートセーブを作成します。[自動ステートロード] が有効になっている場合、RetroArch はこのステートセーブを自動的にロードします。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "自動ステートロード" @@ -13195,10 +13187,6 @@ MSG_HASH( MSG_AUTODETECT, "自動検出" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "ステートセーブを自動ロード中 from" - ) MSG_HASH( MSG_CAPABILITIES, "対応機能" @@ -14287,6 +14275,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "仮想ディスクトレイを閉じることができませんでした。" ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "ステートセーブを自動ロード中 from" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "\"%s\" からのステートセーブの自動読み込みに失敗しました。" @@ -15513,10 +15505,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "フォントを有効にする" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "下メニューのフォントを表示します。下画面にボタンの説明を表示することが出来ます。ステートセーブの日付は表示されません。" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "フォントの色 (赤)" diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index c265bcf884..282e8a4c7f 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -4595,10 +4595,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "코어 정보 상태저장 기능 여부 무시" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "코어 정보의 상태저장 기능 제공 여부를 무시할지 설정합니다. 관련 기능(미리 실행, 되감기 등)을 시험해볼 수 있게 됩니다." - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4839,10 +4835,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "자동 상태저장" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "콘텐츠가 종료되면 자동으로 상태저장 파일을 생성합니다. 자동 상태 불러오기가 활성화 되어 있으면 다음 시작시 해당 상태저장을 자동으로 불러옵니다." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "상태저장 자동으로 불러오기" @@ -13499,10 +13491,6 @@ MSG_HASH( MSG_AUTODETECT, "자동감지" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "상태저장 자동 불러오기: " - ) MSG_HASH( MSG_CAPABILITIES, "기능" @@ -14595,6 +14583,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "가상 디스크 트레이를 닫지 못했습니다." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "상태저장 자동 불러오기: " + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "\"%s\"에서 상태저장을 자동으로 불러오지 못했습니다." @@ -15857,10 +15849,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "폰트 사용" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "아래 화면 메뉴에 폰트를 사용합니다. 활성화하면 아래 화면에 버튼 설명이 표시됩니다. 상태저장 일자 표시는 영향을 받지 않습니다." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "폰트 색 빨강" diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index e9a9701b58..b4637c4589 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -3735,10 +3735,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Automatisch Slaan de Staat op" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatisch een slagstaat maken wanneer inhoud wordt gesloten. RetroArch zal deze slagstaat automatisch laden als 'Staat Automatisch Laden' is ingeschakeld." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, "Laad de slagstaat automatisch bij het opstarten." diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index 28765d046c..aa6da28835 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -4079,6 +4079,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_CACHE_ENABLE, "Utrzymuj stałą lokalną pamięć podręczną zainstalowanych informacji o rdzeniach. Znacznie skraca czas ładowania na platformach z wolnym dostępem do dysku." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, + "Określa, czy zignorować podstawowe informacje zapisują możliwości stanu, pozwalające na eksperymentowanie z powiązanymi funkcjami (uruchamianie z przodu, przewijanie itp.)." + ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4281,7 +4285,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatycznie utwórz stan zapisu, gdy zawartość jest zamknięta. RetroArch automatycznie załaduje ten stan zapisu, jeśli włączona jest opcja \"Załaduj stan automatycznie\"." + "Automatycznie utwórz stan zapisu, gdy zawartość jest zamknięta. Ten stan zapisów jest załadowany przy starcie, jeśli włączony jest \"Automatycznej wczytywanie\"." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, @@ -11959,10 +11963,6 @@ MSG_HASH( MSG_AUTODETECT, "Automatyczne wykrywanie" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Automatyczne ładowanie stanu zapisu" - ) MSG_HASH( MSG_CAPABILITIES, "Możliwości" @@ -12971,6 +12971,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "Obliczenie rozmiaru obszaru widoku nie powiodło się! Nadal używane będą surowe dane. To prawdopodobnie nie zadziała dobrze..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Automatyczne ładowanie stanu zapisu" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Automatyczne ładowanie stanu zapisu z \"%s\" nie powiodło się." @@ -13937,6 +13941,10 @@ MSG_HASH( MSG_3DS_BOTTOM_MENU_LOAD_STATE, "Załaduj\nPunkt przywracania" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, + "Wyświetlaj czcionkę dolnego menu. Włącz, aby wyświetlić opisy przycisków na dolnym ekranie. Wyklucza to datę zapisu." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_OPACITY, "Przezroczystość koloru czcionki" diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index b514609d0e..7db4521c84 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -4079,10 +4079,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Salvar jogo automaticamente" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Cria automaticamente um jogo salvo quando o conteúdo for fechado. O RetroArch carregará automaticamente este jogo salvo se \"Carregue automaticamente o jogo salvo\" estiver ativado." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, "Carrega o último jogo salvo automaticamente na inicialização do RetroArch." @@ -11639,10 +11635,6 @@ MSG_HASH( MSG_AUTODETECT, "Detectar automaticamente" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Autocarregando jogo salvo de" - ) MSG_HASH( MSG_CAPABILITIES, "Capacidades" @@ -12627,6 +12619,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Houve uma falha ao fechar a bandeja virtual do disco." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Autocarregando jogo salvo de" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "O carregamento automático do jogo salvo a partir de \"%s\" falhou." @@ -13585,10 +13581,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Ativar fonte" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Mostra a fonte do menu inferior. Ative para exibir as descrições dos botões na tela inferior. Não tem compatibilidade com a data do jogo salvo." - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Vermelho da fonte" diff --git a/intl/msg_hash_pt_pt.h b/intl/msg_hash_pt_pt.h index c34d6541db..87fbf2b301 100644 --- a/intl/msg_hash_pt_pt.h +++ b/intl/msg_hash_pt_pt.h @@ -495,6 +495,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API, "API de Gráficos Necessária" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_PATH, + "Caminho Completo" +) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SUPPORT_LEVEL, "Posição de gravação de estado" @@ -519,6 +523,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_IN_CONTENT_DIRECTORY, "- Nota: A opção \"Ficheiros do Sistema estão na Pasta de Conteúdos\" está atualmente ativada." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_PATH, + "- A procurar em: '%s" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MISSING_REQUIRED, "Em falta, Requerido:" @@ -543,6 +551,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CORE_LOCK, "Previne que o núcleo atualmente instalado seja modificado. Pode ser usado para evitar atualizações indesejadas quando o conteúdo requer uma versão específica do núcleo (por exemplo, conjuntos de ROM Arcade)." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_SET_STANDALONE_EXEMPT, + "Excluir do menu 'Núcleos sem conteúdo'" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_SET_STANDALONE_EXEMPT, + "Impede que este núcleo seja exibido na aba/menu 'Núcleos sem conteúdo'. Aplica-se somente quando o modo de exibição é definido como 'Personalizado'." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_DELETE, "Remover núcleo" @@ -694,6 +710,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "Suporte a SDL2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Suporte a Direct3D 8" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Suporte a Direct3D 9" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Suporte a Direct3D 10" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Suporte a Direct3D 11" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Suporte a Direct3D 12" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "Suporte a GDI" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Suporte a Vulkan" @@ -774,6 +814,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "Suporte a PulseAudio" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "Suporte para PipeWire" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "Suporte a CoreAudio" @@ -854,6 +898,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Suporte a Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Suporte SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Suporte a libusb" @@ -916,6 +964,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CONTROLS, "Mapeamento de teclas" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ARTSTYLE, + "Estilo de arte" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GAMEPLAY, "Jogabilidade" @@ -924,10 +976,22 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NARRATIVE, "Narrativa" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PACING, + "Ritmo" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PERSPECTIVE, + "Perspectiva" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SETTING, "Definição" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_VEHICULAR, + "Veicular" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, "Editora" @@ -964,6 +1028,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, "Edição da revista Edge" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, + "Mês de lançamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, + "Ano de lançamento" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, "Classificação BBFC" @@ -1011,18 +1083,34 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, "Carregar configuração" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONFIGURATIONS, + "Carregar configuração existente e substituir os valores atuais." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, "Guardar configuração atual" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG, + "Substituir o arquivo de configuração atual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, "Guardar nova configuração" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVE_NEW_CONFIG, + "Salvar a configuração atual em arquivo separado." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RESET_TO_DEFAULT_CONFIG, "Repor os valores padrão" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RESET_TO_DEFAULT_CONFIG, + "Repor todas as configurações para os valores padrão." + ) /* Main Menu > Help */ @@ -1084,6 +1172,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, "Áudio" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, + "Modificar as definições de saída de som." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, "Entrada" @@ -1124,14 +1216,94 @@ MSG_HASH( MENU_ENUM_SUBLABEL_SAVING_SETTINGS, "Modificar as definições de gravação." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SETTINGS, + "Sincronização na Nuvem" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SETTINGS, + "Modificar as definições de sincronização na Nuvem." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_ENABLE, + "Ativar sincronização na Nuvem" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_ENABLE, + "Tentativa de sincronizar configurações, sram e estados para um provedor de armazenamento na Nuvem." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DESTRUCTIVE, + "Sincronia de Nuvem Destrutiva" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_SAVES, + "Sincronização: Salvas/Estados" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_CONFIGS, + "Sincronização: Ficheiros de configuração" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_THUMBS, + "Sincronização: Imagens em Miniaturas" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_SYNC_SYSTEM, + "Sincronização: Arquivos do Sistema" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_SAVES, + "Quando ativado, salvar/estados serão sincronizados para a nuvem." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_CONFIGS, + "Quando ativado, os arquivos de configuração serão sincronizados para a nuvem." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_THUMBS, + "Quando ativado, as miniaturas serão sincronizadas para a nuvem. Não é geralmente recomendado, exceto para grandes coleções de imagens em miniatura personalizadas; caso contrário, o transferidor de miniaturas é uma escolha melhor." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_SYNC_SYSTEM, + "Quando ativado, os arquivos do sistema serão sincronizados para a nuvem. Isto pode aumentar significativamente o tempo necessário para sincronizar; usar com cuidado." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_DESTRUCTIVE, + "Quando desativado, os arquivos são movidos para uma pasta de backup antes de serem substituídos ou excluídos." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_DRIVER, + "Sincronização da nuvem Backend" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_DRIVER, + "Qual protocolo de rede de armazenamento na nuvem a usar." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_URL, + "URL de armazenamento da Nuvem" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_URL, + "A URL para a entrada de API aponta para o serviço de armazenamento em nuvem." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_USERNAME, "Utilizador" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_USERNAME, + "Nome de utilizador para a conta de armazenamento na nuvem." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOUD_SYNC_PASSWORD, "Palavra-passe" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOUD_SYNC_PASSWORD, + "Senha para a conta de armazenamento na nuvem." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, "Registo" @@ -1144,10 +1316,90 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, "Explorador de ficheiros" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "Alterar definições do explorador de ficheiros." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CONFIG, + "Ficheiros de configuração." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_COMPRESSED_ARCHIVE, + "Arquivo comprimido." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_RECORD_CONFIG, + "A gravar arquivo de configuração." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CURSOR, + "Arquivo do cursor do banco de dados." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_CONFIG, + "Ficheiros de configuração." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_SHADER_PRESET, + "Arquivo de predefinição de sombreado." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_SHADER, + "Arquivo shader." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_REMAP, + "Remap do arquivo de controle." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CHEAT, + "Arquivo de cheat." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_OVERLAY, + "Arquivo de Overlay." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_RDB, + "Arquivo de banco de dados." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_FONT, + "Arquivo de fonte TrueType." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_FILE_BROWSER_PLAIN_FILE, "Ficheiro simples." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_MOVIE_OPEN, + "Vídeo. Selecione para abrir este arquivo com o reprodutor de vídeo." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_MUSIC_OPEN, + "Vídeo. Selecione para abrir este arquivo com o reprodutor de música." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_IMAGE, + "Arquivo de imagem." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_IMAGE_OPEN_WITH_VIEWER, + "Imagem. Selecione para abrir este arquivo com o reprodutor de imagem." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CORE_SELECT_FROM_COLLECTION, + "Núcleo Libretro. Selecionar isto irá associar este núcleo ao jogo." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_CORE, + "Núcleo Libretro. Selecione este arquivo para que o RetroArch carregue este núcleo." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_FILE_BROWSER_DIRECTORY, + "Diretório. Selecione-o para abrir este diretório." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, "Aceleração de fotogramas" @@ -1246,12 +1498,44 @@ MSG_HASH( ) /* Core option category placeholders for icons */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MAPPING_SETTINGS, + "Mapeamento" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MEDIA_SETTINGS, "Mídia" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PERFORMANCE_SETTINGS, + "Desempenho" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SOUND_SETTINGS, + "Som" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SPECS_SETTINGS, + "Especificações" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_STORAGE_SETTINGS, + "Armazenamento" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_SETTINGS, + "Sistema" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMING_SETTINGS, + "Temporizador" + ) #ifdef HAVE_MIST +MSG_HASH( + MENU_ENUM_SUBLABEL_STEAM_SETTINGS, + "Alterar configurações relacionadas à Steam." + ) #endif /* Settings > Drivers */ @@ -1268,10 +1552,22 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_INPUT_DRIVER_UDEV, "O driver udev lê eventos evdev para suporte de teclado. Ele também suporta callback de teclado, ratos e touchpads.\nPor padrão na maioria das distribuições, os nós /dev/input são apenas para root (modo 600). Pode configurar uma regra udev que os torna acessíveis a quem não é root." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_INPUT_DRIVER_LINUXRAW, + "O driver de entrada linuxraw requer uma TTY. Os eventos do teclado são lidos diretamente do TTY, o que o torna mais simples, mas não tão flexível quanto o udev. \"Mice, etc, não é suportado. Este driver usa a API mais antiga do joystick (/dev/input/js*)." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_INPUT_DRIVER_NO_DETAILS, + "Controlador de entrada. Dependendo do controlador de vídeo, pode forçá-lo a um controlador de entrada diferente." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, "Comando" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, + "Controlador para usar. (Requerer reiniciar)" + ) MSG_HASH( MENU_ENUM_LABEL_HELP_JOYPAD_DRIVER_DINPUT, "Controlador de DirectInput." @@ -1309,6 +1605,98 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_DRIVER, "Driver de vídeo a ser usado." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_GL1, + "Driver OpenGL 1.x. Versão mínima necessária: OpenGL 1.1. Não suporta shaders. Use drivers OpenGL mais antigos, se possível." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_GL, + "Driver OpenGL 2.x. Este driver permite que núcleos de libretro GL sejam utilizados além de núcleos renderizados por software. Versão mínima necessária: OpenGL 2.0 ou OpenGLES 2.0. Suporta o formato de shader GLSL. Use o driver glcore em vez disso, se possível." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_GL_CORE, + "Driver OpenGL 3.x. Este driver permite que núcleos de libretro GL sejam utilizados além de núcleos renderizados por software. Versão mínima necessária: OpenGL 3.2 ou OpenGLES 3.0. Suporta o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_VULKAN, + "Driver Vulkan. Este driver permite que núcleos de libretro Vulkan sejam utilizados além de núcleos renderizados por software. Versão mínima necessária: Vulkan 1.0. Suporta HDR e shaders Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_SDL1, + "Driver renderizado para o SDL 1.2. Desempenho é considerado como abaixo do ideal. Considere usá-lo apenas como último recurso." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_SDL2, + "Driver renderizado para o SDL 2. Performance para implementações libretro core renderizado é dependente da implementação de SDL da sua plataforma." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_METAL, + "Driver Metal para plataformas Apple. Suporta o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D8, + "Driver Direct3D 8 sem suporte de shader." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D9_CG, + "Driver Direct3D 9 com suporte para o formato antigo de shader Cg." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D9_HLSL, + "Driver Direct3D 9 com suporte para o formato shader HLSL." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D10, + "Driver Direct3D 10 com suporte para o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D11, + "Driver Direct3D 11 com suporte para o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_D3D12, + "Driver Direct3D 12 com suporte para HDR e o formato de shader Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_DISPMANX, + "Driver DispmanX. Usa a API DispmanX para o Videocore IV GPU no Raspberry Pi 0..3. Não há suporte para sobreposição ou shader." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_CACA, + "Driver LibCACA. Produz a saída de caracteres em vez de gráficos. Não recomendado para uso prático." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_EXYNOS, + "Um driver de vídeo Exynos de baixo nível que usa o bloco G2D em Samsung Exynos SoC para operações blit. O desempenho para núcleos renderizados de software deve ser ideal." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_DRM, + "Driver de vídeo DRM simples. Este é um driver de vídeo de baixo nível usando libdrm para escalar hardware usando camadas de GPU." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_SUNXI, + "Um driver de vídeo Sunxi de baixo nível que usa o bloco G2D em Allwinner SoCs." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_WIIU, + "Driver Wii U. Suporta shaders Slang." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_SWITCH, + "Driver Switch. Suporta o formato de shader GLSL." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_VG, + "Driver OpenVG. Usa API de gráficos para vetores 2D acelerados por hardware OpenVG." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_GDI, + "Driver GDI. Usa uma interface legada para Windows. Não recomendado." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_VIDEO_DRIVER_NO_DETAILS, + "Driver de vídeo atual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, "Áudio" @@ -1317,6 +1705,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_DRIVER, "Driver de áudio a ser usado." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_RSOUND, + "Driver RSound para sistemas de áudio em rede." + ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_OSS, + "Driver de Sistema de Som Aberto Legado." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_SL, "Driver OpenSL." @@ -4835,10 +5231,6 @@ MSG_HASH( MSG_AUTODETECT, "Auto-detetar" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto-carregar estado da gravação de" - ) MSG_HASH( MSG_CAPABILITIES, "Funcionalidades" @@ -5555,6 +5947,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "Falha no cálculo do tamanho da janela de visualização! Continuarão a serem utilizados dados em bruto. Provavelmente, irão surgir erros ..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Auto-carregar estado da gravação de" + ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, "Não configurado" diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 528e22e9b3..fdd1b07403 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -4585,7 +4585,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Разрешить обход возможностей быстрых сохранений в свойствах ядра, позволяя экспериментировать со связанными функциями (забегание, обратная перемотка и т.д.)." + "Разрешает игнорировать возможности быстрых сохранений в описании ядер, позволяя экспериментировать со связанными функциями (забегание, обратная перемотка и т.д.)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4829,7 +4829,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Автоматически создавать сохранение при закрытии контента. RetroArch будет автоматически загружать данное сохранение, если включена 'Автозагрузка сохранений'." + "Автоматически сохранять состояние при закрытии контента. Данное сохранение будет загружено при запуске, если включена опция 'Автозагрузка сохранения'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -13435,10 +13435,6 @@ MSG_HASH( MSG_AUTODETECT, "Автоопределение" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Автозагрузка сохранения из" - ) MSG_HASH( MSG_CAPABILITIES, "Возможности" @@ -14531,6 +14527,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Не удалось закрыть лоток виртуального cd-привода." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Автозагрузка сохранения из" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Ошибка автоматической загрузки сохранения состояния из \"%s\"." @@ -15783,7 +15783,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Показывает шрифт нижнего меню. Включите для отображения описания кнопок на нижнем экране. Не включает даты сохранений." + "Показывать шрифт нижнего меню. Включите для отображения описания кнопок на нижнем экране. Не включает даты быстрых сохранений." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, diff --git a/intl/msg_hash_sv.h b/intl/msg_hash_sv.h index 5fd0850100..606adb11a6 100644 --- a/intl/msg_hash_sv.h +++ b/intl/msg_hash_sv.h @@ -3851,10 +3851,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Kringgå kärninformationens funktioner för sparad status" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Anger om kärninformationens spara status-möjligheter ska ignoreras, vilket gör det möjligt att experimentera med relaterade funktioner (run ahead, spola tillbaka, etc.)." - ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4051,10 +4047,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Autospara status" ) -MSG_HASH( - MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Sparar din status automatiskt när innehållet avslutas. RetroArch kommer kunna ladda in status filen automatiskt om 'Spara din status automatiskt' är aktiverat." - ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, "Laddar automatiskt upp den sparade statusen vid spelstart." @@ -9991,10 +9983,6 @@ MSG_HASH( MSG_AUTODETECT, "Autoupptäck" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto ladda sparad status från" - ) MSG_HASH( MSG_CAPABILITIES, "Förmågor" @@ -10675,6 +10663,10 @@ MSG_HASH( MSG_VERSION_OF_LIBRETRO_API, "Version av libretro API" ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Auto ladda sparad status från" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Misslyckades med att automatiskt ladda in sparad status från \"%s\"." diff --git a/intl/msg_hash_tr.h b/intl/msg_hash_tr.h index 3f57d19d63..157c5230a9 100644 --- a/intl/msg_hash_tr.h +++ b/intl/msg_hash_tr.h @@ -4805,7 +4805,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "İçerik kapatıldığında otomatik olarak durum kaydı oluşturur. 'Durumu Otomatik Olarak Yükle' etkinse RetroArch bu durum kaydını otomatik olarak yükler." + "İçerik kapatıldığında otomatik durum kaydı oluşturun. 'Otomatik Durum Yükleme' etkinse, bu durum kaydı başlangıçta yüklenir." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -13483,10 +13483,6 @@ MSG_HASH( MSG_AUTODETECT, "Otomatik algıla" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Durum kaydından otomatik yükle" - ) MSG_HASH( MSG_CAPABILITIES, "Yetenekler" @@ -14579,6 +14575,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Sanal disk tepsisi kapatılamadı." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Durum kaydından otomatik yükle" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "\"%s\" konumundan durum kaydı otomatik olarak yüklenemedi." diff --git a/intl/msg_hash_uk.h b/intl/msg_hash_uk.h index bd97306b82..f1d04ea76c 100644 --- a/intl/msg_hash_uk.h +++ b/intl/msg_hash_uk.h @@ -914,6 +914,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Підтримка Video4Linux2" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "Підтримка SSL" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "Підтримка libusb" @@ -4569,7 +4573,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, - "Визначає, чи ігнорувати можливості резервного копіювання інформаційних заощаджень, дозволяючи експериментувати з пов'язаними особами (виконуються наперед, перемотування тощо)." + "Визначає, чи ігнорувати основні інформаційні можливості збереження штатних можливостей, дозволяючи експериментувати з пов'язаними функціями (виконуючи попереду, перемотування тощо)." ) #ifndef HAVE_DYNAMIC MSG_HASH( @@ -4813,7 +4817,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Автоматично робити стан збереження при закритому вмісті. РетроАрка автоматично завантажить цей стан збереження, якщо увімкнуто \"Завантажити стан\"." + "Автоматично відтворювати стан збереження при закритті вмісту. При ввімкнені автозавантаження - збережений стану." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, @@ -13491,10 +13495,6 @@ MSG_HASH( MSG_AUTODETECT, "Автовизначення" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Автоматичне завантаження стану збереження" - ) MSG_HASH( MSG_CAPABILITIES, "Можливості" @@ -14587,6 +14587,10 @@ MSG_HASH( MSG_VIRTUAL_DISK_TRAY_CLOSE, "Не вдалося закрити віртуальний диск лотку." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Автоматичне завантаження стану збереження" + ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FAILED, "Автозавантаження стану збереження з \"%s\" не вдалося." @@ -15827,7 +15831,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, - "Відображення шрифту в нижньому меню. Увімкніть відображення описів кнопок на нижньому екрані. Виключає дату збереження." + "Виводити шрифт нижнього меню. Увімкніть для відображення описів кнопок на нижньому екрані. Це не впливає на дату збереження." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, diff --git a/intl/msg_hash_vn.h b/intl/msg_hash_vn.h index 4f64a0f7b5..a39e17e9de 100644 --- a/intl/msg_hash_vn.h +++ b/intl/msg_hash_vn.h @@ -2515,10 +2515,6 @@ MSG_HASH( MSG_AUTODETECT, "Tự động phát hiện" ) -MSG_HASH( - MSG_AUTOLOADING_SAVESTATE_FROM, - "Đang tự đông tải savestate từ" - ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, "Đang kết nối vào máy chủ netplay" @@ -2631,6 +2627,10 @@ MSG_HASH( MSG_VIEWPORT_SIZE_CALCULATION_FAILED, "Viewport size calculation failed! Will continue using raw data. This will probably not work right ..." ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Đang tự đông tải savestate từ" + ) /* Lakka */ diff --git a/intl/progress.h b/intl/progress.h index 20f0333a4d..158248f5b7 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -19,7 +19,7 @@ #define LANGUAGE_PROGRESS_CATALAN_APPROVED 0 /* Czech */ -#define LANGUAGE_PROGRESS_CZECH_TRANSLATED 94 +#define LANGUAGE_PROGRESS_CZECH_TRANSLATED 93 #define LANGUAGE_PROGRESS_CZECH_APPROVED 0 /* Welsh */ @@ -31,7 +31,7 @@ #define LANGUAGE_PROGRESS_DANISH_APPROVED 0 /* German */ -#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_GERMAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_GERMAN_APPROVED 14 /* Greek */ @@ -91,7 +91,7 @@ #define LANGUAGE_PROGRESS_JAPANESE_APPROVED 0 /* Korean */ -#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_KOREAN_APPROVED 0 /* Dutch */ @@ -115,7 +115,7 @@ #define LANGUAGE_PROGRESS_PORTUGUESE_BRAZILIAN_APPROVED 9 /* Portuguese */ -#define LANGUAGE_PROGRESS_PORTUGUESE_TRANSLATED 26 +#define LANGUAGE_PROGRESS_PORTUGUESE_TRANSLATED 30 #define LANGUAGE_PROGRESS_PORTUGUESE_APPROVED 0 /* Russian */ @@ -131,7 +131,7 @@ #define LANGUAGE_PROGRESS_SERBIAN_LATIN_APPROVED 0 /* Swedish */ -#define LANGUAGE_PROGRESS_SWEDISH_TRANSLATED 58 +#define LANGUAGE_PROGRESS_SWEDISH_TRANSLATED 57 #define LANGUAGE_PROGRESS_SWEDISH_APPROVED 47 /* Turkish */ @@ -143,7 +143,7 @@ #define LANGUAGE_PROGRESS_TATAR_APPROVED 0 /* Ukrainian */ -#define LANGUAGE_PROGRESS_UKRAINIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_UKRAINIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_UKRAINIAN_APPROVED 7 /* Valencian */ From 9e048d8d77d9a46054ae68462e4df3c4fd16f7e0 Mon Sep 17 00:00:00 2001 From: zoltanvb <101990835+zoltanvb@users.noreply.github.com> Date: Sat, 11 Jan 2025 02:50:35 +0100 Subject: [PATCH 056/574] Reset save state index on content load, if auto index is not enabled. (#17391) --- command.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/command.c b/command.c index 4e7c72f142..d26ca11a11 100644 --- a/command.c +++ b/command.c @@ -1633,7 +1633,11 @@ void command_event_set_savestate_auto_index(settings_t *settings) unsigned max_idx = 0; bool savestate_auto_index = settings->bools.savestate_auto_index; if (!savestate_auto_index) + { + /* Reset savestate index to 0 when loading content. */ + configuration_set_int(settings, settings->ints.state_slot, 0); return; + } scan_states(settings, &max_idx, NULL); configuration_set_int(settings, settings->ints.state_slot, max_idx); RARCH_LOG("[State]: %s: #%d.\n", From fcda24be299355ffd72d399f991534fdf9a3eb5e Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Fri, 10 Jan 2025 20:51:04 -0500 Subject: [PATCH 057/574] Files in archives should always be marked as such (#17390) --- libretro-common/file/archive_file.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libretro-common/file/archive_file.c b/libretro-common/file/archive_file.c index 4df2ce51cc..0b3a6bf1c1 100644 --- a/libretro-common/file/archive_file.c +++ b/libretro-common/file/archive_file.c @@ -50,7 +50,7 @@ static int file_archive_get_file_list_cb( struct archive_extract_userdata *userdata) { union string_list_elem_attr attr; - attr.i = 0; + attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE; if (valid_exts) { @@ -80,8 +80,6 @@ static int file_archive_get_file_list_cb( string_list_deinitialize(&ext_list); return -1; } - - attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE; } string_list_deinitialize(&ext_list); From 8ef798ea5102cd56c1d9c15da95f6e3c791c1306 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Sat, 11 Jan 2025 03:51:48 +0200 Subject: [PATCH 058/574] Add human readable rotation logging (#17387) --- runloop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runloop.c b/runloop.c index 0f34c0bec2..99c5a3304a 100644 --- a/runloop.c +++ b/runloop.c @@ -1879,9 +1879,11 @@ bool runloop_environment_cb(unsigned cmd, void *data) case RETRO_ENVIRONMENT_SET_ROTATION: { unsigned rotation = *(const unsigned*)data; + unsigned rotation_v[4] = {0, 90, 180, 270}; bool video_allow_rotate = settings->bools.video_allow_rotate; - RARCH_DBG("[Environ]: SET_ROTATION: %u\n", rotation); + RARCH_DBG("[Environ]: SET_ROTATION: \"%u\" (%u deg).\n", rotation, rotation_v[rotation % 4]); + if (sys_info) sys_info->core_requested_rotation = rotation; From 62a85ae73790735edc9670f1568a4dae420bb43e Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 12 Jan 2025 00:16:13 +0000 Subject: [PATCH 059/574] Fetch translations from Crowdin --- intl/msg_hash_hu.h | 88 +++++++++++++++++++++++++++++++++++++++++++ intl/msg_hash_it.h | 12 ++++++ intl/msg_hash_pt_pt.h | 4 ++ intl/progress.h | 4 +- 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/intl/msg_hash_hu.h b/intl/msg_hash_hu.h index d0ad427d66..3d91380c35 100644 --- a/intl/msg_hash_hu.h +++ b/intl/msg_hash_hu.h @@ -706,6 +706,30 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "SDL 2 támogatás" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D8_SUPPORT, + "Direct3D 8 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D9_SUPPORT, + "Direct3D 9 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D10_SUPPORT, + "Direct3D 10 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D11_SUPPORT, + "Direct3D 11 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_D3D12_SUPPORT, + "Direct3D 12 támogatás" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GDI_SUPPORT, + "GDI támogatás" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Vulkan támogatás" @@ -786,6 +810,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "PulseAudio támogatás" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PIPEWIRE_SUPPORT, + "PipeWire támogatás" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COREAUDIO_SUPPORT, "CoreAudio támogatás" @@ -866,6 +894,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 támogatás" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SSL_SUPPORT, + "SSL támogatás" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT, "libusb támogatás" @@ -1721,6 +1753,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PULSE, "PulseAudio illesztő. Ha a rendszer PulseAudio-t használ, mindenképpen ez az illesztő ajánlott pl. az ALSA helyett." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_PIPEWIRE, + "PipeWire illesztő. Ha a rendszer PipeWire-t használ, mindenképpen ez az illesztő ajánlott pl. a PulseAudio helyett." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_JACK, "Jack Audio Connection Kit illesztő." @@ -2497,6 +2533,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_AXIS, "Egész-szorzós méretezés tengelye" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS, + "Méretezés a magasság, a szélesség, vagy mindkettő szerint. A fél lépések csak a nagyfelbontású forrásokra vonatkoznak." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_SCALING, "Egész-szorzós méretezés" @@ -2991,6 +3031,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, "Hangkésleltetés (ms)" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_LATENCY, + "A legnagyobb hangkésleltetés ezredmásodpercben. Az illesztő a tényleges késleltetést ezen érték 50%-a körül próbálja tartani. Ha a hangillesztő nem tudja a kívánt késleltetést biztosítani, az érték eltérhet." + ) #ifdef HAVE_MICROPHONE /* Settings > Audio > Input */ @@ -3207,6 +3251,26 @@ MSG_HASH( MENU_ENUM_SUBLABEL_MIXER_ACTION_VOLUME, "A hangfolyam hangereje." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_NONE, + "Állapot: nincs adat" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_STOPPED, + "Leállítva" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING, + "Lejátszás alatt" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_LOOPED, + "Lejátszás alatt (ismétlés)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL, + "Lejátszás alatt (lépés a következőre)" + ) /* Settings > Audio > Menu Sounds */ @@ -4487,6 +4551,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Maginformációs fájl mentési tulajdonságainak átlépése" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, + "A maginformációs fájl állapotmentési információinak figyelmen kívül hagyása. Így lehet kísérletezni az ezzel összefüggő funkciókkal (runahead, visszatekerés, stb.)." + ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4727,6 +4795,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Játékállás automatikus mentése" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, + "Automatikus állapotmentés a tartalom bezárásakor. Ez az állapot töltődik be indításkor, ha az \"Automatikus játékállás betöltés\" be van kapcsolva." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Automatikus játékállás betöltés" @@ -5278,6 +5350,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "A négy előlapi gomb átfedő zónáinak mérete. 100% a nyolc irányban szimmetrikus beállítás." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analóg központosítási zóna" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Ezen a zónán belüli érintéskor az analóg kar érzékelése az első érintéshez lesz viszonyítva." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Képernyőrátétek" @@ -11787,6 +11867,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_TITLE_SCREEN, "Kezdő képernyő" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QT_THUMBNAIL_LOGO, + "Logó" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_QT_ALL_PLAYLISTS, "Minden játéklista" @@ -15405,6 +15489,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Betűkészlet engedélyezése" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, + "Az alsó menü betűkészlete, a gombleírásokhoz az alsó képernyőn. Nem vonatkozik a játékállás mentés dátumára." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Betűszín, piros komponens" diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index c84c4aa6cf..ba1e56eb27 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -4487,6 +4487,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BYPASS, "Supera le informazioni del core per le informazioni del salvataggio di stato" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CORE_INFO_SAVESTATE_BYPASS, + "Specifica se ignorare le informazioni di base salvare le capacità di stato, consentendo di sperimentare con le caratteristiche correlate (eseguire avanti, riavvolgimento, ecc)." + ) #ifndef HAVE_DYNAMIC MSG_HASH( MENU_ENUM_LABEL_VALUE_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, @@ -4727,6 +4731,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, "Stato di salvataggio automatico" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, + "Crea automaticamente uno stato di salvataggio quando il contenuto è chiuso. Questo stato di salvataggio viene caricato all'avvio se 'Stato di caricamento automatico' è abilitato." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, "Carica automaticamente i salvataggi" @@ -15533,6 +15541,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_ENABLE, "Attiva Font" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BOTTOM_FONT_ENABLE, + "Visualizza il carattere del menu inferiore. Abilita per visualizzare le descrizioni dei pulsanti nella schermata inferiore. Questo esclude la data di salvataggio dello stato." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BOTTOM_FONT_COLOR_RED, "Colore rosso del font" diff --git a/intl/msg_hash_pt_pt.h b/intl/msg_hash_pt_pt.h index 87fbf2b301..5f8d182868 100644 --- a/intl/msg_hash_pt_pt.h +++ b/intl/msg_hash_pt_pt.h @@ -1713,6 +1713,10 @@ MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_OSS, "Driver de Sistema de Som Aberto Legado." ) +MSG_HASH( + MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_ALSA, + "Driver ALSA padrão." + ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_DRIVER_SL, "Driver OpenSL." diff --git a/intl/progress.h b/intl/progress.h index 158248f5b7..f7d72129d2 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -75,7 +75,7 @@ #define LANGUAGE_PROGRESS_CROATIAN_APPROVED 0 /* Hungarian */ -#define LANGUAGE_PROGRESS_HUNGARIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_HUNGARIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_HUNGARIAN_APPROVED 0 /* Indonesian */ @@ -83,7 +83,7 @@ #define LANGUAGE_PROGRESS_INDONESIAN_APPROVED 0 /* Italian */ -#define LANGUAGE_PROGRESS_ITALIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_ITALIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_ITALIAN_APPROVED 0 /* Japanese */ From f3092664229699f6647146827cbafad0b294e075 Mon Sep 17 00:00:00 2001 From: iyzsong Date: Sun, 12 Jan 2025 07:21:01 -0600 Subject: [PATCH 060/574] (Qt) Fix desktop menu crash with CHEEVOS disabled (#17400) --- ui/drivers/qt/qt_dialogs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/drivers/qt/qt_dialogs.cpp b/ui/drivers/qt/qt_dialogs.cpp index 5be93e3d3b..bdecef42e8 100644 --- a/ui/drivers/qt/qt_dialogs.cpp +++ b/ui/drivers/qt/qt_dialogs.cpp @@ -574,7 +574,9 @@ ViewOptionsDialog::ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent) : addCategory(new OnscreenDisplayCategory(this)); addCategory(new UserInterfaceCategory(mainwindow, this)); addCategory(new AIServiceCategory(this)); +#ifdef HAVE_CHEEVOS addCategory(new AchievementsCategory(this)); +#endif addCategory(new NetworkCategory(this)); addCategory(new PlaylistsCategory(this)); addCategory(new UserCategory(this)); From 1039db7bf8148e9f0d0bd24d811e61d92d7c1cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Via=C4=8Das=C5=82a=C5=AD?= Date: Sun, 12 Jan 2025 16:21:27 +0300 Subject: [PATCH 061/574] Fix Qt build (#17397) Related to #17346 --- qb/config.libs.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 2024d810d0..2e1ff7222e 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -304,11 +304,11 @@ if [ "$HAVE_QT" != 'no' ]; then check_enabled QT6NETWORK QT Qt 'Qt6Network is' user #check_enabled QT6WEBENGINE QT Qt 'Qt6Webengine is' user - if [ "$HAVE_QT6CORE" == 'yes' ] && \ - [ "$HAVE_QT6GUI" == 'yes' ] && \ - [ "$HAVE_QT6WIDGETS" == 'yes' ] && \ - [ "$HAVE_QT6CONCURRENT" == 'yes' ] && \ - [ "$HAVE_QT6NETWORK" == 'yes' ] + if [ "$HAVE_QT6CORE" = 'yes' ] && \ + [ "$HAVE_QT6GUI" = 'yes' ] && \ + [ "$HAVE_QT6WIDGETS" = 'yes' ] && \ + [ "$HAVE_QT6CONCURRENT" = 'yes' ] && \ + [ "$HAVE_QT6NETWORK" = 'yes' ] then HAVE_QT6='yes' add_define MAKEFILE HAVE_QT6 1 From e71a1620b0c648cbfbedc19c8847fffe60858431 Mon Sep 17 00:00:00 2001 From: zoltanvb <101990835+zoltanvb@users.noreply.github.com> Date: Sun, 12 Jan 2025 17:34:01 +0100 Subject: [PATCH 062/574] Update core list based on what is compiled for 1.20.0 stable version. (#17404) --- pkg/emscripten/libretro/index.html | 162 ++++++++++++++--------------- 1 file changed, 80 insertions(+), 82 deletions(-) diff --git a/pkg/emscripten/libretro/index.html b/pkg/emscripten/libretro/index.html index eae5da79f1..f4cdc5f4f6 100644 --- a/pkg/emscripten/libretro/index.html +++ b/pkg/emscripten/libretro/index.html @@ -28,96 +28,94 @@ - - - - - - - - - - - - - + + - - - - -
-
-
- - RetroArch Logo +
+ +
+ +
+
+
+ + RetroArch Logo +
-
- - - - - - - - - -
- - -
- + + + + + + + + +
+ + Become a patron +
+ diff --git a/pkg/emscripten/libretro/index.html b/pkg/emscripten/libretro/index.html index f4cdc5f4f6..9e2f41882c 100644 --- a/pkg/emscripten/libretro/index.html +++ b/pkg/emscripten/libretro/index.html @@ -1,30 +1,28 @@ - - - RetroArch Web Player - - - - - - - - - - - - - - - -
-
-
- -
- - RetroArch Logo -
-
- - - - - - - - - - + + + + + + + + + diff --git a/pkg/emscripten/libretro/libretro.css b/pkg/emscripten/libretro/libretro.css index 4d08dc2eb4..ec3d514e3d 100644 --- a/pkg/emscripten/libretro/libretro.css +++ b/pkg/emscripten/libretro/libretro.css @@ -81,12 +81,22 @@ } } -/** - * Disable the border around the player. - */ canvas.webplayer { border: none; outline: none; + width: 800px; + height: 600px; +} + +/** + * Hack to make emscripten stop messing with the canvas size while in fullscreen. + * Foiled again! + */ +:fullscreen canvas.webplayer { + min-width: 100vw; + max-width: 100vw; + min-height: 100vh; + max-height: 100vh; } textarea { diff --git a/pkg/emscripten/libretro/libretro.js b/pkg/emscripten/libretro/libretro.js index 7eda8fa194..a2fd96b8e5 100644 --- a/pkg/emscripten/libretro/libretro.js +++ b/pkg/emscripten/libretro/libretro.js @@ -6,24 +6,23 @@ var BrowserFS = BrowserFS; var afs; var initializationCount = 0; -var setImmediate; var Module = { noInitialRun: true, arguments: ["-v", "--menu"], encoder: new TextEncoder(), - message_queue:[], - message_out:[], - message_accum:"", + message_queue: [], + message_out: [], + message_accum: "", retroArchSend: function(msg) { - let bytes = this.encoder.encode(msg+"\n"); - this.message_queue.push([bytes,0]); + let bytes = this.encoder.encode(msg + "\n"); + this.message_queue.push([bytes, 0]); }, retroArchRecv: function() { let out = this.message_out.shift(); - if(out == null && this.message_accum != "") { + if (out == null && this.message_accum != "") { out = this.message_accum; this.message_accum = ""; } @@ -33,35 +32,36 @@ var Module = { function(module) { function stdin() { // Return ASCII code of character, or null if no input - while(module.message_queue.length > 0){ + while (module.message_queue.length > 0) { var msg = module.message_queue[0][0]; var index = module.message_queue[0][1]; - if(index >= msg.length) { + if (index >= msg.length) { module.message_queue.shift(); } else { - module.message_queue[0][1] = index+1; + module.message_queue[0][1] = index + 1; // assumption: msg is a uint8array return msg[index]; } } return null; } + function stdout(c) { - if(c == null) { + if (c == null) { // flush - if(module.message_accum != "") { + if (module.message_accum != "") { module.message_out.push(module.message_accum); module.message_accum = ""; } } else { let s = String.fromCharCode(c); - if(s == "\n") { - if(module.message_accum != "") { + if (s == "\n") { + if (module.message_accum != "") { module.message_out.push(module.message_accum); module.message_accum = ""; } } else { - module.message_accum = module.message_accum+s; + module.message_accum = module.message_accum + s; } } } @@ -69,88 +69,71 @@ var Module = { } ], postRun: [], - onRuntimeInitialized: function() - { - appInitialized(); - }, - print: function(text) - { - console.log(text); - }, - printErr: function(text) - { - console.error(text); - }, - canvas: document.getElementById("canvas"), + onRuntimeInitialized: function() { + appInitialized(); + }, + print: function(text) { + console.log("stdout:", text); + }, + printErr: function(text) { + console.log("stderr:", text); + }, + canvas: document.getElementById("canvas"), totalDependencies: 0, - monitorRunDependencies: function(left) - { - this.totalDependencies = Math.max(this.totalDependencies, left); - } + monitorRunDependencies: function(left) { + this.totalDependencies = Math.max(this.totalDependencies, left); + } }; -function cleanupStorage() -{ +function cleanupStorage() { localStorage.clear(); - if (BrowserFS.FileSystem.IndexedDB.isAvailable()) - { + if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { var req = indexedDB.deleteDatabase("RetroArch"); - req.onsuccess = function () { + req.onsuccess = function() { console.log("Deleted database successfully"); }; - req.onerror = function () { - console.log("Couldn't delete database"); + req.onerror = function() { + console.error("Couldn't delete database"); }; - req.onblocked = function () { - console.log("Couldn't delete database due to the operation being blocked"); + req.onblocked = function() { + console.error("Couldn't delete database due to the operation being blocked"); }; } document.getElementById("btnClean").disabled = true; } -function idbfsInit() -{ +function idbfsInit() { $('#icnLocal').removeClass('fa-globe'); $('#icnLocal').addClass('fa-spinner fa-spin'); var imfs = new BrowserFS.FileSystem.InMemory(); - if (BrowserFS.FileSystem.IndexedDB.isAvailable()) - { + if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { afs = new BrowserFS.FileSystem.AsyncMirror(imfs, - new BrowserFS.FileSystem.IndexedDB(function(e, fs) - { - if (e) - { - //fallback to imfs - afs = new BrowserFS.FileSystem.InMemory(); - console.log("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); - appInitialized(); - } - else - { - // initialize afs by copying files from async storage to sync storage. - afs.initialize(function (e) - { - if (e) - { + new BrowserFS.FileSystem.IndexedDB(function(e, fs) { + if (e) { + // fallback to imfs afs = new BrowserFS.FileSystem.InMemory(); - console.log("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); + console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); appInitialized(); + } else { + // initialize afs by copying files from async storage to sync storage. + afs.initialize(function(e) { + if (e) { + afs = new BrowserFS.FileSystem.InMemory(); + console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); + appInitialized(); + } else { + idbfsSyncComplete(); + } + }); } - else - { - idbfsSyncComplete(); - } - }); - } - }, - "RetroArch")); + }, + "RetroArch")); } } -function idbfsSyncComplete() -{ +function idbfsSyncComplete() { $('#icnLocal').removeClass('fa-spinner').removeClass('fa-spin'); $('#icnLocal').addClass('fa-check'); console.log("WEBPLAYER: idbfs setup successful"); @@ -158,69 +141,66 @@ function idbfsSyncComplete() appInitialized(); } -function appInitialized() -{ - /* Need to wait for the file system, the wasm runtime, and the zip download - to complete before enabling the Run button. */ - initializationCount++; - if (initializationCount == 3) - { - setupFileSystem("browser"); - preLoadingComplete(); - } - } +function appInitialized() { + /* Need to wait for the file system, the wasm runtime, and the zip download + to complete before enabling the Run button. */ + initializationCount++; + if (initializationCount == 3) { + setupFileSystem("browser"); + preLoadingComplete(); + } +} -function preLoadingComplete() -{ - /* Make the Preview image clickable to start RetroArch. */ - $('.webplayer-preview').addClass('loaded').click(function () { +function preLoadingComplete() { + // Make the Preview image clickable to start RetroArch. + $('.webplayer-preview').addClass('loaded').click(function() { startRetroArch(); return false; - }); - document.getElementById("btnRun").disabled = false; - $('#btnRun').removeClass('disabled'); + }); + $('#btnRun').removeClass('disabled').removeAttr("disabled").click(function() { + startRetroArch(); + return false; + }); } var zipTOC; function zipfsInit() { - // 256 MB max bundle size - let buffer = new ArrayBuffer(256*1024*1024); - let bufferView = new Uint8Array(buffer); - let idx = 0; - // bundle should be in five parts (this can be changed later) - Promise.all([fetch("assets/frontend/bundle.zip.aa"), - fetch("assets/frontend/bundle.zip.ab"), - fetch("assets/frontend/bundle.zip.ac"), - fetch("assets/frontend/bundle.zip.ad"), - fetch("assets/frontend/bundle.zip.ae") - ]).then(function(resps) { - Promise.all(resps.map((r) => r.arrayBuffer())).then(function(buffers) { - for (let buf of buffers) { - if (idx+buf.byteLength > buffer.maxByteLength) { - console.log("WEBPLAYER: error: bundle.zip is too large"); - } - bufferView.set(new Uint8Array(buf), idx, buf.byteLength); - idx += buf.byteLength; - } - BrowserFS.FileSystem.ZipFS.computeIndex(BrowserFS.BFSRequire('buffer').Buffer(new Uint8Array(buffer, 0, idx)), function(toc) { - zipTOC = toc; - appInitialized(); - }); - }) - }); + // 256 MB max bundle size + let buffer = new ArrayBuffer(256 * 1024 * 1024); + let bufferView = new Uint8Array(buffer); + let idx = 0; + // bundle should be in five parts (this can be changed later) + Promise.all([fetch("assets/frontend/bundle.zip.aa"), + fetch("assets/frontend/bundle.zip.ab"), + fetch("assets/frontend/bundle.zip.ac"), + fetch("assets/frontend/bundle.zip.ad"), + fetch("assets/frontend/bundle.zip.ae") + ]).then(function(resps) { + Promise.all(resps.map((r) => r.arrayBuffer())).then(function(buffers) { + for (let buf of buffers) { + if (idx + buf.byteLength > buffer.maxByteLength) { + console.error("WEBPLAYER: error: bundle.zip is too large"); + } + bufferView.set(new Uint8Array(buf), idx, buf.byteLength); + idx += buf.byteLength; + } + BrowserFS.FileSystem.ZipFS.computeIndex(BrowserFS.BFSRequire('buffer').Buffer(new Uint8Array(buffer, 0, idx)), function(toc) { + zipTOC = toc; + appInitialized(); + }); + }) + }); } -function setupFileSystem(backend) -{ - /* create a mountable filesystem that will server as a root - mountpoint for browserfs */ - var mfs = new BrowserFS.FileSystem.MountableFileSystem(); - /* create an XmlHttpRequest filesystem for the bundled data */ +function setupFileSystem(backend) { + // create a mountable filesystem that will server as a root mountpoint for browserfs + var mfs = new BrowserFS.FileSystem.MountableFileSystem(); + + // create an XmlHttpRequest filesystem for the bundled data var xfs1 = new BrowserFS.FileSystem.ZipFS(zipTOC); - /* create an XmlHttpRequest filesystem for core assets */ - var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest - (".index-xhr", "assets/cores/"); + // create an XmlHttpRequest filesystem for core assets + var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest(".index-xhr", "assets/cores/"); console.log("WEBPLAYER: initializing filesystem: " + backend); mfs.mount('/home/web_user/retroarch/userdata', afs); @@ -229,75 +209,81 @@ function setupFileSystem(backend) mfs.mount('/home/web_user/retroarch/userdata/content/downloads', xfs2); BrowserFS.initialize(mfs); var BFS = new BrowserFS.EmscriptenFS(Module.FS, Module.PATH, Module.ERRNO_CODES); - Module.FS.mount(BFS, {root: '/home'}, '/home'); + Module.FS.mount(BFS, { + root: '/home' + }, '/home'); console.log("WEBPLAYER: " + backend + " filesystem initialization successful"); } -/** - * Retrieve the value of the given GET parameter. - */ +// Retrieve the value of the given GET parameter. function getParam(name) { - var results = new RegExp('[?&]' + name + '=([^&#]*)').exec(window.location.href); - if (results) { - return results[1] || null; - } + var results = new RegExp('[?&]' + name + '=([^&#]*)').exec(window.location.href); + if (results) { + return results[1] || null; + } } -function startRetroArch() -{ +function startRetroArch() { $('.webplayer').show(); $('.webplayer-preview').hide(); document.getElementById("btnRun").disabled = true; - $('#btnFullscreen').removeClass('disabled'); - $('#btnMenu').removeClass('disabled'); - $('#btnAdd').removeClass('disabled'); - $('#btnRom').removeClass('disabled'); + $('#btnAdd').removeClass("disabled").removeAttr("disabled").click(function() { + $('#btnRom').click(); + }); + $('#btnRom').removeAttr("disabled").change(function(e) { + selectFiles(e.target.files); + }); + $('#btnMenu').removeClass("disabled").removeAttr("disabled").click(function() { + Module._cmd_toggle_menu(); + Module.canvas.focus(); + }); + $('#btnFullscreen').removeClass("disabled").removeAttr("disabled").click(function() { + Module.requestFullscreen(false); + Module.canvas.focus(); + }); - document.getElementById("btnAdd").disabled = false; - document.getElementById("btnRom").disabled = false; - document.getElementById("btnMenu").disabled = false; - document.getElementById("btnFullscreen").disabled = false; - - Module["canvas"] = document.getElementById("canvas"); - Module["canvas"].addEventListener("click", () => Module["canvas"].focus()); - Module['callMain'](Module['arguments']); - Module['resumeMainLoop'](); - Module['canvas'].focus(); + Module.canvas.focus(); + Module.canvas.addEventListener("pointerdown", function() { + Module.canvas.focus(); + }, false); + Module.callMain(Module.arguments); } -function selectFiles(files) -{ + +function selectFiles(files) { $('#btnAdd').addClass('disabled'); $('#icnAdd').removeClass('fa-plus'); $('#icnAdd').addClass('fa-spinner spinning'); var count = files.length; - for (var i = 0; i < count; i++) - { + for (var i = 0; i < count; i++) { filereader = new FileReader(); filereader.file_name = files[i].name; filereader.readAsArrayBuffer(files[i]); - filereader.onload = function(){uploadData(this.result, this.file_name)}; - filereader.onloadend = function(evt) - { + filereader.onload = function() { + uploadData(this.result, this.file_name) + }; + filereader.onloadend = function(evt) { console.log("WEBPLAYER: file: " + this.file_name + " upload complete"); - if (evt.target.readyState == FileReader.DONE) - { + if (evt.target.readyState == FileReader.DONE) { $('#btnAdd').removeClass('disabled'); $('#icnAdd').removeClass('fa-spinner spinning'); $('#icnAdd').addClass('fa-plus'); } - } + } } } -function uploadData(data,name) -{ +function uploadData(data, name) { var dataView = new Uint8Array(data); Module.FS.createDataFile('/', name, dataView, true, false); - var data = Module.FS.readFile(name,{ encoding: 'binary' }); - Module.FS.writeFile('/home/web_user/retroarch/userdata/content/' + name, data ,{ encoding: 'binary' }); + var data = Module.FS.readFile(name, { + encoding: 'binary' + }); + Module.FS.writeFile('/home/web_user/retroarch/userdata/content/' + name, data, { + encoding: 'binary' + }); Module.FS.unlink(name); } @@ -306,8 +292,7 @@ function switchCore(corename) { } function switchStorage(backend) { - if (backend != localStorage.getItem("backend")) - { + if (backend != localStorage.getItem("backend")) { localStorage.setItem("backend", backend); location.reload(); } @@ -315,21 +300,24 @@ function switchStorage(backend) { // When the browser has loaded everything. $(function() { - // Enable all available ToolTips. + // Enable data clear + $('#btnClean').click(function() { + cleanupStorage(); + }); + + // Enable all available ToolTips. $('.tooltip-enable').tooltip({ placement: 'right' }); // Allow hiding the top menu. $('.showMenu').hide(); - $('#btnHideMenu, .showMenu').click(function () { + $('#btnHideMenu, .showMenu').click(function() { $('nav').slideToggle('slow'); $('.showMenu').toggle('slow'); }); - /** - * Attempt to disable some default browser keys. - */ + // Attempt to disable some default browser keys. var keys = { 9: "tab", 13: "enter", @@ -351,20 +339,20 @@ $(function() { 116: "F5", 117: "F6", 118: "F7", - 119: "F8", - 120: "F9", - 121: "F10", - 122: "F11", - 123: "F12" - }; - window.addEventListener('keydown', function (e) { + 119: "F8", + 120: "F9", + 121: "F10", + 122: "F11", + 123: "F12" + }; + window.addEventListener('keydown', function(e) { if (keys[e.which]) { e.preventDefault(); } }); // Switch the core when selecting one. - $('#core-selector a').click(function () { + $('#core-selector a').click(function() { var coreChoice = $(this).data('core'); switchCore(coreChoice); }); @@ -381,8 +369,8 @@ function loadCore(core) { var coreTitle = $('#core-selector a[data-core="' + core + '"]').addClass('active').text(); $('#dropdownMenu1').text(coreTitle); // Load the Core's related JavaScript. - import("./"+core+"_libretro.js").then(script => { - script.default(Module).then(mod => { + import("./" + core + "_libretro.js").then(script => { + script.default(Module).then(mod => { Module = mod; $('#icnRun').removeClass('fa-spinner').removeClass('fa-spin'); $('#icnRun').addClass('fa-play'); @@ -390,18 +378,12 @@ function loadCore(core) { $('#lblLocal').addClass('active'); idbfsInit(); zipfsInit(); - }).catch(err => { console.error("Couldn't instantiate module",err); throw err; }); - }).catch(err => { console.error("Couldn't load script",err); throw err; }); -} - -function keyPress(k) -{ - function kp(k, event) { - var oEvent = new KeyboardEvent(event, { code: k }); - - document.dispatchEvent(oEvent); - document.getElementById('canvas').focus(); - } - kp(k, "keydown"); - setTimeout(function(){kp(k, "keyup")}, 50); -} + }).catch(err => { + console.error("Couldn't instantiate module", err); + throw err; + }); + }).catch(err => { + console.error("Couldn't load script", err); + throw err; + }); +} \ No newline at end of file diff --git a/retroarch.c b/retroarch.c index 504df5e3f3..6f01ebb8e3 100644 --- a/retroarch.c +++ b/retroarch.c @@ -3945,6 +3945,9 @@ bool command_event(enum event_command cmd, void *data) } #endif break; + case CMD_EVENT_RELOAD_CONFIG: + config_load(global_get_ptr()); + break; case CMD_EVENT_DSP_FILTER_INIT: #ifdef HAVE_DSP_FILTER { From 97803f56271b8d3cc32da9af420cb23912e775ff Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 30 Jan 2025 00:14:14 +0000 Subject: [PATCH 168/574] Fetch translations from Crowdin --- intl/msg_hash_es.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 5978310554..cbbab40ead 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -2789,7 +2789,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_FRAME_DELAY, - "Establece el tiempo de espera en milisegundos entre la ejecución del núcleo y la presentación de la imagen. Puede reducir la latencia a costa de aumentar la probabilidad de sufrir tirones de imagen.\nUn valor igual o superior a 20 se considerará como un porcentaje de la duración de fotogramas." + "Establece el tiempo de espera en milisegundos entre la ejecución del núcleo y la presentación de la imagen. Reduce la latencia a costa de aumentar la probabilidad de sufrir tirones en la imagen.\nUn valor igual o superior a 20 se considerará como un porcentaje de la duración de fotogramas." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTO, @@ -2797,7 +2797,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY_AUTO, - "Ajusta el retraso de fotogramas real de forma dinámica." + "Ajusta el 'Retraso de fotogramas' efectivo de forma dinámica." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_FRAME_DELAY_AUTO, From fd8ba559d71ac0520ae63bab7ec02956d6102830 Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Wed, 29 Jan 2025 22:06:59 -0500 Subject: [PATCH 169/574] net_http: fix memleak (#17487) --- libretro-common/net/net_http.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libretro-common/net/net_http.c b/libretro-common/net/net_http.c index eb433765cd..48092c8a99 100644 --- a/libretro-common/net/net_http.c +++ b/libretro-common/net/net_http.c @@ -968,7 +968,6 @@ struct http_t *net_http_new(struct http_connection_t *conn) state->response.buflen = 16 * 1024; state->response.data = (char*)malloc(state->response.buflen); state->response.headers = string_list_new(); - string_list_initialize(state->response.headers); return state; } From 4b5f782fe4b252d62815a02993e6f1ee0b4de92d Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Thu, 30 Jan 2025 13:57:19 -0500 Subject: [PATCH 170/574] iOS: Fix crash during scanning (#17489) --- tasks/task_database_cue.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tasks/task_database_cue.c b/tasks/task_database_cue.c index 56478ccfff..e3354ffeef 100644 --- a/tasks/task_database_cue.c +++ b/tasks/task_database_cue.c @@ -279,14 +279,19 @@ int detect_ps2_game(intfstream_t *fd, char *s, size_t len, const char *filename) #define DISC_DATA_SIZE_PS2 0x84000 int pos; char raw_game_id[50]; - char disc_data[DISC_DATA_SIZE_PS2]; + char *disc_data; /* Load data into buffer and use pointers */ if (intfstream_seek(fd, 0, SEEK_SET) < 0) return false; + disc_data = malloc(DISC_DATA_SIZE_PS2); + if (intfstream_read(fd, disc_data, DISC_DATA_SIZE_PS2) <= 0) + { + free(disc_data); return false; + } disc_data[DISC_DATA_SIZE_PS2 - 1] = '\0'; @@ -373,6 +378,7 @@ int detect_ps2_game(intfstream_t *fd, char *s, size_t len, const char *filename) string_remove_all_whitespace(s, raw_game_id); cue_append_multi_disc_suffix(s, filename); + free(disc_data); return true; } } @@ -390,6 +396,7 @@ int detect_ps2_game(intfstream_t *fd, char *s, size_t len, const char *filename) s[9 ] = 'X'; s[10] = '\0'; cue_append_multi_disc_suffix(s, filename); + free(disc_data); return false; } From cacd5a9a234f3c9abc8d352f6fea19117e2e1a00 Mon Sep 17 00:00:00 2001 From: Joe Osborn Date: Thu, 30 Jan 2025 10:58:18 -0800 Subject: [PATCH 171/574] Workerized emscripten retroarch (WIP) (#17484) * workerized RA * Workerized (non-async) web player, using OPFS This patch eliminates the need for asyncify and uses modern filesystem APIs instead of the deprecated, unmaintained BrowserFS. This is a WIP patch because it won't fully work until these two Emscripten PRs land and are released: https://github.com/emscripten-core/emscripten/pull/23518 https://github.com/emscripten-core/emscripten/pull/23021 The former fixes an offscreen canvas context recreation bug, and the latter adds an equivalent to BrowserFS's XHR filesystem (but without the hazardous running-XHR-on-the-main-thread problem). The biggest issue is that local storage of users who were using the old version of the webplayer will be gone when they switch to the new webplayer. I don't have a good story for converting the old BrowserFS IDBFS contents into the new OPFS filesystem (the move is worth doing because OPFS supports seeking and reading only bits of a file, and because BrowserFS is dead). I've kept around the old libretro webplayer under pkg/emscripten/libretro-classic, and with these make flags you can build a non-workerized RA that uses asyncify to sleep as before: make -f Makefile.emscripten libretro=$CORE HAVE_WORKER=0 HAVE_WASMFS=0 PTHREAD=0 HAVE_AL=1 I also moved the default directory for core content on emscripten to not be a subdirectory of the local filesystem mount, because it's confusing to have a subdirectory that's lazily fetched and not mirrored to the local storage. I think it won't impact existing users of the classic web player because they already have a retroarch.cfg in place. * Get fetchfs working without manifest support * makefile fixes --- Makefile.common | 5 +- Makefile.emscripten | 89 ++-- frontend/drivers/platform_emscripten.c | 7 +- gfx/drivers_context/emscriptenegl_ctx.c | 3 - gfx/drivers_context/emscriptenwebgl_ctx.c | 279 +++++++++++++ gfx/video_driver.c | 5 +- gfx/video_driver.h | 1 + input/drivers/rwebinput_input.c | 16 +- libretro-common/include/retro_timers.h | 4 +- .../browserfs.min.js | 0 pkg/emscripten/libretro-classic/index.html | 204 +++++++++ pkg/emscripten/libretro-classic/indexer | 34 ++ pkg/emscripten/libretro-classic/libretro.css | 120 ++++++ pkg/emscripten/libretro-classic/libretro.js | 389 ++++++++++++++++++ pkg/emscripten/libretro/index.html | 10 +- pkg/emscripten/libretro/libretro.js | 216 ++++------ pkg/emscripten/libretro/zip.min.js | 1 + 17 files changed, 1201 insertions(+), 182 deletions(-) create mode 100644 gfx/drivers_context/emscriptenwebgl_ctx.c rename pkg/emscripten/{libretro => libretro-classic}/browserfs.min.js (100%) create mode 100644 pkg/emscripten/libretro-classic/index.html create mode 100755 pkg/emscripten/libretro-classic/indexer create mode 100644 pkg/emscripten/libretro-classic/libretro.css create mode 100644 pkg/emscripten/libretro-classic/libretro.js create mode 100644 pkg/emscripten/libretro/zip.min.js diff --git a/Makefile.common b/Makefile.common index 2dcb7e08b4..ef2c79c445 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1526,7 +1526,10 @@ ifeq ($(HAVE_GL_CONTEXT), 1) endif ifeq ($(HAVE_EMSCRIPTEN), 1) - OBJ += gfx/drivers_context/emscriptenegl_ctx.o + ifeq ($(HAVE_EGL), 1) + OBJ += gfx/drivers_context/emscriptenegl_ctx.o + endif + OBJ += gfx/drivers_context/emscriptenwebgl_ctx.o endif ifeq ($(HAVE_MALI_FBDEV), 1) diff --git a/Makefile.emscripten b/Makefile.emscripten index 164db24cf3..414d63b748 100644 --- a/Makefile.emscripten +++ b/Makefile.emscripten @@ -24,7 +24,8 @@ HAVE_SCREENSHOTS = 1 HAVE_REWIND = 1 HAVE_AUDIOMIXER = 1 HAVE_CC_RESAMPLER = 1 -HAVE_EGL = 1 +HAVE_EGL ?= 0 +HAVE_OPENGLES = 1 HAVE_RJPEG = 0 HAVE_RPNG = 1 HAVE_EMSCRIPTEN = 1 @@ -48,6 +49,8 @@ HAVE_7ZIP = 1 HAVE_BSV_MOVIE = 1 HAVE_AL = 1 HAVE_CHD ?= 0 +HAVE_WASMFS ?= 1 +HAVE_WORKER ?= 1 # WARNING -- READ BEFORE ENABLING # The rwebaudio driver is known to have several audio bugs, such as @@ -68,7 +71,7 @@ HAVE_OPENGLES3 ?= 0 ASYNC ?= 0 LTO ?= 0 -PTHREAD ?= 0 +PTHREAD ?= 4 STACK_SIZE ?= 4194304 INITIAL_HEAP ?= 134217728 @@ -92,37 +95,20 @@ _cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focu _cmd_set_volume,_cmd_set_shader,_cmd_cheat_set_code,_cmd_cheat_get_code,_cmd_cheat_toggle_index,_cmd_cheat_get_code_state,_cmd_cheat_realloc,\ _cmd_cheat_get_size,_cmd_cheat_apply_cheats +EXPORTS := callMain,FS,PATH,ERRNO_CODES,stringToNewUTF8,UTF8ToString + LIBS := -s USE_ZLIB=1 -LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s STACK_SIZE=$(STACK_SIZE) -s INITIAL_MEMORY=$(INITIAL_HEAP) \ - -s EXPORTED_RUNTIME_METHODS=callMain,FS,PATH,ERRNO_CODES,stringToNewUTF8,UTF8ToString \ - -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="$(EXPORTED_FUNCTIONS)" \ - -s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \ - --extern-pre-js emscripten/pre.js \ - --js-library emscripten/library_rwebcam.js \ - --js-library emscripten/library_platform_emscripten.js -ifeq ($(HAVE_RWEBAUDIO), 1) - LDFLAGS += --js-library emscripten/library_rwebaudio.js - DEFINES += -DHAVE_RWEBAUDIO -endif -ifeq ($(HAVE_AL), 1) - LDFLAGS += -lopenal - DEFINES += -DHAVE_AL - override ASYNC = 1 +ifeq ($(HAVE_WASMFS), 1) + LIBS += -s WASMFS -s FORCE_FILESYSTEM=1 -lfetchfs.js -lopfs.js + EXPORTS := $(EXPORTS),FETCHFS,OPFS endif -ifneq ($(PTHREAD), 0) - LDFLAGS += -s MAXIMUM_MEMORY=1073741824 -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD) - CFLAGS += -pthread - HAVE_THREADS=1 -else - HAVE_THREADS=0 -endif - -ifeq ($(ASYNC), 1) - LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192 - ifeq ($(DEBUG), 1) - LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE +ifeq ($(HAVE_WORKER), 1) + LIBS += -s PROXY_TO_PTHREAD -s USE_ES6_IMPORT_META=0 -sENVIRONMENT=worker,web +else + ifeq ($(HAVE_AL), 1) + override ASYNC = 1 endif endif @@ -147,6 +133,45 @@ ifeq ($(HAVE_SDL2), 1) DEFINES += -DHAVE_SDL2 endif + +LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s STACK_SIZE=$(STACK_SIZE) -s INITIAL_MEMORY=$(INITIAL_HEAP) \ + -s EXPORTED_RUNTIME_METHODS=$(EXPORTS) \ + -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="$(EXPORTED_FUNCTIONS)" \ + -s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \ + -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 \ + -s OFFSCREENCANVAS_SUPPORT \ + -s OFFSCREEN_FRAMEBUFFER \ + --extern-pre-js emscripten/pre.js \ + --js-library emscripten/library_rwebcam.js \ + --js-library emscripten/library_platform_emscripten.js + +ifeq ($(HAVE_RWEBAUDIO), 1) + LDFLAGS += --js-library emscripten/library_rwebaudio.js + DEFINES += -DHAVE_RWEBAUDIO +endif + +ifeq ($(HAVE_AL), 1) + LDFLAGS += -lopenal + DEFINES += -DHAVE_AL +endif + +ifneq ($(PTHREAD), 0) + LDFLAGS += -s WASM_MEM_MAX=1073741824 -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD) + CFLAGS += -pthread -s SHARED_MEMORY + HAVE_THREADS=1 +else + HAVE_THREADS=0 +endif + + +ifeq ($(ASYNC), 1) + DEFINES += -DEMSCRIPTEN_ASYNCIFY + LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192 + ifeq ($(DEBUG), 1) + LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE + endif +endif + include Makefile.common CFLAGS += $(DEF_FLAGS) -Ideps -Ideps/stb @@ -183,8 +208,10 @@ RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) all: $(TARGET) -$(TARGET): $(RARCH_OBJ) $(libretro) - @$(if $(libretro), mv -f $(libretro) $(libretro_new),) +$(libretro_new) : $(libretro) + mv -f $(libretro) $(libretro_new) + +$(TARGET): $(RARCH_OBJ) $(libretro_new) @$(if $(Q), $(shell echo echo "LD $@ \ $(libretro_new) $(LIBS) $(LDFLAGS)"),) $(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS) diff --git a/frontend/drivers/platform_emscripten.c b/frontend/drivers/platform_emscripten.c index 0657d139ec..d4aac7183b 100644 --- a/frontend/drivers/platform_emscripten.c +++ b/frontend/drivers/platform_emscripten.c @@ -235,8 +235,8 @@ static void frontend_emscripten_get_env(int *argc, char *argv[], "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT], user_path, "content", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], user_path, - "content/downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], base_path, + "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], user_path, "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], @@ -308,7 +308,10 @@ int main(int argc, char *argv[]) specialHTMLTargets["!canvas"] = Module.canvas; }); + emscripten_set_canvas_element_size("!canvas", 800, 600); + emscripten_set_element_css_size("!canvas", 800.0, 600.0); emscripten_set_main_loop(emscripten_mainloop, 0, 0); + emscripten_set_main_loop_timing(EM_TIMING_RAF, 1); rarch_main(argc, argv, NULL); return 0; diff --git a/gfx/drivers_context/emscriptenegl_ctx.c b/gfx/drivers_context/emscriptenegl_ctx.c index 797999227c..bef3727f05 100644 --- a/gfx/drivers_context/emscriptenegl_ctx.c +++ b/gfx/drivers_context/emscriptenegl_ctx.c @@ -124,11 +124,9 @@ static void gfx_ctx_emscripten_destroy(void *data) if (!emscripten) return; - #ifdef HAVE_EGL egl_destroy(&emscripten->egl); #endif - free(data); } @@ -191,7 +189,6 @@ static void *gfx_ctx_emscripten_init(void *video_driver) #endif return emscripten; - error: gfx_ctx_emscripten_destroy(video_driver); return NULL; diff --git a/gfx/drivers_context/emscriptenwebgl_ctx.c b/gfx/drivers_context/emscriptenwebgl_ctx.c new file mode 100644 index 0000000000..dec9fc7329 --- /dev/null +++ b/gfx/drivers_context/emscriptenwebgl_ctx.c @@ -0,0 +1,279 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2012-2015 - Michael Lelli + * + * 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 + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#include "../../retroarch.h" +#include "../../verbosity.h" + +typedef struct +{ + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; + unsigned fb_width; + unsigned fb_height; +} emscripten_ctx_data_t; + +static void gfx_ctx_emscripten_webgl_swap_interval(void *data, int interval) +{ + if (interval == 0) + emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0); + else + emscripten_set_main_loop_timing(EM_TIMING_RAF, interval); +} + +static void gfx_ctx_emscripten_webgl_get_canvas_size(int *width, int *height) +{ + EmscriptenFullscreenChangeEvent fullscreen_status; + bool is_fullscreen = false; + EMSCRIPTEN_RESULT r = emscripten_get_fullscreen_status(&fullscreen_status); + + if (r == EMSCRIPTEN_RESULT_SUCCESS) + { + if (fullscreen_status.isFullscreen) + { + is_fullscreen = true; + *width = fullscreen_status.screenWidth; + *height = fullscreen_status.screenHeight; + } + } + if (!is_fullscreen) + { + double w, h; + r = emscripten_get_element_css_size("#canvas", &w, &h); + *width = (int)w; + *height = (int)h; + + if (r != EMSCRIPTEN_RESULT_SUCCESS) + { + *width = 800; + *height = 600; + RARCH_ERR("[EMSCRIPTEN/WebGL]: Could not get screen dimensions: %d\n",r); + } + } +} + +static void gfx_ctx_emscripten_webgl_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height) +{ + int input_width=0; + int input_height=0; + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + + *resize = false; + gfx_ctx_emscripten_webgl_get_canvas_size(&input_width, &input_height); + *width = (unsigned)input_width; + *height = (unsigned)input_height; + if(*width != emscripten->fb_width || *height != emscripten->fb_height) { + *resize = true; + } + emscripten->fb_width = (unsigned)*width; + emscripten->fb_height = (unsigned)*height; + *quit = false; +} + +static void gfx_ctx_emscripten_webgl_swap_buffers(void *data) +{ + emscripten_webgl_commit_frame(); +} + +static void gfx_ctx_emscripten_webgl_get_video_size(void *data, + unsigned *width, unsigned *height) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + int s_width, s_height; + if (!emscripten) + return; + gfx_ctx_emscripten_webgl_get_canvas_size(&s_width, &s_height); + *width = (unsigned)s_width; + *height = (unsigned)s_height; +} + +static void gfx_ctx_emscripten_webgl_destroy(void *data) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + + if (!emscripten) + return; + + emscripten_webgl_destroy_context(emscripten->ctx); + + free(data); +} + +static void *gfx_ctx_emscripten_webgl_init(void *video_driver) +{ + int width, height; + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*) + calloc(1, sizeof(*emscripten)); + + EmscriptenWebGLContextAttributes attrs={0}; + emscripten_webgl_init_context_attributes(&attrs); + attrs.alpha = false; + attrs.depth = true; + attrs.stencil = true; + attrs.antialias = false; + attrs.powerPreference = EM_WEBGL_POWER_PREFERENCE_HIGH_PERFORMANCE; + attrs.majorVersion = 2; + attrs.minorVersion = 2; + attrs.enableExtensionsByDefault = true; + attrs.explicitSwapControl = true; + attrs.renderViaOffscreenBackBuffer = true; + attrs.proxyContextToMainThread = EMSCRIPTEN_WEBGL_CONTEXT_PROXY_DISALLOW; + + if (!emscripten) + return NULL; + + emscripten->ctx = emscripten_webgl_create_context("#canvas", &attrs); + if(!emscripten->ctx) { + RARCH_LOG("[EMSCRIPTEN/WEBGL]: Failed to initialize webgl\n"); + goto error; + } + emscripten_webgl_get_drawing_buffer_size(emscripten->ctx, &width, &height); + emscripten_webgl_make_context_current(emscripten->ctx); + emscripten->fb_width = (unsigned)width; + emscripten->fb_height = (unsigned)height; + RARCH_LOG("[EMSCRIPTEN/WEBGL]: Dimensions: %ux%u\n", emscripten->fb_width, emscripten->fb_height); + + return emscripten; + +error: + gfx_ctx_emscripten_webgl_destroy(video_driver); + return NULL; +} + +static bool gfx_ctx_emscripten_webgl_set_video_mode(void *data, + unsigned width, unsigned height, + bool fullscreen) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + EMSCRIPTEN_RESULT r; + if(!emscripten || !emscripten->ctx) return false; + + if (width != 0 && height != 0) { + RARCH_LOG("[EMSCRIPTEN/WebGL]: set canvas size to %d, %d\n", width, height); + r = emscripten_set_canvas_element_size("#canvas", + (int)width, (int)height); + + if (r != EMSCRIPTEN_RESULT_SUCCESS) { + RARCH_ERR("[EMSCRIPTEN/WebGL]: error resizing canvas: %d\n", r); + return false; + } + } + emscripten->fb_width = width; + emscripten->fb_height = height; + + return true; +} + +bool gfx_ctx_emscripten_webgl_set_resize(void *data, unsigned width, unsigned height) { + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + EMSCRIPTEN_RESULT r; + if(!emscripten || !emscripten->ctx) return false; + RARCH_LOG("[EMSCRIPTEN/WebGL]: set canvas size to %d, %d\n", width, height); + r = emscripten_set_canvas_element_size("#canvas", + (int)width, (int)height); + if (r != EMSCRIPTEN_RESULT_SUCCESS) { + RARCH_ERR("[EMSCRIPTEN/WebGL]: error resizing canvas: %d\n", r); + return false; + } + return true; +} + +static enum gfx_ctx_api gfx_ctx_emscripten_webgl_get_api(void *data) { return GFX_CTX_OPENGL_ES_API; } + +static bool gfx_ctx_emscripten_webgl_bind_api(void *data, + enum gfx_ctx_api api, unsigned major, unsigned minor) +{ + return true; +} + +static void gfx_ctx_emscripten_webgl_input_driver(void *data, + const char *name, + input_driver_t **input, void **input_data) +{ + void *rwebinput = input_driver_init_wrap(&input_rwebinput, name); + *input = rwebinput ? &input_rwebinput : NULL; + *input_data = rwebinput; +} + +static bool gfx_ctx_emscripten_webgl_has_focus(void *data) { + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + return emscripten && emscripten->ctx; +} + +static bool gfx_ctx_emscripten_webgl_suppress_screensaver(void *data, bool enable) { return false; } + +static float gfx_ctx_emscripten_webgl_translate_aspect(void *data, + unsigned width, unsigned height) { return (float)width / height; } + +static void gfx_ctx_emscripten_webgl_bind_hw_render(void *data, bool enable) +{ + emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; + emscripten_webgl_make_context_current(emscripten->ctx); +} + +static uint32_t gfx_ctx_emscripten_webgl_get_flags(void *data) +{ + uint32_t flags = 0; + BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_GLSL); + return flags; +} + +static void gfx_ctx_emscripten_webgl_set_flags(void *data, uint32_t flags) { } + +const gfx_ctx_driver_t gfx_ctx_emscripten_webgl = { + gfx_ctx_emscripten_webgl_init, + gfx_ctx_emscripten_webgl_destroy, + gfx_ctx_emscripten_webgl_get_api, + gfx_ctx_emscripten_webgl_bind_api, + gfx_ctx_emscripten_webgl_swap_interval, + gfx_ctx_emscripten_webgl_set_video_mode, + gfx_ctx_emscripten_webgl_get_video_size, + NULL, /* get_refresh_rate */ + NULL, /* get_video_output_size */ + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + NULL, /* get_metrics */ + gfx_ctx_emscripten_webgl_translate_aspect, + NULL, /* update_title */ + gfx_ctx_emscripten_webgl_check_window, + gfx_ctx_emscripten_webgl_set_resize, /* set_resize */ + gfx_ctx_emscripten_webgl_has_focus, + gfx_ctx_emscripten_webgl_suppress_screensaver, + false, + gfx_ctx_emscripten_webgl_swap_buffers, + gfx_ctx_emscripten_webgl_input_driver, + NULL, + NULL, + NULL, + NULL, + "webgl_emscripten", + gfx_ctx_emscripten_webgl_get_flags, + gfx_ctx_emscripten_webgl_set_flags, + gfx_ctx_emscripten_webgl_bind_hw_render, + NULL, + NULL +}; diff --git a/gfx/video_driver.c b/gfx/video_driver.c index fde66068d4..00701c43b3 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -162,8 +162,11 @@ static const gfx_ctx_driver_t *gfx_ctx_gl_drivers[] = { #ifdef HAVE_OSMESA &gfx_ctx_osmesa, #endif -#ifdef EMSCRIPTEN +#if (defined(EMSCRIPTEN) && defined(HAVE_EGL)) &gfx_ctx_emscripten, +#endif +#ifdef EMSCRIPTEN + &gfx_ctx_emscripten_webgl, #endif &gfx_ctx_null, NULL diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 7dfc555d5e..7c02cd3366 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -1384,6 +1384,7 @@ extern const gfx_ctx_driver_t gfx_ctx_cgl; extern const gfx_ctx_driver_t gfx_ctx_cocoagl; extern const gfx_ctx_driver_t gfx_ctx_cocoavk; extern const gfx_ctx_driver_t gfx_ctx_emscripten; +extern const gfx_ctx_driver_t gfx_ctx_emscripten_webgl; extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; extern const gfx_ctx_driver_t gfx_ctx_khr_display; extern const gfx_ctx_driver_t gfx_ctx_gdi; diff --git a/input/drivers/rwebinput_input.c b/input/drivers/rwebinput_input.c index 67823f16e2..9ade8ecc37 100644 --- a/input/drivers/rwebinput_input.c +++ b/input/drivers/rwebinput_input.c @@ -417,7 +417,7 @@ static void *rwebinput_input_init(const char *joypad_driver) rwebinput_generate_lut(); r = emscripten_set_keydown_callback( - "!canvas", rwebinput, false, + "#canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -426,7 +426,7 @@ static void *rwebinput_input_init(const char *joypad_driver) } r = emscripten_set_keyup_callback( - "!canvas", rwebinput, false, + "#canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -435,7 +435,7 @@ static void *rwebinput_input_init(const char *joypad_driver) } r = emscripten_set_keypress_callback( - "!canvas", rwebinput, false, + "#canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -443,7 +443,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create keypress callback: %d\n", r); } - r = emscripten_set_mousedown_callback("!canvas", rwebinput, false, + r = emscripten_set_mousedown_callback("#canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -451,7 +451,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create mousedown callback: %d\n", r); } - r = emscripten_set_mouseup_callback("!canvas", rwebinput, false, + r = emscripten_set_mouseup_callback("#canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -459,7 +459,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create mouseup callback: %d\n", r); } - r = emscripten_set_mousemove_callback("!canvas", rwebinput, false, + r = emscripten_set_mousemove_callback("#canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -468,7 +468,7 @@ static void *rwebinput_input_init(const char *joypad_driver) } r = emscripten_set_wheel_callback( - "!canvas", rwebinput, false, + "#canvas", rwebinput, false, rwebinput_wheel_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -819,7 +819,7 @@ static void rwebinput_input_poll(void *data) static void rwebinput_grab_mouse(void *data, bool state) { if (state) - emscripten_request_pointerlock("!canvas", EM_TRUE); + emscripten_request_pointerlock("#canvas", EM_TRUE); else emscripten_exit_pointerlock(); } diff --git a/libretro-common/include/retro_timers.h b/libretro-common/include/retro_timers.h index 96041255a3..e519ad617f 100644 --- a/libretro-common/include/retro_timers.h +++ b/libretro-common/include/retro_timers.h @@ -39,7 +39,7 @@ #include #elif defined(_3DS) #include <3ds.h> -#elif defined(EMSCRIPTEN) +#elif (defined(EMSCRIPTEN) && defined(EMSCRIPTEN_ASYNCIFY)) #include #else #include @@ -100,7 +100,7 @@ static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp) #define retro_sleep(msec) (usleep(1000 * (msec))) #elif defined(WIIU) #define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec)))) -#elif defined(EMSCRIPTEN) +#elif defined(EMSCRIPTEN) && defined(EMSCRIPTEN_ASYNCIFY) #define retro_sleep(msec) (emscripten_sleep(msec)) #else static INLINE void retro_sleep(unsigned msec) diff --git a/pkg/emscripten/libretro/browserfs.min.js b/pkg/emscripten/libretro-classic/browserfs.min.js similarity index 100% rename from pkg/emscripten/libretro/browserfs.min.js rename to pkg/emscripten/libretro-classic/browserfs.min.js diff --git a/pkg/emscripten/libretro-classic/index.html b/pkg/emscripten/libretro-classic/index.html new file mode 100644 index 0000000000..9e2f41882c --- /dev/null +++ b/pkg/emscripten/libretro-classic/index.html @@ -0,0 +1,204 @@ + + + + + RetroArch Web Player + + + + + + + + + + + + + +
+
+
+ +
+ + RetroArch Logo +
+
+ + + + + + + + + + diff --git a/pkg/emscripten/libretro-classic/indexer b/pkg/emscripten/libretro-classic/indexer new file mode 100755 index 0000000000..5544f481cb --- /dev/null +++ b/pkg/emscripten/libretro-classic/indexer @@ -0,0 +1,34 @@ +#! /usr/bin/env coffee + +fs = require 'fs' +path = require 'path' + +symLinks = {} + +rdSync = (dpath, tree, name) -> + files = fs.readdirSync(dpath) + for file in files + # ignore non-essential directories / files + continue if file in ['.git', 'node_modules', 'bower_components', 'build'] or file[0] is '.' + fpath = dpath + '/' + file + try + # Avoid infinite loops. + lstat = fs.lstatSync(fpath) + if lstat.isSymbolicLink() + symLinks[lstat.dev] ?= {} + # Ignore if we've seen it before + continue if symLinks[lstat.dev][lstat.ino]? + symLinks[lstat.dev][lstat.ino] = 0 + + fstat = fs.statSync(fpath) + if fstat.isDirectory() + tree[file] = child = {} + rdSync(fpath, child, file) + else + tree[file] = null + catch e + # Ignore and move on. + return tree + +fs_listing = rdSync(process.cwd(), {}, '/') +console.log(JSON.stringify(fs_listing)) diff --git a/pkg/emscripten/libretro-classic/libretro.css b/pkg/emscripten/libretro-classic/libretro.css new file mode 100644 index 0000000000..4d08dc2eb4 --- /dev/null +++ b/pkg/emscripten/libretro-classic/libretro.css @@ -0,0 +1,120 @@ +/** + * RetroArch Web Player + * + * This provides the basic styling for the RetroArch web player. + */ + +/** + * Make sure the background of the player is black. + * Also make sure line height is 0 so there's no extra space on the bottom. + */ +.webplayer-container { + background-color: black; + line-height: 0; +} + +/** + * Webplayer Preview when not loaded. + */ +.webplayer-preview { + margin: 0 auto; + cursor: wait; + opacity: 0.2; + transition: all 0.8s; + -webkit-animation: loading 0.8s ease-in-out infinite alternate; + -moz-animation: loading 0.8s ease-in-out infinite alternate; + animation: loading 0.8s ease-in-out infinite alternate; +} +.webplayer-preview.loaded { + cursor: pointer; + opacity: 1; + -webkit-animation: loaded 0.8s ease-in-out; + -moz-animation: loaded 0.8s ease-in-out; + animation: loaded 0.8s ease-in-out; +} +@keyframes loaded { + from { + opacity: 0.2; + } + to { + opacity: 1; + } +} +@-moz-keyframes loaded { + from { + opacity: 0.2; + } + to { + opacity: 1; + } +} +@-webkit-keyframes loaded { + from { + opacity: 0.2; + } + to { + opacity: 1; + } +} +@keyframes loading{ + from { + opacity: 0.2; + } + to { + opacity: 0.35; + } +} +@-moz-keyframes loading{ + from { + opacity: 0.2; + } + to { + opacity: 0.35; + } +} +@-webkit-keyframes loading { + from { + opacity: 0.2; + } + to { + opacity: 0.35; + } +} + +/** + * Disable the border around the player. + */ +canvas.webplayer { + border: none; + outline: none; +} + +textarea { + font-family: monospace; + font-size: 0.7em; + height: 95%; + width: 95%; + border-style: none; + border-color: transparent; + overflow: auto; + resize: none; +} + +/** + * Toggle Top Navigation + */ +.toggleMenu { + float: right; +} +.showMenu { + position: absolute; + right: 0; + cursor: pointer; +} +#icnShowMenu { + color: #565656 !important; +} + +.navbar { + box-shadow: none; +} diff --git a/pkg/emscripten/libretro-classic/libretro.js b/pkg/emscripten/libretro-classic/libretro.js new file mode 100644 index 0000000000..f0c07a341a --- /dev/null +++ b/pkg/emscripten/libretro-classic/libretro.js @@ -0,0 +1,389 @@ +/** + * RetroArch Web Player + * + * This provides the basic JavaScript for the RetroArch web player. + */ +var BrowserFS = BrowserFS; +var afs; +var initializationCount = 0; + +var Module = { + noInitialRun: true, + arguments: ["-v", "--menu"], + + encoder: new TextEncoder(), + message_queue: [], + message_out: [], + message_accum: "", + + retroArchSend: function(msg) { + let bytes = this.encoder.encode(msg + "\n"); + this.message_queue.push([bytes, 0]); + }, + retroArchRecv: function() { + let out = this.message_out.shift(); + if (out == null && this.message_accum != "") { + out = this.message_accum; + this.message_accum = ""; + } + return out; + }, + preRun: [ + function(module) { + function stdin() { + // Return ASCII code of character, or null if no input + while (module.message_queue.length > 0) { + var msg = module.message_queue[0][0]; + var index = module.message_queue[0][1]; + if (index >= msg.length) { + module.message_queue.shift(); + } else { + module.message_queue[0][1] = index + 1; + // assumption: msg is a uint8array + return msg[index]; + } + } + return null; + } + + function stdout(c) { + if (c == null) { + // flush + if (module.message_accum != "") { + module.message_out.push(module.message_accum); + module.message_accum = ""; + } + } else { + let s = String.fromCharCode(c); + if (s == "\n") { + if (module.message_accum != "") { + module.message_out.push(module.message_accum); + module.message_accum = ""; + } + } else { + module.message_accum = module.message_accum + s; + } + } + } + module.FS.init(stdin, stdout); + } + ], + postRun: [], + onRuntimeInitialized: function() { + appInitialized(); + }, + print: function(text) { + console.log("stdout:", text); + }, + printErr: function(text) { + console.log("stderr:", text); + }, + canvas: document.getElementById("canvas"), + totalDependencies: 0, + monitorRunDependencies: function(left) { + this.totalDependencies = Math.max(this.totalDependencies, left); + } +}; + + +function cleanupStorage() { + localStorage.clear(); + if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { + var req = indexedDB.deleteDatabase("RetroArch"); + req.onsuccess = function() { + console.log("Deleted database successfully"); + }; + req.onerror = function() { + console.error("Couldn't delete database"); + }; + req.onblocked = function() { + console.error("Couldn't delete database due to the operation being blocked"); + }; + } + + document.getElementById("btnClean").disabled = true; +} + +function idbfsInit() { + $('#icnLocal').removeClass('fa-globe'); + $('#icnLocal').addClass('fa-spinner fa-spin'); + var imfs = new BrowserFS.FileSystem.InMemory(); + if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { + afs = new BrowserFS.FileSystem.AsyncMirror(imfs, + new BrowserFS.FileSystem.IndexedDB(function(e, fs) { + if (e) { + // fallback to imfs + afs = new BrowserFS.FileSystem.InMemory(); + console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); + appInitialized(); + } else { + // initialize afs by copying files from async storage to sync storage. + afs.initialize(function(e) { + if (e) { + afs = new BrowserFS.FileSystem.InMemory(); + console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); + appInitialized(); + } else { + idbfsSyncComplete(); + } + }); + } + }, + "RetroArch")); + } +} + +function idbfsSyncComplete() { + $('#icnLocal').removeClass('fa-spinner').removeClass('fa-spin'); + $('#icnLocal').addClass('fa-check'); + console.log("WEBPLAYER: idbfs setup successful"); + + appInitialized(); +} + +function appInitialized() { + /* Need to wait for the file system, the wasm runtime, and the zip download + to complete before enabling the Run button. */ + initializationCount++; + if (initializationCount == 3) { + setupFileSystem("browser"); + preLoadingComplete(); + } +} + +function preLoadingComplete() { + // Make the Preview image clickable to start RetroArch. + $('.webplayer-preview').addClass('loaded').click(function() { + startRetroArch(); + return false; + }); + $('#btnRun').removeClass('disabled').removeAttr("disabled").click(function() { + startRetroArch(); + return false; + }); +} + +var zipTOC; + +function zipfsInit() { + // 256 MB max bundle size + let buffer = new ArrayBuffer(256 * 1024 * 1024); + let bufferView = new Uint8Array(buffer); + let idx = 0; + // bundle should be in five parts (this can be changed later) + Promise.all([fetch("assets/frontend/bundle.zip.aa"), + fetch("assets/frontend/bundle.zip.ab"), + fetch("assets/frontend/bundle.zip.ac"), + fetch("assets/frontend/bundle.zip.ad"), + fetch("assets/frontend/bundle.zip.ae") + ]).then(function(resps) { + Promise.all(resps.map((r) => r.arrayBuffer())).then(function(buffers) { + for (let buf of buffers) { + if (idx + buf.byteLength > buffer.maxByteLength) { + console.error("WEBPLAYER: error: bundle.zip is too large"); + } + bufferView.set(new Uint8Array(buf), idx, buf.byteLength); + idx += buf.byteLength; + } + BrowserFS.FileSystem.ZipFS.computeIndex(BrowserFS.BFSRequire('buffer').Buffer(new Uint8Array(buffer, 0, idx)), function(toc) { + zipTOC = toc; + appInitialized(); + }); + }) + }); +} + +function setupFileSystem(backend) { + // create a mountable filesystem that will server as a root mountpoint for browserfs + var mfs = new BrowserFS.FileSystem.MountableFileSystem(); + + // create an XmlHttpRequest filesystem for the bundled data + var xfs1 = new BrowserFS.FileSystem.ZipFS(zipTOC); + // create an XmlHttpRequest filesystem for core assets + var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest(".index-xhr", "assets/cores/"); + + console.log("WEBPLAYER: initializing filesystem: " + backend); + mfs.mount('/home/web_user/retroarch/userdata', afs); + + mfs.mount('/home/web_user/retroarch/', xfs1); + mfs.mount('/home/web_user/retroarch/userdata/content/downloads', xfs2); + BrowserFS.initialize(mfs); + var BFS = new BrowserFS.EmscriptenFS(Module.FS, Module.PATH, Module.ERRNO_CODES); + Module.FS.mount(BFS, { + root: '/home' + }, '/home'); + console.log("WEBPLAYER: " + backend + " filesystem initialization successful"); +} + +// Retrieve the value of the given GET parameter. +function getParam(name) { + var results = new RegExp('[?&]' + name + '=([^&#]*)').exec(window.location.href); + if (results) { + return results[1] || null; + } +} + +function startRetroArch() { + $('.webplayer').show(); + $('.webplayer-preview').hide(); + document.getElementById("btnRun").disabled = true; + + $('#btnAdd').removeClass("disabled").removeAttr("disabled").click(function() { + $('#btnRom').click(); + }); + $('#btnRom').removeAttr("disabled").change(function(e) { + selectFiles(e.target.files); + }); + $('#btnMenu').removeClass("disabled").removeAttr("disabled").click(function() { + Module._cmd_toggle_menu(); + Module.canvas.focus(); + }); + $('#btnFullscreen').removeClass("disabled").removeAttr("disabled").click(function() { + Module.requestFullscreen(false); + Module.canvas.focus(); + }); + + Module.canvas.focus(); + Module.canvas.addEventListener("pointerdown", function() { + Module.canvas.focus(); + }, false); + Module.callMain(Module.arguments); +} + +function selectFiles(files) { + $('#btnAdd').addClass('disabled'); + $('#icnAdd').removeClass('fa-plus'); + $('#icnAdd').addClass('fa-spinner spinning'); + var count = files.length; + + for (var i = 0; i < count; i++) { + filereader = new FileReader(); + filereader.file_name = files[i].name; + filereader.readAsArrayBuffer(files[i]); + filereader.onload = function() { + uploadData(this.result, this.file_name) + }; + filereader.onloadend = function(evt) { + console.log("WEBPLAYER: file: " + this.file_name + " upload complete"); + if (evt.target.readyState == FileReader.DONE) { + $('#btnAdd').removeClass('disabled'); + $('#icnAdd').removeClass('fa-spinner spinning'); + $('#icnAdd').addClass('fa-plus'); + } + } + } +} + +function uploadData(data, name) { + var dataView = new Uint8Array(data); + Module.FS.createDataFile('/', name, dataView, true, false); + + var data = Module.FS.readFile(name, { + encoding: 'binary' + }); + Module.FS.writeFile('/home/web_user/retroarch/userdata/content/' + name, data, { + encoding: 'binary' + }); + Module.FS.unlink(name); +} + +function switchCore(corename) { + localStorage.setItem("core", corename); +} + +function switchStorage(backend) { + if (backend != localStorage.getItem("backend")) { + localStorage.setItem("backend", backend); + location.reload(); + } +} + +// When the browser has loaded everything. +$(function() { + // Enable data clear + $('#btnClean').click(function() { + cleanupStorage(); + }); + + // Enable all available ToolTips. + $('.tooltip-enable').tooltip({ + placement: 'right' + }); + + // Allow hiding the top menu. + $('.showMenu').hide(); + $('#btnHideMenu, .showMenu').click(function() { + $('nav').slideToggle('slow'); + $('.showMenu').toggle('slow'); + }); + + // Attempt to disable some default browser keys. + var keys = { + 9: "tab", + 13: "enter", + 16: "shift", + 18: "alt", + 27: "esc", + 33: "rePag", + 34: "avPag", + 35: "end", + 36: "home", + 37: "left", + 38: "up", + 39: "right", + 40: "down", + 112: "F1", + 113: "F2", + 114: "F3", + 115: "F4", + 116: "F5", + 117: "F6", + 118: "F7", + 119: "F8", + 120: "F9", + 121: "F10", + 122: "F11", + 123: "F12" + }; + window.addEventListener('keydown', function(e) { + if (keys[e.which]) { + e.preventDefault(); + } + }); + + // Switch the core when selecting one. + $('#core-selector a').click(function() { + var coreChoice = $(this).data('core'); + switchCore(coreChoice); + }); + // Find which core to load. + var core = localStorage.getItem("core", core); + if (!core) { + core = 'gambatte'; + } + loadCore(core); +}); + +function loadCore(core) { + // Make the core the selected core in the UI. + var coreTitle = $('#core-selector a[data-core="' + core + '"]').addClass('active').text(); + $('#dropdownMenu1').text(coreTitle); + // Load the Core's related JavaScript. + import("./" + core + "_libretro.js").then(script => { + script.default(Module).then(mod => { + Module = mod; + $('#icnRun').removeClass('fa-spinner').removeClass('fa-spin'); + $('#icnRun').addClass('fa-play'); + $('#lblDrop').removeClass('active'); + $('#lblLocal').addClass('active'); + idbfsInit(); + zipfsInit(); + }).catch(err => { + console.error("Couldn't instantiate module", err); + throw err; + }); + }).catch(err => { + console.error("Couldn't load script", err); + throw err; + }); +} diff --git a/pkg/emscripten/libretro/index.html b/pkg/emscripten/libretro/index.html index 9e2f41882c..b1846f5985 100644 --- a/pkg/emscripten/libretro/index.html +++ b/pkg/emscripten/libretro/index.html @@ -192,13 +192,13 @@ RetroArch Logo - - - - + + + + - + diff --git a/pkg/emscripten/libretro/libretro.js b/pkg/emscripten/libretro/libretro.js index a2fd96b8e5..788aca3054 100644 --- a/pkg/emscripten/libretro/libretro.js +++ b/pkg/emscripten/libretro/libretro.js @@ -3,9 +3,8 @@ * * This provides the basic JavaScript for the RetroArch web player. */ -var BrowserFS = BrowserFS; -var afs; -var initializationCount = 0; +var retroarch_ready = false; +var setImmediate; var Module = { noInitialRun: true, @@ -70,6 +69,7 @@ var Module = { ], postRun: [], onRuntimeInitialized: function() { + retroarch_ready = true; appInitialized(); }, print: function(text) { @@ -86,70 +86,22 @@ var Module = { }; -function cleanupStorage() { - localStorage.clear(); - if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { - var req = indexedDB.deleteDatabase("RetroArch"); - req.onsuccess = function() { - console.log("Deleted database successfully"); - }; - req.onerror = function() { - console.error("Couldn't delete database"); - }; - req.onblocked = function() { - console.error("Couldn't delete database due to the operation being blocked"); - }; - } - - document.getElementById("btnClean").disabled = true; +async function cleanupStorage() +{ + localStorage.clear(); + let storage = await navigator.storage.getDirectory(); + await storage.remove({recursive: true}); + document.getElementById("btnClean").disabled = true; } -function idbfsInit() { - $('#icnLocal').removeClass('fa-globe'); - $('#icnLocal').addClass('fa-spinner fa-spin'); - var imfs = new BrowserFS.FileSystem.InMemory(); - if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { - afs = new BrowserFS.FileSystem.AsyncMirror(imfs, - new BrowserFS.FileSystem.IndexedDB(function(e, fs) { - if (e) { - // fallback to imfs - afs = new BrowserFS.FileSystem.InMemory(); - console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); - appInitialized(); - } else { - // initialize afs by copying files from async storage to sync storage. - afs.initialize(function(e) { - if (e) { - afs = new BrowserFS.FileSystem.InMemory(); - console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); - appInitialized(); - } else { - idbfsSyncComplete(); - } - }); - } - }, - "RetroArch")); - } -} - -function idbfsSyncComplete() { - $('#icnLocal').removeClass('fa-spinner').removeClass('fa-spin'); - $('#icnLocal').addClass('fa-check'); - console.log("WEBPLAYER: idbfs setup successful"); - - appInitialized(); -} - -function appInitialized() { - /* Need to wait for the file system, the wasm runtime, and the zip download - to complete before enabling the Run button. */ - initializationCount++; - if (initializationCount == 3) { - setupFileSystem("browser"); - preLoadingComplete(); - } -} +function appInitialized() +{ + /* Need to wait for the wasm runtime to load before enabling the Run button. */ + if (retroarch_ready) + { + setupFileSystem().then(() => { preLoadingComplete(); }); + } + } function preLoadingComplete() { // Make the Preview image clickable to start RetroArch. @@ -163,56 +115,63 @@ function preLoadingComplete() { }); } -var zipTOC; - -function zipfsInit() { - // 256 MB max bundle size - let buffer = new ArrayBuffer(256 * 1024 * 1024); - let bufferView = new Uint8Array(buffer); - let idx = 0; - // bundle should be in five parts (this can be changed later) - Promise.all([fetch("assets/frontend/bundle.zip.aa"), - fetch("assets/frontend/bundle.zip.ab"), - fetch("assets/frontend/bundle.zip.ac"), - fetch("assets/frontend/bundle.zip.ad"), - fetch("assets/frontend/bundle.zip.ae") - ]).then(function(resps) { - Promise.all(resps.map((r) => r.arrayBuffer())).then(function(buffers) { - for (let buf of buffers) { - if (idx + buf.byteLength > buffer.maxByteLength) { - console.error("WEBPLAYER: error: bundle.zip is too large"); - } - bufferView.set(new Uint8Array(buf), idx, buf.byteLength); - idx += buf.byteLength; - } - BrowserFS.FileSystem.ZipFS.computeIndex(BrowserFS.BFSRequire('buffer').Buffer(new Uint8Array(buffer, 0, idx)), function(toc) { - zipTOC = toc; - appInitialized(); - }); - }) - }); +async function setupZipFS(mount) { + let buffers = await Promise.all([ + fetch("assets/frontend/bundle.zip.aa").then((r) => r.arrayBuffer()), + fetch("assets/frontend/bundle.zip.ab").then((r) => r.arrayBuffer()), + fetch("assets/frontend/bundle.zip.ac").then((r) => r.arrayBuffer()), + fetch("assets/frontend/bundle.zip.ad").then((r) => r.arrayBuffer()) + ]); + let buffer = new ArrayBuffer(256*1024*1024); + let bufferView = new Uint8Array(buffer); + let idx = 0; + for (let buf of buffers) { + if (idx+buf.byteLength > buffer.maxByteLength) { + console.log("WEBPLAYER: error: bundle.zip is too large"); + } + bufferView.set(new Uint8Array(buf), idx, buf.byteLength); + idx += buf.byteLength; + } + const zipBuf = new Uint8Array(buffer, 0, idx); + const zipReader = new zip.ZipReader(new zip.Uint8ArrayReader(zipBuf), {useWebWorkers:false}); + const entries = await zipReader.getEntries(); + for(const file of entries) { + if (file.getData && !file.directory) { + const writer = new zip.Uint8ArrayWriter(); + const data = await file.getData(writer); + Module.FS.createPreloadedFile(mount+"/"+file.filename, undefined, data, true, true); + } else if (file.directory) { + Module.FS.mkdirTree(mount+"/"+file.filename); + } + } + await zipReader.close(); } -function setupFileSystem(backend) { - // create a mountable filesystem that will server as a root mountpoint for browserfs - var mfs = new BrowserFS.FileSystem.MountableFileSystem(); +function loadIndex(index, path) { + for (const key of Object.keys(index)) { + if (index[key]) { + Module.FS.mkdirTree(path+key+"/"); + loadIndex(index[key], path+key+"/"); + } else { + Module.FS.open(path+key, "w+"); + } + } +} - // create an XmlHttpRequest filesystem for the bundled data - var xfs1 = new BrowserFS.FileSystem.ZipFS(zipTOC); - // create an XmlHttpRequest filesystem for core assets - var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest(".index-xhr", "assets/cores/"); +async function setupFileSystem() +{ + Module.FS.mkdirTree("/home/web_user/retroarch/userdata"); - console.log("WEBPLAYER: initializing filesystem: " + backend); - mfs.mount('/home/web_user/retroarch/userdata', afs); + Module.FS.mount(Module.OPFS, {}, "/home/web_user/retroarch/userdata"); + + Module.FS.mkdir("/home/web_user/retroarch/downloads",700); + let index = await (await fetch("assets/cores/.index-xhr")).json(); + let manifest = {}; + Module.FS.mount(Module.FETCHFS, {"base_url":"assets/cores"}, "/home/web_user/retroarch/downloads"); + loadIndex(index, "/home/web_user/retroarch/downloads/"); - mfs.mount('/home/web_user/retroarch/', xfs1); - mfs.mount('/home/web_user/retroarch/userdata/content/downloads', xfs2); - BrowserFS.initialize(mfs); - var BFS = new BrowserFS.EmscriptenFS(Module.FS, Module.PATH, Module.ERRNO_CODES); - Module.FS.mount(BFS, { - root: '/home' - }, '/home'); - console.log("WEBPLAYER: " + backend + " filesystem initialization successful"); + setupZipFS("/home/web_user/retroarch"); + console.log("WEBPLAYER: filesystem initialization successful"); } // Retrieve the value of the given GET parameter. @@ -242,7 +201,6 @@ function startRetroArch() { Module.requestFullscreen(false); Module.canvas.focus(); }); - Module.canvas.focus(); Module.canvas.addEventListener("pointerdown", function() { Module.canvas.focus(); @@ -364,26 +322,26 @@ $(function() { loadCore(core); }); +async function downloadScript(src) { + let resp = await fetch(src); + let blob = await resp.blob(); + return blob; +} + function loadCore(core) { // Make the core the selected core in the UI. var coreTitle = $('#core-selector a[data-core="' + core + '"]').addClass('active').text(); $('#dropdownMenu1').text(coreTitle); - // Load the Core's related JavaScript. - import("./" + core + "_libretro.js").then(script => { - script.default(Module).then(mod => { - Module = mod; - $('#icnRun').removeClass('fa-spinner').removeClass('fa-spin'); - $('#icnRun').addClass('fa-play'); - $('#lblDrop').removeClass('active'); - $('#lblLocal').addClass('active'); - idbfsInit(); - zipfsInit(); - }).catch(err => { - console.error("Couldn't instantiate module", err); - throw err; - }); - }).catch(err => { - console.error("Couldn't load script", err); - throw err; + downloadScript("./"+core+"_libretro.js").then(scriptBlob => { + Module.mainScriptUrlOrBlob = scriptBlob; + import(URL.createObjectURL(scriptBlob)).then(script => { + script.default(Module).then(mod => { + Module = mod; + $('#icnRun').removeClass('fa-spinner').removeClass('fa-spin'); + $('#icnRun').addClass('fa-play'); + $('#lblDrop').removeClass('active'); + $('#lblLocal').addClass('active'); + }).catch(err => { console.error("Couldn't instantiate module",err); throw err; }); + }).catch(err => { console.error("Couldn't load script",err); throw err; }); }); -} \ No newline at end of file +} diff --git a/pkg/emscripten/libretro/zip.min.js b/pkg/emscripten/libretro/zip.min.js new file mode 100644 index 0000000000..8fa7801643 --- /dev/null +++ b/pkg/emscripten/libretro/zip.min.js @@ -0,0 +1 @@ +((e,t)=>{"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).zip={})})(this,(function(e){"use strict";const{Array:t,Object:n,String:r,Number:s,BigInt:i,Math:a,Date:o,Map:c,Set:l,Response:u,URL:f,Error:d,Uint8Array:w,Uint16Array:p,Uint32Array:h,DataView:g,Blob:m,Promise:y,TextEncoder:b,TextDecoder:S,document:k,crypto:z,btoa:v,TransformStream:x,ReadableStream:A,WritableStream:C,CompressionStream:_,DecompressionStream:D,navigator:W,Worker:R}="undefined"!=typeof globalThis?globalThis:this||self;var F=void 0!==k?k.currentScript:null;const E=4294967295,T=65535,L=67324752,U=134695760,I=U,N=33639248,q=101010256,O=101075792,P=117853008,H=22,M=21589,B=2048,V="/",Z=new o(2107,11,31),K=new o(1980,0,1),G=void 0,X="undefined",Y="function";class j{constructor(e){return class extends x{constructor(t,n){const r=new e(n);super({transform(e,t){t.enqueue(r.append(e))},flush(e){const t=r.flush();t&&e.enqueue(t)}})}}}}let J=2;try{typeof W!=X&&W.hardwareConcurrency&&(J=W.hardwareConcurrency)}catch(e){}const Q={chunkSize:524288,maxWorkers:J,terminateWorkerTimeout:5e3,useWebWorkers:!0,useCompressionStream:!0,workerScripts:G,CompressionStreamNative:typeof _!=X&&_,DecompressionStreamNative:typeof D!=X&&D},$=n.assign({},Q);function ee(){return $}function te(e){return a.max(e.chunkSize,64)}function ne(e){const{baseURL:n,chunkSize:r,maxWorkers:s,terminateWorkerTimeout:i,useCompressionStream:a,useWebWorkers:o,Deflate:c,Inflate:l,CompressionStream:u,DecompressionStream:f,workerScripts:w}=e;if(re("baseURL",n),re("chunkSize",r),re("maxWorkers",s),re("terminateWorkerTimeout",i),re("useCompressionStream",a),re("useWebWorkers",o),c&&($.CompressionStream=new j(c)),l&&($.DecompressionStream=new j(l)),re("CompressionStream",u),re("DecompressionStream",f),w!==G){const{deflate:e,inflate:n}=w;if((e||n)&&($.workerScripts||($.workerScripts={})),e){if(!t.isArray(e))throw new d("workerScripts.deflate must be an array");$.workerScripts.deflate=e}if(n){if(!t.isArray(n))throw new d("workerScripts.inflate must be an array");$.workerScripts.inflate=n}}}function re(e,t){t!==G&&($[e]=t)}function se(e,t,r){return class{constructor(s){const i=this;var a,o;a=s,o="level",(typeof n.hasOwn===Y?n.hasOwn(a,o):a.hasOwnProperty(o))&&s.level===G&&delete s.level,i.codec=new e(n.assign({},t,s)),r(i.codec,(e=>{if(i.pendingData){const t=i.pendingData;i.pendingData=new w(t.length+e.length);const{pendingData:n}=i;n.set(t,0),n.set(e,t.length)}else i.pendingData=new w(e)}))}append(e){return this.codec.push(e),s(this)}flush(){return this.codec.push(new w,!0),s(this)}};function s(e){if(e.pendingData){const t=e.pendingData;return e.pendingData=null,t}return new w}}const ie=[];for(let e=0;256>e;e++){let t=e;for(let e=0;8>e;e++)1&t?t=t>>>1^3988292384:t>>>=1;ie[e]=t}class ae{constructor(e){this.crc=e||-1}append(e){let t=0|this.crc;for(let n=0,r=0|e.length;r>n;n++)t=t>>>8^ie[255&(t^e[n])];this.crc=t}get(){return~this.crc}}class oe extends x{constructor(){let e;const t=new ae;super({transform(e,n){t.append(e),n.enqueue(e)},flush(){const n=new w(4);new g(n.buffer).setUint32(0,t.get()),e.value=n}}),e=this}}function ce(e){if(typeof b==X){const t=new w((e=unescape(encodeURIComponent(e))).length);for(let n=0;n0&&t&&(e[n-1]=le.partial(t,e[n-1]&2147483648>>t-1,1)),e},partial:(e,t,n)=>32===e?t:(n?0|t:t<<32-e)+1099511627776*e,getPartial:e=>a.round(e/1099511627776)||32,_shiftRight(e,t,n,r){for(void 0===r&&(r=[]);t>=32;t-=32)r.push(n),n=0;if(0===t)return r.concat(e);for(let s=0;s>>t),n=e[s]<<32-t;const s=e.length?e[e.length-1]:0,i=le.getPartial(s);return r.push(le.partial(t+i&31,t+i>32?n:r.pop(),1)),r}},ue={bytes:{fromBits(e){const t=le.bitLength(e)/8,n=new w(t);let r;for(let s=0;t>s;s++)3&s||(r=e[s/4]),n[s]=r>>>24,r<<=8;return n},toBits(e){const t=[];let n,r=0;for(n=0;n9007199254740991)throw new d("Cannot hash more than 2^53 - 1 bits");const i=new h(n);let a=0;for(let e=t.blockSize+r-(t.blockSize+r&t.blockSize-1);s>=e;e+=t.blockSize)t._block(i.subarray(16*a,16*(a+1))),a+=1;return n.splice(0,16*a),t}finalize(){const e=this;let t=e._buffer;const n=e._h;t=le.concat(t,[le.partial(1,1)]);for(let e=t.length+2;15&e;e++)t.push(0);for(t.push(a.floor(e._length/4294967296)),t.push(0|e._length);t.length;)e._block(t.splice(0,16));return e.reset(),n}_f(e,t,n,r){return e>19?e>39?e>59?e>79?void 0:t^n^r:t&n|t&r|n&r:t^n^r:t&n|~t&r}_S(e,t){return t<>>32-e}_block(e){const n=this,r=n._h,s=t(80);for(let t=0;16>t;t++)s[t]=e[t];let i=r[0],o=r[1],c=r[2],l=r[3],u=r[4];for(let e=0;79>=e;e++){16>e||(s[e]=n._S(1,s[e-3]^s[e-8]^s[e-14]^s[e-16]));const t=n._S(5,i)+n._f(e,o,c,l)+u+s[e]+n._key[a.floor(e/20)]|0;u=l,l=c,c=n._S(30,o),o=i,i=t}r[0]=r[0]+i|0,r[1]=r[1]+o|0,r[2]=r[2]+c|0,r[3]=r[3]+l|0,r[4]=r[4]+u|0}},de={getRandomValues(e){const t=new h(e.buffer),n=e=>{let t=987654321;const n=4294967295;return()=>(t=36969*(65535&t)+(t>>16)&n,(((t<<16)+(e=18e3*(65535&e)+(e>>16)&n)&n)/4294967296+.5)*(a.random()>.5?1:-1))};for(let r,s=0;snew we.hmacSha1(ue.bytes.toBits(e)),pbkdf2(e,t,n,r){if(n=n||1e4,0>r||0>n)throw new d("invalid params to pbkdf2");const s=1+(r>>5)<<2;let i,a,o,c,l;const u=new ArrayBuffer(s),f=new g(u);let w=0;const p=le;for(t=ue.bytes.toBits(t),l=1;(s||1)>w;l++){for(i=a=e.encrypt(p.concat(t,[l])),o=1;n>o;o++)for(a=e.encrypt(a),c=0;cw&&os&&(e=(new n).update(e).finalize());for(let t=0;s>t;t++)r[0][t]=909522486^e[t],r[1][t]=1549556828^e[t];t._baseHash[0].update(r[0]),t._baseHash[1].update(r[1]),t._resultHash=new n(t._baseHash[0])}reset(){const e=this;e._resultHash=new e._hash(e._baseHash[0]),e._updated=!1}update(e){this._updated=!0,this._resultHash.update(e)}digest(){const e=this,t=e._resultHash.finalize(),n=new e._hash(e._baseHash[1]).update(t).finalize();return e.reset(),n}encrypt(e){if(this._updated)throw new d("encrypt on already updated hmac called!");return this.update(e),this.digest(e)}}},pe=typeof z!=X&&typeof z.getRandomValues==Y,he="Invalid password",ge="Invalid signature",me="zipjs-abort-check-password";function ye(e){return pe?z.getRandomValues(e):de.getRandomValues(e)}const be=16,Se={name:"PBKDF2"},ke=n.assign({hash:{name:"HMAC"}},Se),ze=n.assign({iterations:1e3,hash:{name:"SHA-1"}},Se),ve=["deriveBits"],xe=[8,12,16],Ae=[16,24,32],Ce=10,_e=[0,0,0,0],De=typeof z!=X,We=De&&z.subtle,Re=De&&typeof We!=X,Fe=ue.bytes,Ee=class{constructor(e){const t=this;t._tables=[[[],[],[],[],[]],[[],[],[],[],[]]],t._tables[0][0][0]||t._precompute();const n=t._tables[0][4],r=t._tables[1],s=e.length;let i,a,o,c=1;if(4!==s&&6!==s&&8!==s)throw new d("invalid aes key size");for(t._key=[a=e.slice(0),o=[]],i=s;4*s+28>i;i++){let e=a[i-1];(i%s==0||8===s&&i%s==4)&&(e=n[e>>>24]<<24^n[e>>16&255]<<16^n[e>>8&255]<<8^n[255&e],i%s==0&&(e=e<<8^e>>>24^c<<24,c=c<<1^283*(c>>7))),a[i]=a[i-s]^e}for(let e=0;i;e++,i--){const t=a[3&e?i:i-4];o[e]=4>=i||4>e?t:r[0][n[t>>>24]]^r[1][n[t>>16&255]]^r[2][n[t>>8&255]]^r[3][n[255&t]]}}encrypt(e){return this._crypt(e,0)}decrypt(e){return this._crypt(e,1)}_precompute(){const e=this._tables[0],t=this._tables[1],n=e[4],r=t[4],s=[],i=[];let a,o,c,l;for(let e=0;256>e;e++)i[(s[e]=e<<1^283*(e>>7))^e]=e;for(let u=a=0;!n[u];u^=o||1,a=i[a]||1){let i=a^a<<1^a<<2^a<<3^a<<4;i=i>>8^255&i^99,n[u]=i,r[i]=u,l=s[c=s[o=s[u]]];let f=16843009*l^65537*c^257*o^16843008*u,d=257*s[i]^16843008*i;for(let n=0;4>n;n++)e[n][u]=d=d<<24^d>>>8,t[n][i]=f=f<<24^f>>>8}for(let n=0;5>n;n++)e[n]=e[n].slice(0),t[n]=t[n].slice(0)}_crypt(e,t){if(4!==e.length)throw new d("invalid aes block size");const n=this._key[t],r=n.length/4-2,s=[0,0,0,0],i=this._tables[t],a=i[0],o=i[1],c=i[2],l=i[3],u=i[4];let f,w,p,h=e[0]^n[0],g=e[t?3:1]^n[1],m=e[2]^n[2],y=e[t?1:3]^n[3],b=4;for(let e=0;r>e;e++)f=a[h>>>24]^o[g>>16&255]^c[m>>8&255]^l[255&y]^n[b],w=a[g>>>24]^o[m>>16&255]^c[y>>8&255]^l[255&h]^n[b+1],p=a[m>>>24]^o[y>>16&255]^c[h>>8&255]^l[255&g]^n[b+2],y=a[y>>>24]^o[h>>16&255]^c[g>>8&255]^l[255&m]^n[b+3],b+=4,h=f,g=w,m=p;for(let e=0;4>e;e++)s[t?3&-e:e]=u[h>>>24]<<24^u[g>>16&255]<<16^u[m>>8&255]<<8^u[255&y]^n[b++],f=h,h=g,g=m,m=y,y=f;return s}},Te=class{constructor(e,t){this._prf=e,this._initIv=t,this._iv=t}reset(){this._iv=this._initIv}update(e){return this.calculate(this._prf,e,this._iv)}incWord(e){if(255&~(e>>24))e+=1<<24;else{let t=e>>16&255,n=e>>8&255,r=255&e;255===t?(t=0,255===n?(n=0,255===r?r=0:++r):++n):++t,e=0,e+=t<<16,e+=n<<8,e+=r}return e}incCounter(e){0===(e[0]=this.incWord(e[0]))&&(e[1]=this.incWord(e[1]))}calculate(e,t,n){let r;if(!(r=t.length))return[];const s=le.bitLength(t);for(let s=0;r>s;s+=4){this.incCounter(n);const r=e.encrypt(n);t[s]^=r[0],t[s+1]^=r[1],t[s+2]^=r[2],t[s+3]^=r[3]}return le.clamp(t,s)}},Le=we.hmacSha1;let Ue=De&&Re&&typeof We.importKey==Y,Ie=De&&Re&&typeof We.deriveBits==Y;class Ne extends x{constructor({password:e,rawPassword:t,signed:r,encryptionStrength:s,checkPasswordOnly:i}){super({start(){n.assign(this,{ready:new y((e=>this.resolveReady=e)),password:He(e,t),signed:r,strength:s-1,pending:new w})},async transform(e,t){const n=this,{password:r,strength:s,resolveReady:a,ready:o}=n;r?(await(async(e,t,n,r)=>{const s=await Pe(e,t,n,Be(r,0,xe[t])),i=Be(r,xe[t]);if(s[0]!=i[0]||s[1]!=i[1])throw new d(he)})(n,s,r,Be(e,0,xe[s]+2)),e=Be(e,xe[s]+2),i?t.error(new d(me)):a()):await o;const c=new w(e.length-Ce-(e.length-Ce)%be);t.enqueue(Oe(n,e,c,0,Ce,!0))},async flush(e){const{signed:t,ctr:n,hmac:r,pending:s,ready:i}=this;if(r&&n){await i;const a=Be(s,0,s.length-Ce),o=Be(s,s.length-Ce);let c=new w;if(a.length){const e=Ze(Fe,a);r.update(e);const t=n.update(e);c=Ve(Fe,t)}if(t){const e=Be(Ve(Fe,r.digest()),0,Ce);for(let t=0;Ce>t;t++)if(e[t]!=o[t])throw new d(ge)}e.enqueue(c)}}})}}class qe extends x{constructor({password:e,rawPassword:t,encryptionStrength:r}){let s;super({start(){n.assign(this,{ready:new y((e=>this.resolveReady=e)),password:He(e,t),strength:r-1,pending:new w})},async transform(e,t){const n=this,{password:r,strength:s,resolveReady:i,ready:a}=n;let o=new w;r?(o=await(async(e,t,n)=>{const r=ye(new w(xe[t]));return Me(r,await Pe(e,t,n,r))})(n,s,r),i()):await a;const c=new w(o.length+e.length-e.length%be);c.set(o,0),t.enqueue(Oe(n,e,c,o.length,0))},async flush(e){const{ctr:t,hmac:n,pending:r,ready:i}=this;if(n&&t){await i;let a=new w;if(r.length){const e=t.update(Ze(Fe,r));n.update(e),a=Ve(Fe,e)}s.signature=Ve(Fe,n.digest()).slice(0,Ce),e.enqueue(Me(a,s.signature))}}}),s=this}}function Oe(e,t,n,r,s,i){const{ctr:a,hmac:o,pending:c}=e,l=t.length-s;let u;for(c.length&&(t=Me(c,t),n=((e,t)=>{if(t&&t>e.length){const n=e;(e=new w(t)).set(n,0)}return e})(n,l-l%be)),u=0;l-be>=u;u+=be){const e=Ze(Fe,Be(t,u,u+be));i&&o.update(e);const s=a.update(e);i||o.update(s),n.set(Ve(Fe,s),u+r)}return e.pending=Be(t,u),n}async function Pe(e,r,s,i){e.password=null;const a=await(async(e,t,n,r,s)=>{if(!Ue)return we.importKey(t);try{return await We.importKey("raw",t,n,!1,s)}catch(e){return Ue=!1,we.importKey(t)}})(0,s,ke,0,ve),o=await(async(e,t,n)=>{if(!Ie)return we.pbkdf2(t,e.salt,ze.iterations,n);try{return await We.deriveBits(e,t,n)}catch(r){return Ie=!1,we.pbkdf2(t,e.salt,ze.iterations,n)}})(n.assign({salt:i},ze),a,8*(2*Ae[r]+2)),c=new w(o),l=Ze(Fe,Be(c,0,Ae[r])),u=Ze(Fe,Be(c,Ae[r],2*Ae[r])),f=Be(c,2*Ae[r]);return n.assign(e,{keys:{key:l,authentication:u,passwordVerification:f},ctr:new Te(new Ee(l),t.from(_e)),hmac:new Le(u)}),f}function He(e,t){return t===G?ce(e):t}function Me(e,t){let n=e;return e.length+t.length&&(n=new w(e.length+t.length),n.set(e,0),n.set(t,e.length)),n}function Be(e,t,n){return e.subarray(t,n)}function Ve(e,t){return e.fromBits(t)}function Ze(e,t){return e.toBits(t)}class Ke extends x{constructor({password:e,passwordVerification:t,checkPasswordOnly:r}){super({start(){n.assign(this,{password:e,passwordVerification:t}),je(this,e)},transform(e,t){const n=this;if(n.password){const t=Xe(n,e.subarray(0,12));if(n.password=null,t[11]!=n.passwordVerification)throw new d(he);e=e.subarray(12)}r?t.error(new d(me)):t.enqueue(Xe(n,e))}})}}class Ge extends x{constructor({password:e,passwordVerification:t}){super({start(){n.assign(this,{password:e,passwordVerification:t}),je(this,e)},transform(e,t){const n=this;let r,s;if(n.password){n.password=null;const t=ye(new w(12));t[11]=n.passwordVerification,r=new w(e.length+t.length),r.set(Ye(n,t),0),s=12}else r=new w(e.length),s=0;r.set(Ye(n,e),s),t.enqueue(r)}})}}function Xe(e,t){const n=new w(t.length);for(let r=0;r>>24]),s=~e.crcKey2.get(),e.keys=[n,r,s]}function Qe(e){const t=2|e.keys[2];return $e(a.imul(t,1^t)>>>8)}function $e(e){return 255&e}function et(e){return 4294967295&e}const tt="deflate-raw";class nt extends x{constructor(e,{chunkSize:t,CompressionStream:n,CompressionStreamNative:r}){super({});const{compressed:s,encrypted:i,useCompressionStream:a,zipCrypto:o,signed:c,level:l}=e,u=this;let f,d,w=st(super.readable);i&&!o||!c||(f=new oe,w=ot(w,f)),s&&(w=at(w,a,{level:l,chunkSize:t},r,n)),i&&(o?w=ot(w,new Ge(e)):(d=new qe(e),w=ot(w,d))),it(u,w,(()=>{let e;i&&!o&&(e=d.signature),i&&!o||!c||(e=new g(f.value.buffer).getUint32(0)),u.signature=e}))}}class rt extends x{constructor(e,{chunkSize:t,DecompressionStream:n,DecompressionStreamNative:r}){super({});const{zipCrypto:s,encrypted:i,signed:a,signature:o,compressed:c,useCompressionStream:l}=e;let u,f,w=st(super.readable);i&&(s?w=ot(w,new Ke(e)):(f=new Ne(e),w=ot(w,f))),c&&(w=at(w,l,{chunkSize:t},r,n)),i&&!s||!a||(u=new oe,w=ot(w,u)),it(this,w,(()=>{if((!i||s)&&a){const e=new g(u.value.buffer);if(o!=e.getUint32(0,!1))throw new d(ge)}}))}}function st(e){return ot(e,new x({transform(e,t){e&&e.length&&t.enqueue(e)}}))}function it(e,t,r){t=ot(t,new x({flush:r})),n.defineProperty(e,"readable",{get:()=>t})}function at(e,t,n,r,s){try{e=ot(e,new(t&&r?r:s)(tt,n))}catch(r){if(!t)return e;try{e=ot(e,new s(tt,n))}catch(t){return e}}return e}function ot(e,t){return e.pipeThrough(t)}const ct="data",lt="close",ut="deflate",ft="inflate";class dt extends x{constructor(e,t){super({});const r=this,{codecType:s}=e;let i;s.startsWith(ut)?i=nt:s.startsWith(ft)&&(i=rt);let a=0,o=0;const c=new i(e,t),l=super.readable,u=new x({transform(e,t){e&&e.length&&(o+=e.length,t.enqueue(e))},flush(){n.assign(r,{inputSize:o})}}),f=new x({transform(e,t){e&&e.length&&(a+=e.length,t.enqueue(e))},flush(){const{signature:e}=c;n.assign(r,{signature:e,outputSize:a,inputSize:o})}});n.defineProperty(r,"readable",{get:()=>l.pipeThrough(u).pipeThrough(c).pipeThrough(f)})}}class wt extends x{constructor(e){let t;super({transform:function n(r,s){if(t){const e=new w(t.length+r.length);e.set(t),e.set(r,t.length),r=e,t=null}r.length>e?(s.enqueue(r.slice(0,e)),n(r.slice(e),s)):t=r},flush(e){t&&t.length&&e.enqueue(t)}})}}let pt=typeof R!=X;class ht{constructor(e,{readable:t,writable:r},{options:s,config:i,streamOptions:a,useWebWorkers:o,transferStreams:c,scripts:l},u){const{signal:f}=a;return n.assign(e,{busy:!0,readable:t.pipeThrough(new wt(i.chunkSize)).pipeThrough(new gt(t,a),{signal:f}),writable:r,options:n.assign({},s),scripts:l,transferStreams:c,terminate:()=>new y((t=>{const{worker:n,busy:r}=e;n?(r?e.resolveTerminated=t:(n.terminate(),t()),e.interface=null):t()})),onTaskFinished(){const{resolveTerminated:t}=e;t&&(e.resolveTerminated=null,e.terminated=!0,e.worker.terminate(),t()),e.busy=!1,u(e)}}),(o&&pt?bt:yt)(e,i)}}class gt extends x{constructor(e,{onstart:t,onprogress:n,size:r,onend:s}){let i=0;super({async start(){t&&await mt(t,r)},async transform(e,t){i+=e.length,n&&await mt(n,i,r),t.enqueue(e)},async flush(){e.size=i,s&&await mt(s,i)}})}}async function mt(e,...t){try{await e(...t)}catch(e){}}function yt(e,t){return{run:()=>(async({options:e,readable:t,writable:n,onTaskFinished:r},s)=>{try{const r=new dt(e,s);await t.pipeThrough(r).pipeTo(n,{preventClose:!0,preventAbort:!0});const{signature:i,inputSize:a,outputSize:o}=r;return{signature:i,inputSize:a,outputSize:o}}finally{r()}})(e,t)}}function bt(e,t){const{baseURL:r,chunkSize:s}=t;if(!e.interface){let i;try{i=((e,t,r)=>{const s={type:"module"};let i,a;typeof e==Y&&(e=e());try{i=new f(e,t)}catch(t){i=e}if(St)try{a=new R(i)}catch(e){St=!1,a=new R(i,s)}else a=new R(i,s);return a.addEventListener("message",(e=>(async({data:e},t)=>{const{type:r,value:s,messageId:i,result:a,error:o}=e,{reader:c,writer:l,resolveResult:u,rejectResult:f,onTaskFinished:p}=t;try{if(o){const{message:e,stack:t,code:r,name:s}=o,i=new d(e);n.assign(i,{stack:t,code:r,name:s}),h(i)}else{if("pull"==r){const{value:e,done:n}=await c.read();zt({type:ct,value:e,done:n,messageId:i},t)}r==ct&&(await l.ready,await l.write(new w(s)),zt({type:"ack",messageId:i},t)),r==lt&&h(null,a)}}catch(o){zt({type:lt,messageId:i},t),h(o)}function h(e,t){e?f(e):u(t),l&&l.releaseLock(),p()}})(e,r))),a})(e.scripts[0],r,e)}catch(n){return pt=!1,yt(e,t)}n.assign(e,{worker:i,interface:{run:()=>(async(e,t)=>{let r,s;const i=new y(((e,t)=>{r=e,s=t}));n.assign(e,{reader:null,writer:null,resolveResult:r,rejectResult:s,result:i});const{readable:a,options:o,scripts:c}=e,{writable:l,closed:u}=(e=>{let t;const n=new y((e=>t=e));return{writable:new C({async write(t){const n=e.getWriter();await n.ready,await n.write(t),n.releaseLock()},close(){t()},abort:t=>e.getWriter().abort(t)}),closed:n}})(e.writable),f=zt({type:"start",scripts:c.slice(1),options:o,config:t,readable:a,writable:l},e);f||n.assign(e,{reader:a.getReader(),writer:l.getWriter()});const d=await i;return f||await l.getWriter().close(),await u,d})(e,{chunkSize:s})}})}return e.interface}let St=!0,kt=!0;function zt(e,{worker:t,writer:n,onTaskFinished:r,transferStreams:s}){try{const{value:n,readable:r,writable:i}=e,a=[];if(n&&(n.byteLength{const n=vt.find((e=>!e.busy));if(n)return _t(n),new ht(n,e,t,h);if(vt.lengthxt.push({resolve:n,stream:e,workerOptions:t})))})()).run();function h(e){if(xt.length){const[{resolve:t,stream:n,workerOptions:r}]=xt.splice(0,1);t(new ht(e,n,r,h))}else e.worker?(_t(e),((e,t)=>{const{config:n}=t,{terminateWorkerTimeout:r}=n;s.isFinite(r)&&r>=0&&(e.terminated?e.terminated=!1:e.terminateTimeout=setTimeout((async()=>{vt=vt.filter((t=>t!=e));try{await e.terminate()}catch(e){}}),r))})(e,t)):vt=vt.filter((t=>t!=e))}}function _t(e){const{terminateTimeout:t}=e;t&&(clearTimeout(t),e.terminateTimeout=null)}const Dt="HTTP error ",Wt="HTTP Range not supported",Rt="Writer iterator completed too soon",Ft="Range",Et="GET",Tt="bytes",Lt=65536,Ut="writable";class It{constructor(){this.size=0}init(){this.initialized=!0}}class Nt extends It{get readable(){const e=this,{chunkSize:t=Lt}=e,n=new A({start(){this.chunkOffset=0},async pull(r){const{offset:s=0,size:i,diskNumberStart:o}=n,{chunkOffset:c}=this;r.enqueue(await on(e,s+c,a.min(t,i-c),o)),c+t>i?r.close():this.chunkOffset+=t}});return n}}class qt extends It{constructor(){super();const e=this,t=new C({write:t=>e.writeUint8Array(t)});n.defineProperty(e,Ut,{get:()=>t})}writeUint8Array(){}}class Ot extends Nt{constructor(e){super(),n.assign(this,{blob:e,size:e.size})}async readUint8Array(e,t){const n=this,r=e+t,s=e||rt&&(i=i.slice(e,r)),new w(i)}}class Pt extends It{constructor(e){super();const t=new x,r=[];e&&r.push(["Content-Type",e]),n.defineProperty(this,Ut,{get:()=>t.writable}),this.blob=new u(t.readable,{headers:r}).blob()}getData(){return this.blob}}class Ht extends Nt{constructor(e,t){super(),Bt(this,e,t)}async init(){await Vt(this,Qt,Xt),super.init()}readUint8Array(e,t){return Zt(this,e,t,Qt,Xt)}}class Mt extends Nt{constructor(e,t){super(),Bt(this,e,t)}async init(){await Vt(this,$t,Yt),super.init()}readUint8Array(e,t){return Zt(this,e,t,$t,Yt)}}function Bt(e,t,r){const{preventHeadRequest:s,useRangeHeader:i,forceRangeRequests:a,combineSizeEocd:o}=r;delete(r=n.assign({},r)).preventHeadRequest,delete r.useRangeHeader,delete r.forceRangeRequests,delete r.combineSizeEocd,delete r.useXHR,n.assign(e,{url:t,options:r,preventHeadRequest:s,useRangeHeader:i,forceRangeRequests:a,combineSizeEocd:o})}async function Vt(e,t,n){const{url:r,preventHeadRequest:i,useRangeHeader:a,forceRangeRequests:o,combineSizeEocd:c}=e;if((e=>{const{baseURL:t}=ee(),{protocol:n}=new f(e,t);return"http:"==n||"https:"==n})(r)&&(a||o)&&(void 0===i||i)){const r=await t(Et,e,Kt(e,c?-22:void 0));if(!o&&r.headers.get("Accept-Ranges")!=Tt)throw new d(Wt);{let i;c&&(e.eocdCache=new w(await r.arrayBuffer()));const a=r.headers.get("Content-Range");if(a){const e=a.trim().split(/\s*\/\s*/);if(e.length){const t=e[1];t&&"*"!=t&&(i=s(t))}}i===G?await Jt(e,t,n):e.size=i}}else await Jt(e,t,n)}async function Zt(e,t,n,r,s){const{useRangeHeader:i,forceRangeRequests:a,eocdCache:o,size:c,options:l}=e;if(i||a){if(o&&t==c-H&&n==H)return o;const s=await r(Et,e,Kt(e,t,n));if(206!=s.status)throw new d(Wt);return new w(await s.arrayBuffer())}{const{data:r}=e;return r||await s(e,l),new w(e.data.subarray(t,t+n))}}function Kt(e,t=0,r=1){return n.assign({},Gt(e),{[Ft]:Tt+"="+(0>t?t:t+"-"+(t+r-1))})}function Gt({options:e}){const{headers:t}=e;if(t)return Symbol.iterator in t?n.fromEntries(t):t}async function Xt(e){await jt(e,Qt)}async function Yt(e){await jt(e,$t)}async function jt(e,t){const n=await t(Et,e,Gt(e));e.data=new w(await n.arrayBuffer()),e.size||(e.size=e.data.length)}async function Jt(e,t,n){if(e.preventHeadRequest)await n(e,e.options);else{const r=(await t("HEAD",e,Gt(e))).headers.get("Content-Length");r?e.size=s(r):await n(e,e.options)}}async function Qt(e,{options:t,url:r},s){const i=await fetch(r,n.assign({},t,{method:e,headers:s}));if(400>i.status)return i;throw 416==i.status?new d(Wt):new d(Dt+(i.statusText||i.status))}function $t(e,{url:t},r){return new y(((s,i)=>{const a=new XMLHttpRequest;if(a.addEventListener("load",(()=>{if(400>a.status){const e=[];a.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((t=>{const n=t.trim().split(/\s*:\s*/);n[0]=n[0].trim().replace(/^[a-z]|-[a-z]/g,(e=>e.toUpperCase())),e.push(n)})),s({status:a.status,arrayBuffer:()=>a.response,headers:new c(e)})}else i(416==a.status?new d(Wt):new d(Dt+(a.statusText||a.status)))}),!1),a.addEventListener("error",(e=>i(e.detail?e.detail.error:new d("Network error"))),!1),a.open(e,t),r)for(const e of n.entries(r))a.setRequestHeader(e[0],e[1]);a.responseType="arraybuffer",a.send()}))}class en extends Nt{constructor(e,t={}){super(),n.assign(this,{url:e,reader:t.useXHR?new Mt(e,t):new Ht(e,t)})}set size(e){}get size(){return this.reader.size}async init(){await this.reader.init(),super.init()}readUint8Array(e,t){return this.reader.readUint8Array(e,t)}}class tn extends Nt{constructor(e){super(),this.readers=e}async init(){const e=this,{readers:t}=e;e.lastDiskNumber=0,e.lastDiskOffset=0,await y.all(t.map((async(n,r)=>{await n.init(),r!=t.length-1&&(e.lastDiskOffset+=n.size),e.size+=n.size}))),super.init()}async readUint8Array(e,t,n=0){const r=this,{readers:s}=this;let i,o=n;-1==o&&(o=s.length-1);let c=e;for(;c>=s[o].size;)c-=s[o].size,o++;const l=s[o],u=l.size;if(c+t>u){const s=u-c;i=new w(t),i.set(await on(l,c,s)),i.set(await r.readUint8Array(e+s,t-s,n),s)}else i=await on(l,c,t);return r.lastDiskNumber=a.max(o,r.lastDiskNumber),i}}class nn extends It{constructor(e,t=4294967295){super();const r=this;let s,i,a;n.assign(r,{diskNumber:0,diskOffset:0,size:0,maxSize:t,availableSize:t});const o=new C({async write(t){const{availableSize:n}=r;if(a)t.lengtho})}}async function rn(e,t){if(!e.init||e.initialized)return y.resolve();await e.init(t)}function sn(e){return t.isArray(e)&&(e=new tn(e)),e instanceof A&&(e={readable:e}),e}function an(e){e.writable===G&&typeof e.next==Y&&(e=new nn(e)),e instanceof C&&(e={writable:e});const{writable:t}=e;return t.size===G&&(t.size=0),e instanceof nn||n.assign(e,{diskNumber:0,diskOffset:0,availableSize:1/0,maxSize:1/0}),e}function on(e,t,n,r){return e.readUint8Array(t,n,r)}const cn=tn,ln=nn,un="\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");function fn(e,t){return t&&"cp437"==t.trim().toLowerCase()?(e=>{{let t="";for(let n=0;nthis[t]=e[t]))}}const Ln="File format is not recognized",Un="End of central directory not found",In="End of Zip64 central directory locator not found",Nn="Central directory header not found",qn="Local file header not found",On="Zip64 extra field not found",Pn="File contains encrypted entry",Hn="Encryption method not supported",Mn="Compression method not supported",Bn="Split zip file",Vn="utf-8",Zn="cp437",Kn=[[gn,E],[mn,E],[yn,E],[bn,T]],Gn={[T]:{getValue:sr,bytes:4},[E]:{getValue:ir,bytes:8}};class Xn{constructor(e,t={}){n.assign(this,{reader:sn(e),options:t,config:ee()})}async*getEntriesGenerator(e={}){const t=this;let{reader:r}=t;const{config:s}=t;if(await rn(r),r.size!==G&&r.readUint8Array||(r=new Ot(await new u(r.readable).blob()),await rn(r)),r.size{const r=new w(4);var s;return s=t,ar(r).setUint32(0,s,!0),await i(22)||await i(a.min(1048582,n));async function i(t){const s=n-t,i=await on(e,s,t);for(let e=i.length-22;e>=0;e--)if(i[e]==r[0]&&i[e+1]==r[1]&&i[e+2]==r[2]&&i[e+3]==r[3])return{offset:s+e,buffer:i.slice(e,e+22).buffer}}})(r,q,r.size);if(!i)throw sr(ar(await on(r,0,4)))==U?new d(Bn):new d(Un);const o=ar(i);let c=sr(o,12),l=sr(o,16);const f=i.offset,p=rr(o,20),h=f+H+p;let g=rr(o,4);const m=r.lastDiskNumber||0;let y=rr(o,6),b=rr(o,8),S=0,k=0;if(l==E||c==E||b==T||y==T){const e=ar(await on(r,i.offset-20,20));if(sr(e,0)==P){l=ir(e,8);let t=await on(r,l,56,-1),n=ar(t);const s=i.offset-20-56;if(sr(n,0)!=O&&l!=s){const e=l;l=s,S=l-e,t=await on(r,l,56,-1),n=ar(t)}if(sr(n,0)!=O)throw new d(In);g==T&&(g=sr(n,16)),y==T&&(y=sr(n,20)),b==T&&(b=ir(n,32)),c==E&&(c=ir(n,40)),l-=c}}if(ll)throw new d(Ln);let z=0,v=await on(r,l,c,y),x=ar(v);if(c){const e=i.offset-c;if(sr(x,z)!=N&&l!=e){const t=l;l=e,S+=l-t,v=await on(r,l,c,y),x=ar(v)}}const A=i.offset-l-(r.lastDiskOffset||0);if(c==A||0>A||(c=A,v=await on(r,l,c,y),x=ar(v)),0>l||l>=r.size)throw new d(Ln);const C=$n(t,e,"filenameEncoding"),_=$n(t,e,"commentEncoding");for(let i=0;b>i;i++){const o=new Yn(r,s,t.options);if(sr(x,z)!=N)throw new d(Nn);jn(o,x,z+6);const c=!!o.bitFlag.languageEncodingFlag,l=z+46,u=l+o.filenameLength,f=u+o.extraFieldLength,w=rr(x,z+4),p=!0,h=v.subarray(l,u),g=rr(x,z+32),m=f+g,y=v.subarray(f,m),A=c,D=c,W=p&&!(16&~nr(x,z+38)),R=sr(x,z+42)+S;n.assign(o,{versionMadeBy:w,msDosCompatible:p,compressedSize:0,uncompressedSize:0,commentLength:g,directory:W,offset:R,diskNumberStart:rr(x,z+34),internalFileAttribute:rr(x,z+36),externalFileAttribute:sr(x,z+38),rawFilename:h,filenameUTF8:A,commentUTF8:D,rawExtraField:v.subarray(u,f)});const F=$n(t,e,"decodeText")||fn,E=A?Vn:C||Zn,T=D?Vn:_||Zn;let L=F(h,E);L===G&&(L=fn(h,E));let U=F(y,T);U===G&&(U=fn(y,T)),n.assign(o,{rawComment:y,filename:L,comment:U,directory:W||L.endsWith(V)}),k=a.max(R,k),Jn(o,o,x,z+6),o.zipCrypto=o.encrypted&&!o.extraFieldAES;const I=new Tn(o);I.getData=(e,t)=>o.getData(e,I,t),z=m;const{onprogress:q}=e;if(q)try{await q(i+1,b,new Tn(o))}catch(e){}yield I}const D=$n(t,e,"extractPrependedData"),W=$n(t,e,"extractAppendedData");return D&&(t.prependedData=k>0?await on(r,0,k):new w),t.comment=p?await on(r,f+H,p):new w,W&&(t.appendedData=h>>8&255:p>>>24&255),signature:p,compressed:0!=l&&!z,encrypted:s.encrypted&&!z,useWebWorkers:$n(s,r,"useWebWorkers"),useCompressionStream:$n(s,r,"useCompressionStream"),transferStreams:$n(s,r,"transferStreams"),checkPasswordOnly:R},config:u,streamOptions:{signal:W,size:_,onstart:E,onprogress:T,onend:U}};let N=0;try{({outputSize:N}=await Ct({readable:D,writable:F},I))}catch(e){if(!R||e.message!=me)throw e}finally{const e=$n(s,r,"preventClose");F.size+=N,e||F.locked||await F.getWriter().close()}return R?G:e.getData?e.getData():F}}function jn(e,t,r){const s=e.rawBitFlag=rr(t,r+2),i=!(1&~s),a=sr(t,r+6);n.assign(e,{encrypted:i,version:rr(t,r),bitFlag:{level:(6&s)>>1,dataDescriptor:!(8&~s),languageEncodingFlag:(s&B)==B},rawLastModDate:a,lastModDate:er(a),filenameLength:rr(t,r+22),extraFieldLength:rr(t,r+24)})}function Jn(e,t,r,s,i){const{rawExtraField:a}=t,l=t.extraField=new c,u=ar(new w(a));let f=0;try{for(;f{t.zip64=!0;const n=ar(e.data),r=Kn.filter((([e,n])=>t[e]==n));for(let s=0,i=0;s{const s=ar(e.data),i=nr(s,4);n.assign(e,{vendorVersion:nr(s,0),vendorId:nr(s,2),strength:i,originalCompressionMethod:r,compressionMethod:rr(s,5)}),t.compressionMethod=e.compressionMethod})(y,t,p),t.extraFieldAES=y):t.compressionMethod=p;const b=l.get(10);b&&(((e,t)=>{const r=ar(e.data);let s,i=4;try{for(;i{const r=ar(e.data),s=nr(r,0),i=[],a=[];n?(1&~s||(i.push(Sn),a.push(kn)),2&~s||(i.push(zn),a.push("rawLastAccessDate")),4&~s||(i.push(vn),a.push("rawCreationDate"))):5>e.data.length||(i.push(Sn),a.push(kn));let c=1;i.forEach(((n,s)=>{if(e.data.length>=c+4){const i=sr(r,c);t[n]=e[n]=new o(1e3*i);const l=a[s];e[l]=i}c+=4}))})(S,t,i),t.extraFieldExtendedTimestamp=S);const k=l.get(6534);k&&(t.extraFieldUSDZ=k)}function Qn(e,t,r,s,i){const a=ar(e.data),o=new ae;o.append(i[r]);const c=ar(new w(4));c.setUint32(0,o.get(),!0);const l=sr(a,1);n.assign(e,{version:nr(a,0),[t]:fn(e.data.subarray(5)),valid:!i.bitFlag.languageEncodingFlag&&l==sr(c,0)}),e.valid&&(s[t]=e[t],s[t+"UTF8"]=!0)}function $n(e,t,n){return t[n]===G?e.options[n]:t[n]}function er(e){const t=(4294901760&e)>>16,n=65535&e;try{return new o(1980+((65024&t)>>9),((480&t)>>5)-1,31&t,(63488&n)>>11,(2016&n)>>5,2*(31&n),0)}catch(e){}}function tr(e){return new o(s(e/i(1e4)-i(116444736e5)))}function nr(e,t){return e.getUint8(t)}function rr(e,t){return e.getUint16(t,!0)}function sr(e,t){return e.getUint32(t,!0)}function ir(e,t){return s(e.getBigUint64(t,!0))}function ar(e){return new g(e.buffer)}const or="File already exists",cr="Zip file comment exceeds 64KB",lr="File entry comment exceeds 64KB",ur="File entry name exceeds 64KB",fr="Version exceeds 65535",dr="The strength must equal 1, 2, or 3",wr="Extra field type exceeds 65535",pr="Extra field data exceeds 64KB",hr="Zip64 is not supported (make sure 'keepOrder' is set to 'true')",gr="Undefined uncompressed size",mr=new w([7,0,2,0,65,69,3,0,0]);let yr=0;const br=[];class Sr{constructor(e,t={}){const r=(e=an(e)).availableSize!==G&&e.availableSize>0&&e.availableSize!==1/0&&e.maxSize!==G&&e.maxSize>0&&e.maxSize!==1/0;n.assign(this,{writer:e,addSplitZipSignature:r,options:t,config:ee(),files:new c,filenames:new l,offset:t.offset===G?e.writable.size:t.offset,pendingEntriesSize:0,pendingAddFileCalls:new l,bufferedWrites:0})}async add(e="",r,s={}){const c=this,{pendingAddFileCalls:l,config:f}=c;let m;yrbr.push(e)));try{if(e=e.trim(),c.filenames.has(e))throw new d(or);return c.filenames.add(e),m=(async(e,r,s,c)=>{r=r.trim(),c.directory&&!r.endsWith(V)?r+=V:c.directory=r.endsWith(V);const l=vr(e,c,"encodeText",ce);let f=l(r);if(f===G&&(f=ce(r)),Fr(f)>T)throw new d(ur);const m=c.comment||"";let b=l(m);if(b===G&&(b=ce(m)),Fr(b)>T)throw new d(lr);const S=vr(e,c,Wn,20);if(S>T)throw new d(fr);const k=vr(e,c,Rn,20);if(k>T)throw new d(fr);const z=vr(e,c,Sn,new o),v=vr(e,c,zn),A=vr(e,c,vn),C=vr(e,c,Cn,!0),_=vr(e,c,xn,0),D=vr(e,c,An,0),W=vr(e,c,"passThrough");let R,F;W||(R=vr(e,c,"password"),F=vr(e,c,"rawPassword"));const N=vr(e,c,"encryptionStrength",3),q=vr(e,c,Fn),O=vr(e,c,"extendedTimestamp",!0),P=vr(e,c,"keepOrder",!0),H=vr(e,c,"level"),X=vr(e,c,"useWebWorkers"),Y=vr(e,c,"bufferedWrite"),j=vr(e,c,"dataDescriptorSignature",!1),J=vr(e,c,"signal"),Q=vr(e,c,"useUnicodeFileNames",!0),$=vr(e,c,"useCompressionStream"),ee=vr(e,c,"compressionMethod");let ne=vr(e,c,"dataDescriptor",!0),re=vr(e,c,_n);if(!q&&(R!==G||F!==G)&&(1>N||N>3))throw new d(dr);let se=new w;const{extraField:ie}=c;if(ie){let e=0,t=0;ie.forEach((t=>e+=4+Fr(t))),se=new w(e),ie.forEach(((e,n)=>{if(n>T)throw new d(wr);if(Fr(e)>T)throw new d(pr);Wr(se,new p([n]),t),Wr(se,new p([Fr(e)]),t+2),Wr(se,e,t+4),t+=4+Fr(e)}))}let ae=0,oe=0,le=0;if(W&&(({uncompressedSize:le}=c),le===G))throw new d(gr);const ue=!0===re;s&&(s=sn(s),await rn(s),W?ae=xr(le):s.size===G?(ne=!0,(re||re===G)&&(re=!0,le=ae=4294967296)):(le=s.size,ae=xr(le)));const{diskOffset:fe,diskNumber:de,maxSize:we}=e.writer,pe=ue||le>E,he=ue||ae>E,ge=ue||e.offset+e.pendingEntriesSize-fe>E,me=vr(e,c,"supportZip64SplitFile",!0)&&ue||de+a.ceil(e.pendingEntriesSize/we)>T;if(ge||pe||he||me){if(!1===re||!P)throw new d(hr);re=!0}re=re||!1;const ye=vr(e,c,Dn),{signature:be}=c,Se=(e=>{const{rawFilename:t,lastModDate:n,lastAccessDate:r,creationDate:s,level:i,zip64:o,zipCrypto:c,useUnicodeFileNames:l,dataDescriptor:u,directory:f,rawExtraField:d,encryptionStrength:p,extendedTimestamp:g,encrypted:m}=e;let{version:y,compressionMethod:b}=e;const S=!f&&(i>0||i===G&&0!==b);let k,z,v,x;if(m&&!c){k=new w(Fr(mr)+2);const e=Rr(k);Cr(e,0,39169),Wr(k,mr,2),Ar(e,8,p)}else k=new w;if(g){v=new w(9+(r?4:0)+(s?4:0));const e=Rr(v);Cr(e,0,M),Cr(e,2,Fr(v)-4),x=1+(r?2:0)+(s?4:0),Ar(e,4,x);let t=5;_r(e,t,a.floor(n.getTime()/1e3)),t+=4,r&&(_r(e,t,a.floor(r.getTime()/1e3)),t+=4),s&&_r(e,t,a.floor(s.getTime()/1e3));try{z=new w(36);const e=Rr(z),t=zr(n);Cr(e,0,10),Cr(e,2,32),Cr(e,8,1),Cr(e,10,24),Dr(e,12,t),Dr(e,20,zr(r)||t),Dr(e,28,zr(s)||t)}catch(e){z=new w}}else z=v=new w;let A=0;l&&(A|=B),u&&(A|=8),b===G&&(b=S?8:0),8==b&&(i>=1&&3>i&&(A|=6),i>=3&&5>i&&(A|=1),9===i&&(A|=2)),o&&(y=y>45?y:45),m&&(A|=1,c||(y=y>51?y:51,k[9]=b,b=99));const C=new w(26),_=Rr(C);Cr(_,0,y),Cr(_,2,A),Cr(_,4,b);const D=new h(1),W=Rr(D);let R;R=K>n?K:n>Z?Z:n,Cr(W,0,(R.getHours()<<6|R.getMinutes())<<5|R.getSeconds()/2),Cr(W,2,(R.getFullYear()-1980<<4|R.getMonth()+1)<<5|R.getDate());const F=D[0];_r(_,6,F),Cr(_,22,Fr(t));const E=Fr(k,v,z,d);Cr(_,24,E);const T=new w(30+Fr(t)+E);return _r(Rr(T),0,L),Wr(T,C,4),Wr(T,t,30),Wr(T,k,30+Fr(t)),Wr(T,v,30+Fr(t,k)),Wr(T,z,30+Fr(t,k,v)),Wr(T,d,30+Fr(t,k,v,z)),{localHeaderArray:T,headerArray:C,headerView:_,lastModDate:n,rawLastModDate:F,encrypted:m,compressed:S,version:y,compressionMethod:b,extraFieldExtendedTimestampFlag:x,rawExtraFieldExtendedTimestamp:v,rawExtraFieldNTFS:z,rawExtraFieldAES:k,extraFieldLength:E}})(c=n.assign({},c,{rawFilename:f,rawComment:b,version:S,versionMadeBy:k,lastModDate:z,lastAccessDate:v,creationDate:A,rawExtraField:se,zip64:re,zip64UncompressedSize:pe,zip64CompressedSize:he,zip64Offset:ge,zip64DiskNumberStart:me,password:R,rawPassword:F,level:$||e.config.CompressionStream!==G||e.config.CompressionStreamNative!==G?H:0,useWebWorkers:X,encryptionStrength:N,extendedTimestamp:O,zipCrypto:q,bufferedWrite:Y,keepOrder:P,useUnicodeFileNames:Q,dataDescriptor:ne,dataDescriptorSignature:j,signal:J,msDosCompatible:C,internalFileAttribute:_,externalFileAttribute:D,useCompressionStream:$,passThrough:W,encrypted:!!(R&&Fr(R)||F&&Fr(F))||W&&ye,signature:be,compressionMethod:ee})),ke=(e=>{const{zip64:t,dataDescriptor:n,dataDescriptorSignature:r}=e;let s,i=new w,a=0;return n&&(i=new w(t?r?24:20:r?16:12),s=Rr(i),r&&(a=4,_r(s,0,I))),{dataDescriptorArray:i,dataDescriptorView:s,dataDescriptorOffset:a}})(c),ze=Fr(Se.localHeaderArray,ke.dataDescriptorArray);let ve;oe=ze+ae,e.options.usdz&&(oe+=oe+64),e.pendingEntriesSize+=oe;try{ve=await(async(e,r,s,a,o)=>{const{files:c,writer:l}=e,{keepOrder:f,dataDescriptor:p,signal:h}=o,{headerInfo:m}=a,{usdz:b}=e.options,S=t.from(c.values()).pop();let k,z,v,A,C,_,D,W={};c.set(r,W);try{let t;f&&(t=S&&S.lock,W.lock=new y((e=>v=e))),!(o.bufferedWrite||e.writerLocked||e.bufferedWrites&&f)&&p||b?(_=l,await R()):(_=new x,D=new u(_.readable).blob(),_.writable.size=0,k=!0,e.bufferedWrites++,await rn(l)),await rn(_);const{writable:m}=l;let{diskOffset:z}=l;if(e.addSplitZipSignature){delete e.addSplitZipSignature;const t=new w(4);_r(Rr(t),0,U),await kr(m,t),e.offset+=4}b&&((e,t)=>{const{headerInfo:n}=e;let{localHeaderArray:r,extraFieldLength:s}=n,i=Rr(r),a=64-(t+Fr(r))%64;4>a&&(a+=64);const o=new w(a),c=Rr(o);Cr(c,0,6534),Cr(c,2,a-2);const l=r;n.localHeaderArray=r=new w(Fr(l)+a),Wr(r,l),Wr(r,o,Fr(l)),i=Rr(r),Cr(i,28,s+a),e.metadataSize+=a})(a,e.offset-z),k||(await t,await F(m));const{diskNumber:T}=l;if(C=!0,W.diskNumberStart=T,W=await(async(e,t,{diskNumberStart:r,lock:s},a,o,c)=>{const{headerInfo:l,dataDescriptorInfo:u,metadataSize:f}=a,{localHeaderArray:d,headerArray:p,lastModDate:h,rawLastModDate:g,encrypted:m,compressed:y,version:b,compressionMethod:S,rawExtraFieldExtendedTimestamp:k,extraFieldExtendedTimestampFlag:z,rawExtraFieldNTFS:v,rawExtraFieldAES:x}=l,{dataDescriptorArray:A}=u,{rawFilename:C,lastAccessDate:_,creationDate:D,password:W,rawPassword:R,level:F,zip64:T,zip64UncompressedSize:L,zip64CompressedSize:U,zip64Offset:I,zip64DiskNumberStart:N,zipCrypto:q,dataDescriptor:O,directory:P,versionMadeBy:H,rawComment:M,rawExtraField:B,useWebWorkers:V,onstart:Z,onprogress:K,onend:X,signal:Y,encryptionStrength:j,extendedTimestamp:J,msDosCompatible:Q,internalFileAttribute:$,externalFileAttribute:ee,useCompressionStream:ne,passThrough:re}=c,se={lock:s,versionMadeBy:H,zip64:T,directory:!!P,filenameUTF8:!0,rawFilename:C,commentUTF8:!0,rawComment:M,rawExtraFieldExtendedTimestamp:k,rawExtraFieldNTFS:v,rawExtraFieldAES:x,rawExtraField:B,extendedTimestamp:J,msDosCompatible:Q,internalFileAttribute:$,externalFileAttribute:ee,diskNumberStart:r};let{signature:ie,uncompressedSize:ae}=c,oe=0;re||(ae=0);const{writable:ce}=t;if(e){e.chunkSize=te(o),await kr(ce,d);const t=e.readable,n=t.size=e.size,r={options:{codecType:ut,level:F,rawPassword:R,password:W,encryptionStrength:j,zipCrypto:m&&q,passwordVerification:m&&q&&g>>8&255,signed:!re,compressed:y&&!re,encrypted:m&&!re,useWebWorkers:V,useCompressionStream:ne,transferStreams:!1},config:o,streamOptions:{signal:Y,size:n,onstart:Z,onprogress:K,onend:X}},s=await Ct({readable:t,writable:ce},r);oe=s.outputSize,re||(ae=s.inputSize,ie=s.signature),ce.size+=ae}else await kr(ce,d);let le;if(T){let e=4;L&&(e+=8),U&&(e+=8),I&&(e+=8),N&&(e+=4),le=new w(e)}else le=new w;return((e,t)=>{const{signature:n,rawExtraFieldZip64:r,compressedSize:s,uncompressedSize:a,headerInfo:o,dataDescriptorInfo:c}=e,{headerView:l,encrypted:u}=o,{dataDescriptorView:f,dataDescriptorOffset:d}=c,{zip64:w,zip64UncompressedSize:p,zip64CompressedSize:h,zipCrypto:g,dataDescriptor:m}=t;if(u&&!g||n===G||(_r(l,10,n),m&&_r(f,d,n)),w){const e=Rr(r);Cr(e,0,1),Cr(e,2,Fr(r)-4);let t=4;p&&(_r(l,18,E),Dr(e,t,i(a)),t+=8),h&&(_r(l,14,E),Dr(e,t,i(s))),m&&(Dr(f,d+4,i(s)),Dr(f,d+12,i(a)))}else _r(l,14,s),_r(l,18,a),m&&(_r(f,d+4,s),_r(f,d+8,a))})({signature:ie,rawExtraFieldZip64:le,compressedSize:oe,uncompressedSize:ae,headerInfo:l,dataDescriptorInfo:u},c),O&&await kr(ce,A),n.assign(se,{uncompressedSize:ae,compressedSize:oe,lastModDate:h,rawLastModDate:g,creationDate:D,lastAccessDate:_,encrypted:m,zipCrypto:q,size:f+oe,compressionMethod:S,version:b,headerArray:p,signature:ie,rawExtraFieldZip64:le,extraFieldExtendedTimestampFlag:z,zip64UncompressedSize:L,zip64CompressedSize:U,zip64Offset:I,zip64DiskNumberStart:N}),se})(s,_,W,a,e.config,o),C=!1,c.set(r,W),W.filename=r,k){await _.writable.getWriter().close();let e=await D;await t,await R(),A=!0,p||(e=await(async(e,t,n,{zipCrypto:r})=>{let s;s=await t.slice(0,26).arrayBuffer(),26!=s.byteLength&&(s=s.slice(0,26));const i=new g(s);return e.encrypted&&!r||_r(i,14,e.signature),e.zip64?(_r(i,18,E),_r(i,22,E)):(_r(i,18,e.compressedSize),_r(i,22,e.uncompressedSize)),await kr(n,new w(s)),t.slice(s.byteLength)})(W,e,m,o)),await F(m),W.diskNumberStart=l.diskNumber,z=l.diskOffset,await e.stream().pipeTo(m,{preventClose:!0,preventAbort:!0,signal:h}),m.size+=e.size,A=!1}if(W.offset=e.offset-z,W.zip64)((e,t)=>{const{rawExtraFieldZip64:n,offset:r,diskNumberStart:s}=e,{zip64UncompressedSize:a,zip64CompressedSize:o,zip64Offset:c,zip64DiskNumberStart:l}=t,u=Rr(n);let f=4;a&&(f+=8),o&&(f+=8),c&&(Dr(u,f,i(r)),f+=8),l&&_r(u,f,s)})(W,o);else if(W.offset>E)throw new d(hr);return e.offset+=W.size,W}catch(t){if(k&&A||!k&&C){if(e.hasCorruptedEntries=!0,t)try{t.corruptedEntry=!0}catch(e){}k?e.offset+=_.writable.size:e.offset=_.writable.size}throw c.delete(r),t}finally{k&&e.bufferedWrites--,v&&v(),z&&z()}async function R(){e.writerLocked=!0;const{lockWriter:t}=e;e.lockWriter=new y((t=>z=()=>{e.writerLocked=!1,t()})),await t}async function F(e){Fr(m.localHeaderArray)>l.availableSize&&(l.availableSize=0,await kr(e,new w))}})(e,r,s,{headerInfo:Se,dataDescriptorInfo:ke,metadataSize:ze},c)}finally{e.pendingEntriesSize-=oe}return n.assign(ve,{name:r,comment:m,extraField:ie}),new Tn(ve)})(c,e,r,s),l.add(m),await m}catch(t){throw c.filenames.delete(e),t}finally{l.delete(m);const e=br.shift();e?e():yr--}}async close(e=new w,n={}){const{pendingAddFileCalls:r,writer:s}=this,{writable:o}=s;for(;r.size;)await y.allSettled(t.from(r));return await(async(e,n,r)=>{const{files:s,writer:o}=e,{diskOffset:c,writable:l}=o;let{diskNumber:u}=o,f=0,p=0,h=e.offset-c,g=s.size;for(const[,e]of s){const{rawFilename:t,rawExtraFieldZip64:n,rawExtraFieldAES:r,rawComment:s,rawExtraFieldNTFS:i,rawExtraField:o,extendedTimestamp:c,extraFieldExtendedTimestampFlag:l,lastModDate:u}=e;let f;if(c){f=new w(9);const e=Rr(f);Cr(e,0,M),Cr(e,2,5),Ar(e,4,l),_r(e,5,a.floor(u.getTime()/1e3))}else f=new w;e.rawExtraFieldCDExtendedTimestamp=f,p+=46+Fr(t,s,n,r,i,f,o)}const m=new w(p),y=Rr(m);await rn(o);let b=0;for(const[e,n]of t.from(s.values()).entries()){const{offset:t,rawFilename:i,rawExtraFieldZip64:a,rawExtraFieldAES:c,rawExtraFieldCDExtendedTimestamp:u,rawExtraFieldNTFS:d,rawExtraField:w,rawComment:p,versionMadeBy:h,headerArray:g,directory:S,zip64:k,zip64UncompressedSize:z,zip64CompressedSize:v,zip64DiskNumberStart:x,zip64Offset:A,msDosCompatible:C,internalFileAttribute:_,externalFileAttribute:D,diskNumberStart:W,uncompressedSize:R,compressedSize:F}=n,L=Fr(a,c,u,d,w);_r(y,f,N),Cr(y,f+4,h);const U=Rr(g);z||_r(U,18,R),v||_r(U,14,F),Wr(m,g,f+6),Cr(y,f+30,L),Cr(y,f+32,Fr(p)),Cr(y,f+34,k&&x?T:W),Cr(y,f+36,_),D?_r(y,f+38,D):S&&C&&Ar(y,f+38,16),_r(y,f+42,k&&A?E:t),Wr(m,i,f+46),Wr(m,a,f+46+Fr(i)),Wr(m,c,f+46+Fr(i,a)),Wr(m,u,f+46+Fr(i,a,c)),Wr(m,d,f+46+Fr(i,a,c,u)),Wr(m,w,f+46+Fr(i,a,c,u,d)),Wr(m,p,f+46+Fr(i)+L);const I=46+Fr(i,p)+L;if(f-b>o.availableSize&&(o.availableSize=0,await kr(l,m.slice(b,f)),b=f),f+=I,r.onprogress)try{await r.onprogress(e+1,s.size,new Tn(n))}catch(e){}}await kr(l,b?m.slice(b):m);let S=o.diskNumber;const{availableSize:k}=o;H>k&&S++;let z=vr(e,r,_n);if(h>E||p>E||g>T||S>T){if(!1===z)throw new d(hr);z=!0}const v=new w(z?98:H),x=Rr(v);f=0,z&&(_r(x,0,O),Dr(x,4,i(44)),Cr(x,12,45),Cr(x,14,45),_r(x,16,S),_r(x,20,u),Dr(x,24,i(g)),Dr(x,32,i(g)),Dr(x,40,i(p)),Dr(x,48,i(h)),_r(x,56,P),Dr(x,64,i(h)+i(p)),_r(x,72,S+1),vr(e,r,"supportZip64SplitFile",!0)&&(S=T,u=T),g=T,h=E,p=E,f+=76),_r(x,f,q),Cr(x,f+4,S),Cr(x,f+6,u),Cr(x,f+8,g),Cr(x,f+10,g),_r(x,f+12,p),_r(x,f+16,h);const A=Fr(n);if(A){if(A>T)throw new d(cr);Cr(x,f+20,A)}await kr(l,v),A&&await kr(l,n)})(this,e,n),vr(this,n,"preventClose")||await o.getWriter().close(),s.getData?s.getData():o}}async function kr(e,t){const n=e.getWriter();try{await n.ready,e.size+=Fr(t),await n.write(t)}finally{n.releaseLock()}}function zr(e){if(e)return(i(e.getTime())+i(116444736e5))*i(1e4)}function vr(e,t,n,r){const s=t[n]===G?e.options[n]:t[n];return s===G?r:s}function xr(e){return e+5*(a.floor(e/16383)+1)}function Ar(e,t,n){e.setUint8(t,n)}function Cr(e,t,n){e.setUint16(t,n,!0)}function _r(e,t,n){e.setUint32(t,n,!0)}function Dr(e,t,n){e.setBigUint64(t,n,!0)}function Wr(e,t,n){e.set(t,n)}function Rr(e){return new g(e.buffer)}function Fr(...e){let t=0;return e.forEach((e=>e&&(t+=e.length))),t}let Er;try{Er=void 0===k&&"undefined"==typeof location?require("url").pathToFileURL(__filename).href:void 0===k?location.href:F&&"SCRIPT"===F.tagName.toUpperCase()&&F.src||new f("zip.min.js",k.baseURI).href}catch(e){}ne({baseURL:Er}),((e,t={})=>{const n='const{Array:e,Object:t,Number:n,Math:r,Error:s,Uint8Array:i,Uint16Array:o,Uint32Array:c,Int32Array:f,Map:a,DataView:l,Promise:u,TextEncoder:w,crypto:h,postMessage:d,TransformStream:p,ReadableStream:y,WritableStream:m,CompressionStream:b,DecompressionStream:g}=self,k=void 0,v="undefined",S="function";class z{constructor(e){return class extends p{constructor(t,n){const r=new e(n);super({transform(e,t){t.enqueue(r.append(e))},flush(e){const t=r.flush();t&&e.enqueue(t)}})}}}}const C=[];for(let e=0;256>e;e++){let t=e;for(let e=0;8>e;e++)1&t?t=t>>>1^3988292384:t>>>=1;C[e]=t}class x{constructor(e){this.t=e||-1}append(e){let t=0|this.t;for(let n=0,r=0|e.length;r>n;n++)t=t>>>8^C[255&(t^e[n])];this.t=t}get(){return~this.t}}class A extends p{constructor(){let e;const t=new x;super({transform(e,n){t.append(e),n.enqueue(e)},flush(){const n=new i(4);new l(n.buffer).setUint32(0,t.get()),e.value=n}}),e=this}}const _={concat(e,t){if(0===e.length||0===t.length)return e.concat(t);const n=e[e.length-1],r=_.i(n);return 32===r?e.concat(t):_.o(t,r,0|n,e.slice(0,e.length-1))},l(e){const t=e.length;if(0===t)return 0;const n=e[t-1];return 32*(t-1)+_.i(n)},u(e,t){if(32*e.length0&&t&&(e[n-1]=_.h(t,e[n-1]&2147483648>>t-1,1)),e},h:(e,t,n)=>32===e?t:(n?0|t:t<<32-e)+1099511627776*e,i:e=>r.round(e/1099511627776)||32,o(e,t,n,r){for(void 0===r&&(r=[]);t>=32;t-=32)r.push(n),n=0;if(0===t)return r.concat(e);for(let s=0;s>>t),n=e[s]<<32-t;const s=e.length?e[e.length-1]:0,i=_.i(s);return r.push(_.h(t+i&31,t+i>32?n:r.pop(),1)),r}},I={bytes:{p(e){const t=_.l(e)/8,n=new i(t);let r;for(let s=0;t>s;s++)3&s||(r=e[s/4]),n[s]=r>>>24,r<<=8;return n},m(e){const t=[];let n,r=0;for(n=0;n9007199254740991)throw new s("Cannot hash more than 2^53 - 1 bits");const o=new c(n);let f=0;for(let e=t.blockSize+r-(t.blockSize+r&t.blockSize-1);i>=e;e+=t.blockSize)t.I(o.subarray(16*f,16*(f+1))),f+=1;return n.splice(0,16*f),t}P(){const e=this;let t=e.C;const n=e.S;t=_.concat(t,[_.h(1,1)]);for(let e=t.length+2;15&e;e++)t.push(0);for(t.push(r.floor(e.A/4294967296)),t.push(0|e.A);t.length;)e.I(t.splice(0,16));return e.reset(),n}D(e,t,n,r){return e>19?e>39?e>59?e>79?void 0:t^n^r:t&n|t&r|n&r:t^n^r:t&n|~t&r}V(e,t){return t<>>32-e}I(t){const n=this,s=n.S,i=e(80);for(let e=0;16>e;e++)i[e]=t[e];let o=s[0],c=s[1],f=s[2],a=s[3],l=s[4];for(let e=0;79>=e;e++){16>e||(i[e]=n.V(1,i[e-3]^i[e-8]^i[e-14]^i[e-16]));const t=n.V(5,o)+n.D(e,c,f,a)+l+i[e]+n.v[r.floor(e/20)]|0;l=a,a=f,f=n.V(30,c),c=o,o=t}s[0]=s[0]+o|0,s[1]=s[1]+c|0,s[2]=s[2]+f|0,s[3]=s[3]+a|0,s[4]=s[4]+l|0}},D={getRandomValues(e){const t=new c(e.buffer),n=e=>{let t=987654321;const n=4294967295;return()=>(t=36969*(65535&t)+(t>>16)&n,(((t<<16)+(e=18e3*(65535&e)+(e>>16)&n)&n)/4294967296+.5)*(r.random()>.5?1:-1))};for(let s,i=0;inew V.R(I.bytes.m(e)),B(e,t,n,r){if(n=n||1e4,0>r||0>n)throw new s("invalid params to pbkdf2");const i=1+(r>>5)<<2;let o,c,f,a,u;const w=new ArrayBuffer(i),h=new l(w);let d=0;const p=_;for(t=I.bytes.m(t),u=1;(i||1)>d;u++){for(o=c=e.encrypt(p.concat(t,[u])),f=1;n>f;f++)for(c=e.encrypt(c),a=0;ad&&fs&&(e=(new n).update(e).P());for(let t=0;s>t;t++)r[0][t]=909522486^e[t],r[1][t]=1549556828^e[t];t.U[0].update(r[0]),t.U[1].update(r[1]),t.K=new n(t.U[0])}reset(){const e=this;e.K=new e.M(e.U[0]),e.N=!1}update(e){this.N=!0,this.K.update(e)}digest(){const e=this,t=e.K.P(),n=new e.M(e.U[1]).update(t).P();return e.reset(),n}encrypt(e){if(this.N)throw new s("encrypt on already updated hmac called!");return this.update(e),this.digest(e)}}},R=typeof h!=v&&typeof h.getRandomValues==S,B="Invalid password",E="Invalid signature",M="zipjs-abort-check-password";function U(e){return R?h.getRandomValues(e):D.getRandomValues(e)}const K=16,N={name:"PBKDF2"},O=t.assign({hash:{name:"HMAC"}},N),T=t.assign({iterations:1e3,hash:{name:"SHA-1"}},N),W=["deriveBits"],j=[8,12,16],H=[16,24,32],L=10,F=[0,0,0,0],q=typeof h!=v,G=q&&h.subtle,J=q&&typeof G!=v,Q=I.bytes,X=class{constructor(e){const t=this;t.O=[[[],[],[],[],[]],[[],[],[],[],[]]],t.O[0][0][0]||t.T();const n=t.O[0][4],r=t.O[1],i=e.length;let o,c,f,a=1;if(4!==i&&6!==i&&8!==i)throw new s("invalid aes key size");for(t.v=[c=e.slice(0),f=[]],o=i;4*i+28>o;o++){let e=c[o-1];(o%i==0||8===i&&o%i==4)&&(e=n[e>>>24]<<24^n[e>>16&255]<<16^n[e>>8&255]<<8^n[255&e],o%i==0&&(e=e<<8^e>>>24^a<<24,a=a<<1^283*(a>>7))),c[o]=c[o-i]^e}for(let e=0;o;e++,o--){const t=c[3&e?o:o-4];f[e]=4>=o||4>e?t:r[0][n[t>>>24]]^r[1][n[t>>16&255]]^r[2][n[t>>8&255]]^r[3][n[255&t]]}}encrypt(e){return this.W(e,0)}decrypt(e){return this.W(e,1)}T(){const e=this.O[0],t=this.O[1],n=e[4],r=t[4],s=[],i=[];let o,c,f,a;for(let e=0;256>e;e++)i[(s[e]=e<<1^283*(e>>7))^e]=e;for(let l=o=0;!n[l];l^=c||1,o=i[o]||1){let i=o^o<<1^o<<2^o<<3^o<<4;i=i>>8^255&i^99,n[l]=i,r[i]=l,a=s[f=s[c=s[l]]];let u=16843009*a^65537*f^257*c^16843008*l,w=257*s[i]^16843008*i;for(let n=0;4>n;n++)e[n][l]=w=w<<24^w>>>8,t[n][i]=u=u<<24^u>>>8}for(let n=0;5>n;n++)e[n]=e[n].slice(0),t[n]=t[n].slice(0)}W(e,t){if(4!==e.length)throw new s("invalid aes block size");const n=this.v[t],r=n.length/4-2,i=[0,0,0,0],o=this.O[t],c=o[0],f=o[1],a=o[2],l=o[3],u=o[4];let w,h,d,p=e[0]^n[0],y=e[t?3:1]^n[1],m=e[2]^n[2],b=e[t?1:3]^n[3],g=4;for(let e=0;r>e;e++)w=c[p>>>24]^f[y>>16&255]^a[m>>8&255]^l[255&b]^n[g],h=c[y>>>24]^f[m>>16&255]^a[b>>8&255]^l[255&p]^n[g+1],d=c[m>>>24]^f[b>>16&255]^a[p>>8&255]^l[255&y]^n[g+2],b=c[b>>>24]^f[p>>16&255]^a[y>>8&255]^l[255&m]^n[g+3],g+=4,p=w,y=h,m=d;for(let e=0;4>e;e++)i[t?3&-e:e]=u[p>>>24]<<24^u[y>>16&255]<<16^u[m>>8&255]<<8^u[255&b]^n[g++],w=p,p=y,y=m,m=b,b=w;return i}},Y=class{constructor(e,t){this.j=e,this.H=t,this.L=t}reset(){this.L=this.H}update(e){return this.F(this.j,e,this.L)}q(e){if(255&~(e>>24))e+=1<<24;else{let t=e>>16&255,n=e>>8&255,r=255&e;255===t?(t=0,255===n?(n=0,255===r?r=0:++r):++n):++t,e=0,e+=t<<16,e+=n<<8,e+=r}return e}G(e){0===(e[0]=this.q(e[0]))&&(e[1]=this.q(e[1]))}F(e,t,n){let r;if(!(r=t.length))return[];const s=_.l(t);for(let s=0;r>s;s+=4){this.G(n);const r=e.encrypt(n);t[s]^=r[0],t[s+1]^=r[1],t[s+2]^=r[2],t[s+3]^=r[3]}return _.u(t,s)}},Z=V.R;let $=q&&J&&typeof G.importKey==S,ee=q&&J&&typeof G.deriveBits==S;class te extends p{constructor({password:e,rawPassword:n,signed:r,encryptionStrength:o,checkPasswordOnly:c}){super({start(){t.assign(this,{ready:new u((e=>this.J=e)),password:ie(e,n),signed:r,X:o-1,pending:new i})},async transform(e,t){const n=this,{password:r,X:o,J:f,ready:a}=n;r?(await(async(e,t,n,r)=>{const i=await se(e,t,n,ce(r,0,j[t])),o=ce(r,j[t]);if(i[0]!=o[0]||i[1]!=o[1])throw new s(B)})(n,o,r,ce(e,0,j[o]+2)),e=ce(e,j[o]+2),c?t.error(new s(M)):f()):await a;const l=new i(e.length-L-(e.length-L)%K);t.enqueue(re(n,e,l,0,L,!0))},async flush(e){const{signed:t,Y:n,Z:r,pending:o,ready:c}=this;if(r&&n){await c;const f=ce(o,0,o.length-L),a=ce(o,o.length-L);let l=new i;if(f.length){const e=ae(Q,f);r.update(e);const t=n.update(e);l=fe(Q,t)}if(t){const e=ce(fe(Q,r.digest()),0,L);for(let t=0;L>t;t++)if(e[t]!=a[t])throw new s(E)}e.enqueue(l)}}})}}class ne extends p{constructor({password:e,rawPassword:n,encryptionStrength:r}){let s;super({start(){t.assign(this,{ready:new u((e=>this.J=e)),password:ie(e,n),X:r-1,pending:new i})},async transform(e,t){const n=this,{password:r,X:s,J:o,ready:c}=n;let f=new i;r?(f=await(async(e,t,n)=>{const r=U(new i(j[t]));return oe(r,await se(e,t,n,r))})(n,s,r),o()):await c;const a=new i(f.length+e.length-e.length%K);a.set(f,0),t.enqueue(re(n,e,a,f.length,0))},async flush(e){const{Y:t,Z:n,pending:r,ready:o}=this;if(n&&t){await o;let c=new i;if(r.length){const e=t.update(ae(Q,r));n.update(e),c=fe(Q,e)}s.signature=fe(Q,n.digest()).slice(0,L),e.enqueue(oe(c,s.signature))}}}),s=this}}function re(e,t,n,r,s,o){const{Y:c,Z:f,pending:a}=e,l=t.length-s;let u;for(a.length&&(t=oe(a,t),n=((e,t)=>{if(t&&t>e.length){const n=e;(e=new i(t)).set(n,0)}return e})(n,l-l%K)),u=0;l-K>=u;u+=K){const e=ae(Q,ce(t,u,u+K));o&&f.update(e);const s=c.update(e);o||f.update(s),n.set(fe(Q,s),u+r)}return e.pending=ce(t,u),n}async function se(n,r,s,o){n.password=null;const c=await(async(e,t,n,r,s)=>{if(!$)return V.importKey(t);try{return await G.importKey("raw",t,n,!1,s)}catch(e){return $=!1,V.importKey(t)}})(0,s,O,0,W),f=await(async(e,t,n)=>{if(!ee)return V.B(t,e.salt,T.iterations,n);try{return await G.deriveBits(e,t,n)}catch(r){return ee=!1,V.B(t,e.salt,T.iterations,n)}})(t.assign({salt:o},T),c,8*(2*H[r]+2)),a=new i(f),l=ae(Q,ce(a,0,H[r])),u=ae(Q,ce(a,H[r],2*H[r])),w=ce(a,2*H[r]);return t.assign(n,{keys:{key:l,$:u,passwordVerification:w},Y:new Y(new X(l),e.from(F)),Z:new Z(u)}),w}function ie(e,t){return t===k?(e=>{if(typeof w==v){const t=new i((e=unescape(encodeURIComponent(e))).length);for(let n=0;n>>24]),i=~e.te.get(),e.keys=[n,s,i]}function ye(e){const t=2|e.keys[2];return me(r.imul(t,1^t)>>>8)}function me(e){return 255&e}function be(e){return 4294967295&e}const ge="deflate-raw";class ke extends p{constructor(e,{chunkSize:t,CompressionStream:n,CompressionStreamNative:r}){super({});const{compressed:s,encrypted:i,useCompressionStream:o,zipCrypto:c,signed:f,level:a}=e,u=this;let w,h,d=Se(super.readable);i&&!c||!f||(w=new A,d=xe(d,w)),s&&(d=Ce(d,o,{level:a,chunkSize:t},r,n)),i&&(c?d=xe(d,new ue(e)):(h=new ne(e),d=xe(d,h))),ze(u,d,(()=>{let e;i&&!c&&(e=h.signature),i&&!c||!f||(e=new l(w.value.buffer).getUint32(0)),u.signature=e}))}}class ve extends p{constructor(e,{chunkSize:t,DecompressionStream:n,DecompressionStreamNative:r}){super({});const{zipCrypto:i,encrypted:o,signed:c,signature:f,compressed:a,useCompressionStream:u}=e;let w,h,d=Se(super.readable);o&&(i?d=xe(d,new le(e)):(h=new te(e),d=xe(d,h))),a&&(d=Ce(d,u,{chunkSize:t},r,n)),o&&!i||!c||(w=new A,d=xe(d,w)),ze(this,d,(()=>{if((!o||i)&&c){const e=new l(w.value.buffer);if(f!=e.getUint32(0,!1))throw new s(E)}}))}}function Se(e){return xe(e,new p({transform(e,t){e&&e.length&&t.enqueue(e)}}))}function ze(e,n,r){n=xe(n,new p({flush:r})),t.defineProperty(e,"readable",{get:()=>n})}function Ce(e,t,n,r,s){try{e=xe(e,new(t&&r?r:s)(ge,n))}catch(r){if(!t)return e;try{e=xe(e,new s(ge,n))}catch(t){return e}}return e}function xe(e,t){return e.pipeThrough(t)}const Ae="data",_e="close";class Ie extends p{constructor(e,n){super({});const r=this,{codecType:s}=e;let i;s.startsWith("deflate")?i=ke:s.startsWith("inflate")&&(i=ve);let o=0,c=0;const f=new i(e,n),a=super.readable,l=new p({transform(e,t){e&&e.length&&(c+=e.length,t.enqueue(e))},flush(){t.assign(r,{inputSize:c})}}),u=new p({transform(e,t){e&&e.length&&(o+=e.length,t.enqueue(e))},flush(){const{signature:e}=f;t.assign(r,{signature:e,outputSize:o,inputSize:c})}});t.defineProperty(r,"readable",{get:()=>a.pipeThrough(l).pipeThrough(f).pipeThrough(u)})}}class Pe extends p{constructor(e){let t;super({transform:function n(r,s){if(t){const e=new i(t.length+r.length);e.set(t),e.set(r,t.length),r=e,t=null}r.length>e?(s.enqueue(r.slice(0,e)),n(r.slice(e),s)):t=r},flush(e){t&&t.length&&e.enqueue(t)}})}}const De=new a,Ve=new a;let Re,Be=0,Ee=!0;async function Me(e){try{const{options:t,scripts:r,config:s}=e;if(r&&r.length)try{Ee?importScripts.apply(k,r):await Ue(r)}catch(e){Ee=!1,await Ue(r)}self.initCodec&&self.initCodec(),s.CompressionStreamNative=self.CompressionStream,s.DecompressionStreamNative=self.DecompressionStream,self.Deflate&&(s.CompressionStream=new z(self.Deflate)),self.Inflate&&(s.DecompressionStream=new z(self.Inflate));const i={highWaterMark:1},o=e.readable||new y({async pull(e){const t=new u((e=>De.set(Be,e)));Ke({type:"pull",messageId:Be}),Be=(Be+1)%n.MAX_SAFE_INTEGER;const{value:r,done:s}=await t;e.enqueue(r),s&&e.close()}},i),c=e.writable||new m({async write(e){let t;const r=new u((e=>t=e));Ve.set(Be,t),Ke({type:Ae,value:e,messageId:Be}),Be=(Be+1)%n.MAX_SAFE_INTEGER,await r}},i),f=new Ie(t,s);Re=new AbortController;const{signal:a}=Re;await o.pipeThrough(f).pipeThrough(new Pe(s.chunkSize)).pipeTo(c,{signal:a,preventClose:!0,preventAbort:!0}),await c.getWriter().close();const{signature:l,inputSize:w,outputSize:h}=f;Ke({type:_e,result:{signature:l,inputSize:w,outputSize:h}})}catch(e){Ne(e)}}async function Ue(e){for(const t of e)await import(t)}function Ke(e){let{value:t}=e;if(t)if(t.length)try{t=new i(t),e.value=t.buffer,d(e,[e.value])}catch(t){d(e)}else d(e);else d(e)}function Ne(e=new s("Unknown error")){const{message:t,stack:n,code:r,name:i}=e;d({error:{message:t,stack:n,code:r,name:i}})}addEventListener("message",(({data:e})=>{const{type:t,messageId:n,value:r,done:s}=e;try{if("start"==t&&Me(e),t==Ae){const e=De.get(n);De.delete(n),e({value:new i(r),done:s})}if("ack"==t){const e=Ve.get(n);Ve.delete(n),e()}t==_e&&Re.abort()}catch(e){Ne(e)}}));const Oe=-2;function Te(t){return We(t.map((([t,n])=>new e(t).fill(n,0,t))))}function We(t){return t.reduce(((t,n)=>t.concat(e.isArray(n)?We(n):n)),[])}const je=[0,1,2,3].concat(...Te([[2,4],[2,5],[4,6],[4,7],[8,8],[8,9],[16,10],[16,11],[32,12],[32,13],[64,14],[64,15],[2,0],[1,16],[1,17],[2,18],[2,19],[4,20],[4,21],[8,22],[8,23],[16,24],[16,25],[32,26],[32,27],[64,28],[64,29]]));function He(){const e=this;function t(e,t){let n=0;do{n|=1&e,e>>>=1,n<<=1}while(--t>0);return n>>>1}e.ne=n=>{const s=e.re,i=e.ie.se,o=e.ie.oe;let c,f,a,l=-1;for(n.ce=0,n.fe=573,c=0;o>c;c++)0!==s[2*c]?(n.ae[++n.ce]=l=c,n.le[c]=0):s[2*c+1]=0;for(;2>n.ce;)a=n.ae[++n.ce]=2>l?++l:0,s[2*a]=1,n.le[a]=0,n.ue--,i&&(n.we-=i[2*a+1]);for(e.he=l,c=r.floor(n.ce/2);c>=1;c--)n.de(s,c);a=o;do{c=n.ae[1],n.ae[1]=n.ae[n.ce--],n.de(s,1),f=n.ae[1],n.ae[--n.fe]=c,n.ae[--n.fe]=f,s[2*a]=s[2*c]+s[2*f],n.le[a]=r.max(n.le[c],n.le[f])+1,s[2*c+1]=s[2*f+1]=a,n.ae[1]=a++,n.de(s,1)}while(n.ce>=2);n.ae[--n.fe]=n.ae[1],(t=>{const n=e.re,r=e.ie.se,s=e.ie.pe,i=e.ie.ye,o=e.ie.me;let c,f,a,l,u,w,h=0;for(l=0;15>=l;l++)t.be[l]=0;for(n[2*t.ae[t.fe]+1]=0,c=t.fe+1;573>c;c++)f=t.ae[c],l=n[2*n[2*f+1]+1]+1,l>o&&(l=o,h++),n[2*f+1]=l,f>e.he||(t.be[l]++,u=0,i>f||(u=s[f-i]),w=n[2*f],t.ue+=w*(l+u),r&&(t.we+=w*(r[2*f+1]+u)));if(0!==h){do{for(l=o-1;0===t.be[l];)l--;t.be[l]--,t.be[l+1]+=2,t.be[o]--,h-=2}while(h>0);for(l=o;0!==l;l--)for(f=t.be[l];0!==f;)a=t.ae[--c],a>e.he||(n[2*a+1]!=l&&(t.ue+=(l-n[2*a+1])*n[2*a],n[2*a+1]=l),f--)}})(n),((e,n,r)=>{const s=[];let i,o,c,f=0;for(i=1;15>=i;i++)s[i]=f=f+r[i-1]<<1;for(o=0;n>=o;o++)c=e[2*o+1],0!==c&&(e[2*o]=t(s[c]++,c))})(s,e.he,n.be)}}function Le(e,t,n,r,s){const i=this;i.se=e,i.pe=t,i.ye=n,i.oe=r,i.me=s}He.ge=[0,1,2,3,4,5,6,7].concat(...Te([[2,8],[2,9],[2,10],[2,11],[4,12],[4,13],[4,14],[4,15],[8,16],[8,17],[8,18],[8,19],[16,20],[16,21],[16,22],[16,23],[32,24],[32,25],[32,26],[31,27],[1,28]])),He.ke=[0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224,0],He.ve=[0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576],He.Se=e=>256>e?je[e]:je[256+(e>>>7)],He.ze=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],He.Ce=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],He.xe=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],He.Ae=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];const Fe=Te([[144,8],[112,9],[24,7],[8,8]]);Le._e=We([12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,19,275,147,403,83,339,211,467,51,307,179,435,115,371,243,499,11,267,139,395,75,331,203,459,43,299,171,427,107,363,235,491,27,283,155,411,91,347,219,475,59,315,187,443,123,379,251,507,7,263,135,391,71,327,199,455,39,295,167,423,103,359,231,487,23,279,151,407,87,343,215,471,55,311,183,439,119,375,247,503,15,271,143,399,79,335,207,463,47,303,175,431,111,367,239,495,31,287,159,415,95,351,223,479,63,319,191,447,127,383,255,511,0,64,32,96,16,80,48,112,8,72,40,104,24,88,56,120,4,68,36,100,20,84,52,116,3,131,67,195,35,163,99,227].map(((e,t)=>[e,Fe[t]])));const qe=Te([[30,5]]);function Ge(e,t,n,r,s){const i=this;i.Ie=e,i.Pe=t,i.De=n,i.Ve=r,i.Re=s}Le.Be=We([0,16,8,24,4,20,12,28,2,18,10,26,6,22,14,30,1,17,9,25,5,21,13,29,3,19,11,27,7,23].map(((e,t)=>[e,qe[t]]))),Le.Ee=new Le(Le._e,He.ze,257,286,15),Le.Me=new Le(Le.Be,He.Ce,0,30,15),Le.Ue=new Le(null,He.xe,0,19,7);const Je=[new Ge(0,0,0,0,0),new Ge(4,4,8,4,1),new Ge(4,5,16,8,1),new Ge(4,6,32,32,1),new Ge(4,4,16,16,2),new Ge(8,16,32,32,2),new Ge(8,16,128,128,2),new Ge(8,32,128,256,2),new Ge(32,128,258,1024,2),new Ge(32,258,258,4096,2)],Qe=["need dictionary","stream end","","","stream error","data error","","buffer error","",""],Xe=113,Ye=666,Ze=262;function $e(e,t,n,r){const s=e[2*t],i=e[2*n];return i>s||s==i&&r[t]<=r[n]}function et(){const e=this;let t,n,s,c,f,a,l,u,w,h,d,p,y,m,b,g,k,v,S,z,C,x,A,_,I,P,D,V,R,B,E,M,U;const K=new He,N=new He,O=new He;let T,W,j,H,L,F;function q(){let t;for(t=0;286>t;t++)E[2*t]=0;for(t=0;30>t;t++)M[2*t]=0;for(t=0;19>t;t++)U[2*t]=0;E[512]=1,e.ue=e.we=0,W=j=0}function G(e,t){let n,r=-1,s=e[1],i=0,o=7,c=4;0===s&&(o=138,c=3),e[2*(t+1)+1]=65535;for(let f=0;t>=f;f++)n=s,s=e[2*(f+1)+1],++ii?U[2*n]+=i:0!==n?(n!=r&&U[2*n]++,U[32]++):i>10?U[36]++:U[34]++,i=0,r=n,0===s?(o=138,c=3):n==s?(o=6,c=3):(o=7,c=4))}function J(t){e.Ke[e.pending++]=t}function Q(e){J(255&e),J(e>>>8&255)}function X(e,t){let n;const r=t;F>16-r?(n=e,L|=n<>>16-F,F+=r-16):(L|=e<=n;n++)if(r=i,i=e[2*(n+1)+1],++o>=c||r!=i){if(f>o)do{Y(r,U)}while(0!=--o);else 0!==r?(r!=s&&(Y(r,U),o--),Y(16,U),X(o-3,2)):o>10?(Y(18,U),X(o-11,7)):(Y(17,U),X(o-3,3));o=0,s=r,0===i?(c=138,f=3):r==i?(c=6,f=3):(c=7,f=4)}}function $(){16==F?(Q(L),L=0,F=0):8>F||(J(255&L),L>>>=8,F-=8)}function ee(t,n){let s,i,o;if(e.Ne[W]=t,e.Oe[W]=255&n,W++,0===t?E[2*n]++:(j++,t--,E[2*(He.ge[n]+256+1)]++,M[2*He.Se(t)]++),!(8191&W)&&D>2){for(s=8*W,i=C-k,o=0;30>o;o++)s+=M[2*o]*(5+He.Ce[o]);if(s>>>=3,jc);Y(256,t),H=t[513]}function ne(){F>8?Q(L):F>0&&J(255&L),L=0,F=0}function re(t,n,r){X(0+(r?1:0),3),((t,n)=>{ne(),H=8,Q(n),Q(~n),e.Ke.set(u.subarray(t,t+n),e.pending),e.pending+=n})(t,n)}function se(n){((t,n,r)=>{let s,i,o=0;D>0?(K.ne(e),N.ne(e),o=(()=>{let t;for(G(E,K.he),G(M,N.he),O.ne(e),t=18;t>=3&&0===U[2*He.Ae[t]+1];t--);return e.ue+=14+3*(t+1),t})(),s=e.ue+3+7>>>3,i=e.we+3+7>>>3,i>s||(s=i)):s=i=n+5,n+4>s||-1==t?i==s?(X(2+(r?1:0),3),te(Le._e,Le.Be)):(X(4+(r?1:0),3),((e,t,n)=>{let r;for(X(e-257,5),X(t-1,5),X(n-4,4),r=0;n>r;r++)X(U[2*He.Ae[r]+1],3);Z(E,e-1),Z(M,t-1)})(K.he+1,N.he+1,o+1),te(E,M)):re(t,n,r),q(),r&&ne()})(0>k?-1:k,C-k,n),k=C,t.Te()}function ie(){let e,n,r,s;do{if(s=w-A-C,0===s&&0===C&&0===A)s=f;else if(-1==s)s--;else if(C>=f+f-Ze){u.set(u.subarray(f,f+f),0),x-=f,C-=f,k-=f,e=y,r=e;do{n=65535&d[--r],d[r]=f>n?0:n-f}while(0!=--e);e=f,r=e;do{n=65535&h[--r],h[r]=f>n?0:n-f}while(0!=--e);s+=f}if(0===t.We)return;e=t.je(u,C+A,s),A+=e,3>A||(p=255&u[C],p=(p<A&&0!==t.We)}function oe(e){let t,n,r=I,s=C,i=_;const o=C>f-Ze?C-(f-Ze):0;let c=B;const a=l,w=C+258;let d=u[s+i-1],p=u[s+i];R>_||(r>>=2),c>A&&(c=A);do{if(t=e,u[t+i]==p&&u[t+i-1]==d&&u[t]==u[s]&&u[++t]==u[s+1]){s+=2,t++;do{}while(u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&w>s);if(n=258-(w-s),s=w-258,n>i){if(x=e,i=n,n>=c)break;d=u[s+i-1],p=u[s+i]}}}while((e=65535&h[e&a])>o&&0!=--r);return i>A?A:i}e.le=[],e.be=[],e.ae=[],E=[],M=[],U=[],e.de=(t,n)=>{const r=e.ae,s=r[n];let i=n<<1;for(;i<=e.ce&&(i(W||(W=8),j||(j=8),G||(G=0),t.Le=null,-1==S&&(S=6),1>j||j>9||8!=W||9>x||x>15||0>S||S>9||0>G||G>2?Oe:(t.Fe=e,a=x,f=1<(t.qe=t.Ge=0,t.Le=null,e.pending=0,e.Je=0,n=Xe,c=0,K.re=E,K.ie=Le.Ee,N.re=M,N.ie=Le.Me,O.re=U,O.ie=Le.Ue,L=0,F=0,H=8,q(),(()=>{w=2*f,d[y-1]=0;for(let e=0;y-1>e;e++)d[e]=0;P=Je[D].Pe,R=Je[D].Ie,B=Je[D].De,I=Je[D].Ve,C=0,k=0,A=0,v=_=2,z=0,p=0})(),0))(t))),e.Qe=()=>42!=n&&n!=Xe&&n!=Ye?Oe:(e.Oe=null,e.Ne=null,e.Ke=null,d=null,h=null,u=null,e.Fe=null,n==Xe?-3:0),e.Xe=(e,t,n)=>{let r=0;return-1==t&&(t=6),0>t||t>9||0>n||n>2?Oe:(Je[D].Re!=Je[t].Re&&0!==e.qe&&(r=e.Ye(1)),D!=t&&(D=t,P=Je[D].Pe,R=Je[D].Ie,B=Je[D].De,I=Je[D].Ve),V=n,r)},e.Ze=(e,t,r)=>{let s,i=r,o=0;if(!t||42!=n)return Oe;if(3>i)return 0;for(i>f-Ze&&(i=f-Ze,o=r-i),u.set(t.subarray(o,o+i),0),C=i,k=i,p=255&u[0],p=(p<=s;s++)p=(p<{let o,w,m,I,R;if(i>4||0>i)return Oe;if(!r.$e||!r.et&&0!==r.We||n==Ye&&4!=i)return r.Le=Qe[4],Oe;if(0===r.tt)return r.Le=Qe[7],-5;var B;if(t=r,I=c,c=i,42==n&&(w=8+(a-8<<4)<<8,m=(D-1&255)>>1,m>3&&(m=3),w|=m<<6,0!==C&&(w|=32),w+=31-w%31,n=Xe,J((B=w)>>8&255),J(255&B)),0!==e.pending){if(t.Te(),0===t.tt)return c=-1,0}else if(0===t.We&&I>=i&&4!=i)return t.Le=Qe[7],-5;if(n==Ye&&0!==t.We)return r.Le=Qe[7],-5;if(0!==t.We||0!==A||0!=i&&n!=Ye){switch(R=-1,Je[D].Re){case 0:R=(e=>{let n,r=65535;for(r>s-5&&(r=s-5);;){if(1>=A){if(ie(),0===A&&0==e)return 0;if(0===A)break}if(C+=A,A=0,n=k+r,(0===C||C>=n)&&(A=C-n,C=n,se(!1),0===t.tt))return 0;if(C-k>=f-Ze&&(se(!1),0===t.tt))return 0}return se(4==e),0===t.tt?4==e?2:0:4==e?3:1})(i);break;case 1:R=(e=>{let n,r=0;for(;;){if(Ze>A){if(ie(),Ze>A&&0==e)return 0;if(0===A)break}if(3>A||(p=(p<f-Ze||2!=V&&(v=oe(r)),3>v)n=ee(0,255&u[C]),A--,C++;else if(n=ee(C-x,v-3),A-=v,v>P||3>A)C+=v,v=0,p=255&u[C],p=(p<{let n,r,s=0;for(;;){if(Ze>A){if(ie(),Ze>A&&0==e)return 0;if(0===A)break}if(3>A||(p=(p<_&&f-Ze>=(C-s&65535)&&(2!=V&&(v=oe(s)),5>=v&&(1==V||3==v&&C-x>4096)&&(v=2)),3>_||v>_)if(0!==z){if(n=ee(0,255&u[C-1]),n&&se(!1),C++,A--,0===t.tt)return 0}else z=1,C++,A--;else{r=C+A-3,n=ee(C-1-S,_-3),A-=_-1,_-=2;do{++C>r||(p=(p<1+H+10-F&&(X(2,3),Y(256,Le._e),$()),H=7;else if(re(0,0,!1),3==i)for(o=0;y>o;o++)d[o]=0;if(t.Te(),0===t.tt)return c=-1,0}}return 4!=i?0:1}}function tt(){const e=this;e.nt=0,e.rt=0,e.We=0,e.qe=0,e.tt=0,e.Ge=0}function nt(e){const t=new tt,n=(o=e&&e.chunkSize?e.chunkSize:65536)+5*(r.floor(o/16383)+1);var o;const c=new i(n);let f=e?e.level:-1;void 0===f&&(f=-1),t.He(f),t.$e=c,this.append=(e,r)=>{let o,f,a=0,l=0,u=0;const w=[];if(e.length){t.nt=0,t.et=e,t.We=e.length;do{if(t.rt=0,t.tt=n,o=t.Ye(0),0!=o)throw new s("deflating: "+t.Le);t.rt&&(t.rt==n?w.push(new i(c)):w.push(c.subarray(0,t.rt))),u+=t.rt,r&&t.nt>0&&t.nt!=a&&(r(t.nt),a=t.nt)}while(t.We>0||0===t.tt);return w.length>1?(f=new i(u),w.forEach((e=>{f.set(e,l),l+=e.length}))):f=w[0]?new i(w[0]):new i,f}},this.flush=()=>{let e,r,o=0,f=0;const a=[];do{if(t.rt=0,t.tt=n,e=t.Ye(4),1!=e&&0!=e)throw new s("deflating: "+t.Le);n-t.tt>0&&a.push(c.slice(0,t.rt)),f+=t.rt}while(t.We>0||0===t.tt);return t.Qe(),r=new i(f),a.forEach((e=>{r.set(e,o),o+=e.length})),r}}tt.prototype={He(e,t){const n=this;return n.Fe=new et,t||(t=15),n.Fe.He(n,e,t)},Ye(e){const t=this;return t.Fe?t.Fe.Ye(t,e):Oe},Qe(){const e=this;if(!e.Fe)return Oe;const t=e.Fe.Qe();return e.Fe=null,t},Xe(e,t){const n=this;return n.Fe?n.Fe.Xe(n,e,t):Oe},Ze(e,t){const n=this;return n.Fe?n.Fe.Ze(n,e,t):Oe},je(e,t,n){const r=this;let s=r.We;return s>n&&(s=n),0===s?0:(r.We-=s,e.set(r.et.subarray(r.nt,r.nt+s),t),r.nt+=s,r.qe+=s,s)},Te(){const e=this;let t=e.Fe.pending;t>e.tt&&(t=e.tt),0!==t&&(e.$e.set(e.Fe.Ke.subarray(e.Fe.Je,e.Fe.Je+t),e.rt),e.rt+=t,e.Fe.Je+=t,e.Ge+=t,e.tt-=t,e.Fe.pending-=t,0===e.Fe.pending&&(e.Fe.Je=0))}};const rt=-2,st=-3,it=-5,ot=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],ct=[96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,192,80,7,10,0,8,96,0,8,32,0,9,160,0,8,0,0,8,128,0,8,64,0,9,224,80,7,6,0,8,88,0,8,24,0,9,144,83,7,59,0,8,120,0,8,56,0,9,208,81,7,17,0,8,104,0,8,40,0,9,176,0,8,8,0,8,136,0,8,72,0,9,240,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,200,81,7,13,0,8,100,0,8,36,0,9,168,0,8,4,0,8,132,0,8,68,0,9,232,80,7,8,0,8,92,0,8,28,0,9,152,84,7,83,0,8,124,0,8,60,0,9,216,82,7,23,0,8,108,0,8,44,0,9,184,0,8,12,0,8,140,0,8,76,0,9,248,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,196,81,7,11,0,8,98,0,8,34,0,9,164,0,8,2,0,8,130,0,8,66,0,9,228,80,7,7,0,8,90,0,8,26,0,9,148,84,7,67,0,8,122,0,8,58,0,9,212,82,7,19,0,8,106,0,8,42,0,9,180,0,8,10,0,8,138,0,8,74,0,9,244,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,204,81,7,15,0,8,102,0,8,38,0,9,172,0,8,6,0,8,134,0,8,70,0,9,236,80,7,9,0,8,94,0,8,30,0,9,156,84,7,99,0,8,126,0,8,62,0,9,220,82,7,27,0,8,110,0,8,46,0,9,188,0,8,14,0,8,142,0,8,78,0,9,252,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,194,80,7,10,0,8,97,0,8,33,0,9,162,0,8,1,0,8,129,0,8,65,0,9,226,80,7,6,0,8,89,0,8,25,0,9,146,83,7,59,0,8,121,0,8,57,0,9,210,81,7,17,0,8,105,0,8,41,0,9,178,0,8,9,0,8,137,0,8,73,0,9,242,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,202,81,7,13,0,8,101,0,8,37,0,9,170,0,8,5,0,8,133,0,8,69,0,9,234,80,7,8,0,8,93,0,8,29,0,9,154,84,7,83,0,8,125,0,8,61,0,9,218,82,7,23,0,8,109,0,8,45,0,9,186,0,8,13,0,8,141,0,8,77,0,9,250,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,198,81,7,11,0,8,99,0,8,35,0,9,166,0,8,3,0,8,131,0,8,67,0,9,230,80,7,7,0,8,91,0,8,27,0,9,150,84,7,67,0,8,123,0,8,59,0,9,214,82,7,19,0,8,107,0,8,43,0,9,182,0,8,11,0,8,139,0,8,75,0,9,246,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,206,81,7,15,0,8,103,0,8,39,0,9,174,0,8,7,0,8,135,0,8,71,0,9,238,80,7,9,0,8,95,0,8,31,0,9,158,84,7,99,0,8,127,0,8,63,0,9,222,82,7,27,0,8,111,0,8,47,0,9,190,0,8,15,0,8,143,0,8,79,0,9,254,96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,193,80,7,10,0,8,96,0,8,32,0,9,161,0,8,0,0,8,128,0,8,64,0,9,225,80,7,6,0,8,88,0,8,24,0,9,145,83,7,59,0,8,120,0,8,56,0,9,209,81,7,17,0,8,104,0,8,40,0,9,177,0,8,8,0,8,136,0,8,72,0,9,241,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,201,81,7,13,0,8,100,0,8,36,0,9,169,0,8,4,0,8,132,0,8,68,0,9,233,80,7,8,0,8,92,0,8,28,0,9,153,84,7,83,0,8,124,0,8,60,0,9,217,82,7,23,0,8,108,0,8,44,0,9,185,0,8,12,0,8,140,0,8,76,0,9,249,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,197,81,7,11,0,8,98,0,8,34,0,9,165,0,8,2,0,8,130,0,8,66,0,9,229,80,7,7,0,8,90,0,8,26,0,9,149,84,7,67,0,8,122,0,8,58,0,9,213,82,7,19,0,8,106,0,8,42,0,9,181,0,8,10,0,8,138,0,8,74,0,9,245,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,205,81,7,15,0,8,102,0,8,38,0,9,173,0,8,6,0,8,134,0,8,70,0,9,237,80,7,9,0,8,94,0,8,30,0,9,157,84,7,99,0,8,126,0,8,62,0,9,221,82,7,27,0,8,110,0,8,46,0,9,189,0,8,14,0,8,142,0,8,78,0,9,253,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,195,80,7,10,0,8,97,0,8,33,0,9,163,0,8,1,0,8,129,0,8,65,0,9,227,80,7,6,0,8,89,0,8,25,0,9,147,83,7,59,0,8,121,0,8,57,0,9,211,81,7,17,0,8,105,0,8,41,0,9,179,0,8,9,0,8,137,0,8,73,0,9,243,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,203,81,7,13,0,8,101,0,8,37,0,9,171,0,8,5,0,8,133,0,8,69,0,9,235,80,7,8,0,8,93,0,8,29,0,9,155,84,7,83,0,8,125,0,8,61,0,9,219,82,7,23,0,8,109,0,8,45,0,9,187,0,8,13,0,8,141,0,8,77,0,9,251,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,199,81,7,11,0,8,99,0,8,35,0,9,167,0,8,3,0,8,131,0,8,67,0,9,231,80,7,7,0,8,91,0,8,27,0,9,151,84,7,67,0,8,123,0,8,59,0,9,215,82,7,19,0,8,107,0,8,43,0,9,183,0,8,11,0,8,139,0,8,75,0,9,247,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,207,81,7,15,0,8,103,0,8,39,0,9,175,0,8,7,0,8,135,0,8,71,0,9,239,80,7,9,0,8,95,0,8,31,0,9,159,84,7,99,0,8,127,0,8,63,0,9,223,82,7,27,0,8,111,0,8,47,0,9,191,0,8,15,0,8,143,0,8,79,0,9,255],ft=[80,5,1,87,5,257,83,5,17,91,5,4097,81,5,5,89,5,1025,85,5,65,93,5,16385,80,5,3,88,5,513,84,5,33,92,5,8193,82,5,9,90,5,2049,86,5,129,192,5,24577,80,5,2,87,5,385,83,5,25,91,5,6145,81,5,7,89,5,1537,85,5,97,93,5,24577,80,5,4,88,5,769,84,5,49,92,5,12289,82,5,13,90,5,3073,86,5,193,192,5,24577],at=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],lt=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,112,112],ut=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],wt=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];function ht(){let e,t,n,r,s,i;function o(e,t,o,c,f,a,l,u,w,h,d){let p,y,m,b,g,k,v,S,z,C,x,A,_,I,P;C=0,g=o;do{n[e[t+C]]++,C++,g--}while(0!==g);if(n[0]==o)return l[0]=-1,u[0]=0,0;for(S=u[0],k=1;15>=k&&0===n[k];k++);for(v=k,k>S&&(S=k),g=15;0!==g&&0===n[g];g--);for(m=g,S>g&&(S=g),u[0]=S,I=1<k;k++,I<<=1)if(0>(I-=n[k]))return st;if(0>(I-=n[g]))return st;for(n[g]+=I,i[1]=k=0,C=1,_=2;0!=--g;)i[_]=k+=n[C],_++,C++;g=0,C=0;do{0!==(k=e[t+C])&&(d[i[k]++]=g),C++}while(++g=v;v++)for(p=n[v];0!=p--;){for(;v>A+S;){if(b++,A+=S,P=m-A,P=P>S?S:P,(y=1<<(k=v-A))>p+1&&(y-=p+1,_=v,P>k))for(;++kn[++_];)y-=n[_];if(P=1<1440)return st;s[b]=x=h[0],h[0]+=P,0!==b?(i[b]=g,r[0]=k,r[1]=S,k=g>>>A-S,r[2]=x-s[b-1]-k,w.set(r,3*(s[b-1]+k))):l[0]=x}for(r[1]=v-A,o>C?d[C]d[C]?0:96,r[2]=d[C++]):(r[0]=a[d[C]-c]+16+64,r[2]=f[d[C++]-c]):r[0]=192,y=1<>>A;P>k;k+=y)w.set(r,3*(x+k));for(k=1<>>=1)g^=k;for(g^=k,z=(1<c;c++)t[c]=0;for(c=0;16>c;c++)n[c]=0;for(c=0;3>c;c++)r[c]=0;s.set(n.subarray(0,15),0),i.set(n.subarray(0,16),0)}this.st=(n,r,s,i,f)=>{let a;return c(19),e[0]=0,a=o(n,0,19,19,null,null,s,r,i,e,t),a==st?f.Le="oversubscribed dynamic bit lengths tree":a!=it&&0!==r[0]||(f.Le="incomplete dynamic bit lengths tree",a=st),a},this.it=(n,r,s,i,f,a,l,u,w)=>{let h;return c(288),e[0]=0,h=o(s,0,n,257,at,lt,a,i,u,e,t),0!=h||0===i[0]?(h==st?w.Le="oversubscribed literal/length tree":-4!=h&&(w.Le="incomplete literal/length tree",h=st),h):(c(288),h=o(s,n,r,0,ut,wt,l,f,u,e,t),0!=h||0===f[0]&&n>257?(h==st?w.Le="oversubscribed distance tree":h==it?(w.Le="incomplete distance tree",h=st):-4!=h&&(w.Le="empty distance tree with lengths",h=st),h):0)}}function dt(){const e=this;let t,n,r,s,i=0,o=0,c=0,f=0,a=0,l=0,u=0,w=0,h=0,d=0;function p(e,t,n,r,s,i,o,c){let f,a,l,u,w,h,d,p,y,m,b,g,k,v,S,z;d=c.nt,p=c.We,w=o.ot,h=o.ct,y=o.write,m=yh;)p--,w|=(255&c.ft(d++))<>=a[z+1],h-=a[z+1],16&u){for(u&=15,k=a[z+2]+(w&ot[u]),w>>=u,h-=u;15>h;)p--,w|=(255&c.ft(d++))<>=a[z+1],h-=a[z+1],16&u){for(u&=15;u>h;)p--,w|=(255&c.ft(d++))<>=u,h-=u,m-=k,v>y){S=y-v;do{S+=o.end}while(0>S);if(u=o.end-S,k>u){if(k-=u,y-S>0&&u>y-S)do{o.lt[y++]=o.lt[S++]}while(0!=--u);else o.lt.set(o.lt.subarray(S,S+u),y),y+=u,S+=u,u=0;S=0}}else S=y-v,y-S>0&&2>y-S?(o.lt[y++]=o.lt[S++],o.lt[y++]=o.lt[S++],k-=2):(o.lt.set(o.lt.subarray(S,S+2),y),y+=2,S+=2,k-=2);if(y-S>0&&k>y-S)do{o.lt[y++]=o.lt[S++]}while(0!=--k);else o.lt.set(o.lt.subarray(S,S+k),y),y+=k,S+=k,k=0;break}if(64&u)return c.Le="invalid distance code",k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,st;f+=a[z+2],f+=w&ot[u],z=3*(l+f),u=a[z]}break}if(64&u)return 32&u?(k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,1):(c.Le="invalid literal/length code",k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,st);if(f+=a[z+2],f+=w&ot[u],z=3*(l+f),0===(u=a[z])){w>>=a[z+1],h-=a[z+1],o.lt[y++]=a[z+2],m--;break}}else w>>=a[z+1],h-=a[z+1],o.lt[y++]=a[z+2],m--}while(m>=258&&p>=10);return k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,0}e.init=(e,i,o,c,f,a)=>{t=0,u=e,w=i,r=o,h=c,s=f,d=a,n=null},e.ut=(e,y,m)=>{let b,g,k,v,S,z,C,x=0,A=0,_=0;for(_=y.nt,v=y.We,x=e.ot,A=e.ct,S=e.write,z=S=258&&v>=10&&(e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,m=p(u,w,r,h,s,d,e,y),_=y.nt,v=y.We,x=e.ot,A=e.ct,S=e.write,z=SA;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<>>=n[g+1],A-=n[g+1],k=n[g],0===k){f=n[g+2],t=6;break}if(16&k){a=15&k,i=n[g+2],t=2;break}if(!(64&k)){c=k,o=g/3+n[g+2];break}if(32&k){t=7;break}return t=9,y.Le="invalid literal/length code",m=st,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);case 2:for(b=a;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<>=b,A-=b,c=w,n=s,o=d,t=3;case 3:for(b=c;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<>=n[g+1],A-=n[g+1],k=n[g],16&k){a=15&k,l=n[g+2],t=4;break}if(!(64&k)){c=k,o=g/3+n[g+2];break}return t=9,y.Le="invalid distance code",m=st,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);case 4:for(b=a;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<>=b,A-=b,t=5;case 5:for(C=S-l;0>C;)C+=e.end;for(;0!==i;){if(0===z&&(S==e.end&&0!==e.read&&(S=0,z=S7&&(A-=8,v++,_--),e.write=S,m=e.wt(y,m),S=e.write,z=S{}}ht.dt=(e,t,n,r)=>(e[0]=9,t[0]=5,n[0]=ct,r[0]=ft,0);const pt=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];function yt(e,t){const n=this;let r,s=0,o=0,c=0,a=0;const l=[0],u=[0],w=new dt;let h=0,d=new f(4320);const p=new ht;n.ct=0,n.ot=0,n.lt=new i(t),n.end=t,n.read=0,n.write=0,n.reset=(e,t)=>{t&&(t[0]=0),6==s&&w.ht(e),s=0,n.ct=0,n.ot=0,n.read=n.write=0},n.reset(e,null),n.wt=(e,t)=>{let r,s,i;return s=e.rt,i=n.read,r=(i>n.write?n.end:n.write)-i,r>e.tt&&(r=e.tt),0!==r&&t==it&&(t=0),e.tt-=r,e.Ge+=r,e.$e.set(n.lt.subarray(i,i+r),s),s+=r,i+=r,i==n.end&&(i=0,n.write==n.end&&(n.write=0),r=n.write-i,r>e.tt&&(r=e.tt),0!==r&&t==it&&(t=0),e.tt-=r,e.Ge+=r,e.$e.set(n.lt.subarray(i,i+r),s),s+=r,i+=r),e.rt=s,n.read=i,t},n.ut=(e,t)=>{let i,f,y,m,b,g,k,v;for(m=e.nt,b=e.We,f=n.ot,y=n.ct,g=n.write,k=gy;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<>>1){case 0:f>>>=3,y-=3,i=7&y,f>>>=i,y-=i,s=1;break;case 1:S=[],z=[],C=[[]],x=[[]],ht.dt(S,z,C,x),w.init(S[0],z[0],C[0],0,x[0],0),f>>>=3,y-=3,s=6;break;case 2:f>>>=3,y-=3,s=3;break;case 3:return f>>>=3,y-=3,s=9,e.Le="invalid block type",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t)}break;case 1:for(;32>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<>>16&65535)!=(65535&f))return s=9,e.Le="invalid stored block lengths",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);o=65535&f,f=y=0,s=0!==o?2:0!==h?7:0;break;case 2:if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);if(0===k&&(g==n.end&&0!==n.read&&(g=0,k=gb&&(i=b),i>k&&(i=k),n.lt.set(e.je(m,i),g),m+=i,b-=i,g+=i,k-=i,0!=(o-=i))break;s=0!==h?7:0;break;case 3:for(;14>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<29||(i>>5&31)>29)return s=9,e.Le="too many length or distance symbols",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);if(i=258+(31&i)+(i>>5&31),!r||r.lengthv;v++)r[v]=0;f>>>=14,y-=14,a=0,s=4;case 4:for(;4+(c>>>10)>a;){for(;3>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<>>=3,y-=3}for(;19>a;)r[pt[a++]]=0;if(l[0]=7,i=p.st(r,l,u,d,e),0!=i)return(t=i)==st&&(r=null,s=9),n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);a=0,s=5;case 5:for(;i=c,258+(31&i)+(i>>5&31)>a;){let o,w;for(i=l[0];i>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<w)f>>>=i,y-=i,r[a++]=w;else{for(v=18==w?7:w-14,o=18==w?11:3;i+v>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<>>=i,y-=i,o+=f&ot[v],f>>>=v,y-=v,v=a,i=c,v+o>258+(31&i)+(i>>5&31)||16==w&&1>v)return r=null,s=9,e.Le="invalid bit length repeat",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);w=16==w?r[v-1]:0;do{r[v++]=w}while(0!=--o);a=v}}if(u[0]=-1,A=[],_=[],I=[],P=[],A[0]=9,_[0]=6,i=c,i=p.it(257+(31&i),1+(i>>5&31),r,A,_,I,P,d,e),0!=i)return i==st&&(r=null,s=9),t=i,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);w.init(A[0],_[0],d,I[0],d,P[0]),s=6;case 6:if(n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,1!=(t=w.ut(n,e,t)))return n.wt(e,t);if(t=0,w.ht(e),m=e.nt,b=e.We,f=n.ot,y=n.ct,g=n.write,k=g{n.reset(e,null),n.lt=null,d=null},n.yt=(e,t,r)=>{n.lt.set(e.subarray(t,t+r),0),n.read=n.write=r},n.bt=()=>1==s?1:0}const mt=13,bt=[0,0,255,255];function gt(){const e=this;function t(e){return e&&e.gt?(e.qe=e.Ge=0,e.Le=null,e.gt.mode=7,e.gt.kt.reset(e,null),0):rt}e.mode=0,e.method=0,e.vt=[0],e.St=0,e.marker=0,e.zt=0,e.Ct=t=>(e.kt&&e.kt.ht(t),e.kt=null,0),e.xt=(n,r)=>(n.Le=null,e.kt=null,8>r||r>15?(e.Ct(n),rt):(e.zt=r,n.gt.kt=new yt(n,1<{let n,r;if(!e||!e.gt||!e.et)return rt;const s=e.gt;for(t=4==t?it:0,n=it;;)switch(s.mode){case 0:if(0===e.We)return n;if(n=t,e.We--,e.qe++,8!=(15&(s.method=e.ft(e.nt++)))){s.mode=mt,e.Le="unknown compression method",s.marker=5;break}if(8+(s.method>>4)>s.zt){s.mode=mt,e.Le="invalid win size",s.marker=5;break}s.mode=1;case 1:if(0===e.We)return n;if(n=t,e.We--,e.qe++,r=255&e.ft(e.nt++),((s.method<<8)+r)%31!=0){s.mode=mt,e.Le="incorrect header check",s.marker=5;break}if(!(32&r)){s.mode=7;break}s.mode=2;case 2:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St=(255&e.ft(e.nt++))<<24&4278190080,s.mode=3;case 3:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St+=(255&e.ft(e.nt++))<<16&16711680,s.mode=4;case 4:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St+=(255&e.ft(e.nt++))<<8&65280,s.mode=5;case 5:return 0===e.We?n:(n=t,e.We--,e.qe++,s.St+=255&e.ft(e.nt++),s.mode=6,2);case 6:return s.mode=mt,e.Le="need dictionary",s.marker=0,rt;case 7:if(n=s.kt.ut(e,n),n==st){s.mode=mt,s.marker=0;break}if(0==n&&(n=t),1!=n)return n;n=t,s.kt.reset(e,s.vt),s.mode=12;case 12:return e.We=0,1;case mt:return st;default:return rt}},e._t=(e,t,n)=>{let r=0,s=n;if(!e||!e.gt||6!=e.gt.mode)return rt;const i=e.gt;return s<1<{let n,r,s,i,o;if(!e||!e.gt)return rt;const c=e.gt;if(c.mode!=mt&&(c.mode=mt,c.marker=0),0===(n=e.We))return it;for(r=e.nt,s=c.marker;0!==n&&4>s;)e.ft(r)==bt[s]?s++:s=0!==e.ft(r)?0:4-s,r++,n--;return e.qe+=r-e.nt,e.nt=r,e.We=n,c.marker=s,4!=s?st:(i=e.qe,o=e.Ge,t(e),e.qe=i,e.Ge=o,c.mode=7,0)},e.Pt=e=>e&&e.gt&&e.gt.kt?e.gt.kt.bt():rt}function kt(){}function vt(e){const t=new kt,n=e&&e.chunkSize?r.floor(2*e.chunkSize):131072,o=new i(n);let c=!1;t.xt(),t.$e=o,this.append=(e,r)=>{const f=[];let a,l,u=0,w=0,h=0;if(0!==e.length){t.nt=0,t.et=e,t.We=e.length;do{if(t.rt=0,t.tt=n,0!==t.We||c||(t.nt=0,c=!0),a=t.At(0),c&&a===it){if(0!==t.We)throw new s("inflating: bad input")}else if(0!==a&&1!==a)throw new s("inflating: "+t.Le);if((c||1===a)&&t.We===e.length)throw new s("inflating: bad input");t.rt&&(t.rt===n?f.push(new i(o)):f.push(o.subarray(0,t.rt))),h+=t.rt,r&&t.nt>0&&t.nt!=u&&(r(t.nt),u=t.nt)}while(t.We>0||0===t.tt);return f.length>1?(l=new i(h),f.forEach((e=>{l.set(e,w),w+=e.length}))):l=f[0]?new i(f[0]):new i,l}},this.flush=()=>{t.Ct()}}kt.prototype={xt(e){const t=this;return t.gt=new gt,e||(e=15),t.gt.xt(t,e)},At(e){const t=this;return t.gt?t.gt.At(t,e):rt},Ct(){const e=this;if(!e.gt)return rt;const t=e.gt.Ct(e);return e.gt=null,t},It(){const e=this;return e.gt?e.gt.It(e):rt},_t(e,t){const n=this;return n.gt?n.gt._t(n,e,t):rt},ft(e){return this.et[e]},je(e,t){return this.et.subarray(e,e+t)}},self.initCodec=()=>{self.Deflate=nt,self.Inflate=vt};\n',r=()=>t.useDataURI?"data:text/javascript,"+encodeURIComponent(n):f.createObjectURL(new m([n],{type:"text/javascript"}));e({workerScripts:{inflate:[r],deflate:[r]}})})(ne),e.BlobReader=Ot,e.BlobWriter=Pt,e.Data64URIReader=class extends Nt{constructor(e){super();let t=e.length;for(;"="==e.charAt(t-1);)t--;const r=e.indexOf(",")+1;n.assign(this,{dataURI:e,dataStart:r,size:a.floor(.75*(t-r))})}readUint8Array(e,t){const{dataStart:n,dataURI:r}=this,s=new w(t),i=4*a.floor(e/3),o=atob(r.substring(i+n,4*a.ceil((e+t)/3)+n)),c=e-3*a.floor(i/4);for(let e=c;c+t>e;e++)s[e-c]=o.charCodeAt(e);return s}},e.Data64URIWriter=class extends qt{constructor(e){super(),n.assign(this,{data:"data:"+(e||"")+";base64,",pending:[]})}writeUint8Array(e){const t=this;let n=0,s=t.pending;const i=t.pending.length;for(t.pending="",n=0;n<3*a.floor((i+e.length)/3)-i;n++)s+=r.fromCharCode(e[n]);for(;n2?t.data+=v(s):t.pending=s}getData(){return this.data+v(this.pending)}},e.ERR_BAD_FORMAT=Ln,e.ERR_CENTRAL_DIRECTORY_NOT_FOUND=Nn,e.ERR_DUPLICATED_NAME=or,e.ERR_ENCRYPTED=Pn,e.ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND=In,e.ERR_EOCDR_NOT_FOUND=Un,e.ERR_EXTRAFIELD_ZIP64_NOT_FOUND=On,e.ERR_HTTP_RANGE=Wt,e.ERR_INVALID_COMMENT=cr,e.ERR_INVALID_ENCRYPTION_STRENGTH=dr,e.ERR_INVALID_ENTRY_COMMENT=lr,e.ERR_INVALID_ENTRY_NAME=ur,e.ERR_INVALID_EXTRAFIELD_DATA=pr,e.ERR_INVALID_EXTRAFIELD_TYPE=wr,e.ERR_INVALID_PASSWORD=he,e.ERR_INVALID_SIGNATURE=ge,e.ERR_INVALID_VERSION=fr,e.ERR_ITERATOR_COMPLETED_TOO_SOON=Rt,e.ERR_LOCAL_FILE_HEADER_NOT_FOUND=qn,e.ERR_SPLIT_ZIP_FILE=Bn,e.ERR_UNDEFINED_UNCOMPRESSED_SIZE=gr,e.ERR_UNSUPPORTED_COMPRESSION=Mn,e.ERR_UNSUPPORTED_ENCRYPTION=Hn,e.ERR_UNSUPPORTED_FORMAT=hr,e.HttpRangeReader=class extends en{constructor(e,t={}){t.useRangeHeader=!0,super(e,t)}},e.HttpReader=en,e.Reader=Nt,e.SplitDataReader=tn,e.SplitDataWriter=nn,e.SplitZipReader=cn,e.SplitZipWriter=ln,e.TextReader=class extends Ot{constructor(e){super(new m([e],{type:"text/plain"}))}},e.TextWriter=class extends Pt{constructor(e){super(e),n.assign(this,{encoding:e,utf8:!e||"utf-8"==e.toLowerCase()})}async getData(){const{encoding:e,utf8:t}=this,r=await super.getData();if(r.text&&t)return r.text();{const t=new FileReader;return new y(((s,i)=>{n.assign(t,{onload:({target:e})=>s(e.result),onerror:()=>i(t.error)}),t.readAsText(r,e)}))}}},e.Uint8ArrayReader=class extends Nt{constructor(e){super(),n.assign(this,{array:e,size:e.length})}readUint8Array(e,t){return this.array.slice(e,e+t)}},e.Uint8ArrayWriter=class extends qt{init(e=0){n.assign(this,{offset:0,array:new w(e)}),super.init()}writeUint8Array(e){const t=this;if(t.offset+e.length>t.array.length){const n=t.array;t.array=new w(n.length+e.length),t.array.set(n)}t.array.set(e,t.offset),t.offset+=e.length}getData(){return this.array}},e.Writer=qt,e.ZipReader=Xn,e.ZipReaderStream=class{constructor(e={}){const{readable:t,writable:n}=new x,r=new Xn(t,e).getEntriesGenerator();this.readable=new A({async pull(e){const{done:t,value:n}=await r.next();if(t)return e.close();const s={...n,readable:(()=>{const{readable:e,writable:t}=new x;if(n.getData)return n.getData(t),e})()};delete s.getData,e.enqueue(s)}}),this.writable=n}},e.ZipWriter=Sr,e.ZipWriterStream=class{constructor(e={}){const{readable:t,writable:n}=new x;this.readable=t,this.zipWriter=new Sr(n,e)}transform(e){const{readable:t,writable:n}=new x({flush:()=>{this.zipWriter.close()}});return this.zipWriter.add(e,t),{readable:this.readable,writable:n}}writable(e){const{readable:t,writable:n}=new x;return this.zipWriter.add(e,t),n}close(e,t={}){return this.zipWriter.close(e,t)}},e.configure=ne,e.getMimeType=()=>"application/octet-stream",e.initReader=sn,e.initShimAsyncCodec=(e,t={},n)=>({Deflate:se(e.Deflate,t.deflate,n),Inflate:se(e.Inflate,t.inflate,n)}),e.initStream=rn,e.initWriter=an,e.readUint8Array=on,e.terminateWorkers=async()=>{await y.allSettled(vt.map((e=>(_t(e),e.terminate()))))}})); From 2870a0a8ad91b3d57cfe7549b6e7c0d309fb953a Mon Sep 17 00:00:00 2001 From: LibretroAdmin <105389611+LibretroAdmin@users.noreply.github.com> Date: Thu, 30 Jan 2025 21:35:58 +0100 Subject: [PATCH 172/574] Revert "Workerized emscripten retroarch (WIP) (#17484)" (#17492) This reverts commit cacd5a9a234f3c9abc8d352f6fea19117e2e1a00. --- Makefile.common | 5 +- Makefile.emscripten | 89 ++-- frontend/drivers/platform_emscripten.c | 7 +- gfx/drivers_context/emscriptenegl_ctx.c | 3 + gfx/drivers_context/emscriptenwebgl_ctx.c | 279 ------------- gfx/video_driver.c | 5 +- gfx/video_driver.h | 1 - input/drivers/rwebinput_input.c | 16 +- libretro-common/include/retro_timers.h | 4 +- pkg/emscripten/libretro-classic/index.html | 204 --------- pkg/emscripten/libretro-classic/indexer | 34 -- pkg/emscripten/libretro-classic/libretro.css | 120 ------ pkg/emscripten/libretro-classic/libretro.js | 389 ------------------ .../browserfs.min.js | 0 pkg/emscripten/libretro/index.html | 10 +- pkg/emscripten/libretro/libretro.js | 216 ++++++---- pkg/emscripten/libretro/zip.min.js | 1 - 17 files changed, 182 insertions(+), 1201 deletions(-) delete mode 100644 gfx/drivers_context/emscriptenwebgl_ctx.c delete mode 100644 pkg/emscripten/libretro-classic/index.html delete mode 100755 pkg/emscripten/libretro-classic/indexer delete mode 100644 pkg/emscripten/libretro-classic/libretro.css delete mode 100644 pkg/emscripten/libretro-classic/libretro.js rename pkg/emscripten/{libretro-classic => libretro}/browserfs.min.js (100%) delete mode 100644 pkg/emscripten/libretro/zip.min.js diff --git a/Makefile.common b/Makefile.common index ef2c79c445..2dcb7e08b4 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1526,10 +1526,7 @@ ifeq ($(HAVE_GL_CONTEXT), 1) endif ifeq ($(HAVE_EMSCRIPTEN), 1) - ifeq ($(HAVE_EGL), 1) - OBJ += gfx/drivers_context/emscriptenegl_ctx.o - endif - OBJ += gfx/drivers_context/emscriptenwebgl_ctx.o + OBJ += gfx/drivers_context/emscriptenegl_ctx.o endif ifeq ($(HAVE_MALI_FBDEV), 1) diff --git a/Makefile.emscripten b/Makefile.emscripten index 414d63b748..164db24cf3 100644 --- a/Makefile.emscripten +++ b/Makefile.emscripten @@ -24,8 +24,7 @@ HAVE_SCREENSHOTS = 1 HAVE_REWIND = 1 HAVE_AUDIOMIXER = 1 HAVE_CC_RESAMPLER = 1 -HAVE_EGL ?= 0 -HAVE_OPENGLES = 1 +HAVE_EGL = 1 HAVE_RJPEG = 0 HAVE_RPNG = 1 HAVE_EMSCRIPTEN = 1 @@ -49,8 +48,6 @@ HAVE_7ZIP = 1 HAVE_BSV_MOVIE = 1 HAVE_AL = 1 HAVE_CHD ?= 0 -HAVE_WASMFS ?= 1 -HAVE_WORKER ?= 1 # WARNING -- READ BEFORE ENABLING # The rwebaudio driver is known to have several audio bugs, such as @@ -71,7 +68,7 @@ HAVE_OPENGLES3 ?= 0 ASYNC ?= 0 LTO ?= 0 -PTHREAD ?= 4 +PTHREAD ?= 0 STACK_SIZE ?= 4194304 INITIAL_HEAP ?= 134217728 @@ -95,20 +92,37 @@ _cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focu _cmd_set_volume,_cmd_set_shader,_cmd_cheat_set_code,_cmd_cheat_get_code,_cmd_cheat_toggle_index,_cmd_cheat_get_code_state,_cmd_cheat_realloc,\ _cmd_cheat_get_size,_cmd_cheat_apply_cheats -EXPORTS := callMain,FS,PATH,ERRNO_CODES,stringToNewUTF8,UTF8ToString - LIBS := -s USE_ZLIB=1 +LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s STACK_SIZE=$(STACK_SIZE) -s INITIAL_MEMORY=$(INITIAL_HEAP) \ + -s EXPORTED_RUNTIME_METHODS=callMain,FS,PATH,ERRNO_CODES,stringToNewUTF8,UTF8ToString \ + -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="$(EXPORTED_FUNCTIONS)" \ + -s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \ + --extern-pre-js emscripten/pre.js \ + --js-library emscripten/library_rwebcam.js \ + --js-library emscripten/library_platform_emscripten.js -ifeq ($(HAVE_WASMFS), 1) - LIBS += -s WASMFS -s FORCE_FILESYSTEM=1 -lfetchfs.js -lopfs.js - EXPORTS := $(EXPORTS),FETCHFS,OPFS +ifeq ($(HAVE_RWEBAUDIO), 1) + LDFLAGS += --js-library emscripten/library_rwebaudio.js + DEFINES += -DHAVE_RWEBAUDIO +endif +ifeq ($(HAVE_AL), 1) + LDFLAGS += -lopenal + DEFINES += -DHAVE_AL + override ASYNC = 1 endif -ifeq ($(HAVE_WORKER), 1) - LIBS += -s PROXY_TO_PTHREAD -s USE_ES6_IMPORT_META=0 -sENVIRONMENT=worker,web -else - ifeq ($(HAVE_AL), 1) - override ASYNC = 1 +ifneq ($(PTHREAD), 0) + LDFLAGS += -s MAXIMUM_MEMORY=1073741824 -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD) + CFLAGS += -pthread + HAVE_THREADS=1 +else + HAVE_THREADS=0 +endif + +ifeq ($(ASYNC), 1) + LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192 + ifeq ($(DEBUG), 1) + LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE endif endif @@ -133,45 +147,6 @@ ifeq ($(HAVE_SDL2), 1) DEFINES += -DHAVE_SDL2 endif - -LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s STACK_SIZE=$(STACK_SIZE) -s INITIAL_MEMORY=$(INITIAL_HEAP) \ - -s EXPORTED_RUNTIME_METHODS=$(EXPORTS) \ - -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="$(EXPORTED_FUNCTIONS)" \ - -s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \ - -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 \ - -s OFFSCREENCANVAS_SUPPORT \ - -s OFFSCREEN_FRAMEBUFFER \ - --extern-pre-js emscripten/pre.js \ - --js-library emscripten/library_rwebcam.js \ - --js-library emscripten/library_platform_emscripten.js - -ifeq ($(HAVE_RWEBAUDIO), 1) - LDFLAGS += --js-library emscripten/library_rwebaudio.js - DEFINES += -DHAVE_RWEBAUDIO -endif - -ifeq ($(HAVE_AL), 1) - LDFLAGS += -lopenal - DEFINES += -DHAVE_AL -endif - -ifneq ($(PTHREAD), 0) - LDFLAGS += -s WASM_MEM_MAX=1073741824 -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD) - CFLAGS += -pthread -s SHARED_MEMORY - HAVE_THREADS=1 -else - HAVE_THREADS=0 -endif - - -ifeq ($(ASYNC), 1) - DEFINES += -DEMSCRIPTEN_ASYNCIFY - LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192 - ifeq ($(DEBUG), 1) - LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE - endif -endif - include Makefile.common CFLAGS += $(DEF_FLAGS) -Ideps -Ideps/stb @@ -208,10 +183,8 @@ RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) all: $(TARGET) -$(libretro_new) : $(libretro) - mv -f $(libretro) $(libretro_new) - -$(TARGET): $(RARCH_OBJ) $(libretro_new) +$(TARGET): $(RARCH_OBJ) $(libretro) + @$(if $(libretro), mv -f $(libretro) $(libretro_new),) @$(if $(Q), $(shell echo echo "LD $@ \ $(libretro_new) $(LIBS) $(LDFLAGS)"),) $(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS) diff --git a/frontend/drivers/platform_emscripten.c b/frontend/drivers/platform_emscripten.c index d4aac7183b..0657d139ec 100644 --- a/frontend/drivers/platform_emscripten.c +++ b/frontend/drivers/platform_emscripten.c @@ -235,8 +235,8 @@ static void frontend_emscripten_get_env(int *argc, char *argv[], "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT], user_path, "content", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT])); - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], base_path, - "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], user_path, + "content/downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], user_path, "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], @@ -308,10 +308,7 @@ int main(int argc, char *argv[]) specialHTMLTargets["!canvas"] = Module.canvas; }); - emscripten_set_canvas_element_size("!canvas", 800, 600); - emscripten_set_element_css_size("!canvas", 800.0, 600.0); emscripten_set_main_loop(emscripten_mainloop, 0, 0); - emscripten_set_main_loop_timing(EM_TIMING_RAF, 1); rarch_main(argc, argv, NULL); return 0; diff --git a/gfx/drivers_context/emscriptenegl_ctx.c b/gfx/drivers_context/emscriptenegl_ctx.c index bef3727f05..797999227c 100644 --- a/gfx/drivers_context/emscriptenegl_ctx.c +++ b/gfx/drivers_context/emscriptenegl_ctx.c @@ -124,9 +124,11 @@ static void gfx_ctx_emscripten_destroy(void *data) if (!emscripten) return; + #ifdef HAVE_EGL egl_destroy(&emscripten->egl); #endif + free(data); } @@ -189,6 +191,7 @@ static void *gfx_ctx_emscripten_init(void *video_driver) #endif return emscripten; + error: gfx_ctx_emscripten_destroy(video_driver); return NULL; diff --git a/gfx/drivers_context/emscriptenwebgl_ctx.c b/gfx/drivers_context/emscriptenwebgl_ctx.c deleted file mode 100644 index dec9fc7329..0000000000 --- a/gfx/drivers_context/emscriptenwebgl_ctx.c +++ /dev/null @@ -1,279 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * Copyright (C) 2012-2015 - Michael Lelli - * - * 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 - -#ifdef HAVE_CONFIG_H -#include "../../config.h" -#endif - -#include "../../retroarch.h" -#include "../../verbosity.h" - -typedef struct -{ - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; - unsigned fb_width; - unsigned fb_height; -} emscripten_ctx_data_t; - -static void gfx_ctx_emscripten_webgl_swap_interval(void *data, int interval) -{ - if (interval == 0) - emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0); - else - emscripten_set_main_loop_timing(EM_TIMING_RAF, interval); -} - -static void gfx_ctx_emscripten_webgl_get_canvas_size(int *width, int *height) -{ - EmscriptenFullscreenChangeEvent fullscreen_status; - bool is_fullscreen = false; - EMSCRIPTEN_RESULT r = emscripten_get_fullscreen_status(&fullscreen_status); - - if (r == EMSCRIPTEN_RESULT_SUCCESS) - { - if (fullscreen_status.isFullscreen) - { - is_fullscreen = true; - *width = fullscreen_status.screenWidth; - *height = fullscreen_status.screenHeight; - } - } - if (!is_fullscreen) - { - double w, h; - r = emscripten_get_element_css_size("#canvas", &w, &h); - *width = (int)w; - *height = (int)h; - - if (r != EMSCRIPTEN_RESULT_SUCCESS) - { - *width = 800; - *height = 600; - RARCH_ERR("[EMSCRIPTEN/WebGL]: Could not get screen dimensions: %d\n",r); - } - } -} - -static void gfx_ctx_emscripten_webgl_check_window(void *data, bool *quit, - bool *resize, unsigned *width, unsigned *height) -{ - int input_width=0; - int input_height=0; - emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; - - *resize = false; - gfx_ctx_emscripten_webgl_get_canvas_size(&input_width, &input_height); - *width = (unsigned)input_width; - *height = (unsigned)input_height; - if(*width != emscripten->fb_width || *height != emscripten->fb_height) { - *resize = true; - } - emscripten->fb_width = (unsigned)*width; - emscripten->fb_height = (unsigned)*height; - *quit = false; -} - -static void gfx_ctx_emscripten_webgl_swap_buffers(void *data) -{ - emscripten_webgl_commit_frame(); -} - -static void gfx_ctx_emscripten_webgl_get_video_size(void *data, - unsigned *width, unsigned *height) -{ - emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; - int s_width, s_height; - if (!emscripten) - return; - gfx_ctx_emscripten_webgl_get_canvas_size(&s_width, &s_height); - *width = (unsigned)s_width; - *height = (unsigned)s_height; -} - -static void gfx_ctx_emscripten_webgl_destroy(void *data) -{ - emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; - - if (!emscripten) - return; - - emscripten_webgl_destroy_context(emscripten->ctx); - - free(data); -} - -static void *gfx_ctx_emscripten_webgl_init(void *video_driver) -{ - int width, height; - emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*) - calloc(1, sizeof(*emscripten)); - - EmscriptenWebGLContextAttributes attrs={0}; - emscripten_webgl_init_context_attributes(&attrs); - attrs.alpha = false; - attrs.depth = true; - attrs.stencil = true; - attrs.antialias = false; - attrs.powerPreference = EM_WEBGL_POWER_PREFERENCE_HIGH_PERFORMANCE; - attrs.majorVersion = 2; - attrs.minorVersion = 2; - attrs.enableExtensionsByDefault = true; - attrs.explicitSwapControl = true; - attrs.renderViaOffscreenBackBuffer = true; - attrs.proxyContextToMainThread = EMSCRIPTEN_WEBGL_CONTEXT_PROXY_DISALLOW; - - if (!emscripten) - return NULL; - - emscripten->ctx = emscripten_webgl_create_context("#canvas", &attrs); - if(!emscripten->ctx) { - RARCH_LOG("[EMSCRIPTEN/WEBGL]: Failed to initialize webgl\n"); - goto error; - } - emscripten_webgl_get_drawing_buffer_size(emscripten->ctx, &width, &height); - emscripten_webgl_make_context_current(emscripten->ctx); - emscripten->fb_width = (unsigned)width; - emscripten->fb_height = (unsigned)height; - RARCH_LOG("[EMSCRIPTEN/WEBGL]: Dimensions: %ux%u\n", emscripten->fb_width, emscripten->fb_height); - - return emscripten; - -error: - gfx_ctx_emscripten_webgl_destroy(video_driver); - return NULL; -} - -static bool gfx_ctx_emscripten_webgl_set_video_mode(void *data, - unsigned width, unsigned height, - bool fullscreen) -{ - emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; - EMSCRIPTEN_RESULT r; - if(!emscripten || !emscripten->ctx) return false; - - if (width != 0 && height != 0) { - RARCH_LOG("[EMSCRIPTEN/WebGL]: set canvas size to %d, %d\n", width, height); - r = emscripten_set_canvas_element_size("#canvas", - (int)width, (int)height); - - if (r != EMSCRIPTEN_RESULT_SUCCESS) { - RARCH_ERR("[EMSCRIPTEN/WebGL]: error resizing canvas: %d\n", r); - return false; - } - } - emscripten->fb_width = width; - emscripten->fb_height = height; - - return true; -} - -bool gfx_ctx_emscripten_webgl_set_resize(void *data, unsigned width, unsigned height) { - emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; - EMSCRIPTEN_RESULT r; - if(!emscripten || !emscripten->ctx) return false; - RARCH_LOG("[EMSCRIPTEN/WebGL]: set canvas size to %d, %d\n", width, height); - r = emscripten_set_canvas_element_size("#canvas", - (int)width, (int)height); - if (r != EMSCRIPTEN_RESULT_SUCCESS) { - RARCH_ERR("[EMSCRIPTEN/WebGL]: error resizing canvas: %d\n", r); - return false; - } - return true; -} - -static enum gfx_ctx_api gfx_ctx_emscripten_webgl_get_api(void *data) { return GFX_CTX_OPENGL_ES_API; } - -static bool gfx_ctx_emscripten_webgl_bind_api(void *data, - enum gfx_ctx_api api, unsigned major, unsigned minor) -{ - return true; -} - -static void gfx_ctx_emscripten_webgl_input_driver(void *data, - const char *name, - input_driver_t **input, void **input_data) -{ - void *rwebinput = input_driver_init_wrap(&input_rwebinput, name); - *input = rwebinput ? &input_rwebinput : NULL; - *input_data = rwebinput; -} - -static bool gfx_ctx_emscripten_webgl_has_focus(void *data) { - emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; - return emscripten && emscripten->ctx; -} - -static bool gfx_ctx_emscripten_webgl_suppress_screensaver(void *data, bool enable) { return false; } - -static float gfx_ctx_emscripten_webgl_translate_aspect(void *data, - unsigned width, unsigned height) { return (float)width / height; } - -static void gfx_ctx_emscripten_webgl_bind_hw_render(void *data, bool enable) -{ - emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data; - emscripten_webgl_make_context_current(emscripten->ctx); -} - -static uint32_t gfx_ctx_emscripten_webgl_get_flags(void *data) -{ - uint32_t flags = 0; - BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_GLSL); - return flags; -} - -static void gfx_ctx_emscripten_webgl_set_flags(void *data, uint32_t flags) { } - -const gfx_ctx_driver_t gfx_ctx_emscripten_webgl = { - gfx_ctx_emscripten_webgl_init, - gfx_ctx_emscripten_webgl_destroy, - gfx_ctx_emscripten_webgl_get_api, - gfx_ctx_emscripten_webgl_bind_api, - gfx_ctx_emscripten_webgl_swap_interval, - gfx_ctx_emscripten_webgl_set_video_mode, - gfx_ctx_emscripten_webgl_get_video_size, - NULL, /* get_refresh_rate */ - NULL, /* get_video_output_size */ - NULL, /* get_video_output_prev */ - NULL, /* get_video_output_next */ - NULL, /* get_metrics */ - gfx_ctx_emscripten_webgl_translate_aspect, - NULL, /* update_title */ - gfx_ctx_emscripten_webgl_check_window, - gfx_ctx_emscripten_webgl_set_resize, /* set_resize */ - gfx_ctx_emscripten_webgl_has_focus, - gfx_ctx_emscripten_webgl_suppress_screensaver, - false, - gfx_ctx_emscripten_webgl_swap_buffers, - gfx_ctx_emscripten_webgl_input_driver, - NULL, - NULL, - NULL, - NULL, - "webgl_emscripten", - gfx_ctx_emscripten_webgl_get_flags, - gfx_ctx_emscripten_webgl_set_flags, - gfx_ctx_emscripten_webgl_bind_hw_render, - NULL, - NULL -}; diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 00701c43b3..fde66068d4 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -162,11 +162,8 @@ static const gfx_ctx_driver_t *gfx_ctx_gl_drivers[] = { #ifdef HAVE_OSMESA &gfx_ctx_osmesa, #endif -#if (defined(EMSCRIPTEN) && defined(HAVE_EGL)) - &gfx_ctx_emscripten, -#endif #ifdef EMSCRIPTEN - &gfx_ctx_emscripten_webgl, + &gfx_ctx_emscripten, #endif &gfx_ctx_null, NULL diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 7c02cd3366..7dfc555d5e 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -1384,7 +1384,6 @@ extern const gfx_ctx_driver_t gfx_ctx_cgl; extern const gfx_ctx_driver_t gfx_ctx_cocoagl; extern const gfx_ctx_driver_t gfx_ctx_cocoavk; extern const gfx_ctx_driver_t gfx_ctx_emscripten; -extern const gfx_ctx_driver_t gfx_ctx_emscripten_webgl; extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; extern const gfx_ctx_driver_t gfx_ctx_khr_display; extern const gfx_ctx_driver_t gfx_ctx_gdi; diff --git a/input/drivers/rwebinput_input.c b/input/drivers/rwebinput_input.c index 9ade8ecc37..67823f16e2 100644 --- a/input/drivers/rwebinput_input.c +++ b/input/drivers/rwebinput_input.c @@ -417,7 +417,7 @@ static void *rwebinput_input_init(const char *joypad_driver) rwebinput_generate_lut(); r = emscripten_set_keydown_callback( - "#canvas", rwebinput, false, + "!canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -426,7 +426,7 @@ static void *rwebinput_input_init(const char *joypad_driver) } r = emscripten_set_keyup_callback( - "#canvas", rwebinput, false, + "!canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -435,7 +435,7 @@ static void *rwebinput_input_init(const char *joypad_driver) } r = emscripten_set_keypress_callback( - "#canvas", rwebinput, false, + "!canvas", rwebinput, false, rwebinput_keyboard_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -443,7 +443,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create keypress callback: %d\n", r); } - r = emscripten_set_mousedown_callback("#canvas", rwebinput, false, + r = emscripten_set_mousedown_callback("!canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -451,7 +451,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create mousedown callback: %d\n", r); } - r = emscripten_set_mouseup_callback("#canvas", rwebinput, false, + r = emscripten_set_mouseup_callback("!canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -459,7 +459,7 @@ static void *rwebinput_input_init(const char *joypad_driver) "[EMSCRIPTEN/INPUT] failed to create mouseup callback: %d\n", r); } - r = emscripten_set_mousemove_callback("#canvas", rwebinput, false, + r = emscripten_set_mousemove_callback("!canvas", rwebinput, false, rwebinput_mouse_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -468,7 +468,7 @@ static void *rwebinput_input_init(const char *joypad_driver) } r = emscripten_set_wheel_callback( - "#canvas", rwebinput, false, + "!canvas", rwebinput, false, rwebinput_wheel_cb); if (r != EMSCRIPTEN_RESULT_SUCCESS) { @@ -819,7 +819,7 @@ static void rwebinput_input_poll(void *data) static void rwebinput_grab_mouse(void *data, bool state) { if (state) - emscripten_request_pointerlock("#canvas", EM_TRUE); + emscripten_request_pointerlock("!canvas", EM_TRUE); else emscripten_exit_pointerlock(); } diff --git a/libretro-common/include/retro_timers.h b/libretro-common/include/retro_timers.h index e519ad617f..96041255a3 100644 --- a/libretro-common/include/retro_timers.h +++ b/libretro-common/include/retro_timers.h @@ -39,7 +39,7 @@ #include #elif defined(_3DS) #include <3ds.h> -#elif (defined(EMSCRIPTEN) && defined(EMSCRIPTEN_ASYNCIFY)) +#elif defined(EMSCRIPTEN) #include #else #include @@ -100,7 +100,7 @@ static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp) #define retro_sleep(msec) (usleep(1000 * (msec))) #elif defined(WIIU) #define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec)))) -#elif defined(EMSCRIPTEN) && defined(EMSCRIPTEN_ASYNCIFY) +#elif defined(EMSCRIPTEN) #define retro_sleep(msec) (emscripten_sleep(msec)) #else static INLINE void retro_sleep(unsigned msec) diff --git a/pkg/emscripten/libretro-classic/index.html b/pkg/emscripten/libretro-classic/index.html deleted file mode 100644 index 9e2f41882c..0000000000 --- a/pkg/emscripten/libretro-classic/index.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - RetroArch Web Player - - - - - - - - - - - - - -
-
-
- -
- - RetroArch Logo -
-
- - - - - - - - - - diff --git a/pkg/emscripten/libretro-classic/indexer b/pkg/emscripten/libretro-classic/indexer deleted file mode 100755 index 5544f481cb..0000000000 --- a/pkg/emscripten/libretro-classic/indexer +++ /dev/null @@ -1,34 +0,0 @@ -#! /usr/bin/env coffee - -fs = require 'fs' -path = require 'path' - -symLinks = {} - -rdSync = (dpath, tree, name) -> - files = fs.readdirSync(dpath) - for file in files - # ignore non-essential directories / files - continue if file in ['.git', 'node_modules', 'bower_components', 'build'] or file[0] is '.' - fpath = dpath + '/' + file - try - # Avoid infinite loops. - lstat = fs.lstatSync(fpath) - if lstat.isSymbolicLink() - symLinks[lstat.dev] ?= {} - # Ignore if we've seen it before - continue if symLinks[lstat.dev][lstat.ino]? - symLinks[lstat.dev][lstat.ino] = 0 - - fstat = fs.statSync(fpath) - if fstat.isDirectory() - tree[file] = child = {} - rdSync(fpath, child, file) - else - tree[file] = null - catch e - # Ignore and move on. - return tree - -fs_listing = rdSync(process.cwd(), {}, '/') -console.log(JSON.stringify(fs_listing)) diff --git a/pkg/emscripten/libretro-classic/libretro.css b/pkg/emscripten/libretro-classic/libretro.css deleted file mode 100644 index 4d08dc2eb4..0000000000 --- a/pkg/emscripten/libretro-classic/libretro.css +++ /dev/null @@ -1,120 +0,0 @@ -/** - * RetroArch Web Player - * - * This provides the basic styling for the RetroArch web player. - */ - -/** - * Make sure the background of the player is black. - * Also make sure line height is 0 so there's no extra space on the bottom. - */ -.webplayer-container { - background-color: black; - line-height: 0; -} - -/** - * Webplayer Preview when not loaded. - */ -.webplayer-preview { - margin: 0 auto; - cursor: wait; - opacity: 0.2; - transition: all 0.8s; - -webkit-animation: loading 0.8s ease-in-out infinite alternate; - -moz-animation: loading 0.8s ease-in-out infinite alternate; - animation: loading 0.8s ease-in-out infinite alternate; -} -.webplayer-preview.loaded { - cursor: pointer; - opacity: 1; - -webkit-animation: loaded 0.8s ease-in-out; - -moz-animation: loaded 0.8s ease-in-out; - animation: loaded 0.8s ease-in-out; -} -@keyframes loaded { - from { - opacity: 0.2; - } - to { - opacity: 1; - } -} -@-moz-keyframes loaded { - from { - opacity: 0.2; - } - to { - opacity: 1; - } -} -@-webkit-keyframes loaded { - from { - opacity: 0.2; - } - to { - opacity: 1; - } -} -@keyframes loading{ - from { - opacity: 0.2; - } - to { - opacity: 0.35; - } -} -@-moz-keyframes loading{ - from { - opacity: 0.2; - } - to { - opacity: 0.35; - } -} -@-webkit-keyframes loading { - from { - opacity: 0.2; - } - to { - opacity: 0.35; - } -} - -/** - * Disable the border around the player. - */ -canvas.webplayer { - border: none; - outline: none; -} - -textarea { - font-family: monospace; - font-size: 0.7em; - height: 95%; - width: 95%; - border-style: none; - border-color: transparent; - overflow: auto; - resize: none; -} - -/** - * Toggle Top Navigation - */ -.toggleMenu { - float: right; -} -.showMenu { - position: absolute; - right: 0; - cursor: pointer; -} -#icnShowMenu { - color: #565656 !important; -} - -.navbar { - box-shadow: none; -} diff --git a/pkg/emscripten/libretro-classic/libretro.js b/pkg/emscripten/libretro-classic/libretro.js deleted file mode 100644 index f0c07a341a..0000000000 --- a/pkg/emscripten/libretro-classic/libretro.js +++ /dev/null @@ -1,389 +0,0 @@ -/** - * RetroArch Web Player - * - * This provides the basic JavaScript for the RetroArch web player. - */ -var BrowserFS = BrowserFS; -var afs; -var initializationCount = 0; - -var Module = { - noInitialRun: true, - arguments: ["-v", "--menu"], - - encoder: new TextEncoder(), - message_queue: [], - message_out: [], - message_accum: "", - - retroArchSend: function(msg) { - let bytes = this.encoder.encode(msg + "\n"); - this.message_queue.push([bytes, 0]); - }, - retroArchRecv: function() { - let out = this.message_out.shift(); - if (out == null && this.message_accum != "") { - out = this.message_accum; - this.message_accum = ""; - } - return out; - }, - preRun: [ - function(module) { - function stdin() { - // Return ASCII code of character, or null if no input - while (module.message_queue.length > 0) { - var msg = module.message_queue[0][0]; - var index = module.message_queue[0][1]; - if (index >= msg.length) { - module.message_queue.shift(); - } else { - module.message_queue[0][1] = index + 1; - // assumption: msg is a uint8array - return msg[index]; - } - } - return null; - } - - function stdout(c) { - if (c == null) { - // flush - if (module.message_accum != "") { - module.message_out.push(module.message_accum); - module.message_accum = ""; - } - } else { - let s = String.fromCharCode(c); - if (s == "\n") { - if (module.message_accum != "") { - module.message_out.push(module.message_accum); - module.message_accum = ""; - } - } else { - module.message_accum = module.message_accum + s; - } - } - } - module.FS.init(stdin, stdout); - } - ], - postRun: [], - onRuntimeInitialized: function() { - appInitialized(); - }, - print: function(text) { - console.log("stdout:", text); - }, - printErr: function(text) { - console.log("stderr:", text); - }, - canvas: document.getElementById("canvas"), - totalDependencies: 0, - monitorRunDependencies: function(left) { - this.totalDependencies = Math.max(this.totalDependencies, left); - } -}; - - -function cleanupStorage() { - localStorage.clear(); - if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { - var req = indexedDB.deleteDatabase("RetroArch"); - req.onsuccess = function() { - console.log("Deleted database successfully"); - }; - req.onerror = function() { - console.error("Couldn't delete database"); - }; - req.onblocked = function() { - console.error("Couldn't delete database due to the operation being blocked"); - }; - } - - document.getElementById("btnClean").disabled = true; -} - -function idbfsInit() { - $('#icnLocal').removeClass('fa-globe'); - $('#icnLocal').addClass('fa-spinner fa-spin'); - var imfs = new BrowserFS.FileSystem.InMemory(); - if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { - afs = new BrowserFS.FileSystem.AsyncMirror(imfs, - new BrowserFS.FileSystem.IndexedDB(function(e, fs) { - if (e) { - // fallback to imfs - afs = new BrowserFS.FileSystem.InMemory(); - console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); - appInitialized(); - } else { - // initialize afs by copying files from async storage to sync storage. - afs.initialize(function(e) { - if (e) { - afs = new BrowserFS.FileSystem.InMemory(); - console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); - appInitialized(); - } else { - idbfsSyncComplete(); - } - }); - } - }, - "RetroArch")); - } -} - -function idbfsSyncComplete() { - $('#icnLocal').removeClass('fa-spinner').removeClass('fa-spin'); - $('#icnLocal').addClass('fa-check'); - console.log("WEBPLAYER: idbfs setup successful"); - - appInitialized(); -} - -function appInitialized() { - /* Need to wait for the file system, the wasm runtime, and the zip download - to complete before enabling the Run button. */ - initializationCount++; - if (initializationCount == 3) { - setupFileSystem("browser"); - preLoadingComplete(); - } -} - -function preLoadingComplete() { - // Make the Preview image clickable to start RetroArch. - $('.webplayer-preview').addClass('loaded').click(function() { - startRetroArch(); - return false; - }); - $('#btnRun').removeClass('disabled').removeAttr("disabled").click(function() { - startRetroArch(); - return false; - }); -} - -var zipTOC; - -function zipfsInit() { - // 256 MB max bundle size - let buffer = new ArrayBuffer(256 * 1024 * 1024); - let bufferView = new Uint8Array(buffer); - let idx = 0; - // bundle should be in five parts (this can be changed later) - Promise.all([fetch("assets/frontend/bundle.zip.aa"), - fetch("assets/frontend/bundle.zip.ab"), - fetch("assets/frontend/bundle.zip.ac"), - fetch("assets/frontend/bundle.zip.ad"), - fetch("assets/frontend/bundle.zip.ae") - ]).then(function(resps) { - Promise.all(resps.map((r) => r.arrayBuffer())).then(function(buffers) { - for (let buf of buffers) { - if (idx + buf.byteLength > buffer.maxByteLength) { - console.error("WEBPLAYER: error: bundle.zip is too large"); - } - bufferView.set(new Uint8Array(buf), idx, buf.byteLength); - idx += buf.byteLength; - } - BrowserFS.FileSystem.ZipFS.computeIndex(BrowserFS.BFSRequire('buffer').Buffer(new Uint8Array(buffer, 0, idx)), function(toc) { - zipTOC = toc; - appInitialized(); - }); - }) - }); -} - -function setupFileSystem(backend) { - // create a mountable filesystem that will server as a root mountpoint for browserfs - var mfs = new BrowserFS.FileSystem.MountableFileSystem(); - - // create an XmlHttpRequest filesystem for the bundled data - var xfs1 = new BrowserFS.FileSystem.ZipFS(zipTOC); - // create an XmlHttpRequest filesystem for core assets - var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest(".index-xhr", "assets/cores/"); - - console.log("WEBPLAYER: initializing filesystem: " + backend); - mfs.mount('/home/web_user/retroarch/userdata', afs); - - mfs.mount('/home/web_user/retroarch/', xfs1); - mfs.mount('/home/web_user/retroarch/userdata/content/downloads', xfs2); - BrowserFS.initialize(mfs); - var BFS = new BrowserFS.EmscriptenFS(Module.FS, Module.PATH, Module.ERRNO_CODES); - Module.FS.mount(BFS, { - root: '/home' - }, '/home'); - console.log("WEBPLAYER: " + backend + " filesystem initialization successful"); -} - -// Retrieve the value of the given GET parameter. -function getParam(name) { - var results = new RegExp('[?&]' + name + '=([^&#]*)').exec(window.location.href); - if (results) { - return results[1] || null; - } -} - -function startRetroArch() { - $('.webplayer').show(); - $('.webplayer-preview').hide(); - document.getElementById("btnRun").disabled = true; - - $('#btnAdd').removeClass("disabled").removeAttr("disabled").click(function() { - $('#btnRom').click(); - }); - $('#btnRom').removeAttr("disabled").change(function(e) { - selectFiles(e.target.files); - }); - $('#btnMenu').removeClass("disabled").removeAttr("disabled").click(function() { - Module._cmd_toggle_menu(); - Module.canvas.focus(); - }); - $('#btnFullscreen').removeClass("disabled").removeAttr("disabled").click(function() { - Module.requestFullscreen(false); - Module.canvas.focus(); - }); - - Module.canvas.focus(); - Module.canvas.addEventListener("pointerdown", function() { - Module.canvas.focus(); - }, false); - Module.callMain(Module.arguments); -} - -function selectFiles(files) { - $('#btnAdd').addClass('disabled'); - $('#icnAdd').removeClass('fa-plus'); - $('#icnAdd').addClass('fa-spinner spinning'); - var count = files.length; - - for (var i = 0; i < count; i++) { - filereader = new FileReader(); - filereader.file_name = files[i].name; - filereader.readAsArrayBuffer(files[i]); - filereader.onload = function() { - uploadData(this.result, this.file_name) - }; - filereader.onloadend = function(evt) { - console.log("WEBPLAYER: file: " + this.file_name + " upload complete"); - if (evt.target.readyState == FileReader.DONE) { - $('#btnAdd').removeClass('disabled'); - $('#icnAdd').removeClass('fa-spinner spinning'); - $('#icnAdd').addClass('fa-plus'); - } - } - } -} - -function uploadData(data, name) { - var dataView = new Uint8Array(data); - Module.FS.createDataFile('/', name, dataView, true, false); - - var data = Module.FS.readFile(name, { - encoding: 'binary' - }); - Module.FS.writeFile('/home/web_user/retroarch/userdata/content/' + name, data, { - encoding: 'binary' - }); - Module.FS.unlink(name); -} - -function switchCore(corename) { - localStorage.setItem("core", corename); -} - -function switchStorage(backend) { - if (backend != localStorage.getItem("backend")) { - localStorage.setItem("backend", backend); - location.reload(); - } -} - -// When the browser has loaded everything. -$(function() { - // Enable data clear - $('#btnClean').click(function() { - cleanupStorage(); - }); - - // Enable all available ToolTips. - $('.tooltip-enable').tooltip({ - placement: 'right' - }); - - // Allow hiding the top menu. - $('.showMenu').hide(); - $('#btnHideMenu, .showMenu').click(function() { - $('nav').slideToggle('slow'); - $('.showMenu').toggle('slow'); - }); - - // Attempt to disable some default browser keys. - var keys = { - 9: "tab", - 13: "enter", - 16: "shift", - 18: "alt", - 27: "esc", - 33: "rePag", - 34: "avPag", - 35: "end", - 36: "home", - 37: "left", - 38: "up", - 39: "right", - 40: "down", - 112: "F1", - 113: "F2", - 114: "F3", - 115: "F4", - 116: "F5", - 117: "F6", - 118: "F7", - 119: "F8", - 120: "F9", - 121: "F10", - 122: "F11", - 123: "F12" - }; - window.addEventListener('keydown', function(e) { - if (keys[e.which]) { - e.preventDefault(); - } - }); - - // Switch the core when selecting one. - $('#core-selector a').click(function() { - var coreChoice = $(this).data('core'); - switchCore(coreChoice); - }); - // Find which core to load. - var core = localStorage.getItem("core", core); - if (!core) { - core = 'gambatte'; - } - loadCore(core); -}); - -function loadCore(core) { - // Make the core the selected core in the UI. - var coreTitle = $('#core-selector a[data-core="' + core + '"]').addClass('active').text(); - $('#dropdownMenu1').text(coreTitle); - // Load the Core's related JavaScript. - import("./" + core + "_libretro.js").then(script => { - script.default(Module).then(mod => { - Module = mod; - $('#icnRun').removeClass('fa-spinner').removeClass('fa-spin'); - $('#icnRun').addClass('fa-play'); - $('#lblDrop').removeClass('active'); - $('#lblLocal').addClass('active'); - idbfsInit(); - zipfsInit(); - }).catch(err => { - console.error("Couldn't instantiate module", err); - throw err; - }); - }).catch(err => { - console.error("Couldn't load script", err); - throw err; - }); -} diff --git a/pkg/emscripten/libretro-classic/browserfs.min.js b/pkg/emscripten/libretro/browserfs.min.js similarity index 100% rename from pkg/emscripten/libretro-classic/browserfs.min.js rename to pkg/emscripten/libretro/browserfs.min.js diff --git a/pkg/emscripten/libretro/index.html b/pkg/emscripten/libretro/index.html index b1846f5985..9e2f41882c 100644 --- a/pkg/emscripten/libretro/index.html +++ b/pkg/emscripten/libretro/index.html @@ -192,13 +192,13 @@ RetroArch Logo - - - - + + + + - + diff --git a/pkg/emscripten/libretro/libretro.js b/pkg/emscripten/libretro/libretro.js index 788aca3054..a2fd96b8e5 100644 --- a/pkg/emscripten/libretro/libretro.js +++ b/pkg/emscripten/libretro/libretro.js @@ -3,8 +3,9 @@ * * This provides the basic JavaScript for the RetroArch web player. */ -var retroarch_ready = false; -var setImmediate; +var BrowserFS = BrowserFS; +var afs; +var initializationCount = 0; var Module = { noInitialRun: true, @@ -69,7 +70,6 @@ var Module = { ], postRun: [], onRuntimeInitialized: function() { - retroarch_ready = true; appInitialized(); }, print: function(text) { @@ -86,22 +86,70 @@ var Module = { }; -async function cleanupStorage() -{ - localStorage.clear(); - let storage = await navigator.storage.getDirectory(); - await storage.remove({recursive: true}); - document.getElementById("btnClean").disabled = true; +function cleanupStorage() { + localStorage.clear(); + if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { + var req = indexedDB.deleteDatabase("RetroArch"); + req.onsuccess = function() { + console.log("Deleted database successfully"); + }; + req.onerror = function() { + console.error("Couldn't delete database"); + }; + req.onblocked = function() { + console.error("Couldn't delete database due to the operation being blocked"); + }; + } + + document.getElementById("btnClean").disabled = true; } -function appInitialized() -{ - /* Need to wait for the wasm runtime to load before enabling the Run button. */ - if (retroarch_ready) - { - setupFileSystem().then(() => { preLoadingComplete(); }); - } - } +function idbfsInit() { + $('#icnLocal').removeClass('fa-globe'); + $('#icnLocal').addClass('fa-spinner fa-spin'); + var imfs = new BrowserFS.FileSystem.InMemory(); + if (BrowserFS.FileSystem.IndexedDB.isAvailable()) { + afs = new BrowserFS.FileSystem.AsyncMirror(imfs, + new BrowserFS.FileSystem.IndexedDB(function(e, fs) { + if (e) { + // fallback to imfs + afs = new BrowserFS.FileSystem.InMemory(); + console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); + appInitialized(); + } else { + // initialize afs by copying files from async storage to sync storage. + afs.initialize(function(e) { + if (e) { + afs = new BrowserFS.FileSystem.InMemory(); + console.error("WEBPLAYER: error: " + e + " falling back to in-memory filesystem"); + appInitialized(); + } else { + idbfsSyncComplete(); + } + }); + } + }, + "RetroArch")); + } +} + +function idbfsSyncComplete() { + $('#icnLocal').removeClass('fa-spinner').removeClass('fa-spin'); + $('#icnLocal').addClass('fa-check'); + console.log("WEBPLAYER: idbfs setup successful"); + + appInitialized(); +} + +function appInitialized() { + /* Need to wait for the file system, the wasm runtime, and the zip download + to complete before enabling the Run button. */ + initializationCount++; + if (initializationCount == 3) { + setupFileSystem("browser"); + preLoadingComplete(); + } +} function preLoadingComplete() { // Make the Preview image clickable to start RetroArch. @@ -115,63 +163,56 @@ function preLoadingComplete() { }); } -async function setupZipFS(mount) { - let buffers = await Promise.all([ - fetch("assets/frontend/bundle.zip.aa").then((r) => r.arrayBuffer()), - fetch("assets/frontend/bundle.zip.ab").then((r) => r.arrayBuffer()), - fetch("assets/frontend/bundle.zip.ac").then((r) => r.arrayBuffer()), - fetch("assets/frontend/bundle.zip.ad").then((r) => r.arrayBuffer()) - ]); - let buffer = new ArrayBuffer(256*1024*1024); - let bufferView = new Uint8Array(buffer); - let idx = 0; - for (let buf of buffers) { - if (idx+buf.byteLength > buffer.maxByteLength) { - console.log("WEBPLAYER: error: bundle.zip is too large"); - } - bufferView.set(new Uint8Array(buf), idx, buf.byteLength); - idx += buf.byteLength; - } - const zipBuf = new Uint8Array(buffer, 0, idx); - const zipReader = new zip.ZipReader(new zip.Uint8ArrayReader(zipBuf), {useWebWorkers:false}); - const entries = await zipReader.getEntries(); - for(const file of entries) { - if (file.getData && !file.directory) { - const writer = new zip.Uint8ArrayWriter(); - const data = await file.getData(writer); - Module.FS.createPreloadedFile(mount+"/"+file.filename, undefined, data, true, true); - } else if (file.directory) { - Module.FS.mkdirTree(mount+"/"+file.filename); - } - } - await zipReader.close(); +var zipTOC; + +function zipfsInit() { + // 256 MB max bundle size + let buffer = new ArrayBuffer(256 * 1024 * 1024); + let bufferView = new Uint8Array(buffer); + let idx = 0; + // bundle should be in five parts (this can be changed later) + Promise.all([fetch("assets/frontend/bundle.zip.aa"), + fetch("assets/frontend/bundle.zip.ab"), + fetch("assets/frontend/bundle.zip.ac"), + fetch("assets/frontend/bundle.zip.ad"), + fetch("assets/frontend/bundle.zip.ae") + ]).then(function(resps) { + Promise.all(resps.map((r) => r.arrayBuffer())).then(function(buffers) { + for (let buf of buffers) { + if (idx + buf.byteLength > buffer.maxByteLength) { + console.error("WEBPLAYER: error: bundle.zip is too large"); + } + bufferView.set(new Uint8Array(buf), idx, buf.byteLength); + idx += buf.byteLength; + } + BrowserFS.FileSystem.ZipFS.computeIndex(BrowserFS.BFSRequire('buffer').Buffer(new Uint8Array(buffer, 0, idx)), function(toc) { + zipTOC = toc; + appInitialized(); + }); + }) + }); } -function loadIndex(index, path) { - for (const key of Object.keys(index)) { - if (index[key]) { - Module.FS.mkdirTree(path+key+"/"); - loadIndex(index[key], path+key+"/"); - } else { - Module.FS.open(path+key, "w+"); - } - } -} +function setupFileSystem(backend) { + // create a mountable filesystem that will server as a root mountpoint for browserfs + var mfs = new BrowserFS.FileSystem.MountableFileSystem(); -async function setupFileSystem() -{ - Module.FS.mkdirTree("/home/web_user/retroarch/userdata"); + // create an XmlHttpRequest filesystem for the bundled data + var xfs1 = new BrowserFS.FileSystem.ZipFS(zipTOC); + // create an XmlHttpRequest filesystem for core assets + var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest(".index-xhr", "assets/cores/"); - Module.FS.mount(Module.OPFS, {}, "/home/web_user/retroarch/userdata"); - - Module.FS.mkdir("/home/web_user/retroarch/downloads",700); - let index = await (await fetch("assets/cores/.index-xhr")).json(); - let manifest = {}; - Module.FS.mount(Module.FETCHFS, {"base_url":"assets/cores"}, "/home/web_user/retroarch/downloads"); - loadIndex(index, "/home/web_user/retroarch/downloads/"); + console.log("WEBPLAYER: initializing filesystem: " + backend); + mfs.mount('/home/web_user/retroarch/userdata', afs); - setupZipFS("/home/web_user/retroarch"); - console.log("WEBPLAYER: filesystem initialization successful"); + mfs.mount('/home/web_user/retroarch/', xfs1); + mfs.mount('/home/web_user/retroarch/userdata/content/downloads', xfs2); + BrowserFS.initialize(mfs); + var BFS = new BrowserFS.EmscriptenFS(Module.FS, Module.PATH, Module.ERRNO_CODES); + Module.FS.mount(BFS, { + root: '/home' + }, '/home'); + console.log("WEBPLAYER: " + backend + " filesystem initialization successful"); } // Retrieve the value of the given GET parameter. @@ -201,6 +242,7 @@ function startRetroArch() { Module.requestFullscreen(false); Module.canvas.focus(); }); + Module.canvas.focus(); Module.canvas.addEventListener("pointerdown", function() { Module.canvas.focus(); @@ -322,26 +364,26 @@ $(function() { loadCore(core); }); -async function downloadScript(src) { - let resp = await fetch(src); - let blob = await resp.blob(); - return blob; -} - function loadCore(core) { // Make the core the selected core in the UI. var coreTitle = $('#core-selector a[data-core="' + core + '"]').addClass('active').text(); $('#dropdownMenu1').text(coreTitle); - downloadScript("./"+core+"_libretro.js").then(scriptBlob => { - Module.mainScriptUrlOrBlob = scriptBlob; - import(URL.createObjectURL(scriptBlob)).then(script => { - script.default(Module).then(mod => { - Module = mod; - $('#icnRun').removeClass('fa-spinner').removeClass('fa-spin'); - $('#icnRun').addClass('fa-play'); - $('#lblDrop').removeClass('active'); - $('#lblLocal').addClass('active'); - }).catch(err => { console.error("Couldn't instantiate module",err); throw err; }); - }).catch(err => { console.error("Couldn't load script",err); throw err; }); + // Load the Core's related JavaScript. + import("./" + core + "_libretro.js").then(script => { + script.default(Module).then(mod => { + Module = mod; + $('#icnRun').removeClass('fa-spinner').removeClass('fa-spin'); + $('#icnRun').addClass('fa-play'); + $('#lblDrop').removeClass('active'); + $('#lblLocal').addClass('active'); + idbfsInit(); + zipfsInit(); + }).catch(err => { + console.error("Couldn't instantiate module", err); + throw err; + }); + }).catch(err => { + console.error("Couldn't load script", err); + throw err; }); -} +} \ No newline at end of file diff --git a/pkg/emscripten/libretro/zip.min.js b/pkg/emscripten/libretro/zip.min.js deleted file mode 100644 index 8fa7801643..0000000000 --- a/pkg/emscripten/libretro/zip.min.js +++ /dev/null @@ -1 +0,0 @@ -((e,t)=>{"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).zip={})})(this,(function(e){"use strict";const{Array:t,Object:n,String:r,Number:s,BigInt:i,Math:a,Date:o,Map:c,Set:l,Response:u,URL:f,Error:d,Uint8Array:w,Uint16Array:p,Uint32Array:h,DataView:g,Blob:m,Promise:y,TextEncoder:b,TextDecoder:S,document:k,crypto:z,btoa:v,TransformStream:x,ReadableStream:A,WritableStream:C,CompressionStream:_,DecompressionStream:D,navigator:W,Worker:R}="undefined"!=typeof globalThis?globalThis:this||self;var F=void 0!==k?k.currentScript:null;const E=4294967295,T=65535,L=67324752,U=134695760,I=U,N=33639248,q=101010256,O=101075792,P=117853008,H=22,M=21589,B=2048,V="/",Z=new o(2107,11,31),K=new o(1980,0,1),G=void 0,X="undefined",Y="function";class j{constructor(e){return class extends x{constructor(t,n){const r=new e(n);super({transform(e,t){t.enqueue(r.append(e))},flush(e){const t=r.flush();t&&e.enqueue(t)}})}}}}let J=2;try{typeof W!=X&&W.hardwareConcurrency&&(J=W.hardwareConcurrency)}catch(e){}const Q={chunkSize:524288,maxWorkers:J,terminateWorkerTimeout:5e3,useWebWorkers:!0,useCompressionStream:!0,workerScripts:G,CompressionStreamNative:typeof _!=X&&_,DecompressionStreamNative:typeof D!=X&&D},$=n.assign({},Q);function ee(){return $}function te(e){return a.max(e.chunkSize,64)}function ne(e){const{baseURL:n,chunkSize:r,maxWorkers:s,terminateWorkerTimeout:i,useCompressionStream:a,useWebWorkers:o,Deflate:c,Inflate:l,CompressionStream:u,DecompressionStream:f,workerScripts:w}=e;if(re("baseURL",n),re("chunkSize",r),re("maxWorkers",s),re("terminateWorkerTimeout",i),re("useCompressionStream",a),re("useWebWorkers",o),c&&($.CompressionStream=new j(c)),l&&($.DecompressionStream=new j(l)),re("CompressionStream",u),re("DecompressionStream",f),w!==G){const{deflate:e,inflate:n}=w;if((e||n)&&($.workerScripts||($.workerScripts={})),e){if(!t.isArray(e))throw new d("workerScripts.deflate must be an array");$.workerScripts.deflate=e}if(n){if(!t.isArray(n))throw new d("workerScripts.inflate must be an array");$.workerScripts.inflate=n}}}function re(e,t){t!==G&&($[e]=t)}function se(e,t,r){return class{constructor(s){const i=this;var a,o;a=s,o="level",(typeof n.hasOwn===Y?n.hasOwn(a,o):a.hasOwnProperty(o))&&s.level===G&&delete s.level,i.codec=new e(n.assign({},t,s)),r(i.codec,(e=>{if(i.pendingData){const t=i.pendingData;i.pendingData=new w(t.length+e.length);const{pendingData:n}=i;n.set(t,0),n.set(e,t.length)}else i.pendingData=new w(e)}))}append(e){return this.codec.push(e),s(this)}flush(){return this.codec.push(new w,!0),s(this)}};function s(e){if(e.pendingData){const t=e.pendingData;return e.pendingData=null,t}return new w}}const ie=[];for(let e=0;256>e;e++){let t=e;for(let e=0;8>e;e++)1&t?t=t>>>1^3988292384:t>>>=1;ie[e]=t}class ae{constructor(e){this.crc=e||-1}append(e){let t=0|this.crc;for(let n=0,r=0|e.length;r>n;n++)t=t>>>8^ie[255&(t^e[n])];this.crc=t}get(){return~this.crc}}class oe extends x{constructor(){let e;const t=new ae;super({transform(e,n){t.append(e),n.enqueue(e)},flush(){const n=new w(4);new g(n.buffer).setUint32(0,t.get()),e.value=n}}),e=this}}function ce(e){if(typeof b==X){const t=new w((e=unescape(encodeURIComponent(e))).length);for(let n=0;n0&&t&&(e[n-1]=le.partial(t,e[n-1]&2147483648>>t-1,1)),e},partial:(e,t,n)=>32===e?t:(n?0|t:t<<32-e)+1099511627776*e,getPartial:e=>a.round(e/1099511627776)||32,_shiftRight(e,t,n,r){for(void 0===r&&(r=[]);t>=32;t-=32)r.push(n),n=0;if(0===t)return r.concat(e);for(let s=0;s>>t),n=e[s]<<32-t;const s=e.length?e[e.length-1]:0,i=le.getPartial(s);return r.push(le.partial(t+i&31,t+i>32?n:r.pop(),1)),r}},ue={bytes:{fromBits(e){const t=le.bitLength(e)/8,n=new w(t);let r;for(let s=0;t>s;s++)3&s||(r=e[s/4]),n[s]=r>>>24,r<<=8;return n},toBits(e){const t=[];let n,r=0;for(n=0;n9007199254740991)throw new d("Cannot hash more than 2^53 - 1 bits");const i=new h(n);let a=0;for(let e=t.blockSize+r-(t.blockSize+r&t.blockSize-1);s>=e;e+=t.blockSize)t._block(i.subarray(16*a,16*(a+1))),a+=1;return n.splice(0,16*a),t}finalize(){const e=this;let t=e._buffer;const n=e._h;t=le.concat(t,[le.partial(1,1)]);for(let e=t.length+2;15&e;e++)t.push(0);for(t.push(a.floor(e._length/4294967296)),t.push(0|e._length);t.length;)e._block(t.splice(0,16));return e.reset(),n}_f(e,t,n,r){return e>19?e>39?e>59?e>79?void 0:t^n^r:t&n|t&r|n&r:t^n^r:t&n|~t&r}_S(e,t){return t<>>32-e}_block(e){const n=this,r=n._h,s=t(80);for(let t=0;16>t;t++)s[t]=e[t];let i=r[0],o=r[1],c=r[2],l=r[3],u=r[4];for(let e=0;79>=e;e++){16>e||(s[e]=n._S(1,s[e-3]^s[e-8]^s[e-14]^s[e-16]));const t=n._S(5,i)+n._f(e,o,c,l)+u+s[e]+n._key[a.floor(e/20)]|0;u=l,l=c,c=n._S(30,o),o=i,i=t}r[0]=r[0]+i|0,r[1]=r[1]+o|0,r[2]=r[2]+c|0,r[3]=r[3]+l|0,r[4]=r[4]+u|0}},de={getRandomValues(e){const t=new h(e.buffer),n=e=>{let t=987654321;const n=4294967295;return()=>(t=36969*(65535&t)+(t>>16)&n,(((t<<16)+(e=18e3*(65535&e)+(e>>16)&n)&n)/4294967296+.5)*(a.random()>.5?1:-1))};for(let r,s=0;snew we.hmacSha1(ue.bytes.toBits(e)),pbkdf2(e,t,n,r){if(n=n||1e4,0>r||0>n)throw new d("invalid params to pbkdf2");const s=1+(r>>5)<<2;let i,a,o,c,l;const u=new ArrayBuffer(s),f=new g(u);let w=0;const p=le;for(t=ue.bytes.toBits(t),l=1;(s||1)>w;l++){for(i=a=e.encrypt(p.concat(t,[l])),o=1;n>o;o++)for(a=e.encrypt(a),c=0;cw&&os&&(e=(new n).update(e).finalize());for(let t=0;s>t;t++)r[0][t]=909522486^e[t],r[1][t]=1549556828^e[t];t._baseHash[0].update(r[0]),t._baseHash[1].update(r[1]),t._resultHash=new n(t._baseHash[0])}reset(){const e=this;e._resultHash=new e._hash(e._baseHash[0]),e._updated=!1}update(e){this._updated=!0,this._resultHash.update(e)}digest(){const e=this,t=e._resultHash.finalize(),n=new e._hash(e._baseHash[1]).update(t).finalize();return e.reset(),n}encrypt(e){if(this._updated)throw new d("encrypt on already updated hmac called!");return this.update(e),this.digest(e)}}},pe=typeof z!=X&&typeof z.getRandomValues==Y,he="Invalid password",ge="Invalid signature",me="zipjs-abort-check-password";function ye(e){return pe?z.getRandomValues(e):de.getRandomValues(e)}const be=16,Se={name:"PBKDF2"},ke=n.assign({hash:{name:"HMAC"}},Se),ze=n.assign({iterations:1e3,hash:{name:"SHA-1"}},Se),ve=["deriveBits"],xe=[8,12,16],Ae=[16,24,32],Ce=10,_e=[0,0,0,0],De=typeof z!=X,We=De&&z.subtle,Re=De&&typeof We!=X,Fe=ue.bytes,Ee=class{constructor(e){const t=this;t._tables=[[[],[],[],[],[]],[[],[],[],[],[]]],t._tables[0][0][0]||t._precompute();const n=t._tables[0][4],r=t._tables[1],s=e.length;let i,a,o,c=1;if(4!==s&&6!==s&&8!==s)throw new d("invalid aes key size");for(t._key=[a=e.slice(0),o=[]],i=s;4*s+28>i;i++){let e=a[i-1];(i%s==0||8===s&&i%s==4)&&(e=n[e>>>24]<<24^n[e>>16&255]<<16^n[e>>8&255]<<8^n[255&e],i%s==0&&(e=e<<8^e>>>24^c<<24,c=c<<1^283*(c>>7))),a[i]=a[i-s]^e}for(let e=0;i;e++,i--){const t=a[3&e?i:i-4];o[e]=4>=i||4>e?t:r[0][n[t>>>24]]^r[1][n[t>>16&255]]^r[2][n[t>>8&255]]^r[3][n[255&t]]}}encrypt(e){return this._crypt(e,0)}decrypt(e){return this._crypt(e,1)}_precompute(){const e=this._tables[0],t=this._tables[1],n=e[4],r=t[4],s=[],i=[];let a,o,c,l;for(let e=0;256>e;e++)i[(s[e]=e<<1^283*(e>>7))^e]=e;for(let u=a=0;!n[u];u^=o||1,a=i[a]||1){let i=a^a<<1^a<<2^a<<3^a<<4;i=i>>8^255&i^99,n[u]=i,r[i]=u,l=s[c=s[o=s[u]]];let f=16843009*l^65537*c^257*o^16843008*u,d=257*s[i]^16843008*i;for(let n=0;4>n;n++)e[n][u]=d=d<<24^d>>>8,t[n][i]=f=f<<24^f>>>8}for(let n=0;5>n;n++)e[n]=e[n].slice(0),t[n]=t[n].slice(0)}_crypt(e,t){if(4!==e.length)throw new d("invalid aes block size");const n=this._key[t],r=n.length/4-2,s=[0,0,0,0],i=this._tables[t],a=i[0],o=i[1],c=i[2],l=i[3],u=i[4];let f,w,p,h=e[0]^n[0],g=e[t?3:1]^n[1],m=e[2]^n[2],y=e[t?1:3]^n[3],b=4;for(let e=0;r>e;e++)f=a[h>>>24]^o[g>>16&255]^c[m>>8&255]^l[255&y]^n[b],w=a[g>>>24]^o[m>>16&255]^c[y>>8&255]^l[255&h]^n[b+1],p=a[m>>>24]^o[y>>16&255]^c[h>>8&255]^l[255&g]^n[b+2],y=a[y>>>24]^o[h>>16&255]^c[g>>8&255]^l[255&m]^n[b+3],b+=4,h=f,g=w,m=p;for(let e=0;4>e;e++)s[t?3&-e:e]=u[h>>>24]<<24^u[g>>16&255]<<16^u[m>>8&255]<<8^u[255&y]^n[b++],f=h,h=g,g=m,m=y,y=f;return s}},Te=class{constructor(e,t){this._prf=e,this._initIv=t,this._iv=t}reset(){this._iv=this._initIv}update(e){return this.calculate(this._prf,e,this._iv)}incWord(e){if(255&~(e>>24))e+=1<<24;else{let t=e>>16&255,n=e>>8&255,r=255&e;255===t?(t=0,255===n?(n=0,255===r?r=0:++r):++n):++t,e=0,e+=t<<16,e+=n<<8,e+=r}return e}incCounter(e){0===(e[0]=this.incWord(e[0]))&&(e[1]=this.incWord(e[1]))}calculate(e,t,n){let r;if(!(r=t.length))return[];const s=le.bitLength(t);for(let s=0;r>s;s+=4){this.incCounter(n);const r=e.encrypt(n);t[s]^=r[0],t[s+1]^=r[1],t[s+2]^=r[2],t[s+3]^=r[3]}return le.clamp(t,s)}},Le=we.hmacSha1;let Ue=De&&Re&&typeof We.importKey==Y,Ie=De&&Re&&typeof We.deriveBits==Y;class Ne extends x{constructor({password:e,rawPassword:t,signed:r,encryptionStrength:s,checkPasswordOnly:i}){super({start(){n.assign(this,{ready:new y((e=>this.resolveReady=e)),password:He(e,t),signed:r,strength:s-1,pending:new w})},async transform(e,t){const n=this,{password:r,strength:s,resolveReady:a,ready:o}=n;r?(await(async(e,t,n,r)=>{const s=await Pe(e,t,n,Be(r,0,xe[t])),i=Be(r,xe[t]);if(s[0]!=i[0]||s[1]!=i[1])throw new d(he)})(n,s,r,Be(e,0,xe[s]+2)),e=Be(e,xe[s]+2),i?t.error(new d(me)):a()):await o;const c=new w(e.length-Ce-(e.length-Ce)%be);t.enqueue(Oe(n,e,c,0,Ce,!0))},async flush(e){const{signed:t,ctr:n,hmac:r,pending:s,ready:i}=this;if(r&&n){await i;const a=Be(s,0,s.length-Ce),o=Be(s,s.length-Ce);let c=new w;if(a.length){const e=Ze(Fe,a);r.update(e);const t=n.update(e);c=Ve(Fe,t)}if(t){const e=Be(Ve(Fe,r.digest()),0,Ce);for(let t=0;Ce>t;t++)if(e[t]!=o[t])throw new d(ge)}e.enqueue(c)}}})}}class qe extends x{constructor({password:e,rawPassword:t,encryptionStrength:r}){let s;super({start(){n.assign(this,{ready:new y((e=>this.resolveReady=e)),password:He(e,t),strength:r-1,pending:new w})},async transform(e,t){const n=this,{password:r,strength:s,resolveReady:i,ready:a}=n;let o=new w;r?(o=await(async(e,t,n)=>{const r=ye(new w(xe[t]));return Me(r,await Pe(e,t,n,r))})(n,s,r),i()):await a;const c=new w(o.length+e.length-e.length%be);c.set(o,0),t.enqueue(Oe(n,e,c,o.length,0))},async flush(e){const{ctr:t,hmac:n,pending:r,ready:i}=this;if(n&&t){await i;let a=new w;if(r.length){const e=t.update(Ze(Fe,r));n.update(e),a=Ve(Fe,e)}s.signature=Ve(Fe,n.digest()).slice(0,Ce),e.enqueue(Me(a,s.signature))}}}),s=this}}function Oe(e,t,n,r,s,i){const{ctr:a,hmac:o,pending:c}=e,l=t.length-s;let u;for(c.length&&(t=Me(c,t),n=((e,t)=>{if(t&&t>e.length){const n=e;(e=new w(t)).set(n,0)}return e})(n,l-l%be)),u=0;l-be>=u;u+=be){const e=Ze(Fe,Be(t,u,u+be));i&&o.update(e);const s=a.update(e);i||o.update(s),n.set(Ve(Fe,s),u+r)}return e.pending=Be(t,u),n}async function Pe(e,r,s,i){e.password=null;const a=await(async(e,t,n,r,s)=>{if(!Ue)return we.importKey(t);try{return await We.importKey("raw",t,n,!1,s)}catch(e){return Ue=!1,we.importKey(t)}})(0,s,ke,0,ve),o=await(async(e,t,n)=>{if(!Ie)return we.pbkdf2(t,e.salt,ze.iterations,n);try{return await We.deriveBits(e,t,n)}catch(r){return Ie=!1,we.pbkdf2(t,e.salt,ze.iterations,n)}})(n.assign({salt:i},ze),a,8*(2*Ae[r]+2)),c=new w(o),l=Ze(Fe,Be(c,0,Ae[r])),u=Ze(Fe,Be(c,Ae[r],2*Ae[r])),f=Be(c,2*Ae[r]);return n.assign(e,{keys:{key:l,authentication:u,passwordVerification:f},ctr:new Te(new Ee(l),t.from(_e)),hmac:new Le(u)}),f}function He(e,t){return t===G?ce(e):t}function Me(e,t){let n=e;return e.length+t.length&&(n=new w(e.length+t.length),n.set(e,0),n.set(t,e.length)),n}function Be(e,t,n){return e.subarray(t,n)}function Ve(e,t){return e.fromBits(t)}function Ze(e,t){return e.toBits(t)}class Ke extends x{constructor({password:e,passwordVerification:t,checkPasswordOnly:r}){super({start(){n.assign(this,{password:e,passwordVerification:t}),je(this,e)},transform(e,t){const n=this;if(n.password){const t=Xe(n,e.subarray(0,12));if(n.password=null,t[11]!=n.passwordVerification)throw new d(he);e=e.subarray(12)}r?t.error(new d(me)):t.enqueue(Xe(n,e))}})}}class Ge extends x{constructor({password:e,passwordVerification:t}){super({start(){n.assign(this,{password:e,passwordVerification:t}),je(this,e)},transform(e,t){const n=this;let r,s;if(n.password){n.password=null;const t=ye(new w(12));t[11]=n.passwordVerification,r=new w(e.length+t.length),r.set(Ye(n,t),0),s=12}else r=new w(e.length),s=0;r.set(Ye(n,e),s),t.enqueue(r)}})}}function Xe(e,t){const n=new w(t.length);for(let r=0;r>>24]),s=~e.crcKey2.get(),e.keys=[n,r,s]}function Qe(e){const t=2|e.keys[2];return $e(a.imul(t,1^t)>>>8)}function $e(e){return 255&e}function et(e){return 4294967295&e}const tt="deflate-raw";class nt extends x{constructor(e,{chunkSize:t,CompressionStream:n,CompressionStreamNative:r}){super({});const{compressed:s,encrypted:i,useCompressionStream:a,zipCrypto:o,signed:c,level:l}=e,u=this;let f,d,w=st(super.readable);i&&!o||!c||(f=new oe,w=ot(w,f)),s&&(w=at(w,a,{level:l,chunkSize:t},r,n)),i&&(o?w=ot(w,new Ge(e)):(d=new qe(e),w=ot(w,d))),it(u,w,(()=>{let e;i&&!o&&(e=d.signature),i&&!o||!c||(e=new g(f.value.buffer).getUint32(0)),u.signature=e}))}}class rt extends x{constructor(e,{chunkSize:t,DecompressionStream:n,DecompressionStreamNative:r}){super({});const{zipCrypto:s,encrypted:i,signed:a,signature:o,compressed:c,useCompressionStream:l}=e;let u,f,w=st(super.readable);i&&(s?w=ot(w,new Ke(e)):(f=new Ne(e),w=ot(w,f))),c&&(w=at(w,l,{chunkSize:t},r,n)),i&&!s||!a||(u=new oe,w=ot(w,u)),it(this,w,(()=>{if((!i||s)&&a){const e=new g(u.value.buffer);if(o!=e.getUint32(0,!1))throw new d(ge)}}))}}function st(e){return ot(e,new x({transform(e,t){e&&e.length&&t.enqueue(e)}}))}function it(e,t,r){t=ot(t,new x({flush:r})),n.defineProperty(e,"readable",{get:()=>t})}function at(e,t,n,r,s){try{e=ot(e,new(t&&r?r:s)(tt,n))}catch(r){if(!t)return e;try{e=ot(e,new s(tt,n))}catch(t){return e}}return e}function ot(e,t){return e.pipeThrough(t)}const ct="data",lt="close",ut="deflate",ft="inflate";class dt extends x{constructor(e,t){super({});const r=this,{codecType:s}=e;let i;s.startsWith(ut)?i=nt:s.startsWith(ft)&&(i=rt);let a=0,o=0;const c=new i(e,t),l=super.readable,u=new x({transform(e,t){e&&e.length&&(o+=e.length,t.enqueue(e))},flush(){n.assign(r,{inputSize:o})}}),f=new x({transform(e,t){e&&e.length&&(a+=e.length,t.enqueue(e))},flush(){const{signature:e}=c;n.assign(r,{signature:e,outputSize:a,inputSize:o})}});n.defineProperty(r,"readable",{get:()=>l.pipeThrough(u).pipeThrough(c).pipeThrough(f)})}}class wt extends x{constructor(e){let t;super({transform:function n(r,s){if(t){const e=new w(t.length+r.length);e.set(t),e.set(r,t.length),r=e,t=null}r.length>e?(s.enqueue(r.slice(0,e)),n(r.slice(e),s)):t=r},flush(e){t&&t.length&&e.enqueue(t)}})}}let pt=typeof R!=X;class ht{constructor(e,{readable:t,writable:r},{options:s,config:i,streamOptions:a,useWebWorkers:o,transferStreams:c,scripts:l},u){const{signal:f}=a;return n.assign(e,{busy:!0,readable:t.pipeThrough(new wt(i.chunkSize)).pipeThrough(new gt(t,a),{signal:f}),writable:r,options:n.assign({},s),scripts:l,transferStreams:c,terminate:()=>new y((t=>{const{worker:n,busy:r}=e;n?(r?e.resolveTerminated=t:(n.terminate(),t()),e.interface=null):t()})),onTaskFinished(){const{resolveTerminated:t}=e;t&&(e.resolveTerminated=null,e.terminated=!0,e.worker.terminate(),t()),e.busy=!1,u(e)}}),(o&&pt?bt:yt)(e,i)}}class gt extends x{constructor(e,{onstart:t,onprogress:n,size:r,onend:s}){let i=0;super({async start(){t&&await mt(t,r)},async transform(e,t){i+=e.length,n&&await mt(n,i,r),t.enqueue(e)},async flush(){e.size=i,s&&await mt(s,i)}})}}async function mt(e,...t){try{await e(...t)}catch(e){}}function yt(e,t){return{run:()=>(async({options:e,readable:t,writable:n,onTaskFinished:r},s)=>{try{const r=new dt(e,s);await t.pipeThrough(r).pipeTo(n,{preventClose:!0,preventAbort:!0});const{signature:i,inputSize:a,outputSize:o}=r;return{signature:i,inputSize:a,outputSize:o}}finally{r()}})(e,t)}}function bt(e,t){const{baseURL:r,chunkSize:s}=t;if(!e.interface){let i;try{i=((e,t,r)=>{const s={type:"module"};let i,a;typeof e==Y&&(e=e());try{i=new f(e,t)}catch(t){i=e}if(St)try{a=new R(i)}catch(e){St=!1,a=new R(i,s)}else a=new R(i,s);return a.addEventListener("message",(e=>(async({data:e},t)=>{const{type:r,value:s,messageId:i,result:a,error:o}=e,{reader:c,writer:l,resolveResult:u,rejectResult:f,onTaskFinished:p}=t;try{if(o){const{message:e,stack:t,code:r,name:s}=o,i=new d(e);n.assign(i,{stack:t,code:r,name:s}),h(i)}else{if("pull"==r){const{value:e,done:n}=await c.read();zt({type:ct,value:e,done:n,messageId:i},t)}r==ct&&(await l.ready,await l.write(new w(s)),zt({type:"ack",messageId:i},t)),r==lt&&h(null,a)}}catch(o){zt({type:lt,messageId:i},t),h(o)}function h(e,t){e?f(e):u(t),l&&l.releaseLock(),p()}})(e,r))),a})(e.scripts[0],r,e)}catch(n){return pt=!1,yt(e,t)}n.assign(e,{worker:i,interface:{run:()=>(async(e,t)=>{let r,s;const i=new y(((e,t)=>{r=e,s=t}));n.assign(e,{reader:null,writer:null,resolveResult:r,rejectResult:s,result:i});const{readable:a,options:o,scripts:c}=e,{writable:l,closed:u}=(e=>{let t;const n=new y((e=>t=e));return{writable:new C({async write(t){const n=e.getWriter();await n.ready,await n.write(t),n.releaseLock()},close(){t()},abort:t=>e.getWriter().abort(t)}),closed:n}})(e.writable),f=zt({type:"start",scripts:c.slice(1),options:o,config:t,readable:a,writable:l},e);f||n.assign(e,{reader:a.getReader(),writer:l.getWriter()});const d=await i;return f||await l.getWriter().close(),await u,d})(e,{chunkSize:s})}})}return e.interface}let St=!0,kt=!0;function zt(e,{worker:t,writer:n,onTaskFinished:r,transferStreams:s}){try{const{value:n,readable:r,writable:i}=e,a=[];if(n&&(n.byteLength{const n=vt.find((e=>!e.busy));if(n)return _t(n),new ht(n,e,t,h);if(vt.lengthxt.push({resolve:n,stream:e,workerOptions:t})))})()).run();function h(e){if(xt.length){const[{resolve:t,stream:n,workerOptions:r}]=xt.splice(0,1);t(new ht(e,n,r,h))}else e.worker?(_t(e),((e,t)=>{const{config:n}=t,{terminateWorkerTimeout:r}=n;s.isFinite(r)&&r>=0&&(e.terminated?e.terminated=!1:e.terminateTimeout=setTimeout((async()=>{vt=vt.filter((t=>t!=e));try{await e.terminate()}catch(e){}}),r))})(e,t)):vt=vt.filter((t=>t!=e))}}function _t(e){const{terminateTimeout:t}=e;t&&(clearTimeout(t),e.terminateTimeout=null)}const Dt="HTTP error ",Wt="HTTP Range not supported",Rt="Writer iterator completed too soon",Ft="Range",Et="GET",Tt="bytes",Lt=65536,Ut="writable";class It{constructor(){this.size=0}init(){this.initialized=!0}}class Nt extends It{get readable(){const e=this,{chunkSize:t=Lt}=e,n=new A({start(){this.chunkOffset=0},async pull(r){const{offset:s=0,size:i,diskNumberStart:o}=n,{chunkOffset:c}=this;r.enqueue(await on(e,s+c,a.min(t,i-c),o)),c+t>i?r.close():this.chunkOffset+=t}});return n}}class qt extends It{constructor(){super();const e=this,t=new C({write:t=>e.writeUint8Array(t)});n.defineProperty(e,Ut,{get:()=>t})}writeUint8Array(){}}class Ot extends Nt{constructor(e){super(),n.assign(this,{blob:e,size:e.size})}async readUint8Array(e,t){const n=this,r=e+t,s=e||rt&&(i=i.slice(e,r)),new w(i)}}class Pt extends It{constructor(e){super();const t=new x,r=[];e&&r.push(["Content-Type",e]),n.defineProperty(this,Ut,{get:()=>t.writable}),this.blob=new u(t.readable,{headers:r}).blob()}getData(){return this.blob}}class Ht extends Nt{constructor(e,t){super(),Bt(this,e,t)}async init(){await Vt(this,Qt,Xt),super.init()}readUint8Array(e,t){return Zt(this,e,t,Qt,Xt)}}class Mt extends Nt{constructor(e,t){super(),Bt(this,e,t)}async init(){await Vt(this,$t,Yt),super.init()}readUint8Array(e,t){return Zt(this,e,t,$t,Yt)}}function Bt(e,t,r){const{preventHeadRequest:s,useRangeHeader:i,forceRangeRequests:a,combineSizeEocd:o}=r;delete(r=n.assign({},r)).preventHeadRequest,delete r.useRangeHeader,delete r.forceRangeRequests,delete r.combineSizeEocd,delete r.useXHR,n.assign(e,{url:t,options:r,preventHeadRequest:s,useRangeHeader:i,forceRangeRequests:a,combineSizeEocd:o})}async function Vt(e,t,n){const{url:r,preventHeadRequest:i,useRangeHeader:a,forceRangeRequests:o,combineSizeEocd:c}=e;if((e=>{const{baseURL:t}=ee(),{protocol:n}=new f(e,t);return"http:"==n||"https:"==n})(r)&&(a||o)&&(void 0===i||i)){const r=await t(Et,e,Kt(e,c?-22:void 0));if(!o&&r.headers.get("Accept-Ranges")!=Tt)throw new d(Wt);{let i;c&&(e.eocdCache=new w(await r.arrayBuffer()));const a=r.headers.get("Content-Range");if(a){const e=a.trim().split(/\s*\/\s*/);if(e.length){const t=e[1];t&&"*"!=t&&(i=s(t))}}i===G?await Jt(e,t,n):e.size=i}}else await Jt(e,t,n)}async function Zt(e,t,n,r,s){const{useRangeHeader:i,forceRangeRequests:a,eocdCache:o,size:c,options:l}=e;if(i||a){if(o&&t==c-H&&n==H)return o;const s=await r(Et,e,Kt(e,t,n));if(206!=s.status)throw new d(Wt);return new w(await s.arrayBuffer())}{const{data:r}=e;return r||await s(e,l),new w(e.data.subarray(t,t+n))}}function Kt(e,t=0,r=1){return n.assign({},Gt(e),{[Ft]:Tt+"="+(0>t?t:t+"-"+(t+r-1))})}function Gt({options:e}){const{headers:t}=e;if(t)return Symbol.iterator in t?n.fromEntries(t):t}async function Xt(e){await jt(e,Qt)}async function Yt(e){await jt(e,$t)}async function jt(e,t){const n=await t(Et,e,Gt(e));e.data=new w(await n.arrayBuffer()),e.size||(e.size=e.data.length)}async function Jt(e,t,n){if(e.preventHeadRequest)await n(e,e.options);else{const r=(await t("HEAD",e,Gt(e))).headers.get("Content-Length");r?e.size=s(r):await n(e,e.options)}}async function Qt(e,{options:t,url:r},s){const i=await fetch(r,n.assign({},t,{method:e,headers:s}));if(400>i.status)return i;throw 416==i.status?new d(Wt):new d(Dt+(i.statusText||i.status))}function $t(e,{url:t},r){return new y(((s,i)=>{const a=new XMLHttpRequest;if(a.addEventListener("load",(()=>{if(400>a.status){const e=[];a.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((t=>{const n=t.trim().split(/\s*:\s*/);n[0]=n[0].trim().replace(/^[a-z]|-[a-z]/g,(e=>e.toUpperCase())),e.push(n)})),s({status:a.status,arrayBuffer:()=>a.response,headers:new c(e)})}else i(416==a.status?new d(Wt):new d(Dt+(a.statusText||a.status)))}),!1),a.addEventListener("error",(e=>i(e.detail?e.detail.error:new d("Network error"))),!1),a.open(e,t),r)for(const e of n.entries(r))a.setRequestHeader(e[0],e[1]);a.responseType="arraybuffer",a.send()}))}class en extends Nt{constructor(e,t={}){super(),n.assign(this,{url:e,reader:t.useXHR?new Mt(e,t):new Ht(e,t)})}set size(e){}get size(){return this.reader.size}async init(){await this.reader.init(),super.init()}readUint8Array(e,t){return this.reader.readUint8Array(e,t)}}class tn extends Nt{constructor(e){super(),this.readers=e}async init(){const e=this,{readers:t}=e;e.lastDiskNumber=0,e.lastDiskOffset=0,await y.all(t.map((async(n,r)=>{await n.init(),r!=t.length-1&&(e.lastDiskOffset+=n.size),e.size+=n.size}))),super.init()}async readUint8Array(e,t,n=0){const r=this,{readers:s}=this;let i,o=n;-1==o&&(o=s.length-1);let c=e;for(;c>=s[o].size;)c-=s[o].size,o++;const l=s[o],u=l.size;if(c+t>u){const s=u-c;i=new w(t),i.set(await on(l,c,s)),i.set(await r.readUint8Array(e+s,t-s,n),s)}else i=await on(l,c,t);return r.lastDiskNumber=a.max(o,r.lastDiskNumber),i}}class nn extends It{constructor(e,t=4294967295){super();const r=this;let s,i,a;n.assign(r,{diskNumber:0,diskOffset:0,size:0,maxSize:t,availableSize:t});const o=new C({async write(t){const{availableSize:n}=r;if(a)t.lengtho})}}async function rn(e,t){if(!e.init||e.initialized)return y.resolve();await e.init(t)}function sn(e){return t.isArray(e)&&(e=new tn(e)),e instanceof A&&(e={readable:e}),e}function an(e){e.writable===G&&typeof e.next==Y&&(e=new nn(e)),e instanceof C&&(e={writable:e});const{writable:t}=e;return t.size===G&&(t.size=0),e instanceof nn||n.assign(e,{diskNumber:0,diskOffset:0,availableSize:1/0,maxSize:1/0}),e}function on(e,t,n,r){return e.readUint8Array(t,n,r)}const cn=tn,ln=nn,un="\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");function fn(e,t){return t&&"cp437"==t.trim().toLowerCase()?(e=>{{let t="";for(let n=0;nthis[t]=e[t]))}}const Ln="File format is not recognized",Un="End of central directory not found",In="End of Zip64 central directory locator not found",Nn="Central directory header not found",qn="Local file header not found",On="Zip64 extra field not found",Pn="File contains encrypted entry",Hn="Encryption method not supported",Mn="Compression method not supported",Bn="Split zip file",Vn="utf-8",Zn="cp437",Kn=[[gn,E],[mn,E],[yn,E],[bn,T]],Gn={[T]:{getValue:sr,bytes:4},[E]:{getValue:ir,bytes:8}};class Xn{constructor(e,t={}){n.assign(this,{reader:sn(e),options:t,config:ee()})}async*getEntriesGenerator(e={}){const t=this;let{reader:r}=t;const{config:s}=t;if(await rn(r),r.size!==G&&r.readUint8Array||(r=new Ot(await new u(r.readable).blob()),await rn(r)),r.size{const r=new w(4);var s;return s=t,ar(r).setUint32(0,s,!0),await i(22)||await i(a.min(1048582,n));async function i(t){const s=n-t,i=await on(e,s,t);for(let e=i.length-22;e>=0;e--)if(i[e]==r[0]&&i[e+1]==r[1]&&i[e+2]==r[2]&&i[e+3]==r[3])return{offset:s+e,buffer:i.slice(e,e+22).buffer}}})(r,q,r.size);if(!i)throw sr(ar(await on(r,0,4)))==U?new d(Bn):new d(Un);const o=ar(i);let c=sr(o,12),l=sr(o,16);const f=i.offset,p=rr(o,20),h=f+H+p;let g=rr(o,4);const m=r.lastDiskNumber||0;let y=rr(o,6),b=rr(o,8),S=0,k=0;if(l==E||c==E||b==T||y==T){const e=ar(await on(r,i.offset-20,20));if(sr(e,0)==P){l=ir(e,8);let t=await on(r,l,56,-1),n=ar(t);const s=i.offset-20-56;if(sr(n,0)!=O&&l!=s){const e=l;l=s,S=l-e,t=await on(r,l,56,-1),n=ar(t)}if(sr(n,0)!=O)throw new d(In);g==T&&(g=sr(n,16)),y==T&&(y=sr(n,20)),b==T&&(b=ir(n,32)),c==E&&(c=ir(n,40)),l-=c}}if(ll)throw new d(Ln);let z=0,v=await on(r,l,c,y),x=ar(v);if(c){const e=i.offset-c;if(sr(x,z)!=N&&l!=e){const t=l;l=e,S+=l-t,v=await on(r,l,c,y),x=ar(v)}}const A=i.offset-l-(r.lastDiskOffset||0);if(c==A||0>A||(c=A,v=await on(r,l,c,y),x=ar(v)),0>l||l>=r.size)throw new d(Ln);const C=$n(t,e,"filenameEncoding"),_=$n(t,e,"commentEncoding");for(let i=0;b>i;i++){const o=new Yn(r,s,t.options);if(sr(x,z)!=N)throw new d(Nn);jn(o,x,z+6);const c=!!o.bitFlag.languageEncodingFlag,l=z+46,u=l+o.filenameLength,f=u+o.extraFieldLength,w=rr(x,z+4),p=!0,h=v.subarray(l,u),g=rr(x,z+32),m=f+g,y=v.subarray(f,m),A=c,D=c,W=p&&!(16&~nr(x,z+38)),R=sr(x,z+42)+S;n.assign(o,{versionMadeBy:w,msDosCompatible:p,compressedSize:0,uncompressedSize:0,commentLength:g,directory:W,offset:R,diskNumberStart:rr(x,z+34),internalFileAttribute:rr(x,z+36),externalFileAttribute:sr(x,z+38),rawFilename:h,filenameUTF8:A,commentUTF8:D,rawExtraField:v.subarray(u,f)});const F=$n(t,e,"decodeText")||fn,E=A?Vn:C||Zn,T=D?Vn:_||Zn;let L=F(h,E);L===G&&(L=fn(h,E));let U=F(y,T);U===G&&(U=fn(y,T)),n.assign(o,{rawComment:y,filename:L,comment:U,directory:W||L.endsWith(V)}),k=a.max(R,k),Jn(o,o,x,z+6),o.zipCrypto=o.encrypted&&!o.extraFieldAES;const I=new Tn(o);I.getData=(e,t)=>o.getData(e,I,t),z=m;const{onprogress:q}=e;if(q)try{await q(i+1,b,new Tn(o))}catch(e){}yield I}const D=$n(t,e,"extractPrependedData"),W=$n(t,e,"extractAppendedData");return D&&(t.prependedData=k>0?await on(r,0,k):new w),t.comment=p?await on(r,f+H,p):new w,W&&(t.appendedData=h>>8&255:p>>>24&255),signature:p,compressed:0!=l&&!z,encrypted:s.encrypted&&!z,useWebWorkers:$n(s,r,"useWebWorkers"),useCompressionStream:$n(s,r,"useCompressionStream"),transferStreams:$n(s,r,"transferStreams"),checkPasswordOnly:R},config:u,streamOptions:{signal:W,size:_,onstart:E,onprogress:T,onend:U}};let N=0;try{({outputSize:N}=await Ct({readable:D,writable:F},I))}catch(e){if(!R||e.message!=me)throw e}finally{const e=$n(s,r,"preventClose");F.size+=N,e||F.locked||await F.getWriter().close()}return R?G:e.getData?e.getData():F}}function jn(e,t,r){const s=e.rawBitFlag=rr(t,r+2),i=!(1&~s),a=sr(t,r+6);n.assign(e,{encrypted:i,version:rr(t,r),bitFlag:{level:(6&s)>>1,dataDescriptor:!(8&~s),languageEncodingFlag:(s&B)==B},rawLastModDate:a,lastModDate:er(a),filenameLength:rr(t,r+22),extraFieldLength:rr(t,r+24)})}function Jn(e,t,r,s,i){const{rawExtraField:a}=t,l=t.extraField=new c,u=ar(new w(a));let f=0;try{for(;f{t.zip64=!0;const n=ar(e.data),r=Kn.filter((([e,n])=>t[e]==n));for(let s=0,i=0;s{const s=ar(e.data),i=nr(s,4);n.assign(e,{vendorVersion:nr(s,0),vendorId:nr(s,2),strength:i,originalCompressionMethod:r,compressionMethod:rr(s,5)}),t.compressionMethod=e.compressionMethod})(y,t,p),t.extraFieldAES=y):t.compressionMethod=p;const b=l.get(10);b&&(((e,t)=>{const r=ar(e.data);let s,i=4;try{for(;i{const r=ar(e.data),s=nr(r,0),i=[],a=[];n?(1&~s||(i.push(Sn),a.push(kn)),2&~s||(i.push(zn),a.push("rawLastAccessDate")),4&~s||(i.push(vn),a.push("rawCreationDate"))):5>e.data.length||(i.push(Sn),a.push(kn));let c=1;i.forEach(((n,s)=>{if(e.data.length>=c+4){const i=sr(r,c);t[n]=e[n]=new o(1e3*i);const l=a[s];e[l]=i}c+=4}))})(S,t,i),t.extraFieldExtendedTimestamp=S);const k=l.get(6534);k&&(t.extraFieldUSDZ=k)}function Qn(e,t,r,s,i){const a=ar(e.data),o=new ae;o.append(i[r]);const c=ar(new w(4));c.setUint32(0,o.get(),!0);const l=sr(a,1);n.assign(e,{version:nr(a,0),[t]:fn(e.data.subarray(5)),valid:!i.bitFlag.languageEncodingFlag&&l==sr(c,0)}),e.valid&&(s[t]=e[t],s[t+"UTF8"]=!0)}function $n(e,t,n){return t[n]===G?e.options[n]:t[n]}function er(e){const t=(4294901760&e)>>16,n=65535&e;try{return new o(1980+((65024&t)>>9),((480&t)>>5)-1,31&t,(63488&n)>>11,(2016&n)>>5,2*(31&n),0)}catch(e){}}function tr(e){return new o(s(e/i(1e4)-i(116444736e5)))}function nr(e,t){return e.getUint8(t)}function rr(e,t){return e.getUint16(t,!0)}function sr(e,t){return e.getUint32(t,!0)}function ir(e,t){return s(e.getBigUint64(t,!0))}function ar(e){return new g(e.buffer)}const or="File already exists",cr="Zip file comment exceeds 64KB",lr="File entry comment exceeds 64KB",ur="File entry name exceeds 64KB",fr="Version exceeds 65535",dr="The strength must equal 1, 2, or 3",wr="Extra field type exceeds 65535",pr="Extra field data exceeds 64KB",hr="Zip64 is not supported (make sure 'keepOrder' is set to 'true')",gr="Undefined uncompressed size",mr=new w([7,0,2,0,65,69,3,0,0]);let yr=0;const br=[];class Sr{constructor(e,t={}){const r=(e=an(e)).availableSize!==G&&e.availableSize>0&&e.availableSize!==1/0&&e.maxSize!==G&&e.maxSize>0&&e.maxSize!==1/0;n.assign(this,{writer:e,addSplitZipSignature:r,options:t,config:ee(),files:new c,filenames:new l,offset:t.offset===G?e.writable.size:t.offset,pendingEntriesSize:0,pendingAddFileCalls:new l,bufferedWrites:0})}async add(e="",r,s={}){const c=this,{pendingAddFileCalls:l,config:f}=c;let m;yrbr.push(e)));try{if(e=e.trim(),c.filenames.has(e))throw new d(or);return c.filenames.add(e),m=(async(e,r,s,c)=>{r=r.trim(),c.directory&&!r.endsWith(V)?r+=V:c.directory=r.endsWith(V);const l=vr(e,c,"encodeText",ce);let f=l(r);if(f===G&&(f=ce(r)),Fr(f)>T)throw new d(ur);const m=c.comment||"";let b=l(m);if(b===G&&(b=ce(m)),Fr(b)>T)throw new d(lr);const S=vr(e,c,Wn,20);if(S>T)throw new d(fr);const k=vr(e,c,Rn,20);if(k>T)throw new d(fr);const z=vr(e,c,Sn,new o),v=vr(e,c,zn),A=vr(e,c,vn),C=vr(e,c,Cn,!0),_=vr(e,c,xn,0),D=vr(e,c,An,0),W=vr(e,c,"passThrough");let R,F;W||(R=vr(e,c,"password"),F=vr(e,c,"rawPassword"));const N=vr(e,c,"encryptionStrength",3),q=vr(e,c,Fn),O=vr(e,c,"extendedTimestamp",!0),P=vr(e,c,"keepOrder",!0),H=vr(e,c,"level"),X=vr(e,c,"useWebWorkers"),Y=vr(e,c,"bufferedWrite"),j=vr(e,c,"dataDescriptorSignature",!1),J=vr(e,c,"signal"),Q=vr(e,c,"useUnicodeFileNames",!0),$=vr(e,c,"useCompressionStream"),ee=vr(e,c,"compressionMethod");let ne=vr(e,c,"dataDescriptor",!0),re=vr(e,c,_n);if(!q&&(R!==G||F!==G)&&(1>N||N>3))throw new d(dr);let se=new w;const{extraField:ie}=c;if(ie){let e=0,t=0;ie.forEach((t=>e+=4+Fr(t))),se=new w(e),ie.forEach(((e,n)=>{if(n>T)throw new d(wr);if(Fr(e)>T)throw new d(pr);Wr(se,new p([n]),t),Wr(se,new p([Fr(e)]),t+2),Wr(se,e,t+4),t+=4+Fr(e)}))}let ae=0,oe=0,le=0;if(W&&(({uncompressedSize:le}=c),le===G))throw new d(gr);const ue=!0===re;s&&(s=sn(s),await rn(s),W?ae=xr(le):s.size===G?(ne=!0,(re||re===G)&&(re=!0,le=ae=4294967296)):(le=s.size,ae=xr(le)));const{diskOffset:fe,diskNumber:de,maxSize:we}=e.writer,pe=ue||le>E,he=ue||ae>E,ge=ue||e.offset+e.pendingEntriesSize-fe>E,me=vr(e,c,"supportZip64SplitFile",!0)&&ue||de+a.ceil(e.pendingEntriesSize/we)>T;if(ge||pe||he||me){if(!1===re||!P)throw new d(hr);re=!0}re=re||!1;const ye=vr(e,c,Dn),{signature:be}=c,Se=(e=>{const{rawFilename:t,lastModDate:n,lastAccessDate:r,creationDate:s,level:i,zip64:o,zipCrypto:c,useUnicodeFileNames:l,dataDescriptor:u,directory:f,rawExtraField:d,encryptionStrength:p,extendedTimestamp:g,encrypted:m}=e;let{version:y,compressionMethod:b}=e;const S=!f&&(i>0||i===G&&0!==b);let k,z,v,x;if(m&&!c){k=new w(Fr(mr)+2);const e=Rr(k);Cr(e,0,39169),Wr(k,mr,2),Ar(e,8,p)}else k=new w;if(g){v=new w(9+(r?4:0)+(s?4:0));const e=Rr(v);Cr(e,0,M),Cr(e,2,Fr(v)-4),x=1+(r?2:0)+(s?4:0),Ar(e,4,x);let t=5;_r(e,t,a.floor(n.getTime()/1e3)),t+=4,r&&(_r(e,t,a.floor(r.getTime()/1e3)),t+=4),s&&_r(e,t,a.floor(s.getTime()/1e3));try{z=new w(36);const e=Rr(z),t=zr(n);Cr(e,0,10),Cr(e,2,32),Cr(e,8,1),Cr(e,10,24),Dr(e,12,t),Dr(e,20,zr(r)||t),Dr(e,28,zr(s)||t)}catch(e){z=new w}}else z=v=new w;let A=0;l&&(A|=B),u&&(A|=8),b===G&&(b=S?8:0),8==b&&(i>=1&&3>i&&(A|=6),i>=3&&5>i&&(A|=1),9===i&&(A|=2)),o&&(y=y>45?y:45),m&&(A|=1,c||(y=y>51?y:51,k[9]=b,b=99));const C=new w(26),_=Rr(C);Cr(_,0,y),Cr(_,2,A),Cr(_,4,b);const D=new h(1),W=Rr(D);let R;R=K>n?K:n>Z?Z:n,Cr(W,0,(R.getHours()<<6|R.getMinutes())<<5|R.getSeconds()/2),Cr(W,2,(R.getFullYear()-1980<<4|R.getMonth()+1)<<5|R.getDate());const F=D[0];_r(_,6,F),Cr(_,22,Fr(t));const E=Fr(k,v,z,d);Cr(_,24,E);const T=new w(30+Fr(t)+E);return _r(Rr(T),0,L),Wr(T,C,4),Wr(T,t,30),Wr(T,k,30+Fr(t)),Wr(T,v,30+Fr(t,k)),Wr(T,z,30+Fr(t,k,v)),Wr(T,d,30+Fr(t,k,v,z)),{localHeaderArray:T,headerArray:C,headerView:_,lastModDate:n,rawLastModDate:F,encrypted:m,compressed:S,version:y,compressionMethod:b,extraFieldExtendedTimestampFlag:x,rawExtraFieldExtendedTimestamp:v,rawExtraFieldNTFS:z,rawExtraFieldAES:k,extraFieldLength:E}})(c=n.assign({},c,{rawFilename:f,rawComment:b,version:S,versionMadeBy:k,lastModDate:z,lastAccessDate:v,creationDate:A,rawExtraField:se,zip64:re,zip64UncompressedSize:pe,zip64CompressedSize:he,zip64Offset:ge,zip64DiskNumberStart:me,password:R,rawPassword:F,level:$||e.config.CompressionStream!==G||e.config.CompressionStreamNative!==G?H:0,useWebWorkers:X,encryptionStrength:N,extendedTimestamp:O,zipCrypto:q,bufferedWrite:Y,keepOrder:P,useUnicodeFileNames:Q,dataDescriptor:ne,dataDescriptorSignature:j,signal:J,msDosCompatible:C,internalFileAttribute:_,externalFileAttribute:D,useCompressionStream:$,passThrough:W,encrypted:!!(R&&Fr(R)||F&&Fr(F))||W&&ye,signature:be,compressionMethod:ee})),ke=(e=>{const{zip64:t,dataDescriptor:n,dataDescriptorSignature:r}=e;let s,i=new w,a=0;return n&&(i=new w(t?r?24:20:r?16:12),s=Rr(i),r&&(a=4,_r(s,0,I))),{dataDescriptorArray:i,dataDescriptorView:s,dataDescriptorOffset:a}})(c),ze=Fr(Se.localHeaderArray,ke.dataDescriptorArray);let ve;oe=ze+ae,e.options.usdz&&(oe+=oe+64),e.pendingEntriesSize+=oe;try{ve=await(async(e,r,s,a,o)=>{const{files:c,writer:l}=e,{keepOrder:f,dataDescriptor:p,signal:h}=o,{headerInfo:m}=a,{usdz:b}=e.options,S=t.from(c.values()).pop();let k,z,v,A,C,_,D,W={};c.set(r,W);try{let t;f&&(t=S&&S.lock,W.lock=new y((e=>v=e))),!(o.bufferedWrite||e.writerLocked||e.bufferedWrites&&f)&&p||b?(_=l,await R()):(_=new x,D=new u(_.readable).blob(),_.writable.size=0,k=!0,e.bufferedWrites++,await rn(l)),await rn(_);const{writable:m}=l;let{diskOffset:z}=l;if(e.addSplitZipSignature){delete e.addSplitZipSignature;const t=new w(4);_r(Rr(t),0,U),await kr(m,t),e.offset+=4}b&&((e,t)=>{const{headerInfo:n}=e;let{localHeaderArray:r,extraFieldLength:s}=n,i=Rr(r),a=64-(t+Fr(r))%64;4>a&&(a+=64);const o=new w(a),c=Rr(o);Cr(c,0,6534),Cr(c,2,a-2);const l=r;n.localHeaderArray=r=new w(Fr(l)+a),Wr(r,l),Wr(r,o,Fr(l)),i=Rr(r),Cr(i,28,s+a),e.metadataSize+=a})(a,e.offset-z),k||(await t,await F(m));const{diskNumber:T}=l;if(C=!0,W.diskNumberStart=T,W=await(async(e,t,{diskNumberStart:r,lock:s},a,o,c)=>{const{headerInfo:l,dataDescriptorInfo:u,metadataSize:f}=a,{localHeaderArray:d,headerArray:p,lastModDate:h,rawLastModDate:g,encrypted:m,compressed:y,version:b,compressionMethod:S,rawExtraFieldExtendedTimestamp:k,extraFieldExtendedTimestampFlag:z,rawExtraFieldNTFS:v,rawExtraFieldAES:x}=l,{dataDescriptorArray:A}=u,{rawFilename:C,lastAccessDate:_,creationDate:D,password:W,rawPassword:R,level:F,zip64:T,zip64UncompressedSize:L,zip64CompressedSize:U,zip64Offset:I,zip64DiskNumberStart:N,zipCrypto:q,dataDescriptor:O,directory:P,versionMadeBy:H,rawComment:M,rawExtraField:B,useWebWorkers:V,onstart:Z,onprogress:K,onend:X,signal:Y,encryptionStrength:j,extendedTimestamp:J,msDosCompatible:Q,internalFileAttribute:$,externalFileAttribute:ee,useCompressionStream:ne,passThrough:re}=c,se={lock:s,versionMadeBy:H,zip64:T,directory:!!P,filenameUTF8:!0,rawFilename:C,commentUTF8:!0,rawComment:M,rawExtraFieldExtendedTimestamp:k,rawExtraFieldNTFS:v,rawExtraFieldAES:x,rawExtraField:B,extendedTimestamp:J,msDosCompatible:Q,internalFileAttribute:$,externalFileAttribute:ee,diskNumberStart:r};let{signature:ie,uncompressedSize:ae}=c,oe=0;re||(ae=0);const{writable:ce}=t;if(e){e.chunkSize=te(o),await kr(ce,d);const t=e.readable,n=t.size=e.size,r={options:{codecType:ut,level:F,rawPassword:R,password:W,encryptionStrength:j,zipCrypto:m&&q,passwordVerification:m&&q&&g>>8&255,signed:!re,compressed:y&&!re,encrypted:m&&!re,useWebWorkers:V,useCompressionStream:ne,transferStreams:!1},config:o,streamOptions:{signal:Y,size:n,onstart:Z,onprogress:K,onend:X}},s=await Ct({readable:t,writable:ce},r);oe=s.outputSize,re||(ae=s.inputSize,ie=s.signature),ce.size+=ae}else await kr(ce,d);let le;if(T){let e=4;L&&(e+=8),U&&(e+=8),I&&(e+=8),N&&(e+=4),le=new w(e)}else le=new w;return((e,t)=>{const{signature:n,rawExtraFieldZip64:r,compressedSize:s,uncompressedSize:a,headerInfo:o,dataDescriptorInfo:c}=e,{headerView:l,encrypted:u}=o,{dataDescriptorView:f,dataDescriptorOffset:d}=c,{zip64:w,zip64UncompressedSize:p,zip64CompressedSize:h,zipCrypto:g,dataDescriptor:m}=t;if(u&&!g||n===G||(_r(l,10,n),m&&_r(f,d,n)),w){const e=Rr(r);Cr(e,0,1),Cr(e,2,Fr(r)-4);let t=4;p&&(_r(l,18,E),Dr(e,t,i(a)),t+=8),h&&(_r(l,14,E),Dr(e,t,i(s))),m&&(Dr(f,d+4,i(s)),Dr(f,d+12,i(a)))}else _r(l,14,s),_r(l,18,a),m&&(_r(f,d+4,s),_r(f,d+8,a))})({signature:ie,rawExtraFieldZip64:le,compressedSize:oe,uncompressedSize:ae,headerInfo:l,dataDescriptorInfo:u},c),O&&await kr(ce,A),n.assign(se,{uncompressedSize:ae,compressedSize:oe,lastModDate:h,rawLastModDate:g,creationDate:D,lastAccessDate:_,encrypted:m,zipCrypto:q,size:f+oe,compressionMethod:S,version:b,headerArray:p,signature:ie,rawExtraFieldZip64:le,extraFieldExtendedTimestampFlag:z,zip64UncompressedSize:L,zip64CompressedSize:U,zip64Offset:I,zip64DiskNumberStart:N}),se})(s,_,W,a,e.config,o),C=!1,c.set(r,W),W.filename=r,k){await _.writable.getWriter().close();let e=await D;await t,await R(),A=!0,p||(e=await(async(e,t,n,{zipCrypto:r})=>{let s;s=await t.slice(0,26).arrayBuffer(),26!=s.byteLength&&(s=s.slice(0,26));const i=new g(s);return e.encrypted&&!r||_r(i,14,e.signature),e.zip64?(_r(i,18,E),_r(i,22,E)):(_r(i,18,e.compressedSize),_r(i,22,e.uncompressedSize)),await kr(n,new w(s)),t.slice(s.byteLength)})(W,e,m,o)),await F(m),W.diskNumberStart=l.diskNumber,z=l.diskOffset,await e.stream().pipeTo(m,{preventClose:!0,preventAbort:!0,signal:h}),m.size+=e.size,A=!1}if(W.offset=e.offset-z,W.zip64)((e,t)=>{const{rawExtraFieldZip64:n,offset:r,diskNumberStart:s}=e,{zip64UncompressedSize:a,zip64CompressedSize:o,zip64Offset:c,zip64DiskNumberStart:l}=t,u=Rr(n);let f=4;a&&(f+=8),o&&(f+=8),c&&(Dr(u,f,i(r)),f+=8),l&&_r(u,f,s)})(W,o);else if(W.offset>E)throw new d(hr);return e.offset+=W.size,W}catch(t){if(k&&A||!k&&C){if(e.hasCorruptedEntries=!0,t)try{t.corruptedEntry=!0}catch(e){}k?e.offset+=_.writable.size:e.offset=_.writable.size}throw c.delete(r),t}finally{k&&e.bufferedWrites--,v&&v(),z&&z()}async function R(){e.writerLocked=!0;const{lockWriter:t}=e;e.lockWriter=new y((t=>z=()=>{e.writerLocked=!1,t()})),await t}async function F(e){Fr(m.localHeaderArray)>l.availableSize&&(l.availableSize=0,await kr(e,new w))}})(e,r,s,{headerInfo:Se,dataDescriptorInfo:ke,metadataSize:ze},c)}finally{e.pendingEntriesSize-=oe}return n.assign(ve,{name:r,comment:m,extraField:ie}),new Tn(ve)})(c,e,r,s),l.add(m),await m}catch(t){throw c.filenames.delete(e),t}finally{l.delete(m);const e=br.shift();e?e():yr--}}async close(e=new w,n={}){const{pendingAddFileCalls:r,writer:s}=this,{writable:o}=s;for(;r.size;)await y.allSettled(t.from(r));return await(async(e,n,r)=>{const{files:s,writer:o}=e,{diskOffset:c,writable:l}=o;let{diskNumber:u}=o,f=0,p=0,h=e.offset-c,g=s.size;for(const[,e]of s){const{rawFilename:t,rawExtraFieldZip64:n,rawExtraFieldAES:r,rawComment:s,rawExtraFieldNTFS:i,rawExtraField:o,extendedTimestamp:c,extraFieldExtendedTimestampFlag:l,lastModDate:u}=e;let f;if(c){f=new w(9);const e=Rr(f);Cr(e,0,M),Cr(e,2,5),Ar(e,4,l),_r(e,5,a.floor(u.getTime()/1e3))}else f=new w;e.rawExtraFieldCDExtendedTimestamp=f,p+=46+Fr(t,s,n,r,i,f,o)}const m=new w(p),y=Rr(m);await rn(o);let b=0;for(const[e,n]of t.from(s.values()).entries()){const{offset:t,rawFilename:i,rawExtraFieldZip64:a,rawExtraFieldAES:c,rawExtraFieldCDExtendedTimestamp:u,rawExtraFieldNTFS:d,rawExtraField:w,rawComment:p,versionMadeBy:h,headerArray:g,directory:S,zip64:k,zip64UncompressedSize:z,zip64CompressedSize:v,zip64DiskNumberStart:x,zip64Offset:A,msDosCompatible:C,internalFileAttribute:_,externalFileAttribute:D,diskNumberStart:W,uncompressedSize:R,compressedSize:F}=n,L=Fr(a,c,u,d,w);_r(y,f,N),Cr(y,f+4,h);const U=Rr(g);z||_r(U,18,R),v||_r(U,14,F),Wr(m,g,f+6),Cr(y,f+30,L),Cr(y,f+32,Fr(p)),Cr(y,f+34,k&&x?T:W),Cr(y,f+36,_),D?_r(y,f+38,D):S&&C&&Ar(y,f+38,16),_r(y,f+42,k&&A?E:t),Wr(m,i,f+46),Wr(m,a,f+46+Fr(i)),Wr(m,c,f+46+Fr(i,a)),Wr(m,u,f+46+Fr(i,a,c)),Wr(m,d,f+46+Fr(i,a,c,u)),Wr(m,w,f+46+Fr(i,a,c,u,d)),Wr(m,p,f+46+Fr(i)+L);const I=46+Fr(i,p)+L;if(f-b>o.availableSize&&(o.availableSize=0,await kr(l,m.slice(b,f)),b=f),f+=I,r.onprogress)try{await r.onprogress(e+1,s.size,new Tn(n))}catch(e){}}await kr(l,b?m.slice(b):m);let S=o.diskNumber;const{availableSize:k}=o;H>k&&S++;let z=vr(e,r,_n);if(h>E||p>E||g>T||S>T){if(!1===z)throw new d(hr);z=!0}const v=new w(z?98:H),x=Rr(v);f=0,z&&(_r(x,0,O),Dr(x,4,i(44)),Cr(x,12,45),Cr(x,14,45),_r(x,16,S),_r(x,20,u),Dr(x,24,i(g)),Dr(x,32,i(g)),Dr(x,40,i(p)),Dr(x,48,i(h)),_r(x,56,P),Dr(x,64,i(h)+i(p)),_r(x,72,S+1),vr(e,r,"supportZip64SplitFile",!0)&&(S=T,u=T),g=T,h=E,p=E,f+=76),_r(x,f,q),Cr(x,f+4,S),Cr(x,f+6,u),Cr(x,f+8,g),Cr(x,f+10,g),_r(x,f+12,p),_r(x,f+16,h);const A=Fr(n);if(A){if(A>T)throw new d(cr);Cr(x,f+20,A)}await kr(l,v),A&&await kr(l,n)})(this,e,n),vr(this,n,"preventClose")||await o.getWriter().close(),s.getData?s.getData():o}}async function kr(e,t){const n=e.getWriter();try{await n.ready,e.size+=Fr(t),await n.write(t)}finally{n.releaseLock()}}function zr(e){if(e)return(i(e.getTime())+i(116444736e5))*i(1e4)}function vr(e,t,n,r){const s=t[n]===G?e.options[n]:t[n];return s===G?r:s}function xr(e){return e+5*(a.floor(e/16383)+1)}function Ar(e,t,n){e.setUint8(t,n)}function Cr(e,t,n){e.setUint16(t,n,!0)}function _r(e,t,n){e.setUint32(t,n,!0)}function Dr(e,t,n){e.setBigUint64(t,n,!0)}function Wr(e,t,n){e.set(t,n)}function Rr(e){return new g(e.buffer)}function Fr(...e){let t=0;return e.forEach((e=>e&&(t+=e.length))),t}let Er;try{Er=void 0===k&&"undefined"==typeof location?require("url").pathToFileURL(__filename).href:void 0===k?location.href:F&&"SCRIPT"===F.tagName.toUpperCase()&&F.src||new f("zip.min.js",k.baseURI).href}catch(e){}ne({baseURL:Er}),((e,t={})=>{const n='const{Array:e,Object:t,Number:n,Math:r,Error:s,Uint8Array:i,Uint16Array:o,Uint32Array:c,Int32Array:f,Map:a,DataView:l,Promise:u,TextEncoder:w,crypto:h,postMessage:d,TransformStream:p,ReadableStream:y,WritableStream:m,CompressionStream:b,DecompressionStream:g}=self,k=void 0,v="undefined",S="function";class z{constructor(e){return class extends p{constructor(t,n){const r=new e(n);super({transform(e,t){t.enqueue(r.append(e))},flush(e){const t=r.flush();t&&e.enqueue(t)}})}}}}const C=[];for(let e=0;256>e;e++){let t=e;for(let e=0;8>e;e++)1&t?t=t>>>1^3988292384:t>>>=1;C[e]=t}class x{constructor(e){this.t=e||-1}append(e){let t=0|this.t;for(let n=0,r=0|e.length;r>n;n++)t=t>>>8^C[255&(t^e[n])];this.t=t}get(){return~this.t}}class A extends p{constructor(){let e;const t=new x;super({transform(e,n){t.append(e),n.enqueue(e)},flush(){const n=new i(4);new l(n.buffer).setUint32(0,t.get()),e.value=n}}),e=this}}const _={concat(e,t){if(0===e.length||0===t.length)return e.concat(t);const n=e[e.length-1],r=_.i(n);return 32===r?e.concat(t):_.o(t,r,0|n,e.slice(0,e.length-1))},l(e){const t=e.length;if(0===t)return 0;const n=e[t-1];return 32*(t-1)+_.i(n)},u(e,t){if(32*e.length0&&t&&(e[n-1]=_.h(t,e[n-1]&2147483648>>t-1,1)),e},h:(e,t,n)=>32===e?t:(n?0|t:t<<32-e)+1099511627776*e,i:e=>r.round(e/1099511627776)||32,o(e,t,n,r){for(void 0===r&&(r=[]);t>=32;t-=32)r.push(n),n=0;if(0===t)return r.concat(e);for(let s=0;s>>t),n=e[s]<<32-t;const s=e.length?e[e.length-1]:0,i=_.i(s);return r.push(_.h(t+i&31,t+i>32?n:r.pop(),1)),r}},I={bytes:{p(e){const t=_.l(e)/8,n=new i(t);let r;for(let s=0;t>s;s++)3&s||(r=e[s/4]),n[s]=r>>>24,r<<=8;return n},m(e){const t=[];let n,r=0;for(n=0;n9007199254740991)throw new s("Cannot hash more than 2^53 - 1 bits");const o=new c(n);let f=0;for(let e=t.blockSize+r-(t.blockSize+r&t.blockSize-1);i>=e;e+=t.blockSize)t.I(o.subarray(16*f,16*(f+1))),f+=1;return n.splice(0,16*f),t}P(){const e=this;let t=e.C;const n=e.S;t=_.concat(t,[_.h(1,1)]);for(let e=t.length+2;15&e;e++)t.push(0);for(t.push(r.floor(e.A/4294967296)),t.push(0|e.A);t.length;)e.I(t.splice(0,16));return e.reset(),n}D(e,t,n,r){return e>19?e>39?e>59?e>79?void 0:t^n^r:t&n|t&r|n&r:t^n^r:t&n|~t&r}V(e,t){return t<>>32-e}I(t){const n=this,s=n.S,i=e(80);for(let e=0;16>e;e++)i[e]=t[e];let o=s[0],c=s[1],f=s[2],a=s[3],l=s[4];for(let e=0;79>=e;e++){16>e||(i[e]=n.V(1,i[e-3]^i[e-8]^i[e-14]^i[e-16]));const t=n.V(5,o)+n.D(e,c,f,a)+l+i[e]+n.v[r.floor(e/20)]|0;l=a,a=f,f=n.V(30,c),c=o,o=t}s[0]=s[0]+o|0,s[1]=s[1]+c|0,s[2]=s[2]+f|0,s[3]=s[3]+a|0,s[4]=s[4]+l|0}},D={getRandomValues(e){const t=new c(e.buffer),n=e=>{let t=987654321;const n=4294967295;return()=>(t=36969*(65535&t)+(t>>16)&n,(((t<<16)+(e=18e3*(65535&e)+(e>>16)&n)&n)/4294967296+.5)*(r.random()>.5?1:-1))};for(let s,i=0;inew V.R(I.bytes.m(e)),B(e,t,n,r){if(n=n||1e4,0>r||0>n)throw new s("invalid params to pbkdf2");const i=1+(r>>5)<<2;let o,c,f,a,u;const w=new ArrayBuffer(i),h=new l(w);let d=0;const p=_;for(t=I.bytes.m(t),u=1;(i||1)>d;u++){for(o=c=e.encrypt(p.concat(t,[u])),f=1;n>f;f++)for(c=e.encrypt(c),a=0;ad&&fs&&(e=(new n).update(e).P());for(let t=0;s>t;t++)r[0][t]=909522486^e[t],r[1][t]=1549556828^e[t];t.U[0].update(r[0]),t.U[1].update(r[1]),t.K=new n(t.U[0])}reset(){const e=this;e.K=new e.M(e.U[0]),e.N=!1}update(e){this.N=!0,this.K.update(e)}digest(){const e=this,t=e.K.P(),n=new e.M(e.U[1]).update(t).P();return e.reset(),n}encrypt(e){if(this.N)throw new s("encrypt on already updated hmac called!");return this.update(e),this.digest(e)}}},R=typeof h!=v&&typeof h.getRandomValues==S,B="Invalid password",E="Invalid signature",M="zipjs-abort-check-password";function U(e){return R?h.getRandomValues(e):D.getRandomValues(e)}const K=16,N={name:"PBKDF2"},O=t.assign({hash:{name:"HMAC"}},N),T=t.assign({iterations:1e3,hash:{name:"SHA-1"}},N),W=["deriveBits"],j=[8,12,16],H=[16,24,32],L=10,F=[0,0,0,0],q=typeof h!=v,G=q&&h.subtle,J=q&&typeof G!=v,Q=I.bytes,X=class{constructor(e){const t=this;t.O=[[[],[],[],[],[]],[[],[],[],[],[]]],t.O[0][0][0]||t.T();const n=t.O[0][4],r=t.O[1],i=e.length;let o,c,f,a=1;if(4!==i&&6!==i&&8!==i)throw new s("invalid aes key size");for(t.v=[c=e.slice(0),f=[]],o=i;4*i+28>o;o++){let e=c[o-1];(o%i==0||8===i&&o%i==4)&&(e=n[e>>>24]<<24^n[e>>16&255]<<16^n[e>>8&255]<<8^n[255&e],o%i==0&&(e=e<<8^e>>>24^a<<24,a=a<<1^283*(a>>7))),c[o]=c[o-i]^e}for(let e=0;o;e++,o--){const t=c[3&e?o:o-4];f[e]=4>=o||4>e?t:r[0][n[t>>>24]]^r[1][n[t>>16&255]]^r[2][n[t>>8&255]]^r[3][n[255&t]]}}encrypt(e){return this.W(e,0)}decrypt(e){return this.W(e,1)}T(){const e=this.O[0],t=this.O[1],n=e[4],r=t[4],s=[],i=[];let o,c,f,a;for(let e=0;256>e;e++)i[(s[e]=e<<1^283*(e>>7))^e]=e;for(let l=o=0;!n[l];l^=c||1,o=i[o]||1){let i=o^o<<1^o<<2^o<<3^o<<4;i=i>>8^255&i^99,n[l]=i,r[i]=l,a=s[f=s[c=s[l]]];let u=16843009*a^65537*f^257*c^16843008*l,w=257*s[i]^16843008*i;for(let n=0;4>n;n++)e[n][l]=w=w<<24^w>>>8,t[n][i]=u=u<<24^u>>>8}for(let n=0;5>n;n++)e[n]=e[n].slice(0),t[n]=t[n].slice(0)}W(e,t){if(4!==e.length)throw new s("invalid aes block size");const n=this.v[t],r=n.length/4-2,i=[0,0,0,0],o=this.O[t],c=o[0],f=o[1],a=o[2],l=o[3],u=o[4];let w,h,d,p=e[0]^n[0],y=e[t?3:1]^n[1],m=e[2]^n[2],b=e[t?1:3]^n[3],g=4;for(let e=0;r>e;e++)w=c[p>>>24]^f[y>>16&255]^a[m>>8&255]^l[255&b]^n[g],h=c[y>>>24]^f[m>>16&255]^a[b>>8&255]^l[255&p]^n[g+1],d=c[m>>>24]^f[b>>16&255]^a[p>>8&255]^l[255&y]^n[g+2],b=c[b>>>24]^f[p>>16&255]^a[y>>8&255]^l[255&m]^n[g+3],g+=4,p=w,y=h,m=d;for(let e=0;4>e;e++)i[t?3&-e:e]=u[p>>>24]<<24^u[y>>16&255]<<16^u[m>>8&255]<<8^u[255&b]^n[g++],w=p,p=y,y=m,m=b,b=w;return i}},Y=class{constructor(e,t){this.j=e,this.H=t,this.L=t}reset(){this.L=this.H}update(e){return this.F(this.j,e,this.L)}q(e){if(255&~(e>>24))e+=1<<24;else{let t=e>>16&255,n=e>>8&255,r=255&e;255===t?(t=0,255===n?(n=0,255===r?r=0:++r):++n):++t,e=0,e+=t<<16,e+=n<<8,e+=r}return e}G(e){0===(e[0]=this.q(e[0]))&&(e[1]=this.q(e[1]))}F(e,t,n){let r;if(!(r=t.length))return[];const s=_.l(t);for(let s=0;r>s;s+=4){this.G(n);const r=e.encrypt(n);t[s]^=r[0],t[s+1]^=r[1],t[s+2]^=r[2],t[s+3]^=r[3]}return _.u(t,s)}},Z=V.R;let $=q&&J&&typeof G.importKey==S,ee=q&&J&&typeof G.deriveBits==S;class te extends p{constructor({password:e,rawPassword:n,signed:r,encryptionStrength:o,checkPasswordOnly:c}){super({start(){t.assign(this,{ready:new u((e=>this.J=e)),password:ie(e,n),signed:r,X:o-1,pending:new i})},async transform(e,t){const n=this,{password:r,X:o,J:f,ready:a}=n;r?(await(async(e,t,n,r)=>{const i=await se(e,t,n,ce(r,0,j[t])),o=ce(r,j[t]);if(i[0]!=o[0]||i[1]!=o[1])throw new s(B)})(n,o,r,ce(e,0,j[o]+2)),e=ce(e,j[o]+2),c?t.error(new s(M)):f()):await a;const l=new i(e.length-L-(e.length-L)%K);t.enqueue(re(n,e,l,0,L,!0))},async flush(e){const{signed:t,Y:n,Z:r,pending:o,ready:c}=this;if(r&&n){await c;const f=ce(o,0,o.length-L),a=ce(o,o.length-L);let l=new i;if(f.length){const e=ae(Q,f);r.update(e);const t=n.update(e);l=fe(Q,t)}if(t){const e=ce(fe(Q,r.digest()),0,L);for(let t=0;L>t;t++)if(e[t]!=a[t])throw new s(E)}e.enqueue(l)}}})}}class ne extends p{constructor({password:e,rawPassword:n,encryptionStrength:r}){let s;super({start(){t.assign(this,{ready:new u((e=>this.J=e)),password:ie(e,n),X:r-1,pending:new i})},async transform(e,t){const n=this,{password:r,X:s,J:o,ready:c}=n;let f=new i;r?(f=await(async(e,t,n)=>{const r=U(new i(j[t]));return oe(r,await se(e,t,n,r))})(n,s,r),o()):await c;const a=new i(f.length+e.length-e.length%K);a.set(f,0),t.enqueue(re(n,e,a,f.length,0))},async flush(e){const{Y:t,Z:n,pending:r,ready:o}=this;if(n&&t){await o;let c=new i;if(r.length){const e=t.update(ae(Q,r));n.update(e),c=fe(Q,e)}s.signature=fe(Q,n.digest()).slice(0,L),e.enqueue(oe(c,s.signature))}}}),s=this}}function re(e,t,n,r,s,o){const{Y:c,Z:f,pending:a}=e,l=t.length-s;let u;for(a.length&&(t=oe(a,t),n=((e,t)=>{if(t&&t>e.length){const n=e;(e=new i(t)).set(n,0)}return e})(n,l-l%K)),u=0;l-K>=u;u+=K){const e=ae(Q,ce(t,u,u+K));o&&f.update(e);const s=c.update(e);o||f.update(s),n.set(fe(Q,s),u+r)}return e.pending=ce(t,u),n}async function se(n,r,s,o){n.password=null;const c=await(async(e,t,n,r,s)=>{if(!$)return V.importKey(t);try{return await G.importKey("raw",t,n,!1,s)}catch(e){return $=!1,V.importKey(t)}})(0,s,O,0,W),f=await(async(e,t,n)=>{if(!ee)return V.B(t,e.salt,T.iterations,n);try{return await G.deriveBits(e,t,n)}catch(r){return ee=!1,V.B(t,e.salt,T.iterations,n)}})(t.assign({salt:o},T),c,8*(2*H[r]+2)),a=new i(f),l=ae(Q,ce(a,0,H[r])),u=ae(Q,ce(a,H[r],2*H[r])),w=ce(a,2*H[r]);return t.assign(n,{keys:{key:l,$:u,passwordVerification:w},Y:new Y(new X(l),e.from(F)),Z:new Z(u)}),w}function ie(e,t){return t===k?(e=>{if(typeof w==v){const t=new i((e=unescape(encodeURIComponent(e))).length);for(let n=0;n>>24]),i=~e.te.get(),e.keys=[n,s,i]}function ye(e){const t=2|e.keys[2];return me(r.imul(t,1^t)>>>8)}function me(e){return 255&e}function be(e){return 4294967295&e}const ge="deflate-raw";class ke extends p{constructor(e,{chunkSize:t,CompressionStream:n,CompressionStreamNative:r}){super({});const{compressed:s,encrypted:i,useCompressionStream:o,zipCrypto:c,signed:f,level:a}=e,u=this;let w,h,d=Se(super.readable);i&&!c||!f||(w=new A,d=xe(d,w)),s&&(d=Ce(d,o,{level:a,chunkSize:t},r,n)),i&&(c?d=xe(d,new ue(e)):(h=new ne(e),d=xe(d,h))),ze(u,d,(()=>{let e;i&&!c&&(e=h.signature),i&&!c||!f||(e=new l(w.value.buffer).getUint32(0)),u.signature=e}))}}class ve extends p{constructor(e,{chunkSize:t,DecompressionStream:n,DecompressionStreamNative:r}){super({});const{zipCrypto:i,encrypted:o,signed:c,signature:f,compressed:a,useCompressionStream:u}=e;let w,h,d=Se(super.readable);o&&(i?d=xe(d,new le(e)):(h=new te(e),d=xe(d,h))),a&&(d=Ce(d,u,{chunkSize:t},r,n)),o&&!i||!c||(w=new A,d=xe(d,w)),ze(this,d,(()=>{if((!o||i)&&c){const e=new l(w.value.buffer);if(f!=e.getUint32(0,!1))throw new s(E)}}))}}function Se(e){return xe(e,new p({transform(e,t){e&&e.length&&t.enqueue(e)}}))}function ze(e,n,r){n=xe(n,new p({flush:r})),t.defineProperty(e,"readable",{get:()=>n})}function Ce(e,t,n,r,s){try{e=xe(e,new(t&&r?r:s)(ge,n))}catch(r){if(!t)return e;try{e=xe(e,new s(ge,n))}catch(t){return e}}return e}function xe(e,t){return e.pipeThrough(t)}const Ae="data",_e="close";class Ie extends p{constructor(e,n){super({});const r=this,{codecType:s}=e;let i;s.startsWith("deflate")?i=ke:s.startsWith("inflate")&&(i=ve);let o=0,c=0;const f=new i(e,n),a=super.readable,l=new p({transform(e,t){e&&e.length&&(c+=e.length,t.enqueue(e))},flush(){t.assign(r,{inputSize:c})}}),u=new p({transform(e,t){e&&e.length&&(o+=e.length,t.enqueue(e))},flush(){const{signature:e}=f;t.assign(r,{signature:e,outputSize:o,inputSize:c})}});t.defineProperty(r,"readable",{get:()=>a.pipeThrough(l).pipeThrough(f).pipeThrough(u)})}}class Pe extends p{constructor(e){let t;super({transform:function n(r,s){if(t){const e=new i(t.length+r.length);e.set(t),e.set(r,t.length),r=e,t=null}r.length>e?(s.enqueue(r.slice(0,e)),n(r.slice(e),s)):t=r},flush(e){t&&t.length&&e.enqueue(t)}})}}const De=new a,Ve=new a;let Re,Be=0,Ee=!0;async function Me(e){try{const{options:t,scripts:r,config:s}=e;if(r&&r.length)try{Ee?importScripts.apply(k,r):await Ue(r)}catch(e){Ee=!1,await Ue(r)}self.initCodec&&self.initCodec(),s.CompressionStreamNative=self.CompressionStream,s.DecompressionStreamNative=self.DecompressionStream,self.Deflate&&(s.CompressionStream=new z(self.Deflate)),self.Inflate&&(s.DecompressionStream=new z(self.Inflate));const i={highWaterMark:1},o=e.readable||new y({async pull(e){const t=new u((e=>De.set(Be,e)));Ke({type:"pull",messageId:Be}),Be=(Be+1)%n.MAX_SAFE_INTEGER;const{value:r,done:s}=await t;e.enqueue(r),s&&e.close()}},i),c=e.writable||new m({async write(e){let t;const r=new u((e=>t=e));Ve.set(Be,t),Ke({type:Ae,value:e,messageId:Be}),Be=(Be+1)%n.MAX_SAFE_INTEGER,await r}},i),f=new Ie(t,s);Re=new AbortController;const{signal:a}=Re;await o.pipeThrough(f).pipeThrough(new Pe(s.chunkSize)).pipeTo(c,{signal:a,preventClose:!0,preventAbort:!0}),await c.getWriter().close();const{signature:l,inputSize:w,outputSize:h}=f;Ke({type:_e,result:{signature:l,inputSize:w,outputSize:h}})}catch(e){Ne(e)}}async function Ue(e){for(const t of e)await import(t)}function Ke(e){let{value:t}=e;if(t)if(t.length)try{t=new i(t),e.value=t.buffer,d(e,[e.value])}catch(t){d(e)}else d(e);else d(e)}function Ne(e=new s("Unknown error")){const{message:t,stack:n,code:r,name:i}=e;d({error:{message:t,stack:n,code:r,name:i}})}addEventListener("message",(({data:e})=>{const{type:t,messageId:n,value:r,done:s}=e;try{if("start"==t&&Me(e),t==Ae){const e=De.get(n);De.delete(n),e({value:new i(r),done:s})}if("ack"==t){const e=Ve.get(n);Ve.delete(n),e()}t==_e&&Re.abort()}catch(e){Ne(e)}}));const Oe=-2;function Te(t){return We(t.map((([t,n])=>new e(t).fill(n,0,t))))}function We(t){return t.reduce(((t,n)=>t.concat(e.isArray(n)?We(n):n)),[])}const je=[0,1,2,3].concat(...Te([[2,4],[2,5],[4,6],[4,7],[8,8],[8,9],[16,10],[16,11],[32,12],[32,13],[64,14],[64,15],[2,0],[1,16],[1,17],[2,18],[2,19],[4,20],[4,21],[8,22],[8,23],[16,24],[16,25],[32,26],[32,27],[64,28],[64,29]]));function He(){const e=this;function t(e,t){let n=0;do{n|=1&e,e>>>=1,n<<=1}while(--t>0);return n>>>1}e.ne=n=>{const s=e.re,i=e.ie.se,o=e.ie.oe;let c,f,a,l=-1;for(n.ce=0,n.fe=573,c=0;o>c;c++)0!==s[2*c]?(n.ae[++n.ce]=l=c,n.le[c]=0):s[2*c+1]=0;for(;2>n.ce;)a=n.ae[++n.ce]=2>l?++l:0,s[2*a]=1,n.le[a]=0,n.ue--,i&&(n.we-=i[2*a+1]);for(e.he=l,c=r.floor(n.ce/2);c>=1;c--)n.de(s,c);a=o;do{c=n.ae[1],n.ae[1]=n.ae[n.ce--],n.de(s,1),f=n.ae[1],n.ae[--n.fe]=c,n.ae[--n.fe]=f,s[2*a]=s[2*c]+s[2*f],n.le[a]=r.max(n.le[c],n.le[f])+1,s[2*c+1]=s[2*f+1]=a,n.ae[1]=a++,n.de(s,1)}while(n.ce>=2);n.ae[--n.fe]=n.ae[1],(t=>{const n=e.re,r=e.ie.se,s=e.ie.pe,i=e.ie.ye,o=e.ie.me;let c,f,a,l,u,w,h=0;for(l=0;15>=l;l++)t.be[l]=0;for(n[2*t.ae[t.fe]+1]=0,c=t.fe+1;573>c;c++)f=t.ae[c],l=n[2*n[2*f+1]+1]+1,l>o&&(l=o,h++),n[2*f+1]=l,f>e.he||(t.be[l]++,u=0,i>f||(u=s[f-i]),w=n[2*f],t.ue+=w*(l+u),r&&(t.we+=w*(r[2*f+1]+u)));if(0!==h){do{for(l=o-1;0===t.be[l];)l--;t.be[l]--,t.be[l+1]+=2,t.be[o]--,h-=2}while(h>0);for(l=o;0!==l;l--)for(f=t.be[l];0!==f;)a=t.ae[--c],a>e.he||(n[2*a+1]!=l&&(t.ue+=(l-n[2*a+1])*n[2*a],n[2*a+1]=l),f--)}})(n),((e,n,r)=>{const s=[];let i,o,c,f=0;for(i=1;15>=i;i++)s[i]=f=f+r[i-1]<<1;for(o=0;n>=o;o++)c=e[2*o+1],0!==c&&(e[2*o]=t(s[c]++,c))})(s,e.he,n.be)}}function Le(e,t,n,r,s){const i=this;i.se=e,i.pe=t,i.ye=n,i.oe=r,i.me=s}He.ge=[0,1,2,3,4,5,6,7].concat(...Te([[2,8],[2,9],[2,10],[2,11],[4,12],[4,13],[4,14],[4,15],[8,16],[8,17],[8,18],[8,19],[16,20],[16,21],[16,22],[16,23],[32,24],[32,25],[32,26],[31,27],[1,28]])),He.ke=[0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224,0],He.ve=[0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576],He.Se=e=>256>e?je[e]:je[256+(e>>>7)],He.ze=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],He.Ce=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],He.xe=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],He.Ae=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];const Fe=Te([[144,8],[112,9],[24,7],[8,8]]);Le._e=We([12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,19,275,147,403,83,339,211,467,51,307,179,435,115,371,243,499,11,267,139,395,75,331,203,459,43,299,171,427,107,363,235,491,27,283,155,411,91,347,219,475,59,315,187,443,123,379,251,507,7,263,135,391,71,327,199,455,39,295,167,423,103,359,231,487,23,279,151,407,87,343,215,471,55,311,183,439,119,375,247,503,15,271,143,399,79,335,207,463,47,303,175,431,111,367,239,495,31,287,159,415,95,351,223,479,63,319,191,447,127,383,255,511,0,64,32,96,16,80,48,112,8,72,40,104,24,88,56,120,4,68,36,100,20,84,52,116,3,131,67,195,35,163,99,227].map(((e,t)=>[e,Fe[t]])));const qe=Te([[30,5]]);function Ge(e,t,n,r,s){const i=this;i.Ie=e,i.Pe=t,i.De=n,i.Ve=r,i.Re=s}Le.Be=We([0,16,8,24,4,20,12,28,2,18,10,26,6,22,14,30,1,17,9,25,5,21,13,29,3,19,11,27,7,23].map(((e,t)=>[e,qe[t]]))),Le.Ee=new Le(Le._e,He.ze,257,286,15),Le.Me=new Le(Le.Be,He.Ce,0,30,15),Le.Ue=new Le(null,He.xe,0,19,7);const Je=[new Ge(0,0,0,0,0),new Ge(4,4,8,4,1),new Ge(4,5,16,8,1),new Ge(4,6,32,32,1),new Ge(4,4,16,16,2),new Ge(8,16,32,32,2),new Ge(8,16,128,128,2),new Ge(8,32,128,256,2),new Ge(32,128,258,1024,2),new Ge(32,258,258,4096,2)],Qe=["need dictionary","stream end","","","stream error","data error","","buffer error","",""],Xe=113,Ye=666,Ze=262;function $e(e,t,n,r){const s=e[2*t],i=e[2*n];return i>s||s==i&&r[t]<=r[n]}function et(){const e=this;let t,n,s,c,f,a,l,u,w,h,d,p,y,m,b,g,k,v,S,z,C,x,A,_,I,P,D,V,R,B,E,M,U;const K=new He,N=new He,O=new He;let T,W,j,H,L,F;function q(){let t;for(t=0;286>t;t++)E[2*t]=0;for(t=0;30>t;t++)M[2*t]=0;for(t=0;19>t;t++)U[2*t]=0;E[512]=1,e.ue=e.we=0,W=j=0}function G(e,t){let n,r=-1,s=e[1],i=0,o=7,c=4;0===s&&(o=138,c=3),e[2*(t+1)+1]=65535;for(let f=0;t>=f;f++)n=s,s=e[2*(f+1)+1],++ii?U[2*n]+=i:0!==n?(n!=r&&U[2*n]++,U[32]++):i>10?U[36]++:U[34]++,i=0,r=n,0===s?(o=138,c=3):n==s?(o=6,c=3):(o=7,c=4))}function J(t){e.Ke[e.pending++]=t}function Q(e){J(255&e),J(e>>>8&255)}function X(e,t){let n;const r=t;F>16-r?(n=e,L|=n<>>16-F,F+=r-16):(L|=e<=n;n++)if(r=i,i=e[2*(n+1)+1],++o>=c||r!=i){if(f>o)do{Y(r,U)}while(0!=--o);else 0!==r?(r!=s&&(Y(r,U),o--),Y(16,U),X(o-3,2)):o>10?(Y(18,U),X(o-11,7)):(Y(17,U),X(o-3,3));o=0,s=r,0===i?(c=138,f=3):r==i?(c=6,f=3):(c=7,f=4)}}function $(){16==F?(Q(L),L=0,F=0):8>F||(J(255&L),L>>>=8,F-=8)}function ee(t,n){let s,i,o;if(e.Ne[W]=t,e.Oe[W]=255&n,W++,0===t?E[2*n]++:(j++,t--,E[2*(He.ge[n]+256+1)]++,M[2*He.Se(t)]++),!(8191&W)&&D>2){for(s=8*W,i=C-k,o=0;30>o;o++)s+=M[2*o]*(5+He.Ce[o]);if(s>>>=3,jc);Y(256,t),H=t[513]}function ne(){F>8?Q(L):F>0&&J(255&L),L=0,F=0}function re(t,n,r){X(0+(r?1:0),3),((t,n)=>{ne(),H=8,Q(n),Q(~n),e.Ke.set(u.subarray(t,t+n),e.pending),e.pending+=n})(t,n)}function se(n){((t,n,r)=>{let s,i,o=0;D>0?(K.ne(e),N.ne(e),o=(()=>{let t;for(G(E,K.he),G(M,N.he),O.ne(e),t=18;t>=3&&0===U[2*He.Ae[t]+1];t--);return e.ue+=14+3*(t+1),t})(),s=e.ue+3+7>>>3,i=e.we+3+7>>>3,i>s||(s=i)):s=i=n+5,n+4>s||-1==t?i==s?(X(2+(r?1:0),3),te(Le._e,Le.Be)):(X(4+(r?1:0),3),((e,t,n)=>{let r;for(X(e-257,5),X(t-1,5),X(n-4,4),r=0;n>r;r++)X(U[2*He.Ae[r]+1],3);Z(E,e-1),Z(M,t-1)})(K.he+1,N.he+1,o+1),te(E,M)):re(t,n,r),q(),r&&ne()})(0>k?-1:k,C-k,n),k=C,t.Te()}function ie(){let e,n,r,s;do{if(s=w-A-C,0===s&&0===C&&0===A)s=f;else if(-1==s)s--;else if(C>=f+f-Ze){u.set(u.subarray(f,f+f),0),x-=f,C-=f,k-=f,e=y,r=e;do{n=65535&d[--r],d[r]=f>n?0:n-f}while(0!=--e);e=f,r=e;do{n=65535&h[--r],h[r]=f>n?0:n-f}while(0!=--e);s+=f}if(0===t.We)return;e=t.je(u,C+A,s),A+=e,3>A||(p=255&u[C],p=(p<A&&0!==t.We)}function oe(e){let t,n,r=I,s=C,i=_;const o=C>f-Ze?C-(f-Ze):0;let c=B;const a=l,w=C+258;let d=u[s+i-1],p=u[s+i];R>_||(r>>=2),c>A&&(c=A);do{if(t=e,u[t+i]==p&&u[t+i-1]==d&&u[t]==u[s]&&u[++t]==u[s+1]){s+=2,t++;do{}while(u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&u[++s]==u[++t]&&w>s);if(n=258-(w-s),s=w-258,n>i){if(x=e,i=n,n>=c)break;d=u[s+i-1],p=u[s+i]}}}while((e=65535&h[e&a])>o&&0!=--r);return i>A?A:i}e.le=[],e.be=[],e.ae=[],E=[],M=[],U=[],e.de=(t,n)=>{const r=e.ae,s=r[n];let i=n<<1;for(;i<=e.ce&&(i(W||(W=8),j||(j=8),G||(G=0),t.Le=null,-1==S&&(S=6),1>j||j>9||8!=W||9>x||x>15||0>S||S>9||0>G||G>2?Oe:(t.Fe=e,a=x,f=1<(t.qe=t.Ge=0,t.Le=null,e.pending=0,e.Je=0,n=Xe,c=0,K.re=E,K.ie=Le.Ee,N.re=M,N.ie=Le.Me,O.re=U,O.ie=Le.Ue,L=0,F=0,H=8,q(),(()=>{w=2*f,d[y-1]=0;for(let e=0;y-1>e;e++)d[e]=0;P=Je[D].Pe,R=Je[D].Ie,B=Je[D].De,I=Je[D].Ve,C=0,k=0,A=0,v=_=2,z=0,p=0})(),0))(t))),e.Qe=()=>42!=n&&n!=Xe&&n!=Ye?Oe:(e.Oe=null,e.Ne=null,e.Ke=null,d=null,h=null,u=null,e.Fe=null,n==Xe?-3:0),e.Xe=(e,t,n)=>{let r=0;return-1==t&&(t=6),0>t||t>9||0>n||n>2?Oe:(Je[D].Re!=Je[t].Re&&0!==e.qe&&(r=e.Ye(1)),D!=t&&(D=t,P=Je[D].Pe,R=Je[D].Ie,B=Je[D].De,I=Je[D].Ve),V=n,r)},e.Ze=(e,t,r)=>{let s,i=r,o=0;if(!t||42!=n)return Oe;if(3>i)return 0;for(i>f-Ze&&(i=f-Ze,o=r-i),u.set(t.subarray(o,o+i),0),C=i,k=i,p=255&u[0],p=(p<=s;s++)p=(p<{let o,w,m,I,R;if(i>4||0>i)return Oe;if(!r.$e||!r.et&&0!==r.We||n==Ye&&4!=i)return r.Le=Qe[4],Oe;if(0===r.tt)return r.Le=Qe[7],-5;var B;if(t=r,I=c,c=i,42==n&&(w=8+(a-8<<4)<<8,m=(D-1&255)>>1,m>3&&(m=3),w|=m<<6,0!==C&&(w|=32),w+=31-w%31,n=Xe,J((B=w)>>8&255),J(255&B)),0!==e.pending){if(t.Te(),0===t.tt)return c=-1,0}else if(0===t.We&&I>=i&&4!=i)return t.Le=Qe[7],-5;if(n==Ye&&0!==t.We)return r.Le=Qe[7],-5;if(0!==t.We||0!==A||0!=i&&n!=Ye){switch(R=-1,Je[D].Re){case 0:R=(e=>{let n,r=65535;for(r>s-5&&(r=s-5);;){if(1>=A){if(ie(),0===A&&0==e)return 0;if(0===A)break}if(C+=A,A=0,n=k+r,(0===C||C>=n)&&(A=C-n,C=n,se(!1),0===t.tt))return 0;if(C-k>=f-Ze&&(se(!1),0===t.tt))return 0}return se(4==e),0===t.tt?4==e?2:0:4==e?3:1})(i);break;case 1:R=(e=>{let n,r=0;for(;;){if(Ze>A){if(ie(),Ze>A&&0==e)return 0;if(0===A)break}if(3>A||(p=(p<f-Ze||2!=V&&(v=oe(r)),3>v)n=ee(0,255&u[C]),A--,C++;else if(n=ee(C-x,v-3),A-=v,v>P||3>A)C+=v,v=0,p=255&u[C],p=(p<{let n,r,s=0;for(;;){if(Ze>A){if(ie(),Ze>A&&0==e)return 0;if(0===A)break}if(3>A||(p=(p<_&&f-Ze>=(C-s&65535)&&(2!=V&&(v=oe(s)),5>=v&&(1==V||3==v&&C-x>4096)&&(v=2)),3>_||v>_)if(0!==z){if(n=ee(0,255&u[C-1]),n&&se(!1),C++,A--,0===t.tt)return 0}else z=1,C++,A--;else{r=C+A-3,n=ee(C-1-S,_-3),A-=_-1,_-=2;do{++C>r||(p=(p<1+H+10-F&&(X(2,3),Y(256,Le._e),$()),H=7;else if(re(0,0,!1),3==i)for(o=0;y>o;o++)d[o]=0;if(t.Te(),0===t.tt)return c=-1,0}}return 4!=i?0:1}}function tt(){const e=this;e.nt=0,e.rt=0,e.We=0,e.qe=0,e.tt=0,e.Ge=0}function nt(e){const t=new tt,n=(o=e&&e.chunkSize?e.chunkSize:65536)+5*(r.floor(o/16383)+1);var o;const c=new i(n);let f=e?e.level:-1;void 0===f&&(f=-1),t.He(f),t.$e=c,this.append=(e,r)=>{let o,f,a=0,l=0,u=0;const w=[];if(e.length){t.nt=0,t.et=e,t.We=e.length;do{if(t.rt=0,t.tt=n,o=t.Ye(0),0!=o)throw new s("deflating: "+t.Le);t.rt&&(t.rt==n?w.push(new i(c)):w.push(c.subarray(0,t.rt))),u+=t.rt,r&&t.nt>0&&t.nt!=a&&(r(t.nt),a=t.nt)}while(t.We>0||0===t.tt);return w.length>1?(f=new i(u),w.forEach((e=>{f.set(e,l),l+=e.length}))):f=w[0]?new i(w[0]):new i,f}},this.flush=()=>{let e,r,o=0,f=0;const a=[];do{if(t.rt=0,t.tt=n,e=t.Ye(4),1!=e&&0!=e)throw new s("deflating: "+t.Le);n-t.tt>0&&a.push(c.slice(0,t.rt)),f+=t.rt}while(t.We>0||0===t.tt);return t.Qe(),r=new i(f),a.forEach((e=>{r.set(e,o),o+=e.length})),r}}tt.prototype={He(e,t){const n=this;return n.Fe=new et,t||(t=15),n.Fe.He(n,e,t)},Ye(e){const t=this;return t.Fe?t.Fe.Ye(t,e):Oe},Qe(){const e=this;if(!e.Fe)return Oe;const t=e.Fe.Qe();return e.Fe=null,t},Xe(e,t){const n=this;return n.Fe?n.Fe.Xe(n,e,t):Oe},Ze(e,t){const n=this;return n.Fe?n.Fe.Ze(n,e,t):Oe},je(e,t,n){const r=this;let s=r.We;return s>n&&(s=n),0===s?0:(r.We-=s,e.set(r.et.subarray(r.nt,r.nt+s),t),r.nt+=s,r.qe+=s,s)},Te(){const e=this;let t=e.Fe.pending;t>e.tt&&(t=e.tt),0!==t&&(e.$e.set(e.Fe.Ke.subarray(e.Fe.Je,e.Fe.Je+t),e.rt),e.rt+=t,e.Fe.Je+=t,e.Ge+=t,e.tt-=t,e.Fe.pending-=t,0===e.Fe.pending&&(e.Fe.Je=0))}};const rt=-2,st=-3,it=-5,ot=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],ct=[96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,192,80,7,10,0,8,96,0,8,32,0,9,160,0,8,0,0,8,128,0,8,64,0,9,224,80,7,6,0,8,88,0,8,24,0,9,144,83,7,59,0,8,120,0,8,56,0,9,208,81,7,17,0,8,104,0,8,40,0,9,176,0,8,8,0,8,136,0,8,72,0,9,240,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,200,81,7,13,0,8,100,0,8,36,0,9,168,0,8,4,0,8,132,0,8,68,0,9,232,80,7,8,0,8,92,0,8,28,0,9,152,84,7,83,0,8,124,0,8,60,0,9,216,82,7,23,0,8,108,0,8,44,0,9,184,0,8,12,0,8,140,0,8,76,0,9,248,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,196,81,7,11,0,8,98,0,8,34,0,9,164,0,8,2,0,8,130,0,8,66,0,9,228,80,7,7,0,8,90,0,8,26,0,9,148,84,7,67,0,8,122,0,8,58,0,9,212,82,7,19,0,8,106,0,8,42,0,9,180,0,8,10,0,8,138,0,8,74,0,9,244,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,204,81,7,15,0,8,102,0,8,38,0,9,172,0,8,6,0,8,134,0,8,70,0,9,236,80,7,9,0,8,94,0,8,30,0,9,156,84,7,99,0,8,126,0,8,62,0,9,220,82,7,27,0,8,110,0,8,46,0,9,188,0,8,14,0,8,142,0,8,78,0,9,252,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,194,80,7,10,0,8,97,0,8,33,0,9,162,0,8,1,0,8,129,0,8,65,0,9,226,80,7,6,0,8,89,0,8,25,0,9,146,83,7,59,0,8,121,0,8,57,0,9,210,81,7,17,0,8,105,0,8,41,0,9,178,0,8,9,0,8,137,0,8,73,0,9,242,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,202,81,7,13,0,8,101,0,8,37,0,9,170,0,8,5,0,8,133,0,8,69,0,9,234,80,7,8,0,8,93,0,8,29,0,9,154,84,7,83,0,8,125,0,8,61,0,9,218,82,7,23,0,8,109,0,8,45,0,9,186,0,8,13,0,8,141,0,8,77,0,9,250,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,198,81,7,11,0,8,99,0,8,35,0,9,166,0,8,3,0,8,131,0,8,67,0,9,230,80,7,7,0,8,91,0,8,27,0,9,150,84,7,67,0,8,123,0,8,59,0,9,214,82,7,19,0,8,107,0,8,43,0,9,182,0,8,11,0,8,139,0,8,75,0,9,246,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,206,81,7,15,0,8,103,0,8,39,0,9,174,0,8,7,0,8,135,0,8,71,0,9,238,80,7,9,0,8,95,0,8,31,0,9,158,84,7,99,0,8,127,0,8,63,0,9,222,82,7,27,0,8,111,0,8,47,0,9,190,0,8,15,0,8,143,0,8,79,0,9,254,96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,193,80,7,10,0,8,96,0,8,32,0,9,161,0,8,0,0,8,128,0,8,64,0,9,225,80,7,6,0,8,88,0,8,24,0,9,145,83,7,59,0,8,120,0,8,56,0,9,209,81,7,17,0,8,104,0,8,40,0,9,177,0,8,8,0,8,136,0,8,72,0,9,241,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,201,81,7,13,0,8,100,0,8,36,0,9,169,0,8,4,0,8,132,0,8,68,0,9,233,80,7,8,0,8,92,0,8,28,0,9,153,84,7,83,0,8,124,0,8,60,0,9,217,82,7,23,0,8,108,0,8,44,0,9,185,0,8,12,0,8,140,0,8,76,0,9,249,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,197,81,7,11,0,8,98,0,8,34,0,9,165,0,8,2,0,8,130,0,8,66,0,9,229,80,7,7,0,8,90,0,8,26,0,9,149,84,7,67,0,8,122,0,8,58,0,9,213,82,7,19,0,8,106,0,8,42,0,9,181,0,8,10,0,8,138,0,8,74,0,9,245,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,205,81,7,15,0,8,102,0,8,38,0,9,173,0,8,6,0,8,134,0,8,70,0,9,237,80,7,9,0,8,94,0,8,30,0,9,157,84,7,99,0,8,126,0,8,62,0,9,221,82,7,27,0,8,110,0,8,46,0,9,189,0,8,14,0,8,142,0,8,78,0,9,253,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,195,80,7,10,0,8,97,0,8,33,0,9,163,0,8,1,0,8,129,0,8,65,0,9,227,80,7,6,0,8,89,0,8,25,0,9,147,83,7,59,0,8,121,0,8,57,0,9,211,81,7,17,0,8,105,0,8,41,0,9,179,0,8,9,0,8,137,0,8,73,0,9,243,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,203,81,7,13,0,8,101,0,8,37,0,9,171,0,8,5,0,8,133,0,8,69,0,9,235,80,7,8,0,8,93,0,8,29,0,9,155,84,7,83,0,8,125,0,8,61,0,9,219,82,7,23,0,8,109,0,8,45,0,9,187,0,8,13,0,8,141,0,8,77,0,9,251,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,199,81,7,11,0,8,99,0,8,35,0,9,167,0,8,3,0,8,131,0,8,67,0,9,231,80,7,7,0,8,91,0,8,27,0,9,151,84,7,67,0,8,123,0,8,59,0,9,215,82,7,19,0,8,107,0,8,43,0,9,183,0,8,11,0,8,139,0,8,75,0,9,247,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,207,81,7,15,0,8,103,0,8,39,0,9,175,0,8,7,0,8,135,0,8,71,0,9,239,80,7,9,0,8,95,0,8,31,0,9,159,84,7,99,0,8,127,0,8,63,0,9,223,82,7,27,0,8,111,0,8,47,0,9,191,0,8,15,0,8,143,0,8,79,0,9,255],ft=[80,5,1,87,5,257,83,5,17,91,5,4097,81,5,5,89,5,1025,85,5,65,93,5,16385,80,5,3,88,5,513,84,5,33,92,5,8193,82,5,9,90,5,2049,86,5,129,192,5,24577,80,5,2,87,5,385,83,5,25,91,5,6145,81,5,7,89,5,1537,85,5,97,93,5,24577,80,5,4,88,5,769,84,5,49,92,5,12289,82,5,13,90,5,3073,86,5,193,192,5,24577],at=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],lt=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,112,112],ut=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],wt=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];function ht(){let e,t,n,r,s,i;function o(e,t,o,c,f,a,l,u,w,h,d){let p,y,m,b,g,k,v,S,z,C,x,A,_,I,P;C=0,g=o;do{n[e[t+C]]++,C++,g--}while(0!==g);if(n[0]==o)return l[0]=-1,u[0]=0,0;for(S=u[0],k=1;15>=k&&0===n[k];k++);for(v=k,k>S&&(S=k),g=15;0!==g&&0===n[g];g--);for(m=g,S>g&&(S=g),u[0]=S,I=1<k;k++,I<<=1)if(0>(I-=n[k]))return st;if(0>(I-=n[g]))return st;for(n[g]+=I,i[1]=k=0,C=1,_=2;0!=--g;)i[_]=k+=n[C],_++,C++;g=0,C=0;do{0!==(k=e[t+C])&&(d[i[k]++]=g),C++}while(++g=v;v++)for(p=n[v];0!=p--;){for(;v>A+S;){if(b++,A+=S,P=m-A,P=P>S?S:P,(y=1<<(k=v-A))>p+1&&(y-=p+1,_=v,P>k))for(;++kn[++_];)y-=n[_];if(P=1<1440)return st;s[b]=x=h[0],h[0]+=P,0!==b?(i[b]=g,r[0]=k,r[1]=S,k=g>>>A-S,r[2]=x-s[b-1]-k,w.set(r,3*(s[b-1]+k))):l[0]=x}for(r[1]=v-A,o>C?d[C]d[C]?0:96,r[2]=d[C++]):(r[0]=a[d[C]-c]+16+64,r[2]=f[d[C++]-c]):r[0]=192,y=1<>>A;P>k;k+=y)w.set(r,3*(x+k));for(k=1<>>=1)g^=k;for(g^=k,z=(1<c;c++)t[c]=0;for(c=0;16>c;c++)n[c]=0;for(c=0;3>c;c++)r[c]=0;s.set(n.subarray(0,15),0),i.set(n.subarray(0,16),0)}this.st=(n,r,s,i,f)=>{let a;return c(19),e[0]=0,a=o(n,0,19,19,null,null,s,r,i,e,t),a==st?f.Le="oversubscribed dynamic bit lengths tree":a!=it&&0!==r[0]||(f.Le="incomplete dynamic bit lengths tree",a=st),a},this.it=(n,r,s,i,f,a,l,u,w)=>{let h;return c(288),e[0]=0,h=o(s,0,n,257,at,lt,a,i,u,e,t),0!=h||0===i[0]?(h==st?w.Le="oversubscribed literal/length tree":-4!=h&&(w.Le="incomplete literal/length tree",h=st),h):(c(288),h=o(s,n,r,0,ut,wt,l,f,u,e,t),0!=h||0===f[0]&&n>257?(h==st?w.Le="oversubscribed distance tree":h==it?(w.Le="incomplete distance tree",h=st):-4!=h&&(w.Le="empty distance tree with lengths",h=st),h):0)}}function dt(){const e=this;let t,n,r,s,i=0,o=0,c=0,f=0,a=0,l=0,u=0,w=0,h=0,d=0;function p(e,t,n,r,s,i,o,c){let f,a,l,u,w,h,d,p,y,m,b,g,k,v,S,z;d=c.nt,p=c.We,w=o.ot,h=o.ct,y=o.write,m=yh;)p--,w|=(255&c.ft(d++))<>=a[z+1],h-=a[z+1],16&u){for(u&=15,k=a[z+2]+(w&ot[u]),w>>=u,h-=u;15>h;)p--,w|=(255&c.ft(d++))<>=a[z+1],h-=a[z+1],16&u){for(u&=15;u>h;)p--,w|=(255&c.ft(d++))<>=u,h-=u,m-=k,v>y){S=y-v;do{S+=o.end}while(0>S);if(u=o.end-S,k>u){if(k-=u,y-S>0&&u>y-S)do{o.lt[y++]=o.lt[S++]}while(0!=--u);else o.lt.set(o.lt.subarray(S,S+u),y),y+=u,S+=u,u=0;S=0}}else S=y-v,y-S>0&&2>y-S?(o.lt[y++]=o.lt[S++],o.lt[y++]=o.lt[S++],k-=2):(o.lt.set(o.lt.subarray(S,S+2),y),y+=2,S+=2,k-=2);if(y-S>0&&k>y-S)do{o.lt[y++]=o.lt[S++]}while(0!=--k);else o.lt.set(o.lt.subarray(S,S+k),y),y+=k,S+=k,k=0;break}if(64&u)return c.Le="invalid distance code",k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,st;f+=a[z+2],f+=w&ot[u],z=3*(l+f),u=a[z]}break}if(64&u)return 32&u?(k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,1):(c.Le="invalid literal/length code",k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,st);if(f+=a[z+2],f+=w&ot[u],z=3*(l+f),0===(u=a[z])){w>>=a[z+1],h-=a[z+1],o.lt[y++]=a[z+2],m--;break}}else w>>=a[z+1],h-=a[z+1],o.lt[y++]=a[z+2],m--}while(m>=258&&p>=10);return k=c.We-p,k=k>h>>3?h>>3:k,p+=k,d-=k,h-=k<<3,o.ot=w,o.ct=h,c.We=p,c.qe+=d-c.nt,c.nt=d,o.write=y,0}e.init=(e,i,o,c,f,a)=>{t=0,u=e,w=i,r=o,h=c,s=f,d=a,n=null},e.ut=(e,y,m)=>{let b,g,k,v,S,z,C,x=0,A=0,_=0;for(_=y.nt,v=y.We,x=e.ot,A=e.ct,S=e.write,z=S=258&&v>=10&&(e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,m=p(u,w,r,h,s,d,e,y),_=y.nt,v=y.We,x=e.ot,A=e.ct,S=e.write,z=SA;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<>>=n[g+1],A-=n[g+1],k=n[g],0===k){f=n[g+2],t=6;break}if(16&k){a=15&k,i=n[g+2],t=2;break}if(!(64&k)){c=k,o=g/3+n[g+2];break}if(32&k){t=7;break}return t=9,y.Le="invalid literal/length code",m=st,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);case 2:for(b=a;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<>=b,A-=b,c=w,n=s,o=d,t=3;case 3:for(b=c;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<>=n[g+1],A-=n[g+1],k=n[g],16&k){a=15&k,l=n[g+2],t=4;break}if(!(64&k)){c=k,o=g/3+n[g+2];break}return t=9,y.Le="invalid distance code",m=st,e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);case 4:for(b=a;b>A;){if(0===v)return e.ot=x,e.ct=A,y.We=v,y.qe+=_-y.nt,y.nt=_,e.write=S,e.wt(y,m);m=0,v--,x|=(255&y.ft(_++))<>=b,A-=b,t=5;case 5:for(C=S-l;0>C;)C+=e.end;for(;0!==i;){if(0===z&&(S==e.end&&0!==e.read&&(S=0,z=S7&&(A-=8,v++,_--),e.write=S,m=e.wt(y,m),S=e.write,z=S{}}ht.dt=(e,t,n,r)=>(e[0]=9,t[0]=5,n[0]=ct,r[0]=ft,0);const pt=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];function yt(e,t){const n=this;let r,s=0,o=0,c=0,a=0;const l=[0],u=[0],w=new dt;let h=0,d=new f(4320);const p=new ht;n.ct=0,n.ot=0,n.lt=new i(t),n.end=t,n.read=0,n.write=0,n.reset=(e,t)=>{t&&(t[0]=0),6==s&&w.ht(e),s=0,n.ct=0,n.ot=0,n.read=n.write=0},n.reset(e,null),n.wt=(e,t)=>{let r,s,i;return s=e.rt,i=n.read,r=(i>n.write?n.end:n.write)-i,r>e.tt&&(r=e.tt),0!==r&&t==it&&(t=0),e.tt-=r,e.Ge+=r,e.$e.set(n.lt.subarray(i,i+r),s),s+=r,i+=r,i==n.end&&(i=0,n.write==n.end&&(n.write=0),r=n.write-i,r>e.tt&&(r=e.tt),0!==r&&t==it&&(t=0),e.tt-=r,e.Ge+=r,e.$e.set(n.lt.subarray(i,i+r),s),s+=r,i+=r),e.rt=s,n.read=i,t},n.ut=(e,t)=>{let i,f,y,m,b,g,k,v;for(m=e.nt,b=e.We,f=n.ot,y=n.ct,g=n.write,k=gy;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<>>1){case 0:f>>>=3,y-=3,i=7&y,f>>>=i,y-=i,s=1;break;case 1:S=[],z=[],C=[[]],x=[[]],ht.dt(S,z,C,x),w.init(S[0],z[0],C[0],0,x[0],0),f>>>=3,y-=3,s=6;break;case 2:f>>>=3,y-=3,s=3;break;case 3:return f>>>=3,y-=3,s=9,e.Le="invalid block type",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t)}break;case 1:for(;32>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<>>16&65535)!=(65535&f))return s=9,e.Le="invalid stored block lengths",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);o=65535&f,f=y=0,s=0!==o?2:0!==h?7:0;break;case 2:if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);if(0===k&&(g==n.end&&0!==n.read&&(g=0,k=gb&&(i=b),i>k&&(i=k),n.lt.set(e.je(m,i),g),m+=i,b-=i,g+=i,k-=i,0!=(o-=i))break;s=0!==h?7:0;break;case 3:for(;14>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<29||(i>>5&31)>29)return s=9,e.Le="too many length or distance symbols",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);if(i=258+(31&i)+(i>>5&31),!r||r.lengthv;v++)r[v]=0;f>>>=14,y-=14,a=0,s=4;case 4:for(;4+(c>>>10)>a;){for(;3>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<>>=3,y-=3}for(;19>a;)r[pt[a++]]=0;if(l[0]=7,i=p.st(r,l,u,d,e),0!=i)return(t=i)==st&&(r=null,s=9),n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);a=0,s=5;case 5:for(;i=c,258+(31&i)+(i>>5&31)>a;){let o,w;for(i=l[0];i>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<w)f>>>=i,y-=i,r[a++]=w;else{for(v=18==w?7:w-14,o=18==w?11:3;i+v>y;){if(0===b)return n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);t=0,b--,f|=(255&e.ft(m++))<>>=i,y-=i,o+=f&ot[v],f>>>=v,y-=v,v=a,i=c,v+o>258+(31&i)+(i>>5&31)||16==w&&1>v)return r=null,s=9,e.Le="invalid bit length repeat",t=st,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);w=16==w?r[v-1]:0;do{r[v++]=w}while(0!=--o);a=v}}if(u[0]=-1,A=[],_=[],I=[],P=[],A[0]=9,_[0]=6,i=c,i=p.it(257+(31&i),1+(i>>5&31),r,A,_,I,P,d,e),0!=i)return i==st&&(r=null,s=9),t=i,n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,n.wt(e,t);w.init(A[0],_[0],d,I[0],d,P[0]),s=6;case 6:if(n.ot=f,n.ct=y,e.We=b,e.qe+=m-e.nt,e.nt=m,n.write=g,1!=(t=w.ut(n,e,t)))return n.wt(e,t);if(t=0,w.ht(e),m=e.nt,b=e.We,f=n.ot,y=n.ct,g=n.write,k=g{n.reset(e,null),n.lt=null,d=null},n.yt=(e,t,r)=>{n.lt.set(e.subarray(t,t+r),0),n.read=n.write=r},n.bt=()=>1==s?1:0}const mt=13,bt=[0,0,255,255];function gt(){const e=this;function t(e){return e&&e.gt?(e.qe=e.Ge=0,e.Le=null,e.gt.mode=7,e.gt.kt.reset(e,null),0):rt}e.mode=0,e.method=0,e.vt=[0],e.St=0,e.marker=0,e.zt=0,e.Ct=t=>(e.kt&&e.kt.ht(t),e.kt=null,0),e.xt=(n,r)=>(n.Le=null,e.kt=null,8>r||r>15?(e.Ct(n),rt):(e.zt=r,n.gt.kt=new yt(n,1<{let n,r;if(!e||!e.gt||!e.et)return rt;const s=e.gt;for(t=4==t?it:0,n=it;;)switch(s.mode){case 0:if(0===e.We)return n;if(n=t,e.We--,e.qe++,8!=(15&(s.method=e.ft(e.nt++)))){s.mode=mt,e.Le="unknown compression method",s.marker=5;break}if(8+(s.method>>4)>s.zt){s.mode=mt,e.Le="invalid win size",s.marker=5;break}s.mode=1;case 1:if(0===e.We)return n;if(n=t,e.We--,e.qe++,r=255&e.ft(e.nt++),((s.method<<8)+r)%31!=0){s.mode=mt,e.Le="incorrect header check",s.marker=5;break}if(!(32&r)){s.mode=7;break}s.mode=2;case 2:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St=(255&e.ft(e.nt++))<<24&4278190080,s.mode=3;case 3:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St+=(255&e.ft(e.nt++))<<16&16711680,s.mode=4;case 4:if(0===e.We)return n;n=t,e.We--,e.qe++,s.St+=(255&e.ft(e.nt++))<<8&65280,s.mode=5;case 5:return 0===e.We?n:(n=t,e.We--,e.qe++,s.St+=255&e.ft(e.nt++),s.mode=6,2);case 6:return s.mode=mt,e.Le="need dictionary",s.marker=0,rt;case 7:if(n=s.kt.ut(e,n),n==st){s.mode=mt,s.marker=0;break}if(0==n&&(n=t),1!=n)return n;n=t,s.kt.reset(e,s.vt),s.mode=12;case 12:return e.We=0,1;case mt:return st;default:return rt}},e._t=(e,t,n)=>{let r=0,s=n;if(!e||!e.gt||6!=e.gt.mode)return rt;const i=e.gt;return s<1<{let n,r,s,i,o;if(!e||!e.gt)return rt;const c=e.gt;if(c.mode!=mt&&(c.mode=mt,c.marker=0),0===(n=e.We))return it;for(r=e.nt,s=c.marker;0!==n&&4>s;)e.ft(r)==bt[s]?s++:s=0!==e.ft(r)?0:4-s,r++,n--;return e.qe+=r-e.nt,e.nt=r,e.We=n,c.marker=s,4!=s?st:(i=e.qe,o=e.Ge,t(e),e.qe=i,e.Ge=o,c.mode=7,0)},e.Pt=e=>e&&e.gt&&e.gt.kt?e.gt.kt.bt():rt}function kt(){}function vt(e){const t=new kt,n=e&&e.chunkSize?r.floor(2*e.chunkSize):131072,o=new i(n);let c=!1;t.xt(),t.$e=o,this.append=(e,r)=>{const f=[];let a,l,u=0,w=0,h=0;if(0!==e.length){t.nt=0,t.et=e,t.We=e.length;do{if(t.rt=0,t.tt=n,0!==t.We||c||(t.nt=0,c=!0),a=t.At(0),c&&a===it){if(0!==t.We)throw new s("inflating: bad input")}else if(0!==a&&1!==a)throw new s("inflating: "+t.Le);if((c||1===a)&&t.We===e.length)throw new s("inflating: bad input");t.rt&&(t.rt===n?f.push(new i(o)):f.push(o.subarray(0,t.rt))),h+=t.rt,r&&t.nt>0&&t.nt!=u&&(r(t.nt),u=t.nt)}while(t.We>0||0===t.tt);return f.length>1?(l=new i(h),f.forEach((e=>{l.set(e,w),w+=e.length}))):l=f[0]?new i(f[0]):new i,l}},this.flush=()=>{t.Ct()}}kt.prototype={xt(e){const t=this;return t.gt=new gt,e||(e=15),t.gt.xt(t,e)},At(e){const t=this;return t.gt?t.gt.At(t,e):rt},Ct(){const e=this;if(!e.gt)return rt;const t=e.gt.Ct(e);return e.gt=null,t},It(){const e=this;return e.gt?e.gt.It(e):rt},_t(e,t){const n=this;return n.gt?n.gt._t(n,e,t):rt},ft(e){return this.et[e]},je(e,t){return this.et.subarray(e,e+t)}},self.initCodec=()=>{self.Deflate=nt,self.Inflate=vt};\n',r=()=>t.useDataURI?"data:text/javascript,"+encodeURIComponent(n):f.createObjectURL(new m([n],{type:"text/javascript"}));e({workerScripts:{inflate:[r],deflate:[r]}})})(ne),e.BlobReader=Ot,e.BlobWriter=Pt,e.Data64URIReader=class extends Nt{constructor(e){super();let t=e.length;for(;"="==e.charAt(t-1);)t--;const r=e.indexOf(",")+1;n.assign(this,{dataURI:e,dataStart:r,size:a.floor(.75*(t-r))})}readUint8Array(e,t){const{dataStart:n,dataURI:r}=this,s=new w(t),i=4*a.floor(e/3),o=atob(r.substring(i+n,4*a.ceil((e+t)/3)+n)),c=e-3*a.floor(i/4);for(let e=c;c+t>e;e++)s[e-c]=o.charCodeAt(e);return s}},e.Data64URIWriter=class extends qt{constructor(e){super(),n.assign(this,{data:"data:"+(e||"")+";base64,",pending:[]})}writeUint8Array(e){const t=this;let n=0,s=t.pending;const i=t.pending.length;for(t.pending="",n=0;n<3*a.floor((i+e.length)/3)-i;n++)s+=r.fromCharCode(e[n]);for(;n2?t.data+=v(s):t.pending=s}getData(){return this.data+v(this.pending)}},e.ERR_BAD_FORMAT=Ln,e.ERR_CENTRAL_DIRECTORY_NOT_FOUND=Nn,e.ERR_DUPLICATED_NAME=or,e.ERR_ENCRYPTED=Pn,e.ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND=In,e.ERR_EOCDR_NOT_FOUND=Un,e.ERR_EXTRAFIELD_ZIP64_NOT_FOUND=On,e.ERR_HTTP_RANGE=Wt,e.ERR_INVALID_COMMENT=cr,e.ERR_INVALID_ENCRYPTION_STRENGTH=dr,e.ERR_INVALID_ENTRY_COMMENT=lr,e.ERR_INVALID_ENTRY_NAME=ur,e.ERR_INVALID_EXTRAFIELD_DATA=pr,e.ERR_INVALID_EXTRAFIELD_TYPE=wr,e.ERR_INVALID_PASSWORD=he,e.ERR_INVALID_SIGNATURE=ge,e.ERR_INVALID_VERSION=fr,e.ERR_ITERATOR_COMPLETED_TOO_SOON=Rt,e.ERR_LOCAL_FILE_HEADER_NOT_FOUND=qn,e.ERR_SPLIT_ZIP_FILE=Bn,e.ERR_UNDEFINED_UNCOMPRESSED_SIZE=gr,e.ERR_UNSUPPORTED_COMPRESSION=Mn,e.ERR_UNSUPPORTED_ENCRYPTION=Hn,e.ERR_UNSUPPORTED_FORMAT=hr,e.HttpRangeReader=class extends en{constructor(e,t={}){t.useRangeHeader=!0,super(e,t)}},e.HttpReader=en,e.Reader=Nt,e.SplitDataReader=tn,e.SplitDataWriter=nn,e.SplitZipReader=cn,e.SplitZipWriter=ln,e.TextReader=class extends Ot{constructor(e){super(new m([e],{type:"text/plain"}))}},e.TextWriter=class extends Pt{constructor(e){super(e),n.assign(this,{encoding:e,utf8:!e||"utf-8"==e.toLowerCase()})}async getData(){const{encoding:e,utf8:t}=this,r=await super.getData();if(r.text&&t)return r.text();{const t=new FileReader;return new y(((s,i)=>{n.assign(t,{onload:({target:e})=>s(e.result),onerror:()=>i(t.error)}),t.readAsText(r,e)}))}}},e.Uint8ArrayReader=class extends Nt{constructor(e){super(),n.assign(this,{array:e,size:e.length})}readUint8Array(e,t){return this.array.slice(e,e+t)}},e.Uint8ArrayWriter=class extends qt{init(e=0){n.assign(this,{offset:0,array:new w(e)}),super.init()}writeUint8Array(e){const t=this;if(t.offset+e.length>t.array.length){const n=t.array;t.array=new w(n.length+e.length),t.array.set(n)}t.array.set(e,t.offset),t.offset+=e.length}getData(){return this.array}},e.Writer=qt,e.ZipReader=Xn,e.ZipReaderStream=class{constructor(e={}){const{readable:t,writable:n}=new x,r=new Xn(t,e).getEntriesGenerator();this.readable=new A({async pull(e){const{done:t,value:n}=await r.next();if(t)return e.close();const s={...n,readable:(()=>{const{readable:e,writable:t}=new x;if(n.getData)return n.getData(t),e})()};delete s.getData,e.enqueue(s)}}),this.writable=n}},e.ZipWriter=Sr,e.ZipWriterStream=class{constructor(e={}){const{readable:t,writable:n}=new x;this.readable=t,this.zipWriter=new Sr(n,e)}transform(e){const{readable:t,writable:n}=new x({flush:()=>{this.zipWriter.close()}});return this.zipWriter.add(e,t),{readable:this.readable,writable:n}}writable(e){const{readable:t,writable:n}=new x;return this.zipWriter.add(e,t),n}close(e,t={}){return this.zipWriter.close(e,t)}},e.configure=ne,e.getMimeType=()=>"application/octet-stream",e.initReader=sn,e.initShimAsyncCodec=(e,t={},n)=>({Deflate:se(e.Deflate,t.deflate,n),Inflate:se(e.Inflate,t.inflate,n)}),e.initStream=rn,e.initWriter=an,e.readUint8Array=on,e.terminateWorkers=async()=>{await y.allSettled(vt.map((e=>(_t(e),e.terminate()))))}})); From 355b277c111400d6d410b145ada13a82f9b51680 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Thu, 30 Jan 2025 21:41:07 -0500 Subject: [PATCH 173/574] common: Add a user_data pointer to audio_mixer_sound (#17488) --- libretro-common/audio/audio_mixer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index a274989be4..7d8afb25ab 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -122,6 +122,7 @@ struct audio_mixer_sound } mod; #endif } types; + void* user_data; }; struct audio_mixer_voice From 7ba205ba34751d3bb7ea3a9c32930d9d1dbc5172 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Fri, 31 Jan 2025 16:11:34 -0500 Subject: [PATCH 174/574] common: Move audio_mixer_sound user_data to above the types union --- libretro-common/audio/audio_mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index 7d8afb25ab..1d26c0fdd6 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -76,6 +76,7 @@ struct audio_mixer_sound { enum audio_mixer_type type; + void* user_data; union { @@ -122,7 +123,6 @@ struct audio_mixer_sound } mod; #endif } types; - void* user_data; }; struct audio_mixer_voice From 212ae55cfea761baf63843573aa0f21c91ebd54f Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Fri, 31 Jan 2025 22:57:46 -0500 Subject: [PATCH 175/574] glui: extremely minor refactor. (#17501) --- menu/drivers/materialui.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index aee58cb8f3..7c627fc521 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -2744,6 +2744,12 @@ static uint8_t materialui_count_lines(const char *str) return lines; } +static bool materialui_show_sublabel_for_entry(menu_entry_t *entry) +{ + settings_t *settings = config_get_ptr(); + return (settings->bools.menu_show_sublabels && !string_is_empty(entry->sublabel)); +} + /* > Returns number of lines required to display * the sublabel of entry 'entry_idx' */ static uint8_t materialui_count_sublabel_lines( @@ -2753,7 +2759,6 @@ static uint8_t materialui_count_sublabel_lines( menu_entry_t entry; char wrapped_sublabel_str[MENU_LABEL_MAX_LENGTH]; int sublabel_width_max = 0; - settings_t *settings = config_get_ptr(); wrapped_sublabel_str[0] = '\0'; @@ -2764,7 +2769,7 @@ static uint8_t materialui_count_sublabel_lines( menu_entry_get(&entry, 0, entry_idx, NULL, true); /* If sublabel is empty, return immediately */ - if (!settings->bools.menu_show_sublabels || string_is_empty(entry.sublabel)) + if (!materialui_show_sublabel_for_entry(&entry)) return 0; /* Wrap sublabel string to fit available width */ @@ -4192,7 +4197,7 @@ static void materialui_render_menu_entry_default( /* Draw entry sublabel * > Must be done before label + value, since it * affects y offset positions */ - if (settings->bools.menu_show_sublabels && !string_is_empty(entry->sublabel)) + if (materialui_show_sublabel_for_entry(entry)) { /* Note: Due to the way the selection highlight * marker is drawn (height is effectively 1px larger @@ -4552,7 +4557,7 @@ static void materialui_render_menu_entry_playlist_list( /* Draw entry sublabel * > Must be done before label, since it * affects y offset positions */ - if (settings->bools.menu_show_sublabels && !string_is_empty(entry->sublabel)) + if (materialui_show_sublabel_for_entry(entry)) { /* Note: Due to the way the selection highlight * marker is drawn (height is effectively 1px larger From 089a51f674283b96dbde78fa43e2d118798b2d9f Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Sat, 1 Feb 2025 19:22:18 -0500 Subject: [PATCH 176/574] apple: enable emulated mailbox (#17506) --- gfx/common/vulkan_common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 5e1a8d8d19..55c7dee14c 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -43,7 +43,7 @@ #define VENDOR_ID_NV 0x10DE #define VENDOR_ID_INTEL 0x8086 -#if defined(_WIN32) +#if defined(_WIN32) || defined(__APPLE__) #define VULKAN_EMULATE_MAILBOX #endif @@ -698,12 +698,16 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk) &vk->context.memory_properties); #ifdef VULKAN_EMULATE_MAILBOX +#if defined(_WIN32) /* Win32 windowed mode seems to deal just fine with toggling VSync. * Fullscreen however ... */ if (vk->flags & VK_DATA_FLAG_FULLSCREEN) vk->flags |= VK_DATA_FLAG_EMULATE_MAILBOX; else vk->flags &= ~VK_DATA_FLAG_EMULATE_MAILBOX; +#else + vk->flags |= VK_DATA_FLAG_EMULATE_MAILBOX; +#endif #endif /* If we're emulating mailbox, stick to using fences rather than semaphores. From 05f75b83c190530096935240ffb635d2c729860b Mon Sep 17 00:00:00 2001 From: neil4 Date: Sat, 1 Feb 2025 18:27:18 -0600 Subject: [PATCH 177/574] Overlays: Improve Analog Recentering (#17505) - Use closest point on zone perimeter if first touch is outside zone --- input/input_driver.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/input/input_driver.c b/input/input_driver.c index f568cd6f42..0316982215 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -2371,27 +2371,31 @@ static void input_overlay_get_analog_state( if (first_touch) { - unsigned recenter_zone = + unsigned recenter_zone = /* [0,100] */ config_get_ptr()->uints.input_overlay_analog_recenter_zone; - /* Reset analog center */ - x_center[b] = desc->x_shift; - y_center[b] = desc->y_shift; - if (recenter_zone != 0) { - /* Get analog state without adjusting center or saturation */ - x_val = (x - desc->x_shift) / desc->range_x; - y_val = (y - desc->y_shift) / desc->range_y; + float touch_dist, w; - /* Recenter if within zone */ - if ( (x_val * x_val + y_val * y_val) * 1e4 - < (recenter_zone * recenter_zone) - || recenter_zone >= 100) - { - x_center[b] = x; - y_center[b] = y; - } + x_val = (x - desc->x_shift) / desc->range_x; + y_val = (y - desc->y_shift) / desc->range_y; + touch_dist = sqrt((x_val * x_val + y_val * y_val) * 1e4); + + /* Inside zone, recenter to first touch. + * Outside zone, recenter to zone perimeter. */ + if (touch_dist <= recenter_zone || recenter_zone >= 100) + w = 0.0f; + else + w = (touch_dist - recenter_zone) / touch_dist; + + x_center[b] = x * (1.0f - w) + desc->x_shift * w; + y_center[b] = y * (1.0f - w) + desc->y_shift * w; + } + else + { + x_center[b] = desc->x_shift; + y_center[b] = desc->y_shift; } } From 9b3b75aa93d02b5664bc1e029d38d103517627ff Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 3 Feb 2025 00:14:45 +0000 Subject: [PATCH 178/574] Fetch translations from Crowdin --- intl/msg_hash_ca.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/intl/msg_hash_ca.h b/intl/msg_hash_ca.h index c534a9a78e..647e8500bc 100644 --- a/intl/msg_hash_ca.h +++ b/intl/msg_hash_ca.h @@ -4168,6 +4168,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_FRAME_TIME_COUNTER_SETTINGS, "Canvia les opcions del comptador de duració de fotogrames.\nNomés en funcionament quan estigui desactivat el vídeo multifil." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, + "Velocitat de càmera lenta" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, "Limita la velocitat de fotogrames al menú" @@ -4390,6 +4394,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_ASPECT_ADJUST_PORTRAIT, "Aplica un factor de correcció de la relació d’aspecte a la superposició quan la pantalla està orientada verticalment. Els valors positius augmenten l’alçada efectiva de la superposició mentre que els negatius la redueixen." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_SETTINGS, + "Superposició de teclat" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY_MOUSE_SETTINGS, "Superposa el ratolí" @@ -4408,6 +4416,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_PORT_ANY, "Qualsevol" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH, + "Pressionar el gatell en tocar" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_LIGHTGUN_TWO_TOUCH_INPUT, "Entrada de 2 dits" @@ -7000,6 +7012,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SEARCH, "Cerca" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RANDOM_SELECT, + "Selecció aleatòria" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, "Enrere" @@ -10342,8 +10358,32 @@ MSG_HASH( ) #ifdef HAVE_GAME_AI +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS, + "IA del joc" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P1, + "Anul·lar p1" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_OVERRIDE_P2, + "Anul·lar p2" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_GAME_AI_SHOW_DEBUG, + "Mostrar depuració" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_GAME_AI_SHOW_DEBUG, + "Mostrar depuració" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_QUICK_MENU_SHOW_GAME_AI, + "Mostrar IA del joc" + ) #endif \ No newline at end of file From 45586e83da5981bceefbcf0520e49208b4779311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Via=C4=8Das=C5=82a=C5=AD?= Date: Mon, 3 Feb 2025 06:30:02 +0300 Subject: [PATCH 179/574] (PipeWire) Pass the new_rate to the audio driver (#17508) Set the supported sample rate after initialization. Also a few minor fixes. --- audio/common/pipewire.c | 11 ++++----- audio/common/pipewire.h | 2 +- audio/drivers/pipewire.c | 33 ++++++++++++------------- audio/drivers_microphone/pipewire.c | 38 +++++++++++++---------------- 4 files changed, 39 insertions(+), 45 deletions(-) diff --git a/audio/common/pipewire.c b/audio/common/pipewire.c index 2f64656e62..e931254f52 100644 --- a/audio/common/pipewire.c +++ b/audio/common/pipewire.c @@ -203,20 +203,19 @@ void pipewire_core_deinit(pipewire_core_t *pw) pw_thread_loop_stop(pw->thread_loop); if (pw->registry) + { + spa_hook_remove(&pw->registry_listener); pw_proxy_destroy((struct pw_proxy*)pw->registry); + } if (pw->core) { spa_hook_remove(&pw->core_listener); - spa_zero(pw->core_listener); pw_core_disconnect(pw->core); } - if (pw->ctx) - pw_context_destroy(pw->ctx); - - if (pw->thread_loop) - pw_thread_loop_destroy(pw->thread_loop); + spa_clear_ptr(pw->ctx, pw_context_destroy); + spa_clear_ptr(pw->thread_loop, pw_thread_loop_destroy); if (pw->devicelist) string_list_free(pw->devicelist); diff --git a/audio/common/pipewire.h b/audio/common/pipewire.h index cb69c3c5a4..ee57ffb22f 100644 --- a/audio/common/pipewire.h +++ b/audio/common/pipewire.h @@ -33,7 +33,7 @@ #define PW_RARCH_MEDIA_TYPE_VIDEO "Video" #define PW_RARCH_MEDIA_TYPE_MIDI "Midi" #define PW_RARCH_MEDIA_CATEGORY_PLAYBACK "Playback" -#define PW_RARCH_MEDIA_CATEGORY_RECORD "Capture" +#define PW_RARCH_MEDIA_CATEGORY_RECORD "Capture" #define PW_RARCH_MEDIA_ROLE "Game" typedef struct pipewire_core diff --git a/audio/drivers/pipewire.c b/audio/drivers/pipewire.c index 00b51c77b2..e35548d736 100644 --- a/audio/drivers/pipewire.c +++ b/audio/drivers/pipewire.c @@ -61,6 +61,7 @@ static void playback_process_cb(void *data) uint32_t req, idx, n_bytes; int32_t avail; + retro_assert(audio); retro_assert(audio->stream); if ((b = pw_stream_dequeue_buffer(audio->stream)) == NULL) @@ -132,26 +133,22 @@ static void registry_event_global(void *data, uint32_t id, union string_list_elem_attr attr; const struct spa_dict_item *item; pipewire_core_t *pw = (pipewire_core_t*)data; - const char *media = NULL; const char *sink = NULL; - if (spa_streq(type, PW_TYPE_INTERFACE_Node)) + if (spa_streq(type, PW_TYPE_INTERFACE_Node) + && spa_streq("Audio/Sink", spa_dict_lookup(props, PW_KEY_MEDIA_CLASS))) { - media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); - if (media && spa_streq(media, "Audio/Sink")) + sink = spa_dict_lookup(props, PW_KEY_NODE_NAME); + if (sink && pw->devicelist) { - sink = spa_dict_lookup(props, PW_KEY_NODE_NAME); - if (sink && pw->devicelist) - { - attr.i = id; - string_list_append(pw->devicelist, sink, attr); - RARCH_LOG("[Audio] [PipeWire]: Found Sink Node: %s\n", sink); - } - - RARCH_DBG("[Audio] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version); - spa_dict_for_each(item, props) - RARCH_DBG("[Audio] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value); + attr.i = id; + string_list_append(pw->devicelist, sink, attr); + RARCH_LOG("[Audio] [PipeWire]: Found Sink Node: %s\n", sink); } + + RARCH_DBG("[Audio] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version); + spa_dict_for_each(item, props) + RARCH_DBG("[Audio] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value); } } @@ -225,15 +222,17 @@ static void *pipewire_init(const char *device, unsigned rate, PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS, params, 1); - if (res < 0) goto unlock_error; audio->highwater_mark = MIN(RINGBUFFER_SIZE, latency * (uint64_t)rate / 1000 * audio->frame_size); + pw_thread_loop_wait(audio->pw->thread_loop); pw_thread_loop_unlock(audio->pw->thread_loop); + *new_rate = audio->info.rate; + return audio; unlock_error: @@ -384,7 +383,7 @@ static void pipewire_free(void *data) pipewire_audio_t *audio = (pipewire_audio_t*)data; if (!audio) - return pw_deinit(); + return; if (audio->stream) { diff --git a/audio/drivers_microphone/pipewire.c b/audio/drivers_microphone/pipewire.c index 68b7bd7168..c6d2867905 100644 --- a/audio/drivers_microphone/pipewire.c +++ b/audio/drivers_microphone/pipewire.c @@ -72,7 +72,8 @@ static void capture_process_cb(void *data) uint32_t idx, offs, n_bytes; pipewire_microphone_t *mic = (pipewire_microphone_t*)data; - assert(mic->stream); + retro_assert(mic); + retro_assert(mic->stream); if (!(b = pw_stream_dequeue_buffer(mic->stream))) { @@ -120,28 +121,25 @@ static void registry_event_global(void *data, uint32_t id, union string_list_elem_attr attr; const struct spa_dict_item *item; pipewire_core_t *pw = (pipewire_core_t*)data; - const char *media = NULL; const char *sink = NULL; if (!pw) return; - if (spa_streq(type, PW_TYPE_INTERFACE_Node)) + if ( spa_streq(type, PW_TYPE_INTERFACE_Node) + && spa_streq("Audio/Source", spa_dict_lookup(props, PW_KEY_MEDIA_CLASS))) { - media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); - if (media && spa_streq(media, "Audio/Source")) + sink = spa_dict_lookup(props, PW_KEY_NODE_NAME); + if (sink && pw->devicelist) { - if ((sink = spa_dict_lookup(props, PW_KEY_NODE_NAME)) != NULL) - { - attr.i = id; - string_list_append(pw->devicelist, sink, attr); - RARCH_LOG("[Microphone] [PipeWire]: Found Source Node: %s\n", sink); - } - - RARCH_DBG("[Microphone] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version); - spa_dict_for_each(item, props) - RARCH_DBG("[Microphone] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value); + attr.i = id; + string_list_append(pw->devicelist, sink, attr); + RARCH_LOG("[Microphone] [PipeWire]: Found Source Node: %s\n", sink); } + + RARCH_DBG("[Microphone] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version); + spa_dict_for_each(item, props) + RARCH_DBG("[Microphone] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value); } } @@ -285,14 +283,12 @@ static void *pipewire_microphone_open_mic(void *driver_context, struct pw_properties *props = NULL; const char *error = NULL; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - pipewire_microphone_t *mic = calloc(1, sizeof(pipewire_microphone_t)); + pipewire_microphone_t *mic = NULL; - retro_assert(driver_context); - - if (!mic) + if (!driver_context || (mic = calloc(1, sizeof(pipewire_microphone_t))) == NULL) goto error; - mic->pw = (pipewire_core_t*)driver_context; + mic->pw = (pipewire_core_t*)driver_context; pw_thread_loop_lock(mic->pw->thread_loop); @@ -393,7 +389,7 @@ static bool pipewire_microphone_stop_mic(void *driver_context, void *mic_context return false; if (pw_stream_get_state(mic->stream, &error) == PW_STREAM_STATE_STREAMING) - res = pipewire_stream_set_active(pw->thread_loop, mic->stream, false); + res = pipewire_stream_set_active(pw->thread_loop, mic->stream, false); else /* For other states we assume that the stream is inactive */ res = true; From 65014a46b4e13cbd95f3d6ade5b6d3032a6b973f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Via=C4=8Das=C5=82a=C5=AD?= Date: Mon, 3 Feb 2025 06:30:13 +0300 Subject: [PATCH 180/574] Add PipeWire camera driver (#17507) --- Makefile.common | 3 +- camera/camera_driver.c | 3 + camera/camera_driver.h | 1 + camera/drivers/pipewire.c | 466 ++++++++++++++++++++++++++++++++++++++ griffin/griffin.c | 3 + 5 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 camera/drivers/pipewire.c diff --git a/Makefile.common b/Makefile.common index 2dcb7e08b4..7226db8f14 100644 --- a/Makefile.common +++ b/Makefile.common @@ -923,7 +923,8 @@ endif ifeq ($(HAVE_PIPEWIRE), 1) OBJ += audio/drivers/pipewire.o \ - audio/common/pipewire.o + audio/common/pipewire.o \ + camera/drivers/pipewire.o ifeq ($(HAVE_MICROPHONE), 1) OBJ += audio/drivers_microphone/pipewire.o diff --git a/camera/camera_driver.c b/camera/camera_driver.c index 01ed040d40..6925328ad2 100644 --- a/camera/camera_driver.c +++ b/camera/camera_driver.c @@ -49,6 +49,9 @@ const camera_driver_t *camera_drivers[] = { #ifdef HAVE_V4L2 &camera_v4l2, #endif +#ifdef HAVE_PIPEWIRE + &camera_pipewire, +#endif #ifdef EMSCRIPTEN &camera_rwebcam, #endif diff --git a/camera/camera_driver.h b/camera/camera_driver.h index 51ecb35d8f..eb45940461 100644 --- a/camera/camera_driver.h +++ b/camera/camera_driver.h @@ -62,6 +62,7 @@ extern const camera_driver_t *camera_drivers[]; extern camera_driver_t camera_v4l2; +extern camera_driver_t camera_pipewire; extern camera_driver_t camera_android; extern camera_driver_t camera_rwebcam; extern camera_driver_t camera_avfoundation; diff --git a/camera/drivers/pipewire.c b/camera/drivers/pipewire.c new file mode 100644 index 0000000000..32b348a88b --- /dev/null +++ b/camera/drivers/pipewire.c @@ -0,0 +1,466 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2025 - Viachaslau Khalikin + * + * 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 "../camera_driver.h" +#include "../../audio/common/pipewire.h" +#include "../../verbosity.h" + + +/* TODO/FIXME: detect size */ +#define WIDTH 640 +#define HEIGHT 480 + +#define MAX_BUFFERS 64 + +typedef struct pipewire_camera +{ + pipewire_core_t *pw; + + struct pw_stream *stream; + struct spa_hook stream_listener; + + struct scaler_ctx scaler; + uint32_t *buffer_output; + + struct spa_io_position *position; + struct spa_video_info format; + struct spa_rectangle size; +} pipewire_camera_t; + +static struct +{ + uint32_t format; + uint32_t id; +} scaler_video_formats[] = { + { SCALER_FMT_ARGB8888, SPA_VIDEO_FORMAT_ARGB }, + { SCALER_FMT_ABGR8888, SPA_VIDEO_FORMAT_ABGR }, + { SCALER_FMT_0RGB1555, SPA_VIDEO_FORMAT_UNKNOWN }, + { SCALER_FMT_RGB565, SPA_VIDEO_FORMAT_UNKNOWN }, + { SCALER_FMT_BGR24, SPA_VIDEO_FORMAT_BGR }, + { SCALER_FMT_YUYV, SPA_VIDEO_FORMAT_YUY2 }, + { SCALER_FMT_RGBA4444, SPA_VIDEO_FORMAT_UNKNOWN }, +}; + +#if 0 +{ + SPA_FOR_EACH_ELEMENT_VAR(scaler_video_formats, f) + { + if (f->format == format) + return f->id; + } + return SPA_VIDEO_FORMAT_UNKNOWN; +} +#endif + +static uint32_t id_to_scaler_format(uint32_t id) +{ + SPA_FOR_EACH_ELEMENT_VAR(scaler_video_formats, f) + { + if (f->id == id) + return f->format; + } + return SCALER_FMT_ARGB8888; +} + +static int build_format(struct spa_pod_builder *b, const struct spa_pod **params, + uint32_t width, uint32_t height) +{ + struct spa_pod_frame frame[2]; + + /* make an object of type SPA_TYPE_OBJECT_Format and id SPA_PARAM_EnumFormat. + * The object type is important because it defines the properties that are + * acceptable. The id gives more context about what the object is meant to + * contain. In this case we enumerate supported formats. */ + spa_pod_builder_push_object(b, &frame[0], SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); + /* add media type and media subtype properties */ + spa_pod_builder_prop(b, SPA_FORMAT_mediaType, 0); + spa_pod_builder_id(b, SPA_MEDIA_TYPE_video); + spa_pod_builder_prop(b, SPA_FORMAT_mediaSubtype, 0); + spa_pod_builder_id(b, SPA_MEDIA_SUBTYPE_raw); + + /* build an enumeration of formats */ + spa_pod_builder_prop(b, SPA_FORMAT_VIDEO_format, 0); + spa_pod_builder_push_choice(b, &frame[1], SPA_CHOICE_Enum, 0); + spa_pod_builder_id(b, SPA_VIDEO_FORMAT_YUY2); /* default */ + SPA_FOR_EACH_ELEMENT_VAR(scaler_video_formats, f) + { + uint32_t id = f->id; + if (id != SPA_VIDEO_FORMAT_UNKNOWN) + spa_pod_builder_id(b, id); /* alternative */ + } + + spa_pod_builder_pop(b, &frame[1]); + + /* add size and framerate ranges */ + spa_pod_builder_add(b, + SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle( + &SPA_RECTANGLE(MAX(width, 1), MAX(height, 1)), + &SPA_RECTANGLE(1, 1), + &SPA_RECTANGLE(MAX(width, WIDTH), MAX(height, HEIGHT))), + SPA_FORMAT_VIDEO_framerate, SPA_POD_CHOICE_RANGE_Fraction( + &SPA_FRACTION(25, 1), + &SPA_FRACTION(0, 1), + &SPA_FRACTION(30, 1)), + 0); + + params[0] = spa_pod_builder_pop(b, &frame[0]); + + RARCH_LOG("[Camera] [PipeWire]: Supported raw formats:\n"); + spa_debug_format(2, NULL, params[0]); + + return 1; +} + +static bool preprocess_image(pipewire_camera_t *camera) +{ + struct spa_buffer *buf; + struct spa_meta_header *h; + struct pw_buffer *b = NULL; + struct scaler_ctx *ctx = NULL; + + for (;;) + { + if ((b = pw_stream_dequeue_buffer(camera->stream))) + break; + } + if (b == NULL) + { + RARCH_DBG("[Camera] [PipeWire]: Out of buffers\n"); + return false; + } + + buf = b->buffer; + + if ((h = spa_buffer_find_meta_data(buf, SPA_META_Header, sizeof(*h)))) + { + if (h->flags & SPA_META_HEADER_FLAG_CORRUPTED) { + RARCH_LOG("[Camera] [PipeWire] Dropping corruped frame.\n"); + pw_stream_queue_buffer(camera->stream, b); + return false; + } + uint64_t now = pw_stream_get_nsec(camera->stream); + RARCH_DBG("[Camera] [PipeWire]: now:%"PRIu64" pts:%"PRIu64" diff:%"PRIi64"\n", + now, h->pts, now - h->pts); + } + + if (buf->datas[0].data == NULL) + return false; + + ctx = &camera->scaler; + scaler_ctx_scale_direct(ctx, camera->buffer_output, (const uint8_t*)buf->datas[0].data); + + pw_stream_queue_buffer(camera->stream, b); + return true; +} + +static void stream_state_changed_cb(void *data, enum pw_stream_state old, + enum pw_stream_state state, const char *error) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + + RARCH_DBG("[Camera] [PipeWire]: Stream state changed %s -> %s\n", + pw_stream_state_as_string(old), + pw_stream_state_as_string(state)); + + pw_thread_loop_signal(camera->pw->thread_loop, false); +} + +static void stream_io_changed_cb(void *data, uint32_t id, void *area, uint32_t size) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + + switch (id) + { + case SPA_IO_Position: + camera->position = area; + break; + } +} + +static void stream_param_changed_cb(void *data, uint32_t id, const struct spa_pod *param) +{ + uint8_t params_buffer[1024]; + const struct spa_pod *params[5]; + pipewire_camera_t *camera = (pipewire_camera_t*)data; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); + + if (param && id == SPA_PARAM_Tag) + { + spa_debug_pod(0, NULL, param); + return; + } + if (param && id == SPA_PARAM_Latency) + { + struct spa_latency_info info; + if (spa_latency_parse(param, &info) >= 0) + RARCH_DBG("[Camera] [PipeWire]: Got latency: %"PRIu64"\n", (info.min_ns + info.max_ns) / 2); + return; + } + /* NULL means to clear the format */ + if (param == NULL || id != SPA_PARAM_Format) + return; + + RARCH_DBG("[Camera] [PipeWire]: Got format:\n"); + spa_debug_format(2, NULL, param); + + if (spa_format_parse(param, &camera->format.media_type, &camera->format.media_subtype) < 0) + { + RARCH_DBG("[Camera] [PipeWire]: Failed to parse video format.\n"); + return; + } + + if (camera->format.media_type != SPA_MEDIA_TYPE_video) + return; + + switch (camera->format.media_subtype) + { + case SPA_MEDIA_SUBTYPE_raw: + spa_format_video_raw_parse(param, &camera->format.info.raw); + camera->scaler.in_fmt = id_to_scaler_format(camera->format.info.raw.format); + camera->size = SPA_RECTANGLE(camera->format.info.raw.size.width, camera->format.info.raw.size.height); + RARCH_DBG("[Camera] [PipeWire]: Configured capture format = %d\n", camera->format.info.raw.format); + break; + default: + RARCH_WARN("[Camera] [PipeWire]: Unsupported video format: %d\n", camera->format.media_subtype); + return; + } + + if (!camera->size.width || !camera->size.height) + { + pw_stream_set_error(camera->stream, -EINVAL, "invalid size"); + return; + } + + struct spa_pod_frame frame; + spa_pod_builder_push_object(&b, &frame, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers); + spa_pod_builder_add(&b, + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(camera->size.width * 2), + 0); + + spa_pod_builder_add(&b, + SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(8, 1, MAX_BUFFERS), + SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1 << SPA_DATA_MemPtr), + 0); + + params[0] = spa_pod_builder_pop(&b, &frame); + + params[1] = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, + SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header), + SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))); +#if 0 + params[2] = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, + SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform), + SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_videotransform))); +#endif + + camera->buffer_output = (uint32_t *) + malloc(camera->size.width * camera->size.height * sizeof(uint32_t)); + if (!camera->buffer_output) + { + RARCH_ERR("[Camera] [PipeWire]: Failed to allocate output buffer.\n"); + return; + } + + camera->scaler.in_width = camera->scaler.out_width = camera->size.width; + camera->scaler.in_height = camera->scaler.out_height = camera->size.height; + camera->scaler.out_fmt = SCALER_FMT_ARGB8888; + camera->scaler.in_stride = camera->size.width * 2; + camera->scaler.out_stride = camera->size.width * 4; + if (!scaler_ctx_gen_filter(&camera->scaler)) + { + RARCH_ERR("[Camera] [PipeWire]: Failed to create scaler.\n"); + return; + } + + pw_stream_update_params(camera->stream, params, 2); +} + +static const struct pw_stream_events stream_events = { + PW_VERSION_STREAM_EVENTS, + .state_changed = stream_state_changed_cb, + .io_changed = stream_io_changed_cb, + .param_changed = stream_param_changed_cb, + .process = NULL, +}; + +static void pipewire_stop(void *data) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + const char *error = NULL; + + retro_assert(camera); + retro_assert(camera->stream); + retro_assert(camera->pw); + + if (pw_stream_get_state(camera->stream, &error) == PW_STREAM_STATE_PAUSED) + pipewire_stream_set_active(camera->pw->thread_loop, camera->stream, false); +} + +static bool pipewire_start(void *data) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + const char *error = NULL; + + retro_assert(camera); + retro_assert(camera->stream); + retro_assert(camera->pw); + + if (pw_stream_get_state(camera->stream, &error) == PW_STREAM_STATE_STREAMING) + return true; + + return pipewire_stream_set_active(camera->pw->thread_loop, camera->stream, true); +} + +static void pipewire_free(void *data) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + + if (!camera) + return; + + if (camera->stream) + { + pw_thread_loop_lock(camera->pw->thread_loop); + pw_stream_destroy(camera->stream); + camera->stream = NULL; + pw_thread_loop_unlock(camera->pw->thread_loop); + } + + pipewire_core_deinit(camera->pw); + + if (camera->buffer_output) + free(camera->buffer_output); + + scaler_ctx_gen_reset(&camera->scaler); + free(camera); +} + +static void *pipewire_init(const char *device, uint64_t caps, + unsigned width, unsigned height) +{ + int res, n_params; + const struct spa_pod *params[3]; + struct pw_properties *props; + uint8_t buffer[1024]; + pipewire_camera_t *camera = (pipewire_camera_t*)calloc(1, sizeof(*camera)); + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + + if (!camera) + goto error; + + if (!pipewire_core_init(&camera->pw, "camera_driver", NULL)) + goto error; + + pipewire_core_wait_resync(camera->pw); + + props = pw_properties_new(PW_KEY_MEDIA_TYPE, PW_RARCH_MEDIA_TYPE_VIDEO, + PW_KEY_MEDIA_CATEGORY, PW_RARCH_MEDIA_CATEGORY_RECORD, + PW_KEY_MEDIA_ROLE, PW_RARCH_MEDIA_ROLE, + NULL); + if (!props) + goto error; + + if (device) + pw_properties_set(props, PW_KEY_TARGET_OBJECT, device); + + camera->stream = pw_stream_new(camera->pw->core, PW_RARCH_APPNAME, props); + + pw_stream_add_listener(camera->stream, &camera->stream_listener, &stream_events, camera); + + /* build the extra parameters to connect with. To connect, we can provide + * a list of supported formats. We use a builder that writes the param + * object to the stack. */ + n_params = build_format(&b, params, width, height); + { + struct spa_pod_frame f; + struct spa_dict_item items[1]; + /* send a tag, input tags travel upstream */ + spa_tag_build_start(&b, &f, SPA_PARAM_Tag, SPA_DIRECTION_INPUT); + items[0] = SPA_DICT_ITEM_INIT("my-tag-other-key", "my-special-other-tag-value"); + spa_tag_build_add_dict(&b, &SPA_DICT_INIT(items, 1)); + params[n_params++] = spa_tag_build_end(&b, &f); + } + + res = pw_stream_connect(camera->stream, + PW_DIRECTION_INPUT, + PW_ID_ANY, + PW_STREAM_FLAG_AUTOCONNECT | + PW_STREAM_FLAG_INACTIVE | + PW_STREAM_FLAG_MAP_BUFFERS, + params, n_params); + + if (res < 0) + { + RARCH_ERR("[Camera] [PipeWire]: can't connect: %s\n", spa_strerror(res)); + goto error; + } + + pw_thread_loop_unlock(camera->pw->thread_loop); + + return camera; + +error: + RARCH_ERR("[Camera] [PipeWire]: Failed to initialize camera\n"); + pipewire_free(camera); + return NULL; +} + +static bool pipewire_poll(void *data, + retro_camera_frame_raw_framebuffer_t frame_raw_cb, + retro_camera_frame_opengl_texture_t frame_gl_cb) +{ + pipewire_camera_t *camera = (pipewire_camera_t*)data; + const char *error = NULL; + + (void)frame_gl_cb; + + retro_assert(camera); + + if (pw_stream_get_state(camera->stream, &error) != PW_STREAM_STATE_STREAMING) + return false; + + if (!frame_raw_cb || !preprocess_image(camera)) + return false; + + frame_raw_cb(camera->buffer_output, camera->size.width, + camera->size.height, camera->size.width * 4); + return true; +} + +camera_driver_t camera_pipewire = { + pipewire_init, + pipewire_free, + pipewire_start, + pipewire_stop, + pipewire_poll, + "pipewire", +}; diff --git a/griffin/griffin.c b/griffin/griffin.c index eaec707b88..22fbd7dca3 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -811,6 +811,9 @@ CAMERA #ifdef HAVE_V4L2 #include "../camera/drivers/video4linux2.c" #endif +#ifdef HAVE_PIPEWIRE +#include "../camera/drivers/pipewire.c" +#endif #ifdef HAVE_VIDEOPROCESSOR #include "../cores/libretro-video-processor/video_processor_v4l2.c" From 359258a1b5ced3768a80b5c28820d23ebdc9fba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Via=C4=8Das=C5=82a=C5=AD?= Date: Mon, 3 Feb 2025 11:04:23 +0300 Subject: [PATCH 181/574] Add missing drivers to configuration (#17509) `camera_pipewire` and `record_wav` --- configuration.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configuration.c b/configuration.c index ceabc69dca..36cdfe9593 100644 --- a/configuration.c +++ b/configuration.c @@ -233,6 +233,7 @@ enum camera_driver_enum CAMERA_RWEBCAM, CAMERA_ANDROID, CAMERA_AVFOUNDATION, + CAMERA_PIPEWIRE, CAMERA_NULL }; @@ -276,6 +277,7 @@ enum menu_driver_enum enum record_driver_enum { RECORD_FFMPEG = MENU_NULL + 1, + RECORD_WAV, RECORD_NULL }; @@ -590,7 +592,7 @@ static const enum audio_resampler_driver_enum AUDIO_DEFAULT_RESAMPLER_DRIVER = A #if defined(HAVE_FFMPEG) static const enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_FFMPEG; #else -static const enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_NULL; +static const enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_WAV; #endif #ifdef HAVE_WINMM @@ -717,6 +719,8 @@ static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_V4L2; static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_RWEBCAM; #elif defined(ANDROID) static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_ANDROID; +#elif defined(HAVE_PIPEWIRE) +static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_PIPEWIRE; #else static const enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_NULL; #endif @@ -1009,6 +1013,8 @@ const char *config_get_default_record(void) { case RECORD_FFMPEG: return "ffmpeg"; + case RECORD_WAV: + return "wav"; case RECORD_NULL: break; } @@ -1299,6 +1305,8 @@ const char *config_get_default_camera(void) return "android"; case CAMERA_AVFOUNDATION: return "avfoundation"; + case CAMERA_PIPEWIRE: + return "pipewire"; case CAMERA_NULL: break; } From f73df57a1aabae050c55fd66ae03eb0f2e74bf0a Mon Sep 17 00:00:00 2001 From: David Demelier Date: Mon, 3 Feb 2025 15:21:07 +0100 Subject: [PATCH 182/574] Fix non-integer cast to pthread_t (#17512) --- input/common/linux_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input/common/linux_common.c b/input/common/linux_common.c index 32f7c45dde..dcee89e129 100644 --- a/input/common/linux_common.c +++ b/input/common/linux_common.c @@ -266,7 +266,7 @@ void linux_close_illuminance_sensor(linux_illuminance_sensor_t *sensor) if (sensor->thread) { - pthread_t thread = sthread_get_thread_id(sensor->thread); + pthread_t thread = (pthread_t)sthread_get_thread_id(sensor->thread); sensor->done = true; if (pthread_cancel(thread) != 0) From b18a6b644b4f79530fddd8ecf0b6ddf1e8f14100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Ca=C3=B1ero?= <54242962+lucascanero@users.noreply.github.com> Date: Tue, 4 Feb 2025 13:24:47 +0000 Subject: [PATCH 183/574] enable CloudSync on libnx (switch) (#17516) --- Makefile.libnx | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.libnx b/Makefile.libnx index 7f52f506df..56e2247ec4 100644 --- a/Makefile.libnx +++ b/Makefile.libnx @@ -49,6 +49,7 @@ HAVE_PATCH = 1 HAVE_CHEATS = 1 HAVE_RUNAHEAD = 1 HAVE_NETWORKING = 1 +HAVE_CLOUDSYNC = 1 HAVE_IFINFO = 1 HAVE_NETPLAYDISCOVERY = 1 HAVE_STB_FONT = 1 From ea22c7c16c945d1f3f10e7c753664fabb159090b Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Tue, 4 Feb 2025 17:32:37 +0200 Subject: [PATCH 184/574] Main Menu unifications between drivers (#17517) --- config.def.h | 7 +- configuration.c | 1 - menu/drivers/materialui.c | 29 ++- menu/drivers/ozone.c | 116 +++++++----- menu/drivers/xmb.c | 135 +++++++++----- menu/menu_displaylist.c | 358 +++++++++++++++++++------------------- menu/menu_setting.c | 25 --- msg_hash.h | 2 +- 8 files changed, 369 insertions(+), 304 deletions(-) diff --git a/config.def.h b/config.def.h index 560d25d453..fc5744f2d3 100644 --- a/config.def.h +++ b/config.def.h @@ -808,12 +808,7 @@ #endif #endif -/* Specifies 'add content' visibility when using - * menus WITH a dedicated 'Import Content' tab */ -#define DEFAULT_MENU_CONTENT_SHOW_ADD true -/* Specifies 'add content' visibility when using - * menus WITHOUT a dedicated 'Import Content' tab */ -#define DEFAULT_MENU_CONTENT_SHOW_ADD_ENTRY MENU_ADD_CONTENT_ENTRY_DISPLAY_PLAYLISTS_TAB +#define DEFAULT_MENU_CONTENT_SHOW_ADD_ENTRY MENU_ADD_CONTENT_ENTRY_DISPLAY_MAIN_TAB #define DEFAULT_CONTENT_SHOW_PLAYLISTS true diff --git a/configuration.c b/configuration.c index 36cdfe9593..19fec63924 100644 --- a/configuration.c +++ b/configuration.c @@ -2009,7 +2009,6 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("content_show_netplay", &settings->bools.menu_content_show_netplay, true, DEFAULT_CONTENT_SHOW_NETPLAY, false); #endif SETTING_BOOL("content_show_history", &settings->bools.menu_content_show_history, true, DEFAULT_CONTENT_SHOW_HISTORY, false); - SETTING_BOOL("content_show_add", &settings->bools.menu_content_show_add, true, DEFAULT_MENU_CONTENT_SHOW_ADD, false); SETTING_BOOL("content_show_playlists", &settings->bools.menu_content_show_playlists, true, DEFAULT_CONTENT_SHOW_PLAYLISTS, false); #if defined(HAVE_LIBRETRODB) SETTING_BOOL("content_show_explore", &settings->bools.menu_content_show_explore, true, DEFAULT_MENU_CONTENT_SHOW_EXPLORE, false); diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 7c627fc521..e8fe84e9d1 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -9594,28 +9594,31 @@ static int materialui_list_push(void *data, void *userdata, core_info_list_t *list = NULL; materialui_handle_t *mui = (materialui_handle_t*)userdata; + /* Use common lists for all drivers */ + return ret; + if (!mui) return ret; switch (type) { case DISPLAYLIST_LOAD_CONTENT_LIST: + core_info_get_list(&list); + menu_entries_clear(info->list); + menu_entries_append(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), MENU_ENUM_LABEL_FAVORITES, MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0, NULL); - core_info_get_list(&list); if (list->info_count > 0) - { menu_entries_append(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, MENU_SETTING_ACTION, 0, 0, NULL); - } if (frontend_driver_parse_drive_list(info->list, true) != 0) menu_entries_append(info->list, "/", @@ -9623,11 +9626,12 @@ static int materialui_list_push(void *data, void *userdata, MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, MENU_SETTING_ACTION, 0, 0, NULL); - menu_entries_append(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), - MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, - MENU_SETTING_ACTION, 0, 0, NULL); + if (!config_get_ptr()->bools.kiosk_mode_enable) + menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), + MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, + MENU_SETTING_ACTION, 0, 0, NULL); info->flags |= MD_FLAG_NEED_PUSH | MD_FLAG_NEED_REFRESH; ret = 0; @@ -9709,6 +9713,15 @@ static int materialui_list_push(void *data, void *userdata, false); } + if (settings->bools.menu_content_show_favorites) + { + menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_FAVORITES), + MENU_ENUM_LABEL_GOTO_FAVORITES, + MENU_SETTING_ACTION, 0, 0, NULL); + } + if (settings->bools.menu_show_load_disc) { MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index ed39256f2c..22d12e3945 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -1549,7 +1549,6 @@ static ozone_theme_t ozone_theme_purple_rain = { {0}, /* textures */ - /* No theme assets */ "purple_rain" /* name */ }; @@ -1914,15 +1913,21 @@ static uintptr_t ozone_entries_icon_get_texture( /* Menu collection submenus */ case MENU_ENUM_LABEL_PLAYLISTS_TAB: - return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ZIP]; + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_PLAYLIST]; + case MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_HISTORY]; case MENU_ENUM_LABEL_GOTO_FAVORITES: - return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FAVORITE]; + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FAVORITES]; +#ifdef HAVE_IMAGEVIEWER case MENU_ENUM_LABEL_GOTO_IMAGES: - return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGE]; + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGES]; +#endif +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) case MENU_ENUM_LABEL_GOTO_VIDEO: - return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MOVIE]; + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MOVIES]; +#endif case MENU_ENUM_LABEL_GOTO_MUSIC: - return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MUSIC]; + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MUSICS]; case MENU_ENUM_LABEL_GOTO_EXPLORE: if (!string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_EXPLORE))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CURSOR]; @@ -2178,9 +2183,10 @@ static uintptr_t ozone_entries_icon_get_texture( case MENU_ENUM_LABEL_USER_SETTINGS: case MENU_ENUM_LABEL_SETTINGS_SHOW_USER: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_USER]; + case MENU_ENUM_LABEL_ADD_CONTENT_LIST: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MENU_ADD]; case MENU_ENUM_LABEL_DIRECTORY_SETTINGS: case MENU_ENUM_LABEL_SETTINGS_SHOW_DIRECTORY: - case MENU_ENUM_LABEL_ADD_CONTENT_LIST: case MENU_ENUM_LABEL_SCAN_DIRECTORY: case MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_LIST: case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_PARENT: @@ -2199,6 +2205,8 @@ static uintptr_t ozone_entries_icon_get_texture( case MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_SETTINGS: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_NOTIFICATIONS]; #ifdef HAVE_NETWORKING + case MENU_ENUM_LABEL_NETPLAY: + return ozone->tab_textures[OZONE_TAB_TEXTURE_NETWORK]; case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RUN]; case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: @@ -2301,7 +2309,32 @@ static uintptr_t ozone_entries_icon_get_texture( return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FOLDER]; case FILE_TYPE_PLAIN: case FILE_TYPE_IN_CARCHIVE: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FILE]; case FILE_TYPE_RPL_ENTRY: + case FILE_TYPE_PLAYLIST_COLLECTION: + switch (ozone->tabs[ozone->categories_selection_ptr]) + { + case OZONE_SYSTEM_TAB_MAIN: + if (string_is_equal(ozone->title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MUSIC_TAB))) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MUSIC]; + else if (string_is_equal(ozone->title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_IMAGES_TAB))) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGE]; + else if (string_is_equal(ozone->title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_TAB))) + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MOVIE]; + break; + case OZONE_SYSTEM_TAB_MUSIC: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MUSIC]; +#ifdef HAVE_IMAGEVIEWER + case OZONE_SYSTEM_TAB_IMAGES: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGE]; +#endif +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) + case OZONE_SYSTEM_TAB_VIDEO: + return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_MOVIE]; +#endif + default: + break; + } return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FILE]; case FILE_TYPE_SHADER: case FILE_TYPE_SHADER_PRESET: @@ -2318,8 +2351,6 @@ static uintptr_t ozone_entries_icon_get_texture( case FILE_TYPE_CORE: case FILE_TYPE_DIRECT_LOAD: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE]; - case FILE_TYPE_PLAYLIST_COLLECTION: - return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FILE]; case FILE_TYPE_RDB: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RDB]; case FILE_TYPE_RDB_ENTRY: @@ -3665,21 +3696,18 @@ static void ozone_thumbnail_bar_hide_end(void *userdata) ozone->flags |= OZONE_FLAG_NEED_COMPUTE; } -static bool ozone_is_load_content_playlist(void *userdata) +static bool ozone_is_main_menu_playlist(void *userdata) { ozone_handle_t *ozone = (ozone_handle_t*)userdata; menu_entry_t entry; - if ( (ozone->depth != 4) + if ( (ozone->depth != 3) || (ozone->flags & OZONE_FLAG_IS_DB_MANAGER_LIST) || (ozone->flags & OZONE_FLAG_IS_FILE_LIST)) return false; MENU_ENTRY_INITIALIZE(entry); - entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED - | MENU_ENTRY_FLAG_RICH_LABEL_ENABLED; menu_entry_get(&entry, 0, 0, NULL, true); - return entry.type == FILE_TYPE_RPL_ENTRY; } @@ -3927,7 +3955,7 @@ static bool ozone_is_playlist(ozone_handle_t *ozone, bool depth) switch (ozone->tabs[ozone->categories_selection_ptr]) { case OZONE_SYSTEM_TAB_MAIN: - if (ozone_is_load_content_playlist(ozone)) + if (ozone_is_main_menu_playlist(ozone)) return true; case OZONE_SYSTEM_TAB_SETTINGS: case OZONE_SYSTEM_TAB_ADD: @@ -3991,8 +4019,8 @@ static void ozone_sidebar_update_collapse( if (ozone_get_horizontal_selection_type(ozone) == MENU_EXPLORE_TAB) is_playlist = true; - /* Playlists under 'Load Content' don't need sidebar animations */ - if (is_playlist && ozone->depth > 3) + /* Playlists under "Main Menu" don't need sidebar animations */ + if (is_playlist && ozone->depth > 2) goto end; /* To collapse or not to collapse */ @@ -5893,9 +5921,9 @@ border_iterate: else if (ozone->depth == 3 && entry.enum_idx == MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS) { if (string_is_equal(entry.rich_label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HISTORY_TAB))) - texture = ozone->tab_textures[OZONE_TAB_TEXTURE_HISTORY]; + texture = ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_HISTORY]; else if (string_is_equal(entry.rich_label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES_TAB))) - texture = ozone->tab_textures[OZONE_TAB_TEXTURE_FAVORITES]; + texture = ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FAVORITES]; else if (i < ozone->horizontal_list.size) { ozone_node_t *sidebar_node = NULL; @@ -5915,10 +5943,10 @@ border_iterate: texture = sidebar_node->icon; } } - /* "Load Content" playlists */ + /* "Main Menu" playlists */ else if (ozone->tabs[ozone->categories_selection_ptr] == OZONE_SYSTEM_TAB_MAIN) { - if (ozone_is_load_content_playlist(ozone)) + if (ozone_is_main_menu_playlist(ozone)) { const struct playlist_entry *pl_entry = NULL; ozone_node_t *db_node = NULL; @@ -5931,7 +5959,7 @@ border_iterate: && (db_node = RHMAP_GET_STR(ozone->playlist_db_node_map, pl_entry->db_name))) texture = db_node->content_icon; } - else if (ozone->depth == 3 && entry.type == FILE_TYPE_PLAYLIST_COLLECTION) + else if (ozone->depth == 2 && entry.type == FILE_TYPE_PLAYLIST_COLLECTION) { ozone_node_t *sidebar_node = (ozone_node_t*) file_list_get_userdata_at_offset(&ozone->horizontal_list, @@ -5947,6 +5975,7 @@ border_iterate: { switch (ozone->tabs[ozone->categories_selection_ptr]) { + case OZONE_SYSTEM_TAB_MAIN: case OZONE_SYSTEM_TAB_HISTORY: case OZONE_SYSTEM_TAB_FAVORITES: { @@ -8872,10 +8901,10 @@ static void *ozone_init(void **userdata, bool video_is_threaded) if ( settings->bools.menu_content_show_settings && !settings->bools.kiosk_mode_enable) ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_SETTINGS; - if (settings->bools.menu_content_show_favorites) - ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_FAVORITES; if (settings->bools.menu_content_show_history) ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_HISTORY; + if (settings->bools.menu_content_show_favorites) + ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_FAVORITES; #ifdef HAVE_IMAGEVIEWER if (settings->bools.menu_content_show_images) ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_IMAGES; @@ -8886,15 +8915,15 @@ static void *ozone_init(void **userdata, bool video_is_threaded) if (settings->bools.menu_content_show_video) ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_VIDEO; #endif +#if 0 /* Move Netplay and Import Content to Main Menu */ #ifdef HAVE_NETWORKING if (settings->bools.menu_content_show_netplay) ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_NETPLAY; #endif - if ( settings->bools.menu_content_show_add && !settings->bools.kiosk_mode_enable) ozone->tabs[++ozone->system_tab_end] = OZONE_SYSTEM_TAB_ADD; - +#endif /* 0 */ #if defined(HAVE_DYNAMIC) if (settings->uints.menu_content_show_contentless_cores != MENU_CONTENTLESS_CORES_DISPLAY_NONE) @@ -9659,7 +9688,9 @@ static int ozone_list_push(void *data, void *userdata, menu_displaylist_info_t *info, unsigned type) { int ret = -1; - core_info_list_t *list = NULL; + + /* Use common lists for all drivers */ + return ret; switch (type) { @@ -9668,24 +9699,18 @@ static int ozone_list_push(void *data, void *userdata, settings_t *settings = config_get_ptr(); bool menu_content_show_playlists = settings->bools.menu_content_show_playlists; bool kiosk_mode_enable = settings->bools.kiosk_mode_enable; + core_info_list_t *list = NULL; + + core_info_get_list(&list); menu_entries_clear(info->list); + menu_entries_append(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), MENU_ENUM_LABEL_FAVORITES, MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0, NULL); - core_info_get_list(&list); - if (list && list->info_count > 0) - { - menu_entries_append(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), - MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, - MENU_SETTING_ACTION, 0, 0, NULL); - } - if (menu_content_show_playlists) menu_entries_append(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB), @@ -9693,6 +9718,13 @@ static int ozone_list_push(void *data, void *userdata, MENU_ENUM_LABEL_PLAYLISTS_TAB, MENU_SETTING_ACTION, 0, 0, NULL); + if (list && list->info_count > 0) + menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), + MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, + MENU_SETTING_ACTION, 0, 0, NULL); + if (frontend_driver_parse_drive_list(info->list, true) != 0) menu_entries_append(info->list, "/", msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), @@ -9700,13 +9732,11 @@ static int ozone_list_push(void *data, void *userdata, MENU_SETTING_ACTION, 0, 0, NULL); if (!kiosk_mode_enable) - { menu_entries_append(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, MENU_SETTING_ACTION, 0, 0, NULL); - } info->flags |= MD_FLAG_NEED_PUSH | MD_FLAG_NEED_REFRESH; ret = 0; @@ -10300,7 +10330,7 @@ static void ozone_render(void *data, menu_st->selection_ptr = i; /* If this is a playlist, must update thumbnails */ - if ( ((ozone->flags & OZONE_FLAG_IS_PLAYLIST) && (ozone->depth == 1 || ozone->depth == 4)) + if ( ((ozone->flags & OZONE_FLAG_IS_PLAYLIST) && (ozone->depth == 1 || ozone->depth == 3)) || (ozone->flags & OZONE_FLAG_IS_EXPLORE_LIST)) { ozone->flags &= ~OZONE_FLAG_SKIP_THUMBNAIL_RESET; @@ -10336,7 +10366,7 @@ static void ozone_render(void *data, } /* If this is a playlist, must update thumbnails */ else if ((ozone->flags & OZONE_FLAG_IS_PLAYLIST) - && (ozone->depth == 1 || ozone->depth == 4)) + && (ozone->depth == 1 || ozone->depth == 3)) { ozone_set_thumbnail_content(ozone, ""); ozone_update_thumbnail_image(ozone); @@ -11552,7 +11582,7 @@ static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) /* Playlist updates */ if ( (ozone->flags & OZONE_FLAG_IS_PLAYLIST) - && (ozone->depth == 1 || ozone->depth == 4)) + && (ozone->depth == 1 || ozone->depth == 3)) { ozone_set_thumbnail_content(ozone, ""); update_thumbnails = true; @@ -12438,7 +12468,7 @@ static void ozone_populate_entries( * and savestate slots */ if ( ( (ozone->flags & OZONE_FLAG_WANT_THUMBNAIL_BAR)) - && ( ((ozone->flags & OZONE_FLAG_IS_PLAYLIST) && (ozone->depth == 1 || ozone->depth == 4)) + && ( ((ozone->flags & OZONE_FLAG_IS_PLAYLIST) && (ozone->depth == 1 || ozone->depth == 3)) || ((ozone->flags & OZONE_FLAG_IS_DB_MANAGER_LIST) && (ozone->depth >= 4)) || (ozone->flags & OZONE_FLAG_IS_EXPLORE_LIST) || (ozone->flags & OZONE_FLAG_IS_FILE_LIST) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 90cce2e476..e965c9bb46 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -128,6 +128,7 @@ enum #endif #ifdef HAVE_NETWORKING XMB_TEXTURE_NETPLAY, + XMB_TEXTURE_NETPLAY_ALT, XMB_TEXTURE_ROOM, XMB_TEXTURE_ROOM_LAN, XMB_TEXTURE_ROOM_RELAY, @@ -1150,8 +1151,8 @@ static char *xmb_path_dynamic_wallpaper(xmb_handle_t *xmb) path[0] = '\0'; - /* Do not update wallpaper in "Load Content" playlists and inside playlist items */ - if ( (xmb->categories_selection_ptr == XMB_SYSTEM_TAB_MAIN && depth > 4) + /* Do not update wallpaper in "Main Menu" playlists and inside playlist items */ + if ( (xmb->categories_selection_ptr == XMB_SYSTEM_TAB_MAIN && depth > 3) || (xmb->categories_selection_ptr > xmb->system_tab_end && depth > 1)) { if (string_is_empty(xmb->bg_file_path)) @@ -2082,7 +2083,7 @@ static void xmb_list_open_new(xmb_handle_t *xmb, { if (xmb->is_playlist || xmb->is_db_manager_list || xmb->is_explore_list) { - if ( !(xmb->is_db_manager_list && xmb->depth > 4) + if ( !(xmb->is_db_manager_list && xmb->depth > 3) && !xmb->skip_thumbnail_reset) xmb_unload_thumbnail_textures(xmb); @@ -2987,6 +2988,7 @@ static void xmb_populate_entries(void *data, #endif ) ) + || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PLAYLIST_LIST)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST)) @@ -3297,28 +3299,35 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS: return xmb->textures.list[XMB_TEXTURE_FOLDER]; case MENU_ENUM_LABEL_ADD_CONTENT_LIST: - return xmb->textures.list[XMB_TEXTURE_ADD]; + return xmb->textures.list[XMB_TEXTURE_MENU_ADD]; case MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR: case MENU_ENUM_LABEL_VALUE_CONTENTLESS_CORES_TAB: return xmb->textures.list[XMB_TEXTURE_RDB]; /* Menu collection submenus */ case MENU_ENUM_LABEL_PLAYLISTS_TAB: - return xmb->textures.list[XMB_TEXTURE_ZIP]; + return xmb->textures.list[XMB_TEXTURE_PLAYLIST]; + case MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY: + return xmb->textures.list[XMB_TEXTURE_HISTORY]; case MENU_ENUM_LABEL_GOTO_FAVORITES: - return xmb->textures.list[XMB_TEXTURE_FAVORITE]; + return xmb->textures.list[XMB_TEXTURE_FAVORITES]; +#ifdef HAVE_IMAGEVIEWER case MENU_ENUM_LABEL_GOTO_IMAGES: - return xmb->textures.list[XMB_TEXTURE_IMAGE]; + return xmb->textures.list[XMB_TEXTURE_IMAGES]; +#endif +#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) case MENU_ENUM_LABEL_GOTO_VIDEO: - return xmb->textures.list[XMB_TEXTURE_MOVIE]; + return xmb->textures.list[XMB_TEXTURE_MOVIES]; +#endif case MENU_ENUM_LABEL_GOTO_MUSIC: - return xmb->textures.list[XMB_TEXTURE_MUSIC]; + return xmb->textures.list[XMB_TEXTURE_MUSICS]; case MENU_ENUM_LABEL_GOTO_EXPLORE: if (!string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_EXPLORE))) return xmb->textures.list[XMB_TEXTURE_CURSOR]; return xmb->textures.list[XMB_TEXTURE_RDB]; case MENU_ENUM_LABEL_GOTO_CONTENTLESS_CORES: return xmb->textures.list[XMB_TEXTURE_CORE]; + case MENU_ENUM_LABEL_LOAD_DISC: case MENU_ENUM_LABEL_DUMP_DISC: #ifdef HAVE_LAKKA @@ -3561,6 +3570,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_SETTINGS: return xmb->textures.list[XMB_TEXTURE_NOTIFICATIONS]; #ifdef HAVE_NETWORKING + case MENU_ENUM_LABEL_NETPLAY: + return xmb->textures.list[XMB_TEXTURE_NETPLAY]; case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: return xmb->textures.list[XMB_TEXTURE_RUN]; case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: @@ -3665,10 +3676,17 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, break; } } + else + { + if (string_is_equal(xmb->title_name, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MUSIC_TAB))) + return xmb->textures.list[XMB_TEXTURE_MUSIC]; + else if (string_is_equal(xmb->title_name, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_IMAGES_TAB))) + return xmb->textures.list[XMB_TEXTURE_IMAGE]; + else if (string_is_equal(xmb->title_name, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_TAB))) + return xmb->textures.list[XMB_TEXTURE_MOVIE]; + } } break; - case XMB_SYSTEM_TAB_FAVORITES: - return xmb->textures.list[XMB_TEXTURE_FAVORITE]; case XMB_SYSTEM_TAB_MUSIC: return xmb->textures.list[XMB_TEXTURE_MUSIC]; #ifdef HAVE_IMAGEVIEWER @@ -4981,9 +4999,15 @@ static int xmb_draw_item( node->zoom = xmb->items_active_zoom; } - /* Differentiate the basic setting icon from the rest */ - if (texture == xmb->textures.list[XMB_TEXTURE_SUBSETTING]) - gfx_display_set_alpha(color, MIN(node->alpha / 3, xmb->alpha)); + if (i != current && list != &xmb->selection_buf_old) + { + /* Differentiate the basic setting icon from the rest */ + if (texture == xmb->textures.list[XMB_TEXTURE_SUBSETTING]) + gfx_display_set_alpha(color, MIN(node->alpha / 2.4f, xmb->alpha)); + /* Highlight active icon more by dimming all passives */ + else + gfx_display_set_alpha(color, MIN(node->alpha / 1.2f, xmb->alpha)); + } /* Explore list correction hack for not showing wrong icons as "previous" icon */ if (xmb->is_explore_list && !xmb->is_quick_menu && texture) @@ -5018,8 +5042,8 @@ static int xmb_draw_item( texture = sidebar_node->icon; } } - /* "Load Content" playlists */ - else if (xmb->depth == 3 && entry_type == FILE_TYPE_PLAYLIST_COLLECTION) + /* "Main Menu" playlists */ + else if (xmb->depth == 2 && entry_type == FILE_TYPE_PLAYLIST_COLLECTION) { xmb_node_t *sidebar_node = (xmb_node_t*) file_list_get_userdata_at_offset(&xmb->horizontal_list, list->list[i].entry_idx); if (sidebar_node && sidebar_node->icon) @@ -5033,12 +5057,16 @@ static int xmb_draw_item( { case XMB_SYSTEM_TAB_MAIN: { - /* Special fall-through for "Load Content" > Playlists > Favorites */ + /* Special fall-through for "Main Menu" > Playlists > History/Favorites */ char title[NAME_MAX_LENGTH]; menu_entries_get_title(title, sizeof(title)); - if (string_is_equal(title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES))) + if ( string_is_equal(title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY)) + || string_is_equal(title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES))) ; /* no-op */ - else if (xmb->depth == 5) + /* Force "Main Menu" playlists to use content icon while + * inside the playlist content regardless of the option, + * since playlists themselves use the main icon */ + else if (xmb->depth == 4) show_history_icons = PLAYLIST_SHOW_HISTORY_ICONS_CONTENT; else break; @@ -5049,8 +5077,7 @@ static int xmb_draw_item( const struct playlist_entry *pl_entry = NULL; xmb_node_t *db_node = NULL; - playlist_get_index(playlist_get_cached(), - entry.entry_idx, &pl_entry); + playlist_get_index(playlist_get_cached(), entry.entry_idx, &pl_entry); if ( pl_entry && !string_is_empty(pl_entry->db_name) @@ -5143,11 +5170,13 @@ static int xmb_draw_item( if (texture_switch != 0 && color[3] != 0 && !xmb->assets_missing) { - if (texture_switch == xmb->textures.list[XMB_TEXTURE_SWITCH_OFF]) - gfx_display_set_alpha(color, MIN(node->alpha / 2, xmb->alpha)); - else - gfx_display_set_alpha(color, MIN(node->alpha, xmb->alpha)); - + if (list != &xmb->selection_buf_old) + { + if (texture_switch == xmb->textures.list[XMB_TEXTURE_SWITCH_OFF]) + gfx_display_set_alpha(color, MIN(node->alpha / 2, xmb->alpha)); + else + gfx_display_set_alpha(color, MIN(node->alpha, xmb->alpha)); + } xmb_draw_icon( userdata, p_disp, @@ -7522,9 +7551,9 @@ static void xmb_layout_ps3(xmb_handle_t *xmb, int width) xmb->items_passive_zoom = 0.5; xmb->categories_active_alpha = 1.0; - xmb->categories_passive_alpha = 0.85; + xmb->categories_passive_alpha = 0.75; xmb->items_active_alpha = 1.0; - xmb->items_passive_alpha = 0.85; + xmb->items_passive_alpha = 0.75; xmb->shadow_offset = 3.0 * scale_factor; if (xmb->shadow_offset < 1.0) @@ -7577,9 +7606,9 @@ static void xmb_layout_psp(xmb_handle_t *xmb, int width) xmb->items_passive_zoom = 0.5; xmb->categories_active_alpha = 1.0; - xmb->categories_passive_alpha = 0.85; + xmb->categories_passive_alpha = 0.75; xmb->items_active_alpha = 1.0; - xmb->items_passive_alpha = 0.85; + xmb->items_passive_alpha = 0.75; xmb->shadow_offset = 3.0 * scale_factor; if (xmb->shadow_offset < 1.0) @@ -7815,10 +7844,10 @@ static void *xmb_init(void **userdata, bool video_is_threaded) if ( settings->bools.menu_content_show_settings && !settings->bools.kiosk_mode_enable) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_SETTINGS; - if (settings->bools.menu_content_show_favorites) - xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_FAVORITES; if (settings->bools.menu_content_show_history) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_HISTORY; + if (settings->bools.menu_content_show_favorites) + xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_FAVORITES; #ifdef HAVE_IMAGEVIEWER if (settings->bools.menu_content_show_images) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_IMAGES; @@ -7829,15 +7858,15 @@ static void *xmb_init(void **userdata, bool video_is_threaded) if (settings->bools.menu_content_show_video) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_VIDEO; #endif +#if 0 /* Move Netplay and Import Content to Main Menu */ #ifdef HAVE_NETWORKING if (settings->bools.menu_content_show_netplay) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_NETPLAY; #endif - if ( settings->bools.menu_content_show_add && !settings->bools.kiosk_mode_enable) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_ADD; - +#endif /* 0 */ #if defined(HAVE_DYNAMIC) if (settings->uints.menu_content_show_contentless_cores != MENU_CONTENTLESS_CORES_DISPLAY_NONE) xmb->tabs[++xmb->system_tab_end] = XMB_SYSTEM_TAB_CONTENTLESS_CORES; @@ -8094,6 +8123,8 @@ static const char *xmb_texture_path(unsigned id) #ifdef HAVE_NETWORKING case XMB_TEXTURE_NETPLAY: return "netplay.png"; + case XMB_TEXTURE_NETPLAY_ALT: + return "../../../ozone/png/sidebar/netplay.png"; case XMB_TEXTURE_ROOM: return "menu_room.png"; case XMB_TEXTURE_ROOM_LAN: @@ -8244,7 +8275,20 @@ static bool xmb_context_reset_textures( for (i = 0; i < XMB_TEXTURE_LAST; i++) { - if (!gfx_display_reset_textures_list(xmb_texture_path(i), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL)) + /* Use Ozone sidebar icon for netplay icon instead if it exists */ + const char *texture_path = xmb_texture_path(i); +#ifdef HAVE_NETWORKING + if (i == XMB_TEXTURE_NETPLAY && menu_xmb_theme == XMB_ICON_THEME_MONOCHROME) + { + char texpath[PATH_MAX_LENGTH]; + fill_pathname_join_special(texpath, + iconpath, xmb_texture_path(XMB_TEXTURE_NETPLAY_ALT), sizeof(texpath)); + if (path_is_valid(texpath)) + texture_path = xmb_texture_path(XMB_TEXTURE_NETPLAY_ALT); + } +#endif + + if (!gfx_display_reset_textures_list(texture_path, iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL)) { /* New extra battery icons could be missing */ if ( i == XMB_TEXTURE_BATTERY_80 @@ -8258,6 +8302,7 @@ static bool xmb_context_reset_textures( return false; continue; } + /* If the icon is missing return the subsetting (because some themes are incomplete) */ if ( !( i == XMB_TEXTURE_DIALOG_SLICE || i == XMB_TEXTURE_KEY_HOVER @@ -8270,7 +8315,7 @@ static bool xmb_context_reset_textures( /* Do not draw icons if subsetting is missing */ return false; } - /* Do not draw icons if this ones are is missing */ + /* Do not draw icons if these are missing */ switch (i) { case XMB_TEXTURE_POINTER: @@ -8921,16 +8966,27 @@ static int xmb_list_push(void *data, void *userdata, = settings->paths.menu_content_show_settings_password; const char *kiosk_mode_password = settings->paths.kiosk_mode_password; + /* Use common lists for all drivers */ + return -1; + switch (type) { case DISPLAYLIST_LOAD_CONTENT_LIST: menu_entries_clear(info->list); + menu_entries_append(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), MENU_ENUM_LABEL_FAVORITES, MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0, NULL); + if (menu_content_show_pl) + menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB), + msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB), + MENU_ENUM_LABEL_PLAYLISTS_TAB, + MENU_SETTING_ACTION, 0, 0, NULL); + core_info_get_list(&list); if (list->info_count > 0) menu_entries_append(info->list, @@ -8939,13 +8995,6 @@ static int xmb_list_push(void *data, void *userdata, MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, MENU_SETTING_ACTION, 0, 0, NULL); - if (menu_content_show_pl) - menu_entries_append(info->list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB), - msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB), - MENU_ENUM_LABEL_PLAYLISTS_TAB, - MENU_SETTING_ACTION, 0, 0, NULL); - if (frontend_driver_parse_drive_list(info->list, true) != 0) menu_entries_append(info->list, "/", msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 64bd115a84..e6062917ef 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4360,32 +4360,30 @@ static unsigned menu_displaylist_parse_playlists( if (!horizontal) { - bool show_add_content = false; -#if defined(HAVE_XMB) || defined(HAVE_OZONE) const char *menu_ident = menu_driver_ident(); - if ( string_is_equal(menu_ident, "xmb") - || string_is_equal(menu_ident, "ozone")) - show_add_content = settings->bools.menu_content_show_add; - else -#endif - show_add_content = (settings->uints.menu_content_show_add_entry == - MENU_ADD_CONTENT_ENTRY_DISPLAY_PLAYLISTS_TAB); + bool show_add_content = (settings->uints.menu_content_show_add_entry == + MENU_ADD_CONTENT_ENTRY_DISPLAY_PLAYLISTS_TAB); + bool show_history = !string_is_equal(menu_ident, "rgui") + && !(string_is_equal(menu_ident, "glui") && !settings->bools.menu_materialui_show_nav_bar); - if (show_add_content) - if (menu_entries_append(info_list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_ADD_CONTENT_LIST), - MENU_ENUM_LABEL_ADD_CONTENT_LIST, - MENU_SETTING_ACTION, 0, 0, NULL)) - count++; + if (show_history) + { + if (settings->bools.menu_content_show_history) + if (menu_entries_append(info_list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY), + msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY), + MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY, + MENU_SETTING_ACTION, 0, 0, NULL)) + count++; - if (settings->bools.menu_content_show_favorites) - if (menu_entries_append(info_list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES), - msg_hash_to_str(MENU_ENUM_LABEL_GOTO_FAVORITES), - MENU_ENUM_LABEL_GOTO_FAVORITES, - MENU_SETTING_ACTION, 0, 0, NULL)) - count++; + if (settings->bools.menu_content_show_favorites) + if (menu_entries_append(info_list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_FAVORITES), + MENU_ENUM_LABEL_GOTO_FAVORITES, + MENU_SETTING_ACTION, 0, 0, NULL)) + count++; + } if (settings->bools.menu_content_show_images) if (menu_entries_append(info_list, @@ -4413,6 +4411,14 @@ static unsigned menu_displaylist_parse_playlists( count++; #endif + if (show_add_content) + if (menu_entries_append(info_list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_ADD_CONTENT_LIST), + MENU_ENUM_LABEL_ADD_CONTENT_LIST, + MENU_SETTING_ACTION, 0, 0, NULL)) + count++; + #if defined(HAVE_DYNAMIC) if (settings->uints.menu_content_show_contentless_cores != MENU_CONTENTLESS_CORES_DISPLAY_NONE) @@ -4433,7 +4439,6 @@ static unsigned menu_displaylist_parse_playlists( MENU_EXPLORE_TAB, 0, 0, NULL)) count++; #endif - } if (!dir_list_initialize(&str_list, path, NULL, true, @@ -7935,108 +7940,45 @@ unsigned menu_displaylist_build_list( break; case DISPLAYLIST_LOAD_CONTENT_LIST: case DISPLAYLIST_LOAD_CONTENT_SPECIAL: - { - const char *dir_menu_content = settings->paths.directory_menu_content; - bool menu_content_show_favorites = settings->bools.menu_content_show_favorites; + { + const char *menu_ident = menu_driver_ident(); + core_info_list_t *info_list = NULL; - if (!string_is_empty(dir_menu_content)) - if (menu_entries_append(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), - msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), - MENU_ENUM_LABEL_FAVORITES, - MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0, NULL)) - count++; + core_info_get_list(&info_list); - if (menu_content_show_favorites) - if (menu_entries_append(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES), - msg_hash_to_str(MENU_ENUM_LABEL_GOTO_FAVORITES), - MENU_ENUM_LABEL_GOTO_FAVORITES, - MENU_SETTING_ACTION, 0, 0, NULL)) - count++; + if (!string_is_empty(settings->paths.directory_menu_content)) + if (menu_entries_append(list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES), + MENU_ENUM_LABEL_FAVORITES, + MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0, NULL)) + count++; - if (settings->bools.menu_content_show_images) - if (menu_entries_append(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_IMAGES), - msg_hash_to_str(MENU_ENUM_LABEL_GOTO_IMAGES), - MENU_ENUM_LABEL_GOTO_IMAGES, - MENU_SETTING_ACTION, 0, 0, NULL)) - count++; + if (info_list && info_list->info_count > 0) + if (menu_entries_append(list, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), + msg_hash_to_str( + MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), + MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, + MENU_SETTING_ACTION, 0, 0, NULL)) + count++; - if (settings->bools.menu_content_show_music) - if (menu_entries_append(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_MUSIC), - msg_hash_to_str(MENU_ENUM_LABEL_GOTO_MUSIC), - MENU_ENUM_LABEL_GOTO_MUSIC, - MENU_SETTING_ACTION, 0, 0, NULL)) - count++; - -#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) - if (settings->bools.menu_content_show_video) - if (menu_entries_append(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_VIDEO), - msg_hash_to_str(MENU_ENUM_LABEL_GOTO_VIDEO), - MENU_ENUM_LABEL_GOTO_VIDEO, - MENU_SETTING_ACTION, 0, 0, NULL)) - count++; -#endif - -#if defined(HAVE_DYNAMIC) - if (settings->uints.menu_content_show_contentless_cores != - MENU_CONTENTLESS_CORES_DISPLAY_NONE) - if (menu_entries_append(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_CONTENTLESS_CORES), - msg_hash_to_str(MENU_ENUM_LABEL_GOTO_CONTENTLESS_CORES), - MENU_ENUM_LABEL_GOTO_CONTENTLESS_CORES, - MENU_CONTENTLESS_CORES_TAB, 0, 0, NULL)) - count++; -#endif - -#if defined(HAVE_LIBRETRODB) - if (settings->bools.menu_content_show_explore) - if (menu_entries_append(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_EXPLORE), - msg_hash_to_str(MENU_ENUM_LABEL_GOTO_EXPLORE), - MENU_ENUM_LABEL_GOTO_EXPLORE, - MENU_EXPLORE_TAB, 0, 0, NULL)) - count++; -#endif - } - - { - core_info_list_t *info_list = NULL; - core_info_get_list(&info_list); - if (info_list && info_list->info_count > 0) - { - if (menu_entries_append(list, - msg_hash_to_str( - MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST), - msg_hash_to_str( - MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST), - MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, - MENU_SETTING_ACTION, 0, 0, NULL)) - count++; - } - } - - { - bool menu_content_show_playlists = settings->bools.menu_content_show_playlists; - if (menu_content_show_playlists) - if (menu_entries_append(list, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB), - msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB), - MENU_ENUM_LABEL_PLAYLISTS_TAB, - MENU_SETTING_ACTION, 0, 0, NULL)) - count++; - } - - if (frontend_driver_parse_drive_list(list, true) != 0) + if ( !settings->bools.kiosk_mode_enable + && frontend_driver_parse_drive_list(list, true) != 0) if (menu_entries_append(list, "/", msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, MENU_SETTING_ACTION, 0, 0, NULL)) count++; + if (!settings->bools.kiosk_mode_enable) + menu_entries_append(list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS), + MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, + MENU_SETTING_ACTION, 0, 0, NULL); + #if 0 if (menu_entries_append(list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST), @@ -8046,6 +7988,7 @@ unsigned menu_displaylist_build_list( count++; #endif break; + } case DISPLAYLIST_INPUT_MENU_SETTINGS_LIST: { menu_displaylist_build_info_selective_t build_list[] = { @@ -10099,6 +10042,20 @@ unsigned menu_displaylist_build_list( #ifdef HAVE_LAKKA {MENU_ENUM_LABEL_MENU_SHOW_EJECT_DISC, PARSE_ONLY_BOOL, true }, #endif + {MENU_ENUM_LABEL_CONTENT_SHOW_ADD_ENTRY, PARSE_ONLY_UINT, true }, + {MENU_ENUM_LABEL_CONTENT_SHOW_PLAYLISTS, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_CONTENT_SHOW_HISTORY, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_CONTENT_SHOW_FAVORITES, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_CONTENT_SHOW_IMAGES, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_CONTENT_SHOW_MUSIC, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_CONTENT_SHOW_VIDEO, PARSE_ONLY_BOOL, true }, +#if defined(HAVE_DYNAMIC) + {MENU_ENUM_LABEL_CONTENT_SHOW_CONTENTLESS_CORES, PARSE_ONLY_UINT, true }, +#endif + {MENU_ENUM_LABEL_CONTENT_SHOW_EXPLORE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_CONTENT_SHOW_SETTINGS, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_CONTENT_SHOW_SETTINGS_PASSWORD, PARSE_ONLY_STRING, true}, + {MENU_ENUM_LABEL_CONTENT_SHOW_NETPLAY, PARSE_ONLY_BOOL, true }, #ifdef HAVE_ONLINE_UPDATER {MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_MENU_SHOW_CORE_UPDATER, PARSE_ONLY_BOOL, true }, @@ -10118,21 +10075,6 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_MENU_SHOW_RESTART_RETROARCH, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_MENU_SHOW_REBOOT, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_MENU_SHOW_SHUTDOWN, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_SETTINGS, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_SETTINGS_PASSWORD, PARSE_ONLY_STRING, true}, - {MENU_ENUM_LABEL_CONTENT_SHOW_FAVORITES, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_HISTORY, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_IMAGES, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_MUSIC, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_VIDEO, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_NETPLAY, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_ADD, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_ADD_ENTRY, PARSE_ONLY_UINT, true }, -#if defined(HAVE_DYNAMIC) - {MENU_ENUM_LABEL_CONTENT_SHOW_CONTENTLESS_CORES, PARSE_ONLY_UINT, true }, -#endif - {MENU_ENUM_LABEL_CONTENT_SHOW_EXPLORE, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_CONTENT_SHOW_PLAYLISTS, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_TIMEDATE_ENABLE, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_TIMEDATE_STYLE, PARSE_ONLY_UINT, true }, {MENU_ENUM_LABEL_TIMEDATE_DATE_SEPARATOR, PARSE_ONLY_UINT, true }, @@ -14989,12 +14931,19 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, case DISPLAYLIST_MAIN_MENU: menu_entries_clear(info->list); { - rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system; - bool show_add_content = false; -#if defined(HAVE_RGUI) || defined(HAVE_MATERIALUI) || defined(HAVE_OZONE) || defined(HAVE_XMB) - const char *menu_ident = menu_driver_ident(); -#endif - uint32_t flags = runloop_get_flags(); + rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system; + const char *menu_ident = menu_driver_ident(); + uint32_t flags = runloop_get_flags(); + bool show_playlists = settings->bools.menu_content_show_playlists; + bool show_add_content = (settings->uints.menu_content_show_add_entry == + MENU_ADD_CONTENT_ENTRY_DISPLAY_MAIN_TAB) && !settings->bools.kiosk_mode_enable; + bool show_settings = settings->bools.menu_content_show_settings + && ( (string_is_equal(menu_ident, "rgui")) + || (string_is_equal(menu_ident, "glui") && !settings->bools.menu_materialui_show_nav_bar)); + + if ( string_is_equal(menu_ident, "glui") + && settings->bools.menu_materialui_show_nav_bar) + show_playlists = false; if (flags & RUNLOOP_FLAG_CORE_RUNNING) { @@ -15043,11 +14992,24 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, } } - if (settings->bools.menu_content_show_history) - if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, - MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY, - PARSE_ACTION, false) == 0) - count++; + /* Show History and Favorites in menus without sidebar/tabs */ + if ( (string_is_equal(menu_ident, "rgui")) + || (string_is_equal(menu_ident, "glui") && !settings->bools.menu_materialui_show_nav_bar)) + { + if (settings->bools.menu_content_show_history) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, + MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY, + PARSE_ACTION, false) == 0) + count++; + + if (settings->bools.menu_content_show_favorites) + if (menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_FAVORITES), + msg_hash_to_str(MENU_ENUM_LABEL_GOTO_FAVORITES), + MENU_ENUM_LABEL_GOTO_FAVORITES, + MENU_SETTING_ACTION, 0, 0, NULL)) + count++; + } #ifdef HAVE_CDROM if (settings->bools.menu_show_load_disc) @@ -15075,33 +15037,22 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, count++; } #endif /* HAVE_LAKKA */ -#endif +#endif /* HAVE_CDROM */ -#if defined(HAVE_RGUI) || defined(HAVE_MATERIALUI) - if (( string_is_equal(menu_ident, "rgui") - || string_is_equal(menu_ident, "glui")) - && settings->bools.menu_content_show_playlists) + if (show_playlists) if (menu_entries_append(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB), msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB), MENU_ENUM_LABEL_PLAYLISTS_TAB, MENU_SETTING_ACTION, 0, 0, NULL)) count++; -#endif - -#if defined(HAVE_XMB) || defined(HAVE_OZONE) - if ( string_is_equal(menu_ident, "xmb") - || string_is_equal(menu_ident, "ozone")) - show_add_content = settings->bools.menu_content_show_add; - else -#endif - show_add_content = (settings->uints.menu_content_show_add_entry == - MENU_ADD_CONTENT_ENTRY_DISPLAY_MAIN_TAB); if (show_add_content) - if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, + if (menu_entries_append(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_ADD_CONTENT_LIST), MENU_ENUM_LABEL_ADD_CONTENT_LIST, - PARSE_ACTION, false) == 0) + MENU_SETTING_ACTION, 0, 0, NULL)) count++; #ifdef HAVE_NETWORKING @@ -15110,64 +15061,117 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, MENU_ENUM_LABEL_NETPLAY, PARSE_ACTION, false) == 0) count++; -#endif + #ifdef HAVE_ONLINE_UPDATER - if (settings->bools.menu_show_online_updater) + if ( settings->bools.menu_show_online_updater + && !settings->bools.kiosk_mode_enable) if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, MENU_ENUM_LABEL_ONLINE_UPDATER, PARSE_ACTION, false) == 0) count++; -#endif +#endif /* HAVE_ONLINE_UPDATER */ +#endif /* HAVE_NETWORKING */ + #ifdef HAVE_MIST - if (settings->bools.menu_show_core_manager_steam) + if ( settings->bools.menu_show_core_manager_steam + && !settings->bools.kiosk_mode_enable) if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST, PARSE_ACTION, false) == 0) count++; #endif - if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, + + if (show_settings) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, MENU_ENUM_LABEL_SETTINGS, PARSE_ACTION, false) == 0) - count++; + count++; + + if ( !settings->bools.menu_content_show_settings + && !string_is_empty(settings->paths.menu_content_show_settings_password)) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS, + PARSE_ACTION, + false) == 0) + count++; + + if ( settings->bools.kiosk_mode_enable + && !string_is_empty(settings->paths.kiosk_mode_password)) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE, + PARSE_ACTION, + false) == 0) + count++; + if (settings->bools.menu_show_information) if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, MENU_ENUM_LABEL_INFORMATION_LIST, PARSE_ACTION, false) == 0) count++; + #ifdef HAVE_CONFIGFILE - if (settings->bools.menu_show_configurations) + if ( settings->bools.menu_show_configurations + && !settings->bools.kiosk_mode_enable) if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, MENU_ENUM_LABEL_CONFIGURATIONS_LIST, PARSE_ACTION, false) == 0) count++; #endif +#ifdef HAVE_QT + if (settings->bools.desktop_menu_enable) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_SHOW_WIMP, + PARSE_ACTION, + false) == 0) + count++; +#endif + +#if defined(HAVE_LIBNX) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_SWITCH_CPU_PROFILE, + PARSE_ACTION, false) == 0) + count++; +#endif + + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_SWITCH_GPU_PROFILE, + PARSE_ACTION, false) == 0) + count++; + +#if !defined(IOS) if (settings->bools.menu_show_restart_retroarch) - if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, - MENU_ENUM_LABEL_RESTART_RETROARCH, - PARSE_ACTION, false) == 0) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_RESTART_RETROARCH, + PARSE_ACTION, false) == 0) count++; if (settings->bools.menu_show_quit_retroarch) - if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, - MENU_ENUM_LABEL_QUIT_RETROARCH, - PARSE_ACTION, false) == 0) - count++; - - if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, - MENU_ENUM_LABEL_SWITCH_GPU_PROFILE, + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( + info->list, + MENU_ENUM_LABEL_QUIT_RETROARCH, PARSE_ACTION, false) == 0) - count++; + count++; +#endif +#if defined(HAVE_LAKKA) if (settings->bools.menu_show_reboot) if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, MENU_ENUM_LABEL_REBOOT, PARSE_ACTION, false) == 0) count++; + if (settings->bools.menu_show_shutdown) if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list, MENU_ENUM_LABEL_SHUTDOWN, PARSE_ACTION, false) == 0) count++; +#endif info->flags |= MD_FLAG_NEED_PUSH; } diff --git a/menu/menu_setting.c b/menu/menu_setting.c index ed08912c25..a62e5d237a 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -19623,29 +19623,6 @@ static bool setting_append_list( SD_FLAG_NONE); #endif -#if defined(HAVE_XMB) || defined(HAVE_OZONE) - if (string_is_equal(settings->arrays.menu_driver, "xmb") || - string_is_equal(settings->arrays.menu_driver, "ozone")) - { - CONFIG_BOOL( - list, list_info, - &settings->bools.menu_content_show_add, - MENU_ENUM_LABEL_CONTENT_SHOW_ADD, - MENU_ENUM_LABEL_VALUE_CONTENT_SHOW_ADD, - DEFAULT_MENU_CONTENT_SHOW_ADD, - MENU_ENUM_LABEL_VALUE_OFF, - MENU_ENUM_LABEL_VALUE_ON, - &group_info, - &subgroup_info, - parent_group, - general_write_handler, - general_read_handler, - SD_FLAG_NONE); - SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_LAKKA_ADVANCED); - } - else -#endif - { CONFIG_UINT( list, list_info, &settings->uints.menu_content_show_add_entry, @@ -19662,8 +19639,6 @@ static bool setting_append_list( &setting_get_string_representation_uint_menu_add_content_entry_display_type; menu_settings_list_current_add_range(list, list_info, 0, MENU_ADD_CONTENT_ENTRY_DISPLAY_LAST-1, 1, true, true); (*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX; - SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_LAKKA_ADVANCED); - } CONFIG_BOOL( list, list_info, diff --git a/msg_hash.h b/msg_hash.h index fb76dfc69a..c195728ee9 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1619,7 +1619,7 @@ enum msg_hash_enums MENU_LABEL(CONTENT_SHOW_VIDEO), MENU_LABEL(CONTENT_SHOW_NETPLAY), MENU_LABEL(CONTENT_SHOW_HISTORY), - MENU_LABEL(CONTENT_SHOW_ADD), + MENU_LABEL(CONTENT_SHOW_ADD), /* Deprecated */ MENU_LABEL(CONTENT_SHOW_ADD_ENTRY), MENU_LABEL(CONTENT_SHOW_PLAYLISTS), MENU_LABEL(CONTENT_SHOW_EXPLORE), From 94d522388086bf52f45d676f5cf17d277b327a27 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Tue, 4 Feb 2025 21:29:20 +0200 Subject: [PATCH 185/574] Random selector Explore View fix (#17518) --- menu/drivers/materialui.c | 24 +----------------------- menu/drivers/ozone.c | 24 +++--------------------- menu/drivers/rgui.c | 28 +++------------------------- menu/drivers/xmb.c | 24 ++---------------------- menu/menu_driver.c | 30 ++++++++++++++++++++++++++++++ menu/menu_driver.h | 3 +++ 6 files changed, 42 insertions(+), 91 deletions(-) diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index e8fe84e9d1..99dec9009d 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -9352,29 +9352,7 @@ static enum menu_action materialui_parse_menu_entry_action( else if ((mui->flags & MUI_FLAG_IS_PLAYLIST) || (mui->flags & MUI_FLAG_IS_EXPLORE_LIST)) { - struct menu_state *menu_st = menu_state_get_ptr(); - size_t selection_start = 0; - size_t selection_total = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0; - size_t selection = menu_st->selection_ptr; - size_t new_selection = selection; - - /* Skip header items (Search Name + Add Additional Filter + Save as View) */ - if (mui->flags & MUI_FLAG_IS_EXPLORE_LIST) - { - menu_entry_t entry; - MENU_ENTRY_INITIALIZE(entry); - menu_entry_get(&entry, 0, 0, NULL, true); - - if (entry.type == MENU_SETTINGS_LAST + 1) - selection_start = 1; - else if (entry.type == FILE_TYPE_RDB) - selection_start = 2; - } - - new_selection = random_range(selection_start, selection_total - 1); - - while (new_selection == selection && selection_start != selection_total - 1) - new_selection = random_range(selection_start, selection_total - 1); + size_t new_selection = menu_playlist_random_selection(selection, mui->flags & MUI_FLAG_IS_EXPLORE_LIST); if (new_selection != selection) { diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index 22d12e3945..06e816aca3 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -8218,27 +8218,9 @@ static enum menu_action ozone_parse_menu_entry_action( else if ((ozone->flags & OZONE_FLAG_IS_PLAYLIST) || (ozone->flags & OZONE_FLAG_IS_EXPLORE_LIST)) { - size_t selection_start = 0; + size_t new_selection = menu_playlist_random_selection(selection, ozone->flags & OZONE_FLAG_IS_EXPLORE_LIST); - /* Skip header items (Search Name + Add Additional Filter + Save as View) */ - if (ozone->flags & OZONE_FLAG_IS_EXPLORE_LIST) - { - menu_entry_t entry; - MENU_ENTRY_INITIALIZE(entry); - menu_entry_get(&entry, 0, 0, NULL, true); - - if (entry.type == MENU_SETTINGS_LAST + 1) - selection_start = 1; - else if (entry.type == FILE_TYPE_RDB) - selection_start = 2; - } - - new_selection = random_range(selection_start, selection_total - 1); - - while (new_selection == (int)selection && selection_start != selection_total - 1) - new_selection = random_range(selection_start, selection_total - 1); - - if (new_selection != (int)selection) + if (new_selection != selection) { menu_st->selection_ptr = new_selection; ozone_selection_changed(ozone, false); @@ -8248,7 +8230,7 @@ static enum menu_action ozone_parse_menu_entry_action( new_action = MENU_ACTION_NOOP; #ifdef HAVE_AUDIOMIXER - if (new_selection != (int)selection) + if (new_selection != selection) audio_driver_mixer_play_scroll_sound(true); #endif break; diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 1319fdef3f..53c13b7b06 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -7989,6 +7989,7 @@ static enum menu_action rgui_parse_menu_entry_action( menu_entry_t *entry, enum menu_action action) { + struct menu_state *menu_st = menu_state_get_ptr(); enum menu_action new_action = action; /* Scan user inputs */ @@ -8056,7 +8057,6 @@ static enum menu_action rgui_parse_menu_entry_action( if (string_is_equal(rgui->menu_title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MAIN_MENU))) { - struct menu_state *menu_st = menu_state_get_ptr(); /* Jump to first item on Main Menu */ menu_st->selection_ptr = 0; new_action = MENU_ACTION_NOOP; @@ -8112,7 +8112,6 @@ static enum menu_action rgui_parse_menu_entry_action( case MENU_ACTION_SCAN: if (rgui->flags & RGUI_FLAG_IS_PLAYLISTS_TAB) { - struct menu_state *menu_st = menu_state_get_ptr(); size_t selection_total = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0; size_t selection = menu_st->selection_ptr; size_t new_selection = random_range(0, selection_total - 1); @@ -8145,29 +8144,8 @@ static enum menu_action rgui_parse_menu_entry_action( else if ((rgui->flags & RGUI_FLAG_IS_PLAYLIST) || (rgui->flags & RGUI_FLAG_IS_EXPLORE_LIST)) { - struct menu_state *menu_st = menu_state_get_ptr(); - size_t selection_start = 0; - size_t selection_total = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0; - size_t selection = menu_st->selection_ptr; - size_t new_selection = selection; - - /* Skip header items (Search Name + Add Additional Filter + Save as View) */ - if (rgui->flags & RGUI_FLAG_IS_EXPLORE_LIST) - { - menu_entry_t entry; - MENU_ENTRY_INITIALIZE(entry); - menu_entry_get(&entry, 0, 0, NULL, true); - - if (entry.type == MENU_SETTINGS_LAST + 1) - selection_start = 1; - else if (entry.type == FILE_TYPE_RDB) - selection_start = 2; - } - - new_selection = random_range(selection_start, selection_total - 1); - - while (new_selection == selection && selection_start != selection_total - 1) - new_selection = random_range(selection_start, selection_total - 1); + size_t selection = menu_st->selection_ptr; + size_t new_selection = menu_playlist_random_selection(selection, rgui->flags & RGUI_FLAG_IS_EXPLORE_LIST); if (new_selection != selection) { diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index e965c9bb46..717e489155 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -5591,28 +5591,8 @@ static enum menu_action xmb_parse_menu_entry_action( else if ((xmb->is_playlist) || (xmb->is_explore_list)) { - size_t selection_start = 0; - size_t selection_total = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0; - size_t selection = menu_st->selection_ptr; - size_t new_selection = selection; - - /* Skip header items (Search Name + Add Additional Filter + Save as View) */ - if (xmb->is_explore_list) - { - menu_entry_t entry; - MENU_ENTRY_INITIALIZE(entry); - menu_entry_get(&entry, 0, 0, NULL, true); - - if (entry.type == MENU_SETTINGS_LAST + 1) - selection_start = 1; - else if (entry.type == FILE_TYPE_RDB) - selection_start = 2; - } - - new_selection = random_range(selection_start, selection_total - 1); - - while (new_selection == selection && selection_start != selection_total - 1) - new_selection = random_range(selection_start, selection_total - 1); + size_t selection = menu_st->selection_ptr; + size_t new_selection = menu_playlist_random_selection(selection, xmb->is_explore_list); if (new_selection != selection) { diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 4633bf36a5..b5bf94534e 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -21,6 +21,7 @@ #endif #include +#include #include #include #include @@ -8106,3 +8107,32 @@ void menu_update_runahead_mode(void) menu_st->runahead_mode = MENU_RUNAHEAD_MODE_OFF; } #endif + +/* Common method for ignoring specifics while picking random playlist items. */ +size_t menu_playlist_random_selection(size_t selection, bool is_explore_list) +{ + struct menu_state *menu_st = menu_state_get_ptr(); + size_t selection_start = 0; + size_t selection_total = menu_st->entries.list ? MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size : 0; + size_t new_selection = selection; + + /* Skip header items (Search Name + Add Additional Filter + Save as View + Delete this View) */ + if (is_explore_list) + { + menu_entry_t entry; + MENU_ENTRY_INITIALIZE(entry); + menu_entry_get(&entry, 0, 0, NULL, true); + + if (entry.type == MENU_SETTINGS_LAST + 1 || entry.type == FILE_TYPE_PLAIN) + selection_start = 1; + else if (entry.type == FILE_TYPE_RDB) + selection_start = 2; + } + + new_selection = random_range(selection_start, selection_total - 1); + + while (new_selection == selection && selection_start != selection_total - 1) + new_selection = random_range(selection_start, selection_total - 1); + + return new_selection; +} diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 56db326ec2..20ab4a9960 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -745,6 +745,9 @@ bool menu_input_key_bind_set_mode( void menu_update_runahead_mode(void); #endif +size_t menu_playlist_random_selection( + size_t selection, bool is_explore_list); + extern const menu_ctx_driver_t *menu_ctx_drivers[]; extern menu_ctx_driver_t menu_ctx_ozone; From 998200793d0a89c6561bc799ea4a65c0952d12d8 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Wed, 5 Feb 2025 08:19:50 +0200 Subject: [PATCH 186/574] File Browser settings + Directory list cleanup (#17519) --- intl/msg_hash_us.h | 22 +++++++++++++--------- menu/cbs/menu_cbs_sublabel.c | 4 ++++ menu/menu_displaylist.c | 26 ++++++++++++++------------ 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 799d5f467e..f31243d012 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -5053,14 +5053,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filter files being shown in File Browser by supported extensions." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Use Built-In Media Player" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filter by Current Core" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filter files being shown in File Browser by current core." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Remember Last Used Start Directory" @@ -5069,6 +5069,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Open File Browser at the last used location when loading content from the Start Directory. Note: Location will be reset to default upon restarting RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Use Built-In Media Player" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Use Built-In Image Viewer" + ) /* Settings > Frame Throttle */ @@ -8300,7 +8308,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "File Browser" + "Start Directory" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -13422,10 +13430,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Kbd" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Use Built-In Image Viewer" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Max Swapchain Images" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 8fdaa15f37..0bfc17f019 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -846,6 +846,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_bluetooth_driver, MENU_ #endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_wifi_driver, MENU_ENUM_SUBLABEL_WIFI_DRIVER) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_filter_supported_extensions, MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_filter_by_current_core, MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_wallpaper, MENU_ENUM_SUBLABEL_MENU_WALLPAPER) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_dynamic_wallpaper, MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_audio_device, MENU_ENUM_SUBLABEL_AUDIO_DEVICE) @@ -3899,6 +3900,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_filter_supported_extensions); break; + case MENU_ENUM_LABEL_FILTER_BY_CURRENT_CORE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_filter_by_current_core); + break; case MENU_ENUM_LABEL_BLUETOOTH_DRIVER: #ifdef HAVE_BLUETOOTH BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_bluetooth_driver); diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index e6062917ef..a869ed24a8 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -10099,12 +10099,14 @@ unsigned menu_displaylist_build_list( case DISPLAYLIST_MENU_FILE_BROWSER_SETTINGS_LIST: { menu_displaylist_build_info_t build_list[] = { + {MENU_ENUM_LABEL_RGUI_BROWSER_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_CACHE_DIRECTORY, PARSE_ONLY_DIR}, {MENU_ENUM_LABEL_SHOW_HIDDEN_FILES, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, PARSE_ONLY_BOOL}, - {MENU_ENUM_LABEL_USE_BUILTIN_PLAYER, PARSE_ONLY_BOOL}, - {MENU_ENUM_LABEL_USE_BUILTIN_IMAGE_VIEWER, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_FILTER_BY_CURRENT_CORE, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_USE_LAST_START_DIRECTORY, PARSE_ONLY_BOOL}, + {MENU_ENUM_LABEL_USE_BUILTIN_PLAYER, PARSE_ONLY_BOOL}, + {MENU_ENUM_LABEL_USE_BUILTIN_IMAGE_VIEWER, PARSE_ONLY_BOOL}, }; for (i = 0; i < ARRAY_SIZE(build_list); i++) @@ -11290,19 +11292,22 @@ unsigned menu_displaylist_build_list( case DISPLAYLIST_DIRECTORY_SETTINGS_LIST: { menu_displaylist_build_info_t build_list[] = { - {MENU_ENUM_LABEL_SYSTEM_DIRECTORY, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_CORE_ASSETS_DIRECTORY, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_ASSETS_DIRECTORY, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_DYNAMIC_WALLPAPERS_DIRECTORY, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY, PARSE_ONLY_DIR}, {MENU_ENUM_LABEL_RGUI_BROWSER_DIRECTORY, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_RGUI_CONFIG_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_CACHE_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_SYSTEM_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_SAVEFILE_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_SAVESTATE_DIRECTORY, PARSE_ONLY_DIR}, {MENU_ENUM_LABEL_LIBRETRO_DIR_PATH, PARSE_ONLY_DIR}, {MENU_ENUM_LABEL_LIBRETRO_INFO_PATH, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_CONTENT_DATABASE_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_RGUI_CONFIG_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_CORE_ASSETS_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_ASSETS_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY, PARSE_ONLY_DIR}, + {MENU_ENUM_LABEL_DYNAMIC_WALLPAPERS_DIRECTORY, PARSE_ONLY_DIR}, #ifdef HAVE_CHEATS {MENU_ENUM_LABEL_CHEAT_DATABASE_PATH, PARSE_ONLY_DIR}, #endif + {MENU_ENUM_LABEL_CONTENT_DATABASE_DIRECTORY, PARSE_ONLY_DIR}, #ifdef HAVE_VIDEO_FILTER {MENU_ENUM_LABEL_VIDEO_FILTER_DIR, PARSE_ONLY_DIR}, #endif @@ -11326,9 +11331,6 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_CONTENT_MUSIC_HISTORY_DIRECTORY, PARSE_ONLY_DIR}, {MENU_ENUM_LABEL_CONTENT_VIDEO_HISTORY_DIRECTORY, PARSE_ONLY_DIR}, {MENU_ENUM_LABEL_RUNTIME_LOG_DIRECTORY, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_SAVEFILE_DIRECTORY, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_SAVESTATE_DIRECTORY, PARSE_ONLY_DIR}, - {MENU_ENUM_LABEL_CACHE_DIRECTORY, PARSE_ONLY_DIR}, {MENU_ENUM_LABEL_LOG_DIR, PARSE_ONLY_DIR}, }; From 187463d355b0e2eb141bea6e75f2e5d224c28444 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 6 Feb 2025 00:14:50 +0000 Subject: [PATCH 187/574] Fetch translations from Crowdin --- intl/msg_hash_ar.h | 14 +++++++------- intl/msg_hash_ast.h | 10 +++++----- intl/msg_hash_be.h | 24 ++++++++++++++---------- intl/msg_hash_bg.h | 2 +- intl/msg_hash_ca.h | 10 +++++----- intl/msg_hash_chs.h | 18 +++++++++--------- intl/msg_hash_cht.h | 16 ++++++++-------- intl/msg_hash_cs.h | 18 +++++++++--------- intl/msg_hash_cy.h | 4 ++++ intl/msg_hash_da.h | 2 +- intl/msg_hash_de.h | 22 +++++++++++++--------- intl/msg_hash_el.h | 14 +++++++------- intl/msg_hash_es.h | 26 +++++++++++++++----------- intl/msg_hash_fa.h | 2 +- intl/msg_hash_fi.h | 18 +++++++++--------- intl/msg_hash_fr.h | 22 +++++++++++++--------- intl/msg_hash_gl.h | 18 +++++++++--------- intl/msg_hash_he.h | 2 +- intl/msg_hash_hr.h | 2 +- intl/msg_hash_hu.h | 18 +++++++++--------- intl/msg_hash_id.h | 6 +++++- intl/msg_hash_it.h | 22 +++++++++++++--------- intl/msg_hash_ja.h | 18 +++++++++--------- intl/msg_hash_ko.h | 18 +++++++++--------- intl/msg_hash_nl.h | 10 +++++----- intl/msg_hash_no.h | 10 +++++----- intl/msg_hash_pl.h | 18 +++++++++--------- intl/msg_hash_pt_br.h | 18 +++++++++--------- intl/msg_hash_pt_pt.h | 10 +++++----- intl/msg_hash_ru.h | 22 +++++++++++++--------- intl/msg_hash_sk.h | 2 +- intl/msg_hash_sr.h | 2 +- intl/msg_hash_sv.h | 18 +++++++++--------- intl/msg_hash_tr.h | 22 +++++++++++++--------- intl/msg_hash_uk.h | 18 +++++++++--------- intl/msg_hash_val.h | 2 +- intl/msg_hash_vn.h | 2 +- intl/progress.h | 8 ++++---- 38 files changed, 262 insertions(+), 226 deletions(-) diff --git a/intl/msg_hash_ar.h b/intl/msg_hash_ar.h index 6945b64f46..f30ca0a5a0 100644 --- a/intl/msg_hash_ar.h +++ b/intl/msg_hash_ar.h @@ -3093,13 +3093,17 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "تصفية ملحقات غير معروفة" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "تصفية حسب النواة الحالية" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, "استخدام مشغل الوسائط المدمج" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, - "تصفية حسب النواة الحالية" + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "استخدام عارض الصور المدمج" ) /* Settings > Frame Throttle */ @@ -4296,7 +4300,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "مستعرض الملفات" + "مجلد البداية" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, @@ -7450,10 +7454,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "المستخدم" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "استخدام عارض الصور المدمج" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "يلغي مشغل الفيديو أن يستخدم صراحة وضع التخزين المؤقت المحدد." diff --git a/intl/msg_hash_ast.h b/intl/msg_hash_ast.h index e6e56d1c20..b287b952cb 100644 --- a/intl/msg_hash_ast.h +++ b/intl/msg_hash_ast.h @@ -1573,6 +1573,10 @@ MSG_HASH( /* Settings > File Browser */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Usar el visor d'imáxenes integráu" + ) /* Settings > Frame Throttle */ @@ -2320,7 +2324,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Restolador de ficheros" + "Direutoriu inicial" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, @@ -3734,10 +3738,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Usuariu" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Usar el visor d'imáxenes integráu" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_START, "Aniciar" diff --git a/intl/msg_hash_be.h b/intl/msg_hash_be.h index 6b22d4746c..eb52ef4310 100644 --- a/intl/msg_hash_be.h +++ b/intl/msg_hash_be.h @@ -4995,16 +4995,16 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Фільтраваць файлы, якія паказваюцца файлавым браўзерам, па пашырэннях, якія падтрымліваюцца." - ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Выкарыстанне ўбудаванага медыяпрайгравальніка" + "Фільтраваць паказ файлаў файлавым браўзерам паводле падтрымкі пашырэння." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Фільтраванне па бягучаму ядру" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Фільтраваць паказ файлаў файлавым браўзерам па бягучаму ядру." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Памятаць апошні выкарыстаны пачатковы каталог" @@ -5013,6 +5013,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Адкрываць файлавы браўзер на апошнім выкарыстаным месцы пры загрузцы змесціва з пачатковага каталога. Заўвага: месца будзе скінута да прадвызначанага пры перазапуску RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Выкарыстанне ўбудаванага медыяпрайгравальніка" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Убудаваны прагляд малюнкаў" + ) /* Settings > Frame Throttle */ @@ -8204,7 +8212,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Файлавы браўзер" + "Пачатковы каталог" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12726,10 +12734,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Клавіятура" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Убудаваны прагляд малюнкаў" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Максімум малюнкаў у свопчэйне" diff --git a/intl/msg_hash_bg.h b/intl/msg_hash_bg.h index cb0f9da4ff..fe6018ec01 100644 --- a/intl/msg_hash_bg.h +++ b/intl/msg_hash_bg.h @@ -1236,7 +1236,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Разглеждане на файловете" + "Начална Директория" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, diff --git a/intl/msg_hash_ca.h b/intl/msg_hash_ca.h index 647e8500bc..f1d2e74b63 100644 --- a/intl/msg_hash_ca.h +++ b/intl/msg_hash_ca.h @@ -4157,6 +4157,10 @@ MSG_HASH( /* Settings > File Browser */ +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Fes servir el visualitzador d’imatges integrat" + ) /* Settings > Frame Throttle */ @@ -5860,7 +5864,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navegador de fitxers" + "Directori d'inici" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, @@ -8670,10 +8674,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Teclat" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Fes servir el visualitzador d’imatges integrat" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WAITABLE_SWAPCHAINS, "Sincronització rígida de la CPU i GPU. Redueix la latència a cost de rendiment." diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index a3b54bc760..537016475f 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -4805,10 +4805,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "按支持的扩展名过滤文件管理器中显示的文件。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "使用内建媒体播放器" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "过滤当前核心支持文件" @@ -4821,6 +4817,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "在起始目录加载游戏时,于最后打开的位置开启文件浏览器。注:重启全能模拟器后,此位置将重置。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "使用内建媒体播放器" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "使用内建图像查看器" + ) /* Settings > Frame Throttle */ @@ -8008,7 +8012,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "文件浏览器" + "开始文件夹" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12478,10 +12482,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "键盘" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "使用内建图像查看器" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "最大的交换链图像" diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index ba2993618c..22e1e63608 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -4829,10 +4829,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "在檔案瀏覽器中只顯示支援的檔案。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "使用內建的媒體播放器" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "只顯示目前核心支援格式" @@ -4845,6 +4841,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "記住本次執行「開始資料夾」最後載入的檔案位置。 注意: 重新啟動後會還原為預設位置。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "使用內建的媒體播放器" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "使用內建的圖像瀏覽器" + ) /* Settings > Frame Throttle */ @@ -12602,10 +12606,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "鍵盤" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "使用內建的圖像瀏覽器" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "最大交換鏈結圖像" diff --git a/intl/msg_hash_cs.h b/intl/msg_hash_cs.h index 81e7d0234d..2f4b3de627 100644 --- a/intl/msg_hash_cs.h +++ b/intl/msg_hash_cs.h @@ -4633,10 +4633,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtrování neznámých rozšíření" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Použití vestavěného mediálního přehrávače" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrování podle aktuálního jádra" @@ -4645,6 +4641,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Zapamatovat si naposledy použitý úvodní adresář" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Použití vestavěného mediálního přehrávače" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Použít vestavěný prohlížeč obrázků" + ) /* Settings > Frame Throttle */ @@ -7640,7 +7644,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Správce souborů" + "Startovací adresář" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, @@ -12030,10 +12034,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Uživatel" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Použít vestavěný prohlížeč obrázků" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Max. stabilizace snímku" diff --git a/intl/msg_hash_cy.h b/intl/msg_hash_cy.h index a8fd2fdba4..65d4b5ca60 100644 --- a/intl/msg_hash_cy.h +++ b/intl/msg_hash_cy.h @@ -1286,6 +1286,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, "Lawrlwythiadau" ) +MSG_HASH( /* FIXME Not RGUI specific */ + MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, + "Cyfeiriadur Cychwynnol" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, "Rhestri Chwarae" diff --git a/intl/msg_hash_da.h b/intl/msg_hash_da.h index 75841650b1..a81b503d25 100644 --- a/intl/msg_hash_da.h +++ b/intl/msg_hash_da.h @@ -1216,7 +1216,7 @@ MSG_HASH( MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Filhåndtering" + "Start Mappe" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 64aa61e575..4714af9433 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -4877,14 +4877,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Im Dateibrowser nur Dateien mit unterstützten Dateitypen anzeigen." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Eingebauten Mediaplayer verwenden" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Nach aktuellem Core filtern" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Die im Dateibrowser anzuzeigenden Dateien durch aktuellen Core filtern." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Letztes Startverzeichnis merken" @@ -4893,6 +4893,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Den Dateibrowser im zuletzt verwendeten Pfad öffnen, wenn Inhalte aus dem Startverzeichnis geladen werden. Hinweis: Der Pfad wird beim Neustart von RetroArch zurückgesetzt." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Eingebauten Mediaplayer verwenden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Integrierten Bildbetrachter verwenden" + ) /* Settings > Frame Throttle */ @@ -8032,7 +8040,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Dateibrowser" + "Startverzeichnis" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12342,10 +12350,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Tastatur" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Integrierten Bildbetrachter verwenden" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Maximale Anzahl von Zwischenbildern" diff --git a/intl/msg_hash_el.h b/intl/msg_hash_el.h index 4b60c8c01b..122a9d3efc 100644 --- a/intl/msg_hash_el.h +++ b/intl/msg_hash_el.h @@ -2705,13 +2705,17 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Φιλτράρισμα άγνωστων επεκτάσεων" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Φιλτράρισμα με βάση τον τρέχων πυρήνα" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, "Χρήση Ενσωματωμένου Αναπαραγωγέα Πολυμέσων Use Builtin Media Player" ) MSG_HASH( - MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, - "Φιλτράρισμα με βάση τον τρέχων πυρήνα" + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Χρήση Ενσωματωμένου Προβολέα Εικόνων" ) /* Settings > Frame Throttle */ @@ -3352,7 +3356,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Περιηγητής Αρχείων" + "Ευρετήριο έναρξης" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, @@ -4990,10 +4994,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Χρήστης" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Χρήση Ενσωματωμένου Προβολέα Εικόνων" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WAITABLE_SWAPCHAINS, "Σκληρός συγχρονισμός επεξεργαστή και κάρτας γραφικών. Μειώνει την καθυστέρηση με τίμημα την επίδοση." diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index cbbab40ead..3f69905b4c 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -2052,7 +2052,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_SUBFRAMES, - "Inserta fotogramas adicionales entre fotogramas para cualquier efecto shader que esté diseñado para ejecutarse más rápido que la velocidad del contenido. Solo use la opción designada para la frecuencia de actualización de la pantalla actual. No debe usarse en frecuencias de actualización que no sean múltiplos de 60 Hz, como 144 Hz, 165 Hz, etc. No combine con Intervalo de intercambio superior a 1, BFI, Retraso de fotogramas o Sincronizar con la velocidad de fotogramas exacta del contenid[...]" + "Introduce uno o varios fotogramas adicionales para cualquier efecto de shaders pensado para una velocidad de actualización superior a la del contenido. Utiliza únicamente la opción designada para la frecuencia de actualización actual de tu monitor. No se debe utilizar con frecuencias que no sean múltiplos de 60 Hz, como 144 Hz, 165 Hz, etc. No combinar con un intervalo de intercambio de VSync superior a 1, con inserción de fotogramas negros, con el retraso de fotogramas o con Sincroniza[...]" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_SUBFRAMES_VALUE_120, @@ -2797,7 +2797,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY_AUTO, - "Ajusta el 'Retraso de fotogramas' efectivo de forma dinámica." + "Ajusta el retraso de fotogramas real de forma dinámica." ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_FRAME_DELAY_AUTO, @@ -4985,14 +4985,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Muestra en el explorador de archivos únicamente a aquellos archivos que tengan extensiones conocidas." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usar visor de medios integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrar por núcleo actual" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Muestra en el explorador de archivos únicamente los archivos relacionados con el núcleo actual." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Recordar el último directorio usado" @@ -5001,6 +5001,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Abre el explorador de archivos en el último directorio usado al cargar contenidos desde el directorio inicial. Nota: la posición volverá a su valor predeterminado al reiniciar RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usar visor de medios integrado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Usar visor de imágenes integrado" + ) /* Settings > Frame Throttle */ @@ -8184,7 +8192,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Explorador de archivos" + "Directorio inicial" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12662,10 +12670,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Teclado" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Usar visor de imágenes integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Máximo de imágenes en swap chain" diff --git a/intl/msg_hash_fa.h b/intl/msg_hash_fa.h index 35aa4f274e..ce07c2acb8 100644 --- a/intl/msg_hash_fa.h +++ b/intl/msg_hash_fa.h @@ -2972,7 +2972,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "مرورگر فایل" + "مسیر شروع" ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, diff --git a/intl/msg_hash_fi.h b/intl/msg_hash_fi.h index 95200df310..e1c5aa95f8 100644 --- a/intl/msg_hash_fi.h +++ b/intl/msg_hash_fi.h @@ -4361,10 +4361,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Suodata tiedostoja tiedostoselaimessa tuettujen tiedostopäätteiden mukaan." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Käytä sisäänrakennettua mediasoitinta" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Suodata nykyisen ytimen mukaan" @@ -4377,6 +4373,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Avaa tiedostoselain viimeksi käytetyssä sijainnissa, kun lataat sisältöä aloitushakemistosta. Huom: sijainti palautetaan oletusarvoon RetroArchin uudelleenkäynnistyessä." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Käytä sisäänrakennettua mediasoitinta" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Käytä sisäänrakennettua kuvankatselinta" + ) /* Settings > Frame Throttle */ @@ -7116,7 +7120,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Tiedostoselain" + "Aloituskansio" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, @@ -11458,10 +11462,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Näp" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Käytä sisäänrakennettua kuvankatselinta" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Määrää videoajurin käyttämään yksiselitteisesti määritettyä puskurointitilaa." diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index 1592cfbb2b..7252af1aa7 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -4945,14 +4945,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtrer les fichiers affichés dans le navigateur de fichiers selon les extensions prises en charge." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Utiliser le lecteur média intégré" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrer par cœur actif" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtrer les fichiers affichés dans le navigateur de fichiers selon le cœur actuel." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Recharger le dernier dossier de démarrage utilisé" @@ -4961,6 +4961,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Ouvrir le navigateur de fichiers au dernier emplacement utilisé lors du chargement du contenu depuis le dossier de démarrage. Remarque : L'emplacement sera réinitialisé par défaut au redémarrage de RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Utiliser le lecteur média intégré" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Utiliser le lecteur d'images intégré" + ) /* Settings > Frame Throttle */ @@ -8140,7 +8148,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navigateur de fichiers " + "Dossier de démarrage" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12626,10 +12634,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Clavier" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Utiliser le lecteur d'images intégré" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Nombre d'images max en mémoire tampon " diff --git a/intl/msg_hash_gl.h b/intl/msg_hash_gl.h index efbe555e66..31fe3db670 100644 --- a/intl/msg_hash_gl.h +++ b/intl/msg_hash_gl.h @@ -4925,10 +4925,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtra os ficheiros que se mostran no Explorador de ficheiros polas extensións compatibles." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usa o reprodutor multimedia integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrar por núcleo actual" @@ -4941,6 +4937,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Abre o explorador de ficheiros na última localización utilizada ao cargar contido do directorio de inicio. Nota: a localización restablecerase ao valor predeterminado ao reiniciar RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usa o reprodutor multimedia integrado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Use o visor de imaxes integrado" + ) /* Settings > Frame Throttle */ @@ -8060,7 +8064,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Explorador de ficheiros" + "Directorio inicial" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12498,10 +12502,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Usuario" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Use o visor de imaxes integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Max Swapchain Imaxes" diff --git a/intl/msg_hash_he.h b/intl/msg_hash_he.h index 4a892a32b7..93b1008112 100644 --- a/intl/msg_hash_he.h +++ b/intl/msg_hash_he.h @@ -1576,7 +1576,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "סייר קבצים" + "תיקיית ההתחלה" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, diff --git a/intl/msg_hash_hr.h b/intl/msg_hash_hr.h index 47212ec322..c7fc8634b4 100644 --- a/intl/msg_hash_hr.h +++ b/intl/msg_hash_hr.h @@ -1268,7 +1268,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Preglednik datoteka" + "Početna mapa" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, diff --git a/intl/msg_hash_hu.h b/intl/msg_hash_hu.h index 47898feabc..8a236f8bce 100644 --- a/intl/msg_hash_hu.h +++ b/intl/msg_hash_hu.h @@ -4977,10 +4977,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "A nem támogatott kiterjesztésű fájlok nem jelennek meg a Fájlböngészőben." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "A beépített médialejátszó használata" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Szűrés az aktuális mag szerint" @@ -4993,6 +4989,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "A Fájlböngésző az utoljára használt helyen nyílik meg a kezdő könyvtárból töltésnél. A RetroArch újraindításakor visszaáll az alapállapotra." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "A beépített médialejátszó használata" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "A beépített képnézegető használata" + ) /* Settings > Frame Throttle */ @@ -8176,7 +8180,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Fájlkezelő" + "Kezdő könyvtár" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12418,10 +12422,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Bill" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "A beépített képnézegető használata" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Swapchain képek maximális száma" diff --git a/intl/msg_hash_id.h b/intl/msg_hash_id.h index 05320e62a9..57cf269c7d 100644 --- a/intl/msg_hash_id.h +++ b/intl/msg_hash_id.h @@ -2773,6 +2773,10 @@ MSG_HASH( /* Settings > File Browser */ +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Menyaring berkas sesuai Core saat ini di Peramban Berkas." + ) /* Settings > Frame Throttle */ @@ -3316,7 +3320,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Perambah Berkas" + "Direktori Awal" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 2bee247f58..3ac2c08c7f 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -4905,14 +4905,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtra i file che vengono mostrati nel File Browser per le estensioni supportate." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usa Lettore Multimediale Integrato" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtra per core corrente" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtra i file mostrati in Esplora file per nucleo corrente." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Ricorda L'Ultima Directory Di Avvio Usata" @@ -4921,6 +4921,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Aprire l'esplorazione file all'ultima posizione usata durante il caricamento del contenuto dalla cartella di avvio. Nota: la posizione sarà ripristinata a quella predefinita dopo il riavvio di RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usa Lettore Multimediale Integrato" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Usa Visualizzatore Di Immagini Integrato" + ) /* Settings > Frame Throttle */ @@ -8092,7 +8100,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Esplorazione File" + "Cartella predefinita" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12478,10 +12486,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Utente" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Usa Visualizzatore Di Immagini Integrato" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Massimo di immagini in swapchain" diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 9535bb9d74..b387dc776c 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -4865,10 +4865,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "ファイルブラウザに表示されるファイルを対応する拡張子でフィルタリングします。" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "内蔵メディアプレイヤーを使用" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "現在のコアでフィルター" @@ -4881,6 +4877,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "コンテンツをロードする際に、最後に使用したディレクトリでファイルブラウザを開きます。注意: 再起動すると場所はデフォルトにリセットされます。" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "内蔵メディアプレイヤーを使用" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "内蔵画像ビューアを使用" + ) /* Settings > Frame Throttle */ @@ -8040,7 +8044,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "ファイルブラウザ" + "開始ディレクトリ" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12462,10 +12466,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "キーボード" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "内蔵画像ビューアを使用" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "最大スワップチェーンイメージ" diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index 2dc5125697..550313f0b2 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -5021,10 +5021,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "파일 탐색기에서 지원되는 확장자의 파일만 표시합니다." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "내장 미디어 플레이어 사용" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "현재 코어에 따라 필터" @@ -5037,6 +5033,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "시작 디렉토리에서 콘텐츠를 불러올 경우 최근 사용한 위치에서 파일 탐색기를 시작합니다. 참고: RetroArch를 재시작하면 기본 위치로 초기화 됩니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "내장 미디어 플레이어 사용" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "내장 이미지 뷰어 사용" + ) /* Settings > Frame Throttle */ @@ -8228,7 +8232,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "파일 탐색기" + "시작 디렉토리" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12758,10 +12762,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "키보드" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "내장 이미지 뷰어 사용" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "최대 스왑체인 이미지" diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index cd8e2a814d..33ee31a299 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -3877,10 +3877,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtreer onbekende extensies" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Gebruik ingebouwde media speler" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filter op Huidige Core" @@ -3889,6 +3885,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Onthoud de Laatst Gebruikte Startmap" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Gebruik ingebouwde media speler" + ) /* Settings > Frame Throttle */ @@ -5152,7 +5152,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Bestandsbeheer" + "Favorieten" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, diff --git a/intl/msg_hash_no.h b/intl/msg_hash_no.h index 03c1cb002a..824469be34 100644 --- a/intl/msg_hash_no.h +++ b/intl/msg_hash_no.h @@ -2425,10 +2425,6 @@ MSG_HASH( /* Settings > File Browser */ -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Bruk innebygd mediespiller" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrer etter gjeldende kjerne" @@ -2437,6 +2433,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Husk sist brukte startmappe" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Bruk innebygd mediespiller" + ) /* Settings > Frame Throttle */ @@ -3424,7 +3424,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Filutforsker" + "Startmappe" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index 461855fb75..72a7d15774 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -4429,10 +4429,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtruj pliki wyświetlane w przeglądarce plików przez obsługiwane rozszerzenia." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Użyj wbudowanego odtwarzacza multimedialnego" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtruj według bieżącego rdzenia" @@ -4445,6 +4441,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Otwórz przeglądarkę plików w ostatnio używanej lokalizacji podczas ładowania zawartości z katalogu startowego. Uwaga: Lokalizacja zostanie przywrócona do wartości domyślnych po ponownym uruchomieniu RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Użyj wbudowanego odtwarzacza multimedialnego" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Użyj wbudowanej przeglądarki zdjęć" + ) /* Settings > Frame Throttle */ @@ -7236,7 +7240,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Przeglądarka plików" + "Katalog startowy" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, @@ -11250,10 +11254,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Użytkownik" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Użyj wbudowanej przeglądarki zdjęć" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Informuje sterownik wideo, aby jawnie użył określonego trybu buforowania." diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 53ee27625f..7a464264a5 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -4213,10 +4213,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtrar extensões desconhecidas" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Utilizar o reprodutor de mídia integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrar por núcleo atual" @@ -4225,6 +4221,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Lembrar do último diretório usado" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Utilizar o reprodutor de mídia integrado" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Utilizar o visualizador de imagem integrado" + ) /* Settings > Frame Throttle */ @@ -6868,7 +6872,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navegador de arquivos" + "Diretório inicial" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, @@ -10918,10 +10922,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Usuário" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Utilizar o visualizador de imagem integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Máximo de imagens na cadeia de troca" diff --git a/intl/msg_hash_pt_pt.h b/intl/msg_hash_pt_pt.h index a2d102e020..110fcb57c1 100644 --- a/intl/msg_hash_pt_pt.h +++ b/intl/msg_hash_pt_pt.h @@ -3037,14 +3037,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Extensões de filtro desconhecidas" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Usar o reprodutor multimédia integrado" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrar pelo núcleo atual" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Usar o reprodutor multimédia integrado" + ) /* Settings > Frame Throttle */ @@ -3740,7 +3740,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Explorador de ficheiros" + "Pasta inicial" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 7673349a2e..5027e236b3 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -5009,14 +5009,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Фильтровать файлы в браузере файлов по поддерживаемым расширениям." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Встроенный медиаплеер" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Фильтрация по текущему ядру" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Фильтровать отображаемые в браузере файлы по текущему ядру." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Запоминать путь к начальному каталогу" @@ -5025,6 +5025,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "При загрузке контента открывать браузер файлов в последнем использованном каталоге. Путь будет сброшен к стандартному значению при перезапуске RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Встроенный медиаплеер" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Встроенный просмотр изображений" + ) /* Settings > Frame Throttle */ @@ -8220,7 +8228,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Браузер файлов" + "Начальный каталог" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12698,10 +12706,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Клавиатура" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Встроенный просмотр изображений" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Максимум изображений в свопчейне" diff --git a/intl/msg_hash_sk.h b/intl/msg_hash_sk.h index fc14578d52..8240136431 100644 --- a/intl/msg_hash_sk.h +++ b/intl/msg_hash_sk.h @@ -4128,7 +4128,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Správca súborov" + "Hlavný adresár" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, diff --git a/intl/msg_hash_sr.h b/intl/msg_hash_sr.h index 1474715c23..4be99ec1f9 100644 --- a/intl/msg_hash_sr.h +++ b/intl/msg_hash_sr.h @@ -2104,7 +2104,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Pregledač datoteka" + "Početni direktorijum" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, diff --git a/intl/msg_hash_sv.h b/intl/msg_hash_sv.h index e0e9365811..7feb500031 100644 --- a/intl/msg_hash_sv.h +++ b/intl/msg_hash_sv.h @@ -4201,10 +4201,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Filtrera filer som visas i filbläddraren till filändelser som stöds." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Använd intern mediaspelare" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtrera efter Kärna" @@ -4213,6 +4209,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Kom ihåg senaste använda startkatalog" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Använd intern mediaspelare" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Använd inbyggd bildvisare" + ) /* Settings > Frame Throttle */ @@ -6276,7 +6280,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Filhanterare" + "Start katalog" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -9470,10 +9474,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_KEYBOARD, "Tgb" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Använd inbyggd bildvisare" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_WAITABLE_SWAPCHAINS, "Hårdsynkronisera CPU och GPU. Minskar latens på bekostnad av prestanda." diff --git a/intl/msg_hash_tr.h b/intl/msg_hash_tr.h index 1c50218c60..7aac19b51d 100644 --- a/intl/msg_hash_tr.h +++ b/intl/msg_hash_tr.h @@ -4985,14 +4985,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Dosya tarayıcısında gösterilen dosyaları desteklenen uzantılara göre süzgeçle." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Dahili Medya Oynatıcı Kullan" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Mevcut Çekirdeğe Göre Süzgeçle" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Dosya tarayıcısında gösterilen dosyaları mevcut çekirdeğe göre filtreleyin." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Son Kullanılan Başlangıç ​​Dizinini Hatırla" @@ -5001,6 +5001,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Başlangıç ​​Dizininden içerik yüklerken son kullanılan konumda dosya tarayıcısını açın. Not: RetroArch yeniden başlatıldığında konum varsayılana sıfırlanacaktır." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Dahili Medya Oynatıcı Kullan" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Dahili Resim Görüntüleyici Kullan" + ) /* Settings > Frame Throttle */ @@ -8192,7 +8200,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Dosya Tarayıcısı" + "Başlangıç Dizini" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12746,10 +12754,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Kullanıcı" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Dahili Resim Görüntüleyici Kullan" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, "Azami Takas Zinciri Görüntüleri" diff --git a/intl/msg_hash_uk.h b/intl/msg_hash_uk.h index 6b4bcb9892..85acd506e3 100644 --- a/intl/msg_hash_uk.h +++ b/intl/msg_hash_uk.h @@ -4993,10 +4993,6 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, "Фільтрація файлів, що відображаються у браузері файлів, підтримуючи розширення." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Використовувати вбудований медіа-програвач" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Фільтрувати за поточним ядром" @@ -5009,6 +5005,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_USE_LAST_START_DIRECTORY, "Відкрити Файловий браузер в останньому використаному місці при завантаженні вмісту з папки Старт. Примітка: Місцезнаходження буде скинуто при перезапуску RetroArch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, + "Використовувати вбудований медіа-програвач" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Використовувати вбудований переглядач зображень" + ) /* Settings > Frame Throttle */ @@ -8160,7 +8164,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Файловий менеджер" + "Початковий каталог" ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, @@ -12762,10 +12766,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_USER, "Користувач" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, - "Використовувати вбудований переглядач зображень" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Задає прийом відео чітка використовувати вказаний режим буферизації." diff --git a/intl/msg_hash_val.h b/intl/msg_hash_val.h index 3a0558c49a..7ca7ca73a1 100644 --- a/intl/msg_hash_val.h +++ b/intl/msg_hash_val.h @@ -2796,7 +2796,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Navegador d'arxius" + "Directori inicial" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, diff --git a/intl/msg_hash_vn.h b/intl/msg_hash_vn.h index cc076bdc8d..c0ece40668 100644 --- a/intl/msg_hash_vn.h +++ b/intl/msg_hash_vn.h @@ -1932,7 +1932,7 @@ MSG_HASH( ) MSG_HASH( /* FIXME Not RGUI specific */ MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Quản lý tập tin" + "Yêu thích" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, diff --git a/intl/progress.h b/intl/progress.h index 81a52a323e..4d61e056cc 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -39,7 +39,7 @@ #define LANGUAGE_PROGRESS_GREEK_APPROVED 0 /* English, United Kingdom */ -#define LANGUAGE_PROGRESS_ENGLISH_UNITED_KINGDOM_TRANSLATED 100 +#define LANGUAGE_PROGRESS_ENGLISH_UNITED_KINGDOM_TRANSLATED 99 #define LANGUAGE_PROGRESS_ENGLISH_UNITED_KINGDOM_APPROVED 0 /* Esperanto */ @@ -48,7 +48,7 @@ /* Spanish */ #define LANGUAGE_PROGRESS_SPANISH_TRANSLATED 100 -#define LANGUAGE_PROGRESS_SPANISH_APPROVED 90 +#define LANGUAGE_PROGRESS_SPANISH_APPROVED 91 /* Persian */ #define LANGUAGE_PROGRESS_PERSIAN_TRANSLATED 11 @@ -91,7 +91,7 @@ #define LANGUAGE_PROGRESS_JAPANESE_APPROVED 0 /* Korean */ -#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_KOREAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_KOREAN_APPROVED 0 /* Dutch */ @@ -143,7 +143,7 @@ #define LANGUAGE_PROGRESS_TATAR_APPROVED 0 /* Ukrainian */ -#define LANGUAGE_PROGRESS_UKRAINIAN_TRANSLATED 100 +#define LANGUAGE_PROGRESS_UKRAINIAN_TRANSLATED 99 #define LANGUAGE_PROGRESS_UKRAINIAN_APPROVED 7 /* Valencian */ From 5b9d5a90863142c5101ccad53a1b8ba578b141b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Via=C4=8Das=C5=82a=C5=AD?= Date: Thu, 6 Feb 2025 04:10:06 +0300 Subject: [PATCH 188/574] Buildfix for Debian 12 (#17522) --- Makefile.common | 7 +++++-- audio/common/pipewire.c | 7 +++++-- camera/camera_driver.c | 2 +- qb/config.libs.sh | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Makefile.common b/Makefile.common index 7226db8f14..d7a8b97799 100644 --- a/Makefile.common +++ b/Makefile.common @@ -923,13 +923,16 @@ endif ifeq ($(HAVE_PIPEWIRE), 1) OBJ += audio/drivers/pipewire.o \ - audio/common/pipewire.o \ - camera/drivers/pipewire.o + audio/common/pipewire.o ifeq ($(HAVE_MICROPHONE), 1) OBJ += audio/drivers_microphone/pipewire.o endif + ifeq ($(HAVE_PIPEWIRE_STABLE), 1) + OBJ += camera/drivers/pipewire.o + endif + LIBS += $(PIPEWIRE_LIBS) DEF_FLAGS += $(PIPEWIRE_CFLAGS) endif diff --git a/audio/common/pipewire.c b/audio/common/pipewire.c index e931254f52..4a3c970bbd 100644 --- a/audio/common/pipewire.c +++ b/audio/common/pipewire.c @@ -214,8 +214,11 @@ void pipewire_core_deinit(pipewire_core_t *pw) pw_core_disconnect(pw->core); } - spa_clear_ptr(pw->ctx, pw_context_destroy); - spa_clear_ptr(pw->thread_loop, pw_thread_loop_destroy); + if (pw->ctx) + pw_context_destroy(pw->ctx); + + if (pw->thread_loop) + pw_thread_loop_destroy(pw->thread_loop); if (pw->devicelist) string_list_free(pw->devicelist); diff --git a/camera/camera_driver.c b/camera/camera_driver.c index 6925328ad2..68703321e6 100644 --- a/camera/camera_driver.c +++ b/camera/camera_driver.c @@ -49,7 +49,7 @@ const camera_driver_t *camera_drivers[] = { #ifdef HAVE_V4L2 &camera_v4l2, #endif -#ifdef HAVE_PIPEWIRE +#ifdef HAVE_PIPEWIRE_STABLE &camera_pipewire, #endif #ifdef EMSCRIPTEN diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 2e1ff7222e..d5e3076295 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -270,6 +270,7 @@ check_pkgconf ROAR libroar 1.0.12 check_val '' JACK -ljack '' jack 0.120.1 '' false check_val '' PULSE -lpulse '' libpulse '' '' false check_val '' PIPEWIRE -lpipewire-0.3 '' libpipewire-0.3 '' '' false +check_val '' PIPEWIRE_STABLE -lpipewire-0.3 '' libpipewire-0.3 1.0.0 '' false check_val '' SDL -lSDL SDL sdl 1.2.10 '' false check_val '' SDL2 -lSDL2 SDL2 sdl2 2.0.0 '' false From 92c3800731b8d6b169027f5a78022c6ea3a51471 Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Wed, 5 Feb 2025 22:49:08 -0500 Subject: [PATCH 189/574] apple: include b2 core in App Store builds (#17525) --- pkg/apple/update-cores.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/apple/update-cores.sh b/pkg/apple/update-cores.sh index db4657e1a7..8f9c8bc6e8 100755 --- a/pkg/apple/update-cores.sh +++ b/pkg/apple/update-cores.sh @@ -147,6 +147,7 @@ else anarch ardens atari800 + b2 #blastem bluemsx bsnes From bb9f07569c69ead707db921e7cdad8b08fde5f1e Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Thu, 6 Feb 2025 05:49:20 +0200 Subject: [PATCH 190/574] Video stats unit alignments (#17524) --- gfx/video_driver.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gfx/video_driver.c b/gfx/video_driver.c index fde66068d4..609a3c2693 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -4129,17 +4129,17 @@ void video_driver_frame(const void *data, unsigned width, " Viewport: %u x %u\n" " - Scale: %u x %u\n" " - Scale X/Y: %2.2f / %2.2f\n" - " Refresh: %5.2f hz\n" - " Frame Rate: %5.2f fps\n" - " Frame Time: %5.2f ms\n" - " - Deviation: %5.2f %%\n" + " Refresh: %6.2f hz\n" + " Frame Rate:%7.2f fps\n" + " Frame Time: %6.2f ms\n" + " - Deviation:%6.2f %%\n" " Frames: %8" PRIu64"\n" " - Dropped: %5u\n" "AUDIO: %s\n" - " Saturation: %5.2f %%\n" - " Deviation: %5.2f %%\n" - " Underrun: %5.2f %%\n" - " Blocking: %5.2f %%\n" + " Saturation: %6.2f %%\n" + " Deviation: %6.2f %%\n" + " Underrun: %6.2f %%\n" + " Blocking: %6.2f %%\n" " Samples: %8d\n" , video_st->frame_cache_width, From 4c8da979a5b554ceab9521b8f15190154df18687 Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Thu, 6 Feb 2025 14:22:36 -0500 Subject: [PATCH 191/574] fix a couple minor warnings (#17526) --- input/drivers/cocoa_input.m | 10 +++++----- menu/drivers/materialui.c | 1 - pkg/apple/RetroArch_iOS13.xcodeproj/project.pbxproj | 4 ++-- ui/drivers/cocoa/apple_platform.h | 2 ++ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/input/drivers/cocoa_input.m b/input/drivers/cocoa_input.m index 1470fe549f..aac9dd1d3b 100644 --- a/input/drivers/cocoa_input.m +++ b/input/drivers/cocoa_input.m @@ -700,13 +700,13 @@ static int16_t cocoa_input_state( case RETRO_DEVICE_ID_LIGHTGUN_PAUSE: { unsigned new_id = input_driver_lightgun_id_convert(id); - const uint64_t bind_joykey = input_config_binds[port][new_id].joykey; - const uint64_t bind_joyaxis = input_config_binds[port][new_id].joyaxis; - const uint64_t autobind_joykey = input_autoconf_binds[port][new_id].joykey; - const uint64_t autobind_joyaxis= input_autoconf_binds[port][new_id].joyaxis; + const uint32_t bind_joykey = input_config_binds[port][new_id].joykey; + const uint32_t bind_joyaxis = input_config_binds[port][new_id].joyaxis; + const uint32_t autobind_joykey = input_autoconf_binds[port][new_id].joykey; + const uint32_t autobind_joyaxis= input_autoconf_binds[port][new_id].joyaxis; uint16_t joyport = joypad_info->joy_idx; float axis_threshold = joypad_info->axis_threshold; - const uint64_t joykey = (bind_joykey != NO_BTN) ? bind_joykey : autobind_joykey; + const uint32_t joykey = (bind_joykey != NO_BTN) ? bind_joykey : autobind_joykey; const uint32_t joyaxis = (bind_joyaxis != AXIS_NONE) ? bind_joyaxis : autobind_joyaxis; if (binds[port][new_id].valid) diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 99dec9009d..06b2f26857 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -4020,7 +4020,6 @@ static void materialui_render_menu_entry_default( bool draw_text_outside = (x_offset != 0); gfx_display_t *p_disp = disp_get_ptr(); uico_driver_state_t *uico_st = uico_state_get_ptr(); - settings_t *settings = config_get_ptr(); static float color_white[16] = { 1.0f, 1.0f, 1.0f, 1.0f, diff --git a/pkg/apple/RetroArch_iOS13.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_iOS13.xcodeproj/project.pbxproj index 6932dcd0bb..d761dea58f 100644 --- a/pkg/apple/RetroArch_iOS13.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_iOS13.xcodeproj/project.pbxproj @@ -1897,7 +1897,6 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; @@ -1920,6 +1919,7 @@ GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; @@ -1957,7 +1957,6 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; @@ -1979,6 +1978,7 @@ GCC_FAST_MATH = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = fast; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; diff --git a/ui/drivers/cocoa/apple_platform.h b/ui/drivers/cocoa/apple_platform.h index 4128b39658..9bd15b1539 100644 --- a/ui/drivers/cocoa/apple_platform.h +++ b/ui/drivers/cocoa/apple_platform.h @@ -60,7 +60,9 @@ typedef enum apple_view_type * the displays should not sleep. */ - (bool)setDisableDisplaySleep:(bool)disable; +#if !defined(HAVE_COCOATOUCH) - (void)openDocument:(id)sender; +#endif @end #endif From 3f70ac54a56fff1a6d6514e4ab3c93a0592eedea Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 7 Feb 2025 00:14:43 +0000 Subject: [PATCH 192/574] Fetch translations from Crowdin --- intl/msg_hash_pl.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/intl/msg_hash_pl.h b/intl/msg_hash_pl.h index 72a7d15774..74f58af46d 100644 --- a/intl/msg_hash_pl.h +++ b/intl/msg_hash_pl.h @@ -4433,6 +4433,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filtruj według bieżącego rdzenia" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Filtruj pliki wyświetlane w przeglądarce plików według aktualnego rdzenia." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Zapamiętaj ostatnio używany katalog startowy" From 4232700de5f1901b761a12b93185ab27edfa8780 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Fri, 7 Feb 2025 12:43:45 +0200 Subject: [PATCH 193/574] GLUI: Fix menu back to switch tabs like other drivers (#17529) --- menu/drivers/materialui.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 06b2f26857..78c29181a9 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -9466,8 +9466,7 @@ static enum menu_action materialui_parse_menu_entry_action( * user instigates a cancel action from any top * level menu other than main *if* the navigation * bar is hidden */ - if ( (mui->nav_bar.location == MUI_NAV_BAR_LOCATION_HIDDEN) - && (materialui_list_get_size(mui, MENU_LIST_PLAIN) == 1)) + if (materialui_list_get_size(mui, MENU_LIST_PLAIN) == 1) { size_t i; size_t main_menu_tab_index = 0; @@ -9489,6 +9488,9 @@ static enum menu_action materialui_parse_menu_entry_action( { materialui_switch_tabs(mui, main_menu_tab, MENU_ACTION_NOOP); new_action = MENU_ACTION_NOOP; +#ifdef HAVE_AUDIOMIXER + audio_driver_mixer_play_menu_sound(AUDIO_MIXER_SYSTEM_SLOT_CANCEL); +#endif } else if (main_menu_tab_index == mui->nav_bar.active_menu_tab_index) { @@ -9497,12 +9499,6 @@ static enum menu_action materialui_parse_menu_entry_action( materialui_navigation_set(mui, true); } } - else if (materialui_list_get_size(mui, MENU_LIST_PLAIN) == 1) - { - /* Jump to first item on current menu */ - menu_st->selection_ptr = 0; - materialui_navigation_set(mui, true); - } break; default: /* In all other cases, pass through input From 17bc1eba3fca54bbdfda5f63c60149b1384ecacb Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 8 Feb 2025 00:13:29 +0000 Subject: [PATCH 194/574] Fetch translations from Crowdin --- intl/msg_hash_uk.h | 4 ++++ intl/progress.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/intl/msg_hash_uk.h b/intl/msg_hash_uk.h index 85acd506e3..367fe97f54 100644 --- a/intl/msg_hash_uk.h +++ b/intl/msg_hash_uk.h @@ -4997,6 +4997,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Фільтрувати за поточним ядром" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FILTER_BY_CURRENT_CORE, + "Фільтр файлів, що відображаються в браузері файлу по поточному ядру." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_USE_LAST_START_DIRECTORY, "Запам’ятайте Останній Використаний Стартовий Каталог" diff --git a/intl/progress.h b/intl/progress.h index 4d61e056cc..433b2e39b0 100644 --- a/intl/progress.h +++ b/intl/progress.h @@ -143,7 +143,7 @@ #define LANGUAGE_PROGRESS_TATAR_APPROVED 0 /* Ukrainian */ -#define LANGUAGE_PROGRESS_UKRAINIAN_TRANSLATED 99 +#define LANGUAGE_PROGRESS_UKRAINIAN_TRANSLATED 100 #define LANGUAGE_PROGRESS_UKRAINIAN_APPROVED 7 /* Valencian */ From 4cbfa3ad47d478f09003ad461d48c41f6f6f085b Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Sat, 8 Feb 2025 12:56:40 +0200 Subject: [PATCH 195/574] GLUI: Use tab selection remember option (#17532) --- menu/drivers/materialui.c | 58 +++++++++++++++++++++++++++++++++++---- menu/menu_displaylist.c | 2 +- menu/menu_setting.c | 7 +++-- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 78c29181a9..775e761416 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -661,6 +661,11 @@ typedef struct materialui_handle materialui_colors_t colors; /* uint32_t alignment */ uint32_t flags; + size_t playlist_selection[NAME_MAX_LENGTH]; + size_t playlist_selection_ptr; + uint8_t mainmenu_selection_ptr; + uint8_t settings_selection_ptr; + /* Scrollbar parameters */ materialui_scrollbar_t scrollbar; /* int alignment */ int cursor_size; @@ -8184,6 +8189,11 @@ static void *materialui_init(void **userdata, bool video_is_threaded) /* Ensure message box string is empty */ mui->msgbox[0] = '\0'; + mui->mainmenu_selection_ptr = 0; + mui->settings_selection_ptr = 0; + mui->playlist_selection_ptr = 0; + memset(mui->playlist_selection, 0, sizeof(mui->playlist_selection)); + /* Initialise navigation bar */ materialui_init_nav_bar(mui); @@ -8394,12 +8404,23 @@ static void materialui_animate_scroll(materialui_handle_t *mui, on the keyboard) */ static void materialui_navigation_set(void *data, bool scroll) { - materialui_handle_t *mui = (materialui_handle_t*)data; - gfx_display_t *p_disp = disp_get_ptr(); + materialui_handle_t *mui = (materialui_handle_t*)data; + gfx_display_t *p_disp = disp_get_ptr(); + struct menu_state *menu_st = menu_state_get_ptr(); + size_t selection = menu_st->selection_ptr; if (!mui || !scroll) return; + if (mui->flags & MUI_FLAG_IS_PLAYLIST) + mui->playlist_selection[mui->playlist_selection_ptr] = selection; + else if (mui->flags & MUI_FLAG_IS_PLAYLISTS_TAB) + mui->playlist_selection_ptr = selection; + else if (string_is_equal(mui->menu_title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MAIN_MENU))) + mui->mainmenu_selection_ptr = selection; + else if (string_is_equal(mui->menu_title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SETTINGS))) + mui->settings_selection_ptr = selection; + materialui_animate_scroll( mui, materialui_get_scroll(mui, p_disp), @@ -8623,9 +8644,10 @@ static void materialui_init_transition_animation(materialui_handle_t *mui, static void materialui_populate_entries(void *data, const char *path, const char *label, unsigned i) { - materialui_handle_t *mui = (materialui_handle_t*)data; - struct menu_state *menu_st = menu_state_get_ptr(); - settings_t *settings = config_get_ptr(); + materialui_handle_t *mui = (materialui_handle_t*)data; + struct menu_state *menu_st = menu_state_get_ptr(); + settings_t *settings = config_get_ptr(); + uint8_t remember_selection = settings->uints.menu_remember_selection; if (!mui || !settings) return; @@ -8768,6 +8790,32 @@ static void materialui_populate_entries(void *data, const char *path, } #endif + if ( mui->flags & MUI_FLAG_IS_PLAYLIST + && !string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY))) + { + if ( remember_selection == MENU_REMEMBER_SELECTION_ALWAYS + || remember_selection == MENU_REMEMBER_SELECTION_PLAYLISTS) + menu_state_get_ptr()->selection_ptr = mui->playlist_selection[mui->playlist_selection_ptr]; + } + else if (mui->flags & MUI_FLAG_IS_PLAYLISTS_TAB) + { + if ( remember_selection == MENU_REMEMBER_SELECTION_ALWAYS + || remember_selection == MENU_REMEMBER_SELECTION_PLAYLISTS) + menu_state_get_ptr()->selection_ptr = mui->playlist_selection_ptr; + } + else if (string_is_equal(mui->menu_title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MAIN_MENU))) + { + if ( remember_selection == MENU_REMEMBER_SELECTION_ALWAYS + || remember_selection == MENU_REMEMBER_SELECTION_MAIN) + menu_state_get_ptr()->selection_ptr = mui->mainmenu_selection_ptr; + } + else if (string_is_equal(mui->menu_title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SETTINGS))) + { + if ( remember_selection == MENU_REMEMBER_SELECTION_ALWAYS + || remember_selection == MENU_REMEMBER_SELECTION_MAIN) + menu_state_get_ptr()->selection_ptr = mui->settings_selection_ptr; + } + /* Update navigation bar tabs * > Note: We do this regardless of whether * the navigation bar is currently shown. diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index a869ed24a8..bf2ee5a7f4 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -9485,7 +9485,7 @@ unsigned menu_displaylist_build_list( build_list[i].checked = true; break; #endif -#if defined(HAVE_XMB) || defined(HAVE_OZONE) +#if defined(HAVE_XMB) || defined(HAVE_OZONE) || defined(HAVE_RGUI) || defined(HAVE_MATERIALUI) case MENU_ENUM_LABEL_MENU_REMEMBER_SELECTION: build_list[i].checked = true; break; diff --git a/menu/menu_setting.c b/menu/menu_setting.c index a62e5d237a..c8dc0f5d1b 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -7466,7 +7466,7 @@ static void setting_get_string_representation_uint_menu_screensaver_animation( } #endif -#if defined(HAVE_XMB) || defined(HAVE_OZONE) || defined(HAVE_RGUI) +#if defined(HAVE_XMB) || defined(HAVE_OZONE) || defined(HAVE_RGUI) || defined(HAVE_MATERIALUI) static void setting_get_string_representation_uint_menu_remember_selection( rarch_setting_t *setting, char *s, size_t len) @@ -18362,10 +18362,11 @@ static bool setting_append_list( menu_settings_list_current_add_range(list, list_info, 0.1, 10.0, 0.1, true, true); } #endif -#if defined(HAVE_XMB) || defined(HAVE_OZONE) || defined(HAVE_RGUI) +#if defined(HAVE_XMB) || defined(HAVE_OZONE) || defined(HAVE_RGUI) || defined(HAVE_MATERIALUI) if (string_is_equal(settings->arrays.menu_driver, "xmb") || string_is_equal(settings->arrays.menu_driver, "ozone") || - string_is_equal(settings->arrays.menu_driver, "rgui")) + string_is_equal(settings->arrays.menu_driver, "rgui") || + string_is_equal(settings->arrays.menu_driver, "glui")) { CONFIG_UINT( list, list_info, From 5471a9ebfed21251e40a185ac4b0d78d3ca7b60d Mon Sep 17 00:00:00 2001 From: Eric Warmenhoven Date: Sat, 8 Feb 2025 14:32:41 -0500 Subject: [PATCH 196/574] ios: jump back to selected item after closing content (#17534) --- menu/cbs/menu_cbs_ok.c | 2 +- tasks/task_content.c | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index f0d86ce213..4fe2c7adc2 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1048,7 +1048,7 @@ int generic_action_ok_displaylist_push( p_dialog->pending_push = true; break; case ACTION_OK_DL_RPL_ENTRY: - strlcpy(menu->deferred_path, label, sizeof(menu->deferred_path)); + fill_pathname_expand_special(menu->deferred_path, label, sizeof(menu->deferred_path)); info_label = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS); info.enum_idx = MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS; info.directory_ptr = idx; diff --git a/tasks/task_content.c b/tasks/task_content.c index eaa20b7315..5c92a55b4d 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -2129,12 +2129,6 @@ bool task_push_load_content_from_playlist_from_menu( fullpath, &content_ctx, false))) goto end; -#ifdef HAVE_COCOATOUCH - /* This seems to be needed for iOS for some reason - * to show the quick menu after the menu is shown */ - menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUICK_MENU, NULL); -#endif - #ifndef HAVE_DYNAMIC /* No dynamic core loading support: if we reach * this point then a new instance has been From 677e6272786b3bbe944d19cacf869ad2adec01c6 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Sat, 8 Feb 2025 22:19:24 +0200 Subject: [PATCH 197/574] GLUI: Touch related fixes (#17536) --- menu/drivers/materialui.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 775e761416..2815b542a6 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -8409,7 +8409,7 @@ static void materialui_navigation_set(void *data, bool scroll) struct menu_state *menu_st = menu_state_get_ptr(); size_t selection = menu_st->selection_ptr; - if (!mui || !scroll) + if (!mui) return; if (mui->flags & MUI_FLAG_IS_PLAYLIST) @@ -8421,6 +8421,9 @@ static void materialui_navigation_set(void *data, bool scroll) else if (string_is_equal(mui->menu_title, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SETTINGS))) mui->settings_selection_ptr = selection; + if (!scroll) + return; + materialui_animate_scroll( mui, materialui_get_scroll(mui, p_disp), @@ -10249,8 +10252,8 @@ static int materialui_pointer_up(void *userdata, } /* If this is not a playlist or file list, a tap/press * anywhere on the header triggers a MENU_ACTION_CANCEL - * action */ - else + * action unless already at root depth */ + else if (MENU_LIST_GET_STACK_SIZE(menu_st->entries.list, 0) > 1) return materialui_menu_entry_action(mui, entry, selection, MENU_ACTION_CANCEL); } /* Tap/press menu item: Activate and/or select item */ @@ -10307,6 +10310,9 @@ static int materialui_pointer_up(void *userdata, if (ptr != selection) menu_st->selection_ptr = ptr; + /* Set navigation for selection remembering */ + materialui_navigation_set(mui, false); + /* Perform a MENU_ACTION_SELECT on currently * active item * > Note that we still use 'selection' From 58d7879e1dc6705bbd3d69edb2700aca2180805b Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 9 Feb 2025 00:14:47 +0000 Subject: [PATCH 198/574] Fetch translations from Crowdin --- intl/msg_hash_be.h | 2 +- intl/msg_hash_gl.h | 2 +- intl/msg_hash_he.h | 4 ++-- intl/msg_hash_tr.h | 4 ++-- intl/msg_hash_uk.h | 2 +- intl/msg_hash_vn.h | 8 -------- 6 files changed, 7 insertions(+), 15 deletions(-) diff --git a/intl/msg_hash_be.h b/intl/msg_hash_be.h index eb52ef4310..cf56377aeb 100644 --- a/intl/msg_hash_be.h +++ b/intl/msg_hash_be.h @@ -3175,7 +3175,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_RATE_CONTROL_DELTA, - "Ўстаноўка на 0 адключае кіраванне частатой. Іншыя значэнні ўплываюць на адхіленне частаты гуку.\nВызначае межы змены зыходнай частаты пры дынамічнай падладцы. Разлічваецца наступным чынам:\\зыходная частата * (1.0 +/- (адхіленне кіравання частатой))" + "Ўстаноўка на 0 адключае кіраванне частатой. Іншыя значэнні ўплываюць на адхіленне частаты гуку.\nВызначае межы змены зыходнай частаты пры дынамічнай падладцы. Разлічваецца наступным чынам:\\\\зыходная частата * (1.0 +/- (адхіленне кіравання частатой))" ) /* Settings > Audio > MIDI */ diff --git a/intl/msg_hash_gl.h b/intl/msg_hash_gl.h index 31fe3db670..e2382075b1 100644 --- a/intl/msg_hash_gl.h +++ b/intl/msg_hash_gl.h @@ -3287,7 +3287,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_INPUT_POLL_TYPE_BEHAVIOR, - "Inflúe na forma en que se realiza a votación de entrada dentro de RetroArch.\nA principios: a enquisa de entrada realízase antes de que se procese o fotograma.\nNormal: a enquisa de entrada realízase cando se solicita o sondeo.\nTarde: a votación de entrada realízase na primeira solicitude de estado de entrada por fotograma.\\ nSeleccionándoo como \"cedo\" ou \"Tardía\" pode producir menos latencia, dependendo da túa configuración. Ignorarase ao usar xogo en rede." + "Inflúe na forma en que se realiza a votación de entrada dentro de RetroArch.\nA principios: a enquisa de entrada realízase antes de que se procese o fotograma.\nNormal: a enquisa de entrada realízase cando se solicita o sondeo.\nTarde: a votación de entrada realízase na primeira solicitude de estado de entrada por fotograma.\\\\ nSeleccionándoo como \"cedo\" ou \"Tardía\" pode producir menos latencia, dependendo da túa configuración. Ignorarase ao usar xogo en rede." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, diff --git a/intl/msg_hash_he.h b/intl/msg_hash_he.h index 93b1008112..12e2b2c264 100644 --- a/intl/msg_hash_he.h +++ b/intl/msg_hash_he.h @@ -807,7 +807,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "הצגת\\הסתרת תפריט" + "הצגת\\\\הסתרת תפריט" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, @@ -1846,7 +1846,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, - "הצגת\\הסתרת תפריט" + "הצגת\\\\הסתרת תפריט" ) /* Discord Status */ diff --git a/intl/msg_hash_tr.h b/intl/msg_hash_tr.h index 7aac19b51d..9712a25e50 100644 --- a/intl/msg_hash_tr.h +++ b/intl/msg_hash_tr.h @@ -3167,7 +3167,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_AUDIO_RATE_CONTROL_DELTA, - "Bunu 0 olarak ayarlamak hız kontrolünü devre dışı bırakır. Diğer tüm değerler, ses hızı kontrol deltasını kontrol eder.\nGiriş hızının dinamik olarak ne kadar ayarlanabileceğini tanımlar. Giriş hızı şu şekilde tanımlanır:\\giriş hızı * (1,0 +/- (oran kontrol deltası))" + "Bunu 0 olarak ayarlamak hız kontrolünü devre dışı bırakır. Diğer tüm değerler, ses hızı kontrol deltasını kontrol eder.\nGiriş hızının dinamik olarak ne kadar ayarlanabileceğini tanımlar. Giriş hızı şu şekilde tanımlanır:\\\\giriş hızı * (1,0 +/- (oran kontrol deltası))" ) /* Settings > Audio > MIDI */ @@ -3331,7 +3331,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_INPUT_POLL_TYPE_BEHAVIOR, - "RetroArch içinde girdi yoklamanın nasıl yapıldığını etkiler.\nErken - Kare işlenmeden önce girdi yoklama yapılır.\nNormal - Yoklama istendiğinde girdi yoklaması yapılır.\nGeç - Kare başına ilk girdi durumu isteğinde girdi yoklama gerçekleştirilir.\\ n'Erken' veya 'Geç' olarak ayarlamak, yapılandırmanıza bağlı olarak daha az gecikmeyle sonuçlanabilir. Netplay kullanılırken yok sayılır." + "RetroArch içinde girdi yoklamanın nasıl yapıldığını etkiler.\nErken - Kare işlenmeden önce girdi yoklama yapılır.\nNormal - Yoklama istendiğinde girdi yoklaması yapılır.\nGeç - Kare başına ilk girdi durumu isteğinde girdi yoklama gerçekleştirilir.\\\\ n'Erken' veya 'Geç' olarak ayarlamak, yapılandırmanıza bağlı olarak daha az gecikmeyle sonuçlanabilir. Netplay kullanılırken yok sayılır." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, diff --git a/intl/msg_hash_uk.h b/intl/msg_hash_uk.h index 367fe97f54..6090be199b 100644 --- a/intl/msg_hash_uk.h +++ b/intl/msg_hash_uk.h @@ -9891,7 +9891,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_HELP_VIDEO_SHADER_FILTER_PASS, - "Фільтр апаратних засобів для цього проходження. Якщо встановлено значення \\\"За замовчуванням', то фільтр буде встановлено або «Лінійн» або «Голковий», що залежить від параметра 'Bilinear'." + "Фільтр апаратних засобів для цього проходження. Якщо встановлено значення \\\\\"За замовчуванням', то фільтр буде встановлено або «Лінійн» або «Голковий», що залежить від параметра 'Bilinear'." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCALE, diff --git a/intl/msg_hash_vn.h b/intl/msg_hash_vn.h index c0ece40668..3445146da9 100644 --- a/intl/msg_hash_vn.h +++ b/intl/msg_hash_vn.h @@ -618,10 +618,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CPU_CORES, "Số lõi CPU" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_JIT_AVAILABLE, - "" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER, "Loại hệ điều hành" @@ -940,10 +936,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, "Nhà phát triển" ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, - "" - ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, "Phần cứng nâng cao" From 2c06049a2ffb81c58271c24255dbc2685ae296bc Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Sun, 9 Feb 2025 07:11:13 +0200 Subject: [PATCH 199/574] Allow CLI --entryslot fallback to normal states (#17539) --- command.c | 12 ++++++++++-- retroarch.c | 16 +++++++++------- runloop.c | 10 +++++----- runloop.h | 4 ++-- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/command.c b/command.c index ff962d4d44..d55e8d42ab 100644 --- a/command.c +++ b/command.c @@ -1259,7 +1259,7 @@ size_t command_event_save_auto_state(void) size_t _len; runloop_state_t *runloop_st = runloop_state_get_ptr(); char savestate_name_auto[PATH_MAX_LENGTH]; - if (runloop_st->entry_state_slot) + if (runloop_st->entry_state_slot > -1) return 0; if (!core_info_current_supports_savestate()) return 0; @@ -1330,9 +1330,17 @@ bool command_event_load_entry_state(settings_t *settings) entry_state_path[0] = '\0'; if (!runloop_get_entry_state_path( + entry_state_path, sizeof(entry_state_path), + runloop_st->entry_state_slot)) + return false; + + if (!path_is_valid(entry_state_path)) + { + if (!runloop_get_savestate_path( entry_state_path, sizeof(entry_state_path), runloop_st->entry_state_slot)) - return false; + return false; + } entry_path_stats = path_stat(entry_state_path); diff --git a/retroarch.c b/retroarch.c index 6f01ebb8e3..3e5e6550f9 100644 --- a/retroarch.c +++ b/retroarch.c @@ -7381,12 +7381,13 @@ static bool retroarch_parse_input_and_config( break; case 'e': { - unsigned entry_state_slot = (unsigned)strtoul(optarg, NULL, 0); + char *endptr; + int16_t entry_state_slot = (unsigned)strtoul(optarg, &endptr, 0); - if (entry_state_slot) + if (entry_state_slot > -1 && string_is_empty(endptr)) runloop_st->entry_state_slot = entry_state_slot; else - RARCH_WARN("--entryslot argument \"%s\" is not a valid " + RARCH_WARN("[State]: --entryslot argument \"%s\" is not a valid " "entry state slot index. Ignoring.\n", optarg); } break; @@ -7477,18 +7478,18 @@ static bool retroarch_parse_input_and_config( * command line interface */ cli_content_set = true; } - else if (runloop_st->entry_state_slot) + else if (runloop_st->entry_state_slot > -1) { - runloop_st->entry_state_slot = 0; + runloop_st->entry_state_slot = -1; RARCH_WARN("Trying to load entry state without content. Ignoring.\n"); } #ifdef HAVE_BSV_MOVIE - if (runloop_st->entry_state_slot) + if (runloop_st->entry_state_slot > -1) { input_driver_state_t *input_st = input_state_get_ptr(); if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_START_PLAYBACK) { - runloop_st->entry_state_slot = 0; + runloop_st->entry_state_slot = -1; RARCH_WARN("Trying to load entry state while replay playback is active. Ignoring entry state.\n"); } } @@ -7585,6 +7586,7 @@ bool retroarch_main_init(int argc, char *argv[]) input_st->osk_idx = OSK_LOWERCASE_LATIN; video_st->flags |= VIDEO_FLAG_ACTIVE; audio_state_get_ptr()->flags |= AUDIO_FLAG_ACTIVE; + runloop_st->entry_state_slot = -1; if (setjmp(global->error_sjlj_context) > 0) { diff --git a/runloop.c b/runloop.c index c16e76f595..227898a6bb 100644 --- a/runloop.c +++ b/runloop.c @@ -4281,11 +4281,11 @@ static bool event_init_content( if (!(input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_START_PLAYBACK)) #endif { - if ( runloop_st->entry_state_slot + if ( runloop_st->entry_state_slot > -1 && !command_event_load_entry_state(settings)) { /* loading the state failed, reset entry slot */ - runloop_st->entry_state_slot = 0; + runloop_st->entry_state_slot = -1; } } #ifdef HAVE_BSV_MOVIE @@ -4293,7 +4293,7 @@ static bool event_init_content( if (!(input_st->bsv_movie_state.flags & (BSV_FLAG_MOVIE_START_RECORDING | BSV_FLAG_MOVIE_START_PLAYBACK))) #endif { - if (!runloop_st->entry_state_slot && settings->bools.savestate_auto_load) + if (runloop_st->entry_state_slot < 0 && settings->bools.savestate_auto_load) command_event_load_auto_state(); } } @@ -7323,13 +7323,13 @@ bool runloop_get_replay_path(char *s, size_t len, unsigned slot) } -bool runloop_get_entry_state_path(char *s, size_t len, unsigned slot) +bool runloop_get_entry_state_path(char *s, size_t len, int slot) { size_t _len; runloop_state_t *runloop_st = &runloop_state; const char *name_savestate = NULL; - if (!s || !slot) + if (!s) return false; name_savestate = runloop_st->name.savestate; diff --git a/runloop.h b/runloop.h index 611c8155ed..7cac09fb7f 100644 --- a/runloop.h +++ b/runloop.h @@ -252,8 +252,8 @@ struct runloop unsigned fastforward_after_frames; unsigned perf_ptr_libretro; unsigned subsystem_current_count; - unsigned entry_state_slot; unsigned video_swap_interval_auto; + int16_t entry_state_slot; fastmotion_overrides_t fastmotion_override; /* float alignment */ @@ -425,7 +425,7 @@ void runloop_path_set_names(void); uint32_t runloop_get_flags(void); -bool runloop_get_entry_state_path(char *path, size_t len, unsigned slot); +bool runloop_get_entry_state_path(char *path, size_t len, int slot); bool runloop_get_current_savestate_path(char *path, size_t len); From 3bf04c6034d4be7b5a46d4cb13235b0a3eb8b048 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Sun, 9 Feb 2025 07:11:21 +0200 Subject: [PATCH 200/574] GLUI: Fix null label icon (#17538) --- intl/msg_hash_lbl.h | 4 ++++ menu/drivers/materialui.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index eecdf071e2..2f9bb361f0 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1550,6 +1550,10 @@ MSG_HASH( MENU_ENUM_LABEL_DISK_OPTIONS, "core_disk_options" ) +MSG_HASH( + MENU_ENUM_LABEL_DISK_INDEX, + "core_disk_index" + ) MSG_HASH( MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST, "downloaded_file_detect_core_list" diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 2815b542a6..5b44d28d60 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -10692,6 +10692,8 @@ static void materialui_list_insert(void *userdata, * switch */ break; default: + if (string_is_equal(label, "null")) + break; #ifdef HAVE_CHEEVOS if (type >= MENU_SETTINGS_CHEEVOS_START && type < MENU_SETTINGS_NETPLAY_ROOMS_START) From 81df9b04916a0e42f8d1d3d5be50ef06ac514a50 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Sun, 9 Feb 2025 07:11:28 +0200 Subject: [PATCH 201/574] GLUI: Also set navigation with long press (#17537) --- menu/drivers/materialui.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 5b44d28d60..992c795902 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -10341,6 +10341,9 @@ static int materialui_pointer_up(void *userdata, case MENU_INPUT_GESTURE_LONG_PRESS: if ((ptr < entries_end) && (ptr == selection)) { + /* Also set navigation */ + materialui_navigation_set(mui, false); + /* If this is the core updater list, show info * message box for current entry. * In all other cases, perform 'reset to default' From 0d46073bb90066780a554e7948ebc05f6f736ee3 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Sun, 9 Feb 2025 15:24:14 +0200 Subject: [PATCH 202/574] Add mute on rewind option (#17541) --- audio/audio_defines.h | 8 ++- audio/audio_driver.c | 15 ++---- config.def.h | 8 +-- configuration.c | 1 + configuration.h | 1 + intl/msg_hash_us.h | 12 ++++- menu/cbs/menu_cbs_sublabel.c | 4 ++ menu/menu_displaylist.c | 94 ++++++++++++------------------------ menu/menu_setting.c | 21 ++++++-- msg_hash.h | 1 + retroarch.c | 15 +++--- runloop.c | 20 ++++++++ ui/drivers/qt/qt_options.cpp | 3 ++ 13 files changed, 108 insertions(+), 95 deletions(-) diff --git a/audio/audio_defines.h b/audio/audio_defines.h index 18de5f0338..ca2a8e162a 100644 --- a/audio/audio_defines.h +++ b/audio/audio_defines.h @@ -161,7 +161,13 @@ enum audio_driver_state_flags * @see audio_driver_t::write_avail * @see audio_driver_t::buffer_size */ - AUDIO_FLAG_CONTROL = (1 << 5) + AUDIO_FLAG_CONTROL = (1 << 5), + + /** + * Indicates that the audio driver is forcing gain to 0. + * Used for temporary rewind and fast-forward muting. + */ + AUDIO_FLAG_MUTED = (1 << 6) }; typedef struct audio_statistics diff --git a/audio/audio_driver.c b/audio/audio_driver.c index 01a727eb95..2b999a8364 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -400,22 +400,20 @@ bool audio_driver_find_driver( * @param audio_st The overall state of the audio driver. * @param slowmotion_ratio The factor by which slow motion extends the core's runtime * (e.g. a value of 2 means the core is running at half speed). - * @param audio_fastforward_mute True if no audio should be output while the game is in fast-forward. * @param data Audio output data that was most recently provided by the core. * @param samples The size of \c data, in samples. - * @param is_slowmotion True if the player is currently running the game in slow motion. - * @param is_fastmotion True if the player is currently running the game in fast-forward. + * @param is_slowmotion True if the core is currently running in slow motion. + * @param is_fastmotion True if the core is currently running in fast-forward. **/ static void audio_driver_flush( audio_driver_state_t *audio_st, float slowmotion_ratio, - bool audio_fastforward_mute, const int16_t *data, size_t samples, bool is_slowmotion, bool is_fastforward) { struct resampler_data src_data; - float audio_volume_gain = (audio_st->mute_enable || - (audio_fastforward_mute && is_fastforward)) + float audio_volume_gain = + (audio_st->mute_enable || audio_st->flags & AUDIO_FLAG_MUTED) ? 0.0f : audio_st->volume_gain; @@ -850,7 +848,6 @@ void audio_driver_sample(int16_t left, int16_t right) || !(audio_st->output_samples_buf))) audio_driver_flush(audio_st, config_get_ptr()->floats.slowmotion_ratio, - config_get_ptr()->bools.audio_fastforward_mute, audio_st->output_samples_conv_buf, audio_st->data_ptr, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, @@ -900,7 +897,6 @@ size_t audio_driver_sample_batch(const int16_t *data, size_t frames) || !(audio_st->output_samples_buf))) audio_driver_flush(audio_st, config_get_ptr()->floats.slowmotion_ratio, - config_get_ptr()->bools.audio_fastforward_mute, data, frames_to_write << 1, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, @@ -1741,7 +1737,6 @@ void audio_driver_frame_is_reverse(void) settings_t *settings = config_get_ptr(); audio_driver_flush(audio_st, settings->floats.slowmotion_ratio, - settings->bools.audio_fastforward_mute, audio_st->rewind_buf + audio_st->rewind_ptr, audio_st->rewind_size - @@ -1911,7 +1906,6 @@ void audio_driver_menu_sample(void) if (check_flush) audio_driver_flush(audio_st, settings->floats.slowmotion_ratio, - settings->bools.audio_fastforward_mute, samples_buf, 1024, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, @@ -1933,7 +1927,6 @@ void audio_driver_menu_sample(void) if (check_flush) audio_driver_flush(audio_st, settings->floats.slowmotion_ratio, - settings->bools.audio_fastforward_mute, samples_buf, sample_count, (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false, diff --git a/config.def.h b/config.def.h index fc5744f2d3..f4ea524c7c 100644 --- a/config.def.h +++ b/config.def.h @@ -1215,12 +1215,12 @@ #define DEFAULT_AUDIO_RESPECT_SILENT_MODE true #endif -/* Automatically mute audio when fast forward - * is enabled */ +/* Automatically mute audio when fast forward is enabled. */ #define DEFAULT_AUDIO_FASTFORWARD_MUTE false -/* Speed up audio to match fast-forward speed up. - * Avoids crackling */ +/* Speed up audio to match fast forward speed up. */ #define DEFAULT_AUDIO_FASTFORWARD_SPEEDUP false +/* Automatically mute audio when rewind is enabled. */ +#define DEFAULT_AUDIO_REWIND_MUTE false #ifdef HAVE_MICROPHONE /* Microphone support */ diff --git a/configuration.c b/configuration.c index 19fec63924..baa0776947 100644 --- a/configuration.c +++ b/configuration.c @@ -1838,6 +1838,7 @@ static struct config_bool_setting *populate_settings_bool( #endif SETTING_BOOL("audio_fastforward_mute", &settings->bools.audio_fastforward_mute, true, DEFAULT_AUDIO_FASTFORWARD_MUTE, false); SETTING_BOOL("audio_fastforward_speedup", &settings->bools.audio_fastforward_speedup, true, DEFAULT_AUDIO_FASTFORWARD_SPEEDUP, false); + SETTING_BOOL("audio_rewind_mute", &settings->bools.audio_rewind_mute, true, DEFAULT_AUDIO_REWIND_MUTE, false); #ifdef HAVE_WASAPI SETTING_BOOL("audio_wasapi_exclusive_mode", &settings->bools.audio_wasapi_exclusive_mode, true, DEFAULT_WASAPI_EXCLUSIVE_MODE, false); diff --git a/configuration.h b/configuration.h index 185c7a833c..258645c453 100644 --- a/configuration.h +++ b/configuration.h @@ -662,6 +662,7 @@ typedef struct settings bool audio_rate_control; bool audio_fastforward_mute; bool audio_fastforward_speedup; + bool audio_rewind_mute; #ifdef IOS bool audio_respect_silent_mode; #endif diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index f31243d012..e2aea56624 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2986,7 +2986,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, - "Mute When Fast-Forwarding" + "Fast-Forward Audio Mute" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, @@ -2994,12 +2994,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_SPEEDUP, - "Speedup When Fast-Forwarding" + "Fast-Forward Audio Speedup" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP, "Speed up audio when fast-forwarding. Prevents crackling but shifts pitch." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + "Rewind Audio Mute" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE, + "Automatically mute audio when using rewind." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Volume Gain (dB)" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 0bfc17f019..1e3d044d0a 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -538,6 +538,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_audio_mixer_mute, MENU_ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_audio_respect_silent_mode, MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE) #endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_audio_fastforward_mute, MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_audio_rewind_mute, MENU_ENUM_SUBLABEL_AUDIO_REWIND_MUTE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_audio_fastforward_speedup, MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_SPEEDUP) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_camera_allow, MENU_ENUM_SUBLABEL_CAMERA_ALLOW) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_location_allow, MENU_ENUM_SUBLABEL_LOCATION_ALLOW) @@ -4675,6 +4676,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_respect_silent_mode); break; #endif + case MENU_ENUM_LABEL_AUDIO_REWIND_MUTE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_rewind_mute); + break; case MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_fastforward_mute); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index bf2ee5a7f4..29fd42ba4a 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -7731,52 +7731,31 @@ unsigned menu_displaylist_build_list( break; case DISPLAYLIST_AUDIO_SETTINGS_LIST: { - bool audio_mute_enable = *audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE); -#if defined(HAVE_AUDIOMIXER) - bool audio_mixer_mute_enable = *audio_get_bool_ptr(AUDIO_ACTION_MIXER_MUTE_ENABLE); -#else - bool audio_mixer_mute_enable = true; -#endif menu_displaylist_build_info_selective_t build_list[] = { - {MENU_ENUM_LABEL_AUDIO_OUTPUT_SETTINGS, PARSE_ACTION, true }, + {MENU_ENUM_LABEL_AUDIO_OUTPUT_SETTINGS, PARSE_ACTION, true }, #ifdef HAVE_MICROPHONE - {MENU_ENUM_LABEL_MICROPHONE_SETTINGS, PARSE_ACTION, true }, + {MENU_ENUM_LABEL_MICROPHONE_SETTINGS, PARSE_ACTION, true }, #endif - {MENU_ENUM_LABEL_AUDIO_SYNCHRONIZATION_SETTINGS, PARSE_ACTION, true }, - {MENU_ENUM_LABEL_MIDI_SETTINGS, PARSE_ACTION, true }, - {MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS, PARSE_ACTION, false }, - {MENU_ENUM_LABEL_MENU_SOUNDS, PARSE_ACTION, true }, - {MENU_ENUM_LABEL_AUDIO_MUTE, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_AUDIO_MIXER_MUTE, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_AUDIO_RESPECT_SILENT_MODE, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_AUDIO_FASTFORWARD_SPEEDUP, PARSE_ONLY_BOOL, true }, - {MENU_ENUM_LABEL_AUDIO_VOLUME, PARSE_ONLY_FLOAT, false }, - {MENU_ENUM_LABEL_AUDIO_MIXER_VOLUME, PARSE_ONLY_FLOAT, false }, - {MENU_ENUM_LABEL_SYSTEM_BGM_ENABLE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_AUDIO_SYNCHRONIZATION_SETTINGS, PARSE_ACTION, true }, + {MENU_ENUM_LABEL_MIDI_SETTINGS, PARSE_ACTION, true }, +#if defined(HAVE_AUDIOMIXER) + {MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS, PARSE_ACTION, true }, +#endif + {MENU_ENUM_LABEL_MENU_SOUNDS, PARSE_ACTION, true }, + {MENU_ENUM_LABEL_AUDIO_VOLUME, PARSE_ONLY_FLOAT, true }, + {MENU_ENUM_LABEL_AUDIO_MIXER_VOLUME, PARSE_ONLY_FLOAT, true }, + {MENU_ENUM_LABEL_AUDIO_MUTE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_AUDIO_MIXER_MUTE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_AUDIO_RESPECT_SILENT_MODE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_SYSTEM_BGM_ENABLE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_AUDIO_REWIND_MUTE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_AUDIO_FASTFORWARD_SPEEDUP, PARSE_ONLY_BOOL, true }, #if defined(HAVE_DSP_FILTER) - {MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN, PARSE_ONLY_PATH, true }, + {MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN, PARSE_ONLY_PATH, true }, #endif }; - for (i = 0; i < ARRAY_SIZE(build_list); i++) - { - switch (build_list[i].enum_idx) - { - case MENU_ENUM_LABEL_AUDIO_VOLUME: - if (!audio_mute_enable) - build_list[i].checked = true; - break; - case MENU_ENUM_LABEL_AUDIO_MIXER_VOLUME: - case MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS: - if (!audio_mixer_mute_enable) - build_list[i].checked = true; - break; - default: - break; - } - } - for (i = 0; i < ARRAY_SIZE(build_list); i++) { if (!build_list[i].checked && !include_everything) @@ -11441,29 +11420,14 @@ unsigned menu_displaylist_build_list( break; case DISPLAYLIST_REWIND_SETTINGS_LIST: { - bool rewind_enable = settings->bools.rewind_enable; menu_displaylist_build_info_selective_t build_list[] = { - {MENU_ENUM_LABEL_REWIND_ENABLE, PARSE_ONLY_BOOL, true}, - {MENU_ENUM_LABEL_REWIND_GRANULARITY, PARSE_ONLY_UINT, false}, - {MENU_ENUM_LABEL_REWIND_BUFFER_SIZE, PARSE_ONLY_SIZE, false}, - {MENU_ENUM_LABEL_REWIND_BUFFER_SIZE_STEP, PARSE_ONLY_UINT, false}, + {MENU_ENUM_LABEL_REWIND_ENABLE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_REWIND_GRANULARITY, PARSE_ONLY_UINT, true }, + {MENU_ENUM_LABEL_REWIND_BUFFER_SIZE, PARSE_ONLY_SIZE, true }, + {MENU_ENUM_LABEL_REWIND_BUFFER_SIZE_STEP, PARSE_ONLY_UINT, true }, + {MENU_ENUM_LABEL_AUDIO_REWIND_MUTE, PARSE_ONLY_BOOL, true }, }; - for (i = 0; i < ARRAY_SIZE(build_list); i++) - { - switch (build_list[i].enum_idx) - { - case MENU_ENUM_LABEL_REWIND_GRANULARITY: - case MENU_ENUM_LABEL_REWIND_BUFFER_SIZE: - case MENU_ENUM_LABEL_REWIND_BUFFER_SIZE_STEP: - if (rewind_enable) - build_list[i].checked = true; - break; - default: - break; - } - } - for (i = 0; i < ARRAY_SIZE(build_list); i++) { if (!build_list[i].checked && !include_everything) @@ -11485,11 +11449,13 @@ unsigned menu_displaylist_build_list( #ifdef HAVE_REWIND {MENU_ENUM_LABEL_REWIND_SETTINGS, PARSE_ACTION, false}, #endif - {MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS, PARSE_ACTION, true}, - {MENU_ENUM_LABEL_FASTFORWARD_RATIO, PARSE_ONLY_FLOAT, true}, - {MENU_ENUM_LABEL_FASTFORWARD_FRAMESKIP, PARSE_ONLY_BOOL, true}, - {MENU_ENUM_LABEL_SLOWMOTION_RATIO, PARSE_ONLY_FLOAT, true}, - {MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE, PARSE_ONLY_BOOL, true}, + {MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS, PARSE_ACTION, true }, + {MENU_ENUM_LABEL_FASTFORWARD_RATIO, PARSE_ONLY_FLOAT, true }, + {MENU_ENUM_LABEL_FASTFORWARD_FRAMESKIP, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_AUDIO_FASTFORWARD_SPEEDUP, PARSE_ONLY_BOOL, true }, + {MENU_ENUM_LABEL_SLOWMOTION_RATIO, PARSE_ONLY_FLOAT, true }, + {MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE, PARSE_ONLY_BOOL, true }, {MENU_ENUM_LABEL_MENU_THROTTLE_FRAMERATE, PARSE_ONLY_BOOL, false}, }; diff --git a/menu/menu_setting.c b/menu/menu_setting.c index c8dc0f5d1b..d167d951ae 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -12210,10 +12210,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler, - SD_FLAG_CMD_APPLY_AUTO); - (*list)[list_info->index - 1].action_ok = &setting_bool_action_left_with_refresh; - (*list)[list_info->index - 1].action_left = &setting_bool_action_left_with_refresh; - (*list)[list_info->index - 1].action_right = &setting_bool_action_right_with_refresh; + SD_FLAG_NONE); MENU_SETTINGS_LIST_CURRENT_ADD_CMD(list, list_info, CMD_EVENT_REWIND_TOGGLE); CONFIG_UINT( @@ -14742,6 +14739,22 @@ static bool setting_append_list( SD_FLAG_NONE ); + CONFIG_BOOL( + list, list_info, + &settings->bools.audio_rewind_mute, + MENU_ENUM_LABEL_AUDIO_REWIND_MUTE, + MENU_ENUM_LABEL_VALUE_AUDIO_REWIND_MUTE, + DEFAULT_AUDIO_REWIND_MUTE, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE + ); + CONFIG_FLOAT( list, list_info, &settings->floats.audio_volume, diff --git a/msg_hash.h b/msg_hash.h index c195728ee9..6bf6e028b7 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2294,6 +2294,7 @@ enum msg_hash_enums MENU_LABEL(AUDIO_RESPECT_SILENT_MODE), MENU_LABEL(AUDIO_FASTFORWARD_MUTE), MENU_LABEL(AUDIO_FASTFORWARD_SPEEDUP), + MENU_LABEL(AUDIO_REWIND_MUTE), MENU_LABEL(AUDIO_SYNC), MENU_LBL_H(AUDIO_VOLUME), MENU_LABEL(AUDIO_MIXER_VOLUME), diff --git a/retroarch.c b/retroarch.c index 3e5e6550f9..dc692e4333 100644 --- a/retroarch.c +++ b/retroarch.c @@ -5289,17 +5289,14 @@ bool command_event(enum event_command cmd, void *data) } break; case CMD_EVENT_VOLUME_UP: - { - audio_driver_state_t - *audio_st = audio_state_get_ptr(); - command_event_set_volume(settings, 0.5f, + command_event_set_volume(settings, 0.5f, #if defined(HAVE_GFX_WIDGETS) - dispwidget_get_ptr()->active, + dispwidget_get_ptr()->active, #else - false, + false, #endif - audio_st->mute_enable); - } + audio_state_get_ptr()->mute_enable + ); break; case CMD_EVENT_VOLUME_DOWN: command_event_set_volume(settings, -0.5f, @@ -5309,7 +5306,7 @@ bool command_event(enum event_command cmd, void *data) false, #endif audio_state_get_ptr()->mute_enable - ); + ); break; case CMD_EVENT_MIXER_VOLUME_UP: command_event_set_mixer_volume(settings, 0.5f); diff --git a/runloop.c b/runloop.c index 227898a6bb..9f6ce406f7 100644 --- a/runloop.c +++ b/runloop.c @@ -3965,6 +3965,7 @@ static void runloop_apply_fastmotion_override(runloop_state_t *runloop_st, setti { float fastforward_ratio_current; video_driver_state_t *video_st = video_state_get_ptr(); + audio_driver_state_t *audio_st = audio_state_get_ptr(); bool frame_time_counter_reset_after_fastforwarding = settings ? settings->bools.frame_time_counter_reset_after_fastforwarding : false; float fastforward_ratio_default = settings ? @@ -3992,6 +3993,11 @@ static void runloop_apply_fastmotion_override(runloop_state_t *runloop_st, setti else runloop_st->flags &= ~RUNLOOP_FLAG_FASTMOTION; + if (settings->bools.audio_fastforward_mute && (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)) + audio_st->flags |= AUDIO_FLAG_MUTED; + else + audio_st->flags &= ~AUDIO_FLAG_MUTED; + if (input_st) { if (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION) @@ -5458,6 +5464,7 @@ static enum runloop_state_enum runloop_check_state( uico_driver_state_t *uico_st = uico_state_get_ptr(); input_driver_state_t *input_st = input_state_get_ptr(); video_driver_state_t *video_st = video_state_get_ptr(); + audio_driver_state_t *audio_st = audio_state_get_ptr(); gfx_display_t *p_disp = disp_get_ptr(); runloop_state_t *runloop_st = &runloop_state; static bool old_focus = true; @@ -6165,6 +6172,14 @@ static enum runloop_state_enum runloop_check_state( , s, sizeof(s), &t); + if (rewind_pressed != old_rewind_pressed) + { + if (settings->bools.audio_rewind_mute && rewind_pressed) + audio_st->flags |= AUDIO_FLAG_MUTED; + else + audio_st->flags &= ~AUDIO_FLAG_MUTED; + } + old_rewind_pressed = rewind_pressed; #if defined(HAVE_GFX_WIDGETS) @@ -6438,6 +6453,11 @@ static enum runloop_state_enum runloop_check_state( command_event(CMD_EVENT_SET_FRAME_LIMIT, NULL); } + if (settings->bools.audio_fastforward_mute && (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)) + audio_st->flags |= AUDIO_FLAG_MUTED; + else + audio_st->flags &= ~AUDIO_FLAG_MUTED; + driver_set_nonblock_state(); /* Reset frame time counter when toggling diff --git a/ui/drivers/qt/qt_options.cpp b/ui/drivers/qt/qt_options.cpp index 455aaf4a99..d9ab5588f5 100644 --- a/ui/drivers/qt/qt_options.cpp +++ b/ui/drivers/qt/qt_options.cpp @@ -190,7 +190,10 @@ QWidget *AudioPage::widget() 2, 3, 1, 1); volumeGroup->addRow(volumeLayout); + volumeGroup->add(MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE); + volumeGroup->add(MENU_ENUM_LABEL_AUDIO_FASTFORWARD_SPEEDUP); + volumeGroup->add(MENU_ENUM_LABEL_AUDIO_REWIND_MUTE); layout->addWidget(outputGroup); layout->addWidget(resamplerGroup); From 376e4b307cdf141f6680eae925b09ff4376f4e33 Mon Sep 17 00:00:00 2001 From: LibretroAdmin Date: Sun, 9 Feb 2025 15:40:45 +0100 Subject: [PATCH 203/574] Style nits --- command.c | 29 +++++++++---------- menu/menu_explore.c | 64 ++++++++++++++++++++++------------------- menu/menu_setting.c | 70 +++++++++++++++++++-------------------------- retroarch.c | 8 +++--- runloop.c | 12 ++++---- 5 files changed, 86 insertions(+), 97 deletions(-) diff --git a/command.c b/command.c index d55e8d42ab..f2ab73637a 100644 --- a/command.c +++ b/command.c @@ -183,13 +183,12 @@ typedef struct socklen_t cmd_source_len; } command_network_t; -static void network_command_reply( - command_t *cmd, - const char * data, size_t len) +static void network_command_reply(command_t *cmd, + const char *s, size_t len) { command_network_t *netcmd = (command_network_t*)cmd->userptr; /* Respond (fire and forget since it's UDP) */ - sendto(netcmd->net_fd, data, len, 0, + sendto(netcmd->net_fd, s, len, 0, (struct sockaddr*)&netcmd->cmd_source, netcmd->cmd_source_len); } @@ -280,12 +279,11 @@ typedef struct char stdin_buf[CMD_BUF_SIZE]; } command_stdin_t; -static void stdin_command_reply( - command_t *cmd, - const char * data, size_t len) +static void stdin_command_reply(command_t *cmd, + const char *s, size_t len) { /* Just write to stdout! */ - fwrite(data, 1, len, stdout); + fwrite(s, 1, len, stdout); fflush(stdout); } @@ -445,12 +443,11 @@ typedef struct int last_fd; } command_uds_t; -static void uds_command_reply( - command_t *cmd, - const char * data, size_t len) +static void uds_command_reply(command_t *cmd, + const char *s, size_t len) { command_uds_t *subcmd = (command_uds_t*)cmd->userptr; - write(subcmd->last_fd, data, len); + write(subcmd->last_fd, s, len); } static void uds_command_free(command_t *handle) @@ -1165,8 +1162,8 @@ void command_event_init_controllers(rarch_system_info_t *sys_info, } #ifdef HAVE_CONFIGFILE -static size_t command_event_save_config( - const char *config_path, char *s, size_t len) +static size_t command_event_save_config(const char *config_path, + char *s, size_t len) { size_t _len = 0; bool path_exists = !string_is_empty(config_path); @@ -1238,8 +1235,8 @@ static size_t command_event_undo_load_state(char *s, size_t len) bool command_event_resize_windowed_scale(settings_t *settings, unsigned window_scale) { - unsigned idx = 0; - bool video_fullscreen = settings->bools.video_fullscreen; + unsigned idx = 0; + bool video_fullscreen = settings->bools.video_fullscreen; if (window_scale == 0) return false; diff --git a/menu/menu_explore.c b/menu/menu_explore.c index 1e3e1c3e14..3ac2023da4 100644 --- a/menu/menu_explore.c +++ b/menu/menu_explore.c @@ -550,20 +550,20 @@ explore_state_t *menu_explore_build_list(const char *directory_playlist, rdb_num = RHMAP_GET(rdb_indices, rdb_hash); if (!rdb_num) { - size_t systemname_len; + size_t _len; struct explore_rdb newrdb; - char *ext_path = NULL; + char *ext_path = NULL; - newrdb.handle = libretrodb_new(); - newrdb.count = 0; - newrdb.playlist_crcs = NULL; - newrdb.playlist_names = NULL; + newrdb.handle = libretrodb_new(); + newrdb.count = 0; + newrdb.playlist_crcs = NULL; + newrdb.playlist_names = NULL; - systemname_len = db_ext - db_name; - if (systemname_len >= sizeof(newrdb.systemname)) - systemname_len = sizeof(newrdb.systemname)-1; - memcpy(newrdb.systemname, db_name, systemname_len); - newrdb.systemname[systemname_len] = '\0'; + _len = db_ext - db_name; + if (_len >= sizeof(newrdb.systemname)) + _len = sizeof(newrdb.systemname)-1; + memcpy(newrdb.systemname, db_name, _len); + newrdb.systemname[_len] = '\0'; fill_pathname_join_special( tmp, directory_database, db_name, sizeof(tmp)); @@ -971,7 +971,8 @@ static void explore_action_find_complete(void *userdata, const char *line) } } -static int explore_action_ok_find(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) +static int explore_action_ok_find(const char *path, const char *label, + unsigned type, size_t idx, size_t entry_idx) { menu_input_ctx_line_t line; line.label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SEARCH); @@ -983,8 +984,8 @@ static int explore_action_ok_find(const char *path, const char *label, unsigned return 0; } -static const char* explore_get_view_path(struct menu_state *menu_st, menu_list_t *menu_list, - file_list_t *menu_stack) +static const char* explore_get_view_path(struct menu_state *menu_st, + menu_list_t *menu_list, file_list_t *menu_stack) { struct item_file *cur = (struct item_file *)&menu_stack->list[menu_stack->size - 1]; @@ -994,13 +995,16 @@ static const char* explore_get_view_path(struct menu_state *menu_st, menu_list_t const menu_ctx_driver_t *driver_ctx = menu_st->driver_ctx; if (driver_ctx->list_get_entry) { - size_t selection = driver_ctx->list_get_selection ? driver_ctx->list_get_selection(menu_st->userdata) : 0; - size_t _len = driver_ctx->list_get_size ? driver_ctx->list_get_size(menu_st->userdata, MENU_LIST_TABS) : 0; + size_t selection = driver_ctx->list_get_selection + ? driver_ctx->list_get_selection(menu_st->userdata) : 0; + size_t _len = driver_ctx->list_get_size + ? driver_ctx->list_get_size(menu_st->userdata, MENU_LIST_TABS) : 0; if (selection > 0 && _len > 0) { struct item_file *item = NULL; /* Label contains the path and path contains the label */ - if ((item = (struct item_file*)driver_ctx->list_get_entry(menu_st->userdata, MENU_LIST_HORIZONTAL, + if ((item = (struct item_file*)driver_ctx->list_get_entry( + menu_st->userdata, MENU_LIST_HORIZONTAL, (unsigned)(selection - (_len +1))))) return item->label; } @@ -1029,7 +1033,8 @@ static void explore_on_edit_views(enum msg_hash_enums msg) MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } -static int explore_action_ok_deleteview(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) +static int explore_action_ok_deleteview(const char *path, const char *label, + unsigned type, size_t idx, size_t entry_idx) { struct menu_state *menu_st = menu_state_get_ptr(); menu_list_t *menu_list = menu_st->entries.list; @@ -1151,7 +1156,8 @@ static void explore_action_saveview_complete(void *userdata, const char *name) explore_on_edit_views(MENU_ENUM_LABEL_EXPLORE_VIEW_SAVED); } -static int explore_action_ok_saveview(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) +static int explore_action_ok_saveview(const char *path, const char *label, + unsigned type, size_t idx, size_t entry_idx) { menu_input_ctx_line_t line; line.label = msg_hash_to_str(MENU_ENUM_LABEL_EXPLORE_NEW_VIEW); @@ -1446,33 +1452,33 @@ unsigned menu_displaylist_explore(file_list_t *list, settings_t *settings) && !explore_by_info[cat].is_boolean && RBUF_LEN(state->by[cat]) > 1)) { - size_t tmplen = strlcpy(tmp, + size_t _len = strlcpy(tmp, msg_hash_to_str(explore_by_info[cat].by_enum), sizeof(tmp)); if (is_top) { if (explore_by_info[cat].is_numeric) - snprintf(tmp + tmplen, - sizeof(tmp) - tmplen, + snprintf(tmp + _len, + sizeof(tmp) - _len, " (%s - %s)", entries[0]->str, entries[RBUF_LEN(entries) - 1]->str); else if (!explore_by_info[cat].is_boolean) { - tmplen += strlcpy (tmp + tmplen, " (", sizeof(tmp) - tmplen); - tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, + _len += strlcpy (tmp + _len, " (", sizeof(tmp) - _len); + _len += snprintf(tmp + _len, sizeof(tmp) - _len, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_EXPLORE_ITEMS_COUNT), (unsigned)RBUF_LEN(entries)); - strlcpy(tmp + tmplen, ")", sizeof(tmp) - tmplen); + strlcpy(tmp + _len, ")", sizeof(tmp) - _len); } } else if (i != state->view_levels) { - tmplen += strlcpy(tmp + tmplen, " (", sizeof(tmp) - tmplen); - tmplen += strlcpy(tmp + tmplen, + _len += strlcpy(tmp + _len, " (", sizeof(tmp) - _len); + _len += strlcpy(tmp + _len, msg_hash_to_str(MENU_ENUM_LABEL_EXPLORE_RANGE_FILTER), - sizeof(tmp) - tmplen); - strlcpy(tmp + tmplen, ")", sizeof(tmp) - tmplen); + sizeof(tmp) - _len); + strlcpy(tmp + _len, ")", sizeof(tmp) - _len); } explore_menu_entry(list, state, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index d167d951ae..6feb13b46f 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -1069,7 +1069,9 @@ static void setting_get_string_representation_int_gpu_index(rarch_setting_t *set { struct string_list *list = video_driver_get_gpu_api_devices(video_context_driver_get_api()); size_t _len = snprintf(s, len, "%d", *setting->value.target.integer); - if (list && (*setting->value.target.integer < (int)list->size) && !string_is_empty(list->elems[*setting->value.target.integer].data)) + if ( list + && (*setting->value.target.integer < (int)list->size) + && !string_is_empty(list->elems[*setting->value.target.integer].data)) { s[ _len] = ' '; s[++_len] = '-'; @@ -1081,8 +1083,7 @@ static void setting_get_string_representation_int_gpu_index(rarch_setting_t *set } static void setting_get_string_representation_int( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (setting) snprintf(s, len, "%d", *setting->value.target.integer); @@ -1259,13 +1260,12 @@ static void setting_get_string_representation_st_dir(rarch_setting_t *setting, char *s, size_t len) { if (setting) -#if IOS { +#if IOS if (*setting->value.target.string) fill_pathname_abbreviate_special(s, setting->value.target.string, len); else strlcpy(s, setting->dir.empty_path, len); - } #else strlcpy(s, *setting->value.target.string @@ -1273,18 +1273,21 @@ static void setting_get_string_representation_st_dir(rarch_setting_t *setting, : setting->dir.empty_path, len); #endif + } } static void setting_get_string_representation_st_path(rarch_setting_t *setting, char *s, size_t len) { if (setting) + { #if IOS fill_pathname_abbreviate_special(s, path_basename(setting->value.target.string), len); #else fill_pathname(s, path_basename(setting->value.target.string), "", len); #endif + } } static void setting_get_string_representation_st_string(rarch_setting_t *setting, @@ -2541,8 +2544,8 @@ static void end_sub_group( /* MENU SETTINGS */ -static int setting_action_ok_bind_all( - rarch_setting_t *setting, size_t idx, bool wraparound) +static int setting_action_ok_bind_all(rarch_setting_t *setting, + size_t idx, bool wraparound) { if (!menu_input_key_bind_set_mode(MENU_INPUT_BINDS_CTL_BIND_ALL, setting)) return -1; @@ -2572,7 +2575,8 @@ static int setting_action_ok_bind_all_save_autoconfig( char buf[128]; char msg[NAME_MAX_LENGTH]; config_get_autoconf_profile_filename(name, index_offset, buf, sizeof(buf)); - _len = snprintf(msg, sizeof(msg),msg_hash_to_str(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY_NAMED), buf); + _len = snprintf(msg, sizeof(msg), + msg_hash_to_str(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY_NAMED), buf); runloop_msg_queue_push(msg, _len, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } @@ -2849,8 +2853,7 @@ static int setting_string_action_ok_microphone_device( #endif static void setting_get_string_representation_streaming_mode( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -2881,8 +2884,7 @@ static void setting_get_string_representation_streaming_mode( } static void setting_get_string_representation_video_stream_quality( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -3036,8 +3038,7 @@ static void setting_get_string_representation_password( #if TARGET_OS_IPHONE static void setting_get_string_representation_uint_keyboard_gamepad_mapping_type( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -3062,8 +3063,7 @@ static void setting_get_string_representation_uint_keyboard_gamepad_mapping_type #ifdef HAVE_TRANSLATE static void setting_get_string_representation_uint_ai_service_mode( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { enum msg_hash_enums enum_idx = MSG_UNKNOWN; if (!setting) @@ -5057,8 +5057,7 @@ static void setting_get_string_representation_crt_switch_resolution_super( } static void setting_get_string_representation_uint_playlist_sublabel_runtime_type( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5081,8 +5080,7 @@ static void setting_get_string_representation_uint_playlist_sublabel_runtime_typ } static void setting_get_string_representation_uint_playlist_sublabel_last_played_style( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5234,8 +5232,7 @@ static void setting_get_string_representation_uint_playlist_sublabel_last_played } static void setting_get_string_representation_uint_playlist_inline_core_display_type( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5264,8 +5261,7 @@ static void setting_get_string_representation_uint_playlist_inline_core_display_ } static void setting_get_string_representation_uint_playlist_entry_remove_enable( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5295,8 +5291,7 @@ static void setting_get_string_representation_uint_playlist_entry_remove_enable( #ifdef _3DS static void setting_get_string_representation_uint_video_3ds_display_mode( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5333,8 +5328,7 @@ static void setting_get_string_representation_uint_video_3ds_display_mode( #if defined(DINGUX) static void setting_get_string_representation_uint_video_dingux_ipu_filter_type( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5364,8 +5358,7 @@ static void setting_get_string_representation_uint_video_dingux_ipu_filter_type( #if defined(DINGUX_BETA) static void setting_get_string_representation_uint_video_dingux_refresh_rate( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5390,8 +5383,7 @@ static void setting_get_string_representation_uint_video_dingux_refresh_rate( #if defined(RS90) || defined(MIYOO) static void setting_get_string_representation_uint_video_dingux_rs90_softfilter_type( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5416,8 +5408,7 @@ static void setting_get_string_representation_uint_video_dingux_rs90_softfilter_ #endif static void setting_get_string_representation_uint_input_auto_game_focus( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5447,8 +5438,7 @@ static void setting_get_string_representation_uint_input_auto_game_focus( #if defined(HAVE_OVERLAY) static void setting_get_string_representation_uint_input_overlay_show_inputs( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -5477,8 +5467,7 @@ static void setting_get_string_representation_uint_input_overlay_show_inputs( } static void setting_get_string_representation_uint_input_overlay_show_inputs_port( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (setting) snprintf(s, len, "%u", @@ -5499,8 +5488,7 @@ static void setting_get_string_representation_overlay_lightgun_port( } static void setting_get_string_representation_overlay_lightgun_action( - rarch_setting_t *setting, - char *s, size_t len) + rarch_setting_t *setting, char *s, size_t len) { if (!setting) return; @@ -23614,7 +23602,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler, - SD_FLAG_CMD_APPLY_AUTO); + SD_FLAG_CMD_APPLY_AUTO); #endif diff --git a/retroarch.c b/retroarch.c index dc692e4333..a4f47313fb 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2348,11 +2348,11 @@ static struct string_list *string_list_new_special( char zone_desc[TIMEZONE_LENGTH]; while (fgets(zone_desc, TIMEZONE_LENGTH, zones_file)) { - size_t zone_desc_len = strlen(zone_desc); + size_t _len = strlen(zone_desc); - if (zone_desc_len > 0) - if (zone_desc[--zone_desc_len] == '\n') - zone_desc[zone_desc_len] = '\0'; + if (_len > 0) + if (zone_desc[--_len] == '\n') + zone_desc[_len] = '\0'; if (zone_desc && zone_desc[0] != '\0') { diff --git a/runloop.c b/runloop.c index 9f6ce406f7..a33c19f3ab 100644 --- a/runloop.c +++ b/runloop.c @@ -561,7 +561,7 @@ void libretro_get_environment_info( runloop_st->flags &= ~RUNLOOP_FLAG_IGNORE_ENVIRONMENT_CB; } -static dylib_t load_dynamic_core(const char *path, char *buf, +static dylib_t load_dynamic_core(const char *path, char *s, size_t len) { #if defined(ANDROID) @@ -593,7 +593,7 @@ static dylib_t load_dynamic_core(const char *path, char *buf, /* Need to use absolute path for this setting. It can be * saved to content history, and a relative path would * break in that scenario. */ - path_resolve_realpath(buf, len, resolve_symlinks); + path_resolve_realpath(s, len, resolve_symlinks); return dylib_load(path); } @@ -1116,8 +1116,7 @@ static bool validate_per_core_options(char *s, return true; } -static bool validate_game_options( - const char *core_name, +static bool validate_game_options(const char *core_name, char *s, size_t len, bool mkdir) { const char *game_name = path_basename_nocompression(path_get(RARCH_PATH_BASENAME)); @@ -1466,9 +1465,8 @@ bool runloop_environment_cb(unsigned cmd, void *data) case RETRO_ENVIRONMENT_SET_VARIABLE: { + size_t opt_idx, val_idx; const struct retro_variable *var = (const struct retro_variable*)data; - size_t opt_idx; - size_t val_idx; /* If core passes NULL to the callback, return * value indicates whether callback is supported */ @@ -7743,7 +7741,7 @@ void core_run(void) current_core->retro_run(); - + #ifdef HAVE_GAME_AI settings_t *settings = config_get_ptr(); From 0be8fe8e3f305132f3abd09107281d9c2d59d9ef Mon Sep 17 00:00:00 2001 From: LibretroAdmin Date: Sun, 9 Feb 2025 16:07:15 +0100 Subject: [PATCH 204/574] Style nits --- libretro-common/lists/nested_list.c | 21 ++-- libretro-common/streams/rzip_stream.c | 34 +++--- menu/drivers/ozone.c | 144 ++++++++++++-------------- menu/drivers/rgui.c | 34 +++--- menu/drivers/xmb.c | 32 +++--- menu/menu_displaylist.c | 4 +- 6 files changed, 127 insertions(+), 142 deletions(-) diff --git a/libretro-common/lists/nested_list.c b/libretro-common/lists/nested_list.c index 4c5be0f5e6..df6bd3019d 100644 --- a/libretro-common/lists/nested_list.c +++ b/libretro-common/lists/nested_list.c @@ -234,8 +234,8 @@ bool nested_list_add_item(nested_list_t *list, else { string_list_initialize(&id_list); - if (!string_split_noalloc(&id_list, address, delim) || - (id_list.size < 1)) + if ( !string_split_noalloc(&id_list, address, delim) + || (id_list.size < 1)) goto end; if (id_list.size == 1) @@ -357,8 +357,8 @@ nested_list_item_t *nested_list_get_item(nested_list_t *list, else { string_list_initialize(&id_list); - if (!string_split_noalloc(&id_list, address, delim) || - (id_list.size < 1)) + if ( !string_split_noalloc(&id_list, address, delim) + || (id_list.size < 1)) goto end; if (id_list.size == 1) @@ -536,10 +536,10 @@ bool nested_list_item_get_address(nested_list_item_t *list_item, union string_list_elem_attr attr; size_t i; - if (!list_item || - string_is_empty(delim) || - !address || - (len < 1)) + if ( !list_item + || string_is_empty(delim) + || !address + || (len < 1)) goto end; address[0] = '\0'; @@ -562,9 +562,8 @@ bool nested_list_item_get_address(nested_list_item_t *list_item, do { const char *id = current_item->id; - - if (string_is_empty(id) || - !string_list_append(&id_list, id, attr)) + if ( string_is_empty(id) + || !string_list_append(&id_list, id, attr)) goto end; current_item = current_item->parent_item; diff --git a/libretro-common/streams/rzip_stream.c b/libretro-common/streams/rzip_stream.c index 6f56fa66c6..e4058b9d22 100644 --- a/libretro-common/streams/rzip_stream.c +++ b/libretro-common/streams/rzip_stream.c @@ -97,15 +97,15 @@ static bool rzipstream_read_file_header(rzipstream_t *stream) /* Check 'magic numbers' - first 8 bytes * of header */ if ( - (length < RZIP_HEADER_SIZE) || - (header_bytes[0] != 35) || /* # */ - (header_bytes[1] != 82) || /* R */ - (header_bytes[2] != 90) || /* Z */ - (header_bytes[3] != 73) || /* I */ - (header_bytes[4] != 80) || /* P */ - (header_bytes[5] != 118) || /* v */ - (header_bytes[6] != RZIP_VERSION) || /* file format version number */ - (header_bytes[7] != 35)) /* # */ + (length < RZIP_HEADER_SIZE) + || (header_bytes[0] != 35) /* # */ + || (header_bytes[1] != 82) /* R */ + || (header_bytes[2] != 90) /* Z */ + || (header_bytes[3] != 73) /* I */ + || (header_bytes[4] != 80) /* P */ + || (header_bytes[5] != 118) /* v */ + || (header_bytes[6] != RZIP_VERSION) /* file format version number */ + || (header_bytes[7] != 35)) /* # */ { /* Reset file to start */ filestream_seek(stream->file, 0, SEEK_SET); @@ -270,7 +270,7 @@ static bool rzipstream_init_stream( stream->in_buf_size = stream->chunk_size; stream->out_buf_size = stream->chunk_size * 2; /* > Account for minimum zlib overhead - * of 11 bytes... */ + * of 11 bytes... */ stream->out_buf_size = (stream->out_buf_size < (stream->in_buf_size + 11)) ? stream->out_buf_size + 11 : @@ -385,9 +385,9 @@ rzipstream_t* rzipstream_open(const char *path, unsigned mode) /* Sanity check * > Only RETRO_VFS_FILE_ACCESS_READ and * RETRO_VFS_FILE_ACCESS_WRITE are supported */ - if (string_is_empty(path) || - ((mode != RETRO_VFS_FILE_ACCESS_READ) && - (mode != RETRO_VFS_FILE_ACCESS_WRITE))) + if (string_is_empty(path) + || ( (mode != RETRO_VFS_FILE_ACCESS_READ) + && (mode != RETRO_VFS_FILE_ACCESS_WRITE))) return NULL; /* If opening in read mode, ensure file exists */ @@ -506,8 +506,8 @@ static bool rzipstream_read_chunk(rzipstream_t *stream) if (inflate_read != compressed_chunk_size) return false; - if ((inflate_written == 0) || - (inflate_written > stream->out_buf_size)) + if ( (inflate_written == 0) + || (inflate_written > stream->out_buf_size)) return false; /* Record current output buffer occupancy @@ -753,8 +753,8 @@ static bool rzipstream_write_chunk(rzipstream_t *stream) if (deflate_read != stream->in_buf_ptr) return false; - if ((deflate_written == 0) || - (deflate_written > stream->out_buf_size)) + if ( (deflate_written == 0) + || (deflate_written > stream->out_buf_size)) return false; /* Write compressed chunk size to file */ diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index 06e816aca3..ef4b4da4db 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -479,7 +479,7 @@ struct ozone_handle } fonts; size_t (*word_wrap)( - char *dst, size_t dst_size, + char *s, size_t len, const char *src, size_t src_len, int line_width, int wideglyph_width, unsigned max_lines); @@ -2377,23 +2377,23 @@ static uintptr_t ozone_entries_icon_get_texture( case MENU_SETTING_ACTION_CORE_OPTIONS: if (string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_VIDEO]; - else if (string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS)) || - string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SOUND_SETTINGS))) + else if ( string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS)) + || string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SOUND_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_AUDIO]; else if (string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_SETTINGS]; else if (string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_OSD]; - else if (string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS)) || - string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TIMING_SETTINGS))) + else if ( string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS)) + || string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TIMING_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_LATENCY]; else if (string_starts_with(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PERFORMANCE_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_FRAMESKIP]; - else if (string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MEDIA_SETTINGS)) || - string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STORAGE_SETTINGS))) + else if ( string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MEDIA_SETTINGS)) + || string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STORAGE_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_RDB]; - else if (string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_SETTINGS)) || - string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SPECS_SETTINGS))) + else if ( string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_SETTINGS)) + || string_is_equal(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SPECS_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_DRIVERS]; else if (strstr(enum_path, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HACKS_SETTINGS))) return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_POWER]; @@ -3833,8 +3833,9 @@ static void ozone_update_savestate_thumbnail_image(void *data) /* Only request thumbnail if: * > Thumbnail has never been loaded *OR* * > Thumbnail path has changed */ - if ((ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_UNKNOWN) || - !string_is_equal(ozone->savestate_thumbnail_file_path, ozone->prev_savestate_thumbnail_file_path)) + if ((ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_UNKNOWN) + || !string_is_equal(ozone->savestate_thumbnail_file_path, + ozone->prev_savestate_thumbnail_file_path)) { gfx_thumbnail_request_file( ozone->savestate_thumbnail_file_path, @@ -4027,8 +4028,8 @@ static void ozone_sidebar_update_collapse( collapse = ozone_want_collapse(ozone, ozone_collapse_sidebar, is_playlist); /* Skip if already at wanted state */ - if ( (collapse && ozone->sidebar_collapsed) || - (!collapse && !ozone->sidebar_collapsed)) + if ( (collapse && ozone->sidebar_collapsed) + || (!collapse && !ozone->sidebar_collapsed)) goto end; /* Collapse it */ @@ -4479,11 +4480,8 @@ static ozone_node_t *ozone_copy_node(const ozone_node_t *old_node) return new_node; } -static void ozone_list_deep_copy( - const file_list_t *src, - file_list_t *dst, - size_t first, - size_t last) +static void ozone_list_deep_copy(const file_list_t *src, + file_list_t *dst, size_t first, size_t last) { size_t i, j = 0; uintptr_t tag = (uintptr_t)dst; @@ -4523,10 +4521,8 @@ static void ozone_list_deep_copy( dst->size = j; } -static void ozone_list_cache( - void *data, - enum menu_list_type type, - unsigned action) +static void ozone_list_cache(void *data, + enum menu_list_type type, unsigned action) { size_t y, entries_end; unsigned i; @@ -4595,10 +4591,8 @@ text_iterate: &ozone->selection_buf_old, first, last); } -static void ozone_change_tab( - ozone_handle_t *ozone, - enum msg_hash_enums tab, - enum menu_settings_type type) +static void ozone_change_tab(ozone_handle_t *ozone, + enum msg_hash_enums tab, enum menu_settings_type type) { struct menu_state *menu_st = menu_state_get_ptr(); menu_list_t *menu_list = menu_st->entries.list; @@ -4618,9 +4612,7 @@ static void ozone_change_tab( menu_driver_deferred_push_content_list(selection_buf); } -static void ozone_sidebar_goto( - ozone_handle_t *ozone, - unsigned new_selection) +static void ozone_sidebar_goto(ozone_handle_t *ozone, unsigned new_selection) { static const enum msg_hash_enums ozone_system_tabs_idx[OZONE_SYSTEM_TAB_LAST] = { MENU_ENUM_LABEL_MAIN_MENU, @@ -4759,10 +4751,8 @@ static void ozone_sidebar_entries_build_scroll_indices(ozone_handle_t *ozone) ozone->sidebar_index_size++; } -static void ozone_refresh_sidebars( - ozone_handle_t *ozone, - bool ozone_collapse_sidebar, - unsigned video_height) +static void ozone_refresh_sidebars(ozone_handle_t *ozone, + bool ozone_collapse_sidebar, unsigned video_height) { uintptr_t collapsed_tag = (uintptr_t)&ozone->sidebar_collapsed; uintptr_t offset_tag = (uintptr_t)&ozone->sidebar_offset; @@ -4869,13 +4859,10 @@ static size_t ozone_list_get_size(void *data, enum menu_list_type type) return 0; } -static void ozone_init_horizontal_list( - ozone_handle_t *ozone, - settings_t *settings) +static void ozone_init_horizontal_list(ozone_handle_t *ozone, settings_t *settings) { + size_t i, list_size; menu_displaylist_info_t info; - size_t list_size; - size_t i; const char *dir_playlist = settings->paths.directory_playlist; bool menu_content_show_playlists = settings->bools.menu_content_show_playlists; bool ozone_truncate_playlist_name = settings->bools.ozone_truncate_playlist_name; @@ -5106,8 +5093,7 @@ static void ozone_context_reset_horizontal_list(ozone_handle_t *ozone) } } -static void ozone_refresh_horizontal_list( - ozone_handle_t *ozone, +static void ozone_refresh_horizontal_list(ozone_handle_t *ozone, settings_t *settings) { struct menu_state *menu_st = menu_state_get_ptr(); @@ -5206,18 +5192,18 @@ static void ozone_draw_entry_value( && string_ends_with (entry->value, ")")) { if ( - string_is_equal(entry->value, "(PRESET)") || - string_is_equal(entry->value, "(SHADER)") || - string_is_equal(entry->value, "(COMP)") || - string_is_equal(entry->value, "(CORE)") || - string_is_equal(entry->value, "(MOVIE)") || - string_is_equal(entry->value, "(MUSIC)") || - string_is_equal(entry->value, "(DIR)") || - string_is_equal(entry->value, "(RDB)") || - string_is_equal(entry->value, "(CURSOR)")|| - string_is_equal(entry->value, "(CFILE)") || - string_is_equal(entry->value, "(FILE)") || - string_is_equal(entry->value, "(IMAGE)") + string_is_equal(entry->value, "(PRESET)") + || string_is_equal(entry->value, "(SHADER)") + || string_is_equal(entry->value, "(COMP)") + || string_is_equal(entry->value, "(CORE)") + || string_is_equal(entry->value, "(MOVIE)") + || string_is_equal(entry->value, "(MUSIC)") + || string_is_equal(entry->value, "(DIR)") + || string_is_equal(entry->value, "(RDB)") + || string_is_equal(entry->value, "(CURSOR)") + || string_is_equal(entry->value, "(CFILE)") + || string_is_equal(entry->value, "(FILE)") + || string_is_equal(entry->value, "(IMAGE)") ) return; } @@ -5362,10 +5348,8 @@ static void ozone_content_metadata_line( * And if we can scroll so that it's in the middle * Then scroll */ -static void ozone_update_scroll( - ozone_handle_t *ozone, - bool allow_animation, - ozone_node_t *node) +static void ozone_update_scroll(ozone_handle_t *ozone, + bool allow_animation, ozone_node_t *node) { unsigned video_info_height; gfx_animation_ctx_entry_t entry; @@ -5444,8 +5428,7 @@ static void ozone_update_scroll( } static int ozone_get_sublabel_max_width(ozone_handle_t *ozone, - unsigned video_info_width, - unsigned entry_padding) + unsigned video_info_width, unsigned entry_padding) { int sublabel_max_width = video_info_width - (entry_padding * 2) @@ -5464,10 +5447,8 @@ static int ozone_get_sublabel_max_width(ozone_handle_t *ozone, return sublabel_max_width; } -static void ozone_compute_entries_position( - ozone_handle_t *ozone, - bool menu_show_sublabels, - size_t entries_end) +static void ozone_compute_entries_position(ozone_handle_t *ozone, + bool menu_show_sublabels, size_t entries_end) { size_t i; /* Compute entries height and adjust scrolling if needed */ @@ -5587,8 +5568,8 @@ static void ozone_draw_entries( bool is_playlist, math_matrix_4x4 *mymat) { - uint32_t alpha_uint32; size_t i; + uint32_t alpha_uint32; float bottom_boundary; unsigned video_info_height, video_info_width; bool menu_show_sublabels = settings->bools.menu_show_sublabels; @@ -7183,9 +7164,12 @@ static void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone) } else { - bool left_thumbnail_enabled = gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT); + bool left_thumbnail_enabled = gfx_thumbnail_is_enabled( + menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT); - if (!left_thumbnail_enabled && !gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_RIGHT)) + if ( !left_thumbnail_enabled + && !gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, + GFX_THUMBNAIL_RIGHT)) return; if ( (ozone->thumbnails.right.status == GFX_THUMBNAIL_STATUS_AVAILABLE) @@ -7339,8 +7323,8 @@ static void ozone_draw_fullscreen_thumbnails( * > Return instead of error to keep fullscreen * mode after menu/fullscreen toggle */ if (num_thumbnails < 1 && - (right_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING && - left_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING)) + ( right_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING + && left_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING)) return; /* Get base thumbnail dimensions + draw positions */ @@ -7348,7 +7332,8 @@ static void ozone_draw_fullscreen_thumbnails( /* > Thumbnail bounding box height + y position * are fixed */ thumbnail_box_height = view_height - (thumbnail_margin * 2); - thumbnail_y = ozone->dimensions.header_height + thumbnail_margin + ozone->dimensions.spacer_1px; + thumbnail_y = ozone->dimensions.header_height + thumbnail_margin + + ozone->dimensions.spacer_1px; /* Thumbnail bounding box width and x position * depend upon number of active thumbnails */ @@ -7356,7 +7341,8 @@ static void ozone_draw_fullscreen_thumbnails( { thumbnail_box_width = (view_width - (thumbnail_margin * 3) - frame_width) >> 1; left_thumbnail_x = thumbnail_margin; - right_thumbnail_x = left_thumbnail_x + thumbnail_box_width + frame_width + thumbnail_margin; + right_thumbnail_x = left_thumbnail_x + thumbnail_box_width + frame_width + + thumbnail_margin; } else { @@ -7366,8 +7352,8 @@ static void ozone_draw_fullscreen_thumbnails( } /* Sanity check */ - if ((thumbnail_box_width < 1) || - (thumbnail_box_height < 1)) + if ( (thumbnail_box_width < 1) + || (thumbnail_box_height < 1)) goto error; /* Get thumbnail draw dimensions @@ -7388,8 +7374,8 @@ static void ozone_draw_fullscreen_thumbnails( &right_thumbnail_draw_height); /* Sanity check */ - if ((right_thumbnail_draw_width <= 0.0f) || - (right_thumbnail_draw_height <= 0.0f)) + if ( (right_thumbnail_draw_width <= 0.0f) + || (right_thumbnail_draw_height <= 0.0f)) goto error; } @@ -7404,8 +7390,8 @@ static void ozone_draw_fullscreen_thumbnails( &left_thumbnail_draw_height); /* Sanity check */ - if ((left_thumbnail_draw_width <= 0.0f) || - (left_thumbnail_draw_height <= 0.0f)) + if ( (left_thumbnail_draw_width <= 0.0f) + || (left_thumbnail_draw_height <= 0.0f)) goto error; } @@ -7907,14 +7893,14 @@ static bool ozone_is_current_entry_settings(size_t current_selection) if (!string_is_empty(entry_value)) { /* Toggle switch off */ - if (string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) || - string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) + if ( string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) + || string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) { return true; } /* Toggle switch on */ - else if (string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) || - string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON))) + else if ( string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) + || string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON))) { return true; } diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 53c13b7b06..0236ba0b26 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -1375,13 +1375,13 @@ static bool rgui_set_pixel_format_function(void) argb32_to_pixel_platform_format = argb32_to_abgr4444; else if (string_is_equal(driver_ident, "rsx")) /* PS3 */ argb32_to_pixel_platform_format = argb32_to_argb4444; - else if (string_is_equal(driver_ident, "d3d10") || /* D3D10/11/12 */ - string_is_equal(driver_ident, "d3d11") || - string_is_equal(driver_ident, "d3d12")) + else if ( string_is_equal(driver_ident, "d3d10") /* D3D10/11/12 */ + || string_is_equal(driver_ident, "d3d11") + || string_is_equal(driver_ident, "d3d12")) argb32_to_pixel_platform_format = argb32_to_bgra4444; - else if (string_is_equal(driver_ident, "sdl_dingux") || /* DINGUX SDL */ - string_is_equal(driver_ident, "sdl_rs90") || - string_is_equal(driver_ident, "xvideo")) + else if ( string_is_equal(driver_ident, "sdl_dingux") /* DINGUX SDL */ + || string_is_equal(driver_ident, "sdl_rs90") + || string_is_equal(driver_ident, "xvideo")) { argb32_to_pixel_platform_format = argb32_to_rgb565; return false; /* Transparency not supported */ @@ -4923,12 +4923,12 @@ static enum rgui_entry_value_type rgui_get_entry_value_type( if (switch_icons_enabled && entry_setting_type == ST_BOOL) { /* Toggle switch off */ - if (string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) || - string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) + if ( string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_DISABLED)) + || string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) return RGUI_ENTRY_VALUE_SWITCH_OFF; /* Toggle switch on */ - else if (string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) || - string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON))) + else if ( string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)) + || string_is_equal(entry_value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON))) return RGUI_ENTRY_VALUE_SWITCH_ON; } else if (string_is_equal(entry_value, "(RDB)")) @@ -5068,8 +5068,8 @@ static void rgui_render(void *data, unsigned width, unsigned height, /* If the framebuffer changed size, or the background config has * changed, recache the background buffer */ - fb_size_changed = (rgui->last_width != fb_width) || - (rgui->last_height != fb_height); + fb_size_changed = (rgui->last_width != fb_width) + || (rgui->last_height != fb_height); #if defined(GEKKO) /* Wii gfx driver changes menu framebuffer size at @@ -5510,16 +5510,16 @@ static void rgui_render(void *data, unsigned width, unsigned height, if ((rgui->term_layout.height & 1) == 0) { /* Even number of entries */ - if ((show_thumbnail && (term_offset <= term_mid_point)) || - (show_left_thumbnail && (term_offset > term_mid_point))) + if ( (show_thumbnail && (term_offset <= term_mid_point)) + || (show_left_thumbnail && (term_offset > term_mid_point))) thumbnail_width = thumbnail_panel_width; } else { /* Odd number of entries (will always be the case) */ - if ((show_thumbnail && (term_offset < term_mid_point)) || - (show_left_thumbnail && (term_offset > term_mid_point)) || - ((show_thumbnail || show_left_thumbnail) && (term_offset == term_mid_point))) + if ( (show_thumbnail && (term_offset < term_mid_point)) + || (show_left_thumbnail && (term_offset > term_mid_point)) + || ((show_thumbnail || show_left_thumbnail) && (term_offset == term_mid_point))) thumbnail_width = thumbnail_panel_width; } diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 717e489155..317dea7044 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -4653,18 +4653,18 @@ static int xmb_draw_item( && string_ends_with(entry.value, ")")) { if ( - string_is_equal(entry.value, "(PRESET)") || - string_is_equal(entry.value, "(SHADER)") || - string_is_equal(entry.value, "(COMP)") || - string_is_equal(entry.value, "(CORE)") || - string_is_equal(entry.value, "(MOVIE)") || - string_is_equal(entry.value, "(MUSIC)") || - string_is_equal(entry.value, "(DIR)") || - string_is_equal(entry.value, "(RDB)") || - string_is_equal(entry.value, "(CURSOR)") || - string_is_equal(entry.value, "(CFILE)") || - string_is_equal(entry.value, "(FILE)") || - string_is_equal(entry.value, "(IMAGE)") + string_is_equal(entry.value, "(PRESET)") + || string_is_equal(entry.value, "(SHADER)") + || string_is_equal(entry.value, "(COMP)") + || string_is_equal(entry.value, "(CORE)") + || string_is_equal(entry.value, "(MOVIE)") + || string_is_equal(entry.value, "(MUSIC)") + || string_is_equal(entry.value, "(DIR)") + || string_is_equal(entry.value, "(RDB)") + || string_is_equal(entry.value, "(CURSOR)") + || string_is_equal(entry.value, "(CFILE)") + || string_is_equal(entry.value, "(FILE)") + || string_is_equal(entry.value, "(IMAGE)") ) found = true; } @@ -6410,8 +6410,8 @@ static void xmb_draw_fullscreen_thumbnails( right_thumbnail_draw_height_prev = right_thumbnail_draw_height; /* Sanity check */ - if ((right_thumbnail_draw_width <= 0.0f) || - (right_thumbnail_draw_height <= 0.0f)) + if ( (right_thumbnail_draw_width <= 0.0f) + || (right_thumbnail_draw_height <= 0.0f)) goto error; } else if (right_thumbnail->status == GFX_THUMBNAIL_STATUS_PENDING) @@ -6432,8 +6432,8 @@ static void xmb_draw_fullscreen_thumbnails( left_thumbnail_draw_height_prev = left_thumbnail_draw_height; /* Sanity check */ - if ((left_thumbnail_draw_width <= 0.0f) || - (left_thumbnail_draw_height <= 0.0f)) + if ( (left_thumbnail_draw_width <= 0.0f) + || (left_thumbnail_draw_height <= 0.0f)) goto error; } else if (left_thumbnail->status == GFX_THUMBNAIL_STATUS_PENDING) diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 29fd42ba4a..bcd42a93d3 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -8408,7 +8408,7 @@ unsigned menu_displaylist_build_list( PARSE_ONLY_BOOL, false) == 0) count++; } - + break; #endif case DISPLAYLIST_DROPDOWN_LIST_RESOLUTION: @@ -15270,8 +15270,8 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_entries_clear(info->list); #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) { - gfx_ctx_flags_t flags; char new_exts[128]; + gfx_ctx_flags_t flags; size_t _len = 0; flags.flags = 0; From 91aa8034b1f66c04cd4b189067f3b4f4ed19ebb4 Mon Sep 17 00:00:00 2001 From: LibretroAdmin Date: Sun, 9 Feb 2025 16:43:51 +0100 Subject: [PATCH 205/574] Style nits/conventions --- cheat_manager.c | 64 +++++----- libretro-common/audio/audio_mix.c | 44 +++---- libretro-common/audio/audio_mixer.c | 4 +- .../audio/conversion/float_to_s16.c | 63 +++++---- .../audio/conversion/float_to_s16_neon.c | 2 +- .../audio/conversion/mono_to_stereo_float.c | 12 +- .../audio/conversion/s16_to_float.c | 70 +++++----- .../audio/conversion/s16_to_float_neon.c | 2 +- libretro-common/compat/compat_fnmatch.c | 2 +- libretro-common/compat/compat_getopt.c | 8 +- libretro-common/compat/compat_strcasestr.c | 22 ++-- libretro-common/encodings/encoding_crc32.c | 120 ++++++++---------- libretro-common/encodings/encoding_utf.c | 35 +++-- libretro-common/features/features_cpu.c | 4 +- libretro-common/file/archive_file.c | 7 +- libretro-common/file/config_file.c | 10 +- tasks/task_database_cue.c | 31 ++--- tasks/task_decompress.c | 25 ++-- 18 files changed, 248 insertions(+), 277 deletions(-) diff --git a/cheat_manager.c b/cheat_manager.c index a855ab25b6..5d89939e6c 100644 --- a/cheat_manager.c +++ b/cheat_manager.c @@ -394,25 +394,24 @@ static void cheat_manager_load_cb_first_pass(char *key, char *value) } } -static void cheat_manager_load_cb_second_pass(char *key, char *value) +static void cheat_manager_load_cb_second_pass(char *s, char *value) { + size_t _len; char cheat_num_str[20]; - unsigned cheat_num; - unsigned cheat_idx; + unsigned cheat_num, cheat_idx; unsigned idx = 5; - size_t key_length = 0; cheat_manager_t *cheat_st = &cheat_manager_state; errno = 0; - if (strncmp(key, "cheat", 5) != 0) + if (strncmp(s, "cheat", 5) != 0) return; - key_length = strlen((const char*)key); + _len = strlen((const char*)s); - while (idx < key_length && key[idx] >= '0' && key[idx] <= '9' && idx < 24) + while (idx < _len && s[idx] >= '0' && s[idx] <= '9' && idx < 24) { - cheat_num_str[idx - 5] = key[idx]; + cheat_num_str[idx - 5] = s[idx]; idx++; } @@ -423,55 +422,55 @@ static void cheat_manager_load_cb_second_pass(char *key, char *value) if (cheat_num + cheat_st->loading_cheat_offset >= cheat_st->size) return; - key = key + idx + 1; + s = s + idx + 1; cheat_idx = cheat_num + cheat_st->loading_cheat_offset; - if (string_is_equal(key, "address")) + if (string_is_equal(s, "address")) cheat_st->cheats[cheat_idx].address = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "address_bit_position")) + else if (string_is_equal(s, "address_bit_position")) cheat_st->cheats[cheat_idx].address_mask = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "big_endian")) + else if (string_is_equal(s, "big_endian")) cheat_st->cheats[cheat_idx].big_endian = (string_is_equal(value, "true") || string_is_equal(value, "1")); - else if (string_is_equal(key, "cheat_type")) + else if (string_is_equal(s, "cheat_type")) cheat_st->cheats[cheat_idx].cheat_type = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "code")) + else if (string_is_equal(s, "code")) cheat_st->cheats[cheat_idx].code = strdup(value); - else if (string_is_equal(key, "desc")) + else if (string_is_equal(s, "desc")) cheat_st->cheats[cheat_idx].desc = strdup(value); - else if (string_is_equal(key, "enable")) + else if (string_is_equal(s, "enable")) cheat_st->cheats[cheat_idx].state = (string_is_equal(value, "true") || string_is_equal(value, "1")); - else if (string_is_equal(key, "handler")) + else if (string_is_equal(s, "handler")) cheat_st->cheats[cheat_idx].handler = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "memory_search_size")) + else if (string_is_equal(s, "memory_search_size")) cheat_st->cheats[cheat_idx].memory_search_size = (unsigned)strtoul(value, NULL, 0); - else if (string_starts_with_size(key, "repeat_", STRLEN_CONST("repeat_"))) + else if (string_starts_with_size(s, "repeat_", STRLEN_CONST("repeat_"))) { - if (string_is_equal(key, "repeat_add_to_address")) + if (string_is_equal(s, "repeat_add_to_address")) cheat_st->cheats[cheat_idx].repeat_add_to_address = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "repeat_add_to_value")) + else if (string_is_equal(s, "repeat_add_to_value")) cheat_st->cheats[cheat_idx].repeat_add_to_value = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "repeat_count")) + else if (string_is_equal(s, "repeat_count")) cheat_st->cheats[cheat_idx].repeat_count = (unsigned)strtoul(value, NULL, 0); } - else if (string_starts_with_size(key, "rumble", STRLEN_CONST("rumble"))) + else if (string_starts_with_size(s, "rumble", STRLEN_CONST("rumble"))) { - if (string_is_equal(key, "rumble_port")) + if (string_is_equal(s, "rumble_port")) cheat_st->cheats[cheat_idx].rumble_port = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_primary_duration")) + else if (string_is_equal(s, "rumble_primary_duration")) cheat_st->cheats[cheat_idx].rumble_primary_duration = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_primary_strength")) + else if (string_is_equal(s, "rumble_primary_strength")) cheat_st->cheats[cheat_idx].rumble_primary_strength = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_secondary_duration")) + else if (string_is_equal(s, "rumble_secondary_duration")) cheat_st->cheats[cheat_idx].rumble_secondary_duration = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_secondary_strength")) + else if (string_is_equal(s, "rumble_secondary_strength")) cheat_st->cheats[cheat_idx].rumble_secondary_strength = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_type")) + else if (string_is_equal(s, "rumble_type")) cheat_st->cheats[cheat_idx].rumble_type = (unsigned)strtoul(value, NULL, 0); - else if (string_is_equal(key, "rumble_value")) + else if (string_is_equal(s, "rumble_value")) cheat_st->cheats[cheat_idx].rumble_value = (unsigned)strtoul(value, NULL, 0); } - else if (string_is_equal(key, "value")) + else if (string_is_equal(s, "value")) cheat_st->cheats[cheat_idx].value = (unsigned)strtoul(value, NULL, 0); } @@ -708,8 +707,7 @@ bool cheat_manager_get_code_state(unsigned i) static size_t cheat_manager_get_game_specific_filename( char *s, size_t len, - const char *path_cheat_database, - bool saving) + const char *path_cheat_database, bool saving) { char s1[PATH_MAX_LENGTH]; struct retro_system_info sysinfo; diff --git a/libretro-common/audio/audio_mix.c b/libretro-common/audio/audio_mix.c index eb138edd44..812f0dd9ae 100644 --- a/libretro-common/audio/audio_mix.c +++ b/libretro-common/audio/audio_mix.c @@ -38,29 +38,29 @@ #include