asar coverage - build #136


src/asar/
File: src/asar/libsmw.cpp
Date: 2024-01-23 08:00:15
Lines:
303/344
88.1%
Functions:
20/21
95.2%
Branches:
289/452
63.9%

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