v2.2: fix winxp, support ifs-in-ifs

This commit is contained in:
Will Toohey 2021-06-23 09:32:21 +10:00
parent 2ae0fee8be
commit 27af072b0d
7 changed files with 121 additions and 23 deletions

View File

@ -16,7 +16,6 @@ using std::string;
#include <algorithm>
#include <iostream>
#include <fstream>
#include <mutex>
#include "3rd_party/MinHook.h"
#pragma comment(lib, "minhook.lib")
@ -33,12 +32,13 @@ using std::string;
//#include "jubeat.h"
#include "texture_packer.h"
#include "modpath_handler.h"
#include "winxp_mutex.hpp"
// let me use the std:: version, damnit
#undef max
#undef min
#define VER_STRING "2.1"
#define VER_STRING "2.2"
#ifdef _DEBUG
#define DBG_VER_STRING "_DEBUG"
@ -77,7 +77,7 @@ typedef struct image {
// ifs_textures["data/graphics/ver04/logo.ifs/tex/4f754d4f424f092637a49a5527ece9bb"] will be "konami"
static std::unordered_map<string, image_t> ifs_textures;
static std::mutex ifs_textures_mtx;
static CriticalSectionLock ifs_textures_mtx;
typedef std::unordered_set<string> string_set;
@ -673,9 +673,8 @@ AVS_FILE hook_avs_fs_open(const char* name, uint16_t mode, int flags) {
auto norm_path = *_norm_path;
auto mod_path = find_first_modfile(norm_path);
if (!mod_path) {
// mod ifs paths use _ifs
string_replace(norm_path, ".ifs", "_ifs");
// mod ifs paths use _ifs, go one at a time for ifs-inside-ifs
while (!mod_path && string_replace_first(norm_path, ".ifs", "_ifs")) {
mod_path = find_first_modfile(norm_path);
}

View File

@ -126,6 +126,7 @@
<DebugInformationFormat>None</DebugInformationFormat>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -146,6 +147,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DebugInformationFormat>None</DebugInformationFormat>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/Zc:threadSafeInit-</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -181,6 +183,7 @@
<ClInclude Include="ramfs_demangler.h" />
<ClInclude Include="texture_packer.h" />
<ClInclude Include="utils.h" />
<ClInclude Include="winxp_mutex.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="3rd_party\GuillotineBinPack.cpp" />

View File

@ -2,7 +2,6 @@
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#include "ramfs_demangler.h"
@ -10,6 +9,7 @@
#include "config.hpp"
#include "utils.h"
#include "avs.h"
#include "winxp_mutex.hpp"
using std::nullopt;
@ -80,7 +80,7 @@ void cache_mods(void) {
// data, data2, data_op2 etc
// data is "flat", all others must have their own special subfolders
static vector<string> game_folders;
static std::mutex game_folders_mtx;
static CriticalSectionLock game_folders_mtx;
optional<string> normalise_path(string &path) {
// one-off init
@ -228,6 +228,7 @@ optional<string> find_first_cached_item(const string &norm_path) {
}
optional<string> find_first_modfile(const string &norm_path) {
//logf_verbose("%s(%s)", __FUNCTION__, norm_path.c_str());
if (config.developer_mode) {
for (auto &dir : available_mods()) {
auto mod_path = dir + "/" + norm_path;

View File

@ -32,13 +32,13 @@
#include <algorithm>
#include <unordered_map>
#include <mutex>
#include <optional>
#include "3rd_party/hat-trie/htrie_map.h"
#include "ramfs_demangler.h"
#include "utils.h"
#include "winxp_mutex.hpp"
using namespace std;
@ -56,14 +56,17 @@ static unordered_map<void*, string> ram_load_map;
static tsl::htrie_map<char, string> ramfs_map;
static tsl::htrie_map<char, string> mangling_map;
static std::mutex mangling_mtx;
static CriticalSectionLock mangling_mtx;
// since we call this from a function that is already taking the lock
static void ramfs_demangler_demangle_if_possible_nolock(std::string& raw_path);
void ramfs_demangler_on_fs_open(const std::string& norm_path, AVS_FILE open_result) {
if (open_result < 0 || !string_ends_with(norm_path.c_str(), ".ifs")) {
return;
}
const std::lock_guard<std::mutex> lock(mangling_mtx);
mangling_mtx.lock();
auto existing_info = cleanup_map.find(norm_path);
if (existing_info != cleanup_map.end()) {
@ -89,10 +92,12 @@ void ramfs_demangler_on_fs_open(const std::string& norm_path, AVS_FILE open_resu
};
cleanup_map[norm_path] = cleanup;
open_file_map[open_result] = norm_path;
mangling_mtx.unlock();
}
void ramfs_demangler_on_fs_read(AVS_FILE context, void* dest) {
const std::lock_guard<std::mutex> lock(mangling_mtx);
mangling_mtx.lock();
auto find = open_file_map.find(context);
if (find != open_file_map.end()) {
@ -106,26 +111,30 @@ void ramfs_demangler_on_fs_read(AVS_FILE context, void* dest) {
cleanup->second.buffer = dest;
}
}
mangling_mtx.unlock();
}
void ramfs_demangler_on_fs_mount(const char* mountpoint, const char* fsroot, const char* fstype, const char* flags) {
const std::lock_guard<std::mutex> lock(mangling_mtx);
mangling_mtx.lock();
if (!strcmp(fstype, "ramfs")) {
void* buffer;
if (!flags) {
logf_verbose("ramfs has no flags?");
mangling_mtx.unlock();
return;
}
const char* baseptr = strstr(flags, "base=");
if (!baseptr) {
logf_verbose("ramfs has no base pointer?");
mangling_mtx.unlock();
return;
}
buffer = (void*)strtoull(baseptr + strlen("base="), NULL, 0);
auto find = ram_load_map.find(buffer);
if (find != ram_load_map.end()) {
auto orig_path = find->second;
@ -152,18 +161,32 @@ void ramfs_demangler_on_fs_mount(const char* mountpoint, const char* fsroot, con
}
}
else if(string_ends_with(fsroot, ".ifs")) {
//logf_verbose("imagefs mount mapped to %s", fsroot);
mangling_map[mountpoint] = (string)fsroot;
// this fixes ifs-inside-ifs by demangling the root location too
string root = (string)fsroot;
ramfs_demangler_demangle_if_possible_nolock(root);
logf_verbose("imagefs mount mapped to %s", root.c_str());
mangling_map[mountpoint] = root;
}
}
mangling_mtx.unlock();
}
void ramfs_demangler_demangle_if_possible(std::string& raw_path) {
const std::lock_guard<std::mutex> lock(mangling_mtx);
mangling_mtx.lock();
auto search = mangling_map.longest_prefix(raw_path);
if (search != mangling_map.end()) {
//logf_verbose("can demangle %s to %s", search.key().c_str(), search->c_str());
string_replace(raw_path, search.key().c_str(), search->c_str());
}
}
mangling_mtx.unlock();
}
static void ramfs_demangler_demangle_if_possible_nolock(std::string& raw_path) {
auto search = mangling_map.longest_prefix(raw_path);
if (search != mangling_map.end()) {
string_replace(raw_path, search.key().c_str(), search->c_str());
}
}

View File

@ -1,12 +1,11 @@
#include "utils.h"
#include "avs.h"
#include <mutex>
#include "winxp_mutex.hpp"
#define SUPPRESS_PRINTF
void logf(char* fmt, ...) {
static std::mutex log_mutex;
static CriticalSectionLock log_mutex;
static FILE* logfile = NULL;
static bool tried_to_open = false;
va_list args;
@ -18,15 +17,16 @@ void logf(char* fmt, ...) {
#endif
// don't reopen every time: slow as shit
if (!tried_to_open) {
const std::lock_guard<std::mutex> lock(log_mutex);
log_mutex.lock();
if (!logfile) {
fopen_s(&logfile, "ifs_hook.log", "w");
}
tried_to_open = true;
log_mutex.unlock();
}
if (logfile) {
const std::lock_guard<std::mutex> lock(log_mutex);
log_mutex.lock();
va_start(args, fmt);
vfprintf(logfile, fmt, args);
@ -35,6 +35,8 @@ void logf(char* fmt, ...) {
if(config.developer_mode)
fflush(logfile);
log_mutex.unlock();
}
}
@ -81,6 +83,17 @@ void string_replace(std::string &str, const char* from, const char* to) {
}
}
bool string_replace_first(std::string& str, const char* from, const char* to) {
auto pos = str.find(from);
if (pos == std::string::npos) {
return false;
}
str.replace(pos, strlen(from), to);
return true;
}
wchar_t *str_widen(const char *src)
{
int nchars;

View File

@ -20,6 +20,7 @@ void logf(char* fmt, ...);
char* snprintf_auto(const char* fmt, ...);
int string_ends_with(const char * str, const char * suffix);
void string_replace(std::string &str, const char* from, const char* to);
bool string_replace_first(std::string &str, const char* from, const char* to);
wchar_t *str_widen(const char *src);
void str_tolower_inline(char* str);
void str_tolower_inline(std::string &str);

58
layeredfs/winxp_mutex.hpp Normal file
View File

@ -0,0 +1,58 @@
#pragma once
#include <Windows.h>
// This class is a lightweight replacement for std::mutex on Windows platforms.
// std::mutex does not work on Windows XP SP2 with the latest VC++ libraries,
// because it utilizes the Concurrency Runtime that is only supported on Windows
// XP SP3 and above.
// mon addition: avoid std::lock_guard. It uses thread local storage and is just, in general, pain to compile properly.
// This sucks, because RAII is awesome.
class CriticalSectionLock {
public:
CriticalSectionLock() { InitializeCriticalSection(&critical_section_); }
~CriticalSectionLock() { DeleteCriticalSection(&critical_section_); }
void lock() { EnterCriticalSection(&critical_section_); }
void unlock() { LeaveCriticalSection(&critical_section_); }
private:
CRITICAL_SECTION critical_section_;
};
/**
Copyright 2008 Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Code generated by the Protocol Buffer compiler is owned by the owner
of the input file used when generating it. This code is not
standalone and requires a support library to be linked with it. This
support library is itself covered by the above license.
**/