all repos — mgba @ 217d1b238b5d7c194a20d75cf3e48bc98d1411dd

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#include "VFileDevice.h"
 11
 12#include <QDir>
 13
 14#ifdef M_CORE_GBA
 15#include <mgba/gba/core.h>
 16#endif
 17
 18#include <mgba/core/core.h>
 19#include <mgba-util/vfs.h>
 20
 21using namespace QGBA;
 22
 23void CoreManager::setConfig(const mCoreConfig* config) {
 24	m_config = config;
 25}
 26
 27void CoreManager::setMultiplayerController(MultiplayerController* multiplayer) {
 28	m_multiplayer = multiplayer;
 29}
 30
 31CoreController* CoreManager::loadGame(const QString& path) {
 32	QFileInfo info(path);
 33	if (!info.isReadable()) {
 34		QString fname = info.fileName();
 35		QString base = info.path();
 36		if (base.endsWith("/") || base.endsWith(QDir::separator())) {
 37			base.chop(1);
 38		}
 39		VDir* dir = VDirOpenArchive(base.toUtf8().constData());
 40		if (dir) {
 41			VFile* vf = dir->openFile(dir, fname.toUtf8().constData(), O_RDONLY);
 42			if (vf) {
 43				struct VFile* vfclone = VFileMemChunk(NULL, vf->size(vf));
 44				uint8_t buffer[2048];
 45				ssize_t read;
 46				while ((read = vf->read(vf, buffer, sizeof(buffer))) > 0) {
 47					vfclone->write(vfclone, buffer, read);
 48				}
 49				vf->close(vf);
 50				vf = vfclone;
 51			}
 52			dir->close(dir);
 53			return loadGame(vf, fname, base);
 54		} else {
 55			LOG(QT, ERROR) << tr("Failed to open game file: %1").arg(path);
 56		}
 57		return nullptr;
 58	}
 59	VFile* vf = nullptr;
 60	VDir* archive = VDirOpenArchive(path.toUtf8().constData());
 61	if (archive) {
 62		VFile* vfOriginal = VDirFindFirst(archive, [](VFile* vf) {
 63			return mCoreIsCompatible(vf) != mPLATFORM_NONE;
 64		});
 65		ssize_t size;
 66		if (vfOriginal && (size = vfOriginal->size(vfOriginal)) > 0) {
 67			void* mem = vfOriginal->map(vfOriginal, size, MAP_READ);
 68			vf = VFileMemChunk(mem, size);
 69			vfOriginal->unmap(vfOriginal, mem, size);
 70			vfOriginal->close(vfOriginal);
 71		}
 72	}
 73	QDir dir(info.dir());
 74	if (!vf) {
 75		vf = VFileOpen(info.canonicalFilePath().toUtf8().constData(), O_RDONLY);
 76	}
 77	return loadGame(vf, info.fileName(), dir.canonicalPath());
 78}
 79
 80CoreController* CoreManager::loadGame(VFile* vf, const QString& path, const QString& base) {
 81	if (!vf) {
 82		return nullptr;
 83	}
 84
 85	mCore* core = mCoreFindVF(vf);
 86	if (!core) {
 87		vf->close(vf);
 88		LOG(QT, ERROR) << tr("Could not load game. Are you sure it's in the correct format?");
 89		return nullptr;
 90	}
 91
 92	core->init(core);
 93	mCoreInitConfig(core, nullptr);
 94
 95	if (m_config) {
 96		mCoreLoadForeignConfig(core, m_config);
 97	}
 98
 99	if (m_preload) {
100		mCorePreloadVF(core, vf);
101	} else {
102		core->loadROM(core, vf);
103	}
104
105	QByteArray bytes(path.toUtf8());
106	separatePath(bytes.constData(), nullptr, core->dirs.baseName, nullptr);
107
108	QFileInfo info(base);
109	if (info.isDir()) {
110		info = QFileInfo(base + "/" + path);
111	}
112	bytes = info.dir().canonicalPath().toUtf8();
113	mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
114	if (!mCoreAutoloadSave(core)) {
115		LOG(QT, ERROR) << tr("Failed to open save file. Is the save directory writable?");
116	}
117	mCoreAutoloadCheats(core);
118
119	CoreController* cc = new CoreController(core);
120	if (m_multiplayer) {
121		cc->setMultiplayerController(m_multiplayer);
122	}
123	emit coreLoaded(cc);
124	return cc;
125}
126
127CoreController* CoreManager::loadBIOS(int platform, const QString& path) {
128	QFileInfo info(path);
129	VFile* vf = VFileOpen(info.canonicalFilePath().toUtf8().constData(), O_RDONLY);
130	if (!vf) {
131		return nullptr;
132	}
133
134	mCore* core = nullptr;
135	switch (platform) {
136#ifdef M_CORE_GBA
137	case mPLATFORM_GBA:
138		core = GBACoreCreate();
139		break;
140#endif
141	default:
142		vf->close(vf);
143		return nullptr;
144	}
145	if (!core) {
146		vf->close(vf);
147		return nullptr;
148	}
149
150	core->init(core);
151	mCoreInitConfig(core, nullptr);
152
153	if (m_config) {
154		mCoreLoadForeignConfig(core, m_config);
155	}
156
157	core->loadBIOS(core, vf, 0);
158
159	mCoreConfigSetOverrideIntValue(&core->config, "useBios", 1);
160	mCoreConfigSetOverrideIntValue(&core->config, "skipBios", 0);
161
162	QByteArray bytes(info.baseName().toUtf8());
163	strncpy(core->dirs.baseName, bytes.constData(), sizeof(core->dirs.baseName));
164
165	bytes = info.dir().canonicalPath().toUtf8();
166	mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
167
168	CoreController* cc = new CoreController(core);
169	if (m_multiplayer) {
170		cc->setMultiplayerController(m_multiplayer);
171	}
172	emit coreLoaded(cc);
173	return cc;
174}