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