asar coverage - build #139


src/asar/
File: src/asar/libsmw.cpp
Date: 2024-01-23 10:16:20
Lines:
183/246
74.4%
Functions:
15/17
88.2%
Branches:
127/258
49.2%

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
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 178 void writeromdata(int pcoffset, const void * indata, int numbytes)
110 {
111 178 memcpy(const_cast<unsigned char*>(romdata) + pcoffset, indata, (size_t)numbytes);
112 #ifdef ASAR_SHARED
113 addromwrite(pcoffset, numbytes);
114 #endif
115 178 }
116
117 81492 void writeromdata_byte(int pcoffset, unsigned char indata)
118 {
119 81993 memcpy(const_cast<unsigned char*>(romdata) + pcoffset, &indata, 1);
120 #ifdef ASAR_SHARED
121 addromwrite(pcoffset, 1);
122 #endif
123 81652 }
124
125 2 void writeromdata_bytes(int pcoffset, unsigned char indata, int numbytes)
126 {
127 2 memset(const_cast<unsigned char*>(romdata) + pcoffset, indata, (size_t)numbytes);
128 #ifdef ASAR_SHARED
129 addromwrite(pcoffset, numbytes);
130 #endif
131 2 }
132
133 346 int ratsstart(int snesaddr)
134 {
135 346 int pcaddr=snestopc(snesaddr);
136
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 173 times.
346 if (pcaddr<0x7FFF8) return -1;
137 346 const unsigned char * start=romdata+pcaddr-0x10000;
138
1/2
✓ Branch 0 taken 3584 times.
✗ Branch 1 not taken.
3584 for (int i=0x10000;i>=0;i--)
139 {
140
2/2
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 3238 times.
3584 if (!strncmp((const char*)start+i, "STAR", 4) &&
141
2/4
✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 346 times.
✗ Branch 3 not taken.
346 (start[i+4]^start[i+6])==0xFF && (start[i+5]^start[i+7])==0xFF)
142 {
143
1/2
✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
346 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 296 void resizerats(int snesaddr, int newlen)
151 {
152 296 int pos=snestopc(ratsstart(snesaddr));
153
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 148 times.
296 if (pos<0) return;
154
1/2
✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
296 if (newlen!=0) newlen--;
155 296 writeromdata_byte(pos+4, (unsigned char)(newlen&0xFF));
156 296 writeromdata_byte(pos+5, (unsigned char)((newlen>>8)&0xFF));
157 296 writeromdata_byte(pos+6, (unsigned char)((newlen&0xFF)^0xFF));
158 296 writeromdata_byte(pos+7, (unsigned char)(((newlen>>8)&0xFF)^0xFF));
159 }
160
161 6 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
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!strncmp(name, "PROT", 4))
166 {
167 6 memcpy(name, "NULL", 4);//to block recursion, in case someone is an idiot
168
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (len%3) return;
169 6 len/=3;
170
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);
171 }
172 }
173
174 14 void removerats(int snesaddr, unsigned char clean_byte)
175 {
176 14 int addr=ratsstart(snesaddr);
177
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (addr<0) return;
178 // randomdude999: don't forget bank borders
179 14 WalkMetadata(pctosnes(snestopc(addr)+8), handleprot);
180 14 addr=snestopc(addr);
181
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 14 times.
220 for (int i=(romdata[addr+4]|(romdata[addr+5]<<8))+8;i>=0;i--) writeromdata_byte(addr+i, clean_byte);
182 }
183
184 322 static inline int trypcfreespace(int start, int end, int size, int banksize, int minalign, unsigned char freespacebyte)
185 {
186
2/2
✓ Branch 0 taken 14618 times.
✓ Branch 1 taken 24 times.
14642 while (start+size<=end)
187 {
188 14618 if (
189
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14616 times.
14618 ((start+8)&~banksize)!=((start+size-1)&~banksize&0xFFFFFF)//if the contents won't fit in this bank...
190 4 &&
191
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...
192 )
193 {
194 2 start&=~banksize&0xFFFFFF;//round it down to the start of the bank,
195 2 start|=banksize&0xFFFFF8;//then round it up to the end minus the RATS tag...
196 2 continue;
197 }
198
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14612 times.
14616 if (minalign)
199 {
200 4 start&=~minalign&0xFFFFFF;
201 4 start|=minalign&0xFFFFF8;
202 }
203
2/2
✓ Branch 0 taken 7308 times.
✓ Branch 1 taken 7308 times.
14616 if (!strncmp((const char*)romdata+start, "STAR", 4) &&
204
4/4
✓ Branch 0 taken 7159 times.
✓ Branch 1 taken 7159 times.
✓ Branch 2 taken 7159 times.
✓ Branch 3 taken 7159 times.
14318 (romdata[start+4]^romdata[start+6])==0xFF && (romdata[start+5]^romdata[start+7])==0xFF)
205 {
206 14318 start+=(romdata[start+4]|(romdata[start+5]<<8))+1+8;
207 14318 continue;
208 }
209 149 bool bad=false;
210
2/2
✓ Branch 0 taken 204166 times.
✓ Branch 1 taken 298 times.
204464 for (int i=0;i<size;i++)
211 {
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204166 times.
204166 if (romdata[start+i]!=freespacebyte)
213 {
214 // TheBiob: fix freedata align freezing.
215 if ((start & minalign) == 0x7FF8 && i < 8) i = 8;
216 start+=i;
217 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
149 if (bad) continue;
223 298 size-=8;
224
1/2
✓ Branch 0 taken 298 times.
✗ Branch 1 not taken.
298 if (size) size--;//rats tags eat one byte more than specified for some reason
225 149 writeromdata_byte(start+0, 'S');
226 298 writeromdata_byte(start+1, 'T');
227 298 writeromdata_byte(start+2, 'A');
228 298 writeromdata_byte(start+3, 'R');
229 298 writeromdata_byte(start+4, (unsigned char)(size&0xFF));
230 298 writeromdata_byte(start+5, (unsigned char)((size>>8)&0xFF));
231 298 writeromdata_byte(start+6, (unsigned char)((size&0xFF)^0xFF));
232 298 writeromdata_byte(start+7, (unsigned char)(((size>>8)&0xFF)^0xFF));
233 298 return start+8;
234 }
235 12 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 298 int getpcfreespace(int size, bool isforcode, bool autoexpand, bool respectbankborders, bool align, unsigned char freespacebyte)
243 {
244
2/2
✓ Branch 0 taken 149 times.
✓ Branch 1 taken 149 times.
298 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 298 times.
298 if (size>0x10000) return -1;
247 298 size+=8;
248
2/2
✓ Branch 0 taken 294 times.
✓ Branch 1 taken 4 times.
298 if (mapper==lorom)
249 {
250
3/4
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 148 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
294 if (size>0x8008 && respectbankborders) return -1;
251 294 rebootlorom:
252
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 318 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
318 if (romlen>0x200000 && !isforcode)
253 {
254 int pos=trypcfreespace(0x200000-8, (romlen<0x400000)?romlen:0x400000, size,
255 respectbankborders?0x7FFF:0xFFFFFF, align?0x7FFF:(respectbankborders || size<32768)?0:0x7FFF, freespacebyte);
256 if (pos>=0) return pos;
257 }
258
4/4
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 159 times.
✓ Branch 2 taken 157 times.
✓ Branch 3 taken 159 times.
632 int pos=trypcfreespace(0x80000, (romlen<0x200000)?romlen:0x200000, size,
259
3/4
✓ Branch 0 taken 157 times.
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
314 respectbankborders?0x7FFF:0xFFFFFF, align?0x7FFF:(respectbankborders || size<32768)?0:0x7FFF, freespacebyte);
260
2/2
✓ Branch 0 taken 294 times.
✓ Branch 1 taken 24 times.
318 if (pos>=0) return pos;
261
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (autoexpand)
262 {
263 if(0);
264
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 else if (romlen==0x080000)
265 {
266 24 romlen=0x100000;
267 24 writeromdata_byte(snestopc(0x00FFD7), 0x0A);
268 }
269 else if (romlen==0x100000)
270 {
271 romlen=0x200000;
272 writeromdata_byte(snestopc(0x00FFD7), 0x0B);
273 }
274 else if (isforcode) return -1;//no point creating freespace that can't be used
275 else if (romlen==0x200000 || romlen==0x300000)
276 {
277 romlen=0x400000;
278 writeromdata_byte(snestopc(0x00FFD7), 0x0C);
279 }
280 else return -1;
281 12 autoexpand=false;
282 24 goto rebootlorom;
283 }
284 }
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mapper==hirom)
286 {
287 if (isforcode)
288 {
289 for(int i = 0x8000; i < min(romlen, 0x400000); i += 0xFFFF){
290 int space = trypcfreespace(i, min(i+0x7FFF, romlen), size, 0x7FFF, align?0xFFFF:0, freespacebyte);
291 if(space != -1) return space;
292 }
293 return -1;
294 }
295 return trypcfreespace(0, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte);
296 }
297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 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 if (isforcode)
302 {
303 trypcfreespace(0, min(romlen, 0x200000), size, 0x7FFF, align?0x7FFF:0, freespacebyte);
304 }
305 return trypcfreespace(0, romlen, size, 0x7FFF, align ? 0x7FFF : 0, freespacebyte);
306 }
307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mapper==exhirom)
308 {
309 if (isforcode)
310 {
311 for(int i = 0x8000; i < romlen && i < 0x400000; i += 0xFFFF){
312 int space = trypcfreespace(i, min(i+0x7FFF, romlen), size, 0x7FFF, align?0xFFFF:0, freespacebyte);
313 if(space != -1) return space;
314 }
315 return -1;
316 }
317 return trypcfreespace(0, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte);
318 }
319
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (mapper==sfxrom)
320 {
321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!isforcode) return -1;
322 // try not to overwrite smw stuff
323
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
3 return trypcfreespace(0x80000, romlen, size, 0x7FFF, align?0x7FFF:0, freespacebyte);
324 }
325
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (mapper==sa1rom)
326 {
327 2 rebootsa1rom:
328 2 int nextbank=-1;
329
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (int i=0;i<8;i++)
330 {
331
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (i&2) continue;
332
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if (sa1banks[i]+0x100000>romlen)
333 {
334
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
8 if (sa1banks[i]<=romlen && sa1banks[i]+0x100000>romlen) nextbank=sa1banks[i];
335 8 continue;
336 }
337
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
3 int pos=trypcfreespace(sa1banks[i]?sa1banks[i]:0x80000, sa1banks[i]+0x100000, size, 0x7FFF, align?0x7FFF:0, freespacebyte);
338
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (pos>=0) return pos;
339 }
340
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (autoexpand && nextbank>=0)
341 {
342 2 unsigned char x7FD7[]={0, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D};
343 2 romlen=nextbank+0x100000;
344 2 writeromdata_byte(0x7FD7, x7FD7[romlen>>20]);
345 1 autoexpand=false;
346 2 goto rebootsa1rom;
347 }
348 }
349 if (mapper==bigsa1rom)
350 {
351 if(!isforcode && romlen > 0x400000)
352 {
353 int pos=trypcfreespace(0x400000, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte);
354 if(pos>=0) return pos;
355 }
356 int pos=trypcfreespace(0x080000, romlen, size, 0x7FFF, align?0x7FFF:0, freespacebyte);
357 if(pos>=0) return pos;
358 }
359 return -1;
360 }
361
362 void WalkRatsTags(void(*func)(int loc, int len))
363 {
364 int pos=snestopc(0x108000);
365 while (pos<romlen)
366 {
367 if (!strncmp((const char*)romdata+pos, "STAR", 4) &&
368 (romdata[pos+4]^romdata[pos+6])==0xFF && (romdata[pos+5]^romdata[pos+7])==0xFF)
369 {
370 func(pctosnes(pos+8), (romdata[pos+4]|(romdata[pos+5]<<8))+1);
371 pos+=(romdata[pos+4]|(romdata[pos+5]<<8))+1+8;
372 }
373 else pos++;
374 }
375 }
376
377 14 void WalkMetadata(int loc, void(*func)(int loc, char * name, int len, const unsigned char * contents))
378 {
379 14 int pcoff=snestopc(loc);
380
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (strncmp((const char*)romdata+pcoff-8, "STAR", 4)) return;
381 14 const unsigned char * metadata=romdata+pcoff;
382
7/10
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 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 5 times.
✓ Branch 9 taken 5 times.
20 while (is_upper(metadata[0]) && is_upper(metadata[1]) && is_upper(metadata[2]) && is_upper(metadata[3]))
383 {
384
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 if (!strncmp((const char*)metadata, "STOP", 4))
385 {
386 2 metadata=romdata+pcoff;
387
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 5 times.
✗ Branch 9 not taken.
10 while (is_upper(metadata[0]) && is_upper(metadata[1]) && is_upper(metadata[2]) && is_upper(metadata[3]))
388 {
389
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (!strncmp((const char*)metadata, "STOP", 4))
390 {
391 2 break;
392 }
393 6 func(pctosnes((int)(metadata-romdata)), (char*)const_cast<unsigned char*>(metadata), metadata[4], metadata+5);
394 6 metadata+=5+metadata[4];
395 }
396 2 break;
397 }
398 6 metadata+=5+metadata[4];
399 }
400 }
401
402 296 int getsnesfreespace(int size, bool isforcode, bool autoexpand, bool respectbankborders, bool align, unsigned char freespacebyte)
403 {
404 296 return pctosnes(getpcfreespace(size, isforcode, autoexpand, respectbankborders, align, freespacebyte));
405 }
406
407 190 bool openrom(const char * filename, bool confirm)
408 {
409 190 closerom();
410 190 thisfile=fopen(filename, "r+b");
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (!thisfile)
412 {
413 openromerror = error_id_open_rom_failed;
414 return false;
415 }
416 190 fseek(thisfile, 0, SEEK_END);
417 190 header=false;
418
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
190 if (strlen(filename)>4)
419 {
420 190 const char * fnameend=strchr(filename, '\0')-4;
421 190 header=(!stricmp(fnameend, ".smc"));
422 }
423 190 romlen=ftell(thisfile)-(header*512);
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (romlen<0) romlen=0;
425 190 fseek(thisfile, header*512, SEEK_SET);
426 190 romdata=(unsigned char*)malloc(sizeof(unsigned char)*16*1024*1024);
427 190 int truelen=(int)fread(const_cast<unsigned char*>(romdata), 1u, (size_t)romlen, thisfile);
428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (truelen!=romlen)
429 {
430 openromerror = error_id_open_rom_failed;
431 free(const_cast<unsigned char*>(romdata));
432 return false;
433 }
434 190 memset(const_cast<unsigned char*>(romdata)+romlen, 0x00, (size_t)(16*1024*1024-romlen));
435
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 95 times.
190 if (confirm && snestopc(0x00FFC0)+21<(int)romlen && strncmp((const char*)romdata+snestopc(0x00FFC0), "SUPER MARIOWORLD ", 21))
436 {
437 closerom(false);
438 openromerror = header ? error_id_open_rom_not_smw_extension : error_id_open_rom_not_smw_header;
439 return false;
440 }
441
442 190 romdata_r=(unsigned char*)malloc((size_t)romlen);
443 190 romlen_r=romlen;
444 190 memcpy((void*)romdata_r, romdata, (size_t)romlen);//recently allocated, dead
445
446 190 return true;
447 }
448
449 380 uint32_t closerom(bool save)
450 {
451 190 uint32_t romCrc = 0;
452
6/6
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 146 times.
✓ Branch 3 taken 44 times.
✓ Branch 4 taken 142 times.
✓ Branch 5 taken 4 times.
380 if (thisfile && save && romlen)
453 {
454 142 fseek(thisfile, header*512, SEEK_SET);
455 142 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 142 uint8_t* filedata = (uint8_t*)malloc(sizeof(uint8_t) * (romlen + header * 512));
460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
142 if (header)
461 {
462 fseek(thisfile, 0, SEEK_SET);
463 fread(filedata, sizeof(uint8_t), 512, thisfile);
464 }
465 142 memcpy(filedata + (header * 512), romdata, sizeof(uint8_t) * (size_t)romlen);
466 142 romCrc = crc32(filedata, (unsigned int)(romlen + header * 512));
467 142 free(filedata);
468 }
469 }
470
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 190 times.
380 if (thisfile) fclose(thisfile);
471
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 190 times.
380 if (romdata) free(const_cast<unsigned char*>(romdata));
472
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 190 times.
380 if (romdata_r) free(const_cast<unsigned char*>(romdata_r));
473 380 thisfile= nullptr;
474 380 romdata= nullptr;
475 380 romdata_r = nullptr;
476 380 romlen=0;
477 380 return romCrc;
478 }
479
480 176 static unsigned int getchecksum()
481 {
482 88 unsigned int checksum=0;
483
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 72 times.
176 if((romlen & (romlen-1)) == 0)
484 {
485 // romlen is a power of 2, just add up all the bytes
486
2/2
✓ Branch 0 taken 49283104 times.
✓ Branch 1 taken 104 times.
49283208 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 72 int firstpart = bitround(romlen) >> 1;
493 72 int secondpart = romlen - firstpart;
494 72 int repeatcount = firstpart / secondpart;
495 36 unsigned int secondpart_sum = 0;
496
2/2
✓ Branch 0 taken 16849304 times.
✓ Branch 1 taken 72 times.
16849376 for(int i = 0; i < firstpart; i++) checksum += romdata[i];
497
2/2
✓ Branch 0 taken 14681082 times.
✓ Branch 1 taken 72 times.
14681154 for(int i = firstpart; i < romlen; i++) secondpart_sum += romdata[i];
498 72 checksum += secondpart_sum * repeatcount;
499 }
500 176 return checksum&0xFFFF;
501 }
502
503 bool goodchecksum()
504 {
505 int checksum=(int)getchecksum();
506 return ((romdata[snestopc(0x00FFDE)]^romdata[snestopc(0x00FFDC)])==0xFF) && ((romdata[snestopc(0x00FFDF)]^romdata[snestopc(0x00FFDD)])==0xFF) &&
507 ((romdata[snestopc(0x00FFDE)]&0xFF)==(checksum&0xFF)) && ((romdata[snestopc(0x00FFDF)]&0xFF)==((checksum>>8)&0xFF));
508 }
509
510 176 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 176 writeromdata(snestopc(0x00FFDC), "\xFF\xFF\0\0", 4);
514 176 int checksum=(int)getchecksum();
515 176 writeromdata_byte(snestopc(0x00FFDE), (unsigned char)(checksum&255));
516 176 writeromdata_byte(snestopc(0x00FFDF), (unsigned char)((checksum>>8)&255));
517 176 writeromdata_byte(snestopc(0x00FFDC), (unsigned char)((checksum&255)^255));
518 176 writeromdata_byte(snestopc(0x00FFDD), (unsigned char)(((checksum>>8)&255)^255));
519 176 }
520