fs2port/port/tools/extractscenery.c
2026-05-13 21:32:05 -05:00

103 lines
3.8 KiB
C

// FS2 scenery section extractor.
//
// Each FS2 scenery disk is loaded by chunk5 via six descriptors at
// LA60F..LA619 in chunk5 (verified in src/chunk5.s):
//
// LA60F $0322 LoadSceneryFile0
// LA611 $0625 LoadSceneryFile1
// LA613 $032D LoadSceneryFile2
// LA615 $012B LoadSceneryFile3
// LA617 $0142 LoadSceneryFile4
// LA619 $012C bootstrap (Common)
//
// The descriptor encodes (high = sector count, low = starting sector).
// Each sector is 256 bytes; sector N lives at file offset N*256. The
// san-inc pack zeroes tracks 0-1 of every scenery disk (boot loader
// stripped) so sectors 0..31 are zero-filled and the real content
// begins at sector $20 (file offset 0x2000).
//
// `LoadSceneryFileCommon` also re-runs the loader for the bootstrap
// descriptor on every call, but with a destination address read from
// the first word of the just-loaded file. So the file's first two
// bytes are a "load me here" pointer.
//
// This tool dumps each named section to a flat .bin so we can inspect
// the byte layout and feed the chunks into the C port.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct DescriptorT {
const char *name;
uint16_t descriptor; // raw FS2 16-bit value
} DescriptorT;
static const DescriptorT descriptors[] = {
{ "File0", 0x0322 },
{ "File1", 0x0625 },
{ "File2", 0x032D },
{ "File3", 0x012B },
{ "File4", 0x0142 },
{ "bootstrap", 0x012C },
{ NULL, 0 }
};
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "usage: %s in.dsk out_dir\n", argv[0]);
return 1;
}
FILE *f = fopen(argv[1], "rb");
if (f == NULL) {
fprintf(stderr, "cannot open %s\n", argv[1]);
return 1;
}
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
uint8_t *buf = malloc((size_t)size);
if (buf == NULL || fread(buf, 1, (size_t)size, f) != (size_t)size) {
fprintf(stderr, "could not read %s\n", argv[1]);
fclose(f);
free(buf);
return 1;
}
fclose(f);
for (int i = 0; descriptors[i].name != NULL; i++) {
uint16_t d = descriptors[i].descriptor;
uint8_t startSector = (uint8_t)(d & 0xFF);
uint8_t count = (uint8_t)((d >> 8) & 0xFF);
uint32_t offset = (uint32_t)startSector * 256;
uint32_t length = (uint32_t)count * 256;
if (offset + length > (uint32_t)size) {
fprintf(stderr, "%s: out of range (offset 0x%X, length %u, file %ld)\n",
descriptors[i].name, offset, length, size);
continue;
}
char outPath[1024];
snprintf(outPath, sizeof(outPath), "%s/%s.bin", argv[2], descriptors[i].name);
FILE *out = fopen(outPath, "wb");
if (out == NULL) {
fprintf(stderr, "cannot open %s\n", outPath);
continue;
}
fwrite(buf + offset, 1, length, out);
fclose(out);
// Quick header preview: file's first word is the
// suggested load address.
uint16_t loadAddr = (uint16_t)(buf[offset] | (buf[offset + 1] << 8));
printf("%-10s sector=$%02X count=%u file_offset=0x%04X length=%u hdr_word=$%04X -> %s\n",
descriptors[i].name, startSector, count, offset, length, loadAddr, outPath);
}
free(buf);
return 0;
}