all repos — mgba @ d091de405744fee93eacfe55106ead3b2a03f16e

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
152
153bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) {
154	union {
155		char c[0x1C];
156		int32_t i;
157	} buffer;
158	int32_t size = strlen(SHARKPORT_HEADER);
159	STORE_32(size, 0, &buffer.i);
160	if (vf->write(vf, &buffer.i, 4) < 4) {
161		return false;
162	}
163	if (vf->write(vf, SHARKPORT_HEADER, size) < size) {
164		return false;
165	}
166
167	size = 0x000F0000;
168	STORE_32(size, 0, &buffer.i);
169	if (vf->write(vf, &buffer.i, 4) < 4) {
170		return false;
171	}
172
173	const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
174	size = sizeof(cart->title);
175	STORE_32(size, 0, &buffer.i);
176	if (vf->write(vf, &buffer.i, 4) < 4) {
177		return false;
178	}
179	if (vf->write(vf, cart->title, size) < 4) {
180		return false;
181	}
182
183	time_t t = time(0);
184	struct tm* tm = localtime(&t);
185	size = strftime(&buffer.c[4], sizeof(buffer.c) - 4, "%m/%d/%Y %I:%M:%S %p", tm);
186	STORE_32(size, 0, &buffer.i);
187	if (vf->write(vf, buffer.c, size + 4) < size + 4) {
188		return false;
189	}
190
191	// Last field is blank
192	size = 0;
193	STORE_32(size, 0, &buffer.i);
194	if (vf->write(vf, &buffer.i, 4) < 4) {
195		return false;
196	}
197
198	// Write payload
199	size = 0x1C;
200	switch (gba->memory.savedata.type) {
201	case SAVEDATA_SRAM:
202		size += SIZE_CART_SRAM;
203		break;
204	case SAVEDATA_FLASH512:
205		size += SIZE_CART_FLASH512;
206		break;
207	case SAVEDATA_FLASH1M:
208		size += SIZE_CART_FLASH1M;
209		break;
210	case SAVEDATA_EEPROM:
211		size += SIZE_CART_EEPROM;
212		break;
213	case SAVEDATA_FORCE_NONE:
214	case SAVEDATA_AUTODETECT:
215		return false;
216	}
217	STORE_32(size, 0, &buffer.i);
218	if (vf->write(vf, &buffer.i, 4) < 4) {
219		return false;
220	}
221	size -= 0x1C;
222
223	memcpy(buffer.c, cart->title, 16);
224	buffer.c[0x10] = 0;
225	buffer.c[0x11] = 0;
226	buffer.c[0x12] = cart->checksum;
227	buffer.c[0x13] = cart->maker;
228	buffer.c[0x14] = 1;
229	buffer.c[0x15] = 0;
230	buffer.c[0x16] = 0;
231	buffer.c[0x17] = 0;
232	buffer.c[0x18] = 0;
233	buffer.c[0x19] = 0;
234	buffer.c[0x1A] = 0;
235	buffer.c[0x1B] = 0;
236	if (vf->write(vf, buffer.c, 0x1C) < 0x1C) {
237		return false;
238	}
239
240	uint32_t checksum = 0;
241	int i;
242	for (i = 0; i < 0x1C; ++i) {
243		checksum += buffer.c[i] << (checksum % 24);
244	}
245
246	if (vf->write(vf, gba->memory.savedata.data, size) < size) {
247		return false;
248	}
249
250	for (i = 0; i < size; ++i) {
251		checksum += ((char) gba->memory.savedata.data[i]) << (checksum % 24);
252	}
253
254	STORE_32(checksum, 0, &buffer.i);
255	if (vf->write(vf, &buffer.i, 4) < 4) {
256		return false;
257	}
258
259	return true;
260}