Branch data Line data Source code
1 : : #include "std-includes.h"
2 : : #include "libsmw.h"
3 : : #include "autoarray.h"
4 : : #include "errors.h"
5 : : #include "asar.h"
6 : : #include "crc32.h"
7 : : #include <cstdint>
8 : :
9 : : mapper_t mapper=lorom;
10 : : int sa1banks[8]={0<<20, 1<<20, -1, -1, 2<<20, 3<<20, -1, -1};
11 : : const unsigned char * romdata= nullptr; // NOTE: Changed into const to prevent direct write access - use writeromdata() functions below
12 : : int romlen;
13 : : static bool header;
14 : : static FILE * thisfile;
15 : :
16 : : asar_error_id openromerror;
17 : :
18 : : autoarray<writtenblockdata> writtenblocks;
19 : :
20 : : // RPG Hacker: Uses binary search to find the insert position of our ROM write
21 : : #ifdef ASAR_SHARED
22 : : static int findromwritepos(int snesoffset, int searchstartpos, int searchendpos)
23 : : {
24 : : if (searchendpos == searchstartpos)
25 : : {
26 : : return searchstartpos;
27 : : }
28 : :
29 : : int centerpos = searchstartpos + ((searchendpos - searchstartpos) / 2);
30 : :
31 : : if (writtenblocks[centerpos].snesoffset >= snesoffset)
32 : : {
33 : : return findromwritepos(snesoffset, searchstartpos, centerpos);
34 : : }
35 : :
36 : : return findromwritepos(snesoffset, centerpos + 1, searchendpos);
37 : : }
38 : :
39 : :
40 : : static void addromwriteforbank(int snesoffset, int numbytes)
41 : : {
42 : : int currentbank = (snesoffset & 0xFF0000);
43 : :
44 : : int insertpos = findromwritepos(snesoffset, 0, writtenblocks.count);
45 : :
46 : : if (insertpos > 0 && (writtenblocks[insertpos - 1].snesoffset & 0xFF0000) == currentbank
47 : : && writtenblocks[insertpos - 1].snesoffset + writtenblocks[insertpos - 1].numbytes >= snesoffset)
48 : : {
49 : : // Merge if we overlap with a preceding block
50 : : int firstend = writtenblocks[insertpos - 1].snesoffset + writtenblocks[insertpos - 1].numbytes;
51 : : int secondend = snesoffset + numbytes;
52 : :
53 : : int newend = (firstend > secondend ? firstend : secondend);
54 : :
55 : : numbytes = newend - writtenblocks[insertpos - 1].snesoffset;
56 : : snesoffset = writtenblocks[insertpos - 1].snesoffset;
57 : :
58 : : writtenblocks.remove(insertpos - 1);
59 : : insertpos -= 1;
60 : : }
61 : :
62 : : while (insertpos < writtenblocks.count && (writtenblocks[insertpos].snesoffset & 0xFF0000) == currentbank
63 : : && snesoffset + numbytes >= writtenblocks[insertpos].snesoffset)
64 : : {
65 : : // Merge if we overlap with a succeeding block
66 : : int firstend = snesoffset + numbytes;
67 : : int secondend = writtenblocks[insertpos].snesoffset + writtenblocks[insertpos].numbytes;
68 : :
69 : : int newend = (firstend > secondend ? firstend : secondend);
70 : :
71 : : numbytes = newend - snesoffset;
72 : :
73 : : writtenblocks.remove(insertpos);
74 : : }
75 : :
76 : : // Insert ROM write
77 : : writtenblockdata blockdata;
78 : : blockdata.snesoffset = snesoffset;
79 : : blockdata.pcoffset = snestopc(snesoffset);
80 : : blockdata.numbytes = numbytes;
81 : :
82 : : writtenblocks.insert(insertpos, blockdata);
83 : : }
84 : :
85 : :
86 : : static void addromwrite(int pcoffset, int numbytes)
87 : : {
88 : : int snesaddr = pctosnes(pcoffset);
89 : : int bytesleft = numbytes;
90 : :
91 : : // RPG Hacker: Some kind of witchcraft which I actually hope works as intended
92 : : // Basically, the purpose of this is to sort all ROM writes into banks for the sake of cleanness
93 : :
94 : : while (((snesaddr >> 16) & 0xFF) != (((snesaddr + bytesleft) >> 16) & 0xFF))
95 : : {
96 : : int bytesinbank = ((snesaddr + 0x10000) & 0xFF0000) - snesaddr;
97 : :
98 : : addromwriteforbank(snesaddr, bytesinbank);
99 : :
100 : : pcoffset += bytesinbank;
101 : : snesaddr = pctosnes(pcoffset);
102 : : bytesleft -= bytesinbank;
103 : : }
104 : :
105 : : addromwriteforbank(snesaddr, bytesleft);
106 : : }
107 : : #endif
108 : :
109 : 89 : void writeromdata(int pcoffset, const void * indata, int numbytes)
110 : : {
111 : 89 : memcpy(const_cast<unsigned char*>(romdata) + pcoffset, indata, (size_t)numbytes);
112 : : #ifdef ASAR_SHARED
113 : : addromwrite(pcoffset, numbytes);
114 : : #endif
115 : 89 : }
116 : :
117 : 39540 : void writeromdata_byte(int pcoffset, unsigned char indata)
118 : : {
119 : 40036 : memcpy(const_cast<unsigned char*>(romdata) + pcoffset, &indata, 1);
120 : : #ifdef ASAR_SHARED
121 : : addromwrite(pcoffset, 1);
122 : : #endif
123 : 39697 : }
124 : :
125 : 1 : void writeromdata_bytes(int pcoffset, unsigned char indata, int numbytes)
126 : : {
127 : 1 : memset(const_cast<unsigned char*>(romdata) + pcoffset, indata, (size_t)numbytes);
128 : : #ifdef ASAR_SHARED
129 : : addromwrite(pcoffset, numbytes);
130 : : #endif
131 : 1 : }
132 : :
133 : 171 : int ratsstart(int snesaddr)
134 : : {
135 : 171 : int pcaddr=snestopc(snesaddr);
136 [ + - ]: 171 : if (pcaddr<0x7FFF8) return -1;
137 : 171 : const unsigned char * start=romdata+pcaddr-0x10000;
138 [ + - ]: 1774 : for (int i=0x10000;i>=0;i--)
139 : : {
140 [ + + ]: 1774 : if (!strncmp((const char*)start+i, "STAR", 4) &&
141 [ + - + - ]: 171 : (start[i+4]^start[i+6])==0xFF && (start[i+5]^start[i+7])==0xFF)
142 : : {
143 [ + - ]: 171 : if ((start[i+4]|(start[i+5]<<8))>0x10000-i-8-1) return pctosnes((int)(start-romdata+i));
144 : : return -1;
145 : : }
146 : : }
147 : : return -1;
148 : : }
149 : :
150 : 146 : void resizerats(int snesaddr, int newlen)
151 : : {
152 : 146 : int pos=snestopc(ratsstart(snesaddr));
153 [ + - ]: 146 : if (pos<0) return;
154 [ + - ]: 146 : if (newlen!=0) newlen--;
155 : 146 : writeromdata_byte(pos+4, (unsigned char)(newlen&0xFF));
156 : 146 : writeromdata_byte(pos+5, (unsigned char)((newlen>>8)&0xFF));
157 : 146 : writeromdata_byte(pos+6, (unsigned char)((newlen&0xFF)^0xFF));
158 : 146 : writeromdata_byte(pos+7, (unsigned char)(((newlen>>8)&0xFF)^0xFF));
159 : : }
160 : :
161 : 3 : static void handleprot(int loc, char * name, int len, const unsigned char * contents)
162 : : {
163 : : (void)loc; // RPG Hacker: Silence "unused argument" warning.
164 : :
165 [ + - ]: 3 : if (!strncmp(name, "PROT", 4))
166 : : {
167 : 3 : memcpy(name, "NULL", 4);//to block recursion, in case someone is an idiot
168 [ + - ]: 3 : if (len%3) return;
169 : 3 : len/=3;
170 [ + + ]: 7 : for (int i=0;i<len;i++) removerats((contents[(i*3)+0] )|(contents[(i*3)+1]<<8 )|(contents[(i*3)+2]<<16), 0x00);
171 : : }
172 : : }
173 : :
174 : 7 : void removerats(int snesaddr, unsigned char clean_byte)
175 : : {
176 : 7 : int addr=ratsstart(snesaddr);
177 [ + - ]: 7 : if (addr<0) return;
178 : : // randomdude999: don't forget bank borders
179 : 7 : WalkMetadata(pctosnes(snestopc(addr)+8), handleprot);
180 : 7 : addr=snestopc(addr);
181 [ + + ]: 110 : for (int i=(romdata[addr+4]|(romdata[addr+5]<<8))+8;i>=0;i--) writeromdata_byte(addr+i, clean_byte);
182 : : }
183 : :
184 : 158 : static inline int trypcfreespace(int start, int end, int size, int banksize, int minalign, unsigned char freespacebyte)
185 : : {
186 [ + + ]: 7317 : while (start+size<=end)
187 : : {
188 : 7306 : if (
189 [ + + ]: 7306 : ((start+8)&~banksize)!=((start+size-1)&~banksize&0xFFFFFF)//if the contents won't fit in this bank...
190 : 2 : &&
191 [ + - ]: 1 : (start&banksize&0xFFFFF8)!=(banksize&0xFFFFF8)//and the RATS tag can't fit in the bank either...
192 : : )
193 : : {
194 : 1 : start&=~banksize&0xFFFFFF;//round it down to the start of the bank,
195 : 1 : start|=banksize&0xFFFFF8;//then round it up to the end minus the RATS tag...
196 : 1 : continue;
197 : : }
198 [ + + ]: 7305 : if (minalign)
199 : : {
200 : 2 : start&=~minalign&0xFFFFFF;
201 : 2 : start|=minalign&0xFFFFF8;
202 : : }
203 [ + + ]: 7305 : if (!strncmp((const char*)romdata+start, "STAR", 4) &&
204 [ - + - + ]: 7158 : (romdata[start+4]^romdata[start+6])==0xFF && (romdata[start+5]^romdata[start+7])==0xFF)
205 : : {
206 : 7158 : start+=(romdata[start+4]|(romdata[start+5]<<8))+1+8;
207 : 7158 : continue;
208 : : }
209 : : bool bad=false;
210 [ + + ]: 102152 : for (int i=0;i<size;i++)
211 : : {
212 [ - + ]: 102005 : if (romdata[start+i]!=freespacebyte)
213 : : {
214 : : // TheBiob: fix freedata align freezing.
215 [ # # # # ]: 0 : if ((start & minalign) == 0x7FF8 && i < 8) i = 8;
216 : 0 : start+=i;
217 [ # # ]: 0 : if (!i) start++;//this could check for a rats tag instead, but somehow I think this will give better performance.
218 : : bad=true;
219 : : break;
220 : : }
221 : : }
222 : 0 : if (bad) continue;
223 : 147 : size-=8;
224 [ + - ]: 147 : if (size) size--;//rats tags eat one byte more than specified for some reason
225 : : writeromdata_byte(start+0, 'S');
226 : 147 : writeromdata_byte(start+1, 'T');
227 : 147 : writeromdata_byte(start+2, 'A');
228 : 147 : writeromdata_byte(start+3, 'R');
229 : 147 : writeromdata_byte(start+4, (unsigned char)(size&0xFF));
230 : 147 : writeromdata_byte(start+5, (unsigned char)((size>>8)&0xFF));
231 : 147 : writeromdata_byte(start+6, (unsigned char)((size&0xFF)^0xFF));
232 : 147 : writeromdata_byte(start+7, (unsigned char)(((size>>8)&0xFF)^0xFF));
233 : 147 : return start+8;
234 : : }
235 : : return -1;
236 : : }
237 : :
238 : : //This function finds a block of freespace. -1 means "no freespace found", anything else is a PC address.
239 : : //isforcode=false tells it to favor banks 40+, true tells it to avoid them entirely.
240 : : //It automatically adds a RATS tag.
241 : :
242 : 147 : int getpcfreespace(int size, bool isforcode, bool autoexpand, bool respectbankborders, bool align, unsigned char freespacebyte)
243 : : {
244 [ + - ]: 147 : if (!size) return 0x1234;//in case someone protects zero bytes for some dumb reason.
245 : : //You can write zero bytes to anywhere, so I'll just return something that removerats will ignore.
246 [ - + ]: 147 : if (size>0x10000) return -1;
247 : 147 : size+=8;
248 [ + + ]: 147 : if (mapper==lorom)
249 : : {
250 [ - + ]: 145 : if (size>0x8008 && respectbankborders) return -1;
251 : 145 : rebootlorom:
252 [ - + - - ]: 156 : if (romlen>0x200000 && !isforcode)
253 : : {
254 [ # # # # ]: 0 : int pos=trypcfreespace(0x200000-8, (romlen<0x400000)?romlen:0x400000, size,
255 [ # # ]: 0 : respectbankborders?0x7FFF:0xFFFFFF, align?0x7FFF:(respectbankborders || size<32768)?0:0x7FFF, freespacebyte);
256 [ # # ]: 0 : if (pos>=0) return pos;
257 : : }
258 [ + + - + ]: 310 : int pos=trypcfreespace(0x80000, (romlen<0x200000)?romlen:0x200000, size,
259 [ + + ]: 154 : respectbankborders?0x7FFF:0xFFFFFF, align?0x7FFF:(respectbankborders || size<32768)?0:0x7FFF, freespacebyte);
260 [ + + ]: 156 : if (pos>=0) return pos;
261 [ + - ]: 11 : if (autoexpand)
262 : : {
263 : : if(0);
264 [ + - ]: 11 : else if (romlen==0x080000)
265 : : {
266 : 11 : romlen=0x100000;
267 : 11 : writeromdata_byte(snestopc(0x00FFD7), 0x0A);
268 : : }
269 [ # # ]: 0 : else if (romlen==0x100000)
270 : : {
271 : 0 : romlen=0x200000;
272 : 0 : writeromdata_byte(snestopc(0x00FFD7), 0x0B);
273 : : }
274 [ # # ]: 0 : else if (isforcode) return -1;//no point creating freespace that can't be used
275 [ # # # # ]: 0 : else if (romlen==0x200000 || romlen==0x300000)
276 : : {
277 : 0 : romlen=0x400000;
278 : 0 : writeromdata_byte(snestopc(0x00FFD7), 0x0C);
279 : : }
280 : : else return -1;
281 : : autoexpand=false;
282 : 11 : goto rebootlorom;
283 : : }
284 : : }
285 [ - + ]: 2 : if (mapper==hirom)
286 : : {
287 [ # # ]: 0 : if (isforcode)
288 : : {
289 [ # # ]: 0 : for(int i = 0x8000; i < min(romlen, 0x400000); i += 0xFFFF){
290 [ # # ]: 0 : int space = trypcfreespace(i, min(i+0x7FFF, romlen), size, 0x7FFF, align?0xFFFF:0, freespacebyte);
291 [ # # ]: 0 : if(space != -1) return space;
292 : : }
293 : : return -1;
294 : : }
295 [ # # ]: 0 : return trypcfreespace(0, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte);
296 : : }
297 [ - + ]: 2 : if (mapper==exlorom)
298 : : {
299 : : // RPG Hacker: Not really 100% sure what to do here, but I suppose this simplified code will do
300 : : // and we won't need all the complicated stuff from LoROM above?
301 [ # # ]: 0 : if (isforcode)
302 : : {
303 [ # # ]: 0 : trypcfreespace(0, min(romlen, 0x200000), size, 0x7FFF, align?0x7FFF:0, freespacebyte);
304 : : }
305 [ # # ]: 0 : return trypcfreespace(0, romlen, size, 0x7FFF, align ? 0x7FFF : 0, freespacebyte);
306 : : }
307 [ - + ]: 2 : if (mapper==exhirom)
308 : : {
309 [ # # ]: 0 : if (isforcode)
310 : : {
311 [ # # # # ]: 0 : for(int i = 0x8000; i < romlen && i < 0x400000; i += 0xFFFF){
312 [ # # ]: 0 : int space = trypcfreespace(i, min(i+0x7FFF, romlen), size, 0x7FFF, align?0xFFFF:0, freespacebyte);
313 [ # # ]: 0 : if(space != -1) return space;
314 : : }
315 : : return -1;
316 : : }
317 [ # # ]: 0 : return trypcfreespace(0, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte);
318 : : }
319 [ + + ]: 2 : if (mapper==sfxrom)
320 : : {
321 [ - + ]: 1 : if (!isforcode) return -1;
322 : : // try not to overwrite smw stuff
323 [ + - ]: 2 : return trypcfreespace(0x80000, romlen, size, 0x7FFF, align?0x7FFF:0, freespacebyte);
324 : : }
325 [ + - ]: 1 : if (mapper==sa1rom)
326 : : {
327 : 1 : rebootsa1rom:
328 : : int nextbank=-1;
329 [ + + ]: 10 : for (int i=0;i<8;i++)
330 : : {
331 [ + + ]: 9 : if (i&2) continue;
332 [ + + ]: 5 : if (sa1banks[i]+0x100000>romlen)
333 : : {
334 [ + + ]: 4 : if (sa1banks[i]<=romlen && sa1banks[i]+0x100000>romlen) nextbank=sa1banks[i];
335 : 4 : continue;
336 : : }
337 [ + - - + ]: 2 : int pos=trypcfreespace(sa1banks[i]?sa1banks[i]:0x80000, sa1banks[i]+0x100000, size, 0x7FFF, align?0x7FFF:0, freespacebyte);
338 [ + - ]: 1 : if (pos>=0) return pos;
339 : : }
340 [ + - ]: 1 : if (autoexpand && nextbank>=0)
341 : : {
342 : 1 : unsigned char x7FD7[]={0, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D};
343 : 1 : romlen=nextbank+0x100000;
344 : 1 : writeromdata_byte(0x7FD7, x7FD7[romlen>>20]);
345 : : autoexpand=false;
346 : 1 : goto rebootsa1rom;
347 : : }
348 : : }
349 [ # # ]: 0 : if (mapper==bigsa1rom)
350 : : {
351 [ # # # # ]: 0 : if(!isforcode && romlen > 0x400000)
352 : : {
353 [ # # ]: 0 : int pos=trypcfreespace(0x400000, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte);
354 [ # # ]: 0 : if(pos>=0) return pos;
355 : : }
356 [ # # ]: 0 : int pos=trypcfreespace(0x080000, romlen, size, 0x7FFF, align?0x7FFF:0, freespacebyte);
357 [ # # ]: 0 : if(pos>=0) return pos;
358 : : }
359 : : return -1;
360 : : }
361 : :
362 : 0 : void WalkRatsTags(void(*func)(int loc, int len))
363 : : {
364 : 0 : int pos=snestopc(0x108000);
365 [ # # ]: 0 : while (pos<romlen)
366 : : {
367 [ # # ]: 0 : if (!strncmp((const char*)romdata+pos, "STAR", 4) &&
368 [ # # # # ]: 0 : (romdata[pos+4]^romdata[pos+6])==0xFF && (romdata[pos+5]^romdata[pos+7])==0xFF)
369 : : {
370 : 0 : func(pctosnes(pos+8), (romdata[pos+4]|(romdata[pos+5]<<8))+1);
371 : 0 : pos+=(romdata[pos+4]|(romdata[pos+5]<<8))+1+8;
372 : : }
373 : 0 : else pos++;
374 : : }
375 : 0 : }
376 : :
377 : 7 : void WalkMetadata(int loc, void(*func)(int loc, char * name, int len, const unsigned char * contents))
378 : : {
379 : 7 : int pcoff=snestopc(loc);
380 [ + - ]: 7 : if (strncmp((const char*)romdata+pcoff-8, "STAR", 4)) return;
381 : 7 : const unsigned char * metadata=romdata+pcoff;
382 [ + + + - : 10 : while (is_upper(metadata[0]) && is_upper(metadata[1]) && is_upper(metadata[2]) && is_upper(metadata[3]))
+ - + - ]
383 : : {
384 [ + + ]: 5 : if (!strncmp((const char*)metadata, "STOP", 4))
385 : : {
386 : : metadata=romdata+pcoff;
387 [ + - + - : 5 : while (is_upper(metadata[0]) && is_upper(metadata[1]) && is_upper(metadata[2]) && is_upper(metadata[3]))
+ - + - ]
388 : : {
389 [ + + ]: 5 : if (!strncmp((const char*)metadata, "STOP", 4))
390 : : {
391 : : break;
392 : : }
393 : 3 : func(pctosnes((int)(metadata-romdata)), (char*)const_cast<unsigned char*>(metadata), metadata[4], metadata+5);
394 : 3 : metadata+=5+metadata[4];
395 : : }
396 : : break;
397 : : }
398 : 3 : metadata+=5+metadata[4];
399 : : }
400 : : }
401 : :
402 : 146 : int getsnesfreespace(int size, bool isforcode, bool autoexpand, bool respectbankborders, bool align, unsigned char freespacebyte)
403 : : {
404 : 146 : return pctosnes(getpcfreespace(size, isforcode, autoexpand, respectbankborders, align, freespacebyte));
405 : : }
406 : :
407 : 95 : bool openrom(const char * filename, bool confirm)
408 : : {
409 : 95 : closerom();
410 : 95 : thisfile=fopen(filename, "r+b");
411 [ - + ]: 95 : if (!thisfile)
412 : : {
413 : 0 : openromerror = error_id_open_rom_failed;
414 : 0 : return false;
415 : : }
416 : 95 : fseek(thisfile, 0, SEEK_END);
417 : 95 : header=false;
418 [ + - ]: 95 : if (strlen(filename)>4)
419 : : {
420 : 95 : const char * fnameend=strchr(filename, '\0')-4;
421 : 95 : header=(!stricmp(fnameend, ".smc"));
422 : : }
423 : 95 : romlen=ftell(thisfile)-(header*512);
424 [ - + ]: 95 : if (romlen<0) romlen=0;
425 : 95 : fseek(thisfile, header*512, SEEK_SET);
426 : 95 : romdata=(unsigned char*)malloc(sizeof(unsigned char)*16*1024*1024);
427 : 95 : int truelen=(int)fread(const_cast<unsigned char*>(romdata), 1u, (size_t)romlen, thisfile);
428 [ - + ]: 95 : if (truelen!=romlen)
429 : : {
430 : 0 : openromerror = error_id_open_rom_failed;
431 : 0 : free(const_cast<unsigned char*>(romdata));
432 : 0 : return false;
433 : : }
434 : 95 : memset(const_cast<unsigned char*>(romdata)+romlen, 0x00, (size_t)(16*1024*1024-romlen));
435 [ - + - - : 95 : if (confirm && snestopc(0x00FFC0)+21<(int)romlen && strncmp((const char*)romdata+snestopc(0x00FFC0), "SUPER MARIOWORLD ", 21))
- - ]
436 : : {
437 : 0 : closerom(false);
438 [ # # ]: 0 : openromerror = header ? error_id_open_rom_not_smw_extension : error_id_open_rom_not_smw_header;
439 : 0 : return false;
440 : : }
441 : :
442 : 95 : romdata_r=(unsigned char*)malloc((size_t)romlen);
443 : 95 : romlen_r=romlen;
444 : 95 : memcpy((void*)romdata_r, romdata, (size_t)romlen);//recently allocated, dead
445 : :
446 : 95 : return true;
447 : : }
448 : :
449 : 190 : uint32_t closerom(bool save)
450 : : {
451 : : uint32_t romCrc = 0;
452 [ + + + + : 190 : if (thisfile && save && romlen)
+ + ]
453 : : {
454 : 71 : fseek(thisfile, header*512, SEEK_SET);
455 : 71 : fwrite(const_cast<unsigned char*>(romdata), 1, (size_t)romlen, thisfile);
456 : :
457 : : // do a quick re-read of the header, and include that in the crc32 calculation if necessary
458 : : {
459 : 71 : uint8_t* filedata = (uint8_t*)malloc(sizeof(uint8_t) * (romlen + header * 512));
460 [ - + ]: 71 : if (header)
461 : : {
462 : 0 : fseek(thisfile, 0, SEEK_SET);
463 : 0 : fread(filedata, sizeof(uint8_t), 512, thisfile);
464 : : }
465 : 71 : memcpy(filedata + (header * 512), romdata, sizeof(uint8_t) * (size_t)romlen);
466 : 71 : romCrc = crc32(filedata, (unsigned int)(romlen + header * 512));
467 : 71 : free(filedata);
468 : : }
469 : : }
470 [ + + ]: 190 : if (thisfile) fclose(thisfile);
471 [ + + ]: 190 : if (romdata) free(const_cast<unsigned char*>(romdata));
472 [ + + ]: 190 : if (romdata_r) free(const_cast<unsigned char*>(romdata_r));
473 : 190 : thisfile= nullptr;
474 : 190 : romdata= nullptr;
475 : 190 : romdata_r = nullptr;
476 : 190 : romlen=0;
477 : 190 : return romCrc;
478 : : }
479 : :
480 : 88 : static unsigned int getchecksum()
481 : : {
482 : : unsigned int checksum=0;
483 [ + + ]: 88 : if((romlen & (romlen-1)) == 0)
484 : : {
485 : : // romlen is a power of 2, just add up all the bytes
486 [ + + ]: 23593027 : for (int i=0;i<romlen;i++) checksum+=romdata[i];
487 : : }
488 : : else
489 : : {
490 : : // assume romlen is the sum of 2 powers of 2 - i haven't seen any real rom that isn't,
491 : : // and if you make such a rom, fixing its checksum is your problem.
492 : 37 : int firstpart = bitround(romlen) >> 1;
493 : 37 : int secondpart = romlen - firstpart;
494 : 37 : int repeatcount = firstpart / secondpart;
495 : : unsigned int secondpart_sum = 0;
496 [ + + ]: 8424681 : for(int i = 0; i < firstpart; i++) checksum += romdata[i];
497 [ + + ]: 7340604 : for(int i = firstpart; i < romlen; i++) secondpart_sum += romdata[i];
498 : 37 : checksum += secondpart_sum * repeatcount;
499 : : }
500 : 88 : return checksum&0xFFFF;
501 : : }
502 : :
503 : 0 : bool goodchecksum()
504 : : {
505 : 0 : int checksum=(int)getchecksum();
506 [ # # ]: 0 : return ((romdata[snestopc(0x00FFDE)]^romdata[snestopc(0x00FFDC)])==0xFF) && ((romdata[snestopc(0x00FFDF)]^romdata[snestopc(0x00FFDD)])==0xFF) &&
507 [ # # # # : 0 : ((romdata[snestopc(0x00FFDE)]&0xFF)==(checksum&0xFF)) && ((romdata[snestopc(0x00FFDF)]&0xFF)==((checksum>>8)&0xFF));
# # ]
508 : : }
509 : :
510 : 88 : void fixchecksum()
511 : : {
512 : : // randomdude999: clear out checksum bytes before recalculating checksum, this should make it correct on roms that don't have a checksum yet
513 : 88 : writeromdata(snestopc(0x00FFDC), "\xFF\xFF\0\0", 4);
514 : 88 : int checksum=(int)getchecksum();
515 : 88 : writeromdata_byte(snestopc(0x00FFDE), (unsigned char)(checksum&255));
516 : 88 : writeromdata_byte(snestopc(0x00FFDF), (unsigned char)((checksum>>8)&255));
517 : 88 : writeromdata_byte(snestopc(0x00FFDC), (unsigned char)((checksum&255)^255));
518 : 88 : writeromdata_byte(snestopc(0x00FFDD), (unsigned char)(((checksum>>8)&255)^255));
519 : 88 : }
|