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); }
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 }