]> Shamusworld >> Repos - virtualjaguar/blob - src/file.cpp
Initial changeset to experimental branch
[virtualjaguar] / src / file.cpp
1 //
2 // FILE.CPP
3 //
4 // File support
5 // by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -------------------------------------------------------------
12 // JLH  01/16/2010  Created this log ;-)
13 //
14
15 #include "file.h"
16
17 #include <stdarg.h>
18 #include <string.h>
19 #include "crc32.h"
20 #include "eeprom.h"
21 #include "jaguar.h"
22 #include "log.h"
23 #include "memory.h"
24 #include "unzip.h"
25 #include "zlib.h"
26
27 // Private function prototypes
28
29 static int gzfilelength(gzFile gd);
30
31 //
32 // Generic ROM loading
33 //
34 uint32 JaguarLoadROM(uint8 * rom, char * path)
35 {
36 // We really should have some kind of sanity checking for the ROM size here to prevent
37 // a buffer overflow... !!! FIX !!!
38 #warning !!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!
39         uint32 romSize = 0;
40
41 WriteLog("JaguarLoadROM: Attempting to load file '%s'...", path);
42         char * ext = strrchr(path, '.');
43 if (ext == NULL)
44         WriteLog("FAILED!\n");
45 else
46         WriteLog("Succeeded in finding extension (%s)!\n", ext);
47
48         if (ext != NULL)
49         {
50                 WriteLog("VJ: Loading \"%s\"...", path);
51
52                 if (strcasecmp(ext, ".zip") == 0)
53                 {
54                         // Handle ZIP file loading here...
55                         WriteLog("(ZIPped)...");
56
57                         if (load_zipped_file(0, 0, path, NULL, &rom, &romSize) == -1)
58                         {
59                                 WriteLog("Failed!\n");
60                                 return 0;
61                         }
62                 }
63                 else
64                 {
65 /*                      FILE * fp = fopen(path, "rb");
66
67                         if (fp == NULL)
68                         {
69                                 WriteLog("Failed!\n");
70                                 return 0;
71                         }
72
73                         fseek(fp, 0, SEEK_END);
74                         romSize = ftell(fp);
75                         fseek(fp, 0, SEEK_SET);
76                         fread(rom, 1, romSize, fp);
77                         fclose(fp);*/
78
79                         // Handle gzipped files transparently [Adam Green]...
80
81                         gzFile fp = gzopen(path, "rb");
82
83                         if (fp == NULL)
84                         {
85                                 WriteLog("Failed!\n");
86                                 return 0;
87                         }
88
89                         romSize = gzfilelength(fp);
90                         gzseek(fp, 0, SEEK_SET);
91                         gzread(fp, rom, romSize);
92                         gzclose(fp);
93                 }
94
95                 WriteLog("OK (%i bytes)\n", romSize);
96         }
97
98         return romSize;
99 }
100
101 //
102 // Jaguar file loading
103 //
104 bool JaguarLoadFile(char * path)
105 {
106 //      jaguarRomSize = JaguarLoadROM(mem, path);
107         jaguarROMSize = JaguarLoadROM(jaguarMainROM, path);
108
109 /*//This is not *nix friendly for some reason...
110 //              if (!UserSelectFile(path, newPath))
111         if (!UserSelectFile((strlen(path) == 0 ? (char *)"." : path), newPath))
112         {
113                 WriteLog("VJ: Could not find valid ROM in directory \"%s\"...\nAborting!\n", path);
114                 log_done();
115                 exit(0);
116         }*/
117
118         if (jaguarROMSize == 0)
119         {
120 //                      WriteLog("VJ: Could not load ROM from file \"%s\"...\nAborting!\n", newPath);
121                 WriteLog("GUI: Could not load ROM from file \"%s\"...\nAborting load!\n", path);
122 // Need to do something else here, like throw up an error dialog instead of aborting. !!! FIX !!!
123 //              log_done();
124 //              exit(0);
125                 return false;                                                           // This is a start...
126         }
127
128         jaguarMainROMCRC32 = crc32_calcCheckSum(jaguarMainROM, jaguarROMSize);
129         WriteLog("CRC: %08X\n", (unsigned int)jaguarMainROMCRC32);
130         EepromInit();
131
132         jaguarRunAddress = 0x802000;
133
134         char * ext = strrchr(path, '.');                                // Get the file's extension for non-cartridge checking
135
136 //NOTE: Should fix JaguarLoadROM() to replace .zip with what's *in* the zip (.abs, .j64, etc.)
137         if (strcasecmp(ext, ".rom") == 0)
138         {
139                 // File extension ".ROM": Alpine image that loads/runs at $802000
140                 WriteLog("GUI: Setting up homebrew (ROM)... Run address: 00802000, length: %08X\n", jaguarROMSize);
141
142                 for(int i=jaguarROMSize-1; i>=0; i--)
143                         jaguarMainROM[0x2000 + i] = jaguarMainROM[i];
144
145                 memset(jaguarMainROM, 0xFF, 0x2000);
146 /*              memcpy(jaguar_mainRam, jaguar_mainRom, jaguarRomSize);
147                 memset(jaguar_mainRom, 0xFF, 0x600000);
148                 memcpy(jaguar_mainRom + 0x2000, jaguar_mainRam, jaguarRomSize);
149                 memset(jaguar_mainRam, 0x00, 0x400000);*/
150
151 /*
152 Stubulator ROM vectors...
153 handler 001 at $00E00008
154 handler 002 at $00E008DE
155 handler 003 at $00E008E2
156 handler 004 at $00E008E6
157 handler 005 at $00E008EA
158 handler 006 at $00E008EE
159 handler 007 at $00E008F2
160 handler 008 at $00E0054A
161 handler 009 at $00E008FA
162 handler 010 at $00000000
163 handler 011 at $00000000
164 handler 012 at $00E008FE
165 handler 013 at $00E00902
166 handler 014 at $00E00906
167 handler 015 at $00E0090A
168 handler 016 at $00E0090E
169 handler 017 at $00E00912
170 handler 018 at $00E00916
171 handler 019 at $00E0091A
172 handler 020 at $00E0091E
173 handler 021 at $00E00922
174 handler 022 at $00E00926
175 handler 023 at $00E0092A
176 handler 024 at $00E0092E
177 handler 025 at $00E0107A
178 handler 026 at $00E0107A
179 handler 027 at $00E0107A
180 handler 028 at $00E008DA
181 handler 029 at $00E0107A
182 handler 030 at $00E0107A
183 handler 031 at $00E0107A
184 handler 032 at $00000000
185
186 Let's try setting up the illegal instruction vector for a stubulated jaguar...
187 */
188 /*              SET32(jaguar_mainRam, 0x08, 0x00E008DE);
189                 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
190                 SET32(jaguar_mainRam, 0x10, 0x00E008E6);        // <-- Should be here (it is)...
191                 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
192
193                 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
194                 // This kludge works! Yeah!
195                 SET32(jaguarMainRAM, 0x10, 0x00001000);
196                 SET16(jaguarMainRAM, 0x1000, 0x60FE);           // Here: bra Here
197         }
198         else if (strcasecmp(ext, ".abs") == 0)
199         {
200                 // File extension ".ABS": Atari linker output file with header (w/o is useless to us here)
201
202 /*
203 ABS Format sleuthing (LBUGDEMO.ABS):
204
205 000000  60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
206 000010  12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
207 000020  00 00 40 00
208
209 DRI-format file detected...
210 Text segment size = 0x0000050c bytes
211 Data segment size = 0x000462c0 bytes
212 BSS Segment size = 0x00000428 bytes
213 Symbol Table size = 0x000012a6 bytes
214 Absolute Address for text segment = 0x00802000
215 Absolute Address for data segment = 0x0080250c
216 Absolute Address for BSS segment = 0x00004000
217
218 (CRZDEMO.ABS):
219 000000  01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
220 000010  00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
221 000020  00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
222
223 000030  2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
224 000040  00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
225 000050  00 00 00 00 00 00 00 20
226 000058  2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
227 000068  00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
228 000078  00 00 00 00 00 00 00 40
229 000080  2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
230 000090  00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
231 0000a0  00 00 00 00 00 00 00 80
232
233 Header size is $A8 bytes...
234
235 BSD/COFF format file detected...
236 3 sections specified
237 Symbol Table offset = 230160                            ($00038310)
238 Symbol Table contains 1339 symbol entries       ($0000053B)
239 The additional header size is 28 bytes          ($001C)
240 Magic Number for RUN_HDR = 0x00000107
241 Text Segment Size = 7632                                        ($00001DD0)
242 Data Segment Size = 222360                                      ($00036498)
243 BSS Segment Size = 428928                                       ($00068B80)
244 Starting Address for executable = 0x00802000
245 Start of Text Segment = 0x00802000
246 Start of Data Segment = 0x00803dd0
247 */
248                 if (jaguarMainROM[0] == 0x60 && jaguarMainROM[1] == 0x1B)
249                 {
250                         uint32 loadAddress = GET32(jaguarMainROM, 0x16), //runAddress = GET32(jaguar_mainRom, 0x2A),
251                                 codeSize = GET32(jaguarMainROM, 0x02) + GET32(jaguarMainROM, 0x06);
252                         WriteLog("GUI: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress, codeSize);
253
254                         if (loadAddress < 0x800000)
255                                 memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0x24, codeSize);
256                         else
257                         {
258                                 for(int i=codeSize-1; i>=0; i--)
259                                         jaguarMainROM[(loadAddress - 0x800000) + i] = jaguarMainROM[i + 0x24];
260 /*                              memcpy(jaguar_mainRam, jaguar_mainRom + 0x24, codeSize);
261                                 memset(jaguar_mainRom, 0xFF, 0x600000);
262                                 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
263                                 memset(jaguar_mainRam, 0x00, 0x400000);*/
264                         }
265
266                         jaguarRunAddress = loadAddress;
267                 }
268                 else if (jaguarMainROM[0] == 0x01 && jaguarMainROM[1] == 0x50)
269                 {
270                         uint32 loadAddress = GET32(jaguarMainROM, 0x28), runAddress = GET32(jaguarMainROM, 0x24),
271                                 codeSize = GET32(jaguarMainROM, 0x18) + GET32(jaguarMainROM, 0x1C);
272                         WriteLog("GUI: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress, codeSize);
273
274                         if (loadAddress < 0x800000)
275                                 memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0xA8, codeSize);
276                         else
277                         {
278                                 for(int i=codeSize-1; i>=0; i--)
279                                         jaguarMainROM[(loadAddress - 0x800000) + i] = jaguarMainROM[i + 0xA8];
280 /*                              memcpy(jaguar_mainRam, jaguar_mainRom + 0xA8, codeSize);
281                                 memset(jaguar_mainRom, 0xFF, 0x600000);
282                                 memcpy(jaguar_mainRom + (loadAddress - 0x800000), jaguar_mainRam, codeSize);
283                                 memset(jaguar_mainRam, 0x00, 0x400000);*/
284                         }
285
286                         jaguarRunAddress = runAddress;
287                 }
288                 else
289                 {
290                         WriteLog("GUI: Couldn't find correct ABS format: %02X %02X\n", jaguarMainROM[0], jaguarMainROM[1]);
291                         return false;
292                 }
293         }
294         else if (strcasecmp(ext, ".jag") == 0)
295         {
296                 // File extension ".JAG": Atari server file with header
297 //NOTE: The bytes 'JAGR' should also be at position $1C...
298 //      Also, there's *always* a $601A header at position $00...
299                 if (jaguarMainROM[0] == 0x60 && jaguarMainROM[1] == 0x1A)
300                 {
301                         uint32 loadAddress = GET32(jaguarMainROM, 0x22), runAddress = GET32(jaguarMainROM, 0x2A);
302 //This is not always right! Especially when converted via bin2jag1!!!
303 //We should have access to the length of the furshlumiger file that was loaded anyway!
304 //Now, we do! ;-)
305 //                      uint32 progLength = GET32(jaguar_mainRom, 0x02);
306 //jaguarRomSize
307 //jaguarRunAddress
308 //                      WriteLog("Jaguar: Setting up PD ROM... Run address: %08X, length: %08X\n", runAddress, progLength);
309 //                      memcpy(jaguar_mainRam + loadAddress, jaguar_mainRom + 0x2E, progLength);
310                         WriteLog("GUI: Setting up homebrew (JAG)... Run address: %08X, length: %08X\n", runAddress, jaguarROMSize - 0x2E);
311                         memcpy(jaguarMainRAM + loadAddress, jaguarMainROM + 0x2E, jaguarROMSize - 0x2E);
312 //              SET32(jaguar_mainRam, 4, runAddress);
313                         jaguarRunAddress = runAddress;
314                 }
315                 else
316                         return false;
317         }
318         // .J64 (Jaguar cartridge ROM image) is implied by the FileList object...
319
320         return true;
321 }
322
323 //
324 // Get the length of a (possibly) gzipped file
325 //
326 static int gzfilelength(gzFile gd)
327 {
328    int size = 0, length = 0;
329    unsigned char buffer[0x10000];
330
331    gzrewind(gd);
332
333    do
334    {
335       // Read in chunks until EOF
336       size = gzread(gd, buffer, 0x10000);
337
338       if (size <= 0)
339         break;
340
341       length += size;
342    }
343    while (!gzeof(gd));
344
345    gzrewind(gd);
346    return length;
347 }