| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdio.h> | |
| typedef unsigned char u_char; | |
| typedef unsigned short u_short; | |
| typedef struct direntry { | |
| unsigned char une[12]; | |
| #define d_user une[0] | |
| #define d_name une[1] | |
| #define d_ext une[9] | |
| u_short d_fext; | |
| u_char d_fill; | |
| u_char d_last; | |
| u_short d_blks[8]; | |
| } DIR; | |
| #define UNUSED 0xE5 | |
| #define DIROFFSET 0x2000 | |
| #define DIRBLKS 16 | |
| #define BLKSTART (DIROFFSET+DIRBLKS*128) | |
| #define CLSTSIZE 2048 | |
| typedef struct fileentry { | |
| char f_name[30]; | |
| u_short f_fext; | |
| u_char f_last; | |
| u_short f_blks[200]; | |
| } FENTRY; | |
| void makename(char* name, DIR* dir) | |
| { | |
| int i; | |
| char *p = name; | |
| for (i=0; i<8; i++) { | |
| if ((&dir->d_name)[i]==' ') break; | |
| *p++ = (&dir->d_name)[i]; | |
| } | |
| *p++ = '.'; | |
| for (i=0; i<3; i++) { | |
| if ((&dir->d_ext)[i]==' ') break; | |
| *p++ = (&dir->d_ext)[i]; | |
| } | |
| *p = 0; | |
| } | |
| FENTRY* lookup(char* name, FENTRY* files) | |
| { | |
| FENTRY* nul=0, *p = files; | |
| int i; | |
| for (i = 0; i<64; i++) { | |
| if (p->f_name[0]==0) { | |
| if (nul==0) nul = p; | |
| } else { | |
| if (!strcmp(p->f_name,name)) { | |
| return p; | |
| } | |
| } | |
| p++; | |
| } | |
| if (nul==0) { | |
| printf("File table full!\n"); | |
| exit(1); | |
| } | |
| return nul; | |
| } | |
| int main(int argc,char* argv[]) | |
| { | |
| FILE *in,*out; | |
| unsigned char cpmbuf[2048]; | |
| int i,k,n,s,ls; | |
| char name[30]; | |
| FENTRY files[64], *fe; | |
| DIR* dir; | |
| if (argc != 2) { | |
| fprintf(stderr,"Usage: %s cpmdisk.bin\n",argv[0]); | |
| exit(1); | |
| } | |
| for (i=0; i<64; i++) { | |
| files[i].f_name[0] = 0; | |
| files[i].f_fext = 0; | |
| files[i].f_last = 0; | |
| memset(files[i].f_blks,0,sizeof(u_short)*200); | |
| } | |
| in = fopen(argv[1],"rb"); | |
| if (!in) { | |
| perror("open file"); | |
| exit(1); | |
| } | |
| fseek(in,DIROFFSET,0); | |
| for (i=0; i<DIRBLKS; i++) { | |
| fread(cpmbuf,sizeof(DIR),4,in); | |
| for (k=0; k<4; k++) { | |
| dir = (DIR*)(cpmbuf+k*sizeof(DIR)); | |
| if (dir->d_user == UNUSED) continue; | |
| makename(name,dir); | |
| fe = lookup(name,files); | |
| strcpy(fe->f_name,name); | |
| if (dir->d_fext >= fe->f_fext) { | |
| fe->f_fext = dir->d_fext; | |
| fe->f_last = dir->d_last; | |
| } | |
| for (n=0; n<8; n++) { | |
| fe->f_blks[dir->d_fext*8+n] = dir->d_blks[n]; | |
| } | |
| } | |
| } | |
| for (i=0; i<64; i++) { | |
| if (!files[i].f_name[0]) continue; | |
| printf("File %s: (last=%d)\n",files[i].f_name,files[i].f_last%16); | |
| FILE* out = fopen(files[i].f_name,"wb"); | |
| for (k=0; k<199; k++) { | |
| n = files[i].f_blks[k]; | |
| if (n==0) break; | |
| fseek(in,BLKSTART+CLSTSIZE*(n-1),0); | |
| fread(cpmbuf,1,2048,in); | |
| ls = files[i].f_last % 16; | |
| if (!ls) ls = 16; | |
| s = files[i].f_blks[k+1]==0 ? ls*128 : CLSTSIZE; | |
| fwrite(cpmbuf,1,s,out); | |
| printf("%d ",files[i].f_blks[k]); | |
| } | |
| printf("\n"); | |
| fclose(out); | |
| } | |
| exit(0); | |
| } |