Merge latest master changes

This commit is contained in:
Rodolfo Bogado 2017-08-29 20:59:12 -03:00
parent 53753d0474
commit ba330d64fc
79 changed files with 1257 additions and 735 deletions

View file

@ -17,3 +17,11 @@ find_package_handle_standard_args(MINIUPNPC DEFAULT_MSG MINIUPNPC_INCLUDE_DIR MI
set(MINIUPNPC_LIBRARIES ${MINIUPNPC_LIBRARY})
set(MINIUPNPC_INCLUDE_DIRS ${MINIUPNPC_INCLUDE_DIR})
mark_as_advanced(MINIUPNPC_INCLUDE_DIR MINIUPNPC_LIBRARY MINIUPNPC_API_VERSION_STR)
if (MINIUPNPC_FOUND AND NOT TARGET miniupnpc)
add_library(Miniupnpc::miniupnpc UNKNOWN IMPORTED)
set_target_properties(Miniupnpc::miniupnpc PROPERTIES
IMPORTED_LOCATION ${MINIUPNPC_LIBRARIES}
INTERFACE_INCLUDE_DIRECTORIES ${MINIUPNPC_INCLUDE_DIRS}
)
endif()

View file

@ -673,12 +673,8 @@ if(USE_UPNP)
else()
message(STATUS "Using static miniupnpc from Externals")
add_subdirectory(Externals/miniupnpc)
set(MINIUPNPC_INCLUDE_DIRS Externals/miniupnpc/src)
set(MINIUPNPC_LIBRARIES miniupnpc)
endif()
add_definitions(-DUSE_UPNP)
include_directories(${MINIUPNPC_INCLUDE_DIRS})
list(APPEND LIBS ${MINIUPNPC_LIBRARIES})
endif()
if(NOT APPLE)

View file

@ -0,0 +1,14 @@
# HA8xxx - Super Mario Bros. 2 (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0
[Video_Hacks]
EFBToTextureEnable = False
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False

View file

@ -0,0 +1,14 @@
# HA8xxx - Super Mario Bros. (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0
[Video_Hacks]
EFBToTextureEnable = False
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False

View file

@ -0,0 +1,14 @@
# HBAxxx - The Legend of Zelda (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0
[Video_Hacks]
EFBToTextureEnable = False
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False

View file

@ -0,0 +1,14 @@
# HBBxxx - Kirby's Adventure (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0
[Video_Hacks]
EFBToTextureEnable = False
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False

View file

@ -0,0 +1,14 @@
# HBCxxx - Kid Icarus (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0
[Video_Hacks]
EFBToTextureEnable = False
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False

View file

@ -0,0 +1,14 @@
# HBDxxx - Ice Climber (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0
[Video_Hacks]
EFBToTextureEnable = False
[Video_Enhancements]
MaxAnisotropy = 0
ForceFiltering = False

View file

@ -0,0 +1,7 @@
# HBFxxx - Super Mario World (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0

View file

@ -0,0 +1,7 @@
# HBGxxx - F-Zero (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0

View file

@ -0,0 +1,9 @@
# HBIxxx - Super Metroid (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Settings]
SafeTextureCacheColorSamples = 0
UseXFB = True
UseRealXFB = False

View file

@ -0,0 +1,8 @@
# HBKxxx - The Legend of Zelda: Ocarina of Time (Brawl VC)
[Core]
# Values set here will override the main Dolphin settings.
[Video_Hacks]
# Fixes Link preview not appearing in Equipment Menu screen
EFBToTextureEnable = False

View file

@ -18,8 +18,6 @@ if(APPLE)
add_definitions(-DMACOSX -D_DARWIN_C_SOURCE)
endif()
include_directories(include)
set(SRCS src/igd_desc_parse.c
src/miniupnpc.c
src/minixml.c
@ -35,4 +33,6 @@ set(SRCS src/igd_desc_parse.c
src/receivedata.c)
add_library(miniupnpc STATIC ${SRCS})
target_include_directories(miniupnpc PUBLIC src)
add_library(Miniupnpc::miniupnpc ALIAS miniupnpc)

View file

@ -249,7 +249,7 @@
#define wxUSE_INTL 1
#define wxUSE_XLOCALE 1
#define wxUSE_XLOCALE 0
#define wxUSE_DATETIME 1

View file

@ -239,7 +239,7 @@
#define wxUSE_INTL 1
#define wxUSE_XLOCALE 1
#define wxUSE_XLOCALE 0
#define wxUSE_DATETIME 1

View file

@ -246,13 +246,6 @@ public final class NativeLibrary
*/
public static native void SetConfig(String configFile, String Section, String Key, String Value);
/**
* Sets the filename to be run during emulation.
*
* @param filename The filename to be run during emulation.
*/
public static native void SetFilename(String filename);
/**
* Gets the embedded banner within the given ISO/ROM.
*
@ -328,7 +321,7 @@ public final class NativeLibrary
/**
* Begins emulation.
*/
public static native void Run();
public static native void Run(String path);
// Surface Handling
public static native void SurfaceChanged(Surface surf);

View file

@ -66,9 +66,6 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
String path = getArguments().getString(ARGUMENT_GAME_PATH);
NativeLibrary.SetFilename(path);
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
SurfaceView surfaceView = (SurfaceView) contents.findViewById(R.id.surface_emulation);
@ -241,7 +238,8 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
Log.info("[EmulationFragment] Starting emulation: " + mSurface);
// Start emulation using the provided Surface.
NativeLibrary.Run();
String path = getArguments().getString(ARGUMENT_GAME_PATH);
NativeLibrary.Run(path);
}
};

View file

@ -274,10 +274,13 @@ public final class SettingsFile
current = sectionFromLine(line);
sections.put(current.getName(), current);
}
else if ((current != null) && line.contains("="))
else if ((current != null))
{
Setting setting = settingFromLine(current, line, fileName);
current.putSetting(setting);
if (setting != null)
{
current.putSetting(setting);
}
}
}
}
@ -381,6 +384,12 @@ public final class SettingsFile
{
String[] splitLine = line.split("=");
if (splitLine.length != 2)
{
Log.warning("Skipping invalid config line \"" + line + "\"");
return null;
}
String key = splitLine[0].trim();
String value = splitLine[1].trim();

View file

@ -1,19 +1,11 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="diameter">48dp</dimen>
<dimen name="elevation_low">1dp</dimen>
<dimen name="elevation_high">4dp</dimen>
<dimen name="add_button_margin">16dp</dimen>
<dimen name="main_appbar_height">128dp</dimen>
<dimen name="spacing_xsmall">2dp</dimen>
<dimen name="spacing_small">4dp</dimen>
<dimen name="spacing_medium">8dp</dimen>
<dimen name="spacing_medlarge">12dp</dimen>
<dimen name="spacing_large">16dp</dimen>
<dimen name="spacing_xlarge">32dp</dimen>
</resources>

View file

@ -52,23 +52,8 @@
</style>
<!-- Themes for Dialogs -->
<style name="DolphinDialogBase" parent="Theme.AppCompat.Light.Dialog">
<item name="colorPrimary">@color/dolphin_blue</item>
<item name="colorPrimaryDark">@color/dolphin_blue_dark</item>
</style>
<!-- Inherit from the Base Dolphin Dialog Theme -->
<style name="DolphinDialogWii" parent="DolphinDialogBase">
<item name="colorAccent">@color/dolphin_accent_wii</item>
</style>
<style name="DolphinDialogGamecube" parent="DolphinDialogBase">
<item name="colorAccent">@color/dolphin_accent_gamecube</item>
</style>
<style name="DolphinDialogWiiware" parent="DolphinDialogBase">
<item name="colorAccent">@color/dolphin_accent_wiiware</item>
</style>
<style name="DolphinEmulationBase" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/dolphin_blue</item>

View file

@ -53,7 +53,6 @@ JavaVM* g_java_vm;
namespace
{
ANativeWindow* s_surf;
std::string s_filename;
std::string s_set_userpath;
jclass s_jni_class;
@ -466,7 +465,8 @@ JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv* env, jobject obj);
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_CacheClassesAndMethods(JNIEnv* env, jobject obj);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv* env, jobject obj);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv* env, jobject obj,
jstring jFile);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv* env,
jobject obj,
jobject surf);
@ -633,13 +633,6 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetConfig(
ini.Save(File::GetUserPath(D_CONFIG_IDX) + std::string(file));
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename(JNIEnv* env,
jobject obj,
jstring jFile)
{
s_filename = GetJString(env, jFile);
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv* env,
jobject obj,
jint slot)
@ -773,9 +766,11 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimo
WiimoteReal::Refresh();
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv* env, jobject obj)
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv* env, jobject obj,
jstring jFile)
{
__android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", s_filename.c_str());
const std::string path = GetJString(env, jFile);
__android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", path.c_str());
// Install our callbacks
OSD::AddCallback(OSD::CallbackType::Initialization, ButtonManager::Init);
@ -791,7 +786,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv*
// No use running the loop when booting fails
s_have_wm_user_stop = false;
if (BootManager::BootCore(BootParameters::GenerateFromFile(s_filename)))
if (BootManager::BootCore(BootParameters::GenerateFromFile(path)))
{
static constexpr int TIMEOUT = 10000;
static constexpr int WAIT_STEP = 25;

View file

@ -19,14 +19,19 @@
#include "Common/CommonTypes.h"
#include "Common/File.h"
#include "Common/NonCopyable.h"
class WaveFileWriter : NonCopyable
class WaveFileWriter
{
public:
WaveFileWriter();
~WaveFileWriter();
WaveFileWriter(const WaveFileWriter&) = delete;
WaveFileWriter& operator=(const WaveFileWriter&) = delete;
WaveFileWriter(WaveFileWriter&&) = delete;
WaveFileWriter& operator=(WaveFileWriter&&) = delete;
bool Start(const std::string& filename, unsigned int HLESampleRate);
void Stop();

View file

@ -4057,7 +4057,7 @@ void ARM64XEmitter::ANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch)
else
{
_assert_msg_(DYNA_REC, scratch != INVALID_REG,
"ANDSI2R - failed to construct logical immediate value from %08x, need scratch",
"ANDI2R - failed to construct logical immediate value from %08x, need scratch",
(u32)imm);
MOVI2R(scratch, imm);
AND(Rd, Rn, scratch);

View file

@ -120,6 +120,10 @@ endif()
add_dolphin_library(common "${SRCS}" "${LIBS}")
if(USE_UPNP)
target_link_libraries(common PRIVATE Miniupnpc::miniupnpc)
endif()
if(OPROFILE_FOUND)
target_link_libraries(common PRIVATE ${OPROFILE_LIBRARIES})
endif()

View file

@ -10,7 +10,6 @@
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/MemoryUtil.h"
#include "Common/NonCopyable.h"
// Everything that needs to generate code should inherit from this.
// You get memory management for free, plus, you can use all emitter functions without
@ -18,7 +17,7 @@
// Example implementation:
// class JIT : public CodeBlock<ARMXEmitter> {}
template <class T>
class CodeBlock : public T, NonCopyable
class CodeBlock : public T
{
private:
// A privately used function to set the executable RAM space to something invalid.
@ -37,11 +36,16 @@ protected:
std::vector<CodeBlock*> m_children;
public:
CodeBlock() = default;
virtual ~CodeBlock()
{
if (region)
FreeCodeSpace();
}
CodeBlock(const CodeBlock&) = delete;
CodeBlock& operator=(const CodeBlock&) = delete;
CodeBlock(CodeBlock&&) = delete;
CodeBlock& operator=(CodeBlock&&) = delete;
// Call this before you generate any code.
void AllocCodeSpace(size_t size)

View file

@ -138,7 +138,6 @@
<ClInclude Include="MsgHandler.h" />
<ClInclude Include="NandPaths.h" />
<ClInclude Include="Network.h" />
<ClInclude Include="NonCopyable.h" />
<ClInclude Include="PcapFile.h" />
<ClInclude Include="Profiler.h" />
<ClInclude Include="ScopeGuard.h" />

View file

@ -237,7 +237,6 @@
<Filter>GL\GLInterface</Filter>
</ClInclude>
<ClInclude Include="Assert.h" />
<ClInclude Include="NonCopyable.h" />
<ClInclude Include="Analytics.h" />
<ClInclude Include="Semaphore.h" />
<ClInclude Include="ConstantBuffer.h" />

View file

@ -22,27 +22,35 @@
#ifdef _WIN32
#include <windows.h>
#define strerror_r(err, buf, len) strerror_s(buf, len, err)
#endif
// Generic function to get last error message.
// Call directly after the command or use the error num.
// This function might change the error code.
std::string GetLastErrorMsg()
{
const size_t buff_size = 256;
char err_str[buff_size];
constexpr size_t BUFFER_SIZE = 256;
// Wrapper function to get last strerror(errno) string.
// This function might change the error code.
std::string LastStrerrorString()
{
char error_message[BUFFER_SIZE];
#ifdef _WIN32
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
#else
// We assume that the XSI-compliant version of strerror_r (returns int) is used
// rather than the GNU version (returns char*). The returned value is stored to
// an int variable to get a compile-time check that the return type is not char*.
const int result = strerror_r(errno, err_str, buff_size);
const int result = strerror_r(errno, error_message, BUFFER_SIZE);
if (result != 0)
return "";
#endif
return std::string(err_str);
return std::string(error_message);
}
#ifdef _WIN32
// Wrapper function to get GetLastError() string.
// This function might change the error code.
std::string GetLastErrorString()
{
char error_message[BUFFER_SIZE];
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, BUFFER_SIZE, nullptr);
return std::string(error_message);
}
#endif

View file

@ -86,7 +86,12 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
}
#endif // WIN32 ndef
// Generic function to get last error message.
// Call directly after the command or use the error num.
// Wrapper function to get last strerror(errno) string.
// This function might change the error code.
std::string GetLastErrorMsg();
std::string LastStrerrorString();
#ifdef _WIN32
// Wrapper function to get GetLastError() string.
// This function might change the error code.
std::string GetLastErrorString();
#endif

View file

@ -18,12 +18,12 @@
#define LONG int
#endif
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
using s8 = std::int8_t;
using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;

View file

@ -9,14 +9,13 @@
#include <string>
#include "Common/CommonTypes.h"
#include "Common/NonCopyable.h"
namespace File
{
// simple wrapper for cstdlib file functions to
// hopefully will make error checking easier
// and make forgetting an fclose() harder
class IOFile : public NonCopyable
class IOFile
{
public:
IOFile();
@ -25,6 +24,9 @@ public:
~IOFile();
IOFile(const IOFile&) = delete;
IOFile& operator=(const IOFile&) = delete;
IOFile(IOFile&& other) noexcept;
IOFile& operator=(IOFile&& other) noexcept;

View file

@ -7,6 +7,7 @@
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <fstream>
#include <limits.h>
#include <string>
#include <sys/stat.h>
@ -141,14 +142,14 @@ bool Delete(const std::string& filename)
if (!DeleteFile(UTF8ToTStr(filename).c_str()))
{
WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(),
GetLastErrorMsg().c_str());
GetLastErrorString().c_str());
return false;
}
#else
if (unlink(filename.c_str()) == -1)
{
WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", filename.c_str(),
GetLastErrorMsg().c_str());
LastStrerrorString().c_str());
return false;
}
#endif
@ -241,11 +242,14 @@ bool DeleteDir(const std::string& filename)
#ifdef _WIN32
if (::RemoveDirectory(UTF8ToTStr(filename).c_str()))
return true;
ERROR_LOG(COMMON, "DeleteDir: RemoveDirectory failed on %s: %s", filename.c_str(),
GetLastErrorString().c_str());
#else
if (rmdir(filename.c_str()) == 0)
return true;
ERROR_LOG(COMMON, "DeleteDir: rmdir failed on %s: %s", filename.c_str(),
LastStrerrorString().c_str());
#endif
ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg().c_str());
return false;
}
@ -268,12 +272,14 @@ bool Rename(const std::string& srcFilename, const std::string& destFilename)
if (MoveFile(sf.c_str(), df.c_str()))
return true;
}
ERROR_LOG(COMMON, "Rename: MoveFile failed on %s --> %s: %s", srcFilename.c_str(),
destFilename.c_str(), GetLastErrorString().c_str());
#else
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
return true;
ERROR_LOG(COMMON, "Rename: rename failed on %s --> %s: %s", srcFilename.c_str(),
destFilename.c_str(), LastStrerrorString().c_str());
#endif
ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
GetLastErrorMsg().c_str());
return false;
}
@ -312,66 +318,22 @@ bool RenameSync(const std::string& srcFilename, const std::string& destFilename)
return true;
}
// copies file srcFilename to destFilename, returns true on success
bool Copy(const std::string& srcFilename, const std::string& destFilename)
// copies file source_path to destination_path, returns true on success
bool Copy(const std::string& source_path, const std::string& destination_path)
{
INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str());
INFO_LOG(COMMON, "Copy: %s --> %s", source_path.c_str(), destination_path.c_str());
#ifdef _WIN32
if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE))
if (CopyFile(UTF8ToTStr(source_path).c_str(), UTF8ToTStr(destination_path).c_str(), FALSE))
return true;
ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
GetLastErrorMsg().c_str());
ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", source_path.c_str(), destination_path.c_str(),
GetLastErrorString().c_str());
return false;
#else
// buffer size
#define BSIZE 1024
char buffer[BSIZE];
// Open input file
std::ifstream input;
OpenFStream(input, srcFilename, std::ifstream::in | std::ifstream::binary);
if (!input.is_open())
{
ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
GetLastErrorMsg().c_str());
return false;
}
// open output file
File::IOFile output(destFilename, "wb");
if (!output.IsOpen())
{
ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", srcFilename.c_str(),
destFilename.c_str(), GetLastErrorMsg().c_str());
return false;
}
// copy loop
while (!input.eof())
{
// read input
input.read(buffer, BSIZE);
if (!input)
{
ERROR_LOG(COMMON, "Copy: failed reading from source, %s --> %s: %s", srcFilename.c_str(),
destFilename.c_str(), GetLastErrorMsg().c_str());
return false;
}
// write output
if (!output.WriteBytes(buffer, BSIZE))
{
ERROR_LOG(COMMON, "Copy: failed writing to output, %s --> %s: %s", srcFilename.c_str(),
destFilename.c_str(), GetLastErrorMsg().c_str());
return false;
}
}
return true;
std::ifstream source{ source_path, std::ios::binary };
std::ofstream destination{ destination_path, std::ios::binary };
destination << source.rdbuf();
return source.good() && destination.good();
#endif
}
@ -394,14 +356,14 @@ u64 GetSize(FILE* f)
u64 pos = ftello(f);
if (fseeko(f, 0, SEEK_END) != 0)
{
ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", f, GetLastErrorMsg().c_str());
ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", f, LastStrerrorString().c_str());
return 0;
}
u64 size = ftello(f);
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0))
{
ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", f, GetLastErrorMsg().c_str());
ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", f, LastStrerrorString().c_str());
return 0;
}
@ -416,7 +378,7 @@ bool CreateEmptyFile(const std::string& filename)
if (!File::IOFile(filename, "wb"))
{
ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", filename.c_str(),
GetLastErrorMsg().c_str());
LastStrerrorString().c_str());
return false;
}
@ -559,7 +521,7 @@ bool DeleteDirRecursively(const std::string& directory)
}
// Create directory and copy contents (does not overwrite existing files)
void CopyDir(const std::string& source_path, const std::string& dest_path)
void CopyDir(const std::string& source_path, const std::string& dest_path, bool destructive)
{
if (source_path == dest_path)
return;
@ -600,15 +562,21 @@ void CopyDir(const std::string& source_path, const std::string& dest_path)
{
if (!Exists(dest))
File::CreateFullPath(dest + DIR_SEP);
CopyDir(source, dest);
CopyDir(source, dest, destructive);
}
else if (!destructive && !Exists(dest))
{
Copy(source, dest);
}
else if (destructive)
{
Rename(source, dest);
}
else if (!Exists(dest))
File::Copy(source, dest);
#ifdef _WIN32
} while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
#else
}
}
closedir(dirp);
#endif
}
@ -620,7 +588,7 @@ std::string GetCurrentDir()
char* dir = __getcwd(nullptr, 0);
if (!dir)
{
ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", GetLastErrorMsg().c_str());
ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", LastStrerrorString().c_str());
return nullptr;
}
std::string strDir = dir;

