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