Make re3 relocatable #967

Open
madebr wants to merge 4 commits from madebr/re3_conan_libsndfile into master

@ -101,6 +101,7 @@ jobs:
- name: "Build re3 (conan build)" - name: "Build re3 (conan build)"
run: | run: |
conan build ${{ github.workspace }} -if build -bf build -pf package conan build ${{ github.workspace }} -if build -bf build -pf package
cmake build -DRE3_INSTALL_NSIS=ON
- name: "Package re3 (conan package)" - name: "Package re3 (conan package)"
run: | run: |
conan package ${{ github.workspace }} -if build -bf build -pf package conan package ${{ github.workspace }} -if build -bf build -pf package
@ -108,9 +109,10 @@ jobs:
working-directory: ./build working-directory: ./build
run: | run: |
cpack -C RelWithDebInfo cpack -C RelWithDebInfo
cmake -E rm -rf dist/_CPack_Packages
- name: "Archive binary package (github artifacts)" - name: "Archive binary package (github artifacts)"
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: "${{ matrix.os }}-${{ matrix.platform }}" name: "${{ matrix.os }}-${{ matrix.platform }}"
path: build/*.tar.xz path: build/dist/*
if-no-files-found: error if-no-files-found: error

@ -1,82 +1,152 @@
cmake_minimum_required(VERSION 3.8)
set(EXECUTABLE re3) set(EXECUTABLE re3)
set(PROJECT RE3) set(STEAMID 12100)
cmake_minimum_required(VERSION 3.8)
project(${EXECUTABLE} C CXX) project(${EXECUTABLE} C CXX)
set(PROJECT_AUTHOR "GTAModding")
set(PROJECT_URL "https://github.com/gtamodding/re3")
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
if(WIN32) if(WIN32)
set(${PROJECT}_AUDIOS "OAL" "MSS") set(RE3_AUDIOS "OAL" "MSS")
else() else()
set(${PROJECT}_AUDIOS "OAL") set(RE3_AUDIOS "OAL")
endif() endif()
set(${PROJECT}_AUDIO "OAL" CACHE STRING "Audio") set(RE3_AUDIO "OAL" CACHE STRING "Audio")
option(${PROJECT}_WITH_OPUS "Build ${EXECUTABLE} with opus support" OFF) include(CMakeDependentOption)
option(${PROJECT}_WITH_LIBSNDFILE "Build ${EXECUTABLE} with libsndfile (instead of internal decoder)" OFF)
option(RE3_INSTALL "Install ${EXECUTABLE}" OFF)
option(RE3_WITH_OPUS "Build ${EXECUTABLE} with opus support" OFF)
option(RE3_WITH_LIBSNDFILE "Build ${EXECUTABLE} with libsndfile (instead of internal decoder)" OFF)
cmake_dependent_option(RE3_INSTALL_NSIS "Create NSIS installer" ON "WIN32;RE3_INSTALL" OFF)
cmake_dependent_option(RE3_INSTALL_SRC "Create sources archive" OFF "RE3_INSTALL" OFF)
if(RE3_INSTALL_NSIS)
find_program(MAKENSIS_BIN makensis)
if(NOT MAKENSIS_BIN)
message(FATAL_ERROR "Cannot find `makensis` for creating NSIS installer.")
endif()
endif()
set_property(CACHE ${PROJECT}_AUDIO PROPERTY STRINGS ${${PROJECT}_AUDIOS}) set_property(CACHE RE3_AUDIO PROPERTY STRINGS ${RE3_AUDIOS})
message(STATUS "${PROJECT}_AUDIO = ${${PROJECT}_AUDIO} (choices=${${PROJECT}_AUDIOS})") message(STATUS "RE3_AUDIO = ${RE3_AUDIO} (choices=${RE3_AUDIOS})")
set("${PROJECT}_AUDIO_${${PROJECT}_AUDIO}" ON) set("RE3_AUDIO_${RE3_AUDIO}" ON)
if(NOT ${PROJECT}_AUDIO IN_LIST ${PROJECT}_AUDIOS) if(NOT RE3_AUDIO IN_LIST RE3_AUDIOS)
message(FATAL_ERROR "Illegal ${PROJECT}_AUDIO=${${PROJECT}_AUDIO}") message(FATAL_ERROR "Illegal RE3_AUDIO=${RE3_AUDIO}")
endif() endif()
option(${PROJECT}_VENDORED_LIBRW "Use vendored librw" ON) option(RE3_VENDORED_LIBRW "Use vendored librw" ON)
if(${PROJECT}_VENDORED_LIBRW) if(RE3_VENDORED_LIBRW)
add_subdirectory(vendor/librw) add_subdirectory(vendor/librw)
else() else()
find_package(librw REQUIRED) find_package(librw REQUIRED)
endif() endif()
add_subdirectory(src) add_subdirectory(src)
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT ${EXECUTABLE})
if(${PROJECT}_INSTALL) if(RE3_INSTALL)
install(DIRECTORY gamefiles/ DESTINATION ".") install(DIRECTORY gamefiles/ DESTINATION "." COMPONENT comp2_gamedata)
if(LIBRW_PLATFORM_NULL) configure_file(cmake/CPackProjectConfig.cmake.in CPackProjectConfig.cmake @ONLY)
set(platform "-null") #file(GENERATE OUTPUT CPackProjectConfig.cmake INPUT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPackProjectConfig.cmake.in" TARGET ${EXECUTABLE})
elseif(LIBRW_PLATFORM_PS2) set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/dist")
set(platform "-ps2")
elseif(LIBRW_PLATFORM_GL3) if(RE3_INSTALL_SRC)
if(LIBRW_GL3_GFXLIB STREQUAL "GLFW") install(
set(platform "-gl3-glfw") DIRECTORY cmake gamefiles resources src utils
else() DESTINATION .
set(platform "-gl3-sdl2") COMPONENT compZ_sources
endif() EXCLUDE_FROM_ALL
elseif(LIBRW_PLATFORM_D3D9) )
set(platform "-d3d9") install(
endif() FILES conanfile.py CMakeLists.txt premake5.lua README.md CODING_STYLE.md
if(${PROJECT}_AUDIO_OAL) DESTINATION .
set(audio "-oal") COMPONENT compZ_sources
elseif(${PROJECT}_AUDIO_MSS) EXCLUDE_FROM_ALL
set(audio "-mss") )
endif()
if(${PROJECT}_WITH_OPUS)
set(audio "${audio}-opus")
endif()
if(NOT LIBRW_PLATFORM_PS2)
if(WIN32)
set(os "-win")
elseif(APPLE)
set(os "-apple")
elseif(UNIX)
set(os "-linux")
else()
set(compiler "-UNK")
message(WARNING "Unknown os. Created cpack package will be wrong. (override using cpack -P)")
endif()
endif() endif()
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}${platform}${audio}${os}${compiler}") set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "GTA III reversed") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "GTA III reversed")
set(CPACK_PACKAGE_VENDOR "GTAModding") set(CPACK_PACKAGE_VENDOR "${PROJECT_AUTHOR}")
set(CPACK_PROJECT_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackProjectConfig.cmake")
# FIXME: missing license (https://github.com/GTAmodding/re3/issues/794) # FIXME: missing license (https://github.com/GTAmodding/re3/issues/794)
# set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/LICENSE") # set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/LICENSE")
# set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") # set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}")
set(CPACK_GENERATOR "TXZ") set(CPACK_GENERATOR "TXZ")
# FIXME: this is displayed in the GUI installer!!! Needs a disclaimer about trademarks etc.
# set(CPACK_RESOURCE_FILE_LICENSE)
set(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}\\\\resources\\\\logo.bmp")
set(CPACK_PACKAGE_CHECKSUM "SHA256")
list(REMOVE_ITEM CPACK_COMPONENTS_ALL "compZ_sources")
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
if(WIN32)
set(NEED_RUNTIME OFF)
if(MSVC)
if(NOT "-MT" MATCHES CMAKE_C_FLAGS)
# Install MSVC runtime when using dynamic runtime (-MD, -MDd)
if("-MDd" MATCHES CMAKE_C_FLAGS)
set(CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY ON)
endif()
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ".")
set(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT comp3_runtime)
include(InstallRequiredSystemLibraries)
set(NEED_RUNTIME ON)
endif()
endif()
if(RE3_INSTALL_NSIS)
list(APPEND CPACK_GENERATOR "NSIS")
endif()
set(CPACK_NSIS_COMPONENT_INSTALL ON)
set(CPACK_NSIS_DEFINES "!RequestExecutionLevel user")
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
set(CPACK_NSIS_DISPLAY_NAME "${PROJECT_NAME} (${PROJECT_AUTHOR})")
set(CPACK_NSIS_HELP_LINK "${PROJECT_URL}")
set(CPACK_NSIS_URL_INFO_ABOUT "${PROJECT_URL}")
set(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}\\\\resources\\\\logo.ico")
set(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}\\\\resources\\\\logo.ico")
set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
set(CPACK_NSIS_MUI_FINISHPAGE_RUN "${EXECUTABLE}")
endif()
include(CPackComponent)
cpack_add_component(comp1_core
DISPLAY_NAME "Game executable(s)"
DESCRIPTION "Install the game executable(s)."
REQUIRED
)
cpack_add_component(comp2_gamedata
DISPLAY_NAME "Game data fixes"
DESCRIPTION "Install game data fixes."
REQUIRED
DEPENDS "comp1_core"
)
cpack_add_component(comp3_runtime
DISPLAY_NAME "System runtime"
DESCRIPTION "Install C runtime. Not required if a suitable MSVC runtime is already available."
DEPENDS "comp1_core"
)
cpack_add_component(comp4_debug
DISPLAY_NAME "Debug symbols"
DESCRIPTION "Enables debugging your problems. Hopefully not needed."
DEPENDS "comp1_core"
DISABLED
)
cpack_add_component(compZ_sources
DISPLAY_NAME "sources"
DESCRIPTION "The sources of ${PROJECT_NAME}."
DISABLED
HIDDEN
)
include(CPack) include(CPack)
endif() endif()

@ -0,0 +1,76 @@
set(PROJECT_NAME "@PROJECT_NAME@")
set(PROJECT_AUTHOR "@PROJECT_AUTHOR@")
set(LIBRW_PLATFORM "@LIBRW_PLATFORM@")
set(LIBRW_GL3_GFXLIB "@LIBRW_GL3_GFXLIB@")
set(RE3_AUDIO "@RE3_AUDIO@")
set(RE3_WITH_OPUS "@RE3_WITH_OPUS@")
set(WIN32 @WIN32@)
set(APPLE @APPLE@)
set(UNIZ @UNIX@)
set(CMAKE_SIZEOF_VOID_P @CMAKE_SIZEOF_VOID_P@)
if(LIBRW_PLATFORM STREQUAL "NULL")
set(platform "-null")
elseif(LIBRW_PLATFORM STREQUAL "PS2")
set(platform "-ps2")
elseif(LIBRW_PLATFORM STREQUAL "GL3")
if(LIBRW_GL3_GFXLIB STREQUAL "GLFW")
set(platform "-gl3-glfw")
else()
set(platform "-gl3-sdl2")
endif()
elseif(LIBRW_PLATFORM STREQUAL "D3D9")
set(platform "-d3d9")
endif()
if(RE3_AUDIO STREQUAL "OAL")
set(audio "-oal")
elseif(RE3_AUDIO STREQUAL "MSS")
set(audio "-mss")
endif()
if(RE3_WITH_OPUS)
set(audio "${audio}-opus")
endif()
if(WIN32)
set(os "-win")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(os "${os}64")
else()
set(os "${os}32")
endif()
elseif(APPLE)
set(os "-apple")
elseif(UNIX)
set(os "-linux")
else()
set(os "-UNK")
message(WARNING "Unknown os. Created cpack package will be wrong. (override using cpack -P)")
endif()
set(name_osarch "${PROJECT_NAME}${platform}${audio}${os}${compiler}")
set(CPACK_PACKAGE_FILE_NAME "${name_osarch}")
if(CPACK_GENERATOR MATCHES "^(7Z|TBZ|TGZ|TXZ|TZ|TZST|ZIP)$")
set(CPACK_COMPONENTS_GROUPING "ONE_PER_GROUP")
set(CPACK_COMPONENT_COMP1_CORE_GROUP "BinaryGroup")
set(CPACK_COMPONENT_COMP2_GAMEDATA_GROUP "BinaryGroup")
set(CPACK_COMPONENT_COMP3_RUNTIME_GROUP "BinaryGroup")
set(CPACK_COMPONENT_COMP4_DEBUG_GROUP "BinaryGroup")
set(CPACK_COMPONENT_COMPZ_SOURCES_GROUP "SourceGroup")
set(CPACK_ARCHIVE_SOURCEGROUP_FILE_NAME "${PROJECT_NAME}-src")
set(CPACK_ARCHIVE_BINARYGROUP_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}")
elseif(CPACK_GENERATOR MATCHES "^NSIS(64)?$")
list(REMOVE_ITEM CPACK_COMPONENTS_ALL "compZ_sources")
set(CPACK_PACKAGE_FILE_NAME "${name_osarch}-setup")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME} (${PROJECT_AUTHOR})")
set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\${PROJECT_NAME}.lnk\" \"$INSTDIR\\${PROJECT_NAME}.exe\"")
set(CPACK_NSIS_DELETE_ICONS_EXTRA "Delete \"$SMPROGRAMS\\$MUI_TEMP\${PROJECT_NAME}.lnk\"")
endif()

File diff suppressed because it is too large Load Diff

@ -67,9 +67,6 @@ class Re3Conan(ConanFile):
def validate(self): def validate(self):
if self.options["librw"].platform == "gl3" and self.options["librw"].gl3_gfxlib != "glfw": if self.options["librw"].platform == "gl3" and self.options["librw"].gl3_gfxlib != "glfw":
raise ConanInvalidConfiguration("Only `glfw` is supported as gl3_gfxlib.") raise ConanInvalidConfiguration("Only `glfw` is supported as gl3_gfxlib.")
#if not self.options.with_opus:
# if not self.options["libsndfile"].with_external_libs:
# raise ConanInvalidConfiguration("re3 with opus support requires a libsndfile built with external libs (=ogg/flac/opus/vorbis)")
@property @property
def _re3_audio(self): def _re3_audio(self):
@ -108,17 +105,23 @@ class Re3Conan(ConanFile):
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(cmake_wrapper) project(cmake_wrapper)
# FIXME: remove and move to main cmake script once conan CMakeToolchain is fully functional.
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT {})
include("{}/conanbuildinfo.cmake") include("{}/conanbuildinfo.cmake")
conan_basic_setup(TARGETS NO_OUTPUT_DIRS) conan_basic_setup(TARGETS NO_OUTPUT_DIRS)
add_subdirectory("{}" re3) add_subdirectory("{}" re3)
""").format(self.install_folder.replace("\\", "/"), """).format(
self.name,
self.install_folder.replace("\\", "/"),
self.source_folder.replace("\\", "/"))) self.source_folder.replace("\\", "/")))
except FileNotFoundError: except FileNotFoundError:
pass pass
cmake = CMake(self) cmake = CMake(self)
cmake.definitions["RE3_AUDIO"] = self._re3_audio cmake.definitions["RE3_AUDIO"] = self._re3_audio
cmake.definitions["RE3_WITH_OPUS"] = self.options.with_opus cmake.definitions["RE3_WITH_OPUS"] = self.options.with_opus
cmake.definitions["RE3_WITH_LIBSNDFILE"] = self.options.with_libsndfile
cmake.definitions["RE3_INSTALL"] = True cmake.definitions["RE3_INSTALL"] = True
cmake.definitions["RE3_VENDORED_LIBRW"] = False cmake.definitions["RE3_VENDORED_LIBRW"] = False
env = {} env = {}

@ -0,0 +1,17 @@
import os
from PIL import Image
os.chdir(os.path.dirname(os.path.realpath(__file__)))
original = Image.open("logo.png")
icon_sizes = [(256, 256), (128, 128), (64, 64), (48, 48), (32, 32), (16, 16)]
original.save("logo.ico", sizes=icon_sizes)
# Crop logo + make sure that background is white
width, height = original.size
crop_area = (0, height // 6, width, height - height // 6)
cropped_image = original.crop(crop_area)
cropped_size = (crop_area[2] - crop_area[0], crop_area[3] - crop_area[1])
new_image = Image.new("RGBA", cropped_size, "WHITE")
new_image.paste(cropped_image, (0, 0), cropped_image)
new_image.convert("RGB").save("logo.bmp")

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

@ -1,7 +1,9 @@
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
file(GLOB_RECURSE ${PROJECT}_SOURCES "*.cpp" "*.h" "*.rc") file(GLOB_RECURSE RE3_SOURCES "*.cpp" "*.h" "*.rc")
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${RE3_SOURCES})
function(header_directories RETURN_LIST) function(header_directories RETURN_LIST)
file(GLOB_RECURSE ALL_SRCS *.h *.cpp *.c) file(GLOB_RECURSE ALL_SRCS *.h *.cpp *.c)
@ -15,10 +17,10 @@ function(header_directories RETURN_LIST)
set(${RETURN_LIST} ${RELDIRS} PARENT_SCOPE) set(${RETURN_LIST} ${RELDIRS} PARENT_SCOPE)
endfunction() endfunction()
header_directories(${PROJECT}_INCLUDES) header_directories(RE3_INCLUDES)
add_executable(${EXECUTABLE} WIN32 add_executable(${EXECUTABLE} WIN32
${${PROJECT}_SOURCES} ${RE3_SOURCES}
) )
target_link_libraries(${EXECUTABLE} PRIVATE target_link_libraries(${EXECUTABLE} PRIVATE
@ -29,15 +31,22 @@ target_link_libraries(${EXECUTABLE} PRIVATE
target_include_directories(${EXECUTABLE} target_include_directories(${EXECUTABLE}
PRIVATE PRIVATE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}> $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<BUILD_INTERFACE:${${PROJECT}_INCLUDES}> $<BUILD_INTERFACE:${RE3_INCLUDES}>
) )
target_compile_definitions(${EXECUTABLE} target_compile_definitions(${EXECUTABLE}
PRIVATE PRIVATE
$<IF:$<CONFIG:DEBUG>,DEBUG,NDEBUG> $<IF:$<CONFIG:DEBUG>,DEBUG,NDEBUG>
LIBRW LIBRW
${PROJECT}_NO_AUTOLINK RE3_NO_AUTOLINK
RELOCATABLE
) )
if(STEAMID)
target_compile_definitions(${EXECUTABLE}
PRIVATE
STEAMID=${STEAMID}
)
endif()
if(LIBRW_PLATFORM_D3D9) if(LIBRW_PLATFORM_D3D9)
target_compile_definitions(${EXECUTABLE} target_compile_definitions(${EXECUTABLE}
@ -46,13 +55,13 @@ if(LIBRW_PLATFORM_D3D9)
) )
endif() endif()
if(${PROJECT}_AUDIO STREQUAL "OAL") if(RE3_AUDIO STREQUAL "OAL")
find_package(OpenAL REQUIRED) find_package(OpenAL REQUIRED)
target_include_directories(${EXECUTABLE} PRIVATE ${OPENAL_INCLUDE_DIR}) target_include_directories(${EXECUTABLE} PRIVATE ${OPENAL_INCLUDE_DIR})
target_link_libraries(${EXECUTABLE} PRIVATE ${OPENAL_LIBRARY}) target_link_libraries(${EXECUTABLE} PRIVATE ${OPENAL_LIBRARY})
target_compile_definitions(${EXECUTABLE} PRIVATE ${OPENAL_DEFINITIONS}) target_compile_definitions(${EXECUTABLE} PRIVATE ${OPENAL_DEFINITIONS})
target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_OAL) target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_OAL)
elseif(${PROJECT}_AUDIO STREQUAL "MSS") elseif(RE3_AUDIO STREQUAL "MSS")
find_package(MilesSDK REQUIRED) find_package(MilesSDK REQUIRED)
target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_MSS) target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_MSS)
target_link_libraries(${EXECUTABLE} PRIVATE MilesSDK::MilesSDK) target_link_libraries(${EXECUTABLE} PRIVATE MilesSDK::MilesSDK)
@ -62,14 +71,14 @@ find_package(mpg123 REQUIRED)
target_link_libraries(${EXECUTABLE} PRIVATE target_link_libraries(${EXECUTABLE} PRIVATE
MPG123::libmpg123 MPG123::libmpg123
) )
if(${PROJECT}_WITH_OPUS) if(RE3_WITH_OPUS)
find_package(opusfile REQUIRED) find_package(opusfile REQUIRED)
target_link_libraries(${EXECUTABLE} PRIVATE target_link_libraries(${EXECUTABLE} PRIVATE
opusfile::opusfile opusfile::opusfile
) )
target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_OPUS) target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_OPUS)
endif() endif()
if(${PROJECT}_WITH_LIBSNDFILE) if(RE3_WITH_LIBSNDFILE)
find_package(SndFile REQUIRED) find_package(SndFile REQUIRED)
target_link_libraries(${EXECUTABLE} PRIVATE target_link_libraries(${EXECUTABLE} PRIVATE
SndFile::SndFile SndFile::SndFile
@ -107,15 +116,23 @@ set_target_properties(${EXECUTABLE}
CXX_STANDARD 11 CXX_STANDARD 11
CXX_EXTENSIONS OFF CXX_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON CXX_STANDARD_REQUIRED ON
VS_DEBUGGER_ENVIRONMENT "GTA3DIR=$<SHELL_PATH:${PROJECT_SOURCE_DIR}/gamefiles>"
VS_DEBUGGER_COMMAND_ARGUMENTS "-console"
VS_JUST_MY_CODE_DEBUGGING ON
) )
if(${PROJECT}_INSTALL) if(RE3_INSTALL)
install( install(
TARGETS ${EXECUTABLE} TARGETS ${EXECUTABLE}
EXPORT ${EXECUTABLE}-targets EXPORT ${EXECUTABLE}-targets
RUNTIME DESTINATION "." RUNTIME DESTINATION "."
COMPONENT comp1_core
) )
if(MSVC) if(MSVC)
install(FILES $<TARGET_PDB_FILE:${EXECUTABLE}> DESTINATION "." OPTIONAL) install(
FILES $<TARGET_PDB_FILE:${EXECUTABLE}>
DESTINATION "." OPTIONAL
COMPONENT comp4_debug
)
endif() endif()
endif() endif()

@ -1,7 +1,5 @@
#pragma once #pragma once
#include "common.h"
enum eSfxSample enum eSfxSample
{ {
SFX_CAR_HORN_JEEP = 0, SFX_CAR_HORN_JEEP = 0,

@ -1,9 +1,11 @@
#ifdef AUDIO_OAL
#include "common.h" #include "common.h"
#ifdef AUDIO_OAL
#include "stream.h" #include "stream.h"
#include "sampman.h" #include "sampman.h"
#include "relocatable.h"
#if defined _MSC_VER && !defined RE3_NO_AUTOLINK #if defined _MSC_VER && !defined RE3_NO_AUTOLINK
#ifdef AUDIO_OAL_USE_SNDFILE #ifdef AUDIO_OAL_USE_SNDFILE
#pragma comment( lib, "libsndfile-1.lib" ) #pragma comment( lib, "libsndfile-1.lib" )
@ -213,7 +215,7 @@ class CWavFile : public IDecoder
public: public:
CWavFile(const char* path) : m_bIsOpen(false), m_DataStartOffset(0), m_nSampleCount(0), m_nSamplesPerBlock(0), m_pAdpcmBuffer(nil), m_ppPcmBuffers(nil), m_pAdpcmDecoders(nil) CWavFile(const char* path) : m_bIsOpen(false), m_DataStartOffset(0), m_nSampleCount(0), m_nSamplesPerBlock(0), m_pAdpcmBuffer(nil), m_ppPcmBuffers(nil), m_pAdpcmDecoders(nil)
{ {
m_pFile = fopen(path, "rb"); m_pFile = reloc_fopen(path, "rb");
if (!m_pFile) return; if (!m_pFile) return;
#define CLOSE_ON_ERROR(op)\ #define CLOSE_ON_ERROR(op)\
@ -402,7 +404,7 @@ public:
m_pfSound(nil) m_pfSound(nil)
{ {
memset(&m_soundInfo, 0, sizeof(m_soundInfo)); memset(&m_soundInfo, 0, sizeof(m_soundInfo));
m_pfSound = sf_open(path, SFM_READ, &m_soundInfo); m_pfSound = sf_open(reloc_realpath(path), SFM_READ, &m_soundInfo);
} }
~CSndFile() ~CSndFile()
@ -490,7 +492,7 @@ public:
int channels = 0; int channels = 0;
int encoding = 0; int encoding = 0;
m_bOpened = mpg123_open(m_pMH, path) == MPG123_OK m_bOpened = mpg123_open(m_pMH, reloc_realpath(path)) == MPG123_OK
&& mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK; && mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK;
m_nRate = rate; m_nRate = rate;
m_nChannels = channels; m_nChannels = channels;
@ -669,7 +671,7 @@ public:
CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), m_pVagDecoders(nil), m_ppVagBuffers(nil), m_ppPcmBuffers(nil), CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), m_pVagDecoders(nil), m_ppVagBuffers(nil), m_ppPcmBuffers(nil),
m_FileSize(0), m_nNumberOfBlocks(0), m_bBlockRead(false), m_LineInBlock(0), m_CurrentBlock(0) m_FileSize(0), m_nNumberOfBlocks(0), m_bBlockRead(false), m_LineInBlock(0), m_CurrentBlock(0)
{ {
m_pFile = fopen(path, "rb"); m_pFile = reloc_fopen(path, "rb");
if (!m_pFile) return; if (!m_pFile) return;
fseek(m_pFile, 0, SEEK_END); fseek(m_pFile, 0, SEEK_END);
@ -819,7 +821,7 @@ public:
m_nChannels(0) m_nChannels(0)
{ {
int ret; int ret;
m_FileH = op_open_file(path, &ret); m_FileH = op_open_file(reloc_realpath(path), &ret);
if (m_FileH) { if (m_FileH) {
m_nChannels = op_head(m_FileH, 0)->channel_count; m_nChannels = op_head(m_FileH, 0)->channel_count;
@ -915,7 +917,7 @@ void CStream::Terminate()
#endif #endif
} }
CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate) : CStream::CStream(const char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate) :
m_pAlSources(sources), m_pAlSources(sources),
m_alBuffers(buffers), m_alBuffers(buffers),
m_pBuffer(nil), m_pBuffer(nil),
@ -930,7 +932,7 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU
{ {
// Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/) // Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/)
#if !defined(_WIN32) #if !defined(_WIN32)
char *real = casepath(filename); char *real = reloc_casepath(filename);
if (real) { if (real) {
strcpy(m_aFilename, real); strcpy(m_aFilename, real);
free(real); free(real);

@ -86,7 +86,7 @@ public:
static void Initialise(); static void Initialise();
static void Terminate(); static void Terminate();
CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate = 32000); CStream(const char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate = 32000);
~CStream(); ~CStream();
void Delete(); void Delete();

@ -14,6 +14,7 @@
#include "MusicManager.h" #include "MusicManager.h"
#include "Frontend.h" #include "Frontend.h"
#include "Timer.h" #include "Timer.h"
#include "relocatable.h"
#pragma comment( lib, "mss32.lib" ) #pragma comment( lib, "mss32.lib" )
@ -369,7 +370,7 @@ _ResolveLink(char const *path, char *out)
{ {
WCHAR wpath[MAX_PATH]; WCHAR wpath[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, reloc_realpath(path), -1, wpath, MAX_PATH);
if (SUCCEEDED(ppf->Load(wpath, STGM_READ))) if (SUCCEEDED(ppf->Load(wpath, STGM_READ)))
{ {
@ -378,7 +379,7 @@ _ResolveLink(char const *path, char *out)
{ {
strcpy(filepath, path); strcpy(filepath, path);
if (SUCCEEDED(psl->GetPath(filepath, MAX_PATH, &fd, SLGP_UNCPRIORITY))) if (SUCCEEDED(psl->GetPath(reloc_realpath(filepath), MAX_PATH, &fd, SLGP_UNCPRIORITY)))
{ {
OutputDebugString(fd.cFileName); OutputDebugString(fd.cFileName);
@ -429,7 +430,7 @@ _FindMP3s(void)
strcat(path, "*"); strcat(path, "*");
hFind = FindFirstFile(path, &fd); hFind = reloc_FindFirstFile(path, &fd);
if ( hFind == INVALID_HANDLE_VALUE ) if ( hFind == INVALID_HANDLE_VALUE )
{ {
@ -444,7 +445,7 @@ _FindMP3s(void)
if ( filepathlen <= 0) if ( filepathlen <= 0)
{ {
FindClose(hFind); reloc_FindClose(hFind);
return; return;
} }
@ -479,7 +480,7 @@ _FindMP3s(void)
bShortcut = false; bShortcut = false;
} }
mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0);
if ( mp3Stream[0] ) if ( mp3Stream[0] )
{ {
AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL); AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL);
@ -493,7 +494,7 @@ _FindMP3s(void)
if ( _pMP3List == NULL ) if ( _pMP3List == NULL )
{ {
FindClose(hFind); reloc_FindClose(hFind);
if ( f ) if ( f )
fclose(f); fclose(f);
@ -538,7 +539,7 @@ _FindMP3s(void)
while ( true ) while ( true )
{ {
if ( !FindNextFile(hFind, &fd) ) if ( !reloc_FindNextFile(hFind, &fd) )
break; break;
if ( bInitFirstEntry ) if ( bInitFirstEntry )
@ -583,7 +584,7 @@ _FindMP3s(void)
} }
} }
mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0);
if ( mp3Stream[0] ) if ( mp3Stream[0] )
{ {
AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL); AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL);
@ -665,7 +666,7 @@ _FindMP3s(void)
} }
} }
mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0);
if ( mp3Stream[0] ) if ( mp3Stream[0] )
{ {
AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL); AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL);
@ -719,7 +720,7 @@ _FindMP3s(void)
fclose(f); fclose(f);
} }
FindClose(hFind); reloc_FindClose(hFind);
} }
static void static void
@ -959,7 +960,7 @@ cSampleManager::Initialise(void)
#ifdef AUDIO_CACHE #ifdef AUDIO_CACHE
TRACE("cache"); TRACE("cache");
FILE *cacheFile = fopen("audio\\sound.cache", "rb"); FILE *cacheFile = reloc_fopen("audio\\sound.cache", "rb");
if (cacheFile) { if (cacheFile) {
fread(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); fread(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile);
fclose(cacheFile); fclose(cacheFile);
@ -993,7 +994,7 @@ cSampleManager::Initialise(void)
strcpy(filepath, m_szCDRomRootPath); strcpy(filepath, m_szCDRomRootPath);
strcat(filepath, StreamedNameTable[0]); strcat(filepath, StreamedNameTable[0]);
FILE *f = fopen(filepath, "rb"); FILE *f = reloc_fopen(filepath, "rb");
if ( f ) if ( f )
{ {
@ -1006,7 +1007,7 @@ cSampleManager::Initialise(void)
strcpy(filepath, m_szCDRomRootPath); strcpy(filepath, m_szCDRomRootPath);
strcat(filepath, StreamedNameTable[i]); strcat(filepath, StreamedNameTable[i]);
mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0);
if ( mp3Stream[0] ) if ( mp3Stream[0] )
{ {
@ -1076,7 +1077,7 @@ cSampleManager::Initialise(void)
strcpy(_aHDDPath, m_szCDRomRootPath); strcpy(_aHDDPath, m_szCDRomRootPath);
rootpath[0] = '\0'; rootpath[0] = '\0';
FILE *f = fopen(StreamedNameTable[0], "rb"); FILE *f = reloc_fopen(StreamedNameTable[0], "rb");
if ( f ) if ( f )
{ {
@ -1087,7 +1088,7 @@ cSampleManager::Initialise(void)
strcpy(filepath, rootpath); strcpy(filepath, rootpath);
strcat(filepath, StreamedNameTable[i]); strcat(filepath, StreamedNameTable[i]);
mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0);
if ( mp3Stream[0] ) if ( mp3Stream[0] )
{ {
@ -1123,7 +1124,7 @@ cSampleManager::Initialise(void)
} }
#endif #endif
#ifdef AUDIO_CACHE #ifdef AUDIO_CACHE
cacheFile = fopen("audio\\sound.cache", "wb"); cacheFile = reloc_fopen("audio\\sound.cache", "wb");
fwrite(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); fwrite(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile);
fclose(cacheFile); fclose(cacheFile);
} }
@ -1309,7 +1310,7 @@ cSampleManager::CheckForAnAudioFileOnCD(void)
strcat(filepath, StreamedNameTable[AudioManager.GetRandomNumber(1) % TOTAL_STREAMED_SOUNDS]); strcat(filepath, StreamedNameTable[AudioManager.GetRandomNumber(1) % TOTAL_STREAMED_SOUNDS]);
FILE *f = fopen(filepath, "rb"); FILE *f = reloc_fopen(filepath, "rb");
if ( f ) if ( f )
{ {
@ -2009,7 +2010,7 @@ cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream)
strcpy(filepath, m_szCDRomRootPath); strcpy(filepath, m_szCDRomRootPath);
strcat(filepath, StreamedNameTable[nFile]); strcat(filepath, StreamedNameTable[nFile]);
mp3Stream[nStream] = AIL_open_stream(DIG, filepath, 0); mp3Stream[nStream] = AIL_open_stream(DIG, reloc_realpath(filepath), 0);
if ( mp3Stream[nStream] ) if ( mp3Stream[nStream] )
{ {
@ -2289,11 +2290,11 @@ cSampleManager::InitialiseSampleBanks(void)
{ {
int32 nBank = SFX_BANK_0; int32 nBank = SFX_BANK_0;
fpSampleDescHandle = fopen(SampleBankDescFilename, "rb"); fpSampleDescHandle = reloc_fopen(SampleBankDescFilename, "rb");
if ( fpSampleDescHandle == NULL ) if ( fpSampleDescHandle == NULL )
return false; return false;
fpSampleDataHandle = fopen(SampleBankDataFilename, "rb"); fpSampleDataHandle = reloc_fopen(SampleBankDataFilename, "rb");
if ( fpSampleDataHandle == NULL ) if ( fpSampleDataHandle == NULL )
{ {
fclose(fpSampleDescHandle); fclose(fpSampleDescHandle);

@ -14,7 +14,9 @@
#include <AL/efx.h> #include <AL/efx.h>
#include <AL/efx-presets.h> #include <AL/efx-presets.h>
#ifdef _MSC_VER
#pragma comment(lib, "OpenAL32.lib") #pragma comment(lib, "OpenAL32.lib")
#endif
// for user MP3s // for user MP3s
#include <direct.h> #include <direct.h>
@ -24,8 +26,10 @@
#define _getcwd getcwd #define _getcwd getcwd
#endif #endif
#define WITHWINDOWS
#include "common.h" #include "common.h"
#include "crossplatform.h" #include "crossplatform.h"
#include "relocatable.h"
#include "sampman.h" #include "sampman.h"
@ -562,7 +566,7 @@ _FindMP3s(void)
strcat(path, "*"); strcat(path, "*");
hFind = FindFirstFile(path, &fd); hFind = reloc_FindFirstFile(path, &fd);
if ( hFind == INVALID_HANDLE_VALUE ) if ( hFind == INVALID_HANDLE_VALUE )
{ {
@ -576,7 +580,7 @@ _FindMP3s(void)
if ( filepathlen <= 0) if ( filepathlen <= 0)
{ {
FindClose(hFind); reloc_FindClose(hFind);
return; return;
} }
@ -964,7 +968,7 @@ cSampleManager::Initialise(void)
add_providers(); add_providers();
#ifdef AUDIO_CACHE #ifdef AUDIO_CACHE
FILE *cacheFile = fcaseopen("audio\\sound.cache", "rb"); FILE *cacheFile = reloc_fcaseopen("audio\\sound.cache", "rb"); // FIXME: was fcaseopen
if (cacheFile) { if (cacheFile) {
debug("Loadind audio cache (If game crashes around here, then your cache is corrupted, remove audio/sound.cache)\n"); debug("Loadind audio cache (If game crashes around here, then your cache is corrupted, remove audio/sound.cache)\n");
fread(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); fread(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile);
@ -987,7 +991,13 @@ cSampleManager::Initialise(void)
USERERROR("Can't open '%s'\n", StreamedNameTable[i]); USERERROR("Can't open '%s'\n", StreamedNameTable[i]);
} }
#ifdef AUDIO_CACHE #ifdef AUDIO_CACHE
cacheFile = fcaseopen("audio\\sound.cache", "wb"); // FIXME: cross platform mkdir!!!
#ifdef _MSC_VER
::mkdir("audio");
#else
::mkdir("audio", S_IREAD | S_IWRITE | S_IEXEC | S_IXGRP | S_IXOTH);
#endif
cacheFile = reloc_fcaseopen("audio\\sound.cache", "wb");
if(cacheFile) { if(cacheFile) {
debug("Saving audio cache\n"); debug("Saving audio cache\n");
fwrite(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); fwrite(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile);
@ -1970,11 +1980,11 @@ cSampleManager::InitialiseSampleBanks(void)
{ {
int32 nBank = SFX_BANK_0; int32 nBank = SFX_BANK_0;
fpSampleDescHandle = fcaseopen(SampleBankDescFilename, "rb"); fpSampleDescHandle = reloc_fcaseopen(SampleBankDescFilename, "rb");
if ( fpSampleDescHandle == NULL ) if ( fpSampleDescHandle == NULL )
return false; return false;
#ifndef OPUS_SFX #ifndef OPUS_SFX
fpSampleDataHandle = fcaseopen(SampleBankDataFilename, "rb"); fpSampleDataHandle = reloc_fcaseopen(SampleBankDataFilename, "rb");
if ( fpSampleDataHandle == NULL ) if ( fpSampleDataHandle == NULL )
{ {
fclose(fpSampleDescHandle); fclose(fpSampleDescHandle);

@ -6,9 +6,10 @@
#include "rwcore.h" #include "rwcore.h"
#include "RwHelper.h" #include "RwHelper.h"
#include "MemoryMgr.h" #include "MemoryMgr.h"
#include "relocatable.h"
#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__)
#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, "cdvd_stream: " f "\n", ## __VA_ARGS__)
struct CdReadInfo struct CdReadInfo
{ {
@ -472,9 +473,7 @@ CdStreamAddImage(char const *path)
ASSERT(path != nil); ASSERT(path != nil);
ASSERT(gNumImages < MAX_CDIMAGES); ASSERT(gNumImages < MAX_CDIMAGES);
SetLastError(0); gImgFiles[gNumImages] = CreateFile(reloc_realpath(path),
gImgFiles[gNumImages] = CreateFile(path,
GENERIC_READ, GENERIC_READ,
FILE_SHARE_READ, FILE_SHARE_READ,
nil, nil,
@ -482,8 +481,8 @@ CdStreamAddImage(char const *path)
_gdwCdStreamFlags | FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_READONLY, _gdwCdStreamFlags | FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_READONLY,
nil); nil);
ASSERT( gImgFiles[gNumImages] != nil ); ASSERT( gImgFiles[gNumImages] != INVALID_HANDLE_VALUE );
if ( gImgFiles[gNumImages] == NULL ) if ( gImgFiles[gNumImages] == INVALID_HANDLE_VALUE )
return false; return false;
strcpy(gCdImageNames[gNumImages], path); strcpy(gCdImageNames[gNumImages], path);

@ -1,6 +1,7 @@
#ifndef _WIN32 #ifndef _WIN32
#include "common.h" #include "common.h"
#include "crossplatform.h" #include "crossplatform.h"
#include "relocatable.h"
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <semaphore.h> #include <semaphore.h>
@ -19,7 +20,7 @@
#include "MemoryMgr.h" #include "MemoryMgr.h"
#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__)
#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) TRACE ("cddvd_stream: " f "\n", ## __VA_ARGS__)
// #define ONE_THREAD_PER_CHANNEL // Don't use if you're not on SSD/Flash. (Also you may want to benefit from this via using all channels in Streaming.cpp) // #define ONE_THREAD_PER_CHANNEL // Don't use if you're not on SSD/Flash. (Also you may want to benefit from this via using all channels in Streaming.cpp)
@ -145,7 +146,7 @@ CdStreamInit(int32 numChannels)
{ {
struct statvfs fsInfo; struct statvfs fsInfo;
if((statvfs("models/gta3.img", &fsInfo)) < 0) if((statvfs(reloc_realpath("models/gta3.img"), &fsInfo)) < 0)
{ {
CDTRACE("can't get filesystem info"); CDTRACE("can't get filesystem info");
ASSERT(0); ASSERT(0);
@ -192,7 +193,7 @@ GetGTA3ImgSize(void)
realpath(gImgNames[0], path); realpath(gImgNames[0], path);
if (stat(path, &statbuf) == -1) { if (stat(path, &statbuf) == -1) {
// Try case-insensitivity // Try case-insensitivity
char* real = casepath(gImgNames[0], false); char* real = reloc_casepath(gImgNames[0], false);
if (real) if (real)
{ {
realpath(real, path); realpath(real, path);
@ -483,11 +484,11 @@ CdStreamAddImage(char const *path)
ASSERT(path != nil); ASSERT(path != nil);
ASSERT(gNumImages < MAX_CDIMAGES); ASSERT(gNumImages < MAX_CDIMAGES);
gImgFiles[gNumImages] = open(path, _gdwCdStreamFlags); gImgFiles[gNumImages] = open(reloc_realpath(path), _gdwCdStreamFlags);
// Fix case sensitivity and backslashes. // Fix case sensitivity and backslashes.
if (gImgFiles[gNumImages] == -1) { if (gImgFiles[gNumImages] == -1) {
char* real = casepath(path, false); char* real = reloc_casepath(path, false);
if (real) if (real)
{ {
gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags); gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags);

@ -69,7 +69,7 @@ CFileLoader::LoadLevel(const char *filename)
assert(fd > 0); assert(fd > 0);
for(line = LoadLine(fd); line; line = LoadLine(fd)){ for(line = LoadLine(fd); line; line = LoadLine(fd)){
if(*line == '#') if((*line == '#') || (*line == '\0'))
continue; continue;
#ifdef FIX_BUGS #ifdef FIX_BUGS
@ -167,9 +167,12 @@ CFileLoader::LoadLine(int fd)
if(CFileMgr::ReadLine(fd, ms_line, 256) == false) if(CFileMgr::ReadLine(fd, ms_line, 256) == false)
return nil; return nil;
for(i = 0; ms_line[i] != '\0'; i++) for(i = 0; ms_line[i] != '\0'; i++) {
if(ms_line[i] < ' ' || ms_line[i] == ',') if(ms_line[i] == '\n')
ms_line[i] = '\0';
else if(ms_line[i] < ' ' || ms_line[i] == ',')
ms_line[i] = ' '; ms_line[i] = ' ';
}
for(line = ms_line; *line <= ' ' && *line != '\0'; line++); for(line = ms_line; *line <= ' ' && *line != '\0'; line++);
return line; return line;
} }

@ -5,6 +5,7 @@
#endif #endif
#include "common.h" #include "common.h"
#include "crossplatform.h" #include "crossplatform.h"
#include "relocatable.h"
#include "FileMgr.h" #include "FileMgr.h"
@ -27,18 +28,16 @@ struct myFILE
#define NUMFILES 20 #define NUMFILES 20
static myFILE myfiles[NUMFILES]; static myFILE myfiles[NUMFILES];
#if !defined(_WIN32) #if !defined(_WIN32)
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#define _getcwd getcwd #define _getcwd getcwd
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen) // Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
void mychdir(char const *path) void mychdir(char const *path)
{ {
char* r = casepath(path, false); char *r = reloc_casepath(path, false);
if (r) { if(r) {
chdir(r); chdir(r);
free(r); free(r);
} else { } else {
@ -71,8 +70,8 @@ found:
*p++ = 'b'; *p++ = 'b';
*p = '\0'; *p = '\0';
myfiles[fd].file = fcaseopen(filename, realmode); myfiles[fd].file = reloc_fcaseopen(filename, realmode);
if(myfiles[fd].file == nil) if (myfiles[fd].file == nil)
return 0; return 0;
return fd; return fd;
} }
@ -200,24 +199,30 @@ char CFileMgr::ms_dirName[128];
void void
CFileMgr::Initialise(void) CFileMgr::Initialise(void)
{ {
strcpy(ms_dirName, "");
#ifdef RELOCATABLE
strcpy(ms_rootDirName, "");
#else
_getcwd(ms_rootDirName, 128); _getcwd(ms_rootDirName, 128);
strcat(ms_rootDirName, "\\"); strcat(ms_rootDirName, "\\");
#endif
reloc_initialize();
} }
void void
CFileMgr::ChangeDir(const char *dir) CFileMgr::ChangeDir(const char *dir)
{ {
if(*dir == '\\'){ strcpy(ms_dirName, dir);
strcpy(ms_dirName, ms_rootDirName); if (*dir != '\0'){
dir++;
}
if(*dir != '\0'){
strcat(ms_dirName, dir);
// BUG in the game it seems, it's off by one // BUG in the game it seems, it's off by one
if(dir[strlen(dir)-1] != '\\') if (dir[strlen(dir)-1] != '\\') {
strcat(ms_dirName, "\\"); strcat(ms_dirName, "\\");
} }
}
#ifndef RELOCATABLE
mychdir(ms_rootDirName);
mychdir(ms_dirName); mychdir(ms_dirName);
#endif
} }
void void
@ -230,14 +235,19 @@ CFileMgr::SetDir(const char *dir)
if(dir[strlen(dir)-1] != '\\') if(dir[strlen(dir)-1] != '\\')
strcat(ms_dirName, "\\"); strcat(ms_dirName, "\\");
} }
#ifndef RELOCATABLE
mychdir(ms_dirName); mychdir(ms_dirName);
#endif
} }
void void
CFileMgr::SetDirMyDocuments(void) CFileMgr::SetDirMyDocuments(void)
{ {
SetDir(""); // better start at the root if user directory is relative SetDir(""); // better start at the root if user directory is relative
//FIXME: When using USE_MY_DOCUMENTS, the returned path is absolute.
#ifndef RELOCATABLE
mychdir(_psGetUserFilesFolder()); mychdir(_psGetUserFilesFolder());
#endif
} }
ssize_t ssize_t

@ -1,5 +1,6 @@
#pragma once #pragma once
class CFileMgr class CFileMgr
{ {
static char ms_rootDirName[128]; static char ms_rootDirName[128];
@ -20,4 +21,5 @@ public:
static int CloseFile(int fd); static int CloseFile(int fd);
static int GetErrorReadWrite(int fd); static int GetErrorReadWrite(int fd);
static char *GetRootDirName() { return ms_rootDirName; } static char *GetRootDirName() { return ms_rootDirName; }
static const char *GetWorkingDir() { return ms_dirName; }
}; };

@ -4,6 +4,7 @@
#include "common.h" #include "common.h"
#ifndef PS2_MENU #ifndef PS2_MENU
#include "crossplatform.h" #include "crossplatform.h"
#include "relocatable.h"
#include "platform.h" #include "platform.h"
#include "Frontend.h" #include "Frontend.h"
#include "Font.h" #include "Font.h"
@ -3081,8 +3082,8 @@ CMenuManager::DrawPlayerSetupScreen()
WIN32_FIND_DATA FindFileData; WIN32_FIND_DATA FindFileData;
SYSTEMTIME SystemTime; SYSTEMTIME SystemTime;
HANDLE handle = FindFirstFile("skins\\*.bmp", &FindFileData); HANDLE handle = reloc_FindFirstFile("skins\\*.bmp", &FindFileData);
for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = FindNextFile(handle, &FindFileData)) { for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = reloc_FindNextFile(handle, &FindFileData)) {
if (strcmp(FindFileData.cFileName, DEFAULT_SKIN_NAME) != 0) { if (strcmp(FindFileData.cFileName, DEFAULT_SKIN_NAME) != 0) {
m_pSelectedSkin->nextSkin = new tSkinInfo; m_pSelectedSkin->nextSkin = new tSkinInfo;
m_pSelectedSkin = m_pSelectedSkin->nextSkin; m_pSelectedSkin = m_pSelectedSkin->nextSkin;
@ -3095,7 +3096,7 @@ CMenuManager::DrawPlayerSetupScreen()
m_pSelectedSkin->nextSkin = nil; m_pSelectedSkin->nextSkin = nil;
} }
} }
FindClose(handle); reloc_FindClose(handle);
m_nSkinsTotal = nextSkinId; m_nSkinsTotal = nextSkinId;
char nameTemp[256]; char nameTemp[256];
for (m_pSelectedSkin = m_pSkinListHead.nextSkin; m_pSelectedSkin; m_pSelectedSkin = m_pSelectedSkin->nextSkin) { for (m_pSelectedSkin = m_pSkinListHead.nextSkin; m_pSelectedSkin; m_pSelectedSkin = m_pSelectedSkin->nextSkin) {
@ -3686,7 +3687,7 @@ CMenuManager::LoadSettings()
m_nPrefsWidth = 0; m_nPrefsWidth = 0;
m_nPrefsHeight = 0; m_nPrefsHeight = 0;
m_nPrefsDepth = 0; m_nPrefsDepth = 0;
m_nPrefsWindowed = 0; m_nPrefsWindowed =0;
m_nPrefsSubsystem = 0; m_nPrefsSubsystem = 0;
} }
m_nSelectedScreenMode = m_nPrefsWindowed; m_nSelectedScreenMode = m_nPrefsWindowed;
@ -3756,14 +3757,14 @@ CMenuManager::LoadSettings()
WIN32_FIND_DATA FindFileData; WIN32_FIND_DATA FindFileData;
char skinfile[256+16]; // Stack analysis shows 16 bits gap, but I don't trust it. It may very well be MAX_PATH(260). char skinfile[256+16]; // Stack analysis shows 16 bits gap, but I don't trust it. It may very well be MAX_PATH(260).
bool SkinFound = false; bool SkinFound = false;
HANDLE handle = FindFirstFile("skins\\*.bmp", &FindFileData); HANDLE handle = reloc_FindFirstFile("skins\\*.bmp", &FindFileData);
for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = FindNextFile(handle, &FindFileData)) { for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = reloc_FindNextFile(handle, &FindFileData)) {
strcpy(skinfile, m_PrefsSkinFile); strcpy(skinfile, m_PrefsSkinFile);
strcat(skinfile, ".bmp"); strcat(skinfile, ".bmp");
if (strcmp(FindFileData.cFileName, skinfile) == 0) if (strcmp(FindFileData.cFileName, skinfile) == 0)
SkinFound = true; SkinFound = true;
} }
FindClose(handle); reloc_FindClose(handle);
if (!SkinFound) { if (!SkinFound) {
OutputDebugString("Default skin set as no other skins are available OR saved skin not found!"); OutputDebugString("Default skin set as no other skins are available OR saved skin not found!");

@ -1,11 +1,13 @@
#pragma once #pragma once
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#pragma warning(disable: 4244) // int to float #pragma warning(disable: 4244) // int to float
#pragma warning(disable: 4800) // int to bool #pragma warning(disable: 4800) // int to bool
#pragma warning(disable: 4838) // narrowing conversion #pragma warning(disable: 4838) // narrowing conversion
#pragma warning(disable: 4996) // POSIX names #pragma warning(disable: 4996) // POSIX names
#endif
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -305,7 +307,7 @@ void re3_usererror(const char *format, ...);
#endif #endif
#define debug(f, ...) re3_debug("[DBG]: " f, ## __VA_ARGS__) #define debug(f, ...) re3_debug("[DBG]: " f, ## __VA_ARGS__)
#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, ## __VA_ARGS__) #define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f "\n", ## __VA_ARGS__)
#define Error(f, ...) re3_debug("[ERROR]: " f, ## __VA_ARGS__) #define Error(f, ...) re3_debug("[ERROR]: " f, ## __VA_ARGS__)
#define USERERROR(f, ...) re3_usererror(f, ## __VA_ARGS__) #define USERERROR(f, ...) re3_usererror(f, ## __VA_ARGS__)

@ -7,9 +7,9 @@
#include <rpskin.h> #include <rpskin.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#ifndef _WIN32
#include "crossplatform.h" #include "crossplatform.h"
#endif #include "relocatable.h"
using namespace rw; using namespace rw;
@ -337,10 +337,6 @@ const RwTexDictionary *RwTexDictionaryStreamWrite(const RwTexDictionary *texDict
return texDict; return texDict;
} }
RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const void *pData) { RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const void *pData) {
StreamFile *file; StreamFile *file;
StreamMemory *mem; StreamMemory *mem;
@ -361,9 +357,9 @@ RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const v
file = rwNewT(StreamFile, 1, 0); file = rwNewT(StreamFile, 1, 0);
memcpy(file, &fakefile, sizeof(StreamFile)); memcpy(file, &fakefile, sizeof(StreamFile));
#ifndef _WIN32 #ifndef _WIN32
char *r = casepath((char*)pData); char *r = reloc_casepath((char*)pData);
if (r) { if (r) {
if (file->open((char*)r, mode)) { if (file->open(r, mode)) {
free(r); free(r);
return file; return file;
} }
@ -371,7 +367,7 @@ RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const v
} else } else
#endif #endif
{ {
if (file->open((char*)pData, mode)) if (file->open((const char *)pData, mode))
return file; return file;
} }
rwFree(file); rwFree(file);
@ -913,7 +909,7 @@ RwImage *
RtBMPImageWrite(RwImage *image, const RwChar *imageName) RtBMPImageWrite(RwImage *image, const RwChar *imageName)
{ {
#ifndef _WIN32 #ifndef _WIN32
char *r = casepath(imageName); char *r = reloc_casepath(imageName);
if (r) { if (r) {
rw::writeBMP(image, r); rw::writeBMP(image, r);
free(r); free(r);
@ -931,7 +927,7 @@ RtBMPImageRead(const RwChar *imageName)
{ {
#ifndef _WIN32 #ifndef _WIN32
RwImage *image; RwImage *image;
char *r = casepath(imageName); char *r = reloc_casepath(imageName);
if (r) { if (r) {
image = rw::readBMP(r); image = rw::readBMP(r);
free(r); free(r);

@ -233,11 +233,11 @@ TWEAKFUNC(CParticle::ReloadConfig);
void CParticle::ReloadConfig() void CParticle::ReloadConfig()
{ {
debug("Initialising CParticleMgr..."); debug("Initialising CParticleMgr...\n");
mod_ParticleSystemManager.Initialise(); mod_ParticleSystemManager.Initialise();
debug("Initialising CParticle..."); debug("Initialising CParticle...\n");
m_pUnusedListHead = gParticleArray; m_pUnusedListHead = gParticleArray;
@ -622,7 +622,7 @@ CEntity::AddSteamsFromGround(CVector *unused)
void CParticle::Shutdown() void CParticle::Shutdown()
{ {
debug("Shutting down CParticle..."); debug("Shutting down CParticle...\n");
for ( int32 i = 0; i < MAX_SMOKE_FILES; i++ ) for ( int32 i = 0; i < MAX_SMOKE_FILES; i++ )
{ {

@ -1,3 +1,4 @@
#pragma once
#include <time.h> #include <time.h>
// This is the common include for platform/renderer specific skeletons(glfw.cpp, win.cpp etc.) and using cross platform things (like Windows directories wrapper, platform specific global arrays etc.) // This is the common include for platform/renderer specific skeletons(glfw.cpp, win.cpp etc.) and using cross platform things (like Windows directories wrapper, platform specific global arrays etc.)

@ -33,6 +33,7 @@ long _dwOperatingSystemVersion;
#include "skeleton.h" #include "skeleton.h"
#include "platform.h" #include "platform.h"
#include "crossplatform.h" #include "crossplatform.h"
#include "relocatable.h"
#include "main.h" #include "main.h"
#include "FileMgr.h" #include "FileMgr.h"
@ -860,7 +861,7 @@ void _InputInitialiseJoys()
// Load our gamepad mappings. // Load our gamepad mappings.
#define SDL_GAMEPAD_DB_PATH "gamecontrollerdb.txt" #define SDL_GAMEPAD_DB_PATH "gamecontrollerdb.txt"
FILE *f = fopen(SDL_GAMEPAD_DB_PATH, "rb"); FILE *f = reloc_fopen(SDL_GAMEPAD_DB_PATH, "rb");
if (f) { if (f) {
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
size_t fsize = ftell(f); size_t fsize = ftell(f);
@ -936,7 +937,7 @@ void psPostRWinit(void)
// Make sure all keys are released // Make sure all keys are released
CPad::GetPad(0)->Clear(true); CPad::GetPad(0)->Clear(true);
CPad::GetPad(1)->Clear(true); CPad::GetPad(1)->Clear(true);
} }
/* /*
***************************************************************************** *****************************************************************************
@ -1469,6 +1470,10 @@ WinMain(HINSTANCE instance,
if (strstr(cmdLine, "-console")) if (strstr(cmdLine, "-console"))
{ {
AllocConsole(); AllocConsole();
SetConsoleTitle("GTA3 Debug Console");
// Set default big history (to enable scrolling back)
CONSOLE_HISTORY_INFO historyInfo = {sizeof(CONSOLE_HISTORY_INFO), 9999, 4, 0};
SetConsoleHistoryInfo(&historyInfo);
freopen("CONIN$", "r", stdin); freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr); freopen("CONOUT$", "w", stderr);

@ -0,0 +1,492 @@
#ifdef RELOCATABLE
#include "common.h"
#include "FileMgr.h"
#include <string>
#ifdef _MSC_VER
#include <io.h>
#else
#include <libgen.h>
#include <unistd.h>
#endif
#ifdef __APPLE__
#include <sys/param.h>
#include <mach-o/dyld.h>
#endif
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <direct.h>
#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#endif
#define WITHWINDOWS
#include "crossplatform.h"
#include "relocatable.h"
#ifndef R_OK
#define R_OK 4
#endif
#ifdef _WIN32
#define PATHJOIN '\\'
#define PATHJOIN_S "\\"
#define PATHSEP ';'
#else
#define PATHJOIN '/'
#define PATHJOIN_S "/"
#define PATHSEP ':'
#endif
bool
FileExists(const char *path)
{
#if _WIN32
bool exists = PathFileExistsA(path);
struct stat status;
stat(path, &status);
return (status.st_mode & _S_IFREG) != 0;
#else
return access(path, R_OK) == 0;
#endif
}
bool
containsGta3Data(const std::string &dirPath)
{
std::string path(dirPath);
path.append("models" PATHJOIN_S "gta3.img");
return FileExists(path.c_str());
}
#ifdef _WIN32
std::string
winReadRegistry(HKEY hParentKey, const char *keyName, const char *valueName)
{
HKEY hKey;
if (RegOpenKeyExA(hParentKey, keyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
std::string res;
DWORD valueSize = 1024;
res.resize(valueSize);
DWORD keyType;
if (RegQueryValueEx(hKey, valueName, NULL, &keyType, (LPBYTE)res.data(), &valueSize) == ERROR_SUCCESS) {
RegCloseKey(hKey);
if(keyType == REG_SZ) {
res.resize(strlen(res.data()));
return res;
}
}
RegCloseKey(hKey);
}
return "";
}
std::string
psExePath()
{
std::string buf;
buf.resize(MAX_PATH);
if (GetModuleFileName(NULL, (LPSTR)buf.c_str(), MAX_PATH) == 0) {
debug("GetModuleFileNameA failed: cannot get path of executable.\n");
return "";
}
buf.resize(strlen(buf.c_str()));
return buf;
}
#endif
#ifdef __APPLE__
std::string
psExePath()
{
std::string buf;
uint32_t bufsize = 0;
_NSGetExecutablePath(NULL, &bufsize);
buf.resize(bufsize + 1);
if(_NSGetExecutablePath((char*)buf.c_str(), &bufsize) != 0) {
debug("_NSGetExecutablePath failed: cannot get path of executable.\n");
return "";
}
buf.resize(bufsize);
return buf;
}
#endif
#ifdef __linux__
std::string
psExePath()
{
std::string buf;
buf.resize(MAX_PATH);
ssize_t nb = readlink("/proc/self/exe", (char*)buf.c_str(), MAX_PATH);
if (nb == -1) {
return "";
}
buf.resize(strlen(buf.c_str()));
return buf;
}
#endif
std::string
psExeDir()
{
std::string exePath = psExePath();
if (!exePath.size()) {
return "";
}
#ifdef _MSC_VER
std::string::size_type lastSepPos = exePath.rfind(PATHJOIN);
if (lastSepPos >= 0) {
exePath.resize(lastSepPos);
return exePath;
}
return "";
#else
return dirname((char*)exePath.c_str());
#endif
}
#ifdef _WIN32
std::string
winGetGtaDataFolder()
{
if (containsGta3Data("C:\\Program Files\\Rockstar Games\\GTAIII\\")) {
return "C:\\Program Files\\Rockstar Games\\GTAIII\\";
}
std::string location;
location.resize(MAX_PATH);
BOOL success = SHGetSpecialFolderPathA(NULL, (LPSTR)location.c_str(), CSIDL_PROGRAM_FILESX86, FALSE);
if (success) {
location.resize(strlen(location.c_str()));
location.append("\\Rockstar Games\\GTAIII\\");
if(containsGta3Data(location)) {
return location;
}
}
#if defined(STEAMID)
location = winReadRegistry(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App " STR(STEAMID), "InstallLocation");
if (location.size()) {
location.push_back('\\');
if (containsGta3Data(location)) {
return location;
}
}
#endif
return "";
}
#endif
void
normalizePathCorrectPathJoiner(std::string &s)
{
#ifdef _WIN32
#define PATHJOIN_BAD '/'
#else
#define PATHJOIN_BAD '\\'
#endif
std::string::size_type pos(0);
while((pos = s.find(PATHJOIN_BAD, pos)) != std::string::npos) {
s[pos] = PATHJOIN;
}
}
void
ensureTrailingPathJoiner(std::string &s)
{
if(s.size() && *s.rbegin() != PATHJOIN) {
s.push_back(PATHJOIN);
}
}
#include <vector>
std::vector<std::string> searchPaths;
void
reloc_initialize()
{
// FIXME: is called twice
searchPaths.clear();
std::string path;
// 1. add search paths from command line
// FIXME
// 2. `GTA_III_RE_DIR` environment variable
const char *pEnv = ::getenv("GTA3DIR");
if (pEnv) {
std::string env = pEnv;
std::string::size_type start(0);
std::string::size_type end;
while ((end = env.find(PATHSEP, start)) != std::string::npos) {
searchPaths.push_back(env.substr(start, end - start));
start = end + 1;
}
searchPaths.push_back(env.substr(start));
}
// 3. add search paths from INI
// FIXME
// 4. add current working directory to search path
path.resize(MAX_PATH);
char *cwd = getcwd((char *)path.c_str(), path.size());
if (cwd) {
path.resize(strlen(path.c_str()));
searchPaths.push_back(path);
}
// 5. add exe path to search path
path = psExeDir();
if(path.size()) {
searchPaths.push_back(path);
}
#ifdef _WIN32
// 6. add default installation paths
path = winGetGtaDataFolder();
if(path.size()) {
searchPaths.push_back(path);
}
#endif
// 6. built-in path
#ifdef GTA_III_RE_DIR
searchPaths.push_back(GTA_III_RE_DIR);
#endif
// Normalize paths
for(std::string &path : searchPaths) {
normalizePathCorrectPathJoiner(path);
ensureTrailingPathJoiner(path);
}
debug("Full search path is:\n");
for (const std::string &s: searchPaths) {
debug("- %s\n", s.c_str());
}
}
std::string
searchPathsFindData(const char *path)
{
const char *cwd = CFileMgr::GetWorkingDir();
std::string suffix;
if (cwd && *cwd != '\0') {
suffix.append(cwd);
std::string::size_type pos = 0;
while(suffix[pos] == PATHJOIN) {
++pos;
}
suffix = suffix.substr(pos, suffix.size() - pos);
if (suffix[suffix.size() - 1] != PATHJOIN) {
suffix.push_back(PATHJOIN);
}
}
suffix.append(path);
normalizePathCorrectPathJoiner(suffix);
for (const auto &searchpath : searchPaths) {
std::string curPath = searchpath + suffix;
if (FileExists(curPath.c_str())) {
return curPath;
}
FILE *f = fopen(curPath.c_str(), "rb");
if(f) {
fclose(f);
debug("FileExists failed, but fopen succeeded. huh?\n");
}
}
TRACE("Could not find \"%s\" in search paths (cwd=\"%s\").\n", path, cwd);
std::string res;
if (cwd && *cwd != '\0') {
res.append(cwd);
res.push_back(PATHJOIN);
}
res.append(path);
normalizePathCorrectPathJoiner(res);
return res;
}
#include "FileMgr.h"
#include "common.h"
FILE *
reloc_fopen(const char *path, const char *mode)
{
std::string fullPath = searchPathsFindData(path);
TRACE("reloc_fopen(%s, %s) -> fopen(%s, %s)", path, mode, fullPath.c_str(), mode);
return fopen(fullPath.c_str(), mode);
}
const char*
reloc_realpath(const char *filename)
{
static std::string fullPath;
fullPath = searchPathsFindData(filename);
TRACE("reloc_realpath(%s) -> %s", filename, fullPath.c_str());
return fullPath.c_str();
}
struct reloc_HANDLE {
HANDLE hFind;
std::string fullPathName;
int searchPathIndex;
};
HANDLE
reloc_FindFirstFile(const char *pathName, WIN32_FIND_DATA *findFileData)
{
std::string suffix = CFileMgr::GetWorkingDir();
if (suffix.size()) {
std::string::size_type pos = 0;
while(suffix[pos] == PATHJOIN) { ++pos; }
suffix = suffix.substr(pos, suffix.size() - pos);
if (suffix[suffix.size() - 1] != PATHJOIN) {
suffix.push_back(PATHJOIN);
}
}
suffix.append(pathName);
for (int i = 0; i < (int)searchPaths.size(); ++i) {
HANDLE hFind = FindFirstFile((searchPaths[i] + suffix).c_str(), findFileData);
if (hFind != INVALID_HANDLE_VALUE) {
return (HANDLE) new reloc_HANDLE {hFind, suffix, i};
}
}
return INVALID_HANDLE_VALUE;
}
bool
reloc_FindNextFile(HANDLE hFind, WIN32_FIND_DATA *findFileData)
{
reloc_HANDLE *relocHandle = (reloc_HANDLE *) hFind;
if (FindNextFile(relocHandle->hFind, findFileData)) {
return true;
}
FindClose(relocHandle->hFind);
relocHandle->hFind = NULL;
for (int i = relocHandle->searchPathIndex + 1; i < (int)searchPaths.size(); ++i) {
HANDLE newHFind = FindFirstFile((searchPaths[i] + relocHandle->fullPathName).c_str(), findFileData);
if (newHFind != INVALID_HANDLE_VALUE) {
relocHandle->hFind = newHFind;
relocHandle->searchPathIndex = i;
return true;
}
}
return false;
}
bool
reloc_FindClose(HANDLE hFind)
{
reloc_HANDLE *relocHandle = (reloc_HANDLE *)hFind;
bool res = true;
if (relocHandle->hFind != NULL) {
res = FindClose(relocHandle->hFind);
}
delete relocHandle;
return res;
}
#ifndef _WIN32
static bool
casepath_subpath(const std::string &basePath, const char *path, std::string &result) {
const char *curLevelStart;
size_t curLevelSize;
bool currentIsFile;
if (path == NULL) {
return false;
}
// Fail early when the base path does not exist.
DIR *d = opendir(basePath.c_str());
if (d == NULL) {
return false;
}
// Split path in parts, ignoring empty levels (e.g. '/a//b' --> {'a', 'b'})
const char *nextCurLevelStart = path;
while (true) {
curLevelStart = nextCurLevelStart;
const char *delimPos = strpbrk(curLevelStart, "/\\");
if (delimPos == NULL) {
curLevelSize = strlen(curLevelStart);
currentIsFile = true;
break;
}
curLevelSize = delimPos - curLevelStart;
nextCurLevelStart = delimPos + 1;
currentIsFile = false;
if (curLevelSize > 0) {
break;
}
}
char *curLevel = (char*) alloca(curLevelSize + 1);
strncpy(curLevel, curLevelStart, curLevelSize);
curLevel[curLevelSize] = '\0';
struct dirent *e;
while ((e = readdir(d)) != NULL) {
if (strcasecmp(curLevel, e->d_name) == 0) {
if (currentIsFile) {
result = basePath + e->d_name;
closedir(d);
return true;
}
bool subres = casepath_subpath(basePath + e->d_name + PATHJOIN_S, nextCurLevelStart, result);
if (subres) {
return subres;
}
}
}
closedir(d);
return false;
}
char*
reloc_casepath(const char *path, bool checkPathFirst)
{
std::string realPath;
realPath.reserve(PATH_MAX);
if (checkPathFirst) {
for (const std::string &searchPath : searchPaths) {
realPath = searchPath + CFileMgr::GetWorkingDir() + path;
if (access(realPath.c_str(), F_OK) != -1) {
// File path is correct
debug("reloc_casepath(%s, %d) -> %s\n", path, checkPathFirst, realPath.c_str());
return strdup(realPath.c_str());
}
}
}
std::string suffixPath = std::string{CFileMgr::GetWorkingDir()} + path;
for (const std::string &searchPath : searchPaths) {
bool res = casepath_subpath(searchPath, suffixPath.c_str(), realPath);
if (res) {
debug("reloc_casepath(%s, %d) -> %s\n", path, checkPathFirst, realPath.c_str());
return strdup(realPath.c_str());
}
}
debug("reloc_casepath(%s, %d) failed (wd=%s)\n", path, checkPathFirst, CFileMgr::GetWorkingDir());
return NULL;
}
FILE *
reloc_fcaseopen(char const *filename, char const *mode)
{
FILE *result;
char *real = reloc_casepath(filename);
if (real == NULL) {
result = fopen(filename, mode);
} else {
result = fopen(real, mode);
free(real);
}
return result;
}
#endif
#endif

@ -0,0 +1,45 @@
#pragma once
#if defined _WIN32
#ifdef WITHWINDOWS
#include <windows.h>
#endif
#else
#include "crossplatform.h"
#endif
#ifdef RELOCATABLE
void reloc_initialize(void);
FILE *reloc_fopen(const char *path, const char *mode);
const char *reloc_realpath(const char *filename);
#ifdef _WIN32
#define reloc_casepath(PATH, CHECKFIRST) reloc_realpath(PATH)
#define reloc_fcaseopen reloc_fopen
#else
char *reloc_casepath(char const *path, bool checkPathFirst = true);
FILE *reloc_fcaseopen(char const *filename, char const *mode);
#endif
#if defined WITHWINDOWS
HANDLE reloc_FindFirstFile(const char *pathName, WIN32_FIND_DATA *findFileData);
bool reloc_FindNextFile(HANDLE hFind, WIN32_FIND_DATA *findFileData);
bool reloc_FindClose(HANDLE hFind);
#endif
#else
#define reloc_initialize()
#define reloc_fopen(path, mode) fopen(path, mode)
#define reloc_realpath(filename) (filename)
#define reloc_casepath casepath
#define reloc_fcaseopen fcaseopen
#define reloc_FindFirstFile FindFirstFile
#define reloc_FindNextFile FindNextFile
#define reloc_FindClose FindClose
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@ -42,6 +42,6 @@ END
// Icon with lowest ID value placed first to ensure application icon // Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems. // remains consistent on all systems.
IDI_MAIN_ICON ICON DISCARDABLE "gta3.ico" IDI_MAIN_ICON ICON DISCARDABLE "re3.ico"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

@ -97,7 +97,10 @@ cHandlingDataMgr::LoadHandlingData(void)
tHandlingData *handling; tHandlingData *handling;
CFileMgr::SetDir("DATA"); CFileMgr::SetDir("DATA");
CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r"); ssize_t nbBytesRead = CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r");
if(nbBytesRead < 0) {
USERERROR("Cannot open %s\n", HandlingFilename);
}
CFileMgr::SetDir(""); CFileMgr::SetDir("");
start = (char*)work_buff; start = (char*)work_buff;