all repos — mgba @ 6c805acab6673dfdb19b5ff18661008d16be8c82

mGBA Game Boy Advance Emulator

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}