View file

@ -12,7 +12,6 @@
#include <sys/stat.h>
#include "Common/CommonTypes.h"
#include "Common/NonCopyable.h"
#ifdef _WIN32
#include "Common/StringUtil.h"
@ -160,8 +159,9 @@ bool DeleteDirRecursively(const std::string& directory);
// Returns the current directory
std::string GetCurrentDir();
// Create directory and copy contents (does not overwrite existing files)
void CopyDir(const std::string& source_path, const std::string& dest_path);
// Create directory and copy contents (optionally overwrites existing files)
void CopyDir(const std::string& source_path, const std::string& dest_path,
bool destructive = false);
// Set the current directory to given directory
bool SetCurrentDir(const std::string& directory);

View file

@ -9,7 +9,6 @@
#include "Common/BitSet.h"
#include "Common/Logging/Log.h"
#include "Common/NonCopyable.h"
// pure virtual interface
class LogListener
@ -28,7 +27,7 @@ public:
};
};
class LogManager : NonCopyable
class LogManager
{
public:
static LogManager* GetInstance();
@ -36,9 +35,9 @@ public:
static void Shutdown();
void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
const char* fmt, va_list args);
const char* fmt, va_list args);
void LogWithFullPath(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file,
int line, const char* fmt, va_list args);
int line, const char* fmt, va_list args);
LogTypes::LOG_LEVELS GetLogLevel() const;
void SetLogLevel(LogTypes::LOG_LEVELS level);
@ -66,6 +65,11 @@ private:
LogManager();
~LogManager();
LogManager(const LogManager&) = delete;
LogManager& operator=(const LogManager&) = delete;
LogManager(LogManager&&) = delete;
LogManager& operator=(LogManager&&) = delete;
LogTypes::LOG_LEVELS m_level;
std::array<LogContainer, LogTypes::NUMBER_OF_LOGS> m_log{};
std::array<LogListener*, LogListener::NUMBER_OF_LISTENERS> m_listeners{};

View file

@ -136,7 +136,7 @@ u8* MemArena::FindMemoryBase()
u8* base = static_cast<u8*>(VirtualAlloc(nullptr, memory_size, MEM_RESERVE, PAGE_READWRITE));
if (!base)
{
PanicAlert("Failed to map enough memory space: %s", GetLastErrorMsg().c_str());
PanicAlert("Failed to map enough memory space: %s", GetLastErrorString().c_str());
return nullptr;
}
VirtualFree(base, 0, MEM_RELEASE);
@ -153,7 +153,7 @@ u8* MemArena::FindMemoryBase()
void* base = mmap(nullptr, memory_size, PROT_NONE, flags, -1, 0);
if (base == MAP_FAILED)
{
PanicAlert("Failed to map enough memory space: %s", GetLastErrorMsg().c_str());
PanicAlert("Failed to map enough memory space: %s", LastStrerrorString().c_str());
return nullptr;
}
munmap(base, memory_size);

View file

@ -14,7 +14,6 @@
#ifdef _WIN32
#include <windows.h>
#include <psapi.h>
#include "Common/StringUtil.h"
#else
#include <stdio.h>
@ -89,20 +88,13 @@ void FreeMemoryPages(void* ptr, size_t size)
{
if (ptr)
{
bool error_occurred = false;
#ifdef _WIN32
if (!VirtualFree(ptr, 0, MEM_RELEASE))
error_occurred = true;
PanicAlert("FreeMemoryPages failed!\nVirtualFree: %s", GetLastErrorString().c_str());
#else
int retval = munmap(ptr, size);
if (retval != 0)
error_occurred = true;
if (munmap(ptr, size) != 0)
PanicAlert("FreeMemoryPages failed!\nmunmap: %s", LastStrerrorString().c_str());
#endif
if (error_occurred)
PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str());
}
}
@ -120,84 +112,40 @@ void FreeAlignedMemory(void* ptr)
void ReadProtectMemory(void* ptr, size_t size)
{
bool error_occurred = false;
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, PAGE_NOACCESS, &oldValue))
error_occurred = true;
PanicAlert("ReadProtectMemory failed!\nVirtualProtect: %s", GetLastErrorString().c_str());
#else
int retval = mprotect(ptr, size, PROT_NONE);
if (retval != 0)
error_occurred = true;
if (mprotect(ptr, size, PROT_NONE) != 0)
PanicAlert("ReadProtectMemory failed!\nmprotect: %s", LastStrerrorString().c_str());
#endif
if (error_occurred)
PanicAlert("ReadProtectMemory failed!\n%s", GetLastErrorMsg().c_str());
}
void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
{
bool error_occurred = false;
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
error_occurred = true;
PanicAlert("WriteProtectMemory failed!\nVirtualProtect: %s", GetLastErrorString().c_str());
#else
int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
if (retval != 0)
error_occurred = true;
if (mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ) != 0)
PanicAlert("WriteProtectMemory failed!\nmprotect: %s", LastStrerrorString().c_str());
#endif
if (error_occurred)
PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str());
}
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
{
bool error_occurred = false;
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
error_occurred = true;
PanicAlert("UnWriteProtectMemory failed!\nVirtualProtect: %s", GetLastErrorString().c_str());
#else
int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) :
PROT_WRITE | PROT_READ);
if (retval != 0)
error_occurred = true;
#endif
if (error_occurred)
PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str());
}
std::string MemUsage()
{
#ifdef _WIN32
#pragma comment(lib, "psapi")
DWORD processID = GetCurrentProcessId();
HANDLE hProcess;
PROCESS_MEMORY_COUNTERS pmc;
std::string Ret;
// Print information about the memory usage of the process.
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
if (nullptr == hProcess)
return "MemUsage Error";
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
CloseHandle(hProcess);
return Ret;
#else
return "";
if (mprotect(ptr, size,
allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ) != 0)
{
PanicAlert("UnWriteProtectMemory failed!\nmprotect: %s", LastStrerrorString().c_str());
}
#endif
}

View file

@ -1,19 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
// An inheritable class to disallow the copy constructor and operator= functions
class NonCopyable
{
protected:
constexpr NonCopyable() = default;
~NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
NonCopyable(NonCopyable&&) = default;
NonCopyable& operator=(NonCopyable&&) = default;
};

View file

@ -18,9 +18,8 @@
#include "Common/CommonTypes.h"
#include "Common/File.h"
#include "Common/NonCopyable.h"
class PCAP final : public NonCopyable
class PCAP final
{
public:
// Takes ownership of the file object. Assumes the file object is already

View file

@ -291,7 +291,7 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const std::string& filename)
FailWrite:
ERROR_LOG(COMMON, "Could not write to '%s', aborting...", filename.c_str());
if (unlink(filename.c_str()) < 0)
ERROR_LOG(COMMON, "unlink(%s) failed: %s", filename.c_str(), GetLastErrorMsg().c_str());
ERROR_LOG(COMMON, "unlink(%s) failed: %s", filename.c_str(), LastStrerrorString().c_str());
return false;
}

View file

