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_t) read);
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 mCoreAutoloadSave(core);
113 mCoreAutoloadCheats(core);
114
115 CoreController* cc = new CoreController(core);
116 if (m_multiplayer) {
117 cc->setMultiplayerController(m_multiplayer);
118 }
119 emit coreLoaded(cc);
120 return cc;
121}
122
123CoreController* CoreManager::loadBIOS(int platform, const QString& path) {
124 QFileInfo info(path);
125 VFile* vf = VFileOpen(info.canonicalFilePath().toUtf8().constData(), O_RDONLY);
126 if (!vf) {
127 return nullptr;
128 }
129
130 mCore* core = nullptr;
131 switch (platform) {
132#ifdef M_CORE_GBA
133 case PLATFORM_GBA:
134 core = GBACoreCreate();
135 break;
136#endif
137 default:
138 vf->close(vf);
139 return nullptr;
140 }
141 if (!core) {
142 vf->close(vf);
143 return nullptr;
144 }
145
146 core->init(core);
147 mCoreInitConfig(core, nullptr);
148
149 if (m_config) {
150 mCoreLoadForeignConfig(core, m_config);
151 }
152
153 core->loadBIOS(core, vf, 0);
154
155 mCoreConfigSetOverrideIntValue(&core->config, "useBios", 1);
156 mCoreConfigSetOverrideIntValue(&core->config, "skipBios", 0);
157
158 QByteArray bytes(info.baseName().toUtf8());
159 strncpy(core->dirs.baseName, bytes.constData(), sizeof(core->dirs.baseName));
160
161 bytes = info.dir().canonicalPath().toUtf8();
162 mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
163
164 CoreController* cc = new CoreController(core);
165 if (m_multiplayer) {
166 cc->setMultiplayerController(m_multiplayer);
167 }
168 emit coreLoaded(cc);
169 return cc;
170}