asar coverage - build #145


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