158 lines
4.3 KiB
C++
158 lines
4.3 KiB
C++
#include "stdafx.h"
|
|
#include "StudyBoxLoader.h"
|
|
#include "RomData.h"
|
|
#include "MapperFactory.h"
|
|
#include "../Utilities/FolderUtilities.h"
|
|
#include "../Utilities/HexUtilities.h"
|
|
|
|
uint32_t StudyBoxLoader::ReadInt(uint8_t*& data)
|
|
{
|
|
uint32_t val = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
|
data += 4;
|
|
return val;
|
|
}
|
|
|
|
string StudyBoxLoader::ReadFourCC(uint8_t*& data)
|
|
{
|
|
stringstream ss;
|
|
for(int i = 0; i < 4; i++) {
|
|
ss << (char)data[i];
|
|
}
|
|
data += 4;
|
|
return ss.str();
|
|
}
|
|
|
|
vector<uint8_t> StudyBoxLoader::ReadArray(uint8_t*& data, uint32_t length)
|
|
{
|
|
vector<uint8_t> out;
|
|
out.resize(length);
|
|
memcpy(out.data(), data, length);
|
|
data += length;
|
|
return out;
|
|
}
|
|
|
|
bool StudyBoxLoader::LoadStudyBoxTape(vector<uint8_t> studyBoxFile, StudyBoxData& studyBoxData)
|
|
{
|
|
uint8_t* data = studyBoxFile.data();
|
|
uint8_t* end = data + studyBoxFile.size();
|
|
|
|
if(end - data < 16) {
|
|
//File too small to parse
|
|
Log("[Study Box] File is too small to parse");
|
|
return false;
|
|
}
|
|
|
|
if(ReadFourCC(data) != "STBX") {
|
|
//Invalid file!
|
|
Log("[Study Box] Invalid studybox file");
|
|
return false;
|
|
}
|
|
|
|
uint32_t size = ReadInt(data);
|
|
if(size != 4) {
|
|
//Should be 4 bytes, with only a version field
|
|
Log("[Study Box] Unexpected length value");
|
|
return false;
|
|
}
|
|
|
|
uint32_t version = ReadInt(data);
|
|
if(version != 0x100) {
|
|
//Unsupported version
|
|
Log("[Study Box] Unsupported version: " + std::to_string(version));
|
|
return false;
|
|
}
|
|
|
|
uint32_t prevAudioOffset = 0;
|
|
uint32_t prevLeadInOffset = 0;
|
|
while(data < end - 4) {
|
|
string cc = ReadFourCC(data);
|
|
|
|
if(cc == "PAGE") {
|
|
uint32_t pageSize = ReadInt(data);
|
|
uint32_t leadInOffset = ReadInt(data);
|
|
uint32_t audioOffset = ReadInt(data);
|
|
|
|
if(audioOffset < leadInOffset) {
|
|
//Invalid file, lead in must start before the track
|
|
Log("[Study Box] Track lead in must start before the first bit of data");
|
|
return false;
|
|
}
|
|
|
|
if(audioOffset < prevAudioOffset || leadInOffset < prevLeadInOffset) {
|
|
//Invalid file, page chunks must be in the order found on the tape
|
|
Log("[Study Box] PAGE chunks must be in the order found on the audio tape");
|
|
return false;
|
|
}
|
|
|
|
prevAudioOffset = audioOffset;
|
|
prevLeadInOffset = leadInOffset;
|
|
|
|
if((end - data) >= pageSize - 8) {
|
|
vector<uint8_t> pageData = ReadArray(data, pageSize - 8);
|
|
studyBoxData.Pages.push_back({ leadInOffset, audioOffset, pageData });
|
|
} else {
|
|
//Invalid size value
|
|
Log("[Study Box] Invalid size value for PAGE chunk");
|
|
return false;
|
|
}
|
|
} else if(cc == "AUDI") {
|
|
uint32_t size = ReadInt(data);
|
|
uint32_t fileType = ReadInt(data);
|
|
if(fileType == 0) {
|
|
if((end - data) >= size - 4) {
|
|
studyBoxData.AudioFile = ReadArray(data, size - 4);
|
|
//AUDI chunk should be the last in the file
|
|
break;
|
|
} else {
|
|
Log("[Study Box] Invalid size value for AUDI chunk");
|
|
return false;
|
|
}
|
|
} else {
|
|
//Unsupported audio type
|
|
Log("[Study Box] Unsupported audio type: " + std::to_string(fileType));
|
|
return false;
|
|
}
|
|
} else {
|
|
//Unsupported tag
|
|
Log("[Study Box] Unsupported tag");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return studyBoxData.Pages.size() > 0;
|
|
}
|
|
|
|
vector<uint8_t> StudyBoxLoader::LoadBios()
|
|
{
|
|
vector<uint8_t> biosData;
|
|
ifstream biosFile(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "StudyBox.bin"), ios::in | ios::binary);
|
|
if(biosFile) {
|
|
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
|
|
}
|
|
return {};
|
|
}
|
|
|
|
void StudyBoxLoader::LoadRom(RomData& romData, vector<uint8_t>& romFile, string filepath)
|
|
{
|
|
romData.Info.Hash.PrgCrc32 = romData.Info.Hash.Crc32;
|
|
|
|
//Cheat for SHA1 hash (repeat crc32 5 times) - this is to avoid the performance penalty of running SHA1 on a large file
|
|
string crc32String = HexUtilities::ToHex(romData.Info.Hash.Crc32);
|
|
romData.Info.Hash.Sha1 = crc32String + crc32String + crc32String + crc32String + crc32String;
|
|
|
|
romData.Info.Format = RomFormat::StudyBox;
|
|
romData.Info.MapperID = MapperFactory::StudyBoxMapperID;
|
|
romData.Info.Mirroring = MirroringType::Vertical;
|
|
romData.PrgRom = LoadBios();
|
|
romData.Info.System = GameSystem::Famicom;
|
|
|
|
if(romData.PrgRom.size() != 0x40000) {
|
|
romData.Error = true;
|
|
romData.BiosMissing = true;
|
|
} else {
|
|
romData.StudyBox.FileName = filepath;
|
|
if(!LoadStudyBoxTape(romFile, romData.StudyBox)) {
|
|
romData.Error = true;
|
|
}
|
|
}
|
|
}
|