if (GET_WORD(buf,8) <= high_mem) /* Dictionary addr <= High memory */
score += 10;
if (GET_WORD(buf,10) <= GET_WORD(buf,14)) /* Object addr <= Dynamic area */
score += 10;
if (GET_WORD(buf,12) <= GET_WORD(buf,14)) /* Globals <= Dynamic area */
score += 10;
if (GET_WORD(buf,14) <= high_mem) /* Dynamic area <= High memory */
score += 10;
if (GET_WORD(buf,16) < 0x0200) /* Flags bits 9 to 15 clear */
score += 10;
if (version == V1) {
for (i = 0; i < 6; i++)
if (GET_BYTE(buf,18+i) == 0) /* Serial == 0 */
score += 2;
} else {
for (i = 0; i < 6; i++)
if (GET_BYTE(buf,18+i) >= 32 && GET_BYTE(buf,18+i) < 127) /* Serial in ASCII */
score += 2;
}
if (version == V1) {
if (GET_WORD(buf,24) == 0) /* Abbreviations == 0 */
score += 10;
} else {
if (GET_WORD(buf,24) <= GET_WORD(buf,14)) /* Abbreviations <= Dynamic area */
score += 10;
}
if (version == V1 || version == V2) {
if (GET_WORD(buf,26) == 0) /* File size == 0 */
score += 10;
if (GET_WORD(buf,28) == 0) /* Checksum == 0 */
score += 10;
} else if (version == V3) {
if (GET_WORD(buf,26) != 0) {
if (2 * (long) GET_WORD(buf,26) > high_mem)
score += 20;
} else {
if (GET_WORD(buf,28) == 0) /* Checksum == 0 */
score += 20;
}
} else if (version == V4 || version == V5) {
if (4 * (long) GET_WORD(buf,26) > high_mem)
score += 20;
} else {
if (8 * (long) GET_WORD(buf,26) > high_mem)
score += 20;
}
if (GET_WORD(buf,30) == 0) /* Interpreter == 0 */
score += 10;
if (GET_WORD(buf,32) == 0) /* Screen format == 0 */
score += 10;
if (GET_WORD(buf,34) == 0) /* Screen width == 0 */
score += 10;
if (GET_WORD(buf,36) == 0) /* Screen height == 0 */
score += 10;
if (GET_WORD(buf,38) == 0) /* Font format == 0 */
score += 10;
for (i = 0; i < sizeof (header); i++) checksum += header[i];
if (!checksum_valid)
printf ("Checksum unknown.\n");
else if (checksum == 0)
printf ("Checksum good.\n");
else
printf ("Checksum bad.\n");
}/* end_trans */
/****************************************************************************
*
* Apple II specific routines
*
****************************************************************************/
/****************************************************************************
*
* Apple II V2/V3 specific routines
*
****************************************************************************/
void get_small_apple_game (void) {
byte id[18];
int sector = 48;
infile (0, 0x0cbdL, id, sizeof (id));
interleave = strncmp ((char *) id, "Apple II Version E", 18) ?
"0DB97531ECA8642F" : "0123456789ABCDEF";
fseek (fpin[0], apple_sector_offset (sector++), SEEK_SET);
trans (0);
}
end_trans ();
}/* get_small_apple_game */
/****************************************************************************
*
* Apple II V4/V5 specific routines
*
****************************************************************************/
for (i = 0; i < 0x1a00; i++)
if (track_data1[i] == 0xd5)
if (track_data1[(i+1) % 0x1a00] == 0xaa)
if (track_data1[(i+2) % 0x1a00] == 0xad)
goto start_found;
error ("NIB file has bad format");
start_found:
memcpy (track_data2, track_data1 + i, 0x1a00 - i);
memcpy (track_data2 + 0x1a00 - i, track_data1, i);
for (sector = 0; sector < 18; sector++) {
byte *p = track_data2 + 343 * sector + 5;
byte value = 0;
for (i = 0; i < 343; i++)
if (p[i] & 0x80)
p[i] = value ^= trans[p[i] - 0x80];
if (value != 0)
fprintf (stderr, "Warning: Bad sector checksum on NIB image\n");
fseek (fpin[0], apple_sector_offset (sector), SEEK_SET);
trans (0);
}
fseek (fpin[2], 0L, SEEK_SET);
while (filesize > 0L)
trans (2);
end_trans ();
}/* get_medium_apple_game */
/****************************************************************************
*
* Apple II V6 specific routines
*
****************************************************************************/
byte table[1024];
word block_map[MAX_FILES][256];
word read_table_word (int offs) {
if (offs >= sizeof (table) / sizeof (table[0]))
error ("Disk image has bad format");
return GET_WORD(table,offs);
}/* read_table_word */
void find_story_block (word log_block, int *disk, word *phys_block) {
printf ("Image identified as %s side %d.\n", title[this_game], this_side);
if (this_game != prev_game && disk != 0)
error ("Disk images from different games");
if (this_side != disk + 1)
error ("Wrong ordering of disk images");
fseek (fpin[disk], apple_sector_offset (2 * phys_block), SEEK_SET);
trans (disk);
fseek (fpin[disk], apple_sector_offset (2 * phys_block + 1), SEEK_SET);
trans (disk);
}
end_trans ();
}/* get_large_apple_game */
/****************************************************************************
*
* Apple II main routine
*
****************************************************************************/
void get_apple (int n) {
int disk;
if (n == 1) { /* V2 or V3 game */
if (file_info[0].size == 232960L)
error ("The disk image should be in DSK format\n");
get_small_apple_game ();
}
if (n == 2) { /* V4 or V5 game */
if (file_info[0].size == 232960L)
error ("The first disk image should be in DSK format\n");
if (file_info[1].size != 232960L)
error ("The second disk image must be in NIB format\n");
get_medium_apple_game ();
}
if (n == 3) { /* Error */
error ("Wrong number of disk images (try to omit the third image)");
}
if (n >= 4) { /* V6 game */
for (disk = 0; disk < n; disk++)
if (file_info[disk].size == 232960L)
error ("All disk images should be in DSK format");
get_large_apple_game (n);
}
}/* get_apple */
/****************************************************************************
*
* Atari specific routines
*
****************************************************************************/
void get_atari (int n) {
long offset = 0L;
long start = 0L;
int sectors = 0;
int disk = 0;
if (n >= 3)
error ("Too many disk image files for an Atari game");
if (check_for_header (0, 0x01f90L))
start = 0x01f90L;
if (check_for_header (0, 0x01c10L))
start = 0x01c10L;
if (check_for_header (0, 0x02410L))
start = 0x02410L;
if (start == 0L)
for (offset = 16; offset < 0x16810L; offset += 256)
if (check_for_header (0, offset))
start = offset;
if ((GET_BYTE(header,1) & 4) == 4 && n == 1)
error ("This game takes two disk images");
if ((GET_BYTE(header,1) & 4) == 0 && n == 2)
error ("This game takes only one disk image");
if (GET_BYTE(header,0) >= V4 && n == 1)
error ("This game takes two disk images");
if (GET_BYTE(header,0) <= V3 && n == 2)
error ("This game takes only one disk image");
switch (GET_BYTE(header,0)) {
case V3: get_v3_c64 (); break;
case V4: get_v4_c64 (); break;
case V5: get_v5_c64 (); break;
default: error ("Couldn't find start of story file");
}
}/* get_commodore */
/****************************************************************************
*
* CPC specific routines
*
****************************************************************************/
long amstrad_sector_offset (int sector) {
static int mapper[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
static int previous = -1;
fseek (fpin[0], amstrad_sector_offset (2 * map[count]), SEEK_SET);
trans (0);
trans (0);
fseek (fpin[0], amstrad_sector_offset (2 * map[count] + 1), SEEK_SET);
trans (0);
trans (0);
count++;
}
end_trans ();
}/* get_amstrad */
/****************************************************************************
*
* IBM specific routines
*
****************************************************************************/
void get_ibm (int drive) {
#ifdef __MSDOS__
static byte buf[4096];
int track;
if ((fpin[0] = tmpfile ()) == NULL)
error ("Cannot open temporary file");
puts (
"\n"
"ZCut V1.1 -- extract Infocom story files\n"
"\n"
"Written by Stefan Jokisch in 1998. Based on work by Matthew T. Russotto,\n"
"Paul D. Doherty, Stephen Tjasink, Mark Howell and Michael Jenkin.\n"
"\n"
"ZCut extracts Infocom story files (aka Z-code) from\n"
"\n"
"- Amstrad CPC disk images [.DSK]\n"
"- Apple ][ disk images [.DSK, .NIB]\n"
"- Atari 800/XL/XE disk images [.ATR]\n"
"- Commodore 64/128 disk images [.D64]\n"
"- IBM PC bootable disks (MS-DOS version only)\n"
"- any file if the Z-code is stored in one piece\n"
"\n"
"Usage: zcut input-file-1 [input-file-2...] output-file\n"
" zcut drive: output-file");
return EXIT_FAILURE;
}
if ((n = argc - 2) > MAX_FILES)
error ("Too many arguments");