src/platform/qt/CoreManager.cpp (view raw)
1/* Copyright (c) 2013-2017 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "CoreManager.h"
7
8#include "CoreController.h"
9#include "LogController.h"
10
11#include <QDir>
12
13#ifdef M_CORE_GBA
14#include <mgba/gba/core.h>
15#endif
16
17#include <mgba/core/core.h>
18#include <mgba-util/vfs.h>
19
20using namespace QGBA;
21
22void CoreManager::setConfig(const mCoreConfig* config) {
23 m_config = config;
24}
25
26void CoreManager::setMultiplayerController(MultiplayerController* multiplayer) {
27 m_multiplayer = multiplayer;
28}
29
30CoreController* CoreManager::loadGame(const QString& path) {
31 QFileInfo info(path);
32 if (!info.isReadable()) {
33 QString fname = info.fileName();
34 QString base = info.path();
35 if (base.endsWith("/") || base.endsWith(QDir::separator())) {
36 base.chop(1);
37 }
38 VDir* dir = VDirOpenArchive(base.toUtf8().constData());
39 if (dir) {
40 VFile* vf = dir->openFile(dir, fname.toUtf8().constData(), O_RDONLY);
41 if (vf) {
42 struct VFile* vfclone = VFileMemChunk(NULL, vf->size(vf));
43 uint8_t buffer[2048];
44 ssize_t read;
45 while ((read = vf->read(vf, buffer, sizeof(buffer))) > 0) {
46 vfclone->write(vfclone, buffer, read);
47 }
48 vf->close(vf);
49 vf = vfclone;
50 }
51 dir->close(dir);
52 return loadGame(vf, fname, base);
53 } else {
54 LOG(QT, ERROR) << tr("Failed to open game file: %1").arg(path);
55 }
56 return nullptr;
57 }
58 VFile* vf = nullptr;
59 VDir* archive = VDirOpenArchive(path.toUtf8().constData());
60 if (archive) {
61 VFile* vfOriginal = VDirFindFirst(archive, [](VFile* vf) {
62 return mCoreIsCompatible(vf) != PLATFORM_NONE;
63 });
64 ssize_t size;
65 if (vfOriginal && (size = vfOriginal->size(vfOriginal)) > 0) {
66 void* mem = vfOriginal->map(vfOriginal, size, MAP_READ);
67 vf = VFileMemChunk(mem, size);
68 vfOriginal->unmap(vfOriginal, mem, size);
69 vfOriginal->close(vfOriginal);
70 }
71 }
72 QDir dir(info.dir());
73 if (!vf) {
74 vf = VFileOpen(info.canonicalFilePath().toUtf8().constData(), O_RDONLY);
75 }
76 return loadGame(vf, info.fileName(), dir.canonicalPath());
77}
78
79CoreController* CoreManager::loadGame(VFile* vf, const QString& path, const QString& base) {
80 if (!vf) {
81 return nullptr;
82 }
83
84 mCore* core = mCoreFindVF(vf);
85 if (!core) {
86 LOG(QT, ERROR) << tr("Could not load game. Are you sure it's in the correct format?");
87 return nullptr;
88 }
89
90 core->init(core);
91 mCoreInitConfig(core, nullptr);
92
93 if (m_config) {
94 mCoreLoadForeignConfig(core, m_config);
95 }
96
97 if (m_preload) {
98 mCorePreloadVF(core, vf);
99 } else {
100 core->loadROM(core, vf);
101 }
102
103 QByteArray bytes(path.toUtf8());
104 separatePath(bytes.constData(), nullptr, core->dirs.baseName, nullptr);
105
106 QFileInfo info(base);
107 if (info.isDir()) {
108 info = QFileInfo(base + "/" + path);
109 }
110 bytes = info.dir().canonicalPath().toUtf8();
111 mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
112 if (!mCoreAutoloadSave(core)) {
113 LOG(QT, ERROR) << tr("Failed to open save file. Is the save directory writable?");
114 }
115 mCoreAutoloadCheats(core);
116
117 CoreController* cc = new CoreController(core);
118 if (m_multiplayer) {
119 cc->setMultiplayerController(m_multiplayer);
120 }
121 emit coreLoaded(cc);
122 return cc;
123}
124
125CoreController* CoreManager::loadBIOS(int platform, const QString& path) {
126 QFileInfo info(path);
127 VFile* vf = VFileOpen(info.canonicalFilePath().toUtf8().constData(), O_RDONLY);
128 if (!vf) {
129 return nullptr;
130 }
131
132 mCore* core = nullptr;
133 switch (platform) {
134#ifdef M_CORE_GBA
135 case PLATFORM_GBA:
136 core = GBACoreCreate();
137 break;
138#endif
139 default:
140 vf->close(vf);
141 return nullptr;
142 }
143 if (!core) {
144 vf->close(vf);
145 return nullptr;
146 }
147
148 core->init(core);
149 mCoreInitConfig(core, nullptr);
150
151 if (m_config) {
152 mCoreLoadForeignConfig(core, m_config);
153 }
154
155 core->loadBIOS(core, vf, 0);
156
157 mCoreConfigSetOverrideIntValue(&core->config, "useBios", 1);
158 mCoreConfigSetOverrideIntValue(&core->config, "skipBios", 0);
159
160 QByteArray bytes(info.baseName().toUtf8());
161 strncpy(core->dirs.baseName, bytes.constData(), sizeof(core->dirs.baseName));
162
163 bytes = info.dir().canonicalPath().toUtf8();
164 mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
165
166 CoreController* cc = new CoreController(core);
167 if (m_multiplayer) {
168 cc->setMultiplayerController(m_multiplayer);
169 }
170 emit coreLoaded(cc);
171 return cc;
172}