mirror of https://github.com/mgba-emu/mgba.git
Qt: Add CoreManager::getExtdata API
This commit is contained in:
parent
6c805acab6
commit
3dcf879e94
|
@ -36,7 +36,7 @@ struct mStateExtdata {
|
||||||
struct mStateExtdataItem data[EXTDATA_MAX];
|
struct mStateExtdataItem data[EXTDATA_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
bool mStateExtdataInit(struct mStateExtdata*);
|
void mStateExtdataInit(struct mStateExtdata*);
|
||||||
void mStateExtdataDeinit(struct mStateExtdata*);
|
void mStateExtdataDeinit(struct mStateExtdata*);
|
||||||
void mStateExtdataPut(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*);
|
void mStateExtdataPut(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*);
|
||||||
bool mStateExtdataGet(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*);
|
bool mStateExtdataGet(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*);
|
||||||
|
@ -49,6 +49,7 @@ struct mCore;
|
||||||
bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags);
|
bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags);
|
||||||
bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags);
|
bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags);
|
||||||
void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata);
|
void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata);
|
||||||
|
bool mCoreExtractExtdata(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,8 @@ struct mStateExtdataHeader {
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool mStateExtdataInit(struct mStateExtdata* extdata) {
|
void mStateExtdataInit(struct mStateExtdata* extdata) {
|
||||||
memset(extdata->data, 0, sizeof(extdata->data));
|
memset(extdata->data, 0, sizeof(extdata->data));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mStateExtdataDeinit(struct mStateExtdata* extdata) {
|
void mStateExtdataDeinit(struct mStateExtdata* extdata) {
|
||||||
|
@ -43,6 +42,7 @@ void mStateExtdataDeinit(struct mStateExtdata* extdata) {
|
||||||
extdata->data[i].clean(extdata->data[i].data);
|
extdata->data[i].clean(extdata->data[i].data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
memset(extdata->data, 0, sizeof(extdata->data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mStateExtdataPut(struct mStateExtdata* extdata, enum mStateExtdataTag tag, struct mStateExtdataItem* item) {
|
void mStateExtdataPut(struct mStateExtdata* extdata, enum mStateExtdataTag tag, struct mStateExtdataItem* item) {
|
||||||
|
@ -216,7 +216,7 @@ static int _loadPNGChunkHandler(png_structp png, png_unknown_chunkp chunk) {
|
||||||
if (!strcmp((const char*) chunk->name, "gbAs")) {
|
if (!strcmp((const char*) chunk->name, "gbAs")) {
|
||||||
void* state = bundle->state;
|
void* state = bundle->state;
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
uLongf len = bundle->stateSize;
|
uLongf len = bundle->stateSize;
|
||||||
uncompress((Bytef*) state, &len, chunk->data, chunk->size);
|
uncompress((Bytef*) state, &len, chunk->data, chunk->size);
|
||||||
|
@ -297,6 +297,54 @@ static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateEx
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _loadPNGExtadata(struct VFile* vf, struct mStateExtdata* extdata) {
|
||||||
|
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
|
||||||
|
png_infop info = png_create_info_struct(png);
|
||||||
|
png_infop end = png_create_info_struct(png);
|
||||||
|
if (!png || !info || !end) {
|
||||||
|
PNGReadClose(png, info, end);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct mBundledState bundle = {
|
||||||
|
.stateSize = 0,
|
||||||
|
.state = NULL,
|
||||||
|
.extdata = extdata
|
||||||
|
};
|
||||||
|
|
||||||
|
PNGInstallChunkHandler(png, &bundle, _loadPNGChunkHandler, "gbAs gbAx");
|
||||||
|
bool success = PNGReadHeader(png, info);
|
||||||
|
if (!success) {
|
||||||
|
PNGReadClose(png, info, end);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned width = png_get_image_width(png, info);
|
||||||
|
unsigned height = png_get_image_height(png, info);
|
||||||
|
uint32_t* pixels = NULL;
|
||||||
|
pixels = malloc(width * height * 4);
|
||||||
|
if (!pixels) {
|
||||||
|
PNGReadClose(png, info, end);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
success = PNGReadPixels(png, info, pixels, width, height, width);
|
||||||
|
success = success && PNGReadFooter(png, end);
|
||||||
|
PNGReadClose(png, info, end);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
struct mStateExtdataItem item = {
|
||||||
|
.size = width * height * 4,
|
||||||
|
.data = pixels,
|
||||||
|
.clean = free
|
||||||
|
};
|
||||||
|
mStateExtdataPut(extdata, EXTDATA_SCREENSHOT, &item);
|
||||||
|
} else {
|
||||||
|
free(pixels);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) {
|
bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) {
|
||||||
|
@ -425,6 +473,20 @@ void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtda
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mCoreExtractExtdata(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata) {
|
||||||
|
#ifdef USE_PNG
|
||||||
|
if (isPNG(vf)) {
|
||||||
|
return _loadPNGExtadata(vf, extdata);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!core) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ssize_t stateSize = core->stateSize(core);
|
||||||
|
vf->seek(vf, stateSize, SEEK_SET);
|
||||||
|
return mStateExtdataDeserialize(extdata, vf);
|
||||||
|
}
|
||||||
|
|
||||||
bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) {
|
bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) {
|
||||||
struct mStateExtdata extdata;
|
struct mStateExtdata extdata;
|
||||||
mStateExtdataInit(&extdata);
|
mStateExtdataInit(&extdata);
|
||||||
|
|
|
@ -7,12 +7,16 @@
|
||||||
|
|
||||||
#include "CoreController.h"
|
#include "CoreController.h"
|
||||||
#include "LogController.h"
|
#include "LogController.h"
|
||||||
|
#include "VFileDevice.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
#ifdef M_CORE_GBA
|
#ifdef M_CORE_GBA
|
||||||
#include <mgba/gba/core.h>
|
#include <mgba/gba/core.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef M_CORE_GB
|
||||||
|
#include <mgba/gb/core.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
|
@ -27,6 +31,57 @@ void CoreManager::setMultiplayerController(MultiplayerController* multiplayer) {
|
||||||
m_multiplayer = multiplayer;
|
m_multiplayer = multiplayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray CoreManager::getExtdata(const QString& filename, mStateExtdataTag extdataType) {
|
||||||
|
VFileDevice vf(filename, QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
if (!vf.isOpen()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
mStateExtdata extdata;
|
||||||
|
mStateExtdataInit(&extdata);
|
||||||
|
|
||||||
|
QByteArray bytes;
|
||||||
|
auto extract = [&bytes, &extdata, &vf, extdataType](mCore* core) -> bool {
|
||||||
|
if (mCoreExtractExtdata(core, vf, &extdata)) {
|
||||||
|
mStateExtdataItem extitem;
|
||||||
|
if (!mStateExtdataGet(&extdata, extdataType, &extitem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (extitem.size) {
|
||||||
|
bytes = QByteArray::fromRawData(static_cast<const char*>(extitem.data), extitem.size);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
struct mCore* core = nullptr;
|
||||||
|
#ifdef USE_PNG
|
||||||
|
done = extract(nullptr);
|
||||||
|
#endif
|
||||||
|
#ifdef M_CORE_GBA
|
||||||
|
if (!done) {
|
||||||
|
core = GBACoreCreate();
|
||||||
|
core->init(core);
|
||||||
|
done = extract(core);
|
||||||
|
core->deinit(core);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef M_CORE_GB
|
||||||
|
if (!done) {
|
||||||
|
core = GBCoreCreate();
|
||||||
|
core->init(core);
|
||||||
|
done = extract(core);
|
||||||
|
core->deinit(core);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mStateExtdataDeinit(&extdata);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
CoreController* CoreManager::loadGame(const QString& path) {
|
CoreController* CoreManager::loadGame(const QString& path) {
|
||||||
QFileInfo info(path);
|
QFileInfo info(path);
|
||||||
if (!info.isReadable()) {
|
if (!info.isReadable()) {
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#include <mgba/core/serialize.h>
|
||||||
|
|
||||||
struct mCoreConfig;
|
struct mCoreConfig;
|
||||||
struct VFile;
|
struct VFile;
|
||||||
|
|
||||||
|
@ -25,6 +27,8 @@ public:
|
||||||
void setMultiplayerController(MultiplayerController*);
|
void setMultiplayerController(MultiplayerController*);
|
||||||
void setPreload(bool preload) { m_preload = preload; }
|
void setPreload(bool preload) { m_preload = preload; }
|
||||||
|
|
||||||
|
static QByteArray getExtdata(const QString& filename, mStateExtdataTag extdataType);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
CoreController* loadGame(const QString& path);
|
CoreController* loadGame(const QString& path);
|
||||||
CoreController* loadGame(VFile* vf, const QString& path, const QString& base);
|
CoreController* loadGame(VFile* vf, const QString& path, const QString& base);
|
||||||
|
|
Loading…
Reference in New Issue