Dolphin Bootable ISO working!

This commit is contained in:
2026-05-07 17:38:41 -05:00
parent 2cea43dc70
commit 65ca5ae4c4
3 changed files with 170 additions and 194 deletions
+69 -32
View File
@@ -9,49 +9,86 @@
#include "asset/asset.h"
#include "util/string.h"
#include "util/memory.h"
#include "util/endian.h"
#define ISO_SECTOR_SIZE 2048u
#define ISO_PVD_SECTOR 16u
errorret_t assetInitDolphinDVD(void) {
DVD_Init();
DVD_Mount();
// Read disc header to find FST location
u8 *hdr = (u8 *)assetDolphinDVDRead(0, 0x440);
if(!hdr) errorThrow("Failed to read DVD disc header.");
u32 fstOff = assetDolphinDVDReadBigEndian32(hdr + 0x424);
u32 fstSize = assetDolphinDVDReadBigEndian32(hdr + 0x428);
memoryFree(hdr);
// ISO 9660 Primary Volume Descriptor is at sector 16.
u8 *pvd = (u8 *)assetDolphinDVDRead(
(s64)ISO_PVD_SECTOR * ISO_SECTOR_SIZE, ISO_SECTOR_SIZE
);
if(!pvd) errorThrow("Failed to read ISO 9660 PVD.");
// Read the FST
u8 *fst = (u8 *)assetDolphinDVDRead((s64)fstOff, fstSize);
if(!fst) errorThrow("Failed to read DVD FST.");
// Root entry (index 0) bytes 8-11 = total entry count
u32 numEntries = assetDolphinDVDReadBigEndian32(fst + 8);
u8 *strTable = fst + numEntries * 12u;
u32 fileOff = 0, fileLen = 0;
for(u32 i = 1; i < numEntries; i++) {
u8 *e = fst + i * 12u;
if(e[0] != 0) continue;
u32 nameOff = ((u32)e[1] << 16) | ((u32)e[2] << 8) | (u32)e[3];
const char_t *name = (const char_t *)(strTable + nameOff);
if(stringCompareInsensitive(name, ASSET_FILE_NAME) == 0) {
fileOff = assetDolphinDVDReadBigEndian32(e + 4);
fileLen = assetDolphinDVDReadBigEndian32(e + 8);
break;
}
// Sanity-check: type=1, identifier="CD001"
if(pvd[0] != 1 || pvd[1] != 'C' || pvd[2] != 'D' ||
pvd[3] != '0' || pvd[4] != '0' || pvd[5] != '1') {
memoryFree(pvd);
errorThrow("Not a valid ISO 9660 disc.");
}
memoryFree(fst);
if(!fileOff) errorThrow("Failed to find asset file on DVD.");
// Root Directory Record starts at PVD+156.
// ISO 9660 stores multi-byte fields in both byte orders; use the BE copies
// (offset +6 for LBA, +14 for size) since the GameCube is big-endian.
u32 rootLBA = assetDolphinDVDReadBigEndian32(pvd + 156 + 6);
u32 rootSize = assetDolphinDVDReadBigEndian32(pvd + 156 + 14);
memoryFree(pvd);
u8 *data = (u8 *)assetDolphinDVDRead((s64)fileOff, fileLen);
if(!data) errorThrow("Failed to read asset file from DVD.");
u8 *dir = (u8 *)assetDolphinDVDRead(
(s64)rootLBA * ISO_SECTOR_SIZE, rootSize
);
if(!dir) errorThrow("Failed to read ISO 9660 root directory.");
// Scan directory records for dusk.dsk.
// ISO 9660 level-1 names are uppercase with a ";1" version suffix, e.g.
// "DUSK.DSK;1". We strip the suffix before comparing case-insensitively.
u32 fileLBA = 0, fileSize = 0;
u32 pos = 0;
while(pos < rootSize) {
u8 recLen = dir[pos];
if(recLen == 0) {
// Sector padding — skip to the start of the next sector.
pos = (pos + (ISO_SECTOR_SIZE - 1u)) & ~(ISO_SECTOR_SIZE - 1u);
continue;
}
u8 flags = dir[pos + 25];
u8 nameLen = dir[pos + 32];
if(!(flags & 0x02) && nameLen > 1) { // skip directories and "." / ".."
const char_t *isoName = (const char_t *)(dir + pos + 33);
// Build a null-terminated copy of the base name (strip ";N" version).
char_t baseName[32];
u8 baseLen = 0;
while(baseLen < nameLen && isoName[baseLen] != ';' && baseLen < 31) {
baseName[baseLen] = isoName[baseLen];
baseLen++;
}
baseName[baseLen] = '\0';
if(stringCompareInsensitive(baseName, ASSET_FILE_NAME) == 0) {
fileLBA = assetDolphinDVDReadBigEndian32(dir + pos + 6);
fileSize = assetDolphinDVDReadBigEndian32(dir + pos + 14);
break;
}
}
pos += recLen;
}
memoryFree(dir);
if(!fileLBA) errorThrow("Failed to find asset file on ISO.");
u8 *data = (u8 *)assetDolphinDVDRead(
(s64)fileLBA * ISO_SECTOR_SIZE, fileSize
);
if(!data) errorThrow("Failed to read asset file from ISO.");
zip_error_t zerr;
zip_source_t *src = zip_source_buffer_create(data, fileLen, 1, &zerr);
zip_source_t *src = zip_source_buffer_create(data, fileSize, 1, &zerr);
if(!src) {
memoryFree(data);
errorThrow("Failed to create zip source from DVD buffer.");