30 Commits
Author SHA1 Message Date
ExzapandGitHub 61a3b07697 Merge pull request #238 from Fs00/more-translations
More l10n improvements and add workflow to generate POT file
2022-09-14 22:49:14 +02:00
Crementif 6cf5dc9a56 Add matrix server for non-discord chatting
Fixes https://github.com/cemu-project/Cemu/issues/113
2022-09-11 16:56:51 +02:00
ExzapandGitHub 0afa2d75aa CI: build.yml no longer invokes itself, always produce artifact (#243)
- Build check is now a separate workflow
- Build with release config instead of debug
- Upload artifacts
2022-09-11 06:41:19 +02:00
capitalistsandGitHub b5963afbb5 Fix DSUController socket option error on Linux (#234) 2022-09-11 04:20:40 +02:00
SSimcoandGitHub 9a60979242 Linux: Avoid out-of-bounds raw keycode array access (#226) 2022-09-11 02:00:02 +02:00
capitalistsandGitHub d4879da95c Implement analog triggers for DSUController (#239) 2022-09-11 01:32:17 +02:00
Fs00 b47b38448c Add workflow for generating POT file 2022-09-10 19:17:14 +02:00
Fs00 694b9ec495 Avoid including newlines in localizable string 2022-09-10 18:47:32 +02:00
Fs00 08db65bd5a Remove some dead code 2022-09-10 18:47:32 +02:00
Fs00 13aa0a4fd0 Make controller button names translatable and deduplicate code 2022-09-10 18:47:27 +02:00
Fs00 4c6f22ba39 Simplify a few window names 2022-09-10 13:55:37 +02:00
ExzapandGitHub 3349d7b424 Merge pull request #231 from Exzap/main
FSC: Replace wstring paths with utf8 encoded strings + misc clean up
2022-09-10 00:48:20 +02:00
Exzap 680beaaf21 Rename path _utf8Wrapper to _utf8ToPath for better clarity 2022-09-09 23:49:38 +02:00
Exzap 168ecf8825 FSC: Use utf8 path strings instead of wchar
Also introduced helper function _utf8ToPath() to convert a utf8-encoded string to fs::path
2022-09-09 23:49:38 +02:00
Exzap 1ce629126a FSC: Refactor FileTree and remove redundant path parser class 2022-09-09 23:49:38 +02:00
Exzap b8462cec8b FSC: Refactor to use FSCPath instead of legacy code 2022-09-09 23:49:38 +02:00
Exzap 0e0602e8d9 FSC: Use utf8 for mounting and internal target path 2022-09-09 23:49:38 +02:00
SSimcoandGitHub cf598e38c1 Linux: Find case-insensitive file/folder path if not found (#196) 2022-09-09 20:16:46 +02:00
uranuspucksaxophoneandGitHub 6dda53e84f Improve docs (#216) 2022-09-09 18:39:23 +02:00
goeiecool9999andGitHub 045a059742 fix for when file open is successful but the path isn't a file (#220)
FSC and indirectly coreinit relies on FileStream open failing for directories
2022-09-09 16:10:12 +02:00
TotalCaesar659andGitHub 76313fc238 Update bug tracker URL to use HTTPS (#211) 2022-09-08 23:52:45 +02:00
ExzapandGitHub 1e851fe7e2 Latte: Fix infinite loop in special state clearAsDepth() (#209)
This broke while refactoring code for the 2.0 release. Resolves Tokyo Mirage Session and Pokken freezing on boot. Probably also affects some other games

Also updated .gitignore
2022-09-08 17:33:31 +02:00
Timothy RedaelliandGitHub f032088902 Use _Exit instead of exit under Linux (#204)
The best ExitProcess alternative for Linux is _Exit since it doesn't
call exit handlers.
2022-09-08 17:05:31 +02:00
Tom LallyandGitHub 6cdb6eed17 Cleanup udiv128 (#206) 2022-09-08 02:12:53 +02:00
bitscherandGitHub 4eaa600b57 Fix various compiler warnings given by Clang (#170) 2022-09-07 20:04:32 +02:00
bslhqandGitHub 4d1be950e3 Fix various issues related to title names (#192)
Fixed various issues related to title names:
1. If console language is set to non-English, the title names in Title Manager may be empty.
2. Game list do not show custom names if list style set to icon or small icon.
3. Custom title names for some languages (like JP or CN) appear confusing if re-edited.
4. Unexpected overrides of variable values in ParsedMetaXml.h
2022-09-07 19:58:56 +02:00
Jun Bo BiandGitHub b752d2eddd fix clang-cl (#202) 2022-09-07 18:22:40 +02:00
Timothy RedaelliandGitHub 0a1985e481 Set timer milliseconds for "Controller settings" (#194)
This is needed to avoid having the Controller settings window black on Linux
2022-09-07 16:54:48 +02:00
goeiecool9999andGitHub e20bfd00ec Separate filestream.h into OS specific implementation files (#190) 2022-09-07 02:42:25 +02:00
Tom LallyandGitHub f8b5024c09 Improved macro clarity. (#188) 2022-09-07 02:27:52 +02:00
98 changed files with 1242 additions and 1450 deletions
-12
View File
@@ -1,18 +1,6 @@
name: Build Cemu
on:
pull_request:
paths-ignore:
- "*.md"
types:
- opened
- synchronize
- reopened
push:
paths-ignore:
- "*.md"
branches:
- main
workflow_call:
inputs:
deploymode:
+21
View File
@@ -0,0 +1,21 @@
name: Build check
on:
pull_request:
paths-ignore:
- "*.md"
types:
- opened
- synchronize
- reopened
push:
paths-ignore:
- "*.md"
branches:
- main
jobs:
build:
uses: ./.github/workflows/build.yml
with:
deploymode: release
experimentalversion: 999999
+42
View File
@@ -0,0 +1,42 @@
name: Generate translation template
on:
pull_request:
paths-ignore:
- "*.md"
types:
- opened
- synchronize
- reopened
push:
paths-ignore:
- "*.md"
branches:
- main
jobs:
generate-pot:
runs-on: ubuntu-latest
steps:
- name: "Checkout repo"
uses: actions/checkout@v3
- name: "Install gettext"
run: |
sudo apt update -qq
sudo apt install -y gettext
- name: "Generate POT file using xgettext"
run: >
find src -name *.cpp -o -name *.hpp -o -name *.h |
xargs xgettext --from-code=utf-8
-k_ -kwxTRANSLATE -w 100
--check=space-ellipsis --omit-header
-o cemu.pot
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: POT file
path: ./cemu.pot
if-no-files-found: error
+1
View File
@@ -32,6 +32,7 @@ bin/mlc01/*
bin/settings.xml
bin/title_list_cache.xml
bin/debugger/*
bin/sdcard/*
!bin/shaderCache/info.txt
bin/shaderCache/*
+2 -2
View File
@@ -14,7 +14,7 @@ Instructions:
2. Launch `Cemu/generate_vs_solution.bat`.
- If you installed VS to a custom location or use VS 2019, you may need to manually change the path inside the .bat file
3. Wait until it's done, then open `Cemu/build/Cemu.sln` in Visual Studio
4. Then build the solution and once finished you can run and debug it, or build it and check the /bin folder for the final Cemu.exe.
4. Then build the solution and once finished you can run and debug it, or build it and check the /bin folder for the final Cemu_release.exe.
You can also skip steps 3-5 and open the root folder of the cloned repo directly in Visual Studio (as a folder) and use the built-in cmake support but be warned that cmake support in VS can be a bit finicky.
@@ -42,7 +42,7 @@ Additionally, for ubuntu 20.04 only:
2. `cd Cemu`
3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja`
4. `cmake --build build`
5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu`.
5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`.
#### Using GCC
While we use and test Cemu using clang, using GCC might work better with your distro (they should be fairly similar performance/issues wise and should only be considered if compilation is the issue).
+4 -3
View File
@@ -2,6 +2,7 @@
[![Build Process](https://github.com/cemu-project/Cemu/actions/workflows/build.yml/badge.svg)](https://github.com/cemu-project/Cemu/actions/workflows/build.yml)
[![Discord](https://img.shields.io/discord/286429969104764928?label=Cemu&logo=discord&logoColor=FFFFFF)](https://discord.gg/5psYsup)
[![Matrix Server](https://img.shields.io/matrix/dev:cemu.info?server_fqdn=matrix.cemu.info&label=dev:cemu.info&logo=matrix&logoColor=FFFFFF)](https://matrix.to/#/#dev:cemu.info)
This is the code repository of Cemu, a Wii U emulator that is able to run most Wii U games and homebrew in a playable state.
It's written in C/C++ and is being actively developed with new features and fixes to increase compatibility, convenience and usability.
@@ -22,7 +23,7 @@ Cemu is currently only available for 64-bit Windows and Linux devices.
## Download
You can download the latest Cemu releases from the [Github Releases](https://github.com/cemu-project/Cemu/releases/) or from [Cemu's website](https://cemu.info).
You can download the latest Cemu releases from the [GitHub Releases](https://github.com/cemu-project/Cemu/releases/) or from [Cemu's website](https://cemu.info).
Cemu is currently only available in a portable format so no installation is required besides extracting it in a safe place.
@@ -36,8 +37,8 @@ To compile Cemu yourself on Windows or Linux, view the [BUILD.md file](/BUILD.md
## Issues
Issues with the emulator should be filed using [Github Issues](https://github.com/cemu-project/Cemu/issues).
The old bug tracker can be found at [bugs.cemu.info](http://bugs.cemu.info) and still contains relevant issues and feature suggestions.
Issues with the emulator should be filed using [GitHub Issues](https://github.com/cemu-project/Cemu/issues).
The old bug tracker can be found at [bugs.cemu.info](https://bugs.cemu.info) and still contains relevant issues and feature suggestions.
## Contributing
+1 -1
View File
@@ -5,7 +5,7 @@
#include "config/ActiveSettings.h"
#include "Cafe/IOSU/legacy/iosu_crypto.h"
#include "Common/filestream.h"
#include "Common/FileStream.h"
#include <random>
#include <boost/random/uniform_int.hpp>
+7 -7
View File
@@ -24,7 +24,7 @@
#include "Cafe/Filesystem/FST/FST.h"
#include "Common/filestream.h"
#include "Common/FileStream.h"
#include "GamePatch.h"
@@ -209,7 +209,7 @@ void InfoLog_TitleLoaded()
fs::path effectiveSavePath = getTitleSavePath();
std::error_code ec;
const bool saveDirExists = fs::exists(effectiveSavePath, ec);
cemuLog_force("Save path: {}{}", _utf8Wrapper(effectiveSavePath), saveDirExists ? "" : " (not present)");
cemuLog_force("Save path: {}{}", _pathToUtf8(effectiveSavePath), saveDirExists ? "" : " (not present)");
// log shader cache name
cemuLog_log(LogType::Force, "Shader cache file: shaderCache/transferable/{:016x}.bin", titleId);
@@ -617,7 +617,7 @@ namespace CafeSystem
sLaunchModeIsStandalone = true;
cemuLog_log(LogType::Force, "Launching executable in standalone mode due to incorrect layout or missing meta files");
fs::path executablePath = path;
std::string dirName = _utf8Wrapper(executablePath.parent_path().filename());
std::string dirName = _pathToUtf8(executablePath.parent_path().filename());
if (boost::iequals(dirName, "code"))
{
// check for content folder
@@ -626,18 +626,18 @@ namespace CafeSystem
if (fs::is_directory(contentPath, ec))
{
// mounting content folder
bool r = FSCDeviceHostFS_Mount(std::string("/vol/content").c_str(), boost::nowide::widen(_utf8Wrapper(contentPath)).c_str(), FSC_PRIORITY_BASE);
bool r = FSCDeviceHostFS_Mount(std::string("/vol/content").c_str(), _pathToUtf8(contentPath), FSC_PRIORITY_BASE);
if (!r)
{
cemuLog_log(LogType::Force, "Failed to mount {}", _utf8Wrapper(contentPath).c_str());
cemuLog_log(LogType::Force, "Failed to mount {}", _pathToUtf8(contentPath));
return STATUS_CODE::UNABLE_TO_MOUNT;
}
}
}
// mount code folder to a virtual temporary path
FSCDeviceHostFS_Mount(std::string("/internal/code/").c_str(), boost::nowide::widen(_utf8Wrapper(executablePath.parent_path())).c_str(), FSC_PRIORITY_BASE);
FSCDeviceHostFS_Mount(std::string("/internal/code/").c_str(), _pathToUtf8(executablePath.parent_path()), FSC_PRIORITY_BASE);
std::string internalExecutablePath = "/internal/code/";
internalExecutablePath.append(_utf8Wrapper(executablePath.filename()));
internalExecutablePath.append(_pathToUtf8(executablePath.filename()));
_pathToExecutable = internalExecutablePath;
// since a lot of systems (including save folder location) rely on a TitleId, we derive a placeholder id from the executable hash
auto execData = fsc_extractFile(_pathToExecutable.c_str());
+1 -1
View File
@@ -1,5 +1,5 @@
#include "Common/precompiled.h"
#include "Common/filestream.h"
#include "Common/FileStream.h"
#include "Cemu/ncrypto/ncrypto.h"
#include "Cafe/Filesystem/WUD/wud.h"
#include "util/crypto/aes128.h"
+1 -1
View File
@@ -3,7 +3,7 @@
#include "config/ActiveSettings.h"
#include "util/crypto/aes128.h"
#include "Common/filestream.h"
#include "Common/FileStream.h"
#include "util/helpers/StringHelpers.h"
std::mutex mtxKeyCache;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -2,7 +2,7 @@
#include <string.h>
#include <stdlib.h>
#include "wud.h"
#include "Common/filestream.h"
#include "Common/FileStream.h"
wud_t* wud_open(const fs::path& path)
{
+48 -143
View File
@@ -1,14 +1,15 @@
#include "Cafe/Filesystem/fsc.h"
#include "Cafe/Filesystem/FST/fstUtil.h"
struct FSCMountPathNode
{
std::string path;
std::vector<FSCMountPathNode*> subnodes;
FSCMountPathNode* parent;
// device target and path (if list_subnodes is nullptr)
// device target and path (if subnodes is empty)
fscDeviceC* device{ nullptr };
void* ctx{ nullptr };
std::wstring targetPath;
std::string deviceTargetPath; // the destination base path for the device, utf8
// priority
sint32 priority{};
@@ -24,7 +25,7 @@ struct FSCMountPathNode
}
};
// compare two file or directory names using FS rules
// compare two file or directory names using FSA rules
bool FSA_CompareNodeName(std::string_view a, std::string_view b)
{
if (a.size() != b.size())
@@ -74,25 +75,25 @@ void fsc_reset()
* /vol/content/data -> Map to HostFS
* If overlapping paths with different priority are created, then the higher priority one will be checked first
*/
FSCMountPathNode* fsc_createMountPath(CoreinitFSParsedPath* parsedMountPath, sint32 priority)
FSCMountPathNode* fsc_createMountPath(const FSCPath& mountPath, sint32 priority)
{
cemu_assert(priority >= 0 && priority < FSC_PRIORITY_COUNT);
fscEnter();
FSCMountPathNode* nodeParent = s_fscRootNodePerPrio[priority];
for(sint32 i=0; i<parsedMountPath->numNodes; i++)
for (size_t i=0; i< mountPath.GetNodeCount(); i++)
{
// search for subdirectory
FSCMountPathNode* nodeSub = nullptr; // set if we found a subnode with a matching name, else this is used to store the new nodes
for(auto& nodeItr : nodeParent->subnodes)
for (auto& nodeItr : nodeParent->subnodes)
{
if( coreinitFS_checkNodeName(parsedMountPath, i, nodeItr->path.c_str()) )
if (mountPath.MatchNodeName(i, nodeItr->path))
{
// subnode found
nodeSub = nodeItr;
break;
}
}
if( nodeSub )
if (nodeSub)
{
// traverse subnode
nodeParent = nodeSub;
@@ -100,10 +101,10 @@ FSCMountPathNode* fsc_createMountPath(CoreinitFSParsedPath* parsedMountPath, sin
}
// no matching subnode, add new entry
nodeSub = new FSCMountPathNode(nodeParent);
nodeSub->path = coreinitFS_getNodeName(parsedMountPath, i);
nodeSub->path = mountPath.GetNodeName(i);
nodeSub->priority = priority;
nodeParent->subnodes.emplace_back(nodeSub);
if( i == (parsedMountPath->numNodes-1) )
if (i == (mountPath.GetNodeCount() - 1))
{
// last node
fscLeave();
@@ -114,47 +115,44 @@ FSCMountPathNode* fsc_createMountPath(CoreinitFSParsedPath* parsedMountPath, sin
}
// path is empty or already mounted
fscLeave();
if (parsedMountPath->numNodes == 0)
if (mountPath.GetNodeCount() == 0)
return nodeParent;
return nullptr;
}
// Map a virtual FSC directory to a device and device directory
sint32 fsc_mount(const char* mountPath, const wchar_t* _targetPath, fscDeviceC* fscDevice, void* ctx, sint32 priority)
// Map a virtual FSC directory to a device. targetPath points to the destination base directory within the device
sint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDeviceC* fscDevice, void* ctx, sint32 priority)
{
cemu_assert(fscDevice); // device must not be nullptr
cemu_assert(fscDevice);
std::string mountPathTmp(mountPath);
// make sure the target path ends with a slash
std::wstring targetPath(_targetPath);
if (!targetPath.empty() && (targetPath.back() != '/' && targetPath.back() != '\\'))
targetPath.push_back('/');
std::string targetPathWithSlash(targetPath);
if (!targetPathWithSlash.empty() && (targetPathWithSlash.back() != '/' && targetPathWithSlash.back() != '\\'))
targetPathWithSlash.push_back('/');
// parse mount path
CoreinitFSParsedPath parsedMountPath;
coreinitFS_parsePath(&parsedMountPath, mountPath);
FSCPath parsedMountPath(mountPathTmp);
// register path
fscEnter();
FSCMountPathNode* node = fsc_createMountPath(&parsedMountPath, priority);
FSCMountPathNode* node = fsc_createMountPath(parsedMountPath, priority);
if( !node )
{
// path empty, invalid or already used
cemuLog_log(LogType::Force, "fsc_mount failed (virtual path: %s)", mountPath);
cemuLog_log(LogType::Force, "fsc_mount failed (virtual path: {})", mountPath);
fscLeave();
return FSC_STATUS_INVALID_PATH;
}
node->device = fscDevice;
node->ctx = ctx;
node->targetPath = targetPath;
node->deviceTargetPath = targetPathWithSlash;
fscLeave();
return FSC_STATUS_OK;
}
bool fsc_unmount(const char* mountPath, sint32 priority)
bool fsc_unmount(std::string_view mountPath, sint32 priority)
{
CoreinitFSParsedPath parsedMountPath;
coreinitFS_parsePath(&parsedMountPath, mountPath);
std::string _tmp(mountPath);
fscEnter();
FSCMountPathNode* mountPathNode = fsc_lookupPathVirtualNode(mountPath, priority);
FSCMountPathNode* mountPathNode = fsc_lookupPathVirtualNode(_tmp.c_str(), priority);
if (!mountPathNode)
{
fscLeave();
@@ -185,21 +183,19 @@ void fsc_unmountAll()
}
// lookup virtual path and find mounted device and relative device directory
bool fsc_lookupPath(const char* path, std::wstring& devicePathOut, fscDeviceC** fscDeviceOut, void** ctxOut, sint32 priority = FSC_PRIORITY_BASE)
bool fsc_lookupPath(const char* path, std::string& devicePathOut, fscDeviceC** fscDeviceOut, void** ctxOut, sint32 priority = FSC_PRIORITY_BASE)
{
// parse path
CoreinitFSParsedPath parsedPath;
coreinitFS_parsePath(&parsedPath, path);
FSCPath parsedPath(path);
FSCMountPathNode* nodeParent = s_fscRootNodePerPrio[priority];
sint32 i;
size_t i;
fscEnter();
for (i = 0; i < parsedPath.numNodes; i++)
for (i = 0; i < parsedPath.GetNodeCount(); i++)
{
// search for subdirectory
FSCMountPathNode* nodeSub = nullptr;
for(auto& nodeItr : nodeParent->subnodes)
{
if (coreinitFS_checkNodeName(&parsedPath, i, nodeItr->path.c_str()))
{
if (parsedPath.MatchNodeName(i, nodeItr->path))
{
nodeSub = nodeItr;
break;
@@ -213,17 +209,17 @@ bool fsc_lookupPath(const char* path, std::wstring& devicePathOut, fscDeviceC**
// no matching subnode
break;
}
// find deepest device mount point
// if the found node is not a device mount point, then travel back towards the root until we find one
while (nodeParent)
{
if (nodeParent->device)
{
devicePathOut = nodeParent->targetPath;
for (sint32 f = i; f < parsedPath.numNodes; f++)
devicePathOut = nodeParent->deviceTargetPath;
for (size_t f = i; f < parsedPath.GetNodeCount(); f++)
{
const char* nodeName = coreinitFS_getNodeName(&parsedPath, f);
devicePathOut.append(boost::nowide::widen(nodeName));
if (f < (parsedPath.numNodes - 1))
auto nodeName = parsedPath.GetNodeName(f);
devicePathOut.append(nodeName);
if (f < (parsedPath.GetNodeCount() - 1))
devicePathOut.push_back('/');
}
*fscDeviceOut = nodeParent->device;
@@ -241,19 +237,16 @@ bool fsc_lookupPath(const char* path, std::wstring& devicePathOut, fscDeviceC**
// lookup path and find virtual device node
FSCMountPathNode* fsc_lookupPathVirtualNode(const char* path, sint32 priority)
{
// parse path
CoreinitFSParsedPath parsedPath;
coreinitFS_parsePath(&parsedPath, path);
FSCPath parsedPath(path);
FSCMountPathNode* nodeCurrentDir = s_fscRootNodePerPrio[priority];
sint32 i;
fscEnter();
for (i = 0; i < parsedPath.numNodes; i++)
for (size_t i = 0; i < parsedPath.GetNodeCount(); i++)
{
// search for subdirectory
FSCMountPathNode* nodeSub = nullptr;
for (auto& nodeItr : nodeCurrentDir->subnodes)
{
if (coreinitFS_checkNodeName(&parsedPath, i, nodeItr->path.c_str()))
if (parsedPath.MatchNodeName(i, nodeItr->path))
{
nodeSub = nodeItr;
break;
@@ -360,11 +353,9 @@ private:
FSCVirtualFile* fsc_open(const char* path, FSC_ACCESS_FLAG accessFlags, sint32* fscStatus, sint32 maxPriority)
{
cemu_assert_debug(HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE) || HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR)); // must open either file or directory
FSCVirtualFile* dirList[FSC_PRIORITY_COUNT];
uint8 dirListCount = 0;
std::wstring devicePath;
std::string devicePath;
fscDeviceC* fscDevice = NULL;
*fscStatus = FSC_STATUS_UNDEFINED;
void* ctx;
@@ -455,7 +446,7 @@ bool fsc_createDir(char* path, sint32* fscStatus)
fscDeviceC* fscDevice = NULL;
*fscStatus = FSC_STATUS_UNDEFINED;
void* ctx;
std::wstring devicePath;
std::string devicePath;
fscEnter();
if( fsc_lookupPath(path, devicePath, &fscDevice, &ctx) )
{
@@ -472,8 +463,8 @@ bool fsc_createDir(char* path, sint32* fscStatus)
*/
bool fsc_rename(char* srcPath, char* dstPath, sint32* fscStatus)
{
std::wstring srcDevicePath;
std::wstring dstDevicePath;
std::string srcDevicePath;
std::string dstDevicePath;
void* srcCtx;
void* dstCtx;
fscDeviceC* fscSrcDevice = NULL;
@@ -492,7 +483,7 @@ bool fsc_rename(char* srcPath, char* dstPath, sint32* fscStatus)
*/
bool fsc_remove(char* path, sint32* fscStatus)
{
std::wstring devicePath;
std::string devicePath;
fscDeviceC* fscDevice = NULL;
*fscStatus = FSC_STATUS_UNDEFINED;
void* ctx;
@@ -691,7 +682,7 @@ bool fsc_doesFileExist(const char* path, sint32 maxPriority)
return true;
}
// helper function to check if a folder exists
// helper function to check if a directory exists
bool fsc_doesDirectoryExist(const char* path, sint32 maxPriority)
{
fscDeviceC* fscDevice = nullptr;
@@ -708,93 +699,7 @@ bool fsc_doesDirectoryExist(const char* path, sint32 maxPriority)
return true;
}
void coreinitFS_parsePath(CoreinitFSParsedPath* parsedPath, const char* path)
{
// if the path starts with a '/', skip it
if (*path == '/')
path++;
// init parsedPath struct
memset(parsedPath, 0x00, sizeof(CoreinitFSParsedPath));
// init parsed path data
size_t pathLength = std::min((size_t)640, strlen(path));
memcpy(parsedPath->pathData, path, pathLength);
// start parsing
sint32 offset = 0;
sint32 startOffset = 0;
if (offset < pathLength)
{
parsedPath->nodeOffset[parsedPath->numNodes] = offset;
parsedPath->numNodes++;
}
while (offset < pathLength)
{
if (parsedPath->pathData[offset] == '/' || parsedPath->pathData[offset] == '\\')
{
parsedPath->pathData[offset] = '\0';
offset++;
// double slashes are ignored and instead are handled like a single slash
if (parsedPath->pathData[offset] == '/' || parsedPath->pathData[offset] == '\\')
{
// if we're in the beginning and having a \\ it's a network path
if (offset != 1)
{
parsedPath->pathData[offset] = '\0';
offset++;
}
}
// start new node
if (parsedPath->numNodes < FSC_PARSED_PATH_NODES_MAX)
{
if (offset < pathLength)
{
parsedPath->nodeOffset[parsedPath->numNodes] = offset;
parsedPath->numNodes++;
}
}
continue;
}
offset++;
}
// handle special nodes like '.' or '..'
sint32 nodeIndex = 0;
while (nodeIndex < parsedPath->numNodes)
{
if (coreinitFS_checkNodeName(parsedPath, nodeIndex, ".."))
cemu_assert_suspicious(); // how does Cafe OS handle .. ?
else if (coreinitFS_checkNodeName(parsedPath, nodeIndex, "."))
{
// remove this node and shift back all following nodes by 1
parsedPath->numNodes--;
for (sint32 i = nodeIndex; i < parsedPath->numNodes; i++)
{
parsedPath->nodeOffset[i] = parsedPath->nodeOffset[i + 1];
}
// continue without increasing nodeIndex
continue;
}
nodeIndex++;
}
}
bool coreinitFS_checkNodeName(CoreinitFSParsedPath* parsedPath, sint32 index, const char* name)
{
if (index < 0 || index >= parsedPath->numNodes)
return false;
char* nodeName = parsedPath->pathData + parsedPath->nodeOffset[index];
if (boost::iequals(nodeName, name))
return true;
return false;
}
char* coreinitFS_getNodeName(CoreinitFSParsedPath* parsedPath, sint32 index)
{
if (index < 0 || index >= parsedPath->numNodes)
return nullptr;
return parsedPath->pathData + parsedPath->nodeOffset[index];
}
// Initialize Cemu's virtual filesystem
// initialize Cemu's virtual filesystem
void fsc_init()
{
fsc_reset();
+9 -26
View File
@@ -57,25 +57,25 @@ struct FSCDirEntry
class fscDeviceC
{
public:
virtual FSCVirtualFile* fscDeviceOpenByPath(std::wstring_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus)
virtual FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus)
{
cemu_assert_unimplemented();
return nullptr;
}
virtual bool fscDeviceCreateDir(std::wstring_view path, void* ctx, sint32* fscStatus)
virtual bool fscDeviceCreateDir(std::string_view path, void* ctx, sint32* fscStatus)
{
cemu_assert_unimplemented();
return false;
}
virtual bool fscDeviceRemoveFileOrDir(std::wstring_view path, void* ctx, sint32* fscStatus)
virtual bool fscDeviceRemoveFileOrDir(std::string_view path, void* ctx, sint32* fscStatus)
{
cemu_assert_unimplemented();
return false;
}
virtual bool fscDeviceRename(std::wstring_view srcPath, std::wstring_view dstPath, void* ctx, sint32* fscStatus)
virtual bool fscDeviceRename(std::string_view srcPath, std::string_view dstPath, void* ctx, sint32* fscStatus)
{
cemu_assert_unimplemented();
return false;
@@ -161,8 +161,8 @@ struct FSCVirtualFile
#define FSC_PRIORITY_COUNT (4)
void fsc_init();
sint32 fsc_mount(const char* mountPath, const wchar_t* targetPath, fscDeviceC* fscDevice, void* ctx, sint32 priority=0);
bool fsc_unmount(const char* mountPath, sint32 priority);
sint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDeviceC* fscDevice, void* ctx, sint32 priority=0);
bool fsc_unmount(std::string_view mountPath, sint32 priority);
void fsc_unmountAll();
FSCVirtualFile* fsc_open(const char* path, FSC_ACCESS_FLAG accessFlags, sint32* fscStatus, sint32 maxPriority=FSC_PRIORITY_MAX);
@@ -188,32 +188,15 @@ bool fsc_doesFileExist(const char* path, sint32 maxPriority = FSC_PRIORITY_MAX);
bool fsc_doesDirectoryExist(const char* path, sint32 maxPriority = FSC_PRIORITY_MAX);
// wud device
bool FSCDeviceWUD_Mount(const char* mountPath, std::string_view destinationBaseDir, class FSTVolume* mountedVolume, sint32 priority);
bool FSCDeviceWUD_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class FSTVolume* mountedVolume, sint32 priority);
// wua device
bool FSCDeviceWUA_Mount(const char* mountPath, std::string_view destinationBaseDir, class ZArchiveReader* archive, sint32 priority);
bool FSCDeviceWUA_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class ZArchiveReader* archive, sint32 priority);
// hostFS device
void fscDeviceHostFS_mapBaseDirectories_deprecated();
bool FSCDeviceHostFS_Mount(const char* mountPath, const wchar_t* hostFSPath, sint32 priority);
bool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority);
// redirect device
void fscDeviceRedirect_map();
void fscDeviceRedirect_add(std::string_view virtualSourcePath, const fs::path& targetFilePath, sint32 priority);
// Old path parser helper functions
// Replace with FSCPath
#define FSC_PARSED_PATH_NODES_MAX (32)
struct CoreinitFSParsedPath
{
char pathData[640 + 1];
uint16 nodeOffset[FSC_PARSED_PATH_NODES_MAX];
sint32 numNodes;
};
void coreinitFS_parsePath(CoreinitFSParsedPath* parsedPath, const char* path);
bool coreinitFS_checkNodeName(CoreinitFSParsedPath* parsedPath, sint32 index, const char* name);
char* coreinitFS_getNodeName(CoreinitFSParsedPath* parsedPath, sint32 index);
+21 -24
View File
@@ -2,7 +2,7 @@
#include "Cafe/Filesystem/fsc.h"
#include "Cafe/Filesystem/fscDeviceHostFS.h"
#include "Common/filestream.h"
#include "Common/FileStream.h"
/* FSCVirtualFile implementation for HostFS */
@@ -127,7 +127,7 @@ bool FSCVirtualFile_Host::fscDirNext(FSCDirEntry* dirEntry)
m_dirIterator.reset(new fs::directory_iterator(*m_path));
if (!m_dirIterator)
{
cemuLog_force("Failed to iterate directory: {}", _utf8Wrapper(m_path->generic_u8string()));
cemuLog_force("Failed to iterate directory: {}", _pathToUtf8(*m_path));
return false;
}
}
@@ -175,14 +175,14 @@ FSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_F
cemu_assert_debug(writeAccessRequested);
fs = FileStream::createFile2(path);
if (!fs)
cemuLog_force("FSC: File create failed for {}", _utf8Wrapper(path));
cemuLog_force("FSC: File create failed for {}", _pathToUtf8(path));
}
}
else if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::FILE_ALWAYS_CREATE))
{
fs = FileStream::createFile2(path);
if (!fs)
cemuLog_force("FSC: File create failed for {}", _utf8Wrapper(path));
cemuLog_force("FSC: File create failed for {}", _pathToUtf8(path));
}
else
{
@@ -221,36 +221,36 @@ FSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_F
class fscDeviceHostFSC : public fscDeviceC
{
public:
FSCVirtualFile* fscDeviceOpenByPath(std::wstring_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
{
*fscStatus = FSC_STATUS_OK;
FSCVirtualFile* vf = FSCVirtualFile_Host::OpenFile(path, accessFlags, *fscStatus);
FSCVirtualFile* vf = FSCVirtualFile_Host::OpenFile(_utf8ToPath(path), accessFlags, *fscStatus);
cemu_assert_debug((bool)vf == (*fscStatus == FSC_STATUS_OK));
return vf;
}
bool fscDeviceCreateDir(std::wstring_view path, void* ctx, sint32* fscStatus) override
bool fscDeviceCreateDir(std::string_view path, void* ctx, sint32* fscStatus) override
{
fs::path dirPath(path);
if (fs::exists(path))
fs::path dirPath = _utf8ToPath(path);
if (fs::exists(dirPath))
{
if (!fs::is_directory(dirPath))
cemuLog_force("CreateDir: {} already exists but is not a directory", _utf8Wrapper(dirPath));
cemuLog_force("CreateDir: {} already exists but is not a directory", path);
*fscStatus = FSC_STATUS_ALREADY_EXISTS;
return false;
}
std::error_code ec;
bool r = fs::create_directories(dirPath, ec);
if(!r)
cemuLog_force("CreateDir: Failed to create {}", _utf8Wrapper(dirPath));
if (!r)
cemuLog_force("CreateDir: Failed to create {}", path);
*fscStatus = FSC_STATUS_OK;
return true;
}
bool fscDeviceRemoveFileOrDir(std::wstring_view path, void* ctx, sint32* fscStatus) override
bool fscDeviceRemoveFileOrDir(std::string_view path, void* ctx, sint32* fscStatus) override
{
*fscStatus = FSC_STATUS_OK;
fs::path _path(path);
fs::path _path = _utf8ToPath(path);
std::error_code ec;
if (!fs::exists(_path, ec))
{
@@ -266,11 +266,11 @@ public:
return true;
}
bool fscDeviceRename(std::wstring_view srcPath, std::wstring_view dstPath, void* ctx, sint32* fscStatus) override
bool fscDeviceRename(std::string_view srcPath, std::string_view dstPath, void* ctx, sint32* fscStatus) override
{
*fscStatus = FSC_STATUS_OK;
fs::path _srcPath(srcPath);
fs::path _dstPath(dstPath);
fs::path _srcPath = _utf8ToPath(srcPath);
fs::path _dstPath = _utf8ToPath(dstPath);
std::error_code ec;
if (!fs::exists(_srcPath, ec))
{
@@ -293,14 +293,11 @@ public:
void fscDeviceHostFS_mapBaseDirectories_deprecated()
{
const auto mlc = ActiveSettings::GetMlcPath();
fsc_mount("/cemuBossStorage/", (mlc / "usr/boss/").generic_wstring().c_str(), &fscDeviceHostFSC::instance(), NULL, FSC_PRIORITY_BASE);
fsc_mount("/vol/storage_mlc01/", (mlc / "").generic_wstring().c_str(), &fscDeviceHostFSC::instance(), NULL, FSC_PRIORITY_BASE);
fsc_mount("/cemuBossStorage/", _pathToUtf8(mlc / "usr/boss/"), &fscDeviceHostFSC::instance(), NULL, FSC_PRIORITY_BASE);
fsc_mount("/vol/storage_mlc01/", _pathToUtf8(mlc / ""), &fscDeviceHostFSC::instance(), NULL, FSC_PRIORITY_BASE);
}
bool FSCDeviceHostFS_Mount(const char* mountPath, const wchar_t* hostFSPath, sint32 priority)
bool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority)
{
std::wstring hostTargetPath(hostFSPath);
if (!hostTargetPath.empty() && (hostTargetPath.back() != '/' && hostTargetPath.back() != '\\'))
hostTargetPath.push_back('/');
return fsc_mount(mountPath, hostTargetPath.c_str(), &fscDeviceHostFSC::instance(), nullptr, priority) == FSC_STATUS_OK;
return fsc_mount(mountPath, hostTargetPath, &fscDeviceHostFSC::instance(), nullptr, priority) == FSC_STATUS_OK;
}
+7 -8
View File
@@ -9,31 +9,30 @@ struct RedirectEntry
sint32 priority;
};
FileTree<RedirectEntry, false> redirectTree;
FSAFileTree<RedirectEntry> redirectTree;
void fscDeviceRedirect_add(std::string_view virtualSourcePath, const fs::path& targetFilePath, sint32 priority)
{
std::wstring virtualSourcePathW = boost::nowide::widen(std::string(virtualSourcePath));
// check if source already has a redirection
RedirectEntry* existingEntry;
if (redirectTree.getFile(virtualSourcePathW, existingEntry))
if (redirectTree.getFile(virtualSourcePath, existingEntry))
{
if (existingEntry->priority >= priority)
return; // dont replace entries with equal or higher priority
// unregister existing entry
redirectTree.removeFile(virtualSourcePathW.c_str());
redirectTree.removeFile(virtualSourcePath);
delete existingEntry;
}
RedirectEntry* entry = new RedirectEntry(targetFilePath, priority);
redirectTree.addFile(virtualSourcePathW.c_str(), entry);
redirectTree.addFile(virtualSourcePath, entry);
}
class fscDeviceTypeRedirect : public fscDeviceC
{
FSCVirtualFile* fscDeviceOpenByPath(std::wstring_view pathW, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
{
RedirectEntry* redirectionEntry;
if (redirectTree.getFile(pathW, redirectionEntry))
if (redirectTree.getFile(path, redirectionEntry))
return FSCVirtualFile_Host::OpenFile(redirectionEntry->dstPath, accessFlags, *fscStatus);
return nullptr;
}
@@ -52,6 +51,6 @@ void fscDeviceRedirect_map()
{
if (_redirectMapped)
return;
fsc_mount("/", L"/", &fscDeviceTypeRedirect::instance(), nullptr, FSC_PRIORITY_REDIRECT);
fsc_mount("/", "/", &fscDeviceTypeRedirect::instance(), nullptr, FSC_PRIORITY_REDIRECT);
_redirectMapped = true;
}
+4 -9
View File
@@ -119,14 +119,12 @@ private:
class fscDeviceWUAC : public fscDeviceC
{
FSCVirtualFile* fscDeviceOpenByPath(std::wstring_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
{
ZArchiveReader* archive = (ZArchiveReader*)ctx;
cemu_assert_debug(!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION)); // writing to WUA is not supported
std::string pathU8 = boost::nowide::narrow(path.data(), path.size());
ZArchiveNodeHandle fileHandle = archive->LookUp(pathU8, true, true);
ZArchiveNodeHandle fileHandle = archive->LookUp(path, true, true);
if (fileHandle == ZARCHIVE_INVALID_NODE)
{
*fscStatus = FSC_STATUS_FILE_NOT_FOUND;
@@ -169,10 +167,7 @@ public:
}
};
bool FSCDeviceWUA_Mount(const char* mountPath, std::string_view destinationBaseDir, ZArchiveReader* archive, sint32 priority)
bool FSCDeviceWUA_Mount(std::string_view mountPath, std::string_view destinationBaseDir, ZArchiveReader* archive, sint32 priority)
{
std::wstring hostTargetPath(boost::nowide::widen(destinationBaseDir.data(), destinationBaseDir.size()));
if (!hostTargetPath.empty() && (hostTargetPath.back() != '/' && hostTargetPath.back() != '\\'))
hostTargetPath.push_back('/');
return fsc_mount(mountPath, hostTargetPath.c_str(), &fscDeviceWUAC::instance(), archive, priority) == FSC_STATUS_OK;
return fsc_mount(mountPath, destinationBaseDir, &fscDeviceWUAC::instance(), archive, priority) == FSC_STATUS_OK;
}
+5 -9
View File
@@ -120,16 +120,15 @@ private:
class fscDeviceWUDC : public fscDeviceC
{
FSCVirtualFile* fscDeviceOpenByPath(std::wstring_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override
{
FSTVolume* mountedVolume = (FSTVolume*)ctx;
cemu_assert_debug(!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION)); // writing to FST is never allowed
std::string pathU8 = boost::nowide::narrow(path.data(), path.size());
if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE))
{
FSTFileHandle fstFileHandle;
if (mountedVolume->OpenFile(pathU8, fstFileHandle, true))
if (mountedVolume->OpenFile(path, fstFileHandle, true))
{
*fscStatus = FSC_STATUS_OK;
return new FSCDeviceWudFileCtx(mountedVolume, fstFileHandle);
@@ -138,7 +137,7 @@ class fscDeviceWUDC : public fscDeviceC
if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))
{
FSTDirectoryIterator dirIterator;
if (mountedVolume->OpenDirectoryIterator(pathU8, dirIterator))
if (mountedVolume->OpenDirectoryIterator(path, dirIterator))
{
*fscStatus = FSC_STATUS_OK;
return new FSCDeviceWudFileCtx(mountedVolume, dirIterator);
@@ -157,10 +156,7 @@ public:
}
};
bool FSCDeviceWUD_Mount(const char* mountPath, std::string_view destinationBaseDir, FSTVolume* mountedVolume, sint32 priority)
bool FSCDeviceWUD_Mount(std::string_view mountPath, std::string_view destinationBaseDir, FSTVolume* mountedVolume, sint32 priority)
{
std::wstring hostTargetPath(boost::nowide::widen(destinationBaseDir.data(), destinationBaseDir.size()));
if (!hostTargetPath.empty() && (hostTargetPath.back() != '/' && hostTargetPath.back() != '\\'))
hostTargetPath.push_back('/');
return fsc_mount(mountPath, hostTargetPath.c_str(), &fscDeviceWUDC::instance(), mountedVolume, priority) == FSC_STATUS_OK;
return fsc_mount(mountPath, destinationBaseDir, &fscDeviceWUDC::instance(), mountedVolume, priority) == FSC_STATUS_OK;
}

Some files were not shown because too many files have changed in this diff Show More