LCOV - code coverage report
Current view: top level - asar - libsmw.cpp (source / functions) Coverage Total Hit
Test: asar.info Lines: 75.2 % 226 170
Test Date: 2024-01-15 16:32:53 Functions: 88.2 % 17 15
Branches: 44.2 % 240 106

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

Generated by: LCOV version 2.0-1