From 03b6f175461eaebda716ad8b06da8c608bb6be18 Mon Sep 17 00:00:00 2001 From: Michael Francis <4574480+mfrancis95@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:15:50 -0400 Subject: [PATCH 01/13] Introduce v1.5 compatibility --- src/d_mode.c | 1 + src/d_mode.h | 1 + src/doom/d_main.c | 7 ++++--- src/doom/p_enemy.c | 4 ++-- src/doom/p_inter.c | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/d_mode.c b/src/d_mode.c index 26625ec495..7f9e7fd3dd 100644 --- a/src/d_mode.c +++ b/src/d_mode.c @@ -121,6 +121,7 @@ static struct { GameVersion_t version; } valid_versions[] = { { doom, exe_doom_1_2 }, + { doom, exe_doom_1_5 }, { doom, exe_doom_1_666 }, { doom, exe_doom_1_7 }, { doom, exe_doom_1_8 }, diff --git a/src/d_mode.h b/src/d_mode.h index a3b627ce14..f94aff0073 100644 --- a/src/d_mode.h +++ b/src/d_mode.h @@ -58,6 +58,7 @@ typedef enum typedef enum { exe_doom_1_2, // Doom 1.2: shareware and registered + exe_doom_1_5, // Doom 1.5: " exe_doom_1_666, // Doom 1.666: for shareware, registered and commercial exe_doom_1_7, // Doom 1.7/1.7a: " exe_doom_1_8, // Doom 1.8: " diff --git a/src/doom/d_main.c b/src/doom/d_main.c index 0bab43c15a..ba5e4b5833 100644 --- a/src/doom/d_main.c +++ b/src/doom/d_main.c @@ -982,6 +982,7 @@ static struct GameVersion_t version; } gameversions[] = { {"Doom 1.2", "1.2", exe_doom_1_2}, + {"Doom 1.5", "1.5", exe_doom_1_5}, {"Doom 1.666", "1.666", exe_doom_1_666}, {"Doom 1.7/1.7a", "1.7", exe_doom_1_7}, {"Doom 1.8", "1.8", exe_doom_1_8}, @@ -1009,9 +1010,9 @@ static void InitGameVersion(void) // @arg // @category compat // - // Emulate a specific version of Doom. Valid values are "1.2", - // "1.666", "1.7", "1.8", "1.9", "ultimate", "final", "final2", - // "hacx" and "chex". + // Emulate a specific version of Doom. Valid values are "1.2", + // "1.5", "1.666", "1.7", "1.8", "1.9", "ultimate", "final", + // "final2", "hacx" and "chex". // p = M_CheckParmWithArgs("-gameversion", 1); diff --git a/src/doom/p_enemy.c b/src/doom/p_enemy.c index b68666dc5a..c6acf390e7 100644 --- a/src/doom/p_enemy.c +++ b/src/doom/p_enemy.c @@ -176,7 +176,7 @@ boolean P_CheckMeleeRange (mobj_t* actor) pl = actor->target; dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y); - if (gameversion <= exe_doom_1_2) + if (gameversion < exe_doom_1_5) range = MELEERANGE; else range = MELEERANGE-20*FRACUNIT+pl->info->radius; @@ -933,7 +933,7 @@ void A_SargAttack (mobj_t* actor) A_FaceTarget (actor); - if (gameversion > exe_doom_1_2) + if (gameversion >= exe_doom_1_5) { if (!P_CheckMeleeRange (actor)) return; diff --git a/src/doom/p_inter.c b/src/doom/p_inter.c index c0f1f0904e..b6e403298d 100644 --- a/src/doom/p_inter.c +++ b/src/doom/p_inter.c @@ -915,7 +915,7 @@ P_DamageMobj target->reactiontime = 0; // we're awake now... if ( (!target->threshold || target->type == MT_VILE) - && source && (source != target || gameversion <= exe_doom_1_2) + && source && (source != target || gameversion < exe_doom_1_5) && source->type != MT_VILE) { // if not intent on another player, From ddc641ea755493b7ffb06450b48ba15530f2bcec Mon Sep 17 00:00:00 2001 From: Henrique194 Date: Sun, 14 Jan 2024 18:17:02 -0300 Subject: [PATCH 02/13] Fix EGA color palette --- textscreen/txt_sdl.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c index 42480f4869..eed6167676 100644 --- a/textscreen/txt_sdl.c +++ b/textscreen/txt_sdl.c @@ -88,21 +88,21 @@ static const short code_page_to_unicode[] = CODE_PAGE_TO_UNICODE; static const SDL_Color ega_colors[] = { {0x00, 0x00, 0x00, 0xff}, // 0: Black - {0x00, 0x00, 0xa8, 0xff}, // 1: Blue - {0x00, 0xa8, 0x00, 0xff}, // 2: Green - {0x00, 0xa8, 0xa8, 0xff}, // 3: Cyan - {0xa8, 0x00, 0x00, 0xff}, // 4: Red - {0xa8, 0x00, 0xa8, 0xff}, // 5: Magenta - {0xa8, 0x54, 0x00, 0xff}, // 6: Brown - {0xa8, 0xa8, 0xa8, 0xff}, // 7: Grey - {0x54, 0x54, 0x54, 0xff}, // 8: Dark grey - {0x54, 0x54, 0xfe, 0xff}, // 9: Bright blue - {0x54, 0xfe, 0x54, 0xff}, // 10: Bright green - {0x54, 0xfe, 0xfe, 0xff}, // 11: Bright cyan - {0xfe, 0x54, 0x54, 0xff}, // 12: Bright red - {0xfe, 0x54, 0xfe, 0xff}, // 13: Bright magenta - {0xfe, 0xfe, 0x54, 0xff}, // 14: Yellow - {0xfe, 0xfe, 0xfe, 0xff}, // 15: Bright white + {0x00, 0x00, 0xaa, 0xff}, // 1: Blue + {0x00, 0xaa, 0x00, 0xff}, // 2: Green + {0x00, 0xaa, 0xaa, 0xff}, // 3: Cyan + {0xaa, 0x00, 0x00, 0xff}, // 4: Red + {0xaa, 0x00, 0xaa, 0xff}, // 5: Magenta + {0xaa, 0x55, 0x00, 0xff}, // 6: Brown + {0xaa, 0xaa, 0xaa, 0xff}, // 7: Grey + {0x55, 0x55, 0x55, 0xff}, // 8: Dark grey + {0x55, 0x55, 0xff, 0xff}, // 9: Bright blue + {0x55, 0xff, 0x55, 0xff}, // 10: Bright green + {0x55, 0xff, 0xff, 0xff}, // 11: Bright cyan + {0xff, 0x55, 0x55, 0xff}, // 12: Bright red + {0xff, 0x55, 0xff, 0xff}, // 13: Bright magenta + {0xff, 0xff, 0x55, 0xff}, // 14: Yellow + {0xff, 0xff, 0xff, 0xff}, // 15: Bright white }; #ifdef _WIN32 From f0665c631ee73ea8411bc6092912bb709d927b38 Mon Sep 17 00:00:00 2001 From: dbalsom Date: Sun, 30 Jun 2024 08:42:03 -0400 Subject: [PATCH 03/13] fix reference to timer2.enabled --- opl/opl_sdl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c index f15af6c286..2517de15c0 100644 --- a/opl/opl_sdl.c +++ b/opl/opl_sdl.c @@ -432,7 +432,7 @@ static void WriteRegister(unsigned int reg_num, unsigned int value) if ((value & 0x20) == 0) { - timer1.enabled = (value & 0x02) != 0; + timer2.enabled = (value & 0x02) != 0; OPLTimer_CalculateEndTime(&timer2); } } From 8e17b157dc1e3da0bb47b1511960a3703b96b13d Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 22 Aug 2024 22:09:26 -0400 Subject: [PATCH 04/13] quickcheck: Sync to latest version. --- quickcheck | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickcheck b/quickcheck index f093238324..b1bf88a8a0 160000 --- a/quickcheck +++ b/quickcheck @@ -1 +1 @@ -Subproject commit f093238324ab2c9003864c779b722a7afb72f139 +Subproject commit b1bf88a8a0615d481f0463531c435c639f7dd46d From 7e4b0e8c20cf4024c193da391a4d162995ec382f Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 22 Aug 2024 22:26:12 -0400 Subject: [PATCH 05/13] osx: /usr/local files are not system libraries Anything in /usr/local has been installed locally and is not part of the OS. In particular, Homebrew installs packages into /usr/local; if we want to bundle libraries from Homebrew then these need to be excluded from the /usr pattern immediately below. --- pkg/osx/cp-with-libs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/osx/cp-with-libs b/pkg/osx/cp-with-libs index 04fb5bc6cb..7a2e7d5dc2 100755 --- a/pkg/osx/cp-with-libs +++ b/pkg/osx/cp-with-libs @@ -27,6 +27,9 @@ is_sys_lib() { /System/*) true ;; + /usr/local/*) # homebrew/manual install + false + ;; /usr/*) true ;; @@ -54,7 +57,7 @@ install_with_deps() { if [ -e "$dest_file" ]; then return - fi + fi echo "Installing $bin_name..." From c882ffef0203825ca1961b57c36b1082640c6b9c Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 22 Aug 2024 22:29:23 -0400 Subject: [PATCH 06/13] osx: Strip signature from copied libraries When copying a library we use `install_name_tool` to change the shared library search path so that they will find the versions within the .app bundle. However, since this changes the file, it breaks any code signing signature. We must generate a new ad-hoc signature, particularly since recent versions of macOS have turned on more strict checking for code signing signatures. --- pkg/osx/cp-with-libs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/osx/cp-with-libs b/pkg/osx/cp-with-libs index 7a2e7d5dc2..f4869063f4 100755 --- a/pkg/osx/cp-with-libs +++ b/pkg/osx/cp-with-libs @@ -68,7 +68,6 @@ install_with_deps() { # Copy libraries that this file depends on: otool -L "$src_file" | tail -n +2 | sed 's/^.//; s/ (.*//' | while read; do - # Don't copy system libraries if is_sys_lib "$REPLY"; then @@ -95,6 +94,11 @@ install_with_deps() { if is_dylib "$dest_file"; then install_name_tool -id "@executable_path/$bin_name" "$dest_file" fi + + # The install_name_tool calls above break signatures. Recent versions + # of macOS make signatures mandatory, even if just ad-hoc ones. + codesign --remove-signature "$dest_file" + codesign --force -s - "$dest_file" # ad-hoc signature } # Install the file, and recursively install any libraries: From bfef712cc95bbece6112c05a699b43782349a9c3 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 22 Aug 2024 22:46:59 -0400 Subject: [PATCH 07/13] osx: Revert "Use dylibbundler" This should be unnecessary now after commit c882ffef02. This reverts commit 28472387c230df24eb7fa461d3dd9cf9409e20e0. --- .github/workflows/main.yml | 1 - pkg/osx/GNUmakefile | 25 +++++-------------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b421a57245..3f809fd08e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -90,7 +90,6 @@ jobs: run: | brew install \ automake \ - dylibbundler \ sdl2 \ sdl2_mixer \ sdl2_net \ diff --git a/pkg/osx/GNUmakefile b/pkg/osx/GNUmakefile index 94e20830f1..55d7ac8101 100644 --- a/pkg/osx/GNUmakefile +++ b/pkg/osx/GNUmakefile @@ -18,12 +18,6 @@ DMG=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-$(POSTFIX).dmg TOPLEVEL=../.. TOPLEVEL_DOCS=$(patsubst %,../../%,$(DOC_FILES)) -ifeq (, $(shell which dylibbundler)) - CP=./cp-with-libs -else - CP=cp -endif - # DMG file containing package: $(DMG) : tmp.dmg @@ -75,26 +69,17 @@ $(STAGING_DIR): launcher $(TOPLEVEL_DOCS) app.icns wadfile.icns cp launcher "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/launcher" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)doom" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)heretic" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)hexen" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)strife "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)strife "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)strife" - $(CP) $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup "$(APP_BIN_DIR)" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup "$(APP_BIN_DIR)" $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)setup" - -dylibbundler --bundle-deps --overwrite-files \ - --install-path "@executable_path/" \ - --dest-dir "$(APP_BIN_DIR)" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)doom" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)heretic" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)hexen" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)strife" \ - --fix-file "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)setup" - $(TOPLEVEL)/man/simplecpp -DPRECOMPILED -D__MACOSX__ \ -DDOOM -DHERETIC -DHEXEN -DSTRIFE \ < $(TOPLEVEL)/man/INSTALL.template \ From 7a75ee86052ca6297617abf87d38804c8cb12f4a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 22 Aug 2024 23:23:42 -0400 Subject: [PATCH 08/13] win32: Tweaks to pandoc-formatted HTML I've been using this set of style tweaks for other projects already and it makes a definite improvement. --- pkg/Makefile.am | 2 +- pkg/style.html | 48 +++++++++++++++++++++++++++++++++++++++++++ pkg/win32/GNUmakefile | 14 +++++++------ 3 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 pkg/style.html diff --git a/pkg/Makefile.am b/pkg/Makefile.am index 823851b8f0..3a287b2464 100644 --- a/pkg/Makefile.am +++ b/pkg/Makefile.am @@ -21,5 +21,5 @@ win32/GNUmakefile \ win32/cp-with-libs \ win32/README -EXTRA_DIST=$(OSX_FILES) $(WIN32_FILES) +EXTRA_DIST=style.html $(OSX_FILES) $(WIN32_FILES) diff --git a/pkg/style.html b/pkg/style.html new file mode 100644 index 0000000000..4ae291a3c1 --- /dev/null +++ b/pkg/style.html @@ -0,0 +1,48 @@ + + + + + diff --git a/pkg/win32/GNUmakefile b/pkg/win32/GNUmakefile index 8d55b85df5..da5fea0052 100644 --- a/pkg/win32/GNUmakefile +++ b/pkg/win32/GNUmakefile @@ -9,6 +9,8 @@ else POSTFIX=win32 endif +PANDOC_FLAGS = -f gfm -s --template=default.html5 -H ../style.html + DOOM_ZIP=$(PROGRAM_PREFIX)doom-$(PACKAGE_VERSION)-$(POSTFIX).zip HERETIC_ZIP=$(PROGRAM_PREFIX)heretic-$(PACKAGE_VERSION)-$(POSTFIX).zip HEXEN_ZIP=$(PROGRAM_PREFIX)hexen-$(PACKAGE_VERSION)-$(POSTFIX).zip @@ -32,12 +34,12 @@ $(STRIFE_ZIP): staging-strife hook-strife # Special hooks to custom modify files for particular games. hook-doom: staging-doom - -pandoc -f gfm -s -o $ Date: Wed, 28 Aug 2024 11:35:16 +0700 Subject: [PATCH 09/13] Rewrite win_opendir.c Adapted from https://github.com/win32ports/dirent_h * Fixes issues with postfix "." for non-relative paths. * Support UTF8 paths as input, so we don't need `M_ConvertUtf8ToSysNativeMB` and `M_ConvertSysNativeMBToUtf8` functions. * Support long NTFS paths (32768 characters). --- configure.ac | 2 +- src/CMakeLists.txt | 4 +- src/Makefile.am | 5 +- src/i_glob.c | 20 +- src/m_misc.c | 70 ----- src/m_misc.h | 2 - win32/win_opendir.c | 707 +++++++++++++++++++++++++------------------- win32/win_opendir.h | 175 +++++++---- 8 files changed, 525 insertions(+), 460 deletions(-) diff --git a/configure.ac b/configure.ac index 8ccb9f30c3..b4d76ac42d 100644 --- a/configure.ac +++ b/configure.ac @@ -179,7 +179,7 @@ CFLAGS="$CFLAGS $SDL_CFLAGS ${SAMPLERATE_CFLAGS:-} ${PNG_CFLAGS:-} ${FLUIDSYNTH_ LDFLAGS="$LDFLAGS $SDL_LIBS ${SAMPLERATE_LIBS:-} ${PNG_LIBS:-} ${FLUIDSYNTH_LIBS:-}" case "$host" in *-*-mingw* | *-*-cygwin* | *-*-msvc* ) - LDFLAGS="$LDFLAGS -lwinmm" + LDFLAGS="$LDFLAGS -lwinmm -lshlwapi" ;; *) esac diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b02fe66bb..6fbf079066 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -106,7 +106,7 @@ set(GAME_SOURCE_FILES set(GAME_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/../") -if(MSVC) +if(WIN32) list(APPEND GAME_SOURCE_FILES "../win32/win_opendir.c" "../win32/win_opendir.h") @@ -143,7 +143,7 @@ if(FluidSynth_FOUND) list(APPEND EXTRA_LIBS FluidSynth::libfluidsynth) endif() if(WIN32) - list(APPEND EXTRA_LIBS winmm) + list(APPEND EXTRA_LIBS winmm shlwapi) endif() if(WIN32) diff --git a/src/Makefile.am b/src/Makefile.am index 3d964645a9..68ec563a86 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,6 +21,7 @@ execgames_SCRIPTS = $(SETUP_BINARIES) AM_CFLAGS = -I$(top_srcdir)/textscreen \ -I$(top_srcdir)/opl \ -I$(top_srcdir)/pcsound \ + -I$(top_srcdir)/win32 \ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@ # Common source files used by absolutely everything: @@ -117,7 +118,9 @@ w_file.c w_file.h \ w_file_stdc.c \ w_file_posix.c \ w_file_win32.c \ -w_merge.c w_merge.h +w_merge.c w_merge.h \ +$(top_builddir)/win32/win_opendir.c \ +$(top_builddir)/win32/win_opendir.h MEMORY_NATIVE_SOURCE_FILES=\ diff --git a/src/i_glob.c b/src/i_glob.c index 90c531076e..8b7612837b 100644 --- a/src/i_glob.c +++ b/src/i_glob.c @@ -24,8 +24,7 @@ #include "m_misc.h" #include "config.h" -#if defined(_MSC_VER) -// For Visual C++, we need to include the win_opendir module. +#if defined(_WIN32) #include #define S_ISDIR(m) (((m)& S_IFMT) == S_IFDIR) #elif defined(HAVE_DIRENT_H) @@ -102,7 +101,6 @@ glob_t *I_StartMultiGlob(const char *directory, int flags, int num_globs; glob_t *result; va_list args; - char *directory_native; globs = malloc(sizeof(char *)); if (globs == NULL) @@ -141,18 +139,15 @@ glob_t *I_StartMultiGlob(const char *directory, int flags, return NULL; } - directory_native = M_ConvertUtf8ToSysNativeMB(directory); - - result->dir = opendir(directory_native); + result->dir = opendir(directory); if (result->dir == NULL) { FreeStringList(globs, num_globs); free(result); - free(directory_native); return NULL; } - result->directory = directory_native; + result->directory = M_StringDuplicate(directory); result->globs = globs; result->num_globs = num_globs; result->flags = flags; @@ -246,7 +241,6 @@ static boolean MatchesAnyGlob(const char *name, glob_t *glob) static char *NextGlob(glob_t *glob) { struct dirent *de; - char *temp, *ret; do { @@ -259,13 +253,7 @@ static char *NextGlob(glob_t *glob) || !MatchesAnyGlob(de->d_name, glob)); // Return the fully-qualified path, not just the bare filename. - temp = M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL); - - ret = M_ConvertSysNativeMBToUtf8(temp); - - free(temp); - - return ret; + return M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL); } static void ReadAllFilenames(glob_t *glob) diff --git a/src/m_misc.c b/src/m_misc.c index ace206d4d7..ba1e188965 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -28,23 +28,15 @@ #define WIN32_LEAN_AND_MEAN #include #include -#ifdef _MSC_VER #include -#endif #else #include #endif #include "doomtype.h" -#include "deh_str.h" - -#include "i_swap.h" #include "i_system.h" -#include "i_video.h" #include "m_misc.h" -#include "v_video.h" -#include "w_wad.h" #include "z_zone.h" #ifdef _WIN32 @@ -122,16 +114,6 @@ char *M_ConvertWideToUtf8(const wchar_t *wstr) return ConvertWideToMultiByte(wstr, CP_UTF8); } -static wchar_t *ConvertSysNativeMBToWide(const char *str) -{ - return ConvertMultiByteToWide(str, CP_ACP); -} - -static char *ConvertWideToSysNativeMB(const wchar_t *wstr) -{ - return ConvertWideToMultiByte(wstr, CP_ACP); -} - // Convert UTF8 string to a wide string. The result is newly allocated and must // be freed by the caller after use. @@ -141,58 +123,6 @@ wchar_t *M_ConvertUtf8ToWide(const char *str) } #endif -// Convert multibyte string in system encoding to UTF8. The result is newly -// allocated and must be freed by the caller after use. - -char *M_ConvertSysNativeMBToUtf8(const char *str) -{ -#ifdef _WIN32 - char *ret = NULL; - wchar_t *wstr = NULL; - - wstr = ConvertSysNativeMBToWide(str); - - if (!wstr) - { - return NULL; - } - - ret = M_ConvertWideToUtf8(wstr); - - free(wstr); - - return ret; -#else - return M_StringDuplicate(str); -#endif -} - -// Convert UTF8 string to multibyte string in system encoding. The result is -// newly allocated and must be freed by the caller after use. - -char *M_ConvertUtf8ToSysNativeMB(const char *str) -{ -#ifdef _WIN32 - char *ret = NULL; - wchar_t *wstr = NULL; - - wstr = M_ConvertUtf8ToWide(str); - - if (!wstr) - { - return NULL; - } - - ret = ConvertWideToSysNativeMB(wstr); - - free(wstr); - - return ret; -#else - return M_StringDuplicate(str); -#endif -} - FILE *M_fopen(const char *filename, const char *mode) { #ifdef _WIN32 diff --git a/src/m_misc.h b/src/m_misc.h index 7b9e72cc33..6dc18ccfa3 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -30,8 +30,6 @@ wchar_t *M_ConvertUtf8ToWide(const char *str); char *M_ConvertWideToUtf8(const wchar_t *wstr); #endif -char *M_ConvertUtf8ToSysNativeMB(const char *str); -char *M_ConvertSysNativeMBToUtf8(const char *str); FILE *M_fopen(const char *filename, const char *mode); int M_remove(const char *path); diff --git a/win32/win_opendir.c b/win32/win_opendir.c index b2f67805fc..a03489c9cc 100644 --- a/win32/win_opendir.c +++ b/win32/win_opendir.c @@ -1,336 +1,425 @@ -// -// 03/10/2006 James Haley -// -// For this module only: -// This code is public domain. No change sufficient enough to constitute a -// significant or original work has been made, and thus it remains as such. -// -// -// DESCRIPTION: -// -// Implementation of POSIX opendir for Visual C++. -// Derived from the MinGW C Library Extensions Source (released to the -// public domain). As with other Win32 modules, don't include most DOOM -// headers into this or conflicts will occur. -// -// Original Header: -// -// * dirent.c -// * This file has no copyright assigned and is placed in the Public Domain. -// * This file is a part of the mingw-runtime package. -// * No warranty is given; refer to the file DISCLAIMER within the package. -// * -// * Derived from DIRLIB.C by Matt J. Weinstein -// * This note appears in the DIRLIB.H -// * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 -// * -// * Updated by Jeremy Bettis -// * Significantly revised and rewinddir, seekdir and telldir added by Colin -// * Peters -// - -#ifndef _MSC_VER -#error i_opndir.c is for Microsoft Visual C++ only -#endif +/* +MIT License +Copyright (c) 2019 win32ports +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifdef _WIN32 + +#include "win_opendir.h" -#include +#include #include -#include #define WIN32_LEAN_AND_MEAN -#include /* for GetFileAttributes */ +#include +#include -#include -#define SUFFIX _T("*") -#define SLASH _T("\\") +#ifdef _MSC_VER +#pragma comment(lib, "Shlwapi.lib") +#endif -#include "win_opendir.h" +#ifndef NTFS_MAX_PATH +#define NTFS_MAX_PATH 32768 +#endif /* NTFS_MAX_PATH */ + +#ifndef FSCTL_GET_REPARSE_POINT +#define FSCTL_GET_REPARSE_POINT 0x900a8 +#endif /* FSCTL_GET_REPARSE_POINT */ + +#ifndef FILE_NAME_NORMALIZED +#define FILE_NAME_NORMALIZED 0 +#endif /* FILE_NAME_NORMALIZED */ -// -// opendir -// -// Returns a pointer to a DIR structure appropriately filled in to begin -// searching a directory. -// -DIR *opendir(const _TCHAR *szPath) +int closedir(DIR *dirp) { - DIR *nd; - unsigned int rc; - _TCHAR szFullPath[MAX_PATH]; - - errno = 0; - - if(!szPath) - { - errno = EFAULT; - return (DIR *)0; - } - - if(szPath[0] == _T('\0')) - { - errno = ENOTDIR; - return (DIR *)0; - } - - /* Attempt to determine if the given path really is a directory. */ - rc = GetFileAttributes(szPath); - if(rc == (unsigned int)-1) - { - /* call GetLastError for more error info */ - errno = ENOENT; - return (DIR *)0; - } - if(!(rc & FILE_ATTRIBUTE_DIRECTORY)) - { - /* Error, entry exists but not a directory. */ - errno = ENOTDIR; - return (DIR *)0; - } - - /* Make an absolute pathname. */ - _tfullpath(szFullPath, szPath, MAX_PATH); - - /* Allocate enough space to store DIR structure and the complete - * directory path given. */ - nd = (DIR *)(malloc(sizeof(DIR) + (_tcslen(szFullPath) - + _tcslen(SLASH) - + _tcslen(SUFFIX) + 1) - * sizeof(_TCHAR))); - - if(!nd) - { - /* Error, out of memory. */ - errno = ENOMEM; - return (DIR *)0; - } - - /* Create the search expression. */ - _tcscpy(nd->dd_name, szFullPath); - - /* Add on a slash if the path does not end with one. */ - if(nd->dd_name[0] != _T('\0') - && _tcsrchr(nd->dd_name, _T('/')) != nd->dd_name - + _tcslen(nd->dd_name) - 1 - && _tcsrchr(nd->dd_name, _T('\\')) != nd->dd_name - + _tcslen(nd->dd_name) - 1) - { - _tcscat(nd->dd_name, SLASH); - } - - /* Add on the search pattern */ - _tcscat(nd->dd_name, SUFFIX); - - /* Initialize handle to -1 so that a premature closedir doesn't try - * to call _findclose on it. */ - nd->dd_handle = -1; - - /* Initialize the status. */ - nd->dd_stat = 0; - - /* Initialize the dirent structure. ino and reclen are invalid under - * Win32, and name simply points at the appropriate part of the - * findfirst_t structure. */ - nd->dd_dir.d_ino = 0; - nd->dd_dir.d_reclen = 0; - nd->dd_dir.d_namlen = 0; - memset(nd->dd_dir.d_name, 0, FILENAME_MAX); - - return nd; + struct __dir *data = NULL; + if (!dirp) + { + errno = EBADF; + return -1; + } + data = (struct __dir *) dirp; + CloseHandle((HANDLE) data->fd); + free(data->entries); + free(data); + return 0; } -// -// readdir -// -// Return a pointer to a dirent structure filled with the information on the -// next entry in the directory. -// -struct dirent *readdir(DIR *dirp) +static void __seterrno(int value) { - errno = 0; - - /* Check for valid DIR struct. */ - if(!dirp) - { - errno = EFAULT; - return (struct dirent *)0; - } - - if (dirp->dd_stat < 0) - { - /* We have already returned all files in the directory - * (or the structure has an invalid dd_stat). */ - return (struct dirent *)0; - } - else if (dirp->dd_stat == 0) - { - /* We haven't started the search yet. */ - /* Start the search */ - dirp->dd_handle = _tfindfirst(dirp->dd_name, &(dirp->dd_dta)); - - if(dirp->dd_handle == -1) - { - /* Whoops! Seems there are no files in that - * directory. */ - dirp->dd_stat = -1; - } - else - { - dirp->dd_stat = 1; - } - } - else - { - /* Get the next search entry. */ - if(_tfindnext(dirp->dd_handle, &(dirp->dd_dta))) - { - /* We are off the end or otherwise error. - _findnext sets errno to ENOENT if no more file - Undo this. */ - DWORD winerr = GetLastError(); - if(winerr == ERROR_NO_MORE_FILES) - errno = 0; - _findclose(dirp->dd_handle); - dirp->dd_handle = -1; - dirp->dd_stat = -1; - } - else - { - /* Update the status to indicate the correct - * number. */ - dirp->dd_stat++; - } - } - - if (dirp->dd_stat > 0) - { - /* Successfully got an entry. Everything about the file is - * already appropriately filled in except the length of the - * file name. */ - dirp->dd_dir.d_namlen = _tcslen(dirp->dd_dta.name); - _tcscpy(dirp->dd_dir.d_name, dirp->dd_dta.name); - return &dirp->dd_dir; - } - - return (struct dirent *)0; +#ifdef _MSC_VER + _set_errno(value); +#else /* _MSC_VER */ + errno = value; +#endif /* _MSC_VER */ } +static int __islink(const wchar_t *name, char *buffer) +{ + DWORD io_result = 0; + DWORD bytes_returned = 0; + HANDLE hFile = CreateFileW( + name, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0); + if (hFile == INVALID_HANDLE_VALUE) + { + return 0; + } -// -// closedir -// -// Frees up resources allocated by opendir. -// -int closedir(DIR *dirp) + io_result = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, + &bytes_returned, NULL); + + CloseHandle(hFile); + + if (io_result == 0) + { + return 0; + } + + return ((REPARSE_GUID_DATA_BUFFER *) buffer)->ReparseTag == + IO_REPARSE_TAG_SYMLINK; +} + +#pragma pack(push, 1) + +typedef struct dirent_FILE_ID_128 +{ + BYTE Identifier[16]; +} dirent_FILE_ID_128; + +typedef struct _dirent_FILE_ID_INFO +{ + ULONGLONG VolumeSerialNumber; + dirent_FILE_ID_128 FileId; +} dirent_FILE_ID_INFO; + +#pragma pack(pop) + +typedef enum dirent_FILE_INFO_BY_HANDLE_CLASS +{ + dirent_FileIdInfo = 18 +} dirent_FILE_INFO_BY_HANDLE_CLASS; + +static __ino_t __inode(const wchar_t *name) { - int rc; - - errno = 0; - rc = 0; - - if(!dirp) - { - errno = EFAULT; - return -1; - } - - if(dirp->dd_handle != -1) - { - rc = _findclose(dirp->dd_handle); - } - - /* Delete the dir structure. */ - free(dirp); - - return rc; + __ino_t value = {0}; + BOOL result; + dirent_FILE_ID_INFO fileid; + BY_HANDLE_FILE_INFORMATION info; + typedef BOOL(__stdcall * pfnGetFileInformationByHandleEx)( + HANDLE hFile, dirent_FILE_INFO_BY_HANDLE_CLASS FileInformationClass, + LPVOID lpFileInformation, DWORD dwBufferSize); + + HANDLE hKernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!hKernel32) + { + return value; + } + + pfnGetFileInformationByHandleEx fnGetFileInformationByHandleEx = + (pfnGetFileInformationByHandleEx) GetProcAddress( + hKernel32, "GetFileInformationByHandleEx"); + if (!fnGetFileInformationByHandleEx) + { + return value; + } + + HANDLE hFile = CreateFileW(name, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, 0); + if (hFile == INVALID_HANDLE_VALUE) + { + return value; + } + + result = fnGetFileInformationByHandleEx(hFile, dirent_FileIdInfo, &fileid, + sizeof(fileid)); + if (result) + { + value.serial = fileid.VolumeSerialNumber; + memcpy(value.fileid, fileid.FileId.Identifier, 16); + } + else + { + result = GetFileInformationByHandle(hFile, &info); + if (result) + { + value.serial = info.dwVolumeSerialNumber; + memcpy(value.fileid + 8, &info.nFileIndexHigh, 4); + memcpy(value.fileid + 12, &info.nFileIndexLow, 4); + } + } + CloseHandle(hFile); + return value; } -// -// rewinddir -// -// Return to the beginning of the directory "stream". We simply call findclose -// and then reset things like an opendir. -// -void rewinddir(DIR * dirp) +static DIR *__internal_opendir(wchar_t *wname, int size) { - errno = 0; - - if(!dirp) - { - errno = EFAULT; - return; - } - - if(dirp->dd_handle != -1) - { - _findclose(dirp->dd_handle); - } - - dirp->dd_handle = -1; - dirp->dd_stat = 0; + struct __dir *data = NULL; + struct dirent *tmp_entries = NULL; + static char default_char = '?'; + static wchar_t *prefix = L"\\\\?\\"; + static wchar_t *suffix = L"\\*.*"; + static int extra_prefix = 4; /* use prefix "\\?\" to handle long file names */ + static int extra_suffix = 4; /* use suffix "\*.*" to find everything */ + WIN32_FIND_DATAW w32fd = {0}; + HANDLE hFindFile = INVALID_HANDLE_VALUE; + static int grow_factor = 2; + char *buffer = NULL; + + BOOL relative = PathIsRelativeW(wname + extra_prefix); + + memcpy(wname + size - 1, suffix, sizeof(wchar_t) * extra_suffix); + wname[size + extra_suffix - 1] = 0; + + if (relative) + { + wname += extra_prefix; + size -= extra_prefix; + } + hFindFile = FindFirstFileW(wname, &w32fd); + if (INVALID_HANDLE_VALUE == hFindFile) + { + __seterrno(ENOENT); + return NULL; + } + + data = (struct __dir *) malloc(sizeof(struct __dir)); + if (!data) + { + goto out_of_memory; + } + wname[size - 1] = 0; + data->fd = (intptr_t) CreateFileW(wname, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, 0); + wname[size - 1] = L'\\'; + data->count = 16; + data->index = 0; + data->entries = (struct dirent *) malloc(sizeof(struct dirent) * data->count); + if (!data->entries) + { + goto out_of_memory; + } + buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + if (!buffer) + { + goto out_of_memory; + } + + do + { + WideCharToMultiByte(CP_UTF8, 0, w32fd.cFileName, -1, + data->entries[data->index].d_name, NAME_MAX, + &default_char, NULL); + + memcpy(wname + size, w32fd.cFileName, sizeof(wchar_t) * NAME_MAX); + + if (((w32fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == + FILE_ATTRIBUTE_REPARSE_POINT) + && __islink(wname, buffer)) + { + data->entries[data->index].d_type = DT_LNK; + } + else if ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) == + FILE_ATTRIBUTE_DEVICE) + { + data->entries[data->index].d_type = DT_CHR; + } + else if ((w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == + FILE_ATTRIBUTE_DIRECTORY) + { + data->entries[data->index].d_type = DT_DIR; + } + else + { + data->entries[data->index].d_type = DT_REG; + } + + data->entries[data->index].d_ino = __inode(wname); + data->entries[data->index].d_reclen = sizeof(struct dirent); + data->entries[data->index].d_namelen = + (unsigned char) wcslen(w32fd.cFileName); + data->entries[data->index].d_off = 0; + + if (++data->index == data->count) + { + tmp_entries = (struct dirent *) realloc( + data->entries, + sizeof(struct dirent) * data->count * grow_factor); + if (!tmp_entries) + { + goto out_of_memory; + } + data->entries = tmp_entries; + data->count *= grow_factor; + } + } while (FindNextFileW(hFindFile, &w32fd) != 0); + + free(buffer); + FindClose(hFindFile); + + data->count = data->index; + data->index = 0; + return (DIR *) data; + +out_of_memory: + if (data) + { + if (INVALID_HANDLE_VALUE != (HANDLE) data->fd) + { + CloseHandle((HANDLE) data->fd); + } + free(data->entries); + } + free(buffer); + free(data); + if (INVALID_HANDLE_VALUE != hFindFile) + { + FindClose(hFindFile); + } + __seterrno(ENOMEM); + return NULL; +} + +static wchar_t *__get_buffer() +{ + wchar_t *name = malloc(sizeof(wchar_t) * (NTFS_MAX_PATH + NAME_MAX + 8)); + if (name) + { + memcpy(name, L"\\\\?\\", sizeof(wchar_t) * 4); + } + return name; } -// -// telldir -// -// Returns the "position" in the "directory stream" which can be used with -// seekdir to go back to an old entry. We simply return the value in stat. -// -long telldir(DIR *dirp) +DIR *opendir(const char *name) { - errno = 0; - - if(!dirp) - { - errno = EFAULT; - return -1; - } - return dirp->dd_stat; + DIR *dirp = NULL; + wchar_t *wname = __get_buffer(); + int size = 0; + if (!wname) + { + errno = ENOMEM; + return NULL; + } + size = MultiByteToWideChar(CP_UTF8, 0, name, -1, wname + 4, NTFS_MAX_PATH); + if (0 == size) + { + free(wname); + return NULL; + } + dirp = __internal_opendir(wname, size + 4); + free(wname); + return dirp; } -// -// seekdir -// -// Seek to an entry previously returned by telldir. We rewind the directory -// and call readdir repeatedly until either dd_stat is the position number -// or -1 (off the end). This is not perfect, in that the directory may -// have changed while we weren't looking. But that is probably the case with -// any such system. -// -void seekdir(DIR *dirp, long lPos) +DIR *_wopendir(const wchar_t *name) { - errno = 0; - - if(!dirp) - { - errno = EFAULT; - return; - } - - if(lPos < -1) - { - /* Seeking to an invalid position. */ - errno = EINVAL; - return; - } - else if(lPos == -1) - { - /* Seek past end. */ - if(dirp->dd_handle != -1) - { - _findclose(dirp->dd_handle); - } - dirp->dd_handle = -1; - dirp->dd_stat = -1; - } - else - { - /* Rewind and read forward to the appropriate index. */ - rewinddir(dirp); - - while((dirp->dd_stat < lPos) && readdir(dirp)) - ; /* do-nothing loop */ - } + DIR *dirp = NULL; + wchar_t *wname = __get_buffer(); + int size = 0; + if (!wname) + { + errno = ENOMEM; + return NULL; + } + size = (int) wcslen(name); + if (size > NTFS_MAX_PATH) + { + free(wname); + return NULL; + } + memcpy(wname + 4, name, sizeof(wchar_t) * (size + 1)); + dirp = __internal_opendir(wname, size + 5); + free(wname); + return dirp; +} + +DIR *fdopendir(intptr_t fd) +{ + DIR *dirp = NULL; + wchar_t *wname = __get_buffer(); + int size = 0; + + if (!wname) + { + errno = ENOMEM; + return NULL; + } + size = GetFinalPathNameByHandleW((HANDLE) fd, wname + 4, NTFS_MAX_PATH, + FILE_NAME_NORMALIZED); + if (0 == size) + { + free(wname); + errno = ENOTDIR; + return NULL; + } + dirp = __internal_opendir(wname, size + 5); + free(wname); + return dirp; } -// EOF +struct dirent *readdir(DIR *dirp) +{ + struct __dir *data = (struct __dir *) dirp; + if (!data) + { + errno = EBADF; + return NULL; + } + if (data->index < data->count) + { + return &data->entries[data->index++]; + } + return NULL; +} + +void seekdir(DIR *dirp, long int offset) +{ + if (dirp) + { + struct __dir *data = (struct __dir *) dirp; + data->index = (offset < data->count) ? offset : data->index; + } +} + +void rewinddir(DIR *dirp) +{ + seekdir(dirp, 0); +} + +long int telldir(DIR *dirp) +{ + if (!dirp) + { + errno = EBADF; + return -1; + } + return ((struct __dir *) dirp)->count; +} + +intptr_t dirfd(DIR *dirp) +{ + if (!dirp) + { + errno = EINVAL; + return -1; + } + return ((struct __dir *) dirp)->fd; +} +#endif /* _WIN32 */ diff --git a/win32/win_opendir.h b/win32/win_opendir.h index c1844e115e..94c9d2c848 100644 --- a/win32/win_opendir.h +++ b/win32/win_opendir.h @@ -1,73 +1,130 @@ -// -// 03/10/2006 James Haley -// -// For this module only: -// This code is public domain. No change sufficient enough to constitute a -// significant or original work has been made, and thus it remains as such. -// -// -// DESCRIPTION: -// -// Implementation of POSIX opendir for Visual C++. -// Derived from the MinGW C Library Extensions Source (released to the -// public domain). -// - -#ifndef I_OPNDIR_H__ -#define I_OPNDIR_H__ - -#include - -#ifndef FILENAME_MAX -#define FILENAME_MAX 260 -#endif +/* +MIT License +Copyright (c) 2019 win32ports +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifdef _WIN32 + +#ifndef WIN_OPENDIR_H +#define WIN_OPENDIR_H + +#include + +#ifndef NAME_MAX +#define NAME_MAX 260 +#endif /* NAME_MAX */ + +#ifndef DT_UNKNOWN +#define DT_UNKNOWN 0 +#endif /* DT_UNKNOWN */ + +#ifndef DT_FIFO +#define DT_FIFO 1 +#endif /* DT_FIFO */ + +#ifndef DT_CHR +#define DT_CHR 2 +#endif /* DT_CHR */ + +#ifndef DT_DIR +#define DT_DIR 4 +#endif /* DT_DIR */ + +#ifndef DT_BLK +#define DT_BLK 6 +#endif /* DT_BLK */ + +#ifndef DT_REG +#define DT_REG 8 +#endif /* DT_REF */ + +#ifndef DT_LNK +#define DT_LNK 10 +#endif /* DT_LNK */ + +#ifndef DT_SOCK +#define DT_SOCK 12 +#endif /* DT_SOCK */ + +#ifndef DT_WHT +#define DT_WHT 14 +#endif /* DT_WHT */ + +#ifndef _DIRENT_HAVE_D_NAMLEN +#define _DIRENT_HAVE_D_NAMLEN 1 +#endif /* _DIRENT_HAVE_D_NAMLEN */ + +#ifndef _DIRENT_HAVE_D_RECLEN +#define _DIRENT_HAVE_D_RECLEN 1 +#endif /* _DIRENT_HAVE_D_RECLEN */ + +#ifndef _DIRENT_HAVE_D_OFF +#define _DIRENT_HAVE_D_OFF 1 +#endif /* _DIRENT_HAVE_D_OFF */ + +#ifndef _DIRENT_HAVE_D_TYPE +#define _DIRENT_HAVE_D_TYPE 1 +#endif /* _DIRENT_HAVE_D_TYPE */ + +typedef void *DIR; + +typedef struct ino_t +{ + unsigned long long serial; + unsigned char fileid[16]; +} __ino_t; struct dirent { - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char d_name[FILENAME_MAX]; /* File name. */ + __ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_namelen; + unsigned char d_type; + char d_name[NAME_MAX]; }; -/* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - * dd_stat field is now int (was short in older versions). - */ -typedef struct +struct __dir { - /* disk transfer area for this dir */ - struct _finddata_t dd_dta; + struct dirent *entries; + intptr_t fd; + long int count; + long int index; +}; + +int closedir(DIR *dirp); + +DIR *opendir(const char *name); + +DIR *_wopendir(const wchar_t *name); - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; +DIR *fdopendir(intptr_t fd); - /* _findnext handle */ - intptr_t dd_handle; +struct dirent *readdir(DIR *dirp); - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; +void seekdir(DIR *dirp, long int offset); - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; -} DIR; +void rewinddir(DIR *dirp); -DIR *opendir(const char *); -struct dirent *readdir(DIR *); -int closedir(DIR *); -void rewinddir(DIR *); -long telldir(DIR *); -void seekdir(DIR *, long); +long int telldir(DIR *dirp); -#endif +intptr_t dirfd(DIR *dirp); -// EOF +#endif /* WIN_OPENDIR_H */ +#endif /* _WIN32 */ From 0d002e6ed2289928907a995fcf0a48021cf71da7 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 7 Sep 2024 08:42:02 -0400 Subject: [PATCH 10/13] net: Hide public IP addresses for privacy labnove19 on the Chocolate Doom Discord expressed safety concerns [1] about playing on public servers and pointed out that the lobby screen reveals the IP address of every player that is connected to the server. There's no actual reason why we need to do this, and an IP address is usually considered personally identifiable information that can also be used to identify a person's physical location. This change therefore changes the server code so that players on the public Internet will not be able to see each others' IP addresses. However, I've been careful to preserve the behavior for non-public addresses: 1. If a localhost player and a public player are both connected to the server, the localhost player can see public IP addresses, since the owner of the server ought to be able to see the addresses of players who connect to their own server. Conversely, public players can see localhost addresses since they're not publicly accessible and reveal no private information anyway. 2. If two LAN players are connected to a server they can see each others' IP addresses, since they're presumably physically colocated anyway. It could actually be pretty frustrating for players to not be able to see each others' IP addresses if they're trying to set up a LAN game, having problems and could use the address to debug. 3. If a LAN player and a public player are both connected to the server, situation, the server and the LAN player are presumably physically colocated, which effectively is the same case as (1) above, so the LAN player can see the public player's IP address. However, the public player only sees "[LAN player]" as we should not disclose details of the server owner's internal network. This change is consistent with the "pet name" change we already made to hide people's names unless they make a deliberate choice to reveal them. [1] https://discord.com/channels/435469554173476866/829452135078428722/1281374017164677161 --- src/net_server.c | 54 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/net_server.c b/src/net_server.c index 42ab0d9f6c..9374b64ec7 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -383,11 +383,35 @@ static net_client_t *NET_SV_Controller(void) return best; } +typedef enum +{ + RANGE_LOCALHOST, // Same process or 127.x + RANGE_PRIVATE, // RFC 1918 + RANGE_PUBLIC, // The public Internet +} ip_range_t; + +static ip_range_t ClientAddressRange(const char *addr) +{ + if (!strcmp(addr, "local client") + || M_StringStartsWith(addr, "127.")) + { + return RANGE_LOCALHOST; + } + if (M_StringStartsWith(addr, "10.") + || M_StringStartsWith(addr, "192.168.")) + { + return RANGE_PRIVATE; + } + return RANGE_PUBLIC; +} + static void NET_SV_SendWaitingData(net_client_t *client) { net_waitdata_t wait_data; net_packet_t *packet; net_client_t *controller; + ip_range_t client_range, player_range; + const char *addr; int i; NET_SV_AssignPlayers(); @@ -416,6 +440,11 @@ static void NET_SV_SendWaitingData(net_client_t *client) sizeof(sha1_digest_t)); wait_data.is_freedoom = controller->is_freedoom; + // We only send IP addresses to locally-connected clients (including + // the 127.* loopback range): + addr = NET_AddrToString(client->connection.addr); + client_range = ClientAddressRange(addr); + // set name and address of each player: for (i = 0; i < wait_data.num_players; ++i) @@ -423,9 +452,28 @@ static void NET_SV_SendWaitingData(net_client_t *client) M_StringCopy(wait_data.player_names[i], sv_players[i]->name, MAXPLAYERNAME); - M_StringCopy(wait_data.player_addrs[i], - NET_AddrToString(sv_players[i]->addr), - MAXPLAYERNAME); + + // For privacy, only local clients or those on a LAN get to see + // addresses. Public clients only get to see their own address, + // though we do reveal localhost addresses since they're harmless, + // and we do reveal when a client is connected via LAN. + addr = NET_AddrToString(sv_players[i]->addr); + player_range = ClientAddressRange(addr); + if (client_range == RANGE_LOCALHOST || client_range == RANGE_PRIVATE + || i == wait_data.consoleplayer || player_range == RANGE_LOCALHOST) + { + M_StringCopy(wait_data.player_addrs[i], addr, MAXPLAYERNAME); + } + else if (player_range == RANGE_PRIVATE) + { + M_snprintf(wait_data.player_addrs[i], MAXPLAYERNAME, + "[LAN player]"); + } + else + { + M_snprintf(wait_data.player_addrs[i], MAXPLAYERNAME, + "[address hidden]"); + } } // Construct packet: From 7ffa24726c29718967a0bb88ba06fec416048372 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 7 Sep 2024 16:14:08 -0400 Subject: [PATCH 11/13] cpp-linter: Disable several checks This commit disables several cpp-linter checks that I believe are not useful: * cppcoreguidelines-init-variables: Flags when a variable is not initialized at declaration, even if it is never used uninitialized. It is my belief that this is an explicitly harmful practice to encourage: * readability-identifier-length: Flags when variables have short names. The Doom codebase is already full of variables named 'i' or 'j' for loop counters, and I don't think this is really a problem. Naming it something like "count" doesn't do anything particularly useful. * readability-isolate-declaration: Flags when multiple variables are initialized in a single statement. Again, the Doom codebase is full of examples of this, and I'm not convinced there's much benefit in avoiding it. --- .github/workflows/cpp-linter.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/cpp-linter.yml b/.github/workflows/cpp-linter.yml index 9c5e5d77a6..04e6fe72d0 100644 --- a/.github/workflows/cpp-linter.yml +++ b/.github/workflows/cpp-linter.yml @@ -39,6 +39,9 @@ jobs: ,clang-analyzer-* ,cppcoreguidelines-* ,-cppcoreguidelines-avoid-magic-numbers + ,-cppcoreguidelines-init-variables + ,-readability-identifier-length + ,-readability-isolate-declaration ,-readability-magic-numbers - name: Fail fast?! From 04dff379110add7f229f96d56d825a1d44b71771 Mon Sep 17 00:00:00 2001 From: Fabian Greffrath Date: Wed, 11 Sep 2024 09:18:30 +0200 Subject: [PATCH 12/13] Use native texture format (#1810) (#1701) * Init palette alpha Co-authored-by: gendlin <108626604+gendlin@users.noreply.github.com> --- src/i_video.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/i_video.c b/src/i_video.c index 9d9c8ccbad..0271dd0ea6 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -77,8 +77,6 @@ static SDL_Rect blit_rect = { SCREENHEIGHT }; -static uint32_t pixel_format; - // palette static SDL_Color palette[256]; @@ -677,7 +675,7 @@ static void CreateUpscaledTexture(boolean force) SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); new_texture = SDL_CreateTexture(renderer, - pixel_format, + SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, w_upscale*SCREENWIDTH, h_upscale*SCREENHEIGHT); @@ -830,6 +828,7 @@ void I_SetPalette (byte *doompalette) // Zero out the bottom two bits of each channel - the PC VGA // controller only supports 6 bits of accuracy. + palette[i].a = 0xFFU; palette[i].r = gammatable[usegamma][*doompalette++] & ~3; palette[i].g = gammatable[usegamma][*doompalette++] & ~3; palette[i].b = gammatable[usegamma][*doompalette++] & ~3; @@ -1246,8 +1245,6 @@ static void SetVideoMode(void) SDL_GetError()); } - pixel_format = SDL_GetWindowPixelFormat(screen); - SDL_SetWindowMinimumSize(screen, SCREENWIDTH, actualheight); I_InitWindowTitle(); @@ -1358,7 +1355,7 @@ static void SetVideoMode(void) if (argbbuffer == NULL) { - SDL_PixelFormatEnumToMasks(pixel_format, &bpp, + SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ARGB8888, &bpp, &rmask, &gmask, &bmask, &amask); argbbuffer = SDL_CreateRGBSurface(0, SCREENWIDTH, SCREENHEIGHT, bpp, @@ -1382,7 +1379,7 @@ static void SetVideoMode(void) // is going to change frequently. texture = SDL_CreateTexture(renderer, - pixel_format, + SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREENWIDTH, SCREENHEIGHT); From e346f88eb889532844b39a8c9c992b45471c5890 Mon Sep 17 00:00:00 2001 From: Fabian Greffrath Date: Wed, 11 Sep 2024 16:29:50 +0200 Subject: [PATCH 13/13] Blit directly to texture (#1702) * Blit directly to texture (#1870) * Blit directly to texture * Omit unneeded vars * add comment --------- Co-authored-by: gendlin <108626604+gendlin@users.noreply.github.com> --- src/i_video.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/i_video.c b/src/i_video.c index 0271dd0ea6..6c94bf7b10 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -775,13 +775,13 @@ void I_FinishUpdate (void) } // Blit from the paletted 8-bit screen buffer to the intermediate - // 32-bit RGBA buffer that we can load into the texture. + // 32-bit RGBA buffer and update the intermediate texture with the + // contents of the RGBA buffer. + SDL_LockTexture(texture, &blit_rect, &argbbuffer->pixels, + &argbbuffer->pitch); SDL_LowerBlit(screenbuffer, &blit_rect, argbbuffer, &blit_rect); - - // Update the intermediate texture with the contents of the RGBA buffer. - - SDL_UpdateTexture(texture, NULL, argbbuffer->pixels, argbbuffer->pitch); + SDL_UnlockTexture(texture); // Make sure the pillarboxes are kept clear each frame. @@ -1186,8 +1186,6 @@ static void SetVideoMode(void) { int w, h; int x, y; - unsigned int rmask, gmask, bmask, amask; - int bpp; int window_flags = 0, renderer_flags = 0; SDL_DisplayMode mode; @@ -1355,12 +1353,10 @@ static void SetVideoMode(void) if (argbbuffer == NULL) { - SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ARGB8888, &bpp, - &rmask, &gmask, &bmask, &amask); - argbbuffer = SDL_CreateRGBSurface(0, - SCREENWIDTH, SCREENHEIGHT, bpp, - rmask, gmask, bmask, amask); - SDL_FillRect(argbbuffer, NULL, 0); + // pixels and pitch will be filled with the texture's values + // in I_FinishUpdate() + argbbuffer = SDL_CreateRGBSurfaceWithFormatFrom( + NULL, w, h, 0, 0, SDL_PIXELFORMAT_ARGB8888); } if (texture != NULL)