asar coverage - build #268


src/asar/
File: src/asar/libsmw.cpp
Date: 2025-03-01 20:34:29
Lines:
319/358
89.1%
Functions:
21/21
100.0%
Branches:
425/712
59.7%

Line Branch Exec Source
1 #include <algorithm>
2 #include "asar.h"
3 #include "libmisc.h"
4 #include "crc32.h"
5
6 #include "platform/file-helpers.h"
7
8 mapper_t mapper=lorom;
9 int sa1banks[8]={0<<20, 1<<20, -1, -1, 2<<20, 3<<20, -1, -1};
10 const unsigned char * romdata= nullptr; // NOTE: Changed into const to prevent direct write access - use writeromdata() functions below
11 int romlen;
12 static bool header;
13 unsigned char freespacebyte;
14 static FileHandleType thisfile = InvalidFileHandle;
15
16 asar_error_id openromerror;
17
18 autoarray<writtenblockdata> writtenblocks;
19 static int last_writtenblock_ind = 0;
20 // not immediately put into writtenblocks to allow the freespace finder to use
21 // the reclaimed space.
22 static autoarray<writtenblockdata> cleared_rats_tag_blocks;
23 std::vector<writtenblockdata> found_rats_tags;
24 bool found_rats_tags_initialized;
25
26 // RPG Hacker: Uses binary search to find the insert position of our ROM write
27 483266 static int findromwritepos(int snesoffset, int searchstartpos, int searchendpos)
28 {
29
2/2
✓ Branch 0 taken 139381 times.
✓ Branch 1 taken 343885 times.
483266 if (searchendpos == searchstartpos)
30 {
31 139381 return searchstartpos;
32 }
33
34 343885 int centerpos = searchstartpos + ((searchendpos - searchstartpos) / 2);
35
36
4/4
✓ Branch 0 taken 63387 times.
✓ Branch 1 taken 108468 times.
✓ Branch 2 taken 63443 times.
✓ Branch 3 taken 108587 times.
343885 if (writtenblocks[centerpos].snesoffset >= snesoffset)
37 {
38 126830 return findromwritepos(snesoffset, searchstartpos, centerpos);
39 }
40
41 217055 return findromwritepos(snesoffset, centerpos + 1, searchendpos);
42 }
43
44
45 150391 static void addromwriteforbank(int snesoffset, int numbytes)
46 {
47
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 150232 times.
156278 if(numbytes == 0) return;
48
49 // common case: this rom write is immediately after the last one.
50
2/2
✓ Branch 0 taken 150015 times.
✓ Branch 1 taken 217 times.
150232 if(last_writtenblock_ind < writtenblocks.count) {
51
1/2
✓ Branch 0 taken 150015 times.
✗ Branch 1 not taken.
150015 auto& blk = writtenblocks[last_writtenblock_ind];
52
8/8
✓ Branch 0 taken 6127 times.
✓ Branch 1 taken 68796 times.
✓ Branch 2 taken 6126 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 6161 times.
✓ Branch 5 taken 68931 times.
✓ Branch 6 taken 6159 times.
✓ Branch 7 taken 2 times.
150015 if(blk.snesoffset + blk.numbytes == snesoffset && (blk.snesoffset&0xff0000)==(snesoffset&0xff0000)) {
53 // check if we overlap with next block
54 24570 if(last_writtenblock_ind+1 >= writtenblocks.count
55
9/10
✓ Branch 0 taken 3589 times.
✓ Branch 1 taken 8696 times.
✓ Branch 2 taken 3589 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1555 times.
✓ Branch 5 taken 239 times.
✓ Branch 6 taken 7443 times.
✓ Branch 7 taken 478 times.
✓ Branch 8 taken 5920 times.
✓ Branch 9 taken 239 times.
12285 || writtenblocks[last_writtenblock_ind+1].snesoffset > snesoffset+numbytes) {
56 // if not, merge with previous written block
57 11807 blk.numbytes += numbytes;
58 11807 return;
59 }
60 }
61 }
62 138425 int currentbank = (snesoffset & 0xFF0000);
63
64
1/2
✓ Branch 0 taken 138425 times.
✗ Branch 1 not taken.
138425 int insertpos = findromwritepos(snesoffset, 0, writtenblocks.count);
65
66
5/6
✓ Branch 0 taken 138164 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68795 times.
✓ Branch 3 taken 228 times.
✓ Branch 4 taken 68910 times.
✓ Branch 5 taken 231 times.
138164 if (insertpos > 0 && (writtenblocks[insertpos - 1].snesoffset & 0xFF0000) == currentbank
67
12/14
✓ Branch 0 taken 138164 times.
✓ Branch 1 taken 261 times.
✓ Branch 2 taken 137705 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 68795 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 137529 times.
✓ Branch 7 taken 176 times.
✓ Branch 8 taken 68619 times.
✓ Branch 9 taken 510 times.
✓ Branch 10 taken 68705 times.
✓ Branch 11 taken 205 times.
✓ Branch 12 taken 68705 times.
✓ Branch 13 taken 591 times.
276589 && writtenblocks[insertpos - 1].snesoffset + writtenblocks[insertpos - 1].numbytes >= snesoffset)
68 {
69 // Merge if we overlap with a preceding block
70
3/6
✓ Branch 0 taken 137324 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68619 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 68705 times.
✗ Branch 5 not taken.
137324 int firstend = writtenblocks[insertpos - 1].snesoffset + writtenblocks[insertpos - 1].numbytes;
71 137324 int secondend = snesoffset + numbytes;
72
73
2/2
✓ Branch 0 taken 136431 times.
✓ Branch 1 taken 893 times.
137324 int newend = (firstend > secondend ? firstend : secondend);
74
75
1/2
✓ Branch 0 taken 137324 times.
✗ Branch 1 not taken.
137324 numbytes = newend - writtenblocks[insertpos - 1].snesoffset;
76
1/2
✓ Branch 0 taken 137324 times.
✗ Branch 1 not taken.
137324 snesoffset = writtenblocks[insertpos - 1].snesoffset;
77
78 137324 writtenblocks.remove(insertpos - 1);
79 137324 insertpos -= 1;
80 }
81
82
5/6
✓ Branch 0 taken 126724 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30523 times.
✓ Branch 3 taken 32812 times.
✓ Branch 4 taken 30577 times.
✓ Branch 5 taken 32812 times.
265149 while (insertpos < writtenblocks.count && (writtenblocks[insertpos].snesoffset & 0xFF0000) == currentbank
83
9/10
✓ Branch 0 taken 126724 times.
✓ Branch 1 taken 12257 times.
✓ Branch 2 taken 61100 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 264 times.
✓ Branch 5 taken 30259 times.
✓ Branch 6 taken 556 times.
✓ Branch 7 taken 99414 times.
✓ Branch 8 taken 292 times.
✓ Branch 9 taken 69296 times.
265705 && snesoffset + numbytes >= writtenblocks[insertpos].snesoffset)
84 {
85 // Merge if we overlap with a succeeding block
86 556 int firstend = snesoffset + numbytes;
87
3/6
✓ Branch 0 taken 556 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 264 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 292 times.
✗ Branch 5 not taken.
556 int secondend = writtenblocks[insertpos].snesoffset + writtenblocks[insertpos].numbytes;
88
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 556 times.
556 int newend = (firstend > secondend ? firstend : secondend);
90
91 556 numbytes = newend - snesoffset;
92
93 556 writtenblocks.remove(insertpos);
94 }
95
96 // Insert ROM write
97 69296 writtenblockdata blockdata;
98 138425 blockdata.snesoffset = snesoffset;
99 138425 blockdata.pcoffset = snestopc(snesoffset);
100 138425 blockdata.numbytes = numbytes;
101
102
1/2
✓ Branch 0 taken 138425 times.
✗ Branch 1 not taken.
138425 writtenblocks.insert(insertpos, blockdata);
103 138425 last_writtenblock_ind = insertpos;
104 }
105
106
107 150232 void addromwrite(int pcoffset, int numbytes)
108 {
109 150232 int snesaddr = pctosnes(pcoffset);
110 150232 int bytesleft = numbytes;
111
112 // RPG Hacker: Some kind of witchcraft which I actually hope works as intended
113 // Basically, the purpose of this is to sort all ROM writes into banks for the sake of cleanness
114
115
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 150232 times.
150391 while ((snesaddr >> 16) != ((snesaddr + bytesleft) >> 16))
116 {
117 159 int bytesinbank = ((snesaddr + 0x10000) & 0xffff0000) - snesaddr;
118
119 159 addromwriteforbank(snesaddr, bytesinbank);
120
121 159 pcoffset += bytesinbank;
122 159 snesaddr = pctosnes(pcoffset);
123 159 bytesleft -= bytesinbank;
124 }
125
126 150232 addromwriteforbank(snesaddr, bytesleft);
127 150232 }
128
129 28 void writeromdata(int pcoffset, const void * indata, int numbytes)
130 {
131
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
28 memcpy(const_cast<unsigned char*>(romdata) + pcoffset, indata, (size_t)numbytes);
132 28 addromwrite(pcoffset, numbytes);
133 28 }
134
135 149628 void writeromdata_byte(int pcoffset, unsigned char indata, bool add_write)
136 {
137 149628 memcpy(const_cast<unsigned char*>(romdata) + pcoffset, &indata, 1);
138
2/2
✓ Branch 0 taken 140502 times.
✓ Branch 1 taken 9126 times.
149628 if(add_write)
139 140502 addromwrite(pcoffset, 1);
140 149628 }
141
142 128 void writeromdata_bytes(int pcoffset, unsigned char indata, int numbytes, bool add_write)
143 {
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
128 memset(const_cast<unsigned char*>(romdata) + pcoffset, indata, (size_t)numbytes);
145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
128 if(add_write)
146 addromwrite(pcoffset, numbytes);
147 128 }
148
149 110 int ratsstart(int snesaddr)
150 {
151 110 int pcaddr=snestopc(snesaddr);
152
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 106 times.
110 if (pcaddr<0x7FFF8) return -1;
153 106 const unsigned char * start=romdata+pcaddr-0x10000;
154
2/2
✓ Branch 0 taken 132250 times.
✓ Branch 1 taken 2 times.
132252 for (int i=0x10000;i>=0;i--)
155 {
156
5/5
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 66073 times.
✓ Branch 2 taken 66125 times.
✓ Branch 3 taken 52 times.
✓ Branch 4 taken 66073 times.
132250 if (!strncmp((const char*)start+i, "STAR", 4) &&
157
4/8
✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 52 times.
✗ Branch 7 not taken.
104 (start[i+4]^start[i+6])==0xFF && (start[i+5]^start[i+7])==0xFF)
158 {
159
3/6
✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 52 times.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
104 if ((start[i+4]|(start[i+5]<<8))>0x10000-i-8-1) return pctosnes((int)(start-romdata+i));
160 return -1;
161 }
162 }
163 2 return -1;
164 }
165
166 6 static void handleprot(int loc, char * name, int len, const unsigned char * contents)
167 {
168 (void)loc; // RPG Hacker: Silence "unused argument" warning.
169
170
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 if (!strncmp(name, "PROT", 4))
171 {
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 memcpy(name, "NULL", 4);//to block recursion, in case someone is an idiot
173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (len%3) return;
174 6 len/=3;
175
6/8
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 3 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);
176 }
177 }
178
179 28 void removerats(int snesaddr, unsigned char clean_byte)
180 {
181 28 int addr=ratsstart(snesaddr);
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (addr<0) return;
183 // randomdude999: don't forget bank borders
184 28 WalkMetadata(pctosnes(snestopc(addr)+8), handleprot);
185 28 addr=snestopc(addr);
186 // don't use writeromdata() because this must not go to the writtenblocks list.
187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
28 int len = (romdata[addr+4]|(romdata[addr+5]<<8))+9;
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
28 memset(const_cast<unsigned char*>(romdata) + addr, clean_byte, len);
189
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
28 cleared_rats_tag_blocks[cleared_rats_tag_blocks.count] = writtenblockdata{addr, 0, len};
190 }
191
192 272 void handle_cleared_rats_tags()
193 {
194
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 272 times.
300 for(int i = 0; i < cleared_rats_tag_blocks.count; i++) {
195 28 auto & block = cleared_rats_tag_blocks[i];
196 28 addromwrite(block.pcoffset, block.numbytes);
197 }
198 272 cleared_rats_tag_blocks.reset();
199 272 }
200
201 54 static void find_rats_tags()
202 {
203 // TODO: should probably look for overlapping rats tags too, just in case.
204 // note that found_rats_tags must not have overlaps, but we can merge overlapped rats tags into one
205 54 found_rats_tags.clear();
206
2/2
✓ Branch 0 taken 37748952 times.
✓ Branch 1 taken 54 times.
37749006 for(int pos = 0; pos < romlen;) {
207
5/5
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18874474 times.
✓ Branch 2 taken 18874476 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 18874474 times.
37748952 if (!strncmp((const char*)romdata+pos, "STAR", 4) &&
208
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 (romdata[pos+4]^romdata[pos+6])==0xFF &&
209
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 (romdata[pos+5]^romdata[pos+7])==0xFF) {
210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
4 int block_len = (romdata[pos+4]|(romdata[pos+5]<<8))+1+8;
211
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 found_rats_tags.push_back(writtenblockdata{pos, 0, block_len});
212 4 pos += block_len;
213 4 } else {
214 37748948 pos++;
215 }
216 }
217 54 found_rats_tags_initialized = true;
218 54 }
219
220 552 static inline int trypcfreespace(int start, int alt_start, int end, int size, int banksize, int minalign, unsigned char freespacebyte, bool write_rats)
221 {
222
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 542 times.
552 if(alt_start >= 0) start = std::max(start, alt_start);
223
4/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 525 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 249 times.
552 if(!found_rats_tags_initialized) find_rats_tags();
224
2/2
✓ Branch 0 taken 143050 times.
✓ Branch 1 taken 38 times.
143088 while (start+size<=end)
225 {
226
2/2
✓ Branch 0 taken 142878 times.
✓ Branch 1 taken 172 times.
143050 if (write_rats &&
227
2/2
✓ Branch 0 taken 2578 times.
✓ Branch 1 taken 140300 times.
142878 ((start+8)&~banksize)!=((start+size-1)&~banksize&0xFFFFFF)//if the contents won't fit in this bank...
228 )
229 {
230 // if we are not already at the end of the bank
231
2/2
✓ Branch 0 taken 2574 times.
✓ Branch 1 taken 4 times.
2578 if((start&banksize&0xFFFFF8) != (banksize&0xFFFFF8)) {
232 2574 start&=~banksize&0xFFFFFF;//round it down to the start of the bank,
233 2574 start|=banksize&0xFFFFF8;//then round it up to the end minus the RATS tag...
234 72555 continue;
235 //} else if((start&banksize) == (banksize&0xFFFFF8)) {
236 // we are exactly 8 bytes off the end, allow this one to continue
237 } else {
238 // less than 8 bytes left in this bank
239 // go to the start of the next bank
240 4 start = (start+7) & ~7;
241 4 continue;
242 }
243 }
244
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 140300 times.
140472 else if(!write_rats &&
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 172 times.
172 (start&~banksize) != ((start+size-1)&~banksize))
246 {
247 // go to next bank.
248 start = (start|banksize)+1;
249 continue;
250 }
251
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 140466 times.
140472 if (minalign)
252 {
253 6 start&=~minalign&0xFFFFFF;
254 6 start|=minalign&0xFFFFF8;
255 }
256 140472 bool bad=false;
257
2/2
✓ Branch 0 taken 8815886 times.
✓ Branch 1 taken 958 times.
8816844 for (int i=0;i<size;i++)
258 {
259
4/4
✓ Branch 0 taken 69757 times.
✓ Branch 1 taken 4338186 times.
✓ Branch 2 taken 69757 times.
✓ Branch 3 taken 4338186 times.
8815886 if (romdata[start+i]!=freespacebyte)
260 {
261 // TheBiob: fix freedata align freezing.
262
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 139512 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
139514 if ((start & minalign) == 0x7FF8 && i < 8) i = 8;
263 139514 start+=i;
264
2/2
✓ Branch 0 taken 103674 times.
✓ Branch 1 taken 35840 times.
139514 if (!i) start++;//this could check for a rats tag instead, but somehow I think this will give better performance.
265 139514 bad=true;
266 139514 break;
267 }
268 }
269
2/2
✓ Branch 0 taken 139514 times.
✓ Branch 1 taken 958 times.
140472 if (bad) continue;
270 // check against collisions with rats tags.
271 // lower_bound returns first element where comp() is false,
272 // i.e. the first RATS tag that starts after our spot
273
2/3
✓ Branch 0 taken 479 times.
✓ Branch 1 taken 479 times.
✗ Branch 2 not taken.
958 auto rats = std::lower_bound(found_rats_tags.begin(), found_rats_tags.end(), start, [](writtenblockdata& blk, int start){
274 14 return blk.pcoffset < start;
275 });
276 // if there's a rats tag after us,
277
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 477 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 477 times.
958 if(rats != found_rats_tags.end()) {
278 // check that it doesn't intersect our spot
279
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if(rats->pcoffset < start+size) {
280 // our spot ends inside this rats tag, skip to the end of it
281 start = rats->pcoffset + rats->numbytes;
282 continue;
283 }
284 }
285 // if there's a rats tag before us,
286
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 474 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 474 times.
958 if(rats != found_rats_tags.begin()) {
287 10 rats--;
288 // and it doesn't end before our spot starts,
289
10/11
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 4 times.
10 if(start >= rats->pcoffset && start < rats->pcoffset+rats->numbytes) {
290 // we're inside this rats tag, skip to its end
291 2 start = rats->pcoffset + rats->numbytes;
292 2 continue;
293 }
294 }
295 // check against collisions with any written blocks.
296 // written blocks go through like 3x snes->pc->snes and are then sorted by snes.
297 // todo: this is janky..... should sort writtenblocks by pc maybe??
298 956 int snesstart = pctosnes(start);
299 // this gives the index of the first block whose snespos is >= start.
300
1/2
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
956 int writtenblock_pos = findromwritepos(snesstart, 0, writtenblocks.count);
301 // we might need to check the preceding block too.
302 // (but we don't need to check any older ones, as blocks are merged together)
303
2/2
✓ Branch 0 taken 938 times.
✓ Branch 1 taken 18 times.
956 if(writtenblock_pos > 0) writtenblock_pos--;
304
2/2
✓ Branch 0 taken 962 times.
✓ Branch 1 taken 502 times.
1464 for(; writtenblock_pos < writtenblocks.count; writtenblock_pos++)
305 {
306
1/2
✓ Branch 0 taken 962 times.
✗ Branch 1 not taken.
962 auto & block = writtenblocks[writtenblock_pos];
307
4/4
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 254 times.
✓ Branch 2 taken 227 times.
✓ Branch 3 taken 254 times.
962 if(snesstart < block.snesoffset+block.numbytes
308
4/4
✓ Branch 0 taken 221 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 221 times.
✓ Branch 3 taken 6 times.
454 && snesstart+size > block.snesoffset)
309 {
310 442 start = block.pcoffset + block.numbytes;
311 442 bad = true;
312 442 break;
313 }
314 // blocks are sorted by snesoffset, so if they start after our end we know there are no more that could intersect
315
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 254 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 254 times.
520 if(block.snesoffset > snesstart+size) break;
316 }
317
2/2
✓ Branch 0 taken 442 times.
✓ Branch 1 taken 514 times.
956 if (bad) continue;
318
2/2
✓ Branch 0 taken 486 times.
✓ Branch 1 taken 28 times.
514 if(write_rats)
319 {
320 486 size-=8;
321
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 addromwrite(start+8, size);
322
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 if (size) size--;//rats tags eat one byte more than specified for some reason
323
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 writeromdata_byte(start+0, 'S');
324
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 writeromdata_byte(start+1, 'T');
325
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 writeromdata_byte(start+2, 'A');
326
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 writeromdata_byte(start+3, 'R');
327
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 writeromdata_byte(start+4, (unsigned char)(size&0xFF));
328
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 writeromdata_byte(start+5, (unsigned char)((size>>8)&0xFF));
329
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 writeromdata_byte(start+6, (unsigned char)((size&0xFF)^0xFF));
330
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
486 writeromdata_byte(start+7, (unsigned char)(((size>>8)&0xFF)^0xFF));
331 500 return start+8;
332 }
333 else
334 {
335 // not sure if needs to be done here,
336 // but it needs to be done somewhere
337
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 addromwrite(start, size);
338 28 return start;
339 }
340 }
341 38 return -1;
342 }
343
344 //This function finds a block of freespace. -1 means "no freespace found", anything else is a PC address.
345 //isforcode=false tells it to favor banks 40+, true tells it to avoid them entirely.
346 //It automatically adds a RATS tag.
347
348 514 int getpcfreespace(int size, int target_bank, bool autoexpand, bool respectbankborders, bool align, bool write_rats, int search_start)
349 {
350 // TODO: probably should error if specifying target_bank and align, or target_bank and respectbankborders
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
514 if (!size) {
352 // return a dummy valid address. 0x8000 should work in most mappers
353 if(target_bank >= 0) return snestopc(target_bank << 16 | 0x8000);
354 return 0;
355 }
356
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
514 if (size>0x10000 && (write_rats || respectbankborders)) return -1;
357 514 bool isforcode = target_bank == -2;
358
4/4
✓ Branch 0 taken 243 times.
✓ Branch 1 taken 271 times.
✓ Branch 2 taken 243 times.
✓ Branch 3 taken 14 times.
514 if(write_rats)
359 486 size+=8;
360
361 262 auto find_for_fixed_bank = [&](int banksize, bool force_high_half = false) {
362
5/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4 times.
10 if(!force_high_half && (target_bank & 0x40) == 0x40)
363
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
14 return trypcfreespace(snestopc(target_bank<<16), search_start, min(romlen, snestopc(target_bank<<16)+0x10000), size, banksize, 0, freespacebyte, write_rats);
364 else
365
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
16 return trypcfreespace(snestopc(target_bank<<16 | 0x8000), search_start, min(romlen, snestopc(target_bank<<16 | 0x8000)+0x8000), size, banksize, 0, freespacebyte, write_rats);
366 514 };
367
368
4/4
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 264 times.
✓ Branch 2 taken 250 times.
✓ Branch 3 taken 7 times.
514 if (mapper==lorom)
369 {
370
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 494 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
500 if(target_bank >= 0) return find_for_fixed_bank(0x7fff);
371
1/4
✓ Branch 0 taken 494 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
494 if (size>0x8008 && respectbankborders) return -1;
372 513 rebootlorom:
373
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 504 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
532 if (romlen>0x200000 && !isforcode)
374 {
375
8/11
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 14 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 14 times.
✗ Branch 10 not taken.
56 int pos=trypcfreespace(search_start >= 0 ? 0 : 0x200000-8, search_start, (romlen<0x400000)?romlen:0x400000, size,
376
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
28 respectbankborders?0x7FFF:0xFFFFFF, align?0x7FFF:(respectbankborders || size<32768)?0:0x7FFF, freespacebyte, write_rats);
377
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (pos>=0) return pos;
378 }
379
9/11
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 501 times.
✓ Branch 2 taken 255 times.
✓ Branch 3 taken 249 times.
✓ Branch 4 taken 256 times.
✓ Branch 5 taken 248 times.
✓ Branch 6 taken 256 times.
✓ Branch 7 taken 248 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 252 times.
✗ Branch 10 not taken.
1002 int pos=trypcfreespace(search_start >= 0 ? 0 : 0x80000, search_start, (romlen<0x200000)?romlen:0x200000, size,
380
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
498 respectbankborders?0x7FFF:0xFFFFFF, align?0x7FFF:(respectbankborders || size<32768)?0:0x7FFF, freespacebyte, write_rats);
381
2/2
✓ Branch 0 taken 466 times.
✓ Branch 1 taken 38 times.
504 if (pos>=0) return pos;
382
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (autoexpand)
383 {
384 if(0);
385
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 4 times.
38 else if (romlen==0x080000)
386 {
387
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 writeromdata_bytes(romlen, freespacebyte, 0x100000 - romlen, false);
388 34 romlen=0x100000;
389
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 writeromdata_byte(snestopc(0x00FFD7), 0x0A);
390 }
391
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if (romlen==0x100000)
392 {
393
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 writeromdata_bytes(romlen, freespacebyte, 0x200000 - romlen, false);
394 2 romlen=0x200000;
395
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 writeromdata_byte(snestopc(0x00FFD7), 0x0B);
396 }
397
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (isforcode) return -1;//no point creating freespace that can't be used
398
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 else if (romlen==0x200000 || romlen==0x300000)
399 {
400
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 writeromdata_bytes(romlen, freespacebyte, 0x400000 - romlen, false);
401 2 romlen=0x400000;
402
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 writeromdata_byte(snestopc(0x00FFD7), 0x0C);
403 }
404 else return -1;
405 38 autoexpand=false;
406 38 goto rebootlorom;
407 }
408 }
409
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2 times.
14 if (mapper==hirom)
410 {
411
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
10 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
412
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (isforcode)
413 {
414
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 for(int i = 0x8000; i < min(romlen, 0x400000); i += 0x10000){
415
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
2 int space = trypcfreespace(i, search_start, min(i+0x7FFF, romlen), size, 0x7FFF, align?0xFFFF:0, freespacebyte, write_rats);
416
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(space != -1) return space;
417 }
418 return -1;
419 }
420
5/9
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
4 return trypcfreespace(0, search_start, romlen, size, respectbankborders?0xFFFF:0xFFFFFF, align?0xFFFF:0, freespacebyte, write_rats);
421 }
422
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
4 if (mapper==exlorom)
423 {
424 if(target_bank >= 0) return find_for_fixed_bank(0x7fff);
425 // RPG Hacker: Not really 100% sure what to do here, but I suppose this simplified code will do
426 // and we won't need all the complicated stuff from LoROM above?
427 if (isforcode)
428 {
429 trypcfreespace(0, search_start, min(romlen, 0x200000), size, 0x7FFF, align?0x7FFF:0, freespacebyte, write_rats);
430 }
431 return trypcfreespace(0, search_start, romlen, size, 0x7FFF, align ? 0x7FFF : 0, freespacebyte, write_rats);
432 }
433
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
4 if (mapper==exhirom)
434 {
435 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
436 if (isforcode)
437 {
438 for(int i = 0x8000; i < romlen && i < 0x400000; i += 0x10000){
439 int space = trypcfreespace(i, search_start, min(i+0x7FFF, romlen), size, 0x7FFF, align?0xFFFF:0, freespacebyte, write_rats);
440 if(space != -1) return space;
441 }
442 return -1;
443 }
444 return trypcfreespace(0, search_start, romlen, size, respectbankborders?0xFFFF:0xFFFFFF, align?0xFFFF:0, freespacebyte, write_rats);
445 }
446
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
4 if (mapper==sfxrom)
447 {
448
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!isforcode) return -1;
450 // try not to overwrite smw stuff
451
5/9
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 return trypcfreespace(search_start >= 0 ? 0 : 0x80000, search_start, romlen, size, 0x7FFF, align?0x7FFF:0, freespacebyte, write_rats);
452 }
453
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (mapper==sa1rom)
454 {
455
1/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
456 4 rebootsa1rom:
457 4 int nextbank=-1;
458
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (int i=0;i<8;i++)
459 {
460
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (i&2) continue;
461
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
10 if (sa1banks[i]+0x100000>romlen)
462 {
463
6/7
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
8 if (sa1banks[i]<=romlen && sa1banks[i]+0x100000>romlen) nextbank=sa1banks[i];
464 8 continue;
465 }
466
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
2 int pos=trypcfreespace(sa1banks[i]?sa1banks[i]:0x80000, search_start, sa1banks[i]+0x100000, size, 0x7FFF, align?0x7FFF:0, freespacebyte, write_rats);
467
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (pos>=0) return pos;
468 }
469
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)
470 {
471 2 unsigned char x7FD7[]={0, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D};
472
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 writeromdata_bytes(romlen, freespacebyte, nextbank + 0x100000 - romlen, false);
473 2 romlen=nextbank+0x100000;
474
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 writeromdata_byte(0x7FD7, x7FD7[romlen>>20]);
475 2 autoexpand=false;
476 2 goto rebootsa1rom;
477 }
478 }
479 if (mapper==bigsa1rom)
480 {
481 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
482 if(!isforcode && romlen > 0x400000)
483 {
484 int pos=trypcfreespace(0x400000, search_start, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte, write_rats);
485 if(pos>=0) return pos;
486 }
487 int pos=trypcfreespace(search_start >= 0 ? 0 : 0x080000, search_start, romlen, size, 0x7FFF, align?0x7FFF:0, freespacebyte, write_rats);
488 if(pos>=0) return pos;
489 }
490 return -1;
491 }
492
493 28 void WalkMetadata(int loc, void(*func)(int loc, char * name, int len, const unsigned char * contents))
494 {
495 28 int pcoff=snestopc(loc);
496
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
28 if (strncmp((const char*)romdata+pcoff-8, "STAR", 4)) return;
497 28 const unsigned char * metadata=romdata+pcoff;
498
12/15
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 17 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 5 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 5 times.
✓ Branch 14 taken 12 times.
34 while (is_upper(metadata[0]) && is_upper(metadata[1]) && is_upper(metadata[2]) && is_upper(metadata[3]))
499 {
500
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 3 times.
10 if (!strncmp((const char*)metadata, "STOP", 4))
501 {
502 4 metadata=romdata+pcoff;
503
10/15
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 5 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 5 times.
✗ Branch 14 not taken.
10 while (is_upper(metadata[0]) && is_upper(metadata[1]) && is_upper(metadata[2]) && is_upper(metadata[3]))
504 {
505
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 3 times.
10 if (!strncmp((const char*)metadata, "STOP", 4))
506 {
507 4 break;
508 }
509 6 func(pctosnes((int)(metadata-romdata)), (char*)const_cast<unsigned char*>(metadata), metadata[4], metadata+5);
510 6 metadata+=5+metadata[4];
511 }
512 4 break;
513 }
514 6 metadata+=5+metadata[4];
515 }
516 }
517
518 514 int getsnesfreespace(int size, int target_bank, bool autoexpand, bool respectbankborders, bool align, bool write_rats, int search_start)
519 {
520 514 int pcfree = getpcfreespace(size, target_bank, autoexpand, respectbankborders, align, write_rats, snestopc(search_start));
521 514 int snesfree = pctosnes(pcfree);
522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
514 if(snesfree == -1) return -1;
523 514 bool isforcode = target_bank == -2;
524 // not sure if this is ever a concern for other mappers...
525
8/10
✓ Branch 0 taken 374 times.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 186 times.
✓ Branch 3 taken 188 times.
✓ Branch 4 taken 186 times.
✓ Branch 5 taken 187 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 186 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 186 times.
514 if(isforcode && (mapper == hirom || mapper == exhirom)) {
526 2 snesfree = snesfree & ~0x400000;
527 // maybe this should throw an internal error or something instead lol
528
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if((snesfree&0x8000) != 0x8000) return -1;
529 }
530 514 return snesfree;
531 }
532
533 3 bool openrom(const char * filename, bool confirm)
534 {
535 3 closerom();
536 3 thisfile = open_file(filename, FileOpenMode_ReadWrite);
537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (thisfile == InvalidFileHandle)
538 {
539 openromerror = error_id_open_rom_failed;
540 return false;
541 }
542 3 header=false;
543
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (strlen(filename)>4)
544 {
545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 const char * fnameend=strchr(filename, '\0')-4;
546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 header=(!stricmp(fnameend, ".smc"));
547 }
548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 romlen=(int)get_file_size(thisfile)-(header*512);
549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (romlen<0) romlen=0;
550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 set_file_pos(thisfile, header*512);
551 3 romdata=(unsigned char*)malloc(sizeof(unsigned char)*16*1024*1024);
552 3 int truelen=(int)read_file(thisfile, (void*)romdata, (uint32_t)romlen);
553
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (truelen!=romlen)
554 {
555 openromerror = error_id_open_rom_failed;
556 free(const_cast<unsigned char*>(romdata));
557 return false;
558 }
559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 memset(const_cast<unsigned char*>(romdata)+romlen, 0x00, (size_t)(16*1024*1024-romlen));
560
2/11
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
3 if (confirm && snestopc(0x00FFC0)+21<(int)romlen && strncmp((const char*)romdata+snestopc(0x00FFC0), "SUPER MARIOWORLD ", 21))
561 {
562 closerom(false);
563 openromerror = header ? error_id_open_rom_not_smw_extension : error_id_open_rom_not_smw_header;
564 return false;
565 }
566
567 3 romdata_r=(unsigned char*)malloc((size_t)romlen);
568 3 romlen_r=romlen;
569
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 memcpy((void*)romdata_r, romdata, (size_t)romlen);//recently allocated, dead
570
571 3 return true;
572 }
573
574 6 uint32_t closerom(bool save)
575 {
576 6 uint32_t romCrc = 0;
577
4/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 if (thisfile != InvalidFileHandle && save && romlen)
578 {
579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 set_file_pos(thisfile, header*512);
580 3 write_file(thisfile, romdata, (uint32_t)romlen);
581
582 // do a quick re-read of the header, and include that in the crc32 calculation if necessary
583 {
584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 uint8_t* filedata = (uint8_t*)malloc(sizeof(uint8_t) * (romlen + header * 512));
585
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (header)
586 {
587 set_file_pos(thisfile, 0u);
588 read_file(thisfile, filedata, 512);
589 }
590
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 memcpy(filedata + (header * 512), romdata, sizeof(uint8_t) * (size_t)romlen);
591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 romCrc = crc32(filedata, (unsigned int)(romlen + header * 512));
592 3 free(filedata);
593 }
594 }
595
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (thisfile != InvalidFileHandle) close_file(thisfile);
596
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (romdata) free(const_cast<unsigned char*>(romdata));
597
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (romdata_r) free(const_cast<unsigned char*>(romdata_r));
598 6 thisfile= InvalidFileHandle;
599 6 romdata= nullptr;
600 6 romdata_r = nullptr;
601 6 romlen=0;
602 6 return romCrc;
603 }
604
605 28 static unsigned int getchecksum()
606 {
607 28 unsigned int checksum=0;
608
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 5 times.
28 if((romlen & (romlen-1)) == 0)
609 {
610 // romlen is a power of 2, just add up all the bytes
611
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 131084 times.
✓ Branch 3 taken 23 times.
131107 for (int i=0;i<romlen;i++) checksum+=romdata[i];
612 }
613 else
614 {
615 // assume romlen is the sum of 2 powers of 2 - i haven't seen any real rom that isn't,
616 // and if you make such a rom, fixing its checksum is your problem.
617 5 int firstpart = bitround(romlen) >> 1;
618 5 int secondpart = romlen - firstpart;
619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 int repeatcount = firstpart / secondpart;
620 5 unsigned int secondpart_sum = 0;
621
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 65546 times.
✓ Branch 3 taken 5 times.
65551 for(int i = 0; i < firstpart; i++) checksum += romdata[i];
622
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 5 times.
14 for(int i = firstpart; i < romlen; i++) secondpart_sum += romdata[i];
623 5 checksum += secondpart_sum * repeatcount;
624 }
625 28 return checksum&0xFFFF;
626 }
627
628 28 void fixchecksum()
629 {
630 // randomdude999: clear out checksum bytes before recalculating checksum, this should make it correct on roms that don't have a checksum yet
631 28 writeromdata(snestopc(0x00FFDC), "\xFF\xFF\0\0", 4);
632 28 int checksum=(int)getchecksum();
633 28 writeromdata_byte(snestopc(0x00FFDE), (unsigned char)(checksum&255));
634 28 writeromdata_byte(snestopc(0x00FFDF), (unsigned char)((checksum>>8)&255));
635 28 writeromdata_byte(snestopc(0x00FFDC), (unsigned char)((checksum&255)^255));
636 28 writeromdata_byte(snestopc(0x00FFDD), (unsigned char)(((checksum>>8)&255)^255));
637 28 }
638