@ -12,7 +12,6 @@
#include <vector>
#include "Common/IniFile.h"
#include "Common/NonCopyable.h"
#include "Core/HW/EXI/EXI_Device.h"
#include "Core/HW/SI/SI_Device.h"
#include "Core/TitleDatabase.h"
@ -52,7 +51,7 @@ enum GPUDeterminismMode
struct BootParameters;
struct SConfig : NonCopyable
struct SConfig
{
// Wii Devices
bool m_WiiSDCard;
@ -320,6 +319,11 @@ struct SConfig : NonCopyable
bool m_SSLDumpRootCA;
bool m_SSLDumpPeerCert;
SConfig(const SConfig&) = delete;
SConfig& operator=(const SConfig&) = delete;
SConfig(SConfig&&) = delete;
SConfig& operator=(SConfig&&) = delete;
// Save settings
void SaveSettings();

View file

@ -8,7 +8,6 @@
#include <string>
#include "Common/CommonTypes.h"
#include "Common/NonCopyable.h"
class PCAP;
@ -51,7 +50,7 @@ public:
// A capture logger implementation that logs to PCAP files in a custom
// packet-based format.
class PCAPDSPCaptureLogger final : public DSPCaptureLogger, NonCopyable
class PCAPDSPCaptureLogger final : public DSPCaptureLogger
{
public:
// Automatically creates a writeable file (truncate existing file).

View file

@ -9,7 +9,6 @@
#include "Common/CommonTypes.h"
#include "Common/NandPaths.h"
#include "Common/NonCopyable.h"
#include "Common/Swap.h"
#include "Common/Timer.h"
@ -295,7 +294,7 @@ public:
std::string m_filename;
};
class GCMemcard : NonCopyable
class GCMemcard
{
private:
bool m_valid;
@ -317,6 +316,12 @@ private:
public:
explicit GCMemcard(const std::string& fileName, bool forceCreation = false,
bool shift_jis = false);
GCMemcard(const GCMemcard&) = delete;
GCMemcard& operator=(const GCMemcard&) = delete;
GCMemcard(GCMemcard&&) = default;
GCMemcard& operator=(GCMemcard&&) = default;
bool IsValid() const { return m_valid; }
bool IsShiftJIS() const;
bool Save();

View file

@ -10,19 +10,24 @@
#include <vector>
#include "Common/Event.h"
#include "Common/NonCopyable.h"
#include "Core/HW/GCMemcard/GCMemcard.h"
// Uncomment this to write the system data of the memorycard from directory to disc
//#define _WRITE_MC_HEADER 1
void MigrateFromMemcardFile(const std::string& directory_name, int card_index);
class GCMemcardDirectory : public MemoryCardBase, NonCopyable
class GCMemcardDirectory : public MemoryCardBase
{
public:
GCMemcardDirectory(const std::string& directory, int slot, u16 size_mbits, bool shift_jis,
int game_id);
~GCMemcardDirectory();
GCMemcardDirectory(const GCMemcardDirectory&) = delete;
GCMemcardDirectory& operator=(const GCMemcardDirectory&) = delete;
GCMemcardDirectory(GCMemcardDirectory&&) = default;
GCMemcardDirectory& operator=(GCMemcardDirectory&&) = default;
void FlushToFile();
void FlushThread();
s32 Read(u32 src_address, s32 length, u8* dest_address) override;

View file

@ -8,7 +8,6 @@
#include <memory>
#include "Common/CommonTypes.h"
#include "Common/NonCopyable.h"
// All the templated and very repetitive MMIO-related code is isolated in this
// file for easier reading. It mostly contains code related to handling methods
@ -119,7 +118,7 @@ public:
// inlinable, we need to provide some of the implementation of these two
// classes here and can't just use a forward declaration.
template <typename T>
class ReadHandler : public NonCopyable
class ReadHandler
{
public:
ReadHandler();
@ -155,7 +154,7 @@ private:
std::function<T(u32)> m_ReadFunc;
};
template <typename T>
class WriteHandler : public NonCopyable
class WriteHandler
{
public:
WriteHandler();

View file

@ -25,6 +25,7 @@
#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/ScopeGuard.h"
#include "Common/Thread.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
#include "Core/HW/WiimoteReal/IOWin.h"
@ -184,7 +185,7 @@ inline void init_lib()
namespace WiimoteReal
{
int IOWrite(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write, enum WinWriteMethod& stack,
const u8* buf, size_t len, DWORD* written);
const u8* buf, size_t len, DWORD* written);
int IORead(HANDLE& dev_handle, OVERLAPPED& hid_overlap_read, u8* buf, int index);
template <typename T>
@ -201,12 +202,12 @@ WiimoteScannerWindows::WiimoteScannerWindows()
WiimoteScannerWindows::~WiimoteScannerWindows()
{
// TODO: what do we want here?
// TODO: what do we want here?
#if 0
ProcessWiimotes(false, [](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
RemoveWiimote(btdi);
});
ProcessWiimotes(false, [](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
RemoveWiimote(btdi);
});
#endif
}
@ -231,7 +232,7 @@ void WiimoteScannerWindows::Update()
// including that device for further processing
// See https://msdn.microsoft.com/en-us/library/windows/hardware/ff549417(v=vs.85).aspx
static bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* parent_device_info,
PSP_DEVINFO_DATA parent_device_data)
PSP_DEVINFO_DATA parent_device_data)
{
ULONG status;
ULONG problem_number;
@ -258,7 +259,7 @@ static bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* pare
// Get the device id of the parent, required to open the device info
result =
CM_Get_Device_ID(parent_device, parent_device_id.data(), (ULONG)parent_device_id.size(), 0);
CM_Get_Device_ID(parent_device, parent_device_id.data(), (ULONG)parent_device_id.size(), 0);
if (result != CR_SUCCESS)
{
return false;
@ -269,7 +270,7 @@ static bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* pare
// Open the device info data of the parent and put it in the emtpy info set
if (!SetupDiOpenDeviceInfo((*parent_device_info), parent_device_id.data(), nullptr, 0,
parent_device_data))
parent_device_data))
{
SetupDiDestroyDeviceInfoList(parent_device_info);
return false;
@ -279,19 +280,19 @@ static bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* pare
}
std::wstring GetDeviceProperty(const HDEVINFO& device_info, const PSP_DEVINFO_DATA device_data,
const DEVPROPKEY* requested_property)
const DEVPROPKEY* requested_property)
{
DWORD required_size = 0;
DEVPROPTYPE device_property_type;
SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
nullptr, 0, &required_size, 0);
nullptr, 0, &required_size, 0);
std::vector<BYTE> unicode_buffer(required_size, 0);
BOOL result =
SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
unicode_buffer.data(), required_size, nullptr, 0);
SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
unicode_buffer.data(), required_size, nullptr, 0);
if (!result)
{
return std::wstring();
@ -316,7 +317,7 @@ static bool CheckForToshibaStack(const DEVINST& hid_interface_device_instance)
if (GetParentDevice(hid_interface_device_instance, &parent_device_info, &parent_device_data))
{
std::wstring class_driver_provider =
GetDeviceProperty(parent_device_info, &parent_device_data, &DEVPKEY_Device_DriverProvider);
GetDeviceProperty(parent_device_info, &parent_device_data, &DEVPKEY_Device_DriverProvider);
SetupDiDestroyDeviceInfoList(parent_device_info);
@ -333,7 +334,7 @@ static WinWriteMethod GetInitialWriteMethod(bool IsUsingToshibaStack)
// Currently Toshiba Bluetooth Stack needs the Output buffer to be the size of the largest output
// report
return (IsUsingToshibaStack ? WWM_WRITE_FILE_LARGEST_REPORT_SIZE :
WWM_WRITE_FILE_ACTUAL_REPORT_SIZE);
WWM_WRITE_FILE_ACTUAL_REPORT_SIZE);
}
static int WriteToHandle(HANDLE& dev_handle, WinWriteMethod& method, const u8* buf, size_t size)
@ -361,13 +362,15 @@ static int ReadFromHandle(HANDLE& dev_handle, u8* buf)
static bool IsWiimote(const std::basic_string<TCHAR>& device_path, WinWriteMethod& method)
{
HANDLE dev_handle = CreateFile(device_path.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, nullptr);
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, nullptr);
if (dev_handle == INVALID_HANDLE_VALUE)
return false;
Common::ScopeGuard handle_guard{ [&dev_handle] { CloseHandle(dev_handle); } };
u8 buf[MAX_PAYLOAD];
u8 const req_status_report[] = {WR_SET_REPORT | BT_OUTPUT, RT_REQUEST_STATUS, 0};
u8 const req_status_report[] = { WR_SET_REPORT | BT_OUTPUT, RT_REQUEST_STATUS, 0 };
int invalid_report_count = 0;
int rc = WriteToHandle(dev_handle, method, req_status_report, sizeof(req_status_report));
while (rc > 0)
@ -396,13 +399,13 @@ static bool IsWiimote(const std::basic_string<TCHAR>& device_path, WinWriteMetho
// wm is an array of max_wiimotes Wiimotes
// Returns the total number of found and connected Wiimotes.
void WiimoteScannerWindows::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
Wiimote*& found_board)
Wiimote*& found_board)
{
if (!s_loaded_ok)
return;
ProcessWiimotes(true, [](HANDLE hRadio, const BLUETOOTH_RADIO_INFO& rinfo,
BLUETOOTH_DEVICE_INFO_STRUCT& btdi) {
BLUETOOTH_DEVICE_INFO_STRUCT& btdi) {
ForgetWiimote(btdi);
AttachWiimote(hRadio, rinfo, btdi);
});
@ -413,14 +416,14 @@ void WiimoteScannerWindows::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
// Get all hid devices connected
HDEVINFO const device_info =
SetupDiGetClassDevs(&device_id, nullptr, nullptr, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
SetupDiGetClassDevs(&device_id, nullptr, nullptr, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
SP_DEVICE_INTERFACE_DATA device_data = {};
device_data.cbSize = sizeof(device_data);
PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = nullptr;
for (int index = 0;
SetupDiEnumDeviceInterfaces(device_info, nullptr, &device_id, index, &device_data); ++index)
SetupDiEnumDeviceInterfaces(device_info, nullptr, &device_id, index, &device_data); ++index)
{
// Get the size of the data block required
DWORD len;
@ -433,7 +436,7 @@ void WiimoteScannerWindows::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
// Query the data for this device
if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, nullptr,
&device_info_data))
&device_info_data))
{
std::basic_string<TCHAR> device_path(detail_data->DevicePath);
bool IsUsingToshibaStack = CheckForToshibaStack(device_info_data.DevInst);
@ -498,7 +501,7 @@ bool WiimoteWindows::ConnectInternal()
auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE;
m_dev_handle = CreateFile(m_devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, open_flags, nullptr,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
if (m_dev_handle == INVALID_HANDLE_VALUE)
{
@ -507,38 +510,38 @@ bool WiimoteWindows::ConnectInternal()
}
#if 0
TCHAR name[128] = {};
pHidD_GetProductString(dev_handle, name, 128);
TCHAR name[128] = {};
pHidD_GetProductString(dev_handle, name, 128);
//ERROR_LOG(WIIMOTE, "Product string: %s", TStrToUTF8(name).c_str());
//ERROR_LOG(WIIMOTE, "Product string: %s", TStrToUTF8(name).c_str());
if (!IsValidBluetoothName(TStrToUTF8(name)))
{
CloseHandle(dev_handle);
dev_handle = 0;
return false;
}
if (!IsValidBluetoothName(TStrToUTF8(name)))
{
CloseHandle(dev_handle);
dev_handle = 0;
return false;
}
#endif
#if 0
HIDD_ATTRIBUTES attr;
attr.Size = sizeof(attr);
if (!pHidD_GetAttributes(dev_handle, &attr))
{
CloseHandle(dev_handle);
dev_handle = 0;
return false;
}
HIDD_ATTRIBUTES attr;
attr.Size = sizeof(attr);
if (!pHidD_GetAttributes(dev_handle, &attr))
{
CloseHandle(dev_handle);
dev_handle = 0;
return false;
}
#endif
// TODO: thread isn't started here now, do this elsewhere
// This isn't as drastic as it sounds, since the process in which the threads
// reside is normal priority. Needed for keeping audio reports at a decent rate
/*
if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL))
{
ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority");
}
if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL))
{
ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority");
}
*/
return true;
@ -554,8 +557,8 @@ void WiimoteWindows::DisconnectInternal()
}
WiimoteWindows::WiimoteWindows(const std::basic_string<TCHAR>& path,
WinWriteMethod initial_write_method)
: m_devicepath(path), m_write_method(initial_write_method)
WinWriteMethod initial_write_method)
: m_devicepath(path), m_write_method(initial_write_method)
{
m_dev_handle = nullptr;
@ -711,8 +714,8 @@ static int IOWritePerSetOutputReport(HANDLE& dev_handle, const u8* buf, size_t l
}
static int IOWritePerWriteFile(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write,
WinWriteMethod& write_method, const u8* buf, size_t len,
DWORD* written)
WinWriteMethod& write_method, const u8* buf, size_t len,
DWORD* written)
{
DWORD bytes_written;
LPCVOID write_buffer = buf + 1;
@ -734,7 +737,7 @@ static int IOWritePerWriteFile(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write
ResetEvent(hid_overlap_write.hEvent);
BOOLEAN result =
WriteFile(dev_handle, write_buffer, bytes_to_write, &bytes_written, &hid_overlap_write);
WriteFile(dev_handle, write_buffer, bytes_to_write, &bytes_written, &hid_overlap_write);
if (!result)
{
const DWORD error = GetLastError();
@ -818,7 +821,7 @@ static int IOWritePerWriteFile(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write
// Wiimotes work with WriteFile
// as they don't accept output reports via the Control Channel.
int IOWrite(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write, WinWriteMethod& write_method,
const u8* buf, size_t len, DWORD* written)
const u8* buf, size_t len, DWORD* written)
{
switch (write_method)
{
@ -881,7 +884,7 @@ void ProcessWiimotes(bool new_scan, const T& callback)
{
// btdi.szName is sometimes missing it's content - it's a bt feature..
DEBUG_LOG(WIIMOTE, "Authenticated %i connected %i remembered %i ", btdi.fAuthenticated,
btdi.fConnected, btdi.fRemembered);
btdi.fConnected, btdi.fRemembered);
if (IsValidDeviceName(UTF16ToUTF8(btdi.szName)))
{
@ -917,7 +920,7 @@ void RemoveWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
}
bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info,
BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
// We don't want "remembered" devices.
// SetServiceState will just fail with them..
@ -926,16 +929,16 @@ bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info,
auto const& wm_addr = btdi.Address.rgBytes;
NOTICE_LOG(WIIMOTE, "Found Wiimote (%02x:%02x:%02x:%02x:%02x:%02x). Enabling HID service.",
wm_addr[0], wm_addr[1], wm_addr[2], wm_addr[3], wm_addr[4], wm_addr[5]);
wm_addr[0], wm_addr[1], wm_addr[2], wm_addr[3], wm_addr[4], wm_addr[5]);
#if defined(AUTHENTICATE_WIIMOTES)
// Authenticate
auto const& radio_addr = radio_info.address.rgBytes;
// FIXME Not sure this usage of OOB_DATA_INFO is correct...
BLUETOOTH_OOB_DATA_INFO oob_data_info = {0};
BLUETOOTH_OOB_DATA_INFO oob_data_info = { 0 };
memcpy(&oob_data_info.C[0], &radio_addr[0], sizeof(WCHAR) * 6);
const DWORD auth_result = pBluetoothAuthenticateDeviceEx(nullptr, hRadio, &btdi, &oob_data_info,
MITMProtectionNotDefined);
MITMProtectionNotDefined);
if (ERROR_SUCCESS != auth_result)
{
@ -946,17 +949,17 @@ bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info,
GUID guids[16];
// If this is not done, the Wii device will not remember the pairing
const DWORD srv_result =
pBluetoothEnumerateInstalledServices(hRadio, &btdi, &pcServices, guids);
pBluetoothEnumerateInstalledServices(hRadio, &btdi, &pcServices, guids);
if (ERROR_SUCCESS != srv_result)
{
ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothEnumerateInstalledServices returned %08x",
srv_result);
srv_result);
}
#endif
// Activate service
const DWORD hr = pBluetoothSetServiceState(
hRadio, &btdi, &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE);
hRadio, &btdi, &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE);
g_connect_times[btdi.Address.ullLong] = std::time(nullptr);
@ -984,7 +987,7 @@ bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
auto pair_time = g_connect_times.find(btdi.Address.ullLong);
if (pair_time == g_connect_times.end() ||
std::difftime(time(nullptr), pair_time->second) >= avoid_forget_seconds)
std::difftime(time(nullptr), pair_time->second) >= avoid_forget_seconds)
{
// Make Windows forget about device so it will re-find it if visible.
// This is also required to detect a disconnect for some reason..

View file

@ -14,7 +14,6 @@
#include "Common/Event.h"
#include "Common/FifoQueue.h"
#include "Common/Flag.h"
#include "Common/NonCopyable.h"
#include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
@ -24,9 +23,14 @@ class PointerWrap;
namespace WiimoteReal
{
class Wiimote : NonCopyable
class Wiimote
{
public:
Wiimote(const Wiimote&) = delete;
Wiimote& operator=(const Wiimote&) = delete;
Wiimote(Wiimote&&) = default;
Wiimote& operator=(Wiimote&&) = default;
virtual ~Wiimote() {}
// This needs to be called in derived destructors!
void Shutdown();
@ -148,7 +152,7 @@ private:
std::thread m_scan_thread;
Common::Flag m_scan_thread_running;
Common::Event m_scan_mode_changed_event;
std::atomic<WiimoteScanMode> m_scan_mode{WiimoteScanMode::DO_NOT_SCAN};
std::atomic<WiimoteScanMode> m_scan_mode{ WiimoteScanMode::DO_NOT_SCAN };
};
extern std::mutex g_wiimotes_mutex;

View file

@ -327,6 +327,15 @@ void HotkeyManager::LoadDefaults(const ControllerInterface& ciface)
const std::string ALT = "((LMENU | RMENU) & !(LSHIFT | RSHIFT) & !(LCONTROL | RCONTROL))";
const std::string SHIFT = "(!(LMENU | RMENU) & (LSHIFT | RSHIFT) & !(LCONTROL | RCONTROL))";
const std::string CTRL = "(!(LMENU | RMENU) & !(LSHIFT | RSHIFT) & (LCONTROL | RCONTROL))";
#elif __APPLE__
const std::string NON =
"(!`Left Alt` & !(`Left Shift`| `Right Shift`) & !(`Left Control` | `Right Control`))";
const std::string ALT =
"(`Left Alt` & !(`Left Shift`| `Right Shift`) & !(`Left Control` | `Right Control`))";
const std::string SHIFT =
"(!`Left Alt` & (`Left Shift`| `Right Shift`) & !(`Left Control` | `Right Control`))";
const std::string CTRL =
"(!`Left Alt` & !(`Left Shift`| `Right Shift`) & (`Left Control` | `Right Control`))";
#else
const std::string NON = "(!`Alt_L` & !(`Shift_L` | `Shift_R`) & !(`Control_L` | `Control_R` ))";
const std::string ALT = "(`Alt_L` & !(`Shift_L` | `Shift_R`) & !(`Control_L` | `Control_R` ))";

View file

@ -50,7 +50,6 @@ typedef struct pollfd pollfd_t;
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/NonCopyable.h"
#include "Core/HW/Memmap.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/Network/IP/Top.h"
@ -207,7 +206,7 @@ public:
void operator=(WiiSocket const&) = delete;
};
class WiiSockMan : public ::NonCopyable
class WiiSockMan
{
public:
static s32 GetNetErrorCode(s32 ret, const char* caller, bool isRW);
@ -249,7 +248,10 @@ public:
private:
WiiSockMan() = default;
WiiSockMan(const WiiSockMan&) = delete;
WiiSockMan& operator=(const WiiSockMan&) = delete;
WiiSockMan(WiiSockMan&&) = delete;
WiiSockMan& operator=(WiiSockMan&&) = delete;
std::unordered_map<s32, WiiSocket> WiiSockets;
s32 errno_last;
};

View file

@ -4,6 +4,7 @@
#include "Core/IOS/WFS/WFSI.h"
#include <cinttypes>
#include <mbedtls/aes.h>
#include <stack>
#include <string>
@ -20,6 +21,20 @@
#include "Core/IOS/WFS/WFSSRV.h"
#include "DiscIO/NANDContentLoader.h"
namespace
{
std::string TitleIdStr(u64 tid)
{
return StringFromFormat("%c%c%c%c", static_cast<char>(tid >> 24), static_cast<char>(tid >> 16),
static_cast<char>(tid >> 8), static_cast<char>(tid));
}
std::string GroupIdStr(u16 gid)
{
return StringFromFormat("%c%c", gid >> 8, gid & 0xFF);
}
} // namespace
namespace IOS
{
namespace HLE
@ -64,7 +79,7 @@ void ARCUnpacker::Extract(const WriteCallback& callback)
u32 size = Common::swap32(node + 8);
std::string basename = string_table + name_offset;
std::string fullname =
current_directory.empty() ? basename : current_directory + "/" + basename;
current_directory.empty() ? basename : current_directory + "/" + basename;
u8 flags = *node;
if (flags == 1)
@ -74,7 +89,7 @@ void ARCUnpacker::Extract(const WriteCallback& callback)
else
{
std::vector<u8> contents(m_whole_file.data() + data_offset,
m_whole_file.data() + data_offset + size);
m_whole_file.data() + data_offset + size);
callback(fullname, contents);
}
}
@ -86,23 +101,54 @@ WFSI::WFSI(Kernel& ios, const std::string& device_name) : Device(ios, device_nam
{
}
void WFSI::SetCurrentTitleIdAndGroupId(u64 tid, u16 gid)
{
m_current_title_id = tid;
m_current_group_id = gid;
m_current_title_id_str = TitleIdStr(tid);
m_current_group_id_str = GroupIdStr(gid);
}
void WFSI::SetImportTitleIdAndGroupId(u64 tid, u16 gid)
{
m_import_title_id = tid;
m_import_group_id = gid;
m_import_title_id_str = TitleIdStr(tid);
m_import_group_id_str = GroupIdStr(gid);
}
IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
{
s32 return_error_code = IPC_SUCCESS;
switch (request.request)
{
case IOCTL_WFSI_PREPARE_DEVICE:
case IOCTL_WFSI_IMPORT_TITLE_INIT:
{
u32 tmd_addr = Memory::Read_U32(request.buffer_in);
u32 tmd_size = Memory::Read_U32(request.buffer_in + 4);
INFO_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE");
m_patch_type = static_cast<PatchType>(Memory::Read_U32(request.buffer_in + 32));
m_continue_install = Memory::Read_U32(request.buffer_in + 36);
constexpr u32 MAX_TMD_SIZE = 0x4000;
if (tmd_size > MAX_TMD_SIZE)
INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: patch type %d, continue install: %s",
m_patch_type, m_continue_install ? "true" : "false");
if (m_patch_type == PatchType::PATCH_TYPE_2)
{
ERROR_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE: TMD size too large (%d)", tmd_size);
const std::string content_dir =
StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(),
m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
File::Rename(WFS::NativePath(content_dir + "/default.dol"),
WFS::NativePath(content_dir + "/_default.dol"));
}
if (!IOS::ES::IsValidTMDSize(tmd_size))
{
ERROR_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_INIT: TMD size too large (%d)", tmd_size);
return_error_code = IPC_EINVAL;
break;
}
@ -121,18 +167,25 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
memcpy(m_aes_key, ticket.GetTitleKey(m_ios.GetIOSC()).data(), sizeof(m_aes_key));
mbedtls_aes_setkey_dec(&m_aes_ctx, m_aes_key, 128);
SetImportTitleIdAndGroupId(m_tmd.GetTitleId(), m_tmd.GetGroupId());
if (m_patch_type == PatchType::PATCH_TYPE_1)
CancelPatchImport(m_continue_install);
else if (m_patch_type == PatchType::NOT_A_PATCH)
CancelTitleImport(m_continue_install);
break;
}
case IOCTL_WFSI_PREPARE_PROFILE:
m_base_extract_path = StringFromFormat("/vol/%s/tmp/", m_device_name.c_str());
// Fall through intended.
// Fall through intended.
case IOCTL_WFSI_PREPARE_CONTENT:
{
const char* ioctl_name = request.request == IOCTL_WFSI_PREPARE_PROFILE ?
"IOCTL_WFSI_PREPARE_PROFILE" :
"IOCTL_WFSI_PREPARE_CONTENT";
"IOCTL_WFSI_PREPARE_PROFILE" :
"IOCTL_WFSI_PREPARE_CONTENT";
// Initializes the IV from the index of the content in the TMD contents.
u32 content_id = Memory::Read_U32(request.buffer_in + 8);
@ -148,7 +201,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
m_aes_iv[0] = content_info.index >> 8;
m_aes_iv[1] = content_info.index & 0xFF;
INFO_LOG(IOS_WFS, "%s: Content id %08x found at index %d", ioctl_name, content_id,
content_info.index);
content_info.index);
m_arc_unpacker.Reset();
break;
@ -158,29 +211,29 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
case IOCTL_WFSI_IMPORT_CONTENT:
{
const char* ioctl_name = request.request == IOCTL_WFSI_IMPORT_PROFILE ?
"IOCTL_WFSI_IMPORT_PROFILE" :
"IOCTL_WFSI_IMPORT_CONTENT";
"IOCTL_WFSI_IMPORT_PROFILE" :
"IOCTL_WFSI_IMPORT_CONTENT";
u32 content_id = Memory::Read_U32(request.buffer_in + 0xC);
u32 input_ptr = Memory::Read_U32(request.buffer_in + 0x10);
u32 input_size = Memory::Read_U32(request.buffer_in + 0x14);
INFO_LOG(IOS_WFS, "%s: %08x bytes of data at %08x from content id %d", ioctl_name, input_size,
input_ptr, content_id);
input_ptr, content_id);
std::vector<u8> decrypted(input_size);
mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, input_size, m_aes_iv,
Memory::GetPointer(input_ptr), decrypted.data());
Memory::GetPointer(input_ptr), decrypted.data());
m_arc_unpacker.AddBytes(decrypted);
break;
}
case IOCTL_WFSI_FINALIZE_PROFILE:
case IOCTL_WFSI_FINALIZE_CONTENT:
case IOCTL_WFSI_IMPORT_CONTENT_END:
case IOCTL_WFSI_IMPORT_PROFILE_END:
{
const char* ioctl_name = request.request == IOCTL_WFSI_FINALIZE_PROFILE ?
"IOCTL_WFSI_FINALIZE_PROFILE" :
"IOCTL_WFSI_FINALIZE_CONTENT";
const char* ioctl_name = request.request == IOCTL_WFSI_IMPORT_PROFILE_END ?
"IOCTL_WFSI_IMPORT_PROFILE_END" :
"IOCTL_WFSI_IMPORT_CONTENT_END";
INFO_LOG(IOS_WFS, "%s", ioctl_name);
auto callback = [this](const std::string& filename, const std::vector<u8>& bytes) {
@ -204,6 +257,53 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
break;
}
case IOCTL_WFSI_FINALIZE_TITLE_INSTALL:
{
std::string tmd_path;
if (m_patch_type == NOT_A_PATCH)
{
std::string title_install_dir = StringFromFormat("/vol/%s/_install/%s", m_device_name.c_str(),
m_import_title_id_str.c_str());
std::string title_final_dir =
StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(),
m_import_group_id_str.c_str(), m_import_title_id_str.c_str());
File::Rename(WFS::NativePath(title_install_dir), WFS::NativePath(title_final_dir));
tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd",
m_device_name.c_str(), m_import_group_id_str.c_str(),
m_import_title_id_str.c_str(), m_import_title_id);
}
else
{
std::string patch_dir =
StringFromFormat("/vol/%s/title/%s/%s/_patch", m_device_name.c_str(),
m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
File::DeleteDirRecursively(WFS::NativePath(patch_dir));
tmd_path = StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd",
m_device_name.c_str(), m_current_group_id_str.c_str(),
m_current_title_id_str.c_str(), m_import_title_id);
}
File::IOFile tmd_file(WFS::NativePath(tmd_path), "wb");
tmd_file.WriteBytes(m_tmd.GetBytes().data(), m_tmd.GetBytes().size());
break;
}
case IOCTL_WFSI_FINALIZE_PATCH_INSTALL:
{
INFO_LOG(IOS_WFS, "IOCTL_WFSI_FINALIZE_PATCH_INSTALL");
if (m_patch_type != NOT_A_PATCH)
{
std::string current_title_dir =
StringFromFormat("/vol/%s/title/%s/%s", m_device_name.c_str(),
m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
std::string patch_dir = current_title_dir + "/_patch";
File::CopyDir(WFS::NativePath(patch_dir), WFS::NativePath(current_title_dir), true);
}
break;
}
case IOCTL_WFSI_DELETE_TITLE:
// Bytes 0-4: ??
// Bytes 4-8: game id
@ -211,26 +311,40 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
WARN_LOG(IOS_WFS, "IOCTL_WFSI_DELETE_TITLE: unimplemented");
break;
case IOCTL_WFSI_IMPORT_TITLE:
WARN_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE: unimplemented");
case IOCTL_WFSI_GET_VERSION:
INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_VERSION");
Memory::Write_U32(0x20, request.buffer_out);
break;
case IOCTL_WFSI_IMPORT_TITLE_CANCEL:
{
INFO_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE_CANCEL");
bool continue_install = Memory::Read_U32(request.buffer_in) != 0;
if (m_patch_type == PatchType::NOT_A_PATCH)
return_error_code = CancelTitleImport(continue_install);
else if (m_patch_type == PatchType::PATCH_TYPE_1 || m_patch_type == PatchType::PATCH_TYPE_2)
return_error_code = CancelPatchImport(continue_install);
else
return_error_code = WFS_EINVAL;
m_tmd = {};
break;
}
case IOCTL_WFSI_INIT:
{
INFO_LOG(IOS_WFS, "IOCTL_WFSI_INIT");
if (GetIOS()->GetES()->GetTitleId(&m_title_id) < 0)
u64 tid;
if (GetIOS()->GetES()->GetTitleId(&tid) < 0)
{
ERROR_LOG(IOS_WFS, "IOCTL_WFSI_INIT: Could not get title id.");
return_error_code = IPC_EINVAL;
break;
}
m_title_id_str = StringFromFormat(
"%c%c%c%c", static_cast<char>(m_title_id >> 24), static_cast<char>(m_title_id >> 16),
static_cast<char>(m_title_id >> 8), static_cast<char>(m_title_id));
IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(m_title_id);
m_group_id = tmd.GetGroupId();
m_group_id_str = StringFromFormat("%c%c", m_group_id >> 8, m_group_id & 0xFF);
IOS::ES::TMDReader tmd = GetIOS()->GetES()->FindInstalledTMD(tid);
SetCurrentTitleIdAndGroupId(tmd.GetTitleId(), tmd.GetGroupId());
break;
}
@ -240,18 +354,89 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
break;
case IOCTL_WFSI_APPLY_TITLE_PROFILE:
{
INFO_LOG(IOS_WFS, "IOCTL_WFSI_APPLY_TITLE_PROFILE");
m_base_extract_path = StringFromFormat("/vol/%s/_install/%s/content", m_device_name.c_str(),
m_title_id_str.c_str());
File::CreateFullPath(WFS::NativePath(m_base_extract_path));
if (m_patch_type == NOT_A_PATCH)
{
std::string install_directory = StringFromFormat("/vol/%s/_install", m_device_name.c_str());
if (!m_continue_install && File::IsDirectory(WFS::NativePath(install_directory)))
{
File::DeleteDirRecursively(WFS::NativePath(install_directory));
}
m_base_extract_path = StringFromFormat("%s/%s/content", install_directory.c_str(),
m_import_title_id_str.c_str());
File::CreateFullPath(WFS::NativePath(m_base_extract_path));
File::CreateDir(WFS::NativePath(m_base_extract_path));
for (auto dir : { "work", "meta", "save" })
{
std::string path = StringFromFormat("%s/%s/%s", install_directory.c_str(),
m_import_title_id_str.c_str(), dir);
File::CreateDir(WFS::NativePath(path));
}
std::string group_path = StringFromFormat("/vol/%s/title/%s", m_device_name.c_str(),
m_import_group_id_str.c_str());
File::CreateFullPath(WFS::NativePath(group_path));
File::CreateDir(WFS::NativePath(group_path));
}
else
{
m_base_extract_path =
StringFromFormat("/vol/%s/title/%s/%s/_patch/content", m_device_name.c_str(),
m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
File::CreateFullPath(WFS::NativePath(m_base_extract_path));
File::CreateDir(WFS::NativePath(m_base_extract_path));
}
break;
}
case IOCTL_WFSI_GET_TMD:
{
u64 subtitle_id = Memory::Read_U64(request.buffer_in);
u32 address = Memory::Read_U32(request.buffer_in + 24);
INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_TMD: subtitle ID %016" PRIx64, subtitle_id);
u32 tmd_size;
return_error_code =
GetTmd(m_current_group_id, m_current_title_id, subtitle_id, address, &tmd_size);
Memory::Write_U32(tmd_size, request.buffer_out);
break;
}
case IOCTL_WFSI_GET_TMD_ABSOLUTE:
{
u64 subtitle_id = Memory::Read_U64(request.buffer_in);
u32 address = Memory::Read_U32(request.buffer_in + 24);
u16 group_id = Memory::Read_U16(request.buffer_in + 36);
u32 title_id = Memory::Read_U32(request.buffer_in + 32);
INFO_LOG(IOS_WFS, "IOCTL_WFSI_GET_TMD_ABSOLUTE: tid %08x, gid %04x, subtitle ID %016" PRIx64,
title_id, group_id, subtitle_id);
u32 tmd_size;
return_error_code = GetTmd(group_id, title_id, subtitle_id, address, &tmd_size);
Memory::Write_U32(tmd_size, request.buffer_out);
break;
}
case IOCTL_WFSI_SET_FST_BUFFER:
{
INFO_LOG(IOS_WFS, "IOCTL_WFSI_SET_FST_BUFFER: address %08x, size %08x", request.buffer_in,
request.buffer_in_size);
break;
}
case IOCTL_WFSI_NOOP:
break;
case IOCTL_WFSI_LOAD_DOL:
{
std::string path = StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(),
m_group_id_str.c_str(), m_title_id_str.c_str());
std::string path =
StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(),
m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
u32 dol_addr = Memory::Read_U32(request.buffer_in + 0x18);
u32 max_dol_size = Memory::Read_U32(request.buffer_in + 0x14);
@ -267,13 +452,13 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
}
INFO_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: loading %s at address %08x (size %d)", path.c_str(),
dol_addr, max_dol_size);
dol_addr, max_dol_size);
File::IOFile fp(WFS::NativePath(path), "rb");
if (!fp)
{
WARN_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: no such file or directory: %s", path.c_str());
return_error_code = WFSI_ENOENT;
return_error_code = WFS_ENOENT;
break;
}
@ -291,6 +476,23 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
break;
}
case IOCTL_WFSI_CHECK_HAS_SPACE:
WARN_LOG(IOS_WFS, "IOCTL_WFSI_CHECK_HAS_SPACE: returning true");
// TODO(wfs): implement this properly.
// 1 is returned if there is free space, 0 otherwise.
//
// WFSI builds a path depending on the import state
// /vol/VOLUME_ID/title/GROUP_ID/GAME_ID
// /vol/VOLUME_ID/_install/GAME_ID
// then removes everything after the last path separator ('/')
// it then calls WFSISrvGetFreeBlkNum (ioctl 0x5a, aliased to 0x5b) with that path.
// If the ioctl fails, WFSI returns 0.
// If the ioctl succeeds, WFSI returns 0 or 1 depending on the three u32s in the input buffer
// and the three u32s returned by WFSSRV (TODO: figure out what it does)
return_error_code = 1;
break;
default:
// TODO(wfs): Should be returning an error. However until we have
// everything properly stubbed it's easier to simulate the methods
@ -302,6 +504,75 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
return GetDefaultReply(return_error_code);
}
u32 WFSI::GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const
{
std::string path =
StringFromFormat("/vol/%s/title/%s/%s/meta/%016" PRIx64 ".tmd", m_device_name.c_str(),
GroupIdStr(group_id).c_str(), TitleIdStr(title_id).c_str(), subtitle_id);
File::IOFile fp(WFS::NativePath(path), "rb");
if (!fp)
{
WARN_LOG(IOS_WFS, "GetTmd: no such file or directory: %s", path.c_str());
return WFS_ENOENT;
}
if (address)
{
fp.ReadBytes(Memory::GetPointer(address), fp.GetSize());
}
*size = fp.GetSize();
return IPC_SUCCESS;
}
static s32 DeleteTemporaryFiles(const std::string& device_name, u64 title_id)
{
File::Delete(WFS::NativePath(
StringFromFormat("/vol/%s/tmp/%016" PRIx64 ".ini", device_name.c_str(), title_id)));
File::Delete(WFS::NativePath(
StringFromFormat("/vol/%s/tmp/%016" PRIx64 ".ppcini", device_name.c_str(), title_id)));
return IPC_SUCCESS;
}
s32 WFSI::CancelTitleImport(bool continue_install)
{
m_arc_unpacker.Reset();
if (!continue_install)
{
File::DeleteDirRecursively(
WFS::NativePath(StringFromFormat("/vol/%s/_install", m_device_name.c_str())));
}
DeleteTemporaryFiles(m_device_name, m_import_title_id);
return IPC_SUCCESS;
}
s32 WFSI::CancelPatchImport(bool continue_install)
{
m_arc_unpacker.Reset();
if (!continue_install)
{
File::DeleteDirRecursively(WFS::NativePath(
StringFromFormat("/vol/%s/title/%s/%s/_patch", m_device_name.c_str(),
m_current_group_id_str.c_str(), m_current_title_id_str.c_str())));
if (m_patch_type == PatchType::PATCH_TYPE_2)
{
// Move back _default.dol to default.dol.
const std::string content_dir =
StringFromFormat("/vol/%s/title/%s/%s/content", m_device_name.c_str(),
m_current_group_id_str.c_str(), m_current_title_id_str.c_str());
File::Rename(WFS::NativePath(content_dir + "/_default.dol"),
WFS::NativePath(content_dir + "/default.dol"));
}
}
DeleteTemporaryFiles(m_device_name, m_current_title_id);
return IPC_SUCCESS;
}
} // namespace Device
} // namespace HLE
} // namespace IOS

