6 // (C) 2010 Underground Software
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -------------------------------------------------------------
12 // JLH 01/16/2010 Created this log ;-)
13 // JLH 02/28/2010 Added functions to look inside .ZIP files and handle contents
28 // Private function prototypes
30 static int gzfilelength(gzFile gd);
31 static bool CheckExtension(const char * filename, const char * ext);
34 // Generic ROM loading
36 uint32 JaguarLoadROM(uint8 * rom, char * path)
38 // We really should have some kind of sanity checking for the ROM size here to prevent
39 // a buffer overflow... !!! FIX !!!
40 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
43 WriteLog("JaguarLoadROM: Attempting to load file '%s'...", path);
44 char * ext = strrchr(path, '.');
46 // No filename extension == YUO FAIL IT (it is loading the file).
47 // This is naive, but it works. But should probably come up with something a little
48 // more robust, to prevent problems with dopes trying to exploit this.
51 WriteLog("FAILED!\n");
55 WriteLog("Succeeded in finding extension (%s)!\n", ext);
56 WriteLog("VJ: Loading \"%s\"...", path);
58 if (strcasecmp(ext, ".zip") == 0)
60 // Handle ZIP file loading here...
61 WriteLog("(ZIPped)...");
63 uint8_t * buffer = NULL;
64 romSize = GetFileFromZIP(path, FT_SOFTWARE, buffer);
68 WriteLog("Failed!\n");
72 memcpy(rom, buffer, romSize);
77 // Handle gzipped files transparently [Adam Green]...
79 gzFile fp = gzopen(path, "rb");
83 WriteLog("Failed!\n");
87 romSize = gzfilelength(fp);
88 gzseek(fp, 0, SEEK_SET);
89 gzread(fp, rom, romSize);
93 WriteLog("OK (%i bytes)\n", romSize);
99 // Jaguar file loading
101 bool JaguarLoadFile(char * path)
103 // jaguarRomSize = JaguarLoadROM(mem, path);
104 jaguarROMSize = JaguarLoadROM(jaguarMainROM, path);
106 /*//This is not *nix friendly for some reason...
107 // if (!UserSelectFile(path, newPath))
108 if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
110 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
115 if (jaguarROMSize == 0)
117 // WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
118 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
119 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
122 return false; // This is a start...
125 jaguarMainROMCRC32 = crc32_calcCheckSum(jaguarMainROM, jaguarROMSize);
126 WriteLog("CRC: %08X\n", (unsigned int)jaguarMainROMCRC32);
129 jaguarRunAddress = 0x802000;
131 char * ext = strrchr(path, '.'); // Get the file's extension for non-cartridge checking
133 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
134 #warning "!!! Need more robust file type checking in JaguarLoadROM() !!!"
135 if (strcasecmp(ext, ".rom") == 0)
137 // File extension ".ROM": Alpine image that loads/runs at $802000
138 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarROMSize);
140 for(int i=jaguarROMSize-1; i>=0; i--)
141 jaguarMainROM[0x2000 + i] = jaguarMainROM[i];
143 memset(jaguarMainROM, 0xFF, 0x2000);
144 /* memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
145 memset(jaguar_mainRom, 0xFF, 0x600000);
146 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
147 memset(jaguar_mainRam, 0x00, 0x400000);*/
150 Stubulator ROM vectors...
151 handler 001 at $00E00008
152 handler 002 at $00E008DE
153 handler 003 at $00E008E2
154 handler 004 at $00E008E6
155 handler 005 at $00E008EA
156 handler 006 at $00E008EE
157 handler 007 at $00E008F2
158 handler 008 at $00E0054A
159 handler 009 at $00E008FA
160 handler 010 at $00000000
161 handler 011 at $00000000
162 handler 012 at $00E008FE
163 handler 013 at $00E00902
164 handler 014 at $00E00906
165 handler 015 at $00E0090A
166 handler 016 at $00E0090E
167 handler 017 at $00E00912
168 handler 018 at $00E00916
169 handler 019 at $00E0091A
170 handler 020 at $00E0091E
171 handler 021 at $00E00922
172 handler 022 at $00E00926
173 handler 023 at $00E0092A
174 handler 024 at $00E0092E
175 handler 025 at $00E0107A
176 handler 026 at $00E0107A
177 handler 027 at $00E0107A
178 handler 028 at $00E008DA
179 handler 029 at $00E0107A
180 handler 030 at $00E0107A
181 handler 031 at $00E0107A
182 handler 032 at $00000000
184 Let's try setting up the illegal instruction vector for a stubulated jaguar...
186 /* SET32(jaguar_mainRam, 0x08, 0x00E008DE);
187 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
188 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
189 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
191 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
192 // This kludge works! Yeah!
193 SET32(jaguarMainRAM, 0x10, 0x00001000);
194 SET16(jaguarMainRAM, 0x1000, 0x60FE); // Here: bra Here
196 else if (strcasecmp(ext, ".abs") == 0)
198 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
201 ABS Format sleuthing (LBUGDEMO.ABS):
203 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
204 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
207 DRI-format file detected...
208 Text segment size = 0x0000050c bytes
209 Data segment size = 0x000462c0 bytes
210 BSS Segment size = 0x00000428 bytes
211 Symbol Table size = 0x000012a6 bytes
212 Absolute Address for text segment = 0x00802000
213 Absolute Address for data segment = 0x0080250c
214 Absolute Address for BSS segment = 0x00004000
217 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
218 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
219 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
221 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
222 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
223 000050 00 00 00 00 00 00 00 20
224 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
225 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
226 000078 00 00 00 00 00 00 00 40
227 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
228 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
229 0000a0 00 00 00 00 00 00 00 80
231 Header size is $A8 bytes...
233 BSD/COFF format file detected...
235 Symbol Table offset = 230160 ($00038310)
236 Symbol Table contains 1339 symbol entries ($0000053B)
237 The additional header size is 28 bytes ($001C)
238 Magic Number for RUN_HDR = 0x00000107
239 Text Segment Size = 7632 ($00001DD0)
240 Data Segment Size = 222360 ($00036498)
241 BSS Segment Size = 428928 ($00068B80)
242 Starting Address for executable = 0x00802000
243 Start of Text Segment = 0x00802000
244 Start of Data Segment = 0x00803dd0
246 if (jaguarMainROM[0] == 0x60 && jaguarMainROM[1] == 0x1B)
248 uint32 loadAddress = GET32(jaguarMainROM, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
249 codeSize = GET32(jaguarMainROM, 0x02) + GET32(jaguarMainROM, 0x06);
250 WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
252 if (loadAddress < 0x800000)
253 memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0x24, codeSize);
256 for(int i=codeSize-1; i>=0; i--)
257 jaguarMainROM[(loadAddress - 0x800000) + i] = jaguarMainROM[i + 0x24];
258 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
259 memset(jaguar_mainRom, 0xFF, 0x600000);
260 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
261 memset(jaguar_mainRam, 0x00, 0x400000);*/
264 jaguarRunAddress = loadAddress;
266 else if (jaguarMainROM[0] == 0x01 && jaguarMainROM[1] == 0x50)
268 uint32 loadAddress = GET32(jaguarMainROM, 0x28), runAddress = GET32(jaguarMainROM, 0x24),
269 codeSize = GET32(jaguarMainROM, 0x18) + GET32(jaguarMainROM, 0x1C);
270 WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
272 if (loadAddress < 0x800000)
273 memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0xA8, codeSize);
276 for(int i=codeSize-1; i>=0; i--)
277 jaguarMainROM[(loadAddress - 0x800000) + i] = jaguarMainROM[i + 0xA8];
278 /* memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
279 memset(jaguar_mainRom, 0xFF, 0x600000);
280 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
281 memset(jaguar_mainRam, 0x00, 0x400000);*/
284 jaguarRunAddress = runAddress;
288 WriteLog("GUI: Couldn't find correct ABS/COF format: %02X %02X\n", jaguarMainROM[0], jaguarMainROM[1]);
292 else if (strcasecmp(ext, ".jag") == 0)
294 // File extension ".JAG": Atari server file with header
295 //NOTE: The bytes 'JAGR' should also be at position $1C...
296 // Also, there's *always* a $601A header at position $00...
297 if (jaguarMainROM[0] == 0x60 && jaguarMainROM[1] == 0x1A)
299 uint32 loadAddress = GET32(jaguarMainROM, 0x22), runAddress = GET32(jaguarMainROM, 0x2A);
300 //This is not always right! Especially when converted via bin2jag1!!!
301 //We should have access to the length of the furshlumiger file that was loaded anyway!
303 // uint32 progLength = GET32(jaguar_mainRom, 0x02);
306 // WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
307 // memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
308 WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarROMSize - 0x2E);
309 memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0x2E, jaguarROMSize - 0x2E);
310 // SET32(jaguar_mainRam, 4, runAddress);
311 jaguarRunAddress = runAddress;
316 // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
322 // Get the length of a (possibly) gzipped file
324 static int gzfilelength(gzFile gd)
326 int size = 0, length = 0;
327 unsigned char buffer[0x10000];
333 // Read in chunks until EOF
334 size = gzread(gd, buffer, 0x10000);
348 // Compare extension to passed in filename. If equal, return true; otherwise false.
350 static bool CheckExtension(const char * filename, const char * ext)
352 const char * filenameExt = strrchr(filename, '.'); // Get the file's extension (if any)
353 return (strcasecmp(filenameExt, ext) == 0 ? true : false);
357 // Get file from .ZIP
358 // Returns the size of the file inside the .ZIP file that we're looking at
359 // NOTE: If the thing we're looking for is found, it allocates it in the passed in buffer.
360 // Which means we have to deallocate it later.
362 uint32 GetFileFromZIP(const char * zipFile, FileType type, uint8 * &buffer)
364 // NOTE: We could easily check for this by discarding anything that's larger than the RAM/ROM
365 // size of the Jaguar console.
366 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
367 const char ftStrings[5][32] = { "Software", "EEPROM", "Label", "Box Art", "Controller Overlay" };
368 ZIP * zip = openzip(0, 0, zipFile);
372 WriteLog("FILE: Could not open file '%s'!\n", zipFile);
378 zipent * ze = &zip->ent;
381 // Here we simply rely on the file extension to tell the truth, but we know
382 // that extensions lie like sons-a-bitches. So this is naive, we need to do
383 // something a little more robust to keep bad things from happening here.
384 #warning "!!! Checking for image by extension can be fooled !!!"
385 if ((type == FT_LABEL) && (CheckExtension(ze->name, ".png") || CheckExtension(ze->name, ".jpg") || CheckExtension(ze->name, ".gif")))
388 WriteLog("FILE: Found image file '%s'.\n", ze->name);
391 if ((type == FT_SOFTWARE) && (CheckExtension(ze->name, ".j64") || CheckExtension(ze->name, ".rom") || CheckExtension(ze->name, ".abs") || CheckExtension(ze->name, ".cof")))
394 WriteLog("FILE: Found software file '%s'.\n", ze->name);
397 if ((type == FT_EEPROM) && (CheckExtension(ze->name, ".eep") || CheckExtension(ze->name, ".eeprom")))
400 WriteLog("FILE: Found EEPROM file '%s'.\n", ze->name);
405 WriteLog("FILE: Uncompressing...");
406 // Insert file size sanity check here...
407 buffer = new uint8[ze->uncompressed_size];
409 if (readuncompresszip(zip, ze, (char *)buffer) == 0)
411 WriteLog("success! (%u bytes)\n", ze->uncompressed_size);
413 return ze->uncompressed_size;
417 WriteLog("FAILED!\n");
428 WriteLog("FILE: Failed to find file of type %s...\n", ftStrings[type]);
429 // Didn't find what we're looking for...
433 //ParseFileType, etc.