Fix PSP asset loading: stale EBOOT.PBP packing, unreliable zip file reads
EBOOT.PBP packing was a POST_BUILD step with no dependency on the asset pak, so an assets-only rebuild could silently leave a stale dusk.dsk embedded. cmake/targets/psp.cmake now repacks EBOOT.PBP via a properly tracked custom command depending on the executable, PARAM.SFO, and dusk.dsk (and correctly embeds Dusk.prx rather than the raw ELF when BUILD_PRX is on). Separately, libzip's zip_source_filep_create (lazy seeked FILE* reads) proved unreliable on real PSP hardware, corrupting reads of the embedded PSAR (first EINVAL, then zlib data errors) even though the packaged data was verified byte-perfect. assetInitPBP now reads the whole PSAR into memory once and uses zip_source_buffer_create instead. Confirmed working on real hardware. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "asset/asset.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/math.h"
|
||||
|
||||
errorret_t assetInitPBP(const char_t *pbpPath) {
|
||||
assertNotNull(pbpPath, "PBP path cannot be null.");
|
||||
@@ -73,24 +74,49 @@ errorret_t assetInitPBP(const char_t *pbpPath) {
|
||||
errorThrow("Failed to seek to PSAR offset in PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
zip_uint64_t zipPsarOffset = (zip_uint64_t)(
|
||||
ASSET.platform.pbpHeader.psarOffset
|
||||
);
|
||||
zip_int64_t zipPsarSize = (zip_int64_t)(
|
||||
pbpSize - ASSET.platform.pbpHeader.psarOffset
|
||||
);
|
||||
size_t psarSize = pbpSize - ASSET.platform.pbpHeader.psarOffset;
|
||||
|
||||
zip_source_t *psarSource = zip_source_filep_create(
|
||||
ASSET.platform.pbpFile,
|
||||
zipPsarOffset,
|
||||
zipPsarSize,
|
||||
NULL
|
||||
// Read the whole PSAR (the embedded dusk.dsk zip archive) into memory up
|
||||
// front and hand libzip an in-memory buffer, instead of a lazily-seeked
|
||||
// FILE source: repeated seeked reads directly against the open PBP file
|
||||
// proved unreliable on PSP (zip_fread() failing with EINVAL, then with
|
||||
// zlib data corruption, depending on the read chunk size used). Reading
|
||||
// once, straight through, and letting libzip operate on memory from then
|
||||
// on avoids that read path entirely. psarSize is small (tens of KB) so
|
||||
// holding it fully in RAM is cheap.
|
||||
uint8_t *psarData = (uint8_t *)malloc(psarSize);
|
||||
if(psarData == NULL) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Failed to allocate PSAR buffer for file: %s", pbpPath);
|
||||
}
|
||||
|
||||
size_t totalRead = 0;
|
||||
while(totalRead < psarSize) {
|
||||
size_t chunkSize = mathMin(
|
||||
psarSize - totalRead, ASSET_FILE_READ_CHUNK_MAX
|
||||
);
|
||||
size_t chunkRead = fread(
|
||||
psarData + totalRead, 1, chunkSize, ASSET.platform.pbpFile
|
||||
);
|
||||
if(chunkRead == 0) {
|
||||
free(psarData);
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Failed to read PSAR data from file: %s", pbpPath);
|
||||
}
|
||||
totalRead += chunkRead;
|
||||
}
|
||||
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
ASSET.platform.pbpFile = NULL;
|
||||
|
||||
zip_source_t *psarSource = zip_source_buffer_create(
|
||||
psarData, (zip_uint64_t)psarSize, 1, NULL
|
||||
);
|
||||
if(psarSource == NULL) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
free(psarData);
|
||||
errorThrow("Failed to create zip source in PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
|
||||
ASSET.zip = zip_open_from_source(
|
||||
psarSource,
|
||||
ZIP_RDONLY,
|
||||
@@ -98,7 +124,6 @@ errorret_t assetInitPBP(const char_t *pbpPath) {
|
||||
);
|
||||
if(ASSET.zip == NULL) {
|
||||
zip_source_free(psarSource);
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Failed to open zip from PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user