/* * xfi = xfropen(name,num) * n = xfrread(xfi) * err = xfrclose(xfi) * * RESTRICTIONS: NO seeking. * * Three buffers are used. When the 2nd buffer is 1st accessed, * an asynchronous read is started on the 3rd. The buffers cycle. * If the file has an .lzh extension, it is decompressed 1 buffer * at a time. */ #include #include #include #include "scan.h" extern void *AllocMem(); extern FH *Open(); extern void *malloc(), *FindTask(); extern long FillBufWithLZH(); extern long WinSiz; /* Size of each buffer */ extern char EOBK; /* Ptr 2 End of buf keywrd 2b put after last wrd in buf */ extern char *BufIdx; /* Ptr 2 buffer user should start using after open/read */ /* Note that this is modified at each buffer switch. */ extern char *EOCB; /* Ptr 2 End+1 of buf that user is currently reading. */ /* Note that this is modified at each buffer switch. */ extern char *SOCB; /* Ptr 2 Strt of buf user is currently reading from */ /* Note that this is modified at each buffer switch. */ extern XFI *FHandle; extern int KeyWrdOvlp; extern int OpenNew; /* Set to 1 if finished with internal LZH archive file. */ extern int LON; extern int EnableLZHDecomp; int FrstAsyncRd; char *filenm; char *TmpPtr; int flen; int ItsALZH; int FrstRd; void * xfropen(file,num) char *file; long *num; { extern long xfrread(); XFI *xfi; FHandle = AllocMem((ULONG)sizeof(XFI), MEMF_CLEAR | MEMF_PUBLIC); xfi = FHandle; /* needed for abort/cleanup routine */ flen = strlen(file) - 1; filenm = file; ItsALZH = 0; if( EnableLZHDecomp ) { if( tolower( file[ flen--] ) == 'h' && tolower( file[ flen--] == 'z') && tolower( file[ flen--] ) == 'l' && file[ flen] == '.') ItsALZH = 1; flen = strlen(file) - 1; if( tolower( file[ flen--] ) == 'a' && tolower( file[ flen--] == 'h') && tolower( file[ flen--] ) == 'l' && file[ flen] == '.') ItsALZH = 1; } if( ItsALZH ) { /* Allocate all 3 buffers with spare for buffer switch */ xfi->asbuf = (char *)malloc(WinSiz + OVERLAP + 4) + OVERLAP; xfi->usbuf = (char *)malloc(WinSiz + OVERLAP + 4) + OVERLAP; xfi->zsbuf = (char *)malloc(WinSiz + OVERLAP + 4) + OVERLAP; /* Put end of buffer keyword before strt of 1st buffer to prevent */ /* backing up before data is valid. */ strncpy(xfi->asbuf - 4, &EOBK, 3); /* Put newline char right before 1st char of 1st buffer to allow */ /* matching article separtor with newline as it's 1st char. */ strncpy(xfi->asbuf - 1, "\n", 1); /* 0 <= x != buffer size -> end of file */ /* 0 <= x <= buffer size -> x = # of bytes read into buf */ /* x > buffer size -> # of bytes read into buffer = buf size */ /* 0 > x -> end of archive */ /* if no file matches the pattern a 0 is returned. */ /* if there are no more files in the archive to test, a -1 is returnd */ *num = FillBufWithLZH( file, xfi->asbuf); OpenNew = 0; if( *num >= 0 && *num != WinSiz ) { if( *num > WinSiz ) *num = WinSiz; OpenNew = 1; /* dont open new internal file in LHA/LZH archive */ } FrstRd = 0; LON = 1; /* set so we bypass closing archive */ if( *num < 0 ) { *num = 0; LON = 0; OpenNew = 1; } strncpy( xfi->asbuf + *num, &EOBK , 3); BufIdx = xfi->asbuf; TmpPtr = xfi->asbuf; SOCB = TmpPtr; /* Pointer to start of current buffer */ EOCB = TmpPtr + *num; /* Pointer to last byte in buffer + 1 */ xfi->asbuf = xfi->usbuf; /* swap buffs */ xfi->usbuf = xfi->zsbuf; xfi->zsbuf = TmpPtr; Chk_Abort(); } else { OpenNew = 0; LON = 0; xfi->fh = Open(file, 1005); if (xfi->fh) { xfi->fh = (FH *)((long)xfi->fh << 2); /* Allocate all 3 buffers with spare for buffer switch */ xfi->asbuf = (char *)malloc(WinSiz + OVERLAP + 4) + OVERLAP; xfi->usbuf = (char *)malloc(WinSiz + OVERLAP + 4) + OVERLAP; xfi->zsbuf = (char *)malloc(WinSiz + OVERLAP + 4) + OVERLAP; /* Copy end of buffer indicator to end of each of the 3 buffers */ strncpy(xfi->asbuf + WinSiz, &EOBK, 3); strncpy(xfi->usbuf + WinSiz, &EOBK, 3); strncpy(xfi->zsbuf + WinSiz, &EOBK, 3); /* Put end of buffer keyword before strt of 1st buffer to prevent */ /* backing up before data is valid. */ strncpy(xfi->asbuf - 4, &EOBK, 3); /* Put newline char right before 1st char of 1st buffer to allow */ /* matching article separtor with newline as it's 1st char. */ strncpy(xfi->asbuf - 1, "\n", 1); FrstAsyncRd = 1; /* Initialize reply port */ xfi->rp.mp_Node.ln_Type = NT_MSGPORT; xfi->rp.mp_Node.ln_Name = "Async"; xfi->rp.mp_Flags = PA_SIGNAL; xfi->rp.mp_SigBit = AllocSignal(-1); if( xfi->rp.mp_SigBit == -1 ) ErrP("Could not allocate signal\n"); xfi->rp.mp_SigTask = FindTask(NULL); NewList(&(xfi->rp.mp_MsgList)); /* Create a new list header */ /* Fill up 1st buffer and start the read for the 2nd */ SOCB = NULL; EOCB = NULL; Chk_Abort(); xfstartasync(xfi); /* Read into asbuf */ Chk_Abort(); *num = xfrread(xfi); /* Wait 4 prev read & then strt rd into usbuf */ Chk_Abort(); } else { FreeMem(FHandle,(ULONG)sizeof(XFI)); FHandle = 0; xfi = NULL; } } return(xfi); } xfrclose(xfi) XFI *xfi; { extern long *afp; int err = 1; if (xfi) { if( ItsALZH ) { err = 0; if( afp != NULL ) { fclose( afp ); afp = NULL; } if( xfi->asbuf != NULL ) free( xfi->asbuf - OVERLAP); xfi->asbuf = NULL; if( xfi->usbuf != NULL ) free( xfi->usbuf - OVERLAP); xfi->usbuf = NULL; if( xfi->zsbuf != NULL ) free( xfi->zsbuf - OVERLAP); xfi->zsbuf = NULL; FreeMem(xfi,(ULONG)sizeof(XFI)); FHandle = 0; } else { if (xfi->pend) { /* Wait for pending read to complete */ xfi->pend = 0; WaitPort (&xfi->rp); GetMsg (&xfi->rp); } err = xfi->err; if( xfi->fh != NULL ) Close((long)xfi->fh >> 2); if( xfi->asbuf != NULL ) free( xfi->asbuf - OVERLAP); xfi->asbuf = NULL; if( xfi->usbuf != NULL ) free( xfi->usbuf - OVERLAP); xfi->usbuf = NULL; if( xfi->zsbuf != NULL ) free( xfi->zsbuf - OVERLAP); xfi->zsbuf = NULL; if( xfi->rp.mp_SigBit > 0 ) FreeSignal(xfi->rp.mp_SigBit); xfi->rp.mp_SigBit = 0; FreeMem(xfi,(ULONG)sizeof(XFI)); FHandle = 0; } } return(err); } /* Called to make sure a previous read is complete before swapping buffers */ /* and then starting another async read. */ long xfrread(xfi) XFI *xfi; { long NumRead; if( ItsALZH ) { /* 0 <= x != buffer size -> end of file */ /* 0 <= x <= buffer size -> x = # of bytes read into buf */ /* x > buffer size -> # of bytes read into buffer = buf size */ /* 0 > x -> end of archive */ /* If an internal file name does not match the pattern, 0 is returned.*/ /* If there are no more internal files, -1 is returned. */ if( !OpenNew ) { if( FrstRd ) { FrstRd = 0; /* Put end of buffer keyword before strt of 1st buffer to prevent*/ /* backing up before data is valid. */ strncpy(xfi->asbuf - 4, &EOBK, 3); /* Put newline char right before 1st char of 1st buffer to allow */ /* matching article separtor with newline as it's 1st char. */ strncpy(xfi->asbuf - 1, "\n", 1); BufIdx = xfi->asbuf; /* Init pntr 2 new user workspace */ } else { /* if last read did not get an EOF, provide buffer overlap */ memcpy(xfi->asbuf - OVERLAP,xfi->zsbuf + WinSiz - OVERLAP,OVERLAP); BufIdx = xfi->asbuf - KeyWrdOvlp; /* Init pntr 2 new user wrkspc */ } NumRead = FillBufWithLZH( filenm, xfi->asbuf); OpenNew = 0; if( NumRead >= 0 && NumRead != WinSiz ) { /* if EOF */ if( NumRead > WinSiz ) NumRead = WinSiz; OpenNew = 1; /* finished with internal LZH/LHA archive file */ } strncpy(xfi->asbuf + NumRead, &EOBK , 3); if( NumRead < 0 ) LON = 0; } else { /* Comes here on xfrread after the last xfrread with >=0 retrnd.*/ /* Return -1 so EOF processing will be done. */ FrstRd = 1; NumRead = -1; OpenNew = 0; BufIdx = xfi->asbuf; /* Init pntr 2 new user workspace */ strncpy(xfi->asbuf, &EOBK , 3); } TmpPtr = xfi->asbuf; SOCB = TmpPtr; /* Pointer to start of current buffer */ EOCB = TmpPtr + NumRead; /* Pointer to last byte in buffer + 1 */ xfi->asbuf = xfi->usbuf; /* swap buffs */ xfi->usbuf = xfi->zsbuf; xfi->zsbuf = TmpPtr; Chk_Abort(); } else { if (xfi->pend != 0) { /* if pending read has not finished */ WaitPort (&xfi->rp); /* Wait for it */ GetMsg (&xfi->rp); xfi->pend = 0; } /* Copy last OVERLAP bytes of currently used buf to start of next buf */ if (!FrstAsyncRd) memcpy(xfi->asbuf - OVERLAP, xfi->zsbuf + WinSiz - OVERLAP, OVERLAP); if ((NumRead = xfi->sp.sp_Pkt.dp_Res1) <= 0) { /* EOF */ return(0); } /* Last read may not completely fill the buffer */ if ( NumRead < WinSiz ) { /* copy end of buffer keyword after last byte in buffer */ /* No need to worry about overwriting EOB keyword after buffer */ /* because it is not needed anymore. The next file opened will */ /* call xfropen which will reinitialize the EOB's. */ strncpy(xfi->asbuf + NumRead, &EOBK , 3); } /* On 1st read, start at 1st data read, on next reads, start a */ /* little before data just read in to handle keywords spanning buffers */ if (FrstAsyncRd) { BufIdx = xfi->asbuf; FrstAsyncRd = 0; } else { BufIdx = xfi->asbuf - KeyWrdOvlp; /* Init pntr 2 new user workspace */ } TmpPtr = xfi->asbuf; SOCB = TmpPtr; /* Pointer to start of current buffer */ EOCB = TmpPtr + NumRead; /* Pointer to last byte in buffer + 1 */ xfi->asbuf = xfi->usbuf; /* swap buffs */ xfi->usbuf = xfi->zsbuf; xfi->zsbuf = TmpPtr; Chk_Abort(); xfstartasync(xfi); /* new async read */ } return(NumRead); } static xfstartasync(xfi) XFI *xfi; { xfi->sp.sp_Msg.mn_Node.ln_Name = (char *)&(xfi->sp.sp_Pkt); xfi->sp.sp_Pkt.dp_Link = &(xfi->sp.sp_Msg); xfi->sp.sp_Pkt.dp_Port = &xfi->rp; xfi->sp.sp_Pkt.dp_Type = ACTION_READ; xfi->sp.sp_Pkt.dp_Arg1 = xfi->fh->fh_Arg1; xfi->sp.sp_Pkt.dp_Arg2 = (long)xfi->asbuf; xfi->sp.sp_Pkt.dp_Arg3 = WinSiz; PutMsg (xfi->fh->fh_Type, &xfi->sp); xfi->pend = 1; }