all repos — mgba @ 5b80b8e4c748e1b3128f645763f141c993827acf

mGBA Game Boy Advance Emulator

src/gba/sharkport.c (view raw)

  1/* Copyright (c) 2013-2015 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 "sharkport.h"
  7
  8#include "gba/gba.h"
  9#include "util/vfs.h"
 10
 11static const char* const SHARKPORT_HEADER = "SharkPortSave";
 12
 13bool GBASavedataImportSharkPort(struct GBA* gba, struct VFile* vf, bool testChecksum) {
 14	union {
 15		char c[0x1C];
 16		int32_t i;
 17	} buffer;
 18	if (vf->read(vf, &buffer.i, 4) < 4) {
 19		return false;
 20	}
 21	int32_t size;
 22	LOAD_32(size, 0, &buffer.i);
 23	if (size != (int32_t) strlen(SHARKPORT_HEADER)) {
 24		return false;
 25	}
 26	if (vf->read(vf, buffer.c, size) < size) {
 27		return false;
 28	}
 29	if (memcmp(SHARKPORT_HEADER, buffer.c, size) != 0) {
 30		return false;
 31	}
 32	if (vf->read(vf, &buffer.i, 4) < 4) {
 33		return false;
 34	}
 35	LOAD_32(size, 0, &buffer.i);
 36	if (size != 0x000F0000) {
 37		// What is this value?
 38		return false;
 39	}
 40
 41	// Skip first three fields
 42	if (vf->read(vf, &buffer.i, 4) < 4) {
 43		return false;
 44	}
 45	LOAD_32(size, 0, &buffer.i);
 46	if (vf->seek(vf, size, SEEK_CUR) < 0) {
 47		return false;
 48	}
 49
 50	if (vf->read(vf, &buffer.i, 4) < 4) {
 51		return false;
 52	}
 53	LOAD_32(size, 0, &buffer.i);
 54	if (vf->seek(vf, size, SEEK_CUR) < 0) {
 55		return false;
 56	}
 57
 58	if (vf->read(vf, &buffer.i, 4) < 4) {
 59		return false;
 60	}
 61	LOAD_32(size, 0, &buffer.i);
 62	if (vf->seek(vf, size, SEEK_CUR) < 0) {
 63		return false;
 64	}
 65
 66	// Read payload
 67	if (vf->read(vf, &buffer.i, 4) < 4) {
 68		return false;
 69	}
 70	LOAD_32(size, 0, &buffer.i);
 71	if (size < 0x1C || size > SIZE_CART_FLASH1M + 0x1C) {
 72		return false;
 73	}
 74	char* payload = malloc(size);
 75	if (vf->read(vf, payload, size) < size) {
 76		goto cleanup;
 77	}
 78
 79	struct GBACartridge* cart = (struct GBACartridge*) gba->memory.rom;
 80	memcpy(buffer.c, &cart->title, 16);
 81	buffer.c[0x10] = 0;
 82	buffer.c[0x11] = 0;
 83	buffer.c[0x12] = cart->checksum;
 84	buffer.c[0x13] = cart->maker;
 85	buffer.c[0x14] = 1;
 86	buffer.c[0x15] = 0;
 87	buffer.c[0x16] = 0;
 88	buffer.c[0x17] = 0;
 89	buffer.c[0x18] = 0;
 90	buffer.c[0x19] = 0;
 91	buffer.c[0x1A] = 0;
 92	buffer.c[0x1B] = 0;
 93	if (memcmp(buffer.c, payload, 0x1C) != 0) {
 94		goto cleanup;
 95	}
 96
 97	uint32_t checksum;
 98	if (vf->read(vf, &buffer.i, 4) < 4) {
 99		goto cleanup;
100	}
101	LOAD_32(checksum, 0, &buffer.i);
102
103	if (testChecksum) {
104		uint32_t calcChecksum = 0;
105		int i;
106		for (i = 0; i < size; ++i) {
107			calcChecksum += ((int32_t) payload[i]) << (calcChecksum % 24);
108		}
109
110		if (calcChecksum != checksum) {
111			goto cleanup;
112		}
113	}
114
115	uint32_t copySize = size - 0x1C;
116	switch (gba->memory.savedata.type) {
117	case SAVEDATA_SRAM:
118		if (copySize > SIZE_CART_SRAM) {
119			copySize = SIZE_CART_SRAM;
120		}
121		break;
122	case SAVEDATA_FLASH512:
123		if (copySize > SIZE_CART_FLASH512) {
124			GBASavedataForceType(&gba->memory.savedata, SAVEDATA_FLASH1M, gba->memory.savedata.realisticTiming);
125		}
126	// Fall through
127	case SAVEDATA_FLASH1M:
128		if (copySize > SIZE_CART_FLASH1M) {
129			copySize = SIZE_CART_FLASH1M;
130		}
131		break;
132	case SAVEDATA_EEPROM:
133		if (copySize > SIZE_CART_EEPROM) {
134			copySize = SAVEDATA_EEPROM;
135		}
136		break;
137	case SAVEDATA_FORCE_NONE:
138	case SAVEDATA_AUTODETECT:
139		goto cleanup;
140	}
141
142	memcpy(gba->memory.savedata.data, &payload[0x1C], copySize);
143
144	free(payload);
145	return true;
146
147cleanup:
148	free(payload);
149	return false;
150}
151
152bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) {
153	union {
154		char c[0x1C];
155		int32_t i;
156	} buffer;
157	int32_t size = strlen(SHARKPORT_HEADER);
158	STORE_32(size, 0, &buffer.i);
159	if (vf->write(vf, &buffer.i, 4) < 4) {
160		return false;
161	}
162	if (vf->write(vf, SHARKPORT_HEADER, size) < size) {
163		return false;
164	}
165
166	size = 0x000F0000;
167	STORE_32(size, 0, &buffer.i);
168	if (vf->write(vf, &buffer.i, 4) < 4) {
169		return false;
170	}
171
172	const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
173	size = sizeof(cart->title);
174	STORE_32(size, 0, &buffer.i);
175	if (vf->write(vf, &buffer.i, 4) < 4) {
176		return false;
177	}
178	if (vf->write(vf, cart->title, size) < 4) {
179		return false;
180	}
181
182	time_t t = time(0);
183	struct tm* tm = localtime(&t);
184	size = strftime(&buffer.c[4], sizeof(buffer.c) - 4, "%m/%d/%Y %I:%M:%S %p", tm);
185	STORE_32(size, 0, &buffer.i);
186	if (vf->write(vf, buffer.c, size + 4) < size + 4) {
187		return false;
188	}
189
190	// Last field is blank
191	size = 0;
192	STORE_32(size, 0, &buffer.i);
193	if (vf->write(vf, &buffer.i, 4) < 4) {
194		return false;
195	}
196
197	// Write payload
198	size = 0x1C;
199	switch (gba->memory.savedata.type) {
200	case SAVEDATA_SRAM:
201		size += SIZE_CART_SRAM;
202		break;
203	case SAVEDATA_FLASH512:
204		size += SIZE_CART_FLASH512;
205		break;
206	case SAVEDATA_FLASH1M:
207		size += SIZE_CART_FLASH1M;
208		break;
209	case SAVEDATA_EEPROM:
210		size += SIZE_CART_EEPROM;
211		break;
212	case SAVEDATA_FORCE_NONE:
213	case SAVEDATA_AUTODETECT:
214		return false;
215	}
216	STORE_32(size, 0, &buffer.i);
217	if (vf->write(vf, &buffer.i, 4) < 4) {
218		return false;
219	}
220	size -= 0x1C;
221
222	memcpy(buffer.c, &cart->title, 16);
223	buffer.c[0x10] = 0;
224	buffer.c[0x11] = 0;
225	buffer.c[0x12] = cart->checksum;
226	buffer.c[0x13] = cart->maker;
227	buffer.c[0x14] = 1;
228	buffer.c[0x15] = 0;
229	buffer.c[0x16] = 0;
230	buffer.c[0x17] = 0;
231	buffer.c[0x18] = 0;
232	buffer.c[0x19] = 0;
233	buffer.c[0x1A] = 0;
234	buffer.c[0x1B] = 0;
235	if (vf->write(vf, buffer.c, 0x1C) < 0x1C) {
236		return false;
237	}
238
239	uint32_t checksum = 0;
240	int i;
241	for (i = 0; i < 0x1C; ++i) {
242		checksum += buffer.c[i] << (checksum % 24);
243	}
244
245	if (vf->write(vf, gba->memory.savedata.data, size) < size) {
246		return false;
247	}
248
249	for (i = 0; i < size; ++i) {
250		checksum += ((char) gba->memory.savedata.data[i]) << (checksum % 24);
251	}
252
253	STORE_32(checksum, 0, &buffer.i);
254	if (vf->write(vf, &buffer.i, 4) < 4) {
255		return false;
256	}
257
258	return true;
259}