all repos — mgba @ f4dc546da68a757b6e8c04a379583909902f3628

mGBA Game Boy Advance Emulator

src/core/serialize.c (view raw)

  1/* Copyright (c) 2013-2016 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 "serialize.h"
  7
  8#include "util/vfs.h"
  9
 10struct mStateExtdataHeader {
 11	uint32_t tag;
 12	int32_t size;
 13	int64_t offset;
 14};
 15
 16bool mStateExtdataInit(struct mStateExtdata* extdata) {
 17	memset(extdata->data, 0, sizeof(extdata->data));
 18	return true;
 19}
 20
 21void mStateExtdataDeinit(struct mStateExtdata* extdata) {
 22	size_t i;
 23	for (i = 1; i < EXTDATA_MAX; ++i) {
 24		if (extdata->data[i].data && extdata->data[i].clean) {
 25			extdata->data[i].clean(extdata->data[i].data);
 26		}
 27	}
 28}
 29
 30void mStateExtdataPut(struct mStateExtdata* extdata, enum mStateExtdataTag tag, struct mStateExtdataItem* item) {
 31	if (tag == EXTDATA_NONE || tag >= EXTDATA_MAX) {
 32		return;
 33	}
 34
 35	if (extdata->data[tag].data && extdata->data[tag].clean) {
 36		extdata->data[tag].clean(extdata->data[tag].data);
 37	}
 38	extdata->data[tag] = *item;
 39}
 40
 41bool mStateExtdataGet(struct mStateExtdata* extdata, enum mStateExtdataTag tag, struct mStateExtdataItem* item) {
 42	if (tag == EXTDATA_NONE || tag >= EXTDATA_MAX) {
 43		return false;
 44	}
 45
 46	*item = extdata->data[tag];
 47	return true;
 48}
 49
 50bool mStateExtdataSerialize(struct mStateExtdata* extdata, struct VFile* vf) {
 51	ssize_t position = vf->seek(vf, 0, SEEK_CUR);
 52	ssize_t size = sizeof(struct mStateExtdataHeader);
 53	size_t i = 0;
 54	for (i = 1; i < EXTDATA_MAX; ++i) {
 55		if (extdata->data[i].data) {
 56			size += sizeof(struct mStateExtdataHeader);
 57		}
 58	}
 59	if (size == sizeof(struct mStateExtdataHeader)) {
 60		return true;
 61	}
 62	struct mStateExtdataHeader* header = malloc(size);
 63	position += size;
 64
 65	size_t j;
 66	for (i = 1, j = 0; i < EXTDATA_MAX; ++i) {
 67		if (extdata->data[i].data) {
 68			STORE_32LE(i, offsetof(struct mStateExtdataHeader, tag), &header[j]);
 69			STORE_32LE(extdata->data[i].size, offsetof(struct mStateExtdataHeader, size), &header[j]);
 70			STORE_64LE(position, offsetof(struct mStateExtdataHeader, offset), &header[j]);
 71			position += extdata->data[i].size;
 72			++j;
 73		}
 74	}
 75	header[j].tag = 0;
 76	header[j].size = 0;
 77	header[j].offset = 0;
 78
 79	if (vf->write(vf, header, size) != size) {
 80		free(header);
 81		return false;
 82	}
 83	free(header);
 84
 85	for (i = 1; i < EXTDATA_MAX; ++i) {
 86		if (extdata->data[i].data) {
 87			if (vf->write(vf, extdata->data[i].data, extdata->data[i].size) != extdata->data[i].size) {
 88				return false;
 89			}
 90		}
 91	}
 92	return true;
 93}
 94
 95bool mStateExtdataDeserialize(struct mStateExtdata* extdata, struct VFile* vf) {
 96	while (true) {
 97		struct mStateExtdataHeader buffer, header;
 98		if (vf->read(vf, &buffer, sizeof(buffer)) != sizeof(buffer)) {
 99			return false;
100		}
101		LOAD_32LE(header.tag, 0, &buffer.tag);
102		LOAD_32LE(header.size, 0, &buffer.size);
103		LOAD_64LE(header.offset, 0, &buffer.offset);
104
105		if (header.tag == EXTDATA_NONE) {
106			break;
107		}
108		if (header.tag >= EXTDATA_MAX) {
109			continue;
110		}
111		ssize_t position = vf->seek(vf, 0, SEEK_CUR);
112		if (vf->seek(vf, header.offset, SEEK_SET) < 0) {
113			return false;
114		}
115		struct mStateExtdataItem item = {
116			.data = malloc(header.size),
117			.size = header.size,
118			.clean = free
119		};
120		if (!item.data) {
121			continue;
122		}
123		if (vf->read(vf, item.data, header.size) != header.size) {
124			free(item.data);
125			continue;
126		}
127		mStateExtdataPut(extdata, header.tag, &item);
128		vf->seek(vf, position, SEEK_SET);
129	};
130	return true;
131}