// 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 #include #include #include 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; }