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 vf->close(vf);
87 LOG(QT, ERROR) << tr("Could not load game. Are you sure it's in the correct format?");
88 return nullptr;
89 }
90
91 core->init(core);
92 mCoreInitConfig(core, nullptr);
93
94 if (m_config) {
95 mCoreLoadForeignConfig(core, m_config);
96 }
97
98 if (m_preload) {
99 mCorePreloadVF(core, vf);
100 } else {
101 core->loadROM(core, vf);
102 }
103
104 QByteArray bytes(path.toUtf8());
105 separatePath(bytes.constData(), nullptr, core->dirs.baseName, nullptr);
106
107 QFileInfo info(base);
108 if (info.isDir()) {
109 info = QFileInfo(base + "/" + path);
110 }
111 bytes = info.dir().canonicalPath().toUtf8();
112 mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
113 if (!mCoreAutoloadSave(core)) {
114 LOG(QT, ERROR) << tr("Failed to open save file. Is the save directory writable?");
115 }
116 mCoreAutoloadCheats(core);
117
118 CoreController* cc = new CoreController(core);
119 if (m_multiplayer) {
120 cc->setMultiplayerController(m_multiplayer);
121 }
122 emit coreLoaded(cc);
123 return cc;
124}
125
126CoreController* CoreManager::loadBIOS(int platform, const QString& path) {
127 QFileInfo info(path);
128 VFile* vf = VFileOpen(info.canonicalFilePath().toUtf8().constData(), O_RDONLY);
129 if (!vf) {
130 return nullptr;
131 }
132
133 mCore* core = nullptr;
134 switch (platform) {
135#ifdef M_CORE_GBA
136 case PLATFORM_GBA:
137 core = GBACoreCreate();
138 break;
139#endif
140 default:
141 vf->close(vf);
142 return nullptr;
143 }
144 if (!core) {
145 vf->close(vf);
146 return nullptr;
147 }
148
149 core->init(core);
150 mCoreInitConfig(core, nullptr);
151
152 if (m_config) {
153 mCoreLoadForeignConfig(core, m_config);
154 }
155
156 core->loadBIOS(core, vf, 0);
157
158 mCoreConfigSetOverrideIntValue(&core->config, "useBios", 1);
159 mCoreConfigSetOverrideIntValue(&core->config, "skipBios", 0);
160
161 QByteArray bytes(info.baseName().toUtf8());
162 strncpy(core->dirs.baseName, bytes.constData(), sizeof(core->dirs.baseName));
163
164 bytes = info.dir().canonicalPath().toUtf8();
165 mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
166
167 CoreController* cc = new CoreController(core);
168 if (m_multiplayer) {
169 cc->setMultiplayerController(m_multiplayer);
170 }
171 emit coreLoaded(cc);
172 return cc;
173}