1 /*
2   DGen/SDL v1.27+
3 
4   Module for loading in the different ROM image types (.bin/.smd)
5 */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <errno.h>
11 #include "romload.h"
12 #include "system.h"
13 
14 static const char *rom_path = "roms";
15 
set_rom_path(const char * path)16 void set_rom_path(const char *path)
17 {
18 	rom_path = path;
19 }
20 
21 /*
22   WHAT YOU FIND IN THE 512 BYTES HEADER:
23 
24 0: Number of blocks                           1
25 1: H03                                        *
26 2: SPLIT?                                     2
27 8: HAA                                        *
28 9: HBB                                        *
29 ALL OTHER BYTES: H00
30 
31 1: This first byte should have the number of 16KB blocks the rom has.
32 The header isn't part of the formula, so this number is:
33             [size of rom-512]/16384
34    If the size is more than 255, the value should be H00.
35 
36 2: This byte indicates if the ROM is a part of a splitted rom series. If
37 the rom is the last part of the series (or isn't a splitted rom at all),
38 this byte should be H00. In other cases should be H40. See "CREATING
39 SPLITTED ROMS" for details on this format.
40 */
41 
42 /*
43   Allocate a buffer and stuff the named ROM inside. If rom_size is non-NULL,
44   store the ROM size there.
45 */
46 
load_rom(size_t * rom_size,const char * name)47 uint8_t *load_rom(size_t *rom_size, const char *name)
48 {
49 	FILE *file;
50 	size_t size;
51 	uint8_t *rom;
52 	int error;
53 	void *context = NULL;
54 
55 	if (name == NULL)
56 		return NULL;
57 	file = dgen_fopen(rom_path, name, (DGEN_READ | DGEN_CURRENT));
58 	if (file == NULL) {
59 		fprintf(stderr, "%s: can't open ROM file.\n", name);
60 		return NULL;
61 	}
62 retry:
63 	/* A valid ROM will surely not be bigger than 64MB. */
64 	rom = load(&context, &size, file, (64 * 1024 * 1024));
65 	error = errno;
66 	if (rom == NULL) {
67 		if (error)
68 			fprintf(stderr, "%s: unable to load ROM: %s.\n", name,
69 				strerror(error));
70 		else
71 			fprintf(stderr, "%s: no valid ROM found.\n",
72 				name);
73 		load_finish(&context);
74 		fclose(file);
75 		return NULL;
76 	}
77 	if (size < 512) {
78 		/* ROM file too small */
79 		unload(rom);
80 		goto retry;
81 	}
82 	/*
83 	  If "SEGA" isn't found at 0x100 and the total size minus 512 is a
84 	  multiple of 0x4000, it probably is a SMD.
85 	*/
86 	if (memcmp(&rom[0x100], "SEGA", 4)) {
87 		uint8_t *dst = rom;
88 		uint8_t *src = &rom[0x200];
89 		size_t chunks = ((size - 0x200) / 0x4000);
90 
91 		if (((size - 0x200) & (0x4000 - 1)) != 0)
92 			goto bad_rom;
93 		size -= 0x200;
94 		/* Corrupt ROM? Complain and continue anyway. */
95 		if (((rom[0] != 0x00) && (rom[0] != chunks)) ||
96 		    (rom[8] != 0xaa) || (rom[9] != 0xbb))
97 			fprintf(stderr, "%s: corrupt SMD header.\n", name);
98 		/*
99 		  De-interleave ROM, overwrite SMD header with the result.
100 		*/
101 		while (chunks) {
102 			size_t i;
103 			uint8_t tmp[0x2000];
104 
105 			memcpy(tmp, src, 0x2000);
106 			src += 0x2000;
107 			for (i = 0; (i != 0x2000); ++i) {
108 				*(dst++) = *(src++);
109 				*(dst++) = tmp[i];
110 			}
111 			--chunks;
112 		}
113 		/* Does it look like a valid ROM now? */
114 		if (memcmp(&rom[0x100], "SEGA", 4)) {
115 		bad_rom:
116 			/* Invalid ROM */
117 			unload(rom);
118 			goto retry;
119 		}
120 	}
121 	load_finish(&context);
122 	fclose(file);
123 	if (rom_size != NULL)
124 		*rom_size = size;
125 	return rom;
126 }
127 
unload_rom(uint8_t * rom)128 void unload_rom(uint8_t *rom)
129 {
130 	unload(rom);
131 }
132