View file

@ -44,6 +44,14 @@ public:
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
private:
u32 GetTmd(u16 group_id, u32 title_id, u64 subtitle_id, u32 address, u32* size) const;
void SetCurrentTitleIdAndGroupId(u64 tid, u16 gid);
void SetImportTitleIdAndGroupId(u64 tid, u16 gid);
s32 CancelTitleImport(bool continue_install);
s32 CancelPatchImport(bool continue_install);
std::string m_device_name;
mbedtls_aes_context m_aes_ctx;
@ -52,39 +60,69 @@ private:
IOS::ES::TMDReader m_tmd;
std::string m_base_extract_path;
u64 m_title_id;
std::string m_title_id_str;
u16 m_group_id;
std::string m_group_id_str;
u64 m_current_title_id;
std::string m_current_title_id_str;
u16 m_current_group_id;
std::string m_current_group_id_str;
u64 m_import_title_id;
std::string m_import_title_id_str;
u16 m_import_group_id;
std::string m_import_group_id_str;
// Set on IMPORT_TITLE_INIT when the next profile application should not delete
// temporary install files.
bool m_continue_install = false;
// Set on IMPORT_TITLE_INIT to indicate that the install is a patch and not a
// standalone title.
enum PatchType
{
NOT_A_PATCH,
PATCH_TYPE_1,
PATCH_TYPE_2,
};
PatchType m_patch_type = NOT_A_PATCH;
ARCUnpacker m_arc_unpacker;
enum
{
WFSI_ENOENT = -12000,
};
enum
{
IOCTL_WFSI_PREPARE_DEVICE = 0x02,
IOCTL_WFSI_IMPORT_TITLE_INIT = 0x02,
IOCTL_WFSI_PREPARE_CONTENT = 0x03,
IOCTL_WFSI_IMPORT_CONTENT = 0x04,
IOCTL_WFSI_FINALIZE_CONTENT = 0x05,
IOCTL_WFSI_IMPORT_CONTENT_END = 0x05,
IOCTL_WFSI_FINALIZE_TITLE_INSTALL = 0x06,
IOCTL_WFSI_DELETE_TITLE = 0x17,
IOCTL_WFSI_IMPORT_TITLE = 0x2f,
IOCTL_WFSI_GET_VERSION = 0x1b,
IOCTL_WFSI_IMPORT_TITLE_CANCEL = 0x2f,
IOCTL_WFSI_INIT = 0x81,
IOCTL_WFSI_SET_DEVICE_NAME = 0x82,
IOCTL_WFSI_PREPARE_PROFILE = 0x86,
IOCTL_WFSI_IMPORT_PROFILE = 0x87,
IOCTL_WFSI_FINALIZE_PROFILE = 0x88,
IOCTL_WFSI_IMPORT_PROFILE_END = 0x88,
IOCTL_WFSI_APPLY_TITLE_PROFILE = 0x89,
IOCTL_WFSI_GET_TMD = 0x8a,
IOCTL_WFSI_GET_TMD_ABSOLUTE = 0x8b,
IOCTL_WFSI_SET_FST_BUFFER = 0x8e,
IOCTL_WFSI_NOOP = 0x8f,
IOCTL_WFSI_LOAD_DOL = 0x90,
IOCTL_WFSI_FINALIZE_PATCH_INSTALL = 0x91,
IOCTL_WFSI_CHECK_HAS_SPACE = 0x95,
};
};
} // namespace Device

View file

