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];
|
||||
};
|
||||
|
||||
bool mStateExtdataInit(struct mStateExtdata*);
|
||||
void mStateExtdataInit(struct mStateExtdata*);
|
||||
void mStateExtdataDeinit(struct mStateExtdata*);
|
||||
void mStateExtdataPut(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 mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags);
|
||||
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
|
||||
|
||||
|
|
|
@ -31,9 +31,8 @@ struct mStateExtdataHeader {
|
|||
int64_t offset;
|
||||
};
|
||||
|
||||
bool mStateExtdataInit(struct mStateExtdata* extdata) {
|
||||
void mStateExtdataInit(struct mStateExtdata* extdata) {
|
||||
memset(extdata->data, 0, sizeof(extdata->data));
|
||||
return true;
|
||||
}
|
||||
|
||||
void mStateExtdataDeinit(struct mStateExtdata* extdata) {
|
||||
|
@ -43,6 +42,7 @@ void mStateExtdataDeinit(struct mStateExtdata* extdata) {
|
|||
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) {
|
||||
|
@ -216,7 +216,7 @@ static int _loadPNGChunkHandler(png_structp png, png_unknown_chunkp chunk) {
|
|||
if (!strcmp((const char*) chunk->name, "gbAs")) {
|
||||
void* state = bundle->state;
|
||||
if (!state) {
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
uLongf len = bundle->stateSize;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
struct mStateExtdata extdata;
|
||||
mStateExtdataInit(&extdata);
|
||||
|
|
|
@ -7,12 +7,16 @@
|
|||
|
||||
#include "CoreController.h"
|
||||
#include "LogController.h"
|
||||
#include "VFileDevice.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/gba/core.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/gb/core.h>
|
||||
#endif
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
@ -27,6 +31,57 @@ void CoreManager::setMultiplayerController(MultiplayerController* 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) {
|
||||
QFileInfo info(path);
|
||||
if (!info.isReadable()) {
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include <mgba/core/serialize.h>
|
||||
|
||||
struct mCoreConfig;
|
||||
struct VFile;
|
||||
|
||||
|
@ -25,6 +27,8 @@ public:
|
|||
void setMultiplayerController(MultiplayerController*);
|
||||
void setPreload(bool preload) { m_preload = preload; }
|
||||
|
||||
static QByteArray getExtdata(const QString& filename, mStateExtdataTag extdataType);
|
||||
|
||||
public slots:
|
||||
CoreController* loadGame(const QString& path);
|
||||
CoreController* loadGame(VFile* vf, const QString& path, const QString& base);
|
||||
|
|
Loading…
Reference in New Issue