asar coverage - build #70


src/asar/
File: src/asar/libsmw.cpp
Date: 2024-01-18 03:58:25
Lines:
276/332
83.1%
Functions:
20/21
95.2%
Branches:
244/430
56.7%

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