@ -4,6 +4,7 @@
#include "Core/IOS/WFS/WFSSRV.h"
#include <algorithm>
#include <cinttypes>
#include <string>
#include <vector>
@ -58,7 +59,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
// Close all hanging attach/detach ioctls with an appropriate error code.
for (auto address : m_hanging)
{
IOCtlRequest hanging_request{address};
IOCtlRequest hanging_request{ address };
Memory::Write_U32(0x80000000, hanging_request.buffer_out);
Memory::Write_U32(0, hanging_request.buffer_out + 4);
Memory::Write_U32(0, hanging_request.buffer_out + 8);
@ -100,6 +101,29 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
INFO_LOG(IOS_WFS, "IOCTL_WFS_FLUSH: doing nothing");
break;
case IOCTL_WFS_MKDIR:
{
std::string path = NormalizePath(
Memory::GetString(request.buffer_in + 34, Memory::Read_U16(request.buffer_in + 32)));
std::string native_path = WFS::NativePath(path);
if (File::Exists(native_path))
{
INFO_LOG(IOS_WFS, "IOCTL_WFS_MKDIR(%s): already exists", path.c_str());
return_error_code = WFS_EEXIST;
}
else if (!File::CreateDir(native_path))
{
INFO_LOG(IOS_WFS, "IOCTL_WFS_MKDIR(%s): no such file or directory", path.c_str());
return_error_code = WFS_ENOENT;
}
else
{
INFO_LOG(IOS_WFS, "IOCTL_WFS_MKDIR(%s): directory created", path.c_str());
}
break;
}
// TODO(wfs): Globbing is not really implemented, we just fake the one case
// (listing /vol/*) which is required to get the installer to work.
case IOCTL_WFS_GLOB_START:
@ -120,13 +144,13 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
case IOCTL_WFS_SET_HOMEDIR:
m_home_directory =
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
INFO_LOG(IOS_WFS, "IOCTL_WFS_SET_HOMEDIR: %s", m_home_directory.c_str());
break;
case IOCTL_WFS_CHDIR:
m_current_directory =
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
INFO_LOG(IOS_WFS, "IOCTL_WFS_CHDIR: %s", m_current_directory.c_str());
break;
@ -136,9 +160,48 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
Memory::CopyToEmu(request.buffer_out + 2, m_home_directory.data(), m_home_directory.size());
break;
case IOCTL_WFS_GET_ATTRIBUTES:
{
std::string path = NormalizePath(
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in)));
std::string native_path = WFS::NativePath(path);
Memory::Memset(0, request.buffer_out, request.buffer_out_size);
if (!File::Exists(native_path))
{
INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_ATTRIBUTES(%s): no such file or directory", path.c_str());
return_error_code = WFS_ENOENT;
}
else if (File::IsDirectory(native_path))
{
INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_ATTRIBUTES(%s): directory", path.c_str());
Memory::Write_U32(0x80000000, request.buffer_out + 4);
}
else
{
u32 size = static_cast<u32>(File::GetSize(native_path));
INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_ATTRIBUTES(%s): file with size %d", path.c_str(), size);
Memory::Write_U32(size, request.buffer_out);
}
break;
}
case IOCTL_WFS_RENAME:
case IOCTL_WFS_RENAME_2:
{
const std::string source_path =
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
const std::string dest_path =
Memory::GetString(request.buffer_in + 512 + 2, Memory::Read_U16(request.buffer_in + 512));
return_error_code = Rename(source_path, dest_path);
break;
}
case IOCTL_WFS_CREATE_OPEN:
case IOCTL_WFS_OPEN:
{
u32 mode = Memory::Read_U32(request.buffer_in);
const char* ioctl_name =
request.request == IOCTL_WFS_OPEN ? "IOCTL_WFS_OPEN" : "IOCTL_WFS_CREATE_OPEN";
u32 mode = request.request == IOCTL_WFS_OPEN ? Memory::Read_U32(request.buffer_in) : 2;
u16 path_len = Memory::Read_U16(request.buffer_in + 0x20);
std::string path = Memory::GetString(request.buffer_in + 0x22, path_len);
@ -153,14 +216,21 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
if (!fd_obj->Open())
{
ERROR_LOG(IOS_WFS, "IOCTL_WFS_OPEN(%s, %d): error opening file", path.c_str(), mode);
ERROR_LOG(IOS_WFS, "%s(%s, %d): error opening file", ioctl_name, path.c_str(), mode);
ReleaseFileDescriptor(fd);
return_error_code = WFS_ENOENT;
break;
}
INFO_LOG(IOS_WFS, "IOCTL_WFS_OPEN(%s, %d) -> %d", path.c_str(), mode, fd);
Memory::Write_U16(fd, request.buffer_out + 0x14);
INFO_LOG(IOS_WFS, "%s(%s, %d) -> %d", ioctl_name, path.c_str(), mode, fd);
if (request.request == IOCTL_WFS_OPEN)
{
Memory::Write_U16(fd, request.buffer_out + 0x14);
}
else
{
Memory::Write_U16(fd, request.buffer_out);
}
break;
}
@ -194,6 +264,16 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
break;
}
case IOCTL_WFS_CLOSE_2:
{
// TODO(wfs): Figure out the exact semantics difference from the other
// close.
u16 fd = Memory::Read_U16(request.buffer_in + 0x4);
INFO_LOG(IOS_WFS, "IOCTL_WFS_CLOSE_2(%d)", fd);
ReleaseFileDescriptor(fd);
break;
}
case IOCTL_WFS_READ:
case IOCTL_WFS_READ_ABSOLUTE:
{
@ -230,11 +310,50 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
}
INFO_LOG(IOS_WFS, "IOCTL_WFS_READ: read %zd bytes from FD %d (%s)", read_bytes, fd,
fd_obj->path.c_str());
fd_obj->path.c_str());
return_error_code = static_cast<int>(read_bytes);
break;
}
case IOCTL_WFS_WRITE:
case IOCTL_WFS_WRITE_ABSOLUTE:
{
u32 addr = Memory::Read_U32(request.buffer_in);
u32 position = Memory::Read_U32(request.buffer_in + 4); // Only for absolute.
u16 fd = Memory::Read_U16(request.buffer_in + 0xC);
u32 size = Memory::Read_U32(request.buffer_in + 8);
bool absolute = request.request == IOCTL_WFS_WRITE_ABSOLUTE;
FileDescriptor* fd_obj = FindFileDescriptor(fd);
if (fd_obj == nullptr)
{
ERROR_LOG(IOS_WFS, "IOCTL_WFS_WRITE: invalid file descriptor %d", fd);
return_error_code = WFS_EBADFD;
break;
}
u64 previous_position = fd_obj->file.Tell();
if (absolute)
{
fd_obj->file.Seek(position, SEEK_SET);
}
fd_obj->file.WriteArray(Memory::GetPointer(addr), size);
// TODO(wfs): Handle write errors.
if (absolute)
{
fd_obj->file.Seek(previous_position, SEEK_SET);
}
else
{
fd_obj->position += size;
}
INFO_LOG(IOS_WFS, "IOCTL_WFS_WRITE: written %d bytes from FD %d (%s)", size, fd,
fd_obj->path.c_str());
break;
}
default:
// TODO(wfs): Should be returning -3. However until we have everything
// properly stubbed it's easier to simulate the methods succeeding.
@ -246,6 +365,26 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
return GetDefaultReply(return_error_code);
}
s32 WFSSRV::Rename(std::string source, std::string dest) const
{
source = NormalizePath(source);
dest = NormalizePath(dest);
INFO_LOG(IOS_WFS, "IOCTL_WFS_RENAME: %s to %s", source.c_str(), dest.c_str());
const bool opened = std::any_of(m_fds.begin(), m_fds.end(),
[&](const auto& fd) { return fd.in_use && fd.path == source; });
if (opened)
return WFS_FILE_IS_OPENED;
// TODO(wfs): Handle other rename failures
if (!File::Rename(WFS::NativePath(source), WFS::NativePath(dest)))
return WFS_ENOENT;
return IPC_SUCCESS;
}
std::string WFSSRV::NormalizePath(const std::string& path) const
{
std::string expanded;

View file

@ -22,6 +22,15 @@ namespace WFS
std::string NativePath(const std::string& wfs_path);
}
enum
{
WFS_EINVAL = -10003, // Invalid argument.
WFS_EBADFD = -10026, // Invalid file descriptor.
WFS_EEXIST = -10027, // File already exists.
WFS_ENOENT = -10028, // No such file or directory.
WFS_FILE_IS_OPENED = -10032, // Cannot perform operation on an opened file.
};
namespace Device
{
class WFSSRV : public Device
@ -31,6 +40,8 @@ public:
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
s32 Rename(std::string source, std::string dest) const;
private:
// WFS device name, e.g. msc01/msc02.
std::string m_device_name;
@ -59,7 +70,9 @@ private:
IOCTL_WFS_GET_HOMEDIR = 0x12,
IOCTL_WFS_GETCWD = 0x13,
IOCTL_WFS_DELETE = 0x15,
IOCTL_WFS_RENAME = 0x16,
IOCTL_WFS_GET_ATTRIBUTES = 0x17,
IOCTL_WFS_CREATE_OPEN = 0x19,
IOCTL_WFS_OPEN = 0x1A,
IOCTL_WFS_GET_SIZE = 0x1B,
IOCTL_WFS_CLOSE = 0x1E,
@ -67,13 +80,10 @@ private:
IOCTL_WFS_WRITE = 0x22,
IOCTL_WFS_ATTACH_DETACH = 0x2d,
IOCTL_WFS_ATTACH_DETACH_2 = 0x2e,
IOCTL_WFS_RENAME_2 = 0x41,
IOCTL_WFS_CLOSE_2 = 0x47,
IOCTL_WFS_READ_ABSOLUTE = 0x48,
};
enum
{
WFS_EBADFD = -10026, // Invalid file descriptor.
WFS_ENOENT = -10028, // No such file or directory.
IOCTL_WFS_WRITE_ABSOLUTE = 0x49,
};
struct FileDescriptor

View file

