asar coverage - build #180


src/asar/
File: src/asar/libsmw.cpp
Date: 2024-01-28 20:33:35
Lines:
310/349
88.8%
Functions:
21/21
100.0%
Branches:
294/462
63.6%

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