LCOV - code coverage report
Current view: top level - asar - libsmw.cpp (source / functions) Coverage Total Hit
Test: asar build #66 Lines: 84.8 % 309 262
Test Date: 2024-01-16 02:45:19 Functions: 100.0 % 19 19
Branches: 58.0 % 350 203

             Branch data     Line data    Source code
       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         [ +  + ]:      471894 :         if (searchendpos == searchstartpos)
      24                 :             :         {
      25                 :       79543 :                 return searchstartpos;
      26                 :             :         }
      27                 :             : 
      28                 :      312808 :         int centerpos = searchstartpos + ((searchendpos - searchstartpos) / 2);
      29                 :             : 
      30         [ +  + ]:      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                 :      158626 :         int insertpos = findromwritepos(snesoffset, 0, writtenblocks.count);
      44                 :             : 
      45   [ +  +  +  + ]:      158168 :         if (insertpos > 0 && (writtenblocks[insertpos - 1].snesoffset & 0xFF0000) == currentbank
      46   [ +  +  +  +  :      316602 :                 && writtenblocks[insertpos - 1].snesoffset + writtenblocks[insertpos - 1].numbytes >= snesoffset)
          +  -  +  +  +  
                      + ]
      47                 :             :         {
      48                 :             :                 // Merge if we overlap with a preceding block
      49                 :      157102 :                 int firstend = writtenblocks[insertpos - 1].snesoffset + writtenblocks[insertpos - 1].numbytes;
      50                 :      157102 :                 int secondend = snesoffset + numbytes;
      51                 :             : 
      52         [ +  + ]:       78551 :                 int newend = (firstend > secondend ? firstend : secondend);
      53                 :             : 
      54                 :      157102 :                 numbytes = newend - writtenblocks[insertpos - 1].snesoffset;
      55                 :      157102 :                 snesoffset = writtenblocks[insertpos - 1].snesoffset;
      56                 :             : 
      57                 :      157102 :                 writtenblocks.remove(insertpos - 1);
      58                 :       78551 :                 insertpos -= 1;
      59                 :             :         }
      60                 :             : 
      61   [ +  +  +  + ]:      207315 :         while (insertpos <  writtenblocks.count && (writtenblocks[insertpos].snesoffset & 0xFF0000) == currentbank
      62   [ +  +  +  +  :      254255 :                 && snesoffset + numbytes >= writtenblocks[insertpos].snesoffset)
             +  +  +  + ]
      63                 :             :         {
      64                 :             :                 // Merge if we overlap with a succeeding block
      65                 :         409 :                 int firstend = snesoffset + numbytes;
      66                 :         818 :                 int secondend = writtenblocks[insertpos].snesoffset + writtenblocks[insertpos].numbytes;
      67                 :             : 
      68         [ +  + ]:         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                 :      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         [ +  + ]:      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         [ +  + ]:          70 :         if (pcaddr<0x7FFF8) return -1;
     129                 :          62 :         const unsigned char * start=romdata+pcaddr-0x10000;
     130         [ +  - ]:        1028 :         for (int i=0x10000;i>=0;i--)
     131                 :             :         {
     132         [ +  + ]:        1028 :                 if (!strncmp((const char*)start+i, "STAR", 4) &&
     133   [ +  -  +  - ]:          62 :                                 (start[i+4]^start[i+6])==0xFF && (start[i+5]^start[i+7])==0xFF)
     134                 :             :                 {
     135         [ +  - ]:          62 :                         if ((start[i+4]|(start[i+5]<<8))>0x10000-i-8-1) return pctosnes((int)(start-romdata+i));
     136                 :           0 :                         return -1;
     137                 :             :                 }
     138                 :             :         }
     139                 :           0 :         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         [ +  - ]:           6 :         if (!strncmp(name, "PROT", 4))
     147                 :             :         {
     148                 :           6 :                 memcpy(name, "NULL", 4);//to block recursion, in case someone is an idiot
     149         [ +  + ]:           6 :                 if (len%3) return;
     150                 :           6 :                 len/=3;
     151         [ +  + ]:          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         [ +  + ]:          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         [ +  + ]:         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         [ +  + ]:       19868 :         while (start+size<=end)
     181                 :             :         {
     182         [ +  + ]:       19838 :                 if (write_rats &&
     183         [ +  + ]:       19824 :                                 ((start+8)&~banksize)!=((start+size-1)&~banksize&0xFFFFFF)//if the contents won't fit in this bank...
     184                 :           2 :                         &&
     185         [ +  - ]:           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         [ +  + ]:        9925 :                 else if(!write_rats &&
     193         [ -  + ]:          14 :                                 (start&~banksize) != ((start+size-1)&~banksize))
     194                 :             :                 {
     195                 :             :                         // go to next bank.
     196                 :           0 :                         start = (start|banksize)+1;
     197                 :           0 :                         continue;
     198                 :             :                 }
     199         [ +  + ]:       19836 :                 if (minalign)
     200                 :             :                 {
     201                 :           8 :                         start&=~minalign&0xFFFFFF;
     202                 :           8 :                         start|=minalign&0xFFFFF8;
     203                 :             :                 }
     204         [ +  + ]:       19836 :                 if (!strncmp((const char*)romdata+start, "STAR", 4) &&
     205   [ +  +  +  + ]:       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         [ +  + ]:     4333524 :                 for (int i=0;i<size;i++)
     212                 :             :                 {
     213         [ -  + ]:     4333064 :                         if (romdata[start+i]!=freespacebyte)
     214                 :             :                         {
     215                 :             :                                 // TheBiob: fix freedata align freezing.
     216   [ #  #  #  # ]:           0 :                                 if ((start & minalign) == 0x7FF8 && i < 8) i = 8;
     217                 :           0 :                                 start+=i;
     218         [ #  # ]:           0 :                                 if (!i) start++;//this could check for a rats tag instead, but somehow I think this will give better performance.
     219                 :           0 :                                 bad=true;
     220                 :           0 :                                 break;
     221                 :             :                         }
     222                 :             :                 }
     223         [ -  + ]:         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         [ +  + ]:         460 :                 if(writtenblock_pos > 0) writtenblock_pos--;
     233         [ +  + ]:         920 :                 for(; writtenblock_pos < writtenblocks.count; writtenblock_pos++)
     234                 :             :                 {
     235                 :         234 :                         auto & block = writtenblocks[writtenblock_pos];
     236         [ +  + ]:         468 :                         if(snesstart < block.snesoffset+block.numbytes
     237         [ +  + ]:           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         [ +  + ]:         462 :                         if(block.snesoffset > snesstart+size) break;
     245                 :             :                 }
     246         [ +  + ]:         233 :                 if (bad) continue;
     247         [ +  + ]:         454 :                 if(write_rats)
     248                 :             :                 {
     249                 :         444 :                         size-=8;
     250         [ +  - ]:         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         [ +  + ]:         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         [ -  + ]:         454 :         if (size>0x10000) return -1;
     282                 :         454 :         bool isforcode = target_bank == -2;
     283         [ +  + ]:         454 :         if(write_rats)
     284                 :         444 :                 size+=8;
     285                 :             : 
     286                 :           6 :         auto find_for_fixed_bank = [&](int banksize, bool force_high_half = false) {
     287   [ +  -  -  + ]:           6 :                 if(!force_high_half && (target_bank & 0x40) == 0x40)
     288                 :           0 :                         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         [ +  + ]:         454 :         if (mapper==lorom)
     294                 :             :         {
     295   [ +  +  +  - ]:         450 :                 if(target_bank >= 0) return find_for_fixed_bank(0x7fff);
     296   [ +  +  +  + ]:         444 :                 if (size>0x8008 && respectbankborders) return -1;
     297                 :         444 :         rebootlorom:
     298   [ +  +  +  - ]:         474 :                 if (romlen>0x200000 && !isforcode)
     299                 :             :                 {
     300   [ -  +  +  -  :          56 :                         int pos=trypcfreespace(0x200000-8, (romlen<0x400000)?romlen:0x400000, size,
                   +  - ]
     301   [ -  +  -  - ]:          28 :                                         respectbankborders?0x7FFF:0xFFFFFF, align?0x7FFF:(respectbankborders || size<32768)?0:0x7FFF, freespacebyte, write_rats);
     302         [ +  - ]:          28 :                         if (pos>=0) return pos;
     303                 :             :                 }
     304   [ +  +  +  +  :         891 :                 int pos=trypcfreespace(0x80000, (romlen<0x200000)?romlen:0x200000, size,
                   +  - ]
     305   [ +  +  +  + ]:         440 :                                 respectbankborders?0x7FFF:0xFFFFFF, align?0x7FFF:(respectbankborders || size<32768)?0:0x7FFF, freespacebyte, write_rats);
     306         [ +  + ]:         446 :                 if (pos>=0) return pos;
     307         [ +  - ]:          30 :                 if (autoexpand)
     308                 :             :                 {
     309                 :             :                         if(0);
     310         [ +  + ]:          30 :                         else if (romlen==0x080000)
     311                 :             :                         {
     312                 :          26 :                                 romlen=0x100000;
     313                 :          26 :                                 writeromdata_byte(snestopc(0x00FFD7), 0x0A);
     314                 :             :                         }
     315         [ +  + ]:           4 :                         else if (romlen==0x100000)
     316                 :             :                         {
     317                 :           2 :                                 romlen=0x200000;
     318                 :           2 :                                 writeromdata_byte(snestopc(0x00FFD7), 0x0B);
     319                 :             :                         }
     320         [ -  + ]:           2 :                         else if (isforcode) return -1;//no point creating freespace that can't be used
     321   [ -  +  -  - ]:           2 :                         else if (romlen==0x200000 || romlen==0x300000)
     322                 :             :                         {
     323                 :           2 :                                 romlen=0x400000;
     324                 :           2 :                                 writeromdata_byte(snestopc(0x00FFD7), 0x0C);
     325                 :             :                         }
     326                 :           0 :                         else return -1;
     327                 :          15 :                         autoexpand=false;
     328                 :          30 :                         goto rebootlorom;
     329                 :             :                 }
     330                 :             :         }
     331         [ -  + ]:           4 :         if (mapper==hirom)
     332                 :             :         {
     333   [ #  #  #  # ]:           0 :                 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
     334         [ #  # ]:           0 :                 if (isforcode)
     335                 :             :                 {
     336         [ #  # ]:           0 :                         for(int i = 0x8000; i < min(romlen, 0x400000); i += 0x10000){
     337   [ #  #  #  # ]:           0 :                                 int space = trypcfreespace(i, min(i+0x7FFF, romlen), size, 0x7FFF, align?0xFFFF:0, freespacebyte, write_rats);
     338         [ #  # ]:           0 :                                 if(space != -1) return space;
     339                 :             :                         }
     340                 :           0 :                         return -1;
     341                 :             :                 }
     342   [ #  #  #  # ]:           0 :                 return trypcfreespace(0, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte, write_rats);
     343                 :             :         }
     344         [ -  + ]:           4 :         if (mapper==exlorom)
     345                 :             :         {
     346   [ #  #  #  # ]:           0 :                 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         [ #  # ]:           0 :                 if (isforcode)
     350                 :             :                 {
     351   [ #  #  #  # ]:           0 :                         trypcfreespace(0, min(romlen, 0x200000), size, 0x7FFF, align?0x7FFF:0, freespacebyte, write_rats);
     352                 :             :                 }
     353   [ #  #  #  # ]:           0 :                 return trypcfreespace(0, romlen, size, 0x7FFF, align ? 0x7FFF : 0, freespacebyte, write_rats);
     354                 :             :         }
     355         [ -  + ]:           4 :         if (mapper==exhirom)
     356                 :             :         {
     357   [ #  #  #  # ]:           0 :                 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
     358         [ #  # ]:           0 :                 if (isforcode)
     359                 :             :                 {
     360   [ #  #  #  # ]:           0 :                         for(int i = 0x8000; i < romlen && i < 0x400000; i += 0x10000){
     361   [ #  #  #  # ]:           0 :                                 int space = trypcfreespace(i, min(i+0x7FFF, romlen), size, 0x7FFF, align?0xFFFF:0, freespacebyte, write_rats);
     362         [ #  # ]:           0 :                                 if(space != -1) return space;
     363                 :             :                         }
     364                 :           0 :                         return -1;
     365                 :             :                 }
     366   [ #  #  #  # ]:           0 :                 return trypcfreespace(0, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte, write_rats);
     367                 :             :         }
     368         [ +  + ]:           4 :         if (mapper==sfxrom)
     369                 :             :         {
     370   [ -  +  -  - ]:           2 :                 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
     371         [ -  + ]:           2 :                 if (!isforcode) return -1;
     372                 :             :                 // try not to overwrite smw stuff
     373   [ +  +  +  - ]:           3 :                 return trypcfreespace(0x80000, romlen, size, 0x7FFF, align?0x7FFF:0, freespacebyte, write_rats);
     374                 :             :         }
     375         [ +  - ]:           2 :         if (mapper==sa1rom)
     376                 :             :         {
     377   [ +  +  -  - ]:           2 :                 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
     378                 :           2 :         rebootsa1rom:
     379                 :           2 :                 int nextbank=-1;
     380         [ +  + ]:          20 :                 for (int i=0;i<8;i++)
     381                 :             :                 {
     382         [ +  + ]:          18 :                         if (i&2) continue;
     383         [ +  + ]:          10 :                         if (sa1banks[i]+0x100000>romlen)
     384                 :             :                         {
     385   [ +  +  +  - ]:           8 :                                 if (sa1banks[i]<=romlen && sa1banks[i]+0x100000>romlen) nextbank=sa1banks[i];
     386                 :           8 :                                 continue;
     387                 :             :                         }
     388   [ +  +  -  +  :           3 :                         int pos=trypcfreespace(sa1banks[i]?sa1banks[i]:0x80000, sa1banks[i]+0x100000, size, 0x7FFF, align?0x7FFF:0, freespacebyte, write_rats);
                   +  - ]
     389         [ +  - ]:           2 :                         if (pos>=0) return pos;
     390                 :             :                 }
     391   [ +  -  +  - ]:           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                 :           2 :                         writeromdata_byte(0x7FD7, x7FD7[romlen>>20]);
     396                 :           1 :                         autoexpand=false;
     397                 :           2 :                         goto rebootsa1rom;
     398                 :             :                 }
     399                 :             :         }
     400         [ #  # ]:           0 :         if (mapper==bigsa1rom)
     401                 :             :         {
     402   [ #  #  #  # ]:           0 :                 if(target_bank >= 0) return find_for_fixed_bank(0xffff);
     403   [ #  #  #  # ]:           0 :                 if(!isforcode && romlen > 0x400000)
     404                 :             :                 {
     405   [ #  #  #  # ]:           0 :                         int pos=trypcfreespace(0x400000, romlen, size, 0xFFFF, align?0xFFFF:0, freespacebyte, write_rats);
     406         [ #  # ]:           0 :                         if(pos>=0) return pos;
     407                 :             :                 }
     408   [ #  #  #  # ]:           0 :                 int pos=trypcfreespace(0x080000, romlen, size, 0x7FFF, align?0x7FFF:0, freespacebyte, write_rats);
     409         [ #  # ]:           0 :                 if(pos>=0) return pos;
     410                 :             :         }
     411                 :           0 :         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         [ +  + ]:          14 :         if (strncmp((const char*)romdata+pcoff-8, "STAR", 4)) return;
     418                 :          14 :         const unsigned char * metadata=romdata+pcoff;
     419   [ +  +  +  -  :          20 :         while (is_upper(metadata[0]) && is_upper(metadata[1]) && is_upper(metadata[2]) && is_upper(metadata[3]))
          +  -  +  -  +  
                      + ]
     420                 :             :         {
     421         [ +  + ]:          10 :                 if (!strncmp((const char*)metadata, "STOP", 4))
     422                 :             :                 {
     423                 :           2 :                         metadata=romdata+pcoff;
     424   [ +  -  +  -  :          10 :                         while (is_upper(metadata[0]) && is_upper(metadata[1]) && is_upper(metadata[2]) && is_upper(metadata[3]))
          +  -  +  -  +  
                      - ]
     425                 :             :                         {
     426         [ +  + ]:          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         [ -  + ]:         230 :         if (thisfile == InvalidFileHandle)
     449                 :             :         {
     450                 :           0 :                 openromerror = error_id_open_rom_failed;
     451                 :           0 :                 return false;
     452                 :             :         }
     453                 :         230 :         header=false;
     454         [ +  - ]:         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         [ -  + ]:         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         [ -  + ]:         230 :         if (truelen!=romlen)
     465                 :             :         {
     466                 :           0 :                 openromerror = error_id_open_rom_failed;
     467                 :           0 :                 free(const_cast<unsigned char*>(romdata));
     468                 :           0 :                 return false;
     469                 :             :         }
     470                 :         230 :         memset(const_cast<unsigned char*>(romdata)+romlen, 0x00, (size_t)(16*1024*1024-romlen));
     471   [ -  +  -  -  :         230 :         if (confirm && snestopc(0x00FFC0)+21<(int)romlen && strncmp((const char*)romdata+snestopc(0x00FFC0), "SUPER MARIOWORLD     ", 21))
             -  -  -  + ]
     472                 :             :         {
     473                 :           0 :                 closerom(false);
     474         [ #  # ]:           0 :                 openromerror = header ? error_id_open_rom_not_smw_extension : error_id_open_rom_not_smw_header;
     475                 :           0 :                 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   [ +  +  +  +  :         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         [ -  + ]:         156 :                         if (header)
     497                 :             :                         {
     498                 :           0 :                                 set_file_pos(thisfile, 0u);
     499                 :           0 :                                 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         [ +  + ]:         460 :         if (thisfile != InvalidFileHandle) close_file(thisfile);
     507         [ +  + ]:         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         [ +  + ]:         222 :         if((romlen & (romlen-1)) == 0)
     519                 :             :         {
     520                 :             :                 // romlen is a power of 2, just add up all the bytes
     521         [ +  + ]:    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         [ +  + ]:    16849600 :                 for(int i = 0; i < firstpart; i++) checksum += romdata[i];
     532         [ +  + ]:    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 : }
        

Generated by: LCOV version 2.0-1