Merge pull request #90 from gizmo98/patch-2
[libretro-ppsspp.git] / Core / PSPLoaders.cpp
blobd6cae6ca417b15c1efece662e72924fa244b02cb
1 // Copyright (C) 2012 PPSSPP Project
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
18 #ifdef __SYMBIAN32__
19 #include <sys/param.h>
20 #endif
22 #include "file/file_util.h"
24 #include "Common/StringUtils.h"
26 #include "Core/ELF/ElfReader.h"
27 #include "Core/ELF/ParamSFO.h"
29 #include "FileSystems/BlockDevices.h"
30 #include "FileSystems/DirectoryFileSystem.h"
31 #include "FileSystems/ISOFileSystem.h"
32 #include "FileSystems/MetaFileSystem.h"
33 #include "FileSystems/VirtualDiscFileSystem.h"
35 #include "Core/Loaders.h"
36 #include "Core/MemMap.h"
37 #include "Core/HDRemaster.h"
39 #include "Core/MIPS/MIPS.h"
40 #include "Core/MIPS/MIPSAnalyst.h"
41 #include "Core/MIPS/MIPSCodeUtils.h"
43 #include "Host.h"
45 #include "Core/Config.h"
46 #include "Core/System.h"
47 #include "Core/PSPLoaders.h"
48 #include "Core/HLE/HLE.h"
49 #include "Core/HLE/sceKernel.h"
50 #include "Core/HLE/sceKernelThread.h"
51 #include "Core/HLE/sceKernelModule.h"
52 #include "Core/HLE/sceKernelMemory.h"
54 // We gather the game info before actually loading/booting the ISO
55 // to determine if the emulator should enable extra memory and
56 // double-sized texture coordinates.
57 void InitMemoryForGameISO(FileLoader *fileLoader) {
58 IFileSystem* umd2;
60 if (!fileLoader->Exists()) {
61 return;
64 bool actualIso = false;
65 if (fileLoader->IsDirectory())
67 umd2 = new VirtualDiscFileSystem(&pspFileSystem, fileLoader->Path());
69 else
71 auto bd = constructBlockDevice(fileLoader);
72 // Can't init anything without a block device...
73 if (!bd)
74 return;
76 #ifdef _M_X64
77 if (g_Config.bCacheFullIsoInRam) {
78 // The constructor destroys the original block device object after reading it.
79 bd = new RAMBlockDevice(bd);
81 #endif
83 umd2 = new ISOFileSystem(&pspFileSystem, bd);
84 actualIso = true;
87 // Parse PARAM.SFO
89 //pspFileSystem.Mount("host0:",umd2);
91 IFileSystem *entireIso = 0;
92 if (actualIso) {
93 entireIso = new ISOBlockSystem(static_cast<ISOFileSystem *>(umd2));
94 } else {
95 entireIso = umd2;
98 pspFileSystem.Mount("umd0:", entireIso);
99 pspFileSystem.Mount("umd1:", entireIso);
100 pspFileSystem.Mount("disc0:", umd2);
101 pspFileSystem.Mount("umd:", entireIso);
103 std::string gameID;
105 std::string sfoPath("disc0:/PSP_GAME/PARAM.SFO");
106 PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str());
108 if (fileInfo.exists)
110 std::vector<u8> paramsfo;
111 pspFileSystem.ReadEntireFile(sfoPath, paramsfo);
112 if (g_paramSFO.ReadSFO(paramsfo))
114 gameID = g_paramSFO.GetValueString("DISC_ID");
116 for (size_t i = 0; i < ARRAY_SIZE(g_HDRemasters); i++) {
117 if(g_HDRemasters[i].gameID == gameID) {
118 g_RemasterMode = true;
119 Memory::g_MemorySize = g_HDRemasters[i].MemorySize;
120 if(g_HDRemasters[i].DoubleTextureCoordinates)
121 g_DoubleTextureCoordinates = true;
122 break;
125 DEBUG_LOG(LOADER, "HDRemaster mode is %s", g_RemasterMode? "true": "false");
131 // Chinese translators like to rename EBOOT.BIN and replace it with some kind of stub
132 // that probably loads a plugin and then launches the actual game. These stubs don't work in PPSSPP.
133 // No idea why they are doing this, but it works to just bypass it. They could stop
134 // inventing new filenames though...
135 static const char *altBootNames[] = {
136 "disc0:/PSP_GAME/SYSDIR/EBOOT.OLD",
137 "disc0:/PSP_GAME/SYSDIR/EBOOT.DAT",
138 "disc0:/PSP_GAME/SYSDIR/EBOOT.BI",
139 "disc0:/PSP_GAME/SYSDIR/EBOOT.LLD",
140 //"disc0:/PSP_GAME/SYSDIR/OLD_EBOOT.BIN", //Utawareru Mono Chinese version
141 "disc0:/PSP_GAME/SYSDIR/EBOOT.123",
142 "disc0:/PSP_GAME/SYSDIR/EBOOT_LRC_CH.BIN",
143 "disc0:/PSP_GAME/SYSDIR/BOOT0.OLD",
144 "disc0:/PSP_GAME/SYSDIR/BOOT1.OLD",
145 "disc0:/PSP_GAME/SYSDIR/BINOT.BIN",
146 "disc0:/PSP_GAME/SYSDIR/EBOOT.FRY",
147 "disc0:/PSP_GAME/SYSDIR/EBOOT.Z.Y",
148 "disc0:/PSP_GAME/SYSDIR/EBOOT.LEI",
149 "disc0:/PSP_GAME/SYSDIR/EBOOT.DNR",
150 "disc0:/PSP_GAME/SYSDIR/DBZ2.BIN",
151 "disc0:/PSP_GAME/SYSDIR/ss.RAW",
154 bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string)
156 // Mounting stuff relocated to InitMemoryForGameISO due to HD Remaster restructuring of code.
158 std::string sfoPath("disc0:/PSP_GAME/PARAM.SFO");
159 PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str());
160 if (fileInfo.exists)
162 std::vector<u8> paramsfo;
163 pspFileSystem.ReadEntireFile(sfoPath, paramsfo);
164 if (g_paramSFO.ReadSFO(paramsfo))
166 char title[1024];
167 sprintf(title, "%s : %s", g_paramSFO.GetValueString("DISC_ID").c_str(), g_paramSFO.GetValueString("TITLE").c_str());
168 INFO_LOG(LOADER, "%s", title);
169 host->SetWindowTitle(title);
174 std::string bootpath("disc0:/PSP_GAME/SYSDIR/EBOOT.BIN");
176 // Bypass Chinese translation patches, see comment above.
177 for (size_t i = 0; i < ARRAY_SIZE(altBootNames); i++) {
178 if (pspFileSystem.GetFileInfo(altBootNames[i]).exists) {
179 bootpath = altBootNames[i];
183 // Bypass another more dangerous one where the file is in USRDIR - this could collide with files in some game.
184 std::string id = g_paramSFO.GetValueString("DISC_ID");
185 if (id == "NPJH50624" && pspFileSystem.GetFileInfo("disc0:/PSP_GAME/USRDIR/PAKFILE2.BIN").exists) {
186 bootpath = "disc0:/PSP_GAME/USRDIR/PAKFILE2.BIN";
188 if (id == "NPJH00100" && pspFileSystem.GetFileInfo("disc0:/PSP_GAME/USRDIR/DATA/GIM/GBL").exists) {
189 bootpath = "disc0:/PSP_GAME/USRDIR/DATA/GIM/GBL";
192 bool hasEncrypted = false;
193 u32 fd;
194 if ((fd = pspFileSystem.OpenFile(bootpath, FILEACCESS_READ)) != 0)
196 u8 head[4];
197 pspFileSystem.ReadFile(fd, head, 4);
198 if (memcmp(head, "~PSP", 4) == 0 || memcmp(head, "\x7F""ELF", 4) == 0) {
199 hasEncrypted = true;
201 pspFileSystem.CloseFile(fd);
203 if (!hasEncrypted)
205 // try unencrypted BOOT.BIN
206 bootpath = "disc0:/PSP_GAME/SYSDIR/BOOT.BIN";
208 //in case we didn't go through EmuScreen::boot
209 g_Config.loadGameConfig(id);
210 INFO_LOG(LOADER,"Loading %s...", bootpath.c_str());
211 return __KernelLoadExec(bootpath.c_str(), 0, error_string);
214 #if defined(_WIN32) && defined(__MINGW32__)
215 #include "realpath.c"
216 #endif
218 static std::string NormalizePath(const std::string &path)
220 #if defined(_WIN32) && !defined(__MINGW32__)
221 char buf[512] = {0};
222 if (GetFullPathNameA(path.c_str(), sizeof(buf) - 1, buf, NULL) == 0)
223 return "";
224 #else
225 char buf[PATH_MAX + 1];
226 if (realpath(path.c_str(), buf) == NULL)
227 return "";
228 #endif
229 return buf;
232 bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string)
234 // This is really just for headless, might need tweaking later.
235 if (PSP_CoreParameter().mountIsoLoader != nullptr)
237 auto bd = constructBlockDevice(PSP_CoreParameter().mountIsoLoader);
238 if (bd != NULL) {
239 ISOFileSystem *umd2 = new ISOFileSystem(&pspFileSystem, bd);
241 pspFileSystem.Mount("umd1:", umd2);
242 pspFileSystem.Mount("disc0:", umd2);
243 pspFileSystem.Mount("umd:", umd2);
247 std::string full_path = fileLoader->Path();
248 std::string path, file, extension;
249 SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
250 #ifdef _WIN32
251 path = ReplaceAll(path, "/", "\\");
252 #endif
254 if (!PSP_CoreParameter().mountRoot.empty())
256 // We don't want to worry about .. and cwd and such.
257 const std::string rootNorm = NormalizePath(PSP_CoreParameter().mountRoot + "/");
258 const std::string pathNorm = NormalizePath(path + "/");
260 // If root is not a subpath of path, we can't boot the game.
261 if (!startsWith(pathNorm, rootNorm))
263 *error_string = "Cannot boot ELF located outside mountRoot.";
264 return false;
267 const std::string filepath = ReplaceAll(pathNorm.substr(rootNorm.size()), "\\", "/");
268 file = filepath + "/" + file;
269 path = rootNorm + "/";
270 pspFileSystem.SetStartingDirectory(filepath);
273 DirectoryFileSystem *fs = new DirectoryFileSystem(&pspFileSystem, path);
274 pspFileSystem.Mount("umd0:", fs);
276 std::string finalName = "umd0:/" + file + extension;
277 return __KernelLoadExec(finalName.c_str(), 0, error_string);