asar coverage - build #291


src/asar/
File: src/asar/libsmw.cpp
Date: 2025-03-10 01:11:53
Lines:
186/250
74.4%
Functions:
15/17
88.2%
Branches:
118/258
45.7%

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