asar coverage - build #68


src/asar/
File: src/asar/libsmw.cpp
Date: 2024-01-17 04:36:48
Lines:
262/309
84.8%
Functions:
19/19
100.0%
Branches:
215/374
57.5%

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