| 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); | |
| } | |
Xet Storage Details
- Size:
- 7.37 kB
- Xet hash:
- e065992d4c84913a06b8eab5f18618f3b5d50b34f11e14181bfb58ca95e84b92
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.