asar coverage - build #165


src/asar/
File: src/asar/libsmw.cpp
Date: 2024-01-27 07:29:41
Lines:
186/250
74.4%
Functions:
15/17
88.2%
Branches:
128/258
49.6%

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