Recovering old Infocom games from Atari 400/800 disks
From: Michael Current (mcurrent@carleton.edu)
Date: 08/27/98-09:47:41 PM Z
- Next message by date: Michael Current: "RVerter Type Interface (Instructions)"
- Previous message by date: Michael Current: "SpartaDOS disk format"
- Return to Index: Sort by: [ date ] [ author ] [ thread ] [ subject ]
From: Michael Current <mcurrent@carleton.edu> Subject: Recovering old Infocom games from Atari 400/800 disks Date: Thu Aug 27 21:47:41 1998 From: jenkin@cs.yorku.ca (Michael Jenkin) >Newsgroups: rec.games.int-fiction Subject: recovering old infocom games from atari 400/800 disks Date: 2 Apr 93 17:45:18 GMT Organization: York University, CS Dept. Toronto Lines: 259 The following two programs will extract infocom datafiles from atari800 (yes the 8bit machine, not the st) infocom games. The resulting datafiles can then be played with either the infocom interpreter or with the publicly available interpreters that can be found on the net. To use this you will need to get the raw disk image from the original infocom disk uploaded to a somewhat larger machine. Each side of an atari disk has 720 sectors of 128 bytes. Upload these sectors in order into a binary file on your favourite modern platform. NB: This is quite a task. The fastest modem I could attach to the atari was 1200 baud and disk/memory limits make it necessary to break a full disk into a number of smaller files containg the sectors before downloading. Two programs follow. zoffset works for single sided games. It takes the games serial number, the name of a file containing the raw sectors and an output file and does the conversion. zheader2 does the same thing for two sided games. The serial number can be found by either running the game or by doing a strings -6 on the disk image and look for something that resembles a date or by running the game on the atari -- it is printed out first thing. Michael Jenkin York University -------------- zoffset.c /* * a filter to take a raw disk file from an ATARI 800 infocom game * (version 3 or earlier) and the serial number (obtained via strings -6) * and produce a data file playable with either zmachine or infocom * * This version works for games written to a single side of the disk only * (I've seen zork1, 2, and 3 this way as well as deadline. Later games * are written on both sides of the disk. Use the 2 sided utility instead.) * * Michael Jenkin, 1993 */ # include <stdio.h> /* the disk */ unsigned char disk[720*128]; main(argc, argv) int argc; char *argv[]; { int i, offset, len; unsigned short sum, gsum; FILE *fd; if(argc != 4){ (void) fprintf(stderr,"usage: zoffset <serial-id> <disk> <outfile>\n"); exit(1); } if(strlen(argv[1]) != 6){ (void) fprintf(stderr, "serial id's are 6 bytes long e.g. 830329\n"); exit(1); } if((fd = fopen(argv[2], "r")) == NULL){ (void) fprintf(stderr, "open of disk file %s failed!\n",argv[2]); exit(1); } if(fread(disk, sizeof(disk), 1, fd) != 1){ (void) fprintf(stderr, "read of disk file %s failed!\n",argv[2]); exit(1); } (void) fclose(fd); /* search for the key */ offset = -1; for(i=0;i<720*128-6;i++) if(!strncmp(argv[1], &disk[i], 6)){ if(offset >= 0) (void) fprintf(stderr, "duplicate serial numbers! using first\n"); else offset = i - 18; } /* verify that this all makes sense */ if(offset >= 0) (void) fprintf(stderr, "data file starts at offset %d\n",offset); else { (void) fprintf(stderr, "key %s not found in disk image\n",argv[1]); exit(1); } if(disk[offset] != 3) (void) fprintf(stderr, "zoffset only tested on version 3 images....\n"); len = (disk[offset+26] << 8) | disk[offset+27]; sum = (disk[offset+28] << 8) | disk[offset+29]; len *= 2; (void) fprintf(stderr, "The image has length %d\n",len); if((offset + len) >= (128 * 720)){ (void) fprintf(stderr, "The data file is a little short!\n"); exit(1); } /* checksum the game file. checksum starts 64 bytes into disk */ gsum = 0; for(i=64;i<len;i++) gsum += disk[offset+i]; printf("game checksum %d sum %d\n",sum,gsum); if(sum != gsum) printf("checksum failed\n"); /* write it out */ if((fd = fopen(argv[3], "w")) == NULL){ (void) fprintf(stderr, "Can't create output file %s\n",argv[3]); exit(1); } if(fwrite(&disk[offset], len, 1, fd) != 1){ (void) fprintf(stderr, "write of %s failed\n",argv[3]); exit(1); } (void) fclose(fd); } -------- zheader2.c # include <stdio.h> /* * take a 2 disk version of an infocom game an piece it together * * This should work with all of those nasty double sided atari disks * * Michael Jenkin, 1993. */ # define DISKSIZE (720*128) unsigned char side1[DISKSIZE], side2[DISKSIZE]; main(argc, argv) int argc; char *argv[]; { unsigned char *start1, *keysearch(), *last1, *last2; int sum, len, obj, vcb, gbl, cmn, res, i; unsigned short gsum; FILE *fd; if(argc != 5){ (void) fprintf(stderr,"usage: zheader2 <id> <side1> <side2> <outfile>\n"); exit(1); } if(strlen(argv[1]) != 6){ (void) fprintf(stderr, "serial id's are 6 bytes long e.g. 830329\n"); exit(1); } /* read the files in. Nice to have enouch memory to store the disk */ getfile(argv[2], side1); getfile(argv[3], side2); /* find the start of the game file on side1 */ start1 = keysearch(side1, argv[1]); /* verify the header and extract offsets to important segments */ printf("Version is %d\n",*start1); if(*start1 != 3) printf("Only tested on version 3's!\n"); len = (start1[26] << 8) | start1[27]; sum = (start1[28] << 8) | start1[29]; cmn = (start1[24] << 8) | start1[25]; vcb = (start1[8] << 8) | start1[9]; obj = (start1[10] << 8) | start1[11]; gbl = (start1[12] << 8)| start1[13]; res = (start1[4] << 8)|start1[5]; len *= 2; printf("Game file has length %d checksum %d\n",len,sum); printf("cmn %d vcb %d obj %d gbl %d last %d\n", cmn, vcb,obj,gbl,&side1[DISKSIZE]-start1); printf("Trying to split at res+1...\n"); checksplit(argv[4],res+1,len, sum, start1, side2); printf("oh well. got to search for it. this could take a while...\n"); for(i=vcb;i<&side1[DISKSIZE]-start1;i++) checksplit(argv[4], i, len, sum, start1, side2); } checksplit(fname, sp, len, sum, p1, p2) int sp, len, sum; unsigned char *p1, *p2; char *fname; { unsigned short gsum; int i; FILE *fd; if(!(sp % 1000)) printf("trying %d\n",sp); gsum = 0; for(i=64;i<sp;i++) gsum += p1[i]; for(i=0;i<len-sp;i++) gsum += p2[i]; if(gsum != sum) return; printf("split point at %d\n",sp); printf("checksum %d gsum %d\n",sum,gsum); if((fd = fopen(fname, "w")) == NULL){ (void) fprintf(stderr,"unable to create %s\n",fname); exit(1); } if(fwrite(p1, sp, 1, fd) != 1){ (void) fprintf(stderr, "write failed\n"); exit(1); } if(fwrite(p2, len-sp, 1, fd) != 1){ (void) fprintf(stderr, "write 2 failed\n"); exit(1); } (void) fclose(fd); exit(0); } getfile(fname, side) char *fname; unsigned char side[DISKSIZE]; { FILE *fd; if((fd = fopen(fname, "r")) == NULL){ (void) fprintf(stderr, "open of disk file %s failed!\n",fname); exit(1); } if(fread(side, DISKSIZE, 1, fd) != 1){ (void) fprintf(stderr, "read of disk file %s failed!\n",fname); exit(1); } (void) fclose(fd); } unsigned char *keysearch(side, key) unsigned char side[DISKSIZE]; char *key; { unsigned char *start; int i; /* search for the key */ for(start=side, i=0;i<DISKSIZE-6;i++,start++) if(!strncmp(key, start, 6)){ return(start-18); /* offset of serial number from header */ } (void) fprintf(stderr,"unable to find key %s on side1!\n",key); }
- Next message by date: Michael Current: "RVerter Type Interface (Instructions)"
- Previous message by date: Michael Current: "SpartaDOS disk format"
----------------------------------------- Return to message index