Skip to content

Commit

Permalink
v2.2: fix winxp, support ifs-in-ifs
Browse files Browse the repository at this point in the history
  • Loading branch information
mon committed Jun 22, 2021
1 parent 2ae0fee commit 27af072
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 23 deletions.
11 changes: 5 additions & 6 deletions layeredfs/hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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"
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}

Expand Down
3 changes: 3 additions & 0 deletions layeredfs/layeredfs.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
<DebugInformationFormat>None</DebugInformationFormat>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand All @@ -146,6 +147,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DebugInformationFormat>None</DebugInformationFormat>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/Zc:threadSafeInit-</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand Down Expand Up @@ -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" />
Expand Down
5 changes: 3 additions & 2 deletions layeredfs/modpath_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <mutex>

#include "ramfs_demangler.h"

#include "modpath_handler.h"
#include "config.hpp"
#include "utils.h"
#include "avs.h"
#include "winxp_mutex.hpp"

using std::nullopt;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
43 changes: 33 additions & 10 deletions layeredfs/ramfs_demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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()) {
Expand All @@ -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()) {
Expand All @@ -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;
Expand All @@ -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());
}
}
23 changes: 18 additions & 5 deletions layeredfs/utils.cpp
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);
Expand All @@ -35,6 +35,8 @@ void logf(char* fmt, ...) {

if(config.developer_mode)
fflush(logfile);

log_mutex.unlock();
}
}

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions layeredfs/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
58 changes: 58 additions & 0 deletions layeredfs/winxp_mutex.hpp
Original file line number Diff line number Diff line change
@@ -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.
**/

0 comments on commit 27af072

Please sign in to comment.