PSFTags PSFLoader::LoadInternal(uint8 version, uint32 max_exe_size, MDFNFILE *fp, uint32 level, bool force_ignore_pcsp)
{
 uint32 reserved_size, compressed_size, compressed_crc32;
 bool _lib_present = false;
 PSFTags tags;

 std::vector<uint8> decompress_buffer;
 uLongf decompress_len;

 if(!TestMagic(version, fp))
  throw(MDFN_Error(0, _("Not a PSF(version=0x%02x) file!"), version));

 reserved_size = MDFN_de32lsb(fp->data + 4);
 compressed_size = MDFN_de32lsb(fp->data + 8);
 compressed_crc32 = MDFN_de32lsb(fp->data + 12);

 if(fp->size < (16 + reserved_size + compressed_size))
  throw(MDFN_Error(0, _("PSF is missing at least %u bytes of data!"), 16 + reserved_size + compressed_size - fp->size));

 if(crc32(0, fp->data + 16 + reserved_size, compressed_size) != compressed_crc32)
  throw(MDFN_Error(0, _("PSF compressed CRC32 mismatch(data is corrupt)!")));


 {
  const uint8 *tag_section = fp->data + 16 + reserved_size + compressed_size;
  uint32 tag_section_size = fp->size - 16 - reserved_size - compressed_size;

  if(tag_section_size > 5 && !memcmp(tag_section, "[TAG]", 5))
   tags.LoadTags(tag_section + 5, tag_section_size - 5);
 }

 //
 // Handle minipsf simple _lib
 //

 if(level < 15)
 {
  if(tags.TagExists("_lib"))
  {
   std::string tp = tags.GetTag("_lib");

   if(!MDFN_IsFIROPSafe(tp))
   {
    throw(MDFN_Error(0, _("Referenced path \"%s\" is potentially unsafe.  See \"filesys.untrusted_fip_check\" setting."), tp.c_str()));
   }

   MDFNFILE subfile(MDFN_MakeFName(MDFNMKF_AUX, 0, tp.c_str()).c_str(), NULL, NULL);

   LoadInternal(version, max_exe_size, &subfile, level + 1);

   _lib_present = true;
  }
 }

 //
 //
 //

 decompress_buffer.resize(max_exe_size);
 decompress_len = max_exe_size;
 switch( uncompress((Bytef *)&decompress_buffer[0], &decompress_len, (const Bytef *)(fp->data + 16 + reserved_size), compressed_size) )
 {
  default:
	throw(MDFN_Error(0, "zlib unknown error"));

  case Z_OK: break;

  case Z_MEM_ERROR:
	throw(MDFN_Error(0, "zlib Z_MEM_ERROR"));

  case Z_BUF_ERROR:
	throw(MDFN_Error(0, _("PSF decompressed size exceeds maximum allowed!")));

  case Z_DATA_ERROR:
	throw(MDFN_Error(0, _("PSF compressed data is bad.")));
 }

 HandleReserved(fp->data + 16, reserved_size);
 HandleEXE(&decompress_buffer[0], decompress_len, force_ignore_pcsp | _lib_present);
 decompress_buffer.resize(0);

 //
 // handle libN
 //
 if(level < 15)
 {
  for(unsigned int n = 2; n <= INT_MAX; n++)
  {
   char tmpbuf[32];

   trio_snprintf(tmpbuf, 32, "_lib%d", (int)n);

   if(tags.TagExists(tmpbuf))
   {
    MDFNFILE subfile(MDFN_MakeFName(MDFNMKF_AUX, 0, tags.GetTag(tmpbuf).c_str()).c_str(), NULL, NULL);

    LoadInternal(version, max_exe_size, &subfile, level + 1, true);
   }
   else
    break;   
  }
 }

 return(tags);
}
Beispiel #2
0
SPCReader::SPCReader(Stream* fp)
{
#if 0
 reg_pc = 0x430;
 reg_a = 0;
 reg_x = 0;
 reg_y = 0;
 reg_psw = 0;
 reg_sp = 0xFF;

 memset(apuram, 0x00, sizeof(apuram));
 memset(dspregs, 0x00, sizeof(dspregs));
 dspregs[0x6C] = 0xE0;

 fp->read(&apuram[0x400], 0x1000);
 return;
#endif

 if(!TestMagic(fp))
  throw MDFN_Error(0, _("Not a valid SPC file!"));

 uint8 header[0x100];

 fp->rewind();
 fp->read(header, sizeof(header));

 reg_pc = MDFN_de16lsb(&header[0x25]);
 reg_a = header[0x27];
 reg_x = header[0x28];
 reg_y = header[0x29];
 reg_psw = header[0x2A];
 reg_sp = header[0x2B];

 fp->read(apuram, 65536);
 fp->read(dspregs, 0x80);
 fp->seek(0x101C0, SEEK_SET);
 fp->read(apuram + 0xFFC0, 0x40);

 if(header[0x23] == 0x1A)
 {
  bool binary_tags = true;

  if(header[0xA0] == '/' && header[0xA3] == '/')
   binary_tags = false;

  if(header[0xD2] >= '0' && header[0xD2] <= '9' && header[0xD3] == 0x00)
   binary_tags = false;

  fp->seek(0x2E, SEEK_SET);

  song_name = GrabString(fp, 32);
  game_name = GrabString(fp, 32);

  fp->seek(binary_tags ? 0xB0 : 0xB1, SEEK_SET);
  artist_name = GrabString(fp, 32);
 }

 //
 //
 //
#if 0
 fp->seek(0x10200, SEEK_SET);
 uint8 xid_header[8];

 if(fp->read(xid_header, sizeof(xid_header), false) == sizeof(xid_header) && !memcmp(xid_header, "xid6", 4))
 {
  uint8 sub_header[4];

  while(fp->read(sub_header, sizeof(sub_header), false) == sizeof(sub_header))
  {
   const uint8 id = sub_header[0];
   const uint8 type = sub_header[1];
   uint16 len = MDFN_de16lsb(&sub_header[2]);

   printf("ID: 0x%02x, Type: 0x%02x, Len: 0x%04x\n", id, type, len);

   if(type == 1 && len > 4)
    len = (len + 3) &~ 3;

   switch(id)
   {
    default:
	if(type)
	 fp->seek(len, SEEK_CUR);
	break;
 
    case 0x01: song_name = GrabString(fp, len); break;
    case 0x02: game_name = GrabString(fp, len); break;
    case 0x03: artist_name = GrabString(fp, len); break;
   }
  }
 }
#endif
}