Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
common/path_util.cpp
ShadPKG / common / path_util.cpp
1// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3 
4#include <unordered_map>
5#include "common/logging/log.h"
6#include "common/path_util.h"
7#include "common/scope_exit.h"
8 
9#ifdef __APPLE__
10#include <CoreFoundation/CFBundle.h>
11#include <dlfcn.h>
12#include <sys/param.h>
13#endif
14 
15#ifndef MAX_PATH
16#ifdef _WIN32
17// This is the maximum number of UTF-16 code units permissible in Windows file paths
18#define MAX_PATH 260
19#else
20// This is the maximum number of UTF-8 code units permissible in all other OSes' file paths
21#define MAX_PATH 1024
22#endif
23#endif
24 
25#ifdef ENABLE_QT_GUI
26#include <QString>
27#endif
28 
29namespace Common::FS {
30 
31namespace fs = std::filesystem;
32 
33#ifdef __APPLE__
34using IsTranslocatedURLFunc = Boolean (*)(CFURLRef path, bool* isTranslocated,
35 CFErrorRef* __nullable error);
36using CreateOriginalPathForURLFunc = CFURLRef __nullable (*)(CFURLRef translocatedPath,
37 CFErrorRef* __nullable error);
38 
39static CFURLRef UntranslocateBundlePath(const CFURLRef bundle_path) {
40 if (void* security_handle =
41 dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY)) {
42 SCOPE_EXIT {
43 dlclose(security_handle);
44 };
45 
46 const auto IsTranslocatedURL = reinterpret_cast<IsTranslocatedURLFunc>(
47 dlsym(security_handle, "SecTranslocateIsTranslocatedURL"));
48 const auto CreateOriginalPathForURL = reinterpret_cast<CreateOriginalPathForURLFunc>(
49 dlsym(security_handle, "SecTranslocateCreateOriginalPathForURL"));
50 
51 bool is_translocated = false;
52 if (IsTranslocatedURL && CreateOriginalPathForURL &&
53 IsTranslocatedURL(bundle_path, &is_translocated, nullptr) && is_translocated) {
54 return CreateOriginalPathForURL(bundle_path, nullptr);
55 }
56 }
57 return nullptr;
58}
59 
60static std::filesystem::path GetBundleParentDirectory() {
61 if (CFBundleRef bundle_ref = CFBundleGetMainBundle()) {
62 if (CFURLRef bundle_url_ref = CFBundleCopyBundleURL(bundle_ref)) {
63 SCOPE_EXIT {
64 CFRelease(bundle_url_ref);
65 };
66 
67 CFURLRef untranslocated_url_ref = UntranslocateBundlePath(bundle_url_ref);
68 SCOPE_EXIT {
69 if (untranslocated_url_ref) {
70 CFRelease(untranslocated_url_ref);
71 }
72 };
73 
74 char app_bundle_path[MAXPATHLEN];
75 if (CFURLGetFileSystemRepresentation(
76 untranslocated_url_ref ? untranslocated_url_ref : bundle_url_ref, true,
77 reinterpret_cast<u8*>(app_bundle_path), sizeof(app_bundle_path))) {
78 std::filesystem::path bundle_path{app_bundle_path};
79 return bundle_path.parent_path();
80 }
81 }
82 }
83 return std::filesystem::current_path();
84}
85#endif
86 
87static auto UserPaths = [] {
88#ifdef __APPLE__
89 // Set the current path to the directory containing the app bundle.
90 std::filesystem::current_path(GetBundleParentDirectory());
91#endif
92 
93 // Try the portable user directory first.
94 auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
95 if (!std::filesystem::exists(user_dir)) {
96 // If it doesn't exist, use the standard path for the platform instead.
97 // NOTE: On Windows we currently just create the portable directory instead.
98#ifdef __APPLE__
99 user_dir =
100 std::filesystem::path(getenv("HOME")) / "Library" / "Application Support" / "shadPS4";
101#elif defined(__linux__)
102 const char* xdg_data_home = getenv("XDG_DATA_HOME");
103 if (xdg_data_home != nullptr && strlen(xdg_data_home) > 0) {
104 user_dir = std::filesystem::path(xdg_data_home) / "shadPS4";
105 } else {
106 user_dir = std::filesystem::path(getenv("HOME")) / ".local" / "share" / "shadPS4";
107 }
108#endif
109 }
110 
111 std::unordered_map<PathType, fs::path> paths;
112 
113 const auto create_path = [&](PathType shad_path, const fs::path& new_path) {
114 // Non creare directory all'avvio: memorizziamo solo i percorsi.
115 // Le directory verranno create on-demand dove strettamente necessario.
116 paths.insert_or_assign(shad_path, new_path);
117 };
118 
119 create_path(PathType::UserDir, user_dir);
120 create_path(PathType::LogDir, user_dir / LOG_DIR);
121 create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR);
122 create_path(PathType::ShaderDir, user_dir / SHADER_DIR);
123 create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR);
124 create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR);
125 create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR);
126 create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR);
127 create_path(PathType::DownloadDir, user_dir / DOWNLOAD_DIR);
128 create_path(PathType::CapturesDir, user_dir / CAPTURES_DIR);
129 create_path(PathType::CheatsDir, user_dir / CHEATS_DIR);
130 create_path(PathType::PatchesDir, user_dir / PATCHES_DIR);
131 create_path(PathType::MetaDataDir, user_dir / METADATA_DIR);
132 
133 return paths;
134}();
135 
136bool ValidatePath(const fs::path& path) {
137 if (path.empty()) {
138 LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path));
139 return false;
140 }
141 
142#ifdef _WIN32
143 if (path.u16string().size() >= MAX_PATH) {
144 LOG_ERROR(Common_Filesystem, "Input path is too long, path={}", PathToUTF8String(path));
145 return false;
146 }
147#else
148 if (path.u8string().size() >= MAX_PATH) {
149 LOG_ERROR(Common_Filesystem, "Input path is too long, path={}", PathToUTF8String(path));
150 return false;
151 }
152#endif
153 
154 return true;
155}
156 
157std::string PathToUTF8String(const std::filesystem::path& path) {
158 const auto u8_string = path.u8string();
159 return std::string{u8_string.begin(), u8_string.end()};
160}
161 
162const fs::path& GetUserPath(PathType shad_path) {
163 return UserPaths.at(shad_path);
164}
165 
166std::string GetUserPathString(PathType shad_path) {
167 return PathToUTF8String(GetUserPath(shad_path));
168}
169 
170void SetUserPath(PathType shad_path, const fs::path& new_path) {
171 if (!std::filesystem::is_directory(new_path)) {
172 LOG_ERROR(Common_Filesystem, "Filesystem object at new_path={} is not a directory",
173 PathToUTF8String(new_path));
174 return;
175 }
176 
177 UserPaths.insert_or_assign(shad_path, new_path);
178}
179 
180#ifdef ENABLE_QT_GUI
181void PathToQString(QString& result, const std::filesystem::path& path) {
182#ifdef _WIN32
183 result = QString::fromStdWString(path.wstring());
184#else
185 result = QString::fromStdString(path.string());
186#endif
187}
188 
189std::filesystem::path PathFromQString(const QString& path) {
190#ifdef _WIN32
191 return std::filesystem::path(path.toStdWString());
192#else
193 return std::filesystem::path(path.toStdString());
194#endif
195}
196#endif
197 
198} // namespace Common::FS