103 lines
3.8 KiB
C
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;
|
|
}
|