Esempio n. 1
0
//--------------------------------------------------------------------------
int get_aout_file_format_index(linput_t *li)
{
  exec ex;
  register int i = 0;
  if(qlread(li, &ex, sizeof(ex)) != sizeof(ex)) return false;

  if(N_BADMAG(ex)) {
    ex.a_info = swap32(ex.a_info);
    switch(N_MACHTYPE(ex)) {
      case M_386_NETBSD:
      case M_68K_NETBSD:
      case M_68K4K_NETBSD:
      case M_532_NETBSD:
      case M_SPARC_NETBSD:
      case M_PMAX_NETBSD:
      case M_VAX_NETBSD:
      case M_ALPHA_NETBSD:
      case M_ARM6_NETBSD:
        break;

      default:
        return false;
    }
  }

  switch(N_MAGIC(ex)) {
    case NMAGIC:
      ++i;
    case CMAGIC:
      ++i;
    case ZMAGIC:
      ++i;
    case OMAGIC:
      ++i;
    case QMAGIC:
//      msg("text=%d data=%d symsize=%d txtoff=%d sum=%d\n", ex.a_text, ex.a_data,
//                N_SYMSIZE(ex), N_TXTOFF(ex), ex.a_text + ex.a_data + N_SYMSIZE(ex) + N_TXTOFF(ex));
      if ( qlsize(li) >= ex.a_text + ex.a_data + N_SYMSIZE(ex) + N_TXTOFF(ex) )
        break;
      if ( N_MAGIC(ex) == ZMAGIC
        && qlsize(li) >= ex.a_text + ex.a_data + N_SYMSIZE(ex) )
      {
        i = 5; // OpenBSD demand-paged
        break;
      }
    default:
      return false;
  }

  return i+1;
}
Esempio n. 2
0
static int copy_to_remote(const char *lname, const char *rname)
{
  int code = 0;
  int fn = s_open_file(rname, NULL, false);
  if ( fn != -1 )
  {
    linput_t *li = open_linput(lname, false);
    if ( li != NULL )
    {
      size_t size = qlsize(li);
      if ( size > 0 )
      {
        char *buf = (char *)qalloc(size);
        qlread(li, buf, size);
        if ( s_write_file(fn, 0, buf, size) != ssize_t(size) )
          code = qerrcode();
      }
      close_linput(li);
    }
    else
    {
      code = qerrcode();
    }
    s_close_file(fn);
#if DEBUGGER_ID == DEBUGGER_ID_X86_IA32_LINUX_USER
    // chmod +x
    s_ioctl(0, rname, strlen(rname)+1, NULL, 0);
#endif
  }
  else
  {
    code = qerrcode();
  }
  return code;
}
Esempio n. 3
0
//-------------------------------------------------------------------------
// Since the Palm Pilot programs are really poorly recognized by usual
// methods, we are forced to read the resource tablee to determine
// if everying is ok
//return 0 if not a PRC, 2 if has ARM code segments, 1 otherwise
int is_prc_file(linput_t *li)
{
  DatabaseHdrType h;
  if ( qlread(li,&h,sizeof(h)) != sizeof(h) ) return 0;
  swap_prc(h);
  if ( (h.attributes & dmHdrAttrResDB) == 0 ) return 0;
  if ( short(h.numRecords) <= 0 ) return 0;
  const uint32 filesize = qlsize(li);
  const uint32 lowestpos = h.numRecords*sizeof(ResourceMapEntry) + sizeof(h);
  if ( lowestpos > filesize ) return 0;

  // the dates can be plain wrong, so don't check them:
  //uint32 now = time(NULL);
  //&& uint32(h.lastBackupDate) <= now    // use unsigned comparition!
  //&& uint32(h.creationDate) <= now      // use unsigned comparition!
  //&& uint32(h.modificationDate) <= now  // use unsigned comparition!

  size_t size = sizeof(ResourceMapEntry) * h.numRecords;
  ResourceMapEntry *re = (ResourceMapEntry *)alloca(size);
  if ( re == NULL ) return 0;
  if ( qlread(li,re,size) != size ) return 0;
  bool hasArmCode = false;
  for ( int i=0; i < h.numRecords; i++ )
  {
    swap_resource_map_entry(re[i]);
    if ( re[i].ulOffset >= filesize || re[i].ulOffset < lowestpos )
      return 0;
    if ( re[i].fcType == PILOT_RSC_ARMC || re[i].fcType == PILOT_RSC_ARMCL )
      hasArmCode = true;
  }
  return hasArmCode ? 2 : 1;
}
Esempio n. 4
0
bool load_header(linput_t *li)
{
	int headerversion;
	int size;

	qlseek(li, 3);
	if (qlread(li, &yssEndian, 1) != 1)
	{
		error("Truncated file");
		return false;
	}

	qlread(li, &headerversion, 4);
	qlread(li, &size, 4);
	int headersize=0xC;
	if (headerversion == 2)
	{
		qlseek(li, 8, SEEK_CUR);
		headersize+=8;
	}

	// Make sure size variable matches actual size minus header
	if (size != (qlsize(li) - headersize))
	{
		error("Header size isn't valid");
		return false;
	}

	return true;
}
Esempio n. 5
0
//----------------------------------------------------------------------------
int idaapi accept_file(
        linput_t *li,
        char fileformatname[MAX_FILE_FORMAT_NAME],
        int n)
{
  if ( n > 0 )
    return 0;

  int32 spc_file_size = qlsize(li);
  if ( spc_file_size < 0x10200 )
    return 0;

  spc_file_t spc_info;
  if ( qlseek(li, 0) != 0 )
    return 0;
  if ( qlread(li, &spc_info, sizeof(spc_file_t)) != sizeof(spc_file_t) )
    return 0;

  if (memcmp(spc_info.signature, "SNES-SPC700 Sound File Data", 27) != 0
    || spc_info.signature[0x21] != 0x1a || spc_info.signature[0x22] != 0x1a)
    return 0;

  qstrncpy(fileformatname, "SNES-SPC700 Sound File Data", MAX_FILE_FORMAT_NAME);
  return 1;
}
Esempio n. 6
0
//----------------------------------------------------------------------
//
//      check input file format. if recognized, then return 1
//      and fill 'fileformatname'.
//      otherwise return 0
//
int accept_file(linput_t *li, char fileformatname[MAX_FILE_FORMAT_NAME], int n)
{
	if( n!= 0 )
		return 0;

	// quit if file is smaller than size of iNes header
	if (qlsize(li) < sizeof(ines_hdr))
		return 0;

	// set filepos to offset 0
	qlseek(li, 0, SEEK_SET);

	// read NES header
	if(qlread(li, &hdr, INES_HDR_SIZE) != INES_HDR_SIZE)
		return 0;

	// is it a valid ROM image in iNes format?
	if( memcmp("NES", &hdr.id, sizeof(hdr.id)) != 0 || hdr.term != 0x1A )
		return 0;

	// this is the name of the file format which will be
	// displayed in IDA's dialog
	qstrncpy(fileformatname, "Nintendo Entertainment System ROM", MAX_FILE_FORMAT_NAME);

	// set processor to 6502
	if ( ph.id != PLFM_6502 )
	{
		msg("Nintendo Entertainment System ROM detected: setting processor type to M6502.\n");
		set_processor_type("M6502", SETPROC_ALL|SETPROC_FATAL);
	}


	return (1 | ACCEPT_FIRST);
}
Esempio n. 7
0
//-----------------------------------------------------------------------
bool is_intelomf_file(linput_t *li)
{
  uchar magic;
  lmh h;
  qlseek(li, 0);
  if ( qlread(li, &magic, sizeof(magic)) != sizeof(magic)
    || qlread(li, &h, sizeof(h)) != sizeof(h) ) return false;
  int fsize = qlsize(li);
  return magic == INTELOMF_MAGIC_BYTE
      && h.tot_length < fsize;
}
Esempio n. 8
0
//------------------------------------------------------------------------
// process all imports of a pe file
// returns: -1:could not read an impdir; 0-ok;
// other values can be returned by the visitor
inline int pe_loader_t::process_imports(linput_t *li, pe_import_visitor_t &piv)
{
    if ( pe.impdir.rva == 0 )
        return 0;

    if ( transvec.empty() )
        process_sections(li);

    int code = 0;
    bool is_memory_linput = get_linput_type(li) == LINPUT_PROCMEM;
    for ( int ni=0; ; ni++ )
    {
        off_t off = pe.impdir.rva + ni*sizeof(peimpdir_t);
        peimpdir_t &id = piv.id;

        if ( !vmread(li, off, &id, sizeof(id)) )
        {
            int code = piv.impdesc_error(off);
            if ( code != 0 )
                break;
            // we continue if the import descriptor is within the page belonging
            // to the program
            if ( !is_memory_linput )
            {
                uint32 fsize = pe.align_up_in_file(qlsize(li));
                if ( map_ea(off)+sizeof(id) > fsize )
                    return -1;
            }
        }
        if ( id.dllname == 0 && id.table1 == 0 )
            break;
        ea_t ltable = id.table1;  //OriginalFirstThunk
        ea_t atable = id.looktab; //FirstThunk
        bool ok = true;
        char dll[MAXSTR];
        asciiz(li, id.dllname, dll, sizeof(dll), &ok);
        if ( !ok || dll[0] == '\0' )
            break;
        ansi2idb(dll);
        if ( !is_memory_linput && (map_ea(ltable) == BADADDR || ltable < pe.hdrsize) )
            ltable = atable;
        atable += get_imagebase();
        int code = piv.visit_module(dll, atable, ltable);
        if ( code != 0 )
            break;
        code = process_import_table(li, pe, atable, ltable, piv);
        if ( code != 0 )
            break;
    }
    return code;
}
Esempio n. 9
0
//------------------------------------------------------------------------
inline int pe_loader_t::process_sections(linput_t *li, off_t first_sec_pos, int nobjs, pe_section_visitor_t &psv)
{
    transvec.qclear();
    qvector <pesection_t> sec_headers;
    // does the file layout match memory layout?
    bool alt_align = pe.objalign == pe.filealign && pe.objalign < PAGE_SIZE;
    for ( int i=0; i < nobjs; i++ )
    {
        pesection_t& sh = sec_headers.push_back();
        qlseek(li, first_sec_pos + i*sizeof(pesection_t));
        lread(li, &sh, sizeof(sh));
        if ( sh.s_vaddr != uint32(sh.s_scnptr)
                || sh.s_vsize > sh.s_psize )
            alt_align = false;
    }
    if ( alt_align )
        // according to Ivan Teblin from AVERT Labs, such files are
        // mapped by Windows as-is and not section by section
        // we mimic that behaviour
        psv.load_all();

    int off_align = alt_align ? pe.filealign : FILEALIGN;
    if ( pe.is_efi() )
        off_align = 1;

    for ( int i=0; i < nobjs; i++ )
    {
        pesection_t &sh = sec_headers[i];
        uint32 scnptr = align_down(sh.s_scnptr, off_align);//pe.align_down_in_file(sh.s_scnptr);
        transl_t &tr = transvec.push_back();
        tr.start = sh.s_vaddr;
        tr.psize = sh.get_psize(pe);
        tr.end   = pe.align_up_in_file(uint32(sh.s_vaddr + tr.psize));
        tr.pos   = scnptr;
        int code = psv.visit_section(sh, scnptr);
        if ( code != 0 )
            return code;
    }
    if ( nobjs == 0 )
    {
        // add mapping for the header
        transl_t &tr = transvec.push_back();
        tr.start = 0;
        tr.psize = qlsize(li);
        tr.end   = pe.align_up_in_file(pe.imagesize);
        tr.pos   = 0;
    }
    return 0;
}
Esempio n. 10
0
//--------------------------------------------------------------------------
bool macho_file_t::parse_fat_header()
{
  qlseek(li, start_offset);
  if ( qlread(li, &fheader, sizeof(fheader)) != sizeof(fheader) )
    return false;
  int code = (fheader.magic == FAT_MAGIC);
  if ( fheader.magic == FAT_CIGAM )
  {
    swap_fat_header(&fheader);
    code = 2;
  }
  if ( code == 0 || fheader.nfat_arch > 16 )
    return false;

  uint32 fsize = qlsize(li);
  uint32 archs_size = fheader.nfat_arch * sizeof(fat_arch);
  if ( sizeof(fat_header) + archs_size >= fsize )
    return false;

  fat_archs.resize(fheader.nfat_arch);

  if ( qlread(li, fat_archs.begin(), archs_size) != archs_size )
  {
    fat_archs.clear();
    return false;
  }

  for ( uint32_t i=0; i < fheader.nfat_arch; i++ )
  {
    fat_arch *parch = &fat_archs[i];
    if ( code == 2 )
      swap_fat_arch(parch);
    if ( parch->size <= sizeof(mach_header) ||
         parch->size >= fsize ||
         parch->offset < sizeof(fat_header) + archs_size ||
         parch->offset + parch->size > fsize )
    {
      fat_archs.clear();
      return false;
    }
  }
  return true;
}
Esempio n. 11
0
//--------------------------------------------------------------------------
// check and send to the remote server the specified stub
// do it only if its crc does not match the specified crc
// this function runs on the local machine with ida interface
static uchar *sync_stub(const char *fname, uint32 crc, size_t *psize)
{
  char path[QMAXPATH];
  bool told = false;
  if ( getsysfile(path, sizeof(path), fname, NULL) != NULL )
  {
    linput_t *li = open_linput(path, false);
    if ( li != NULL )
    {
      int32 size = qlsize(li);
      if ( size > 0 )
      {
        uchar *buf = qnewarray(uchar, size);
        if ( buf != NULL )
        {
          if ( qlread(li, buf, size) == size )
          {
            if ( calc_crc32(0, buf, size) != crc )
            {
              close_linput(li);
              *psize = size;
              return buf;
            }
            else
            {
              msg("Kernel debugger stub is up to date...\n");
              told = true;
              *psize = 1;       // signal ok
            }
          }
          qfree(buf);
        }
      }
      close_linput(li);
    }
  }
  if ( !told )
    warning("AUTOHIDE NONE\nCould not find/read debugger stub %s", fname);
  return NULL;
}
Esempio n. 12
0
//-----------------------------------------------------------------------------
// process a file record according to its "record_type".
// return true if there is no more records to process.
static bool process_record(linput_t *li, const uchar record_type, bool load) {
    bool finished = false;

    switch (record_type) {

        // A record with a header byte of $81 is a record that may contain code or
        // data from arbitrary segments.
        //
        // header      : 1 byte
        // segment     : 1 byte
        // gran        : 1 byte
        // start_addr  : 4 bytes (entry point)
        // length      : 2 bytes
        // data        : length bytes
        case 0x81:
            {
                mas_header_t header;
                memset(&header, 0, sizeof header);

                // read the header
                if (qlread(li, &header, sizeof header) != sizeof header)
                    mas_error("unable to read header (%d bytes)", sizeof header);

                // granularities that differ from 1 are rare and mostly appear
                // in DSP CPU's that are not designed for byte processing.
                if (header.gran != 1)
                    mas_error("unsupported granularity (%d)", header.gran);

                // set processor
                if (!mas_set_cpu(header.header))
                    mas_error("processor type '0x%X' is currently unsupported",
                        header.header);
                if (!load) // we have the processor, nothing else to do
                {
                  finished = true;
                  break;
                }

                // get segment name
                const char *segname = mas_get_segname(header.segment);
                if (segname == NULL)
                    mas_error("invalid segment '0x%X'", header.segment);

#if defined(DEBUG)
                msg("MAS: ready to read %d bytes (0x%X -> 0x%X)\n",
                    header.length, header.start_addr, header.start_addr + header.length);
#endif

                // send code in the database
                file2base(li, qltell(li), header.start_addr,
                    header.start_addr + header.length,
                    FILEREG_PATCHABLE);

                // set selector
                sel_t selector = allocate_selector(0);

                // create segment
                add_segm(selector, header.start_addr, header.start_addr + header.length,
                           segname, segname);
            }
            break;

        // The last record in a file bears the Header $00 and has only a string as
        // data field. This string does not have an explicit length specification;
        // its end is equal to the file's end.
        //
        // The string contains only the name of the program that created the file
        // and has no further meaning.
        //
        // creator     : x bytes
        case 0x00:
            {
                ulong length = qlsize(li) - qltell(li);
#if defined(DEBUG)
                msg("MAS: creator length : %ld bytes\n", length);
#endif
                if (length >= sizeof creator)
                    mas_error("creator length is too large (%ld >= %ld",
                        length, sizeof creator);
                int tmp;
                if ((tmp = qlread(li, creator, length)) != length)
                    mas_error("unable to read creator string (i read %d)", tmp);
                creator[tmp] = '\0';
            }
            finished = true;
            break;

        // entry_point : 4 bytes
        case 0x80:
            {
                if (qlread(li, &entry_point, 4) != 4)
                    mas_error("unable to read entry_point");
                if (load)
                {
#if defined(DEBUG)
                  msg("MAS: detected entry point : 0x%X\n", entry_point);
#endif
                  inf.startIP = entry_point;      // entry point
                  segment_t *s = getseg(entry_point);
                  inf.start_cs = s ? s->sel : 0;  // selector of code
                }
            }
            break;

        default:
            // start_addr  : 4 bytes
            // length      : 2 bytes
            // data        : length bytes
            if (record_type >= 0x01 && record_type <= 0x7F) {
                struct header {
                    int start_addr;
                    short length;
                } header;

                memset(&header, 0, sizeof header);

                // read the header
                if (qlread(li, &header, sizeof header) != sizeof header)
                    mas_error("unable to read header (%d bytes)", sizeof header);

                if (load)
                {
                  // send code in the database
                  file2base(li, qltell(li), header.start_addr,
                      header.start_addr + header.length,
                      FILEREG_PATCHABLE);

#if defined(DEBUG)
                  msg("MAS: i've read %d DATA bytes (0x%X -> 0x%X)\n",
                      header.length, header.start_addr, header.start_addr + header.length);
#endif

                  // set selector
                  sel_t selector = allocate_selector(0);

                  // create data segment
                  add_segm(selector, header.start_addr, header.start_addr + header.length,
                           "DATA", "DATA");
                }
                else
                  qlseek(li, qltell(li)+header.length);
            }
            else
                mas_error("invalid record type '0x%X'\n", record_type);
    }

    return finished;
}
Esempio n. 13
0
unsigned SuperFamicomCartridge::score_header(linput_t *li, unsigned addr) {
  int32 size = qlsize(li);
  if(size < 0x8000) return 0;

  //skip copier header
  uint32 start = 0;
  if((size & 0x7fff) == 512) start += 512, size -= 512;

  if((uint32)size < addr + 64) return 0;    //image too small to contain header at this location?
  int score = 0;

  uint8 header[64];
  qlseek(li, start + addr);
  qlread(li, header, 64);

  uint16 resetvector = header[ResetVector] | (header[ResetVector + 1] << 8);
  uint16 checksum    = header[Checksum   ] | (header[Checksum    + 1] << 8);
  uint16 complement  = header[Complement ] | (header[Complement  + 1] << 8);

  uint32 resetop_addr = (addr & ~0x7fff) | (resetvector & 0x7fff);
  if(qlseek(li, start + resetop_addr) != (start + resetop_addr)) return 0;
  uint8 resetop;
  if(qlread(li, &resetop, sizeof(uint8)) != sizeof(uint8)) return 0;    //first opcode executed upon reset

  uint8 mapper  = header[Mapper] & ~0x10;                               //mask off irrelevent FastROM-capable bit

  //$00:[000-7fff] contains uninitialized RAM and MMIO.
  //reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
  if(resetvector < 0x8000) return 0;

  //some images duplicate the header in multiple locations, and others have completely
  //invalid header information that cannot be relied upon.
  //below code will analyze the first opcode executed at the specified reset vector to
  //determine the probability that this is the correct header.

  //most likely opcodes
  if(resetop == 0x78  //sei
  || resetop == 0x18  //clc (clc; xce)
  || resetop == 0x38  //sec (sec; xce)
  || resetop == 0x9c  //stz $nnnn (stz $4200)
  || resetop == 0x4c  //jmp $nnnn
  || resetop == 0x5c  //jml $nnnnnn
  ) score += 8;

  //plausible opcodes
  if(resetop == 0xc2  //rep #$nn
  || resetop == 0xe2  //sep #$nn
  || resetop == 0xad  //lda $nnnn
  || resetop == 0xae  //ldx $nnnn
  || resetop == 0xac  //ldy $nnnn
  || resetop == 0xaf  //lda $nnnnnn
  || resetop == 0xa9  //lda #$nn
  || resetop == 0xa2  //ldx #$nn
  || resetop == 0xa0  //ldy #$nn
  || resetop == 0x20  //jsr $nnnn
  || resetop == 0x22  //jsl $nnnnnn
  ) score += 4;

  //implausible opcodes
  if(resetop == 0x40  //rti
  || resetop == 0x60  //rts
  || resetop == 0x6b  //rtl
  || resetop == 0xcd  //cmp $nnnn
  || resetop == 0xec  //cpx $nnnn
  || resetop == 0xcc  //cpy $nnnn
  ) score -= 4;

  //least likely opcodes
  if(resetop == 0x00  //brk #$nn
  || resetop == 0x02  //cop #$nn
  || resetop == 0xdb  //stp
  || resetop == 0x42  //wdm
  || resetop == 0xff  //sbc $nnnnnn,x
  ) score -= 8;

  //at times, both the header and reset vector's first opcode will match ...
  //fallback and rely on info validity in these cases to determine more likely header.

  //a valid checksum is the biggest indicator of a valid header.
  if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;

  if(addr == 0x007fc0 && mapper == 0x20) score += 2;  //0x20 is usually LoROM
  if(addr == 0x00ffc0 && mapper == 0x21) score += 2;  //0x21 is usually HiROM
  if(addr == 0x007fc0 && mapper == 0x22) score += 2;  //0x22 is usually ExLoROM
  if(addr == 0x40ffc0 && mapper == 0x25) score += 2;  //0x25 is usually ExHiROM

  if(header[Company] == 0x33) score += 2;             //0x33 indicates extended header
  if(header[RomType] < 0x08) score++;
  if(header[RomSize] < 0x10) score++;
  if(header[RamSize] < 0x08) score++;
  if(header[CartRegion] < 14) score++;

  if(score < 0) score = 0;
  return score;
}
Esempio n. 14
0
void SuperFamicomCartridge::read_header(linput_t *li) {
  int32 size = qlsize(li);
  if(size < 0) return;

  //skip copier header
  uint32 start = 0;
  has_copier_header = (size & 0x7fff) == 512;
  if(has_copier_header) start += 512, size -= 512;

  type        = TypeUnknown;
  mapper      = LoROM;
  dsp1_mapper = DSP1Unmapped;
  region      = NTSC;
  rom_size    = size;
  ram_size    = 0;

  has_bsx_slot   = false;
  has_superfx    = false;
  has_sa1        = false;
  has_sharprtc   = false;
  has_epsonrtc   = false;
  has_sdd1       = false;
  has_spc7110    = false;
  has_cx4        = false;
  has_dsp1       = false;
  has_dsp2       = false;
  has_dsp3       = false;
  has_dsp4       = false;
  has_obc1       = false;
  has_st010      = false;
  has_st011      = false;
  has_st018      = false;

  //=====================
  //detect Game Boy carts
  //=====================

  if(size >= 0x0140) {
    uint8 data[0x140];
    qlseek(li, start);
    qlread(li, data, 0x140);

    if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
    && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
      type = TypeGameBoy;
      return;
    }
  }

  if(size < 32768) {
    type = TypeUnknown;
    return;
  }

  const unsigned index = find_header(li);
  header_offset = index;

  uint8 extended_header[16 + 64];
  qlseek(li, start + index - 16);
  qlread(li, extended_header, 16 + 64);
  uint8 * header = &extended_header[16];

  const uint8 mapperid = header[Mapper];
  const uint8 rom_type = header[RomType];
  const uint8 lrom_size = header[RomSize];
  const uint8 company  = header[Company];
  const uint8 regionid = header[CartRegion] & 0x7f;

  ram_size = 1024 << (header[RamSize] & 7);
  if(ram_size == 1024) ram_size = 0;  //no RAM present
  if(lrom_size == 0 && ram_size) ram_size = 0;  //fix for Bazooka Blitzkrieg's malformed header (swapped ROM and RAM sizes)

  //0, 1, 13 = NTSC; 2 - 12 = PAL
  region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;

  //=======================
  //detect BS-X flash carts
  //=======================

  if(header[0x13] == 0x00 || header[0x13] == 0xff) {
    if(header[0x14] == 0x00) {
      const uint8 n15 = header[0x15];
      if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
        if(header[0x1a] == 0x33 || header[0x1a] == 0xff) {
          type = TypeBsx;
          mapper = BSXROM;
          region = NTSC;  //BS-X only released in Japan
          return;
        }
      }
    }
  }

  //=========================
  //detect Sufami Turbo carts
  //=========================

  uint8 data[32];
  qlseek(li, start);
  qlread(li, data, 32);

  if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
    if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
      type = TypeSufamiTurboBios;
    } else {
      type = TypeSufamiTurbo;
    }
    mapper = STROM;
    region = NTSC;  //Sufami Turbo only released in Japan
    return;         //RAM size handled outside this routine
  }

  //==========================
  //detect Super Game Boy BIOS
  //==========================

  if(!memcmp(header, "Super GAMEBOY2", 14)) {
    type = TypeSuperGameBoy2Bios;
    return;
  }

  if(!memcmp(header, "Super GAMEBOY", 13)) {
    type = TypeSuperGameBoy1Bios;
    return;
  }

  //=====================
  //detect standard carts
  //=====================

  //detect presence of BS-X flash cartridge connector (reads extended header information)
  if(header[-14] == 'Z') {
    if(header[-11] == 'J') {
      uint8 n13 = header[-13];
      if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
        if(company == 0x33 || (header[-10] == 0x00 && header[-4] == 0x00)) {
          has_bsx_slot = true;
        }
      }
    }
  }

  if(has_bsx_slot) {
    if(!memcmp(header, "Satellaview BS-X     ", 21)) {
      //BS-X base cart
      type = TypeBsxBios;
      mapper = BSXROM;
      region = NTSC;  //BS-X only released in Japan
      return;         //RAM size handled internally by load_cart_bsx() -> BSXCart class
    } else {
      type = TypeBsxSlotted;
      mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
      region = NTSC;  //BS-X slotted cartridges only released in Japan
    }
  } else {
    //standard cart
    type = TypeNormal;

    if(index == 0x7fc0 && size >= 0x401000) {
      mapper = ExLoROM;
    } else if(index == 0x7fc0 && mapperid == 0x32) {
      mapper = ExLoROM;
    } else if(index == 0x7fc0) {
      mapper = LoROM;
    } else if(index == 0xffc0) {
      mapper = HiROM;
    } else {  //index == 0x40ffc0
      mapper = ExHiROM;
    }
  }

  if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
    has_superfx = true;
    mapper = SuperFXROM;
    ram_size = 1024 << (header[-3] & 7);
    if(ram_size == 1024) ram_size = 0;
  }

  if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
    has_sa1 = true;
    mapper = SA1ROM;
  }

  if(mapperid == 0x35 && rom_type == 0x55) {
    has_sharprtc = true;
  }

  if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
    has_sdd1 = true;
  }

  if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
    has_spc7110 = true;
    has_epsonrtc = (rom_type == 0xf9);
    mapper = SPC7110ROM;
  }

  if(mapperid == 0x20 && rom_type == 0xf3) {
    has_cx4 = true;
  }

  if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
    has_dsp1 = true;
  }

  if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
    has_dsp1 = true;
  }

  if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
    has_dsp1 = true;
  }

  if(has_dsp1 == true) {
    if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
      dsp1_mapper = DSP1LoROM1MB;
    } else if((mapperid & 0x2f) == 0x20) {
      dsp1_mapper = DSP1LoROM2MB;
    } else if((mapperid & 0x2f) == 0x21) {
      dsp1_mapper = DSP1HiROM;
    }
  }

  if(mapperid == 0x20 && rom_type == 0x05) {
    has_dsp2 = true;
  }

  if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
    has_dsp3 = true;
  }

  if(mapperid == 0x30 && rom_type == 0x03) {
    has_dsp4 = true;
  }

  if(mapperid == 0x30 && rom_type == 0x25) {
    has_obc1 = true;
  }

  if(mapperid == 0x30 && rom_type == 0xf6 && lrom_size >= 10) {
    has_st010 = true;
  }

  if(mapperid == 0x30 && rom_type == 0xf6 && lrom_size < 10) {
    has_st011 = true;
  }

  if(mapperid == 0x30 && rom_type == 0xf5) {
    has_st018 = true;
  }
}
Esempio n. 15
0
SuperFamicomCartridge::SuperFamicomCartridge(linput_t *li) {
  int32 size = qlsize(li);
  if(size < 0) {
    loader_failure("Failed retrieving rom size.\n");
    return;
  }

  firmware_appended = false;

  //skip copier header
  if((size & 0x7fff) == 512) size -= 512;

  if(size < 0x8000) return;

  read_header(li);

  if(type == TypeGameBoy) return;
  if(type == TypeBsx) return;
  if(type == TypeSufamiTurbo) return;

  if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) {
    if((rom_size & 0x7fff) == 0x100) {
      firmware_appended = true;
      rom_size -= 0x100;
    }
  }

  else if(has_cx4) {
    if((rom_size & 0x7fff) == 0xc00) {
      firmware_appended = true;
      rom_size -= 0xc00;
    }
  }

  if(has_dsp1) {
    if((size & 0x7fff) == 0x2000) {
      firmware_appended = true;
      rom_size -= 0x2000;
    }
  }

  if(has_dsp2) {
    if((size & 0x7fff) == 0x2000) {
      firmware_appended = true;
      rom_size -= 0x2000;
    }
  }

  if(has_dsp3) {
    if((size & 0x7fff) == 0x2000) {
      firmware_appended = true;
      rom_size -= 0x2000;
    }
  }

  if(has_dsp4) {
    if((size & 0x7fff) == 0x2000) {
      firmware_appended = true;
      rom_size -= 0x2000;
    }
  }

  if(has_st010) {
    if((size & 0xffff) == 0xd000) {
      firmware_appended = true;
      rom_size -= 0xd000;
    }
  }

  if(has_st011) {
    if((size & 0xffff) == 0xd000) {
      firmware_appended = true;
      rom_size -= 0xd000;
    }
  }

  if(has_st018) {
    if((size & 0x3ffff) == 0x28000) {
      firmware_appended = true;
      rom_size -= 0x28000;
    }
  }
}