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