all repos — mgba @ 37b2eb05ae944e85bad165fa95da7eaf0e75f7e0

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) {
 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	uint32_t calcChecksum = 0;
104	int i;
105	for (i = 0; i < size; ++i) {
106		calcChecksum += payload[i] << (calcChecksum % 24);
107	}
108
109	if (calcChecksum != checksum) {
110		goto cleanup;
111	}
112
113	uint32_t copySize = size - 0x1C;
114	switch (gba->memory.savedata.type) {
115	case SAVEDATA_SRAM:
116		if (copySize > SIZE_CART_SRAM) {
117			copySize = SIZE_CART_SRAM;
118		}
119		break;
120	case SAVEDATA_FLASH512:
121		if (copySize > SIZE_CART_FLASH512) {
122			GBASavedataForceType(&gba->memory.savedata, SAVEDATA_FLASH1M, gba->memory.savedata.realisticTiming);
123		}
124		// Fall through
125	case SAVEDATA_FLASH1M:
126		if (copySize > SIZE_CART_FLASH1M) {
127			copySize = SIZE_CART_FLASH1M;
128		}
129		break;
130	case SAVEDATA_EEPROM:
131		if (copySize > SIZE_CART_EEPROM) {
132			copySize = SAVEDATA_EEPROM;
133		}
134		break;
135	case SAVEDATA_FORCE_NONE:
136	case SAVEDATA_AUTODETECT:
137		goto cleanup;
138	}
139
140	memcpy(gba->memory.savedata.data, &payload[0x1C], copySize);
141
142	free(payload);
143	return true;
144
145cleanup:
146	free(payload);
147	return false;
148}
149
150
151bool GBASavedataExportSharkPort(const struct GBA* gba, struct VFile* vf) {
152	union {
153		char c[0x1C];
154		int32_t i;
155	} buffer;
156	int32_t size = strlen(SHARKPORT_HEADER);
157	STORE_32(size, 0, &buffer.i);
158	if (vf->write(vf, &buffer.i, 4) < 4) {
159		return false;
160	}
161	if (vf->write(vf, SHARKPORT_HEADER, size) < size) {
162		return false;
163	}
164
165	size = 0x000F0000;
166	STORE_32(size, 0, &buffer.i);
167	if (vf->write(vf, &buffer.i, 4) < 4) {
168		return false;
169	}
170
171	const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
172	size = sizeof(cart->title);
173	STORE_32(size, 0, &buffer.i);
174	if (vf->write(vf, &buffer.i, 4) < 4) {
175		return false;
176	}
177	if (vf->write(vf, cart->title, size) < 4) {
178		return false;
179	}
180
181	time_t t = time(0);
182	struct tm* tm = localtime(&t);
183	size = strftime(&buffer.c[4], sizeof(buffer.c) - 4, "%m/%d/%Y %I:%M:%S %p", tm);
184	STORE_32(size, 0, &buffer.i);
185	if (vf->write(vf, buffer.c, size + 4) < size + 4) {
186		return false;
187	}
188
189	// Last field is blank
190	size = 0;
191	STORE_32(size, 0, &buffer.i);
192	if (vf->write(vf, &buffer.i, 4) < 4) {
193		return false;
194	}
195
196	// Write payload
197	size = 0x1C;
198	switch (gba->memory.savedata.type) {
199	case SAVEDATA_SRAM:
200		size += SIZE_CART_SRAM;
201		break;
202	case SAVEDATA_FLASH512:
203		size += SIZE_CART_FLASH512;
204		break;
205	case SAVEDATA_FLASH1M:
206		size += SIZE_CART_FLASH1M;
207		break;
208	case SAVEDATA_EEPROM:
209		size += SIZE_CART_EEPROM;
210		break;
211	case SAVEDATA_FORCE_NONE:
212	case SAVEDATA_AUTODETECT:
213		return false;
214	}
215	STORE_32(size, 0, &buffer.i);
216	if (vf->write(vf, &buffer.i, 4) < 4) {
217		return false;
218	}
219	size -= 0x1C;
220
221	memcpy(buffer.c, cart->title, 16);
222	buffer.c[0x10] = 0;
223	buffer.c[0x11] = 0;
224	buffer.c[0x12] = cart->checksum;
225	buffer.c[0x13] = cart->maker;
226	buffer.c[0x14] = 1;
227	buffer.c[0x15] = 0;
228	buffer.c[0x16] = 0;
229	buffer.c[0x17] = 0;
230	buffer.c[0x18] = 0;
231	buffer.c[0x19] = 0;
232	buffer.c[0x1A] = 0;
233	buffer.c[0x1B] = 0;
234	if (vf->write(vf, buffer.c, 0x1C) < 0x1C) {
235		return false;
236	}
237
238	uint32_t checksum = 0;
239	int i;
240	for (i = 0; i < 0x1C; ++i) {
241		checksum += buffer.c[i] << (checksum % 24);
242	}
243
244	if (vf->write(vf, gba->memory.savedata.data, size) < size) {
245		return false;
246	}
247
248	for (i = 0; i < size; ++i) {
249		checksum += ((char) gba->memory.savedata.data[i]) << (checksum % 24);
250	}
251
252	STORE_32(checksum, 0, &buffer.i);
253	if (vf->write(vf, &buffer.i, 4) < 4) {
254		return false;
255	}
256
257	return true;
258}