@ -4,8 +4,7 @@
// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic.
#include <fcntl.h>
#include <stdarg.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -20,8 +19,14 @@
#include <sys/un.h>
#endif
#include "Common/Logging/Log.h"
#include "Core/HW/CPU.h"
#include "Core/HW/Memmap.h"
#include "Core/Host.h"
#include "Core/PowerPC/GDBStub.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PPCCache.h"
#include "Core/PowerPC/PowerPC.h"
#define GDB_BFR_MAX 10000
#define GDB_MAX_BP 10
@ -276,8 +281,8 @@ static void gdb_read_command()
if (chk_calc != chk_read)
{
ERROR_LOG(GDB_STUB,
"gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)",
chk_calc, chk_read, cmd_bfr, cmd_len);
"gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)",
chk_calc, chk_read, cmd_bfr, cmd_len);
cmd_len = 0;
gdb_nak();
@ -368,7 +373,7 @@ static void gdb_handle_query()
static void gdb_handle_set_thread()
{
if (memcmp(cmd_bfr, "Hg0", 3) == 0 || memcmp(cmd_bfr, "Hc-1", 4) == 0 ||
memcmp(cmd_bfr, "Hc0", 4) == 0 || memcmp(cmd_bfr, "Hc1", 4) == 0)
memcmp(cmd_bfr, "Hc0", 4) == 0 || memcmp(cmd_bfr, "Hc1", 4) == 0)
return gdb_reply("OK");
gdb_reply("E01");
}
@ -487,7 +492,7 @@ static void gdb_read_registers()
/*
for (i = 0; i < 32; i++)
{
wbe32hex(bufptr + i*8, riPS0(i));
wbe32hex(bufptr + i*8, riPS0(i));
}
bufptr += 32 * 8;
wbe32hex(bufptr, PC); bufptr += 4;
@ -804,7 +809,7 @@ WSADATA InitData;
// exported functions
static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t server_addrlen,
sockaddr* client_addr, socklen_t* client_addrlen);
sockaddr* client_addr, socklen_t* client_addrlen);
#ifndef _WIN32
void gdb_init_local(const char* socket)
@ -831,7 +836,7 @@ void gdb_init(u32 port)
socklen_t client_addrlen = sizeof(saddr_client);
gdb_init_generic(PF_INET, (const sockaddr*)&saddr_server, sizeof(saddr_server),
(sockaddr*)&saddr_client, &client_addrlen);
(sockaddr*)&saddr_client, &client_addrlen);
saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr);
/*if (((saddr_client.sin_addr.s_addr >> 24) & 0xff) != 127 ||
@ -843,7 +848,7 @@ void gdb_init(u32 port)
}
static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t server_addrlen,
sockaddr* client_addr, socklen_t* client_addrlen)
sockaddr* client_addr, socklen_t* client_addrlen)
{
int on;
#ifdef _WIN32

View file

@ -6,14 +6,7 @@
#pragma once
#include <signal.h>
#include "Common/CommonTypes.h"
#include "Common/Thread.h"
#include "Core/HW/CPU.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/PowerPC.h"
#ifdef _WIN32
#define SIGTRAP 5

View file

@ -403,7 +403,7 @@ void Jit64::mtmsr(UGeckoInstruction inst)
// external exceptions when going out of mtmsr in order to execute delayed
// interrupts as soon as possible.
TEST(32, PPCSTATE(msr), Imm32(0x8000));
FixupBranch eeDisabled = J_CC(CC_Z);
FixupBranch eeDisabled = J_CC(CC_Z, true);
TEST(32, PPCSTATE(Exceptions),
Imm32(EXCEPTION_EXTERNAL_INT | EXCEPTION_PERFORMANCE_MONITOR | EXCEPTION_DECREMENTER));

View file

@ -77,8 +77,8 @@ void JitArm64::FlushCarry()
js.carryFlagSet = false;
}
void JitArm64::reg_imm(u32 d, u32 a, u32 value, u32 (*do_op)(u32, u32),
void (ARM64XEmitter::*op)(ARM64Reg, ARM64Reg, u64, ARM64Reg), bool Rc)
void JitArm64::reg_imm(u32 d, u32 a, u32 value, u32(*do_op)(u32, u32),
void (ARM64XEmitter::*op)(ARM64Reg, ARM64Reg, u64, ARM64Reg), bool Rc)
{
if (gpr.IsImm(a))
{
@ -116,7 +116,7 @@ static constexpr u32 BitXOR(u32 a, u32 b)
void JitArm64::arith_imm(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
u32 a = inst.RA, s = inst.RS;
switch (inst.OPCD)
@ -150,7 +150,7 @@ void JitArm64::arith_imm(UGeckoInstruction inst)
void JitArm64::addix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
u32 d = inst.RD, a = inst.RA;
u32 imm = (u32)(s32)inst.SIMM_16;
@ -184,7 +184,7 @@ void JitArm64::addix(UGeckoInstruction inst)
void JitArm64::boolX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, s = inst.RS, b = inst.RB;
if (gpr.IsImm(s) && gpr.IsImm(b))
@ -294,7 +294,7 @@ void JitArm64::boolX(UGeckoInstruction inst)
void JitArm64::addx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -329,7 +329,7 @@ void JitArm64::addx(UGeckoInstruction inst)
void JitArm64::extsXx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, s = inst.RS;
int size = inst.SUBOP10 == 922 ? 16 : 8;
@ -351,7 +351,7 @@ void JitArm64::extsXx(UGeckoInstruction inst)
void JitArm64::cntlzwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA;
int s = inst.RS;
@ -373,7 +373,7 @@ void JitArm64::cntlzwx(UGeckoInstruction inst)
void JitArm64::negx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA;
int d = inst.RD;
@ -397,7 +397,7 @@ void JitArm64::negx(UGeckoInstruction inst)
void JitArm64::cmp(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int crf = inst.CRFD;
u32 a = inst.RA, b = inst.RB;
@ -434,7 +434,7 @@ void JitArm64::cmp(UGeckoInstruction inst)
void JitArm64::cmpl(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int crf = inst.CRFD;
u32 a = inst.RA, b = inst.RB;
@ -462,7 +462,7 @@ void JitArm64::cmpl(UGeckoInstruction inst)
void JitArm64::cmpi(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
u32 a = inst.RA;
s64 B = inst.SIMM_16;
@ -491,7 +491,7 @@ void JitArm64::cmpi(UGeckoInstruction inst)
void JitArm64::cmpli(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
u32 a = inst.RA;
u64 B = inst.UIMM;
int crf = inst.CRFD;
@ -518,7 +518,7 @@ void JitArm64::cmpli(UGeckoInstruction inst)
void JitArm64::rlwinmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
u32 a = inst.RA, s = inst.RS;
u32 mask = Helper_Mask(inst.MB, inst.ME);
@ -532,7 +532,12 @@ void JitArm64::rlwinmx(UGeckoInstruction inst)
gpr.BindToRegister(a, a == s);
if (!inst.SH)
if (!inst.SH && mask == 0xFFFFFFFF)
{
if (a != s)
MOV(gpr.R(a), gpr.R(s));
}
else if (!inst.SH)
{
// Immediate mask
ANDI2R(gpr.R(a), gpr.R(s), mask);
@ -562,7 +567,7 @@ void JitArm64::rlwinmx(UGeckoInstruction inst)
void JitArm64::rlwnmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
u32 a = inst.RA, b = inst.RB, s = inst.RS;
u32 mask = Helper_Mask(inst.MB, inst.ME);
@ -599,7 +604,7 @@ void JitArm64::rlwnmx(UGeckoInstruction inst)
void JitArm64::srawix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA;
int s = inst.RS;
@ -670,7 +675,7 @@ void JitArm64::srawix(UGeckoInstruction inst)
void JitArm64::addic(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, d = inst.RD;
bool rc = inst.OPCD == 13;
@ -703,7 +708,7 @@ void JitArm64::addic(UGeckoInstruction inst)
void JitArm64::mulli(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, d = inst.RD;
@ -725,7 +730,7 @@ void JitArm64::mulli(UGeckoInstruction inst)
void JitArm64::mullwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -749,7 +754,7 @@ void JitArm64::mullwx(UGeckoInstruction inst)
void JitArm64::mulhwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -774,7 +779,7 @@ void JitArm64::mulhwx(UGeckoInstruction inst)
void JitArm64::mulhwux(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -799,7 +804,7 @@ void JitArm64::mulhwux(UGeckoInstruction inst)
void JitArm64::addzex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, d = inst.RD;
@ -832,7 +837,7 @@ void JitArm64::addzex(UGeckoInstruction inst)
void JitArm64::subfx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -856,7 +861,7 @@ void JitArm64::subfx(UGeckoInstruction inst)
void JitArm64::subfex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -926,7 +931,7 @@ void JitArm64::subfex(UGeckoInstruction inst)
void JitArm64::subfcx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -958,7 +963,7 @@ void JitArm64::subfcx(UGeckoInstruction inst)
void JitArm64::subfzex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, d = inst.RD;
@ -988,7 +993,7 @@ void JitArm64::subfzex(UGeckoInstruction inst)
void JitArm64::subfic(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, d = inst.RD;
s32 imm = inst.SIMM_16;
@ -1017,7 +1022,7 @@ void JitArm64::subfic(UGeckoInstruction inst)
void JitArm64::addex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -1082,7 +1087,7 @@ void JitArm64::addex(UGeckoInstruction inst)
void JitArm64::addcx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -1111,7 +1116,7 @@ void JitArm64::addcx(UGeckoInstruction inst)
void JitArm64::divwux(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -1139,7 +1144,7 @@ void JitArm64::divwux(UGeckoInstruction inst)
void JitArm64::divwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
FALLBACK_IF(inst.OE);
int a = inst.RA, b = inst.RB, d = inst.RD;
@ -1217,7 +1222,7 @@ void JitArm64::divwx(UGeckoInstruction inst)
void JitArm64::slwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, b = inst.RB, s = inst.RS;
@ -1265,7 +1270,7 @@ void JitArm64::slwx(UGeckoInstruction inst)
void JitArm64::srwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, b = inst.RB, s = inst.RS;
@ -1312,7 +1317,7 @@ void JitArm64::srwx(UGeckoInstruction inst)
void JitArm64::srawx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, b = inst.RB, s = inst.RS;
bool inplace_carry = CanMergeNextInstructions(1) && js.op[1].wantsCAInFlags;
@ -1415,7 +1420,7 @@ void JitArm64::srawx(UGeckoInstruction inst)
void JitArm64::rlwimix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
JITDISABLE(bJITIntegerOff);
int a = inst.RA, s = inst.RS;
u32 mask = Helper_Mask(inst.MB, inst.ME);

View file

@ -7,7 +7,6 @@
#include <algorithm>
#include <array>
#include <cinttypes>
#include <cstddef>
#include <cstring>
#include <locale>
#include <map>
@ -33,10 +32,6 @@
namespace DiscIO
{
static const DiscContent& AddFileToContents(std::set<DiscContent>* contents,
const std::string& path, u64 offset,
u64 max_size = UINT64_MAX);
// Reads as many bytes as the vector fits (or less, if the file is smaller).
// Returns the number of bytes read.
static size_t ReadFileToVector(const std::string& path, std::vector<u8>* vector);
@ -64,12 +59,12 @@ constexpr u8 FILE_ENTRY = 0;
constexpr u8 DIRECTORY_ENTRY = 1;
DiscContent::DiscContent(u64 offset, u64 size, const std::string& path)
: m_offset(offset), m_size(size), m_content_source(path)
: m_offset(offset), m_size(size), m_content_source(path)
{
}
DiscContent::DiscContent(u64 offset, u64 size, const u8* data)
: m_offset(offset), m_size(size), m_content_source(data)
: m_offset(offset), m_size(size), m_content_source(data)
{
}
@ -82,6 +77,11 @@ u64 DiscContent::GetOffset() const
return m_offset;
}
u64 DiscContent::GetEndOffset() const
{
return m_offset + m_size;
}
u64 DiscContent::GetSize() const
{
return m_size;
@ -120,6 +120,55 @@ bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const
return true;
}
void DiscContentContainer::Add(u64 offset, u64 size, const std::string& path)
{
if (size != 0)
m_contents.emplace(offset, size, path);
}
void DiscContentContainer::Add(u64 offset, u64 size, const u8* data)
{
if (size != 0)
m_contents.emplace(offset, size, data);
}
u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, const std::string& path)
{
const u64 size = File::GetSize(path);
Add(offset, size, path);
return size;
}
u64 DiscContentContainer::CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path)
{
const u64 size = std::min(File::GetSize(path), max_size);
Add(offset, size, path);
return size;
}
bool DiscContentContainer::Read(u64 offset, u64 length, u8* buffer) const
{
// Determine which DiscContent the offset refers to
std::set<DiscContent>::const_iterator it = m_contents.upper_bound(DiscContent(offset));
while (it != m_contents.end() && length > 0)
{
// Zero fill to start of DiscContent data
PadToAddress(it->GetOffset(), &offset, &length, &buffer);
if (!it->Read(&offset, &length, &buffer))
return false;
++it;
_dbg_assert_(DISCIO, it == m_contents.end() || it->GetOffset() >= offset);
}
// Zero fill if we went beyond the last DiscContent
std::fill_n(buffer, static_cast<size_t>(length), 0);
return true;
}
static std::optional<PartitionType> ParsePartitionDirectoryName(const std::string& name)
{
if (name.size() < 2)
@ -157,9 +206,9 @@ static bool IsDirectorySeparator(char c)
{
return c == '/'
#ifdef _WIN32
|| c == '\\'
|| c == '\\'
#endif
;
;
}
static bool PathCharactersEqual(char a, char b)
@ -186,7 +235,7 @@ static bool PathEndsWith(const std::string& path, const std::string& suffix)
}
static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* partition_root,
std::string* true_root = nullptr)
std::string* true_root = nullptr)
{
if (!PathEndsWith(dol_path, "/sys/main.dol"))
return false;
@ -205,7 +254,7 @@ static bool IsValidDirectoryBlob(const std::string& dol_path, std::string* parti
if (true_root)
{
*true_root =
dol_path.substr(0, dol_path.find_last_of(dir_separator, partition_root->size() - 2) + 1);
dol_path.substr(0, dol_path.find_last_of(dir_separator, partition_root->size() - 2) + 1);
}
return true;
@ -229,8 +278,8 @@ static bool IsInFilesDirectory(const std::string& path)
const size_t slash_before_pos = files_pos - 1;
const size_t slash_after_pos = files_pos + 5;
if ((files_pos == 0 || IsDirectorySeparator(path[slash_before_pos])) &&
(slash_after_pos == path.size() || (IsDirectorySeparator(path[slash_after_pos]))) &&
ExistsAndIsValidDirectoryBlob(path.substr(0, files_pos) + "sys/main.dol"))
(slash_after_pos == path.size() || (IsDirectorySeparator(path[slash_after_pos]))) &&
ExistsAndIsValidDirectoryBlob(path.substr(0, files_pos) + "sys/main.dol"))
{
return true;
}
@ -248,7 +297,7 @@ static bool IsMainDolForNonGamePartition(const std::string& path)
std::string partition_directory_name = partition_root.substr(true_root.size());
partition_directory_name.pop_back(); // Remove trailing slash
const std::optional<PartitionType> partition_type =
ParsePartitionDirectoryName(partition_directory_name);
ParsePartitionDirectoryName(partition_directory_name);
if (!partition_type || *partition_type == PartitionType::Game)
return false; // volume_path is the game partition's /sys/main.dol
@ -256,8 +305,8 @@ static bool IsMainDolForNonGamePartition(const std::string& path)
for (const File::FSTEntry& entry : true_root_entry.children)
{
if (entry.isDirectory &&
ParsePartitionDirectoryName(entry.virtualName) == PartitionType::Game &&
ExistsAndIsValidDirectoryBlob(entry.physicalName + "/sys/main.dol"))
ParsePartitionDirectoryName(entry.virtualName) == PartitionType::Game &&
ExistsAndIsValidDirectoryBlob(entry.physicalName + "/sys/main.dol"))
{
return true; // volume_path is the /sys/main.dol for a non-game partition
}
@ -281,7 +330,7 @@ std::unique_ptr<DirectoryBlobReader> DirectoryBlobReader::Create(const std::stri
}
DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root,
const std::string& true_root)
const std::string& true_root)
{
DirectoryBlobPartition game_partition(game_partition_root, {});
m_is_wii = game_partition.IsWii();
@ -312,7 +361,7 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root,
if (type && *type != PartitionType::Game)
{
partitions.emplace_back(DirectoryBlobPartition(entry.physicalName + "/", m_is_wii),
*type);
*type);
}
}
}
@ -322,45 +371,11 @@ DirectoryBlobReader::DirectoryBlobReader(const std::string& game_partition_root,
}
}
bool DirectoryBlobReader::ReadInternal(u64 offset, u64 length, u8* buffer,
const std::set<DiscContent>& contents)
{
if (contents.empty())
return true;
// Determine which DiscContent the offset refers to
std::set<DiscContent>::const_iterator it = contents.lower_bound(DiscContent(offset));
if (it->GetOffset() > offset && it != contents.begin())
--it;
// zero fill to start of file data
PadToAddress(it->GetOffset(), &offset, &length, &buffer);
while (it != contents.end() && length > 0)
{
_dbg_assert_(DISCIO, it->GetOffset() <= offset);
if (!it->Read(&offset, &length, &buffer))
return false;
++it;
if (it != contents.end())
{
_dbg_assert_(DISCIO, it->GetOffset() >= offset);
PadToAddress(it->GetOffset(), &offset, &length, &buffer);
}
}
return true;
}
bool DirectoryBlobReader::Read(u64 offset, u64 length, u8* buffer)
{
// TODO: We don't handle raw access to the encrypted area of Wii discs correctly.
const std::set<DiscContent>& contents =
m_is_wii ? m_nonpartition_contents : m_gamecube_pseudopartition.GetContents();
return ReadInternal(offset, length, buffer, contents);
return (m_is_wii ? m_nonpartition_contents : m_gamecube_pseudopartition.GetContents())
.Read(offset, length, buffer);
}
bool DirectoryBlobReader::SupportsReadWiiDecrypted() const
@ -377,7 +392,7 @@ bool DirectoryBlobReader::ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64
if (it == m_partitions.end())
return false;
return ReadInternal(offset, size, buffer, it->second.GetContents());
return it->second.GetContents().Read(offset, size, buffer);
}
BlobType DirectoryBlobReader::GetBlobType() const
@ -397,19 +412,19 @@ u64 DirectoryBlobReader::GetDataSize() const
}
void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector<u8>& partition_header,
const std::string& game_partition_root)
const std::string& game_partition_root)
{
constexpr u64 NONPARTITION_DISCHEADER_ADDRESS = 0;
constexpr u64 NONPARTITION_DISCHEADER_SIZE = 0x100;
m_disc_header_nonpartition.resize(NONPARTITION_DISCHEADER_SIZE);
const size_t header_bin_bytes_read =
ReadFileToVector(game_partition_root + "disc/header.bin", &m_disc_header_nonpartition);
ReadFileToVector(game_partition_root + "disc/header.bin", &m_disc_header_nonpartition);
// If header.bin is missing or smaller than expected, use the content of sys/boot.bin instead
std::copy(partition_header.data() + header_bin_bytes_read,
partition_header.data() + m_disc_header_nonpartition.size(),
m_disc_header_nonpartition.data() + header_bin_bytes_read);
partition_header.data() + m_disc_header_nonpartition.size(),
m_disc_header_nonpartition.data() + header_bin_bytes_read);
// 0x60 and 0x61 are the only differences between the partition and non-partition headers
if (header_bin_bytes_read < 0x60)
@ -417,8 +432,7 @@ void DirectoryBlobReader::SetNonpartitionDiscHeader(const std::vector<u8>& parti
if (header_bin_bytes_read < 0x61)
m_disc_header_nonpartition[0x61] = 0;
m_nonpartition_contents.emplace(NONPARTITION_DISCHEADER_ADDRESS, NONPARTITION_DISCHEADER_SIZE,
m_disc_header_nonpartition.data());
m_nonpartition_contents.Add(NONPARTITION_DISCHEADER_ADDRESS, m_disc_header_nonpartition);
}
void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_root)
@ -436,26 +450,25 @@ void DirectoryBlobReader::SetWiiRegionData(const std::string& game_partition_roo
constexpr u64 WII_REGION_DATA_ADDRESS = 0x4E000;
constexpr u64 WII_REGION_DATA_SIZE = 0x20;
m_nonpartition_contents.emplace(WII_REGION_DATA_ADDRESS, WII_REGION_DATA_SIZE,
m_wii_region_data.data());
m_nonpartition_contents.Add(WII_REGION_DATA_ADDRESS, m_wii_region_data);
}
void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partitions)
{
std::sort(partitions.begin(), partitions.end(),
[](const PartitionWithType& lhs, const PartitionWithType& rhs) {
if (lhs.type == rhs.type)
return lhs.partition.GetRootDirectory() < rhs.partition.GetRootDirectory();
[](const PartitionWithType& lhs, const PartitionWithType& rhs) {
if (lhs.type == rhs.type)
return lhs.partition.GetRootDirectory() < rhs.partition.GetRootDirectory();
// Ascending sort by partition type, except Update (1) comes before before Game (0)
return (lhs.type > PartitionType::Update || rhs.type > PartitionType::Update) ?
lhs.type < rhs.type :
lhs.type > rhs.type;
});
// Ascending sort by partition type, except Update (1) comes before before Game (0)
return (lhs.type > PartitionType::Update || rhs.type > PartitionType::Update) ?
lhs.type < rhs.type :
lhs.type > rhs.type;
});
u32 subtable_1_size = 0;
while (subtable_1_size < partitions.size() && subtable_1_size < 3 &&
partitions[subtable_1_size].type <= PartitionType::Channel)
partitions[subtable_1_size].type <= PartitionType::Channel)
{
++subtable_1_size;
}
@ -496,19 +509,18 @@ void DirectoryBlobReader::SetPartitions(std::vector<PartitionWithType>&& partiti
const u64 partition_data_size = partitions[i].partition.GetDataSize();
m_partitions.emplace(partition_address, std::move(partitions[i].partition));
const u64 unaligned_next_partition_address =
VolumeWii::PartitionOffsetToRawOffset(partition_data_size, Partition(partition_address));
VolumeWii::PartitionOffsetToRawOffset(partition_data_size, Partition(partition_address));
partition_address = Common::AlignUp(unaligned_next_partition_address, 0x10000ull);
}
m_data_size = partition_address;
m_nonpartition_contents.emplace(PARTITION_TABLE_ADDRESS, m_partition_table.size(),
m_partition_table.data());
m_nonpartition_contents.Add(PARTITION_TABLE_ADDRESS, m_partition_table);
}
// This function sets the header that's shortly before the start of the encrypted
// area, not the header that's right at the beginning of the encrypted area
void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& partition,
u64 partition_address)
u64 partition_address)
{
constexpr u32 TICKET_OFFSET = 0x0;
constexpr u32 TICKET_SIZE = 0x2a4;
@ -519,40 +531,39 @@ void DirectoryBlobReader::SetPartitionHeader(const DirectoryBlobPartition& parti
const std::string& partition_root = partition.GetRootDirectory();
AddFileToContents(&m_nonpartition_contents, partition_root + "ticket.bin",
partition_address + TICKET_OFFSET, TICKET_SIZE);
m_nonpartition_contents.CheckSizeAndAdd(partition_address + TICKET_OFFSET, TICKET_SIZE,
partition_root + "ticket.bin");
const DiscContent& tmd = AddFileToContents(&m_nonpartition_contents, partition_root + "tmd.bin",
partition_address + TMD_OFFSET, MAX_TMD_SIZE);
const u64 tmd_size = m_nonpartition_contents.CheckSizeAndAdd(
partition_address + TMD_OFFSET, MAX_TMD_SIZE, partition_root + "tmd.bin");
const u64 cert_offset = Common::AlignUp(TMD_OFFSET + tmd.GetSize(), 0x20ull);
const u64 cert_offset = Common::AlignUp(TMD_OFFSET + tmd_size, 0x20ull);
const u64 max_cert_size = H3_OFFSET - cert_offset;
const DiscContent& cert = AddFileToContents(&m_nonpartition_contents, partition_root + "cert.bin",
partition_address + cert_offset, max_cert_size);
const u64 cert_size = m_nonpartition_contents.CheckSizeAndAdd(
partition_address + cert_offset, max_cert_size, partition_root + "cert.bin");
AddFileToContents(&m_nonpartition_contents, partition_root + "h3.bin",
partition_address + H3_OFFSET, H3_SIZE);
m_nonpartition_contents.CheckSizeAndAdd(partition_address + H3_OFFSET, H3_SIZE,
partition_root + "h3.bin");
constexpr u32 PARTITION_HEADER_SIZE = 0x1c;
constexpr u32 DATA_OFFSET = 0x20000;
const u64 data_size = Common::AlignUp(partition.GetDataSize(), 0x7c00) / 0x7c00 * 0x8000;
m_partition_headers.emplace_back(PARTITION_HEADER_SIZE);
std::vector<u8>& partition_header = m_partition_headers.back();
Write32(static_cast<u32>(tmd.GetSize()), 0x0, &partition_header);
Write32(static_cast<u32>(tmd_size), 0x0, &partition_header);
Write32(TMD_OFFSET >> 2, 0x4, &partition_header);
Write32(static_cast<u32>(cert.GetSize()), 0x8, &partition_header);
Write32(static_cast<u32>(cert_size), 0x8, &partition_header);
Write32(static_cast<u32>(cert_offset >> 2), 0x0C, &partition_header);
Write32(H3_OFFSET >> 2, 0x10, &partition_header);
Write32(DATA_OFFSET >> 2, 0x14, &partition_header);
Write32(static_cast<u32>(data_size >> 2), 0x18, &partition_header);
m_nonpartition_contents.emplace(partition_address + TICKET_SIZE, PARTITION_HEADER_SIZE,
partition_header.data());
m_nonpartition_contents.Add(partition_address + TICKET_SIZE, partition_header);
}
DirectoryBlobPartition::DirectoryBlobPartition(const std::string& root_directory,
std::optional<bool> is_wii)
: m_root_directory(root_directory)
std::optional<bool> is_wii)
: m_root_directory(root_directory)
{
SetDiscHeaderAndDiscType(is_wii);
SetBI2();
@ -569,7 +580,7 @@ void DirectoryBlobPartition::SetDiscHeaderAndDiscType(std::optional<bool> is_wii
if (ReadFileToVector(boot_bin_path, &m_disc_header) < 0x20)
ERROR_LOG(DISCIO, "%s doesn't exist or is too small", boot_bin_path.c_str());
m_contents.emplace(DISCHEADER_ADDRESS, DISCHEADER_SIZE, m_disc_header.data());
m_contents.Add(DISCHEADER_ADDRESS, m_disc_header);
if (is_wii.has_value())
{
@ -600,7 +611,7 @@ void DirectoryBlobPartition::SetBI2()
if (!m_is_wii && bytes_read < 0x1C)
ERROR_LOG(DISCIO, "Couldn't read region from %s", bi2_path.c_str());
m_contents.emplace(BI2_ADDRESS, BI2_SIZE, m_bi2.data());
m_contents.Add(BI2_ADDRESS, m_bi2);
}
u64 DirectoryBlobPartition::SetApploader()
@ -617,7 +628,7 @@ u64 DirectoryBlobPartition::SetApploader()
else
{
const size_t apploader_size = 0x20 + Common::swap32(*(u32*)&m_apploader[0x14]) +
Common::swap32(*(u32*)&m_apploader[0x18]);
Common::swap32(*(u32*)&m_apploader[0x18]);
if (apploader_size != m_apploader.size())
ERROR_LOG(DISCIO, "%s is the wrong size... Is it really an apploader?", path.c_str());
else
@ -633,7 +644,7 @@ u64 DirectoryBlobPartition::SetApploader()
constexpr u64 APPLOADER_ADDRESS = 0x2440;
m_contents.emplace(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data());
m_contents.Add(APPLOADER_ADDRESS, m_apploader);
// Return DOL address, 32 byte aligned (plus 32 byte padding)
return Common::AlignUp(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull);
@ -641,13 +652,12 @@ u64 DirectoryBlobPartition::SetApploader()
u64 DirectoryBlobPartition::SetDOL(u64 dol_address)
{
const DiscContent& dol =
AddFileToContents(&m_contents, m_root_directory + "sys/main.dol", dol_address);
const u64 dol_size = m_contents.CheckSizeAndAdd(dol_address, m_root_directory + "sys/main.dol");
Write32(static_cast<u32>(dol_address >> m_address_shift), 0x0420, &m_disc_header);
// Return FST address, 32 byte aligned (plus 32 byte padding)
return Common::AlignUp(dol_address + dol.GetSize() + 0x20, 0x20ull);
return Common::AlignUp(dol_address + dol_size + 0x20, 0x20ull);
}
void DirectoryBlobPartition::BuildFST(u64 fst_address)
@ -671,11 +681,11 @@ void DirectoryBlobPartition::BuildFST(u64 fst_address)
u32 name_offset = 0; // Offset within name table
u32 root_offset = 0; // Offset of root of FST
// write root entry
// write root entry
WriteEntryData(&fst_offset, DIRECTORY_ENTRY, 0, 0, total_entries, m_address_shift);
WriteDirectory(rootEntry, &fst_offset, &name_offset, &current_data_address, root_offset,
name_table_offset);
name_table_offset);
// overflow check, compare the aligned name offset with the aligned name table size
_assert_(Common::AlignUp(name_offset, 1ull << m_address_shift) == name_table_size);
@ -685,19 +695,19 @@ void DirectoryBlobPartition::BuildFST(u64 fst_address)
Write32((u32)(m_fst_data.size() >> m_address_shift), 0x0428, &m_disc_header);
Write32((u32)(m_fst_data.size() >> m_address_shift), 0x042c, &m_disc_header);
m_contents.emplace(fst_address, m_fst_data.size(), m_fst_data.data());
m_contents.Add(fst_address, m_fst_data);
m_data_size = current_data_address;
}
void DirectoryBlobPartition::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset,
u64 data_offset, u64 length, u32 address_shift)
u64 data_offset, u64 length, u32 address_shift)
{
m_fst_data[(*entry_offset)++] = type;
m_fst_data[(*entry_offset)++] = (name_offset >> 16) & 0xff;
m_fst_data[(*entry_offset)++] = (name_offset >> 8) & 0xff;
m_fst_data[(*entry_offset)++] = (name_offset)&0xff;
m_fst_data[(*entry_offset)++] = (name_offset) & 0xff;
Write32((u32)(data_offset >> address_shift), *entry_offset, &m_fst_data);
*entry_offset += 4;
@ -707,7 +717,7 @@ void DirectoryBlobPartition::WriteEntryData(u32* entry_offset, u8 type, u32 name
}
void DirectoryBlobPartition::WriteEntryName(u32* name_offset, const std::string& name,
u64 name_table_offset)
u64 name_table_offset)
{
strncpy((char*)&m_fst_data[*name_offset + name_table_offset], name.c_str(), name.length() + 1);
@ -715,14 +725,14 @@ void DirectoryBlobPartition::WriteEntryName(u32* name_offset, const std::string&
}
void DirectoryBlobPartition::WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset,
u32* name_offset, u64* data_offset,
u32 parent_entry_index, u64 name_table_offset)
u32* name_offset, u64* data_offset,
u32 parent_entry_index, u64 name_table_offset)
{
std::vector<File::FSTEntry> sorted_entries = parent_entry.children;
// Sort for determinism
std::sort(sorted_entries.begin(), sorted_entries.end(), [](const File::FSTEntry& one,
const File::FSTEntry& two) {
const File::FSTEntry& two) {
const std::string one_upper = ASCIIToUppercase(one.virtualName);
const std::string two_upper = ASCIIToUppercase(two.virtualName);
return one_upper == two_upper ? one.virtualName < two.virtualName : one_upper < two_upper;
@ -734,7 +744,7 @@ void DirectoryBlobPartition::WriteDirectory(const File::FSTEntry& parent_entry,
{
u32 entry_index = *fst_offset / ENTRY_SIZE;
WriteEntryData(fst_offset, DIRECTORY_ENTRY, *name_offset, parent_entry_index,
entry_index + entry.size + 1, 0);
entry_index + entry.size + 1, 0);
WriteEntryName(name_offset, entry.virtualName, name_table_offset);
WriteDirectory(entry, fst_offset, name_offset, data_offset, entry_index, name_table_offset);
@ -743,25 +753,18 @@ void DirectoryBlobPartition::WriteDirectory(const File::FSTEntry& parent_entry,
{
// put entry in FST
WriteEntryData(fst_offset, FILE_ENTRY, *name_offset, *data_offset, entry.size,
m_address_shift);
m_address_shift);
WriteEntryName(name_offset, entry.virtualName, name_table_offset);
// write entry to virtual disc
auto result = m_contents.emplace(*data_offset, entry.size, entry.physicalName);
_dbg_assert_(DISCIO, result.second); // Check that this offset wasn't already occupied
m_contents.Add(*data_offset, entry.size, entry.physicalName);
// 32 KiB aligned - many games are fine with less alignment, but not all
*data_offset = Common::AlignUp(*data_offset + std::max<u64>(entry.size, 1ull), 0x8000ull);
*data_offset = Common::AlignUp(*data_offset + entry.size, 0x8000ull);
}
}
}
static const DiscContent& AddFileToContents(std::set<DiscContent>* contents,
const std::string& path, u64 offset, u64 max_size)
{
return *(contents->emplace(offset, std::min(File::GetSize(path), max_size), path).first);
}
static size_t ReadFileToVector(const std::string& path, std::vector<u8>* vector)
{
File::IOFile file(path, "rb");
@ -817,7 +820,7 @@ static void ConvertUTF8NamesToSHIFTJIS(File::FSTEntry* parent_entry)
static std::string ASCIIToUppercase(std::string str)
{
std::transform(str.begin(), str.end(), str.begin(),
[](char c) { return std::toupper(c, std::locale::classic()); });
[](char c) { return std::toupper(c, std::locale::classic()); });
return str;
}

View file

@ -15,7 +15,6 @@
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/NonCopyable.h"
#include "DiscIO/Blob.h"
namespace File
@ -43,34 +42,58 @@ public:
explicit DiscContent(u64 offset);
u64 GetOffset() const;
u64 GetEndOffset() const;
u64 GetSize() const;
bool Read(u64* offset, u64* length, u8** buffer) const;
bool operator==(const DiscContent& other) const { return m_offset == other.m_offset; }
bool operator==(const DiscContent& other) const { return GetEndOffset() == other.GetEndOffset(); }
bool operator!=(const DiscContent& other) const { return !(*this == other); }
bool operator<(const DiscContent& other) const { return m_offset < other.m_offset; }
bool operator<(const DiscContent& other) const { return GetEndOffset() < other.GetEndOffset(); }
bool operator>(const DiscContent& other) const { return other < *this; }
bool operator<=(const DiscContent& other) const { return !(*this < other); }
bool operator>=(const DiscContent& other) const { return !(*this > other); }
private:
u64 m_offset;
u64 m_size = 0;
std::string m_path;
ContentSource m_content_source;
};
// We do not allow copying, because it might mess up the pointers inside DiscContents
class DirectoryBlobPartition : private NonCopyable
class DiscContentContainer
{
public:
template <typename T>
void Add(u64 offset, const std::vector<T>& vector)
{
return Add(offset, vector.size() * sizeof(T), reinterpret_cast<const u8*>(vector.data()));
}
void Add(u64 offset, u64 size, const std::string& path);
void Add(u64 offset, u64 size, const u8* data);
u64 CheckSizeAndAdd(u64 offset, const std::string& path);
u64 CheckSizeAndAdd(u64 offset, u64 max_size, const std::string& path);
bool Read(u64 offset, u64 length, u8* buffer) const;
private:
std::set<DiscContent> m_contents;
};
class DirectoryBlobPartition
{
public:
DirectoryBlobPartition() = default;
DirectoryBlobPartition(const std::string& root_directory, std::optional<bool> is_wii);
// We do not allow copying, because it might mess up the pointers inside DiscContents
DirectoryBlobPartition(const DirectoryBlobPartition&) = delete;
DirectoryBlobPartition& operator=(const DirectoryBlobPartition&) = delete;
DirectoryBlobPartition(DirectoryBlobPartition&&) = default;
DirectoryBlobPartition& operator=(DirectoryBlobPartition&&) = default;
bool IsWii() const { return m_is_wii; }
u64 GetDataSize() const { return m_data_size; }
const std::string& GetRootDirectory() const { return m_root_directory; }
const std::vector<u8>& GetHeader() const { return m_disc_header; }
const std::set<DiscContent>& GetContents() const { return m_contents; }
const DiscContentContainer& GetContents() const { return m_contents; }
private:
void SetDiscHeaderAndDiscType(std::optional<bool> is_wii);
void SetBI2();
@ -84,12 +107,12 @@ private:
// FST creation
void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length,
u32 address_shift);
u32 address_shift);
void WriteEntryName(u32* name_offset, const std::string& name, u64 name_table_offset);
void WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, u32* name_offset,
u64* data_offset, u32 parent_entry_index, u64 name_table_offset);
u64* data_offset, u32 parent_entry_index, u64 name_table_offset);
std::set<DiscContent> m_contents;
DiscContentContainer m_contents;
std::vector<u8> m_disc_header;
std::vector<u8> m_bi2;
std::vector<u8> m_apploader;
@ -103,12 +126,17 @@ private:
u64 m_data_size;
};
// We do not allow copying, because it might mess up the pointers inside DiscContents
class DirectoryBlobReader : public BlobReader, private NonCopyable
class DirectoryBlobReader : public BlobReader
{
public:
static std::unique_ptr<DirectoryBlobReader> Create(const std::string& dol_path);
// We do not allow copying, because it might mess up the pointers inside DiscContents
DirectoryBlobReader(const DirectoryBlobReader&) = delete;
DirectoryBlobReader& operator=(const DirectoryBlobReader&) = delete;
DirectoryBlobReader(DirectoryBlobReader&&) = default;
DirectoryBlobReader& operator=(DirectoryBlobReader&&) = default;
bool Read(u64 offset, u64 length, u8* buffer) override;
bool SupportsReadWiiDecrypted() const override;
bool ReadWiiDecrypted(u64 offset, u64 size, u8* buffer, u64 partition_offset) override;
@ -121,7 +149,7 @@ private:
struct PartitionWithType
{
PartitionWithType(DirectoryBlobPartition&& partition_, PartitionType type_)
: partition(std::move(partition_)), type(type_)
: partition(std::move(partition_)), type(type_)
{
}
@ -130,12 +158,10 @@ private:
};
explicit DirectoryBlobReader(const std::string& game_partition_root,
const std::string& true_root);
bool ReadInternal(u64 offset, u64 length, u8* buffer, const std::set<DiscContent>& contents);
const std::string& true_root);
void SetNonpartitionDiscHeader(const std::vector<u8>& partition_header,
const std::string& game_partition_root);
const std::string& game_partition_root);
void SetWiiRegionData(const std::string& game_partition_root);
void SetPartitions(std::vector<PartitionWithType>&& partitions);
void SetPartitionHeader(const DirectoryBlobPartition& partition, u64 partition_address);
@ -144,7 +170,7 @@ private:
DirectoryBlobPartition m_gamecube_pseudopartition;
// For Wii:
std::set<DiscContent> m_nonpartition_contents;
DiscContentContainer m_nonpartition_contents;
std::map<u64, DirectoryBlobPartition> m_partitions;
bool m_is_wii;

View file

@ -28,12 +28,12 @@ std::string DirectoryNameForPartitionType(u32 partition_type)
case 2:
return "CHANNEL";
default:
const std::string type_as_game_id{static_cast<char>((partition_type >> 24) & 0xFF),
static_cast<char>((partition_type >> 16) & 0xFF),
static_cast<char>((partition_type >> 8) & 0xFF),
static_cast<char>(partition_type & 0xFF)};
const std::string type_as_game_id{ static_cast<char>((partition_type >> 24) & 0xFF),
static_cast<char>((partition_type >> 16) & 0xFF),
static_cast<char>((partition_type >> 8) & 0xFF),
static_cast<char>(partition_type & 0xFF) };
if (std::all_of(type_as_game_id.cbegin(), type_as_game_id.cend(),
[](char c) { return std::isprint(c, std::locale::classic()); }))
[](char c) { return std::isprint(c, std::locale::classic()); }))
{
return "P-" + type_as_game_id;
}
@ -43,7 +43,7 @@ std::string DirectoryNameForPartitionType(u32 partition_type)
}
u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
u8* buffer, u64 max_buffer_size, u64 offset_in_file)
u8* buffer, u64 max_buffer_size, u64 offset_in_file)
{
if (!file_info || file_info->IsDirectory() || offset_in_file >= file_info->GetSize())
return 0;
@ -51,9 +51,9 @@ u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* f
const u64 read_length = std::min(max_buffer_size, file_info->GetSize() - offset_in_file);
DEBUG_LOG(DISCIO, "Reading %" PRIx64 " bytes at %" PRIx64 " from file %s. Offset: %" PRIx64
" Size: %" PRIx32,
read_length, offset_in_file, file_info->GetPath().c_str(), file_info->GetOffset(),
file_info->GetSize());
" Size: %" PRIx32,
read_length, offset_in_file, file_info->GetPath().c_str(), file_info->GetOffset(),
file_info->GetSize());
if (!volume.Read(file_info->GetOffset() + offset_in_file, read_length, buffer, partition))
return 0;
@ -62,7 +62,7 @@ u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* f
}
bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size,
const std::string& export_filename)
const std::string& export_filename)
{
File::IOFile f(export_filename, "wb");
if (!f)
@ -89,19 +89,19 @@ bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u6
}
bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info,
const std::string& export_filename)
const std::string& export_filename)
{
if (!file_info || file_info->IsDirectory())
return false;
return ExportData(volume, partition, file_info->GetOffset(), file_info->GetSize(),
export_filename);
export_filename);
}
void ExportDirectory(const Volume& volume, const Partition partition, const FileInfo& directory,
bool recursive, const std::string& filesystem_path,
const std::string& export_folder,
const std::function<bool(const std::string& path)>& update_progress)
bool recursive, const std::string& filesystem_path,
const std::string& export_folder,
const std::function<bool(const std::string& path)>& update_progress)
{
File::CreateFullPath(export_folder + '/');
@ -147,7 +147,7 @@ bool ExportWiiRegionData(const Volume& volume, const std::string& export_filenam
}
bool ExportTicket(const Volume& volume, const Partition& partition,
const std::string& export_filename)
const std::string& export_filename)
{
if (volume.GetVolumeType() != Platform::WII_DISC)
return false;
@ -162,22 +162,22 @@ bool ExportTMD(const Volume& volume, const Partition& partition, const std::stri
const std::optional<u32> size = volume.ReadSwapped<u32>(partition.offset + 0x2a4, PARTITION_NONE);
const std::optional<u64> offset =
volume.ReadSwappedAndShifted(partition.offset + 0x2a8, PARTITION_NONE);
volume.ReadSwappedAndShifted(partition.offset + 0x2a8, PARTITION_NONE);
if (!size || !offset)
return false;
return ExportData(volume, PARTITION_NONE, *offset, *size, export_filename);
return ExportData(volume, PARTITION_NONE, partition.offset + *offset, *size, export_filename);
}
bool ExportCertificateChain(const Volume& volume, const Partition& partition,
const std::string& export_filename)
const std::string& export_filename)
{
if (volume.GetVolumeType() != Platform::WII_DISC)
return false;
const std::optional<u32> size = volume.ReadSwapped<u32>(partition.offset + 0x2ac, PARTITION_NONE);
const std::optional<u64> offset =
volume.ReadSwappedAndShifted(partition.offset + 0x2b0, PARTITION_NONE);
volume.ReadSwappedAndShifted(partition.offset + 0x2b0, PARTITION_NONE);
if (!size || !offset)
return false;
@ -185,13 +185,13 @@ bool ExportCertificateChain(const Volume& volume, const Partition& partition,
}
bool ExportH3Hashes(const Volume& volume, const Partition& partition,
const std::string& export_filename)
const std::string& export_filename)
{
if (volume.GetVolumeType() != Platform::WII_DISC)
return false;
const std::optional<u64> offset =
volume.ReadSwappedAndShifted(partition.offset + 0x2b4, PARTITION_NONE);
volume.ReadSwappedAndShifted(partition.offset + 0x2b4, PARTITION_NONE);
if (!offset)
return false;
@ -199,7 +199,7 @@ bool ExportH3Hashes(const Volume& volume, const Partition& partition,
}
bool ExportHeader(const Volume& volume, const Partition& partition,
const std::string& export_filename)
const std::string& export_filename)
{
if (!IsDisc(volume.GetVolumeType()))
return false;
@ -208,7 +208,7 @@ bool ExportHeader(const Volume& volume, const Partition& partition,
}
bool ExportBI2Data(const Volume& volume, const Partition& partition,
const std::string& export_filename)
const std::string& export_filename)
{
if (!IsDisc(volume.GetVolumeType()))
return false;
@ -217,7 +217,7 @@ bool ExportBI2Data(const Volume& volume, const Partition& partition,
}
bool ExportApploader(const Volume& volume, const Partition& partition,
const std::string& export_filename)
const std::string& export_filename)
{
if (!IsDisc(volume.GetVolumeType()))
return false;
@ -319,7 +319,7 @@ bool ExportFST(const Volume& volume, const Partition& partition, const std::stri
}
bool ExportSystemData(const Volume& volume, const Partition& partition,
const std::string& export_folder)
const std::string& export_folder)
{
bool success = true;

View file

@ -27,22 +27,22 @@ namespace DiscIO
{
constexpr u32 FST_ENTRY_SIZE = 4 * 3; // An FST entry consists of three 32-bit integers
// Set everything manually.
// Set everything manually.
FileInfoGCWii::FileInfoGCWii(const u8* fst, u8 offset_shift, u32 index, u32 total_file_infos)
: m_fst(fst), m_offset_shift(offset_shift), m_index(index), m_total_file_infos(total_file_infos)
: m_fst(fst), m_offset_shift(offset_shift), m_index(index), m_total_file_infos(total_file_infos)
{
}
// For the root object only.
// m_fst and m_index must be correctly set before GetSize() is called!
FileInfoGCWii::FileInfoGCWii(const u8* fst, u8 offset_shift)
: m_fst(fst), m_offset_shift(offset_shift), m_index(0), m_total_file_infos(GetSize())
: m_fst(fst), m_offset_shift(offset_shift), m_index(0), m_total_file_infos(GetSize())
{
}
// Copy data that is common to the whole file system.
FileInfoGCWii::FileInfoGCWii(const FileInfoGCWii& file_info, u32 index)
: FileInfoGCWii(file_info.m_fst, file_info.m_offset_shift, index, file_info.m_total_file_infos)
: FileInfoGCWii(file_info.m_fst, file_info.m_offset_shift, index, file_info.m_total_file_infos)
{
}
@ -82,7 +82,7 @@ FileInfo::const_iterator FileInfoGCWii::end() const
u32 FileInfoGCWii::Get(EntryProperty entry_property) const
{
return Common::swap32(m_fst + FST_ENTRY_SIZE * m_index +
sizeof(u32) * static_cast<int>(entry_property));
sizeof(u32) * static_cast<int>(entry_property));
}
u32 FileInfoGCWii::GetSize() const
@ -108,7 +108,7 @@ u32 FileInfoGCWii::GetTotalChildren() const
u64 FileInfoGCWii::GetNameOffset() const
{
return static_cast<u64>(FST_ENTRY_SIZE) * m_total_file_infos +
(Get(EntryProperty::NAME_OFFSET) & 0xFFFFFF);
(Get(EntryProperty::NAME_OFFSET) & 0xFFFFFF);
}
std::string FileInfoGCWii::GetName() const
@ -136,7 +136,7 @@ std::string FileInfoGCWii::GetPath() const
// because the root directory at index 0 contains all files.
FileInfoGCWii potential_parent(*this, m_index - 1);
while (!(potential_parent.IsDirectory() &&
potential_parent.Get(EntryProperty::FILE_SIZE) > m_index))
potential_parent.Get(EntryProperty::FILE_SIZE) > m_index))
{
potential_parent = FileInfoGCWii(*this, potential_parent.m_index - 1);
}
@ -185,7 +185,7 @@ bool FileInfoGCWii::IsValid(u64 fst_size, const FileInfoGCWii& parent_directory)
}
FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partition)
: FileSystem(volume, partition), m_valid(false), m_root(nullptr, 0, 0, 0)
: FileSystem(volume, partition), m_valid(false), m_root(nullptr, 0, 0, 0)
{
u8 offset_shift;
// Check if this is a GameCube or Wii disc
@ -266,7 +266,7 @@ std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(const std::string& path)
}
std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(const std::string& path,
const FileInfo& file_info) const
const FileInfo& file_info) const
{
// Given a path like "directory1/directory2/fileA.bin", this function will
// find directory1 and then call itself to search for "directory2/fileA.bin".
@ -309,7 +309,11 @@ std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(u64 disc_offset) const
{
FileInfoGCWii file_info(m_root, i);
if (!file_info.IsDirectory())
m_offset_file_info_cache.emplace(file_info.GetOffset() + file_info.GetSize(), i);
{
const u32 size = file_info.GetSize();
if (size != 0)
m_offset_file_info_cache.emplace(file_info.GetOffset() + size, i);
}
}
}

View file

@ -73,7 +73,7 @@ void AdvancedWidget::CreateWidgets()
utility_layout->addWidget(m_dump_efb_target, 2, 0);
utility_layout->addWidget(m_enable_freelook, 2, 1);
#if defined(HAVE_FFMPEG)
utility_layout->addWidget(m_dump_use_ffv1, 3, -1);
utility_layout->addWidget(m_dump_use_ffv1, 3, 0);
#endif
// Misc.

View file

@ -69,7 +69,6 @@ QGroupBox* InfoWidget::CreateBannerDetails()
m_long_maker = CreateValueDisplay();
m_description = new QTextEdit();
m_description->setReadOnly(true);
QWidget* banner = CreateBannerGraphic();
CreateLanguageSelector();
layout->addRow(tr("Show Language:"), m_language_selector);
@ -85,7 +84,11 @@ QGroupBox* InfoWidget::CreateBannerDetails()
{
layout->addRow(tr("Name:"), m_long_name);
}
layout->addRow(tr("Banner:"), banner);
if (!m_game.GetBanner().isNull())
{
layout->addRow(tr("Banner:"), CreateBannerGraphic());
}
group->setLayout(layout);
return group;

View file

@ -12,7 +12,8 @@
PropertiesDialog::PropertiesDialog(QWidget* parent, const GameFile& game) : QDialog(parent)
{
setWindowTitle(QStringLiteral("%1: %2").arg(game.GetGameID()).arg(game.GetLongName()));
setWindowTitle(
QStringLiteral("%1: %2 - %3").arg(game.GetFileName(), game.GetGameID(), game.GetLongName()));
QVBoxLayout* layout = new QVBoxLayout();
QTabWidget* tab_widget = new QTabWidget(this);

View file

@ -5,6 +5,7 @@
#include <QCryptographicHash>
#include <QDataStream>
#include <QDir>
#include <QFileInfo>
#include <QImage>
#include <QSharedPointer>
@ -82,7 +83,7 @@ QString GameFile::GetCacheFileName() const
// files with the same names in different folders.
QString hash =
QString::fromUtf8(QCryptographicHash::hash(m_path.toUtf8(), QCryptographicHash::Md5).toHex());
return folder + m_file_name + hash;
return folder + GetFileName() + hash;
}
void GameFile::ReadBanner(const DiscIO::Volume& volume)
@ -99,8 +100,6 @@ void GameFile::ReadBanner(const DiscIO::Volume& volume)
if (!banner.isNull())
m_banner = QPixmap::fromImage(banner);
else
m_banner = Resources::GetMisc(Resources::BANNER_MISSING);
}
bool GameFile::LoadFileInfo(const QString& path)
@ -109,9 +108,6 @@ bool GameFile::LoadFileInfo(const QString& path)
if (!info.exists() || !info.isReadable())
return false;
m_file_name = info.fileName();
m_extension = info.suffix();
m_folder = info.dir().dirName();
m_last_modified = info.lastModified();
m_size = info.size();
@ -129,7 +125,8 @@ void GameFile::LoadState()
bool GameFile::IsElfOrDol()
{
return m_extension == QStringLiteral("elf") || m_extension == QStringLiteral("dol");
QString extension = GetFileExtension();
return extension == QStringLiteral("elf") || extension == QStringLiteral("dol");
}
bool GameFile::TryLoadCache()
@ -192,13 +189,11 @@ bool GameFile::TryLoadElfDol()
return false;
m_revision = 0;
m_long_names[DiscIO::Language::LANGUAGE_ENGLISH] = m_file_name;
m_platform = DiscIO::Platform::ELF_DOL;
m_region = DiscIO::Region::UNKNOWN_REGION;
m_country = DiscIO::Country::COUNTRY_UNKNOWN;
m_blob_type = DiscIO::BlobType::DIRECTORY;
m_raw_size = m_size;
m_banner = Resources::GetMisc(Resources::BANNER_MISSING);
m_rating = 0;
return true;
@ -209,6 +204,21 @@ void GameFile::SaveCache()
// TODO
}
QString GameFile::GetFileName() const
{
return QFileInfo(m_path).fileName();
}
QString GameFile::GetFileExtension() const
{
return QFileInfo(m_path).suffix();
}
QString GameFile::GetFileFolder() const
{
return QFileInfo(m_path).dir().dirName();
}
QString GameFile::GetBannerString(const QMap<DiscIO::Language, QString>& m) const
{
// Try the settings language, then English, then just pick one.

View file

@ -30,9 +30,9 @@ public:
bool IsValid() const;
// These will be properly initialized before we try to load the file.
QString GetFilePath() const { return m_path; }
QString GetFileName() const { return m_file_name; }
QString GetFileExtension() const { return m_extension; }
QString GetFileFolder() const { return m_folder; }
QString GetFileName() const;
QString GetFileExtension() const;
QString GetFileFolder() const;
qint64 GetFileSize() const { return m_size; }
// The rest will not.
QString GetGameID() const { return m_game_id; }
@ -88,9 +88,6 @@ private:
bool m_valid;
QString m_path;
QString m_file_name;
QString m_extension;
QString m_folder;
QDateTime m_last_modified;
qint64 m_size = 0;
@ -105,7 +102,6 @@ private:
QMap<DiscIO::Language, QString> m_short_makers;
QMap<DiscIO::Language, QString> m_long_makers;
QMap<DiscIO::Language, QString> m_descriptions;
QString m_company;
u8 m_disc_number = 0;
DiscIO::Region m_region;
DiscIO::Platform m_platform;

View file

@ -49,8 +49,6 @@ GameList::GameList(QWidget* parent) : QStackedWidget(parent)
connect(m_list, &QTableView::doubleClicked, this, &GameList::GameSelected);
connect(m_grid, &QListView::doubleClicked, this, &GameList::GameSelected);
connect(&Settings::Instance(), &Settings::PathAdded, m_model, &GameListModel::DirectoryAdded);
connect(&Settings::Instance(), &Settings::PathRemoved, m_model, &GameListModel::DirectoryRemoved);
connect(m_model, &QAbstractItemModel::rowsInserted, this, &GameList::ConsiderViewChange);
connect(m_model, &QAbstractItemModel::rowsRemoved, this, &GameList::ConsiderViewChange);

View file

@ -14,8 +14,11 @@ GameListModel::GameListModel(QObject* parent) : QAbstractTableModel(parent)
{
connect(&m_tracker, &GameTracker::GameLoaded, this, &GameListModel::UpdateGame);
connect(&m_tracker, &GameTracker::GameRemoved, this, &GameListModel::RemoveGame);
connect(this, &GameListModel::DirectoryAdded, &m_tracker, &GameTracker::AddDirectory);
connect(this, &GameListModel::DirectoryRemoved, &m_tracker, &GameTracker::RemoveDirectory);
connect(&Settings::Instance(), &Settings::PathAdded, &m_tracker, &GameTracker::AddDirectory);
connect(&Settings::Instance(), &Settings::PathRemoved, &m_tracker, &GameTracker::RemoveDirectory);
for (const QString& dir : Settings::Instance().GetPaths())
m_tracker.AddDirectory(dir);
connect(&Settings::Instance(), &Settings::ThemeChanged, [this] {
// Tell the view to repaint. The signal 'dataChanged' also seems like it would work here, but
@ -60,6 +63,8 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
// GameCube banners are 96x32, but Wii banners are 192x64.
// TODO: use custom banners from rom directory like DolphinWX?
QPixmap banner = game->GetBanner();
if (banner.isNull())
banner = Resources::GetMisc(Resources::BANNER_MISSING);
banner.setDevicePixelRatio(std::max(banner.width() / GAMECUBE_BANNER_SIZE.width(),
banner.height() / GAMECUBE_BANNER_SIZE.height()));
return banner;
@ -73,7 +78,10 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
Core::TitleDatabase::TitleType::Channel :
Core::TitleDatabase::TitleType::Other));
if (display_name.isEmpty())
return game->GetLongName();
display_name = game->GetLongName();
if (display_name.isEmpty())
display_name = game->GetFileName();
return display_name;
}
@ -200,19 +208,22 @@ QSharedPointer<GameFile> GameListModel::GetGameFile(int index) const
return m_games[index];
}
void GameListModel::UpdateGame(QSharedPointer<GameFile> game)
void GameListModel::UpdateGame(const QSharedPointer<GameFile>& game)
{
QString path = game->GetFilePath();
int entry = FindGame(path);
if (entry < 0)
entry = m_games.size();
int index = FindGame(path);
if (index < 0)
{
beginInsertRows(QModelIndex(), m_games.size(), m_games.size());
m_games.push_back(game);
endInsertRows();
}
else
return;
beginInsertRows(QModelIndex(), entry, entry);
m_games.insert(entry, game);
endInsertRows();
{
m_games[index] = game;
emit dataChanged(createIndex(index, 0), createIndex(index + 1, columnCount(QModelIndex())));
}
}
void GameListModel::RemoveGame(const QString& path)

View file

@ -45,13 +45,9 @@ public:
NUM_COLS
};
void UpdateGame(QSharedPointer<GameFile> game);
void UpdateGame(const QSharedPointer<GameFile>& game);
void RemoveGame(const QString& path);
signals:
void DirectoryAdded(const QString& dir);
void DirectoryRemoved(const QString& dir);
private:
// Index in m_games, or -1 if it isn't found
int FindGame(const QString& path) const;

View file

@ -17,26 +17,11 @@ static const QStringList game_filters{
GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent)
{
m_loader = new GameLoader;
m_loader->moveToThread(&m_loader_thread);
qRegisterMetaType<QSharedPointer<GameFile>>();
connect(&m_loader_thread, &QThread::finished, m_loader, &QObject::deleteLater);
connect(this, &QFileSystemWatcher::directoryChanged, this, &GameTracker::UpdateDirectory);
connect(this, &QFileSystemWatcher::fileChanged, this, &GameTracker::UpdateFile);
connect(this, &GameTracker::PathChanged, m_loader, &GameLoader::LoadGame);
connect(m_loader, &GameLoader::GameLoaded, this, &GameTracker::GameLoaded);
m_loader_thread.start();
for (QString dir : Settings::Instance().GetPaths())
AddDirectory(dir);
}
GameTracker::~GameTracker()
{
m_loader_thread.quit();
m_loader_thread.wait();
m_load_thread.Reset([this](const QString& path) { LoadGame(path); });
}
void GameTracker::AddDirectory(const QString& dir)
@ -84,7 +69,7 @@ void GameTracker::UpdateDirectory(const QString& dir)
{
addPath(path);
m_tracked_files[path] = QSet<QString>{dir};
emit PathChanged(path);
m_load_thread.EmplaceItem(path);
}
}
@ -130,7 +115,7 @@ void GameTracker::UpdateFile(const QString& file)
GameRemoved(file);
addPath(file);
emit PathChanged(file);
m_load_thread.EmplaceItem(file);
}
else if (removePath(file))
{
@ -139,7 +124,7 @@ void GameTracker::UpdateFile(const QString& file)
}
}
void GameLoader::LoadGame(const QString& path)
void GameTracker::LoadGame(const QString& path)
{
if (!DiscIO::ShouldHideFromGameList(path.toStdString()))
{

View file

@ -9,25 +9,19 @@
#include <QSet>
#include <QSharedPointer>
#include <QString>
#include <QStringList>
#include <QThread>
#include "Common/WorkQueueThread.h"
#include "DolphinQt2/GameList/GameFile.h"
class GameLoader;
// Watches directories and loads GameFiles in a separate thread.
// To use this, just add directories using AddDirectory, and listen for the
// GameLoaded and GameRemoved signals. Ignore the PathChanged signal, it's
// only there because the Qt people made fileChanged and directoryChanged
// private.
// GameLoaded and GameRemoved signals.
class GameTracker final : public QFileSystemWatcher
{
Q_OBJECT
public:
explicit GameTracker(QObject* parent = nullptr);
~GameTracker();
void AddDirectory(const QString& dir);
void RemoveDirectory(const QString& dir);
@ -36,28 +30,15 @@ signals:
void GameLoaded(QSharedPointer<GameFile> game);
void GameRemoved(const QString& path);
void PathChanged(const QString& path);
private:
void LoadGame(const QString& path);
void UpdateDirectory(const QString& dir);
void UpdateFile(const QString& path);
QSet<QString> FindMissingFiles(const QString& dir);
// game path -> directories that track it
QMap<QString, QSet<QString>> m_tracked_files;
QThread m_loader_thread;
GameLoader* m_loader;
};
class GameLoader final : public QObject
{
Q_OBJECT
public:
void LoadGame(const QString& path);
signals:
void GameLoaded(QSharedPointer<GameFile> game);
Common::WorkQueueThread<QString> m_load_thread;
};
Q_DECLARE_METATYPE(QSharedPointer<GameFile>)

View file

@ -9,8 +9,6 @@
#include <QObject>
#include <QVector>
#include "Common/NonCopyable.h"
#include "Core/NetPlayClient.h"
#include "Core/NetPlayServer.h"
@ -23,11 +21,16 @@ class GameListModel;
class InputConfig;
// UI settings to be stored in the config directory.
class Settings final : public QObject, NonCopyable
class Settings final : public QObject
{
Q_OBJECT
public:
Settings(const Settings&) = delete;
Settings& operator=(const Settings&) = delete;
Settings(Settings&&) = delete;
Settings& operator=(Settings&&) = delete;
static Settings& Instance();
// UI

View file

@ -203,8 +203,9 @@ void AdvancedConfigPane::UpdateCPUClock()
int percent = static_cast<int>(std::round(SConfig::GetInstance().m_OCFactor * 100.f));
int clock = static_cast<int>(std::round(SConfig::GetInstance().m_OCFactor * core_clock));
m_clock_override_text->SetLabel(
SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d MHz)", percent, clock) : wxString(""));
m_clock_override_text->SetLabel(SConfig::GetInstance().m_OCEnable ?
wxString::Format("%d %% (%d MHz)", percent, clock) :
wxString());
}
void AdvancedConfigPane::LoadCustomRTC()

View file

@ -352,15 +352,15 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
ProgramShaderCache::CompileShader(m_EfbPokes,
StringFromFormat(
"in vec2 rawpos;\n"
"in vec4 color0;\n" // color
"in int color1;\n" // depth
"in vec4 rawcolor0;\n" // color
"in int rawcolor1;\n" // depth
"out vec4 v_c;\n"
"out float v_z;\n"
"void main(void) {\n"
" gl_Position = vec4(((rawpos + 0.5) / vec2(640.0, 528.0) * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);\n"
" gl_PointSize = %d.0 / 640.0;\n"
" v_c = color0.bgra;\n"
" v_z = float(color1 & 0xFFFFFF) / 16777216.0;\n"
" v_c = rawcolor0.bgra;\n"
" v_z = float(rawcolor1 & 0xFFFFFF) / 16777216.0;\n"
"}\n", m_targetWidth).c_str(),
StringFromFormat(

View file

@ -13,12 +13,17 @@
namespace OGL
{
class SamplerCache : NonCopyable
class SamplerCache
{
public:
SamplerCache();
~SamplerCache();
SamplerCache(const SamplerCache&) = delete;
SamplerCache& operator=(const SamplerCache&) = delete;
SamplerCache(SamplerCache&&) = delete;
SamplerCache& operator=(SamplerCache&&) = delete;
void SetSamplerState(u32 stage, const TexMode0& tm0, const TexMode1& tm1, bool custom_tex);
void Clear();
void BindNearestSampler(u32 stage);

View file

@ -765,12 +765,6 @@ namespace TexDecoder
// Decodes all known Gamecube/Wii texture formats.
// by ector
bool IsCompressed(HostTextureFormat format)
{
return format >= PC_TEX_FMT_DXT1 && format <= PC_TEX_FMT_BPTC;
}
s32 GetTexelSizeInNibbles(s32 format)
{
switch (format & 0x3f) {

View file

@ -6,7 +6,6 @@
#pragma once
#include <limits>
#include "Common/NonCopyable.h"
#include "Common/Swap.h"
#include "VideoCommon/CPMemory.h"
@ -145,12 +144,15 @@ struct PortableVertexDeclaration
// Note that this class can't just invent arbitrary vertex formats out of its input -
// all the data loading code must always be made compatible.
class NativeVertexFormat : NonCopyable
class NativeVertexFormat
{
public:
virtual ~NativeVertexFormat()
{}
NativeVertexFormat(const NativeVertexFormat&) = delete;
NativeVertexFormat& operator=(const NativeVertexFormat&) = delete;
NativeVertexFormat(NativeVertexFormat&&) = default;
NativeVertexFormat& operator=(NativeVertexFormat&&) = default;
virtual void SetupVertexPointers() = 0;
u32 GetVertexStride() const

View file

@ -778,10 +778,8 @@ bool Renderer::IsFrameDumping()
if (m_screenshot_request.IsSet())
return true;
#if defined(HAVE_LIBAV) || defined(_WIN32)
if (SConfig::GetInstance().m_DumpFrames)
return true;
#endif
ShutdownFrameDumping();
return false;

View file

@ -114,7 +114,10 @@ enum HostTextureFormat
namespace TexDecoder
{
bool IsCompressed(HostTextureFormat format);
static inline bool IsCompressed(HostTextureFormat format)
{
return format >= PC_TEX_FMT_DXT1 && format <= PC_TEX_FMT_BPTC;
}
u32 GetTexelSizeInNibbles(u32 format);
u32 GetTextureSizeInBytes(u32 width, u32 height, u32 format);
u32 GetBlockWidthInTexels(u32 format);
@ -129,4 +132,4 @@ void DecodeTexel(u8 *dst, const u8 *src, u32 s, u32 t, u32 imageWidth, u32 texfo
void DecodeTexelRGBA8FromTmem(u8 *dst, const u8 *src_ar, const u8* src_gb, u32 s, u32 t, u32 imageWidth);
void DecodeTexelBGRA8FromTmem(u8 *dst, const u8 *src_ar, const u8* src_gb, u32 s, u32 t, u32 imageWidth);
void SetTexFmtOverlayOptions(bool enable, bool center);
}
}

View file

@ -775,12 +775,6 @@ namespace TexDecoder
// Decodes all known Gamecube/Wii texture formats.
// by ector
bool IsCompressed(HostTextureFormat format)
{
return format >= PC_TEX_FMT_DXT1 && format <= PC_TEX_FMT_BPTC;
}
u32 GetTexelSizeInNibbles(u32 format)
{
switch (format & 0x3f)
@ -3322,4 +3316,4 @@ HostTextureFormat DecodeBGRA8FromTmem(u32* dst, const u8 *src_ar, const u8 *src_
}
return PC_TEX_FMT_BGRA32;
}
}
}