#include #include #include #include #include typedef struct { unsigned lsn; unsigned char size; } cluster; typedef union { struct { char flags; char name[8]; char ext[3]; cluster c[4]; char slink; } h; struct { char flags; cluster c[7]; unsigned notused; char slink; } c; } dirent; char *errstr[]={ "General disk error", "Read error", "Invalid drive", "Not a DRAGONDOS disk", "Invalid entry access", "Required parameter missing", "File not found", "Cannot open output file" }; int err=0; /* note: dragon drives are numbered 1-4, so the initial working drive value of 0 indicates no valid drive */ int wdrv=0, wtrck=-1, whead=-1, notracks, nosecs, dread=0; /* enough buffer for one track (18 sectors) and directory track */ char tbuf[4608], dbuf[4608]; /* get sector from track buffer or read new track - NULL on error */ char *getabs(int track, int sector) { int retry=2; if(wdrv<1) { err=2; return NULL; } if(dread && (track<0 || track>=notracks || sector<1 || sector>nosecs)) { err=1; return NULL; } if(track==20 && sector<19) { if(!dread) { do { if(!retry--) { err=1; return NULL; } } while(biosdisk(2, wdrv-1, 0, 20, 1, 18, dbuf)); dread=1; } return &dbuf[--sector<<8]; } if(track!=wtrck || (sector-1)/18!=whead) { do { if(!retry--) { wtrck=-1; err=1; return NULL; } } while(biosdisk(2, wdrv-1, (sector-1)/18, track, 1, 18, tbuf)); wtrck=track; whead=(sector-1)/18; } return &tbuf[(--sector%18)<<8]; } /* get sector from lsn - otherwise same as getabs */ char *getsec(int lsn) { return getabs(lsn/nosecs, (lsn%nosecs)+1); } /* set current working drive. reads track 20 and gets number of tracks and sectors per track from sector 1 */ int setwdrv(int drive) { char *buf; /* error if drive out of range */ if(drive<1 || drive>4) { err=2; return -1; } /* disk reset */ biosdisk(0, drive-1, 0, 0, 0, 0, NULL); wdrv=drive; if((buf=getabs(20, 1))==NULL) return -1; notracks=buf[252]; nosecs=buf[253]; /* check for dragondos disk */ if((notracks+buf[254]+1)&0xff+(nosecs+buf[255]+1)&0xff) { err=3; return -1; } return 0; } /* return little-endian copy of big-endian integer (for lsns) */ int bigend(int num) { return (num&0xff00)>>8|(num&0xff)<<8; } /* return directory entry */ dirent *getent(int entry) { dirent *ebuf; if(entry<0 || entry>159) { err=4; return NULL; } ebuf=(dirent *)getabs(20, (entry/10)+3); return &ebuf[entry%10]; } void docluster(cluster *c, FILE *f, unsigned bytlast) { char *buf; int i=c->size,l=bigend(c->lsn); for(; i>1; i--) { buf=getsec(l++); fwrite(buf, 1, 256, f); } buf=getsec(l); fwrite(buf, 1, bytlast&0xff, f); } int main(int argc, char *argv[]) { char fname[13]; char far *dparm=MK_FP(0, 0x78); dirent *ent; FILE *out; int i; dparm=MK_FP(dparm[3]<<8|dparm[2], dparm[1]<<8|dparm[0]); dparm[3]=1; if(argc<3) { err=5; goto errexit; } if(setwdrv(2)) goto errexit; if((ent=getent(0))==NULL) goto errexit; for(i=0; i<160 && !(ent->h.flags&0x08); i++) { if((ent=getent(i))==NULL) goto errexit; if(!(ent->h.flags&0x81)) { strncpy(fname, ent->h.name, 8); fname[8]=0x00; strcat(fname,"."); strncat(fname, ent->h.ext, 3); fname[12]=0x00; if(!strcmp(strupr(argv[1]), strupr(fname))) goto dofile; } } err=6; goto errexit; dofile: if((out=fopen(argv[2], "wb"))==NULL) { err=7; goto errexit; } for(i=0; i<4; i++) { if((i<3 && ent->h.c[i+1].size!=0) || (i==3 && ent->h.flags&0x20)) { docluster(&ent->h.c[i], out, 0x100); } else { docluster(&ent->h.c[i], out, ent->h.slink); break; } } while(ent->h.flags&0x20) { ent=getent(ent->h.slink); for(i=0; i<7; i++) { if((i<7 && ent->c.c[i+1].size!=0) || (i==7&&ent->c.flags&0x20)) { docluster(&ent->c.c[i], out, 0x100); } else { docluster(&ent->c.c[i], out, (unsigned) ent->c.slink); break; } } } fclose(out); goto normex; errexit: puts(errstr[err]); dparm[3]=2; exit(1); normex: dparm[3]=2; return 0; }