home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
dirs
/
lhlib_436.lzh
/
LhLib
/
LhEncode.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-15
|
18KB
|
834 lines
/* $Revision Header * Header built automatically - do not edit! *************
*
* (C) Copyright 1990 by Holger P. Krekel & Olaf 'Olsen' Barthel
*
* Name .....: LhEncode.c
* Created ..: Wednesday 11-Jul-90 19:40
* Revision .: 0
*
* Date Author Comment
* ========= ======== ====================
* 11-Jul-90 Olsen Created this file!
*
* $Revision Header ********************************************************/
/* ARP cli template and help information. */
char *CLI_Template = "FROM,TO,N=NoQuery/S,F=Faster/S,H=Header/S";
char *CLI_Help = "\n\33[33m\33[1mLhEncode \33[0m\33[31m© Copyright 1990 by Holger P. Krekel & Olaf Barthel,\n\
All rights reserved.\n\n\
Usage: \33[1mLhEncode\33[0m [File or wildcard pattern] [File/directory name]\n\
[FASTER] [HEADER] [NOQUERY]\n";
/* Argument vector offsets. */
#define ARG_FROM 1
#define ARG_TO 2
#define ARG_NOQUERY 3
#define ARG_FASTER 4
#define ARG_HEADER 5
/* Global and shared data. */
struct Library *LhBase;
struct timerequest *TimeRequest;
struct MsgPort *TimePort;
struct Device *TimerBase;
struct FileRequester *FileRequester;
struct LhBuffer *LhBuffer;
BYTE Faster,Header,Query = TRUE;
ULONG TotalSecs = 0,TotalMicros = 0;
LONG TotalRatio,NumEntries = 0;
/* Linked list of file names. */
struct NameLink *RootLink;
char **NameList;
LONG NumNames = 0;
/* Function prototypes. */
extern int SubCmp();
LONG StrCmp(char **Str1,char **Str2);
BYTE BuildList(VOID);
VOID FreeLinks(VOID);
BYTE ScanDir(char *Pattern);
LONG GetFileSize(char *Name);
BYTE SetRawMode(BYTE Mode);
BYTE Encode(char *Src,char *Dst);
VOID main(int argc,char **argv);
/* Stub routines. */
LONG Chk_Abort(VOID) { return(0); }
VOID _wb_parse(VOID) {}
/* Assembly language fragment to be used by the QSort
* routine.
*/
#asm
xdef _SubCmp
_SubCmp:movem.l d2-d7/a2-a6,-(sp)
movem.l a0/a1,-(sp)
jsr _geta4#
jsr _StrCmp
add.w #8,sp
movem.l (sp)+,d2-d7/a2-a6
rts
#endasm
/* StrCmp():
*
* Compare two strings ignoring case (international).
*/
LONG
StrCmp(char **Str1,char **Str2)
{
char *a = *Str1,*b = *Str2;
for( ; ToUpper(*a) == ToUpper(*b) ; a++, b++)
{
if(!(*a))
return(0);
}
return(ToUpper(*a) - ToUpper(*b));
}
/* BuildList():
*
* Build an array of string pointers to be passed to the
* QSort function by scanning a linked list of names.
*/
BYTE
BuildList()
{
struct NameLink *TempLink;
for(TempLink = RootLink ; TempLink ; TempLink = TempLink -> Next)
NumNames++;
if(NameList = (char **)ArpAlloc(NumNames * sizeof(char *)))
{
NumNames = 0;
for(TempLink = RootLink ; TempLink ; TempLink = TempLink -> Next)
{
if(NameList[NumNames] = (char *)ArpAlloc(strlen(TempLink -> Name) + 1))
strcpy(NameList[NumNames++],TempLink -> Name);
else
return(FALSE);
}
return(QSort(NameList,NumNames,sizeof(char *),SubCmp));
}
return(FALSE);
}
/* FreeLinks():
*
* Free the linked list of names created by the directory
* scanner.
*/
VOID
FreeLinks()
{
struct NameLink *TempLink,*LastLink = NULL;
for(TempLink = RootLink ; TempLink ; TempLink = LastLink)
{
LastLink = TempLink -> Next;
FreeMem(TempLink,sizeof(struct NameLink));
}
}
/* ScanDir():
*
* Scan a directory for a given pattern and build a linked
* list of the names.
*/
BYTE
ScanDir(char *Pattern)
{
struct NameLink *LastLink = NULL;
char *Temp;
while(Temp = scdir(Pattern))
{
if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
{
SetSignal(0,SIGBREAKF_CTRL_C);
Puts("\n*** BREAK: LhEncode\a");
return(FALSE);
}
if(SetSignal(0,0) & SIGBREAKF_CTRL_D)
{
SetSignal(0,SIGBREAKF_CTRL_D);
return(TRUE);
}
if(RootLink)
{
struct NameLink *NextLink;
if(NextLink = (struct NameLink *)AllocMem(sizeof(struct NameLink),MEMF_PUBLIC | MEMF_CLEAR))
{
LastLink -> Next = NextLink;
strcpy(NextLink -> Name,Temp);
LastLink = NextLink;
}
else
return(TRUE);
}
else
{
if(RootLink = (struct NameLink *)AllocMem(sizeof(struct NameLink),MEMF_PUBLIC | MEMF_CLEAR))
{
strcpy(RootLink -> Name,Temp);
LastLink = RootLink;
}
else
return(TRUE);
}
}
return(TRUE);
}
/* GetFileSize():
*
* Asks the DOS to return the length of a given file.
*/
LONG
GetFileSize(char *Name)
{
struct FileInfoBlock *FileInfo;
BPTR FileLock;
LONG FileSize = 0;
if(FileInfo = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
{
if(FileLock = Lock(Name,ACCESS_READ))
{
if(Examine(FileLock,FileInfo))
FileSize = FileInfo -> fib_Size;
UnLock(FileLock);
}
FreeMem(FileInfo,sizeof(struct FileInfoBlock));
}
return(FileSize);
}
/* SetRawMode():
*
* Toggles between raw (single character) and 'cooked'
* (line input) data input from a console window.
*/
BYTE
SetRawMode(BYTE Mode)
{
LONG Args[7];
if(Mode)
Args[0] = DOSTRUE;
else
Args[0] = DOSFALSE;
return(SendPacket(ACTION_SCREEN_MODE,Args,(struct MsgPort *)((struct Process *)SysBase -> ThisTask) -> pr_ConsoleTask));
}
/* Encode():
*
* Encode a file for later usage (by any application or
* by LhDecode).
*/
BYTE
Encode(char *Src,char *Dst)
{
BPTR In,Out;
LONG FromSize;
LONG *From,*To;
LONG Secs,Micros;
BYTE Ratio;
struct timeval Req1,Req2;
char TempName[MaxInputBuf];
BPTR CheckLock;
Printf("%-31.31s ",BaseName(Src));
/* How long is our source file? */
if(!(FromSize = GetFileSize(Src)))
{
Printf("\33[33munable to examine file (Error %ld)\33[31m\a\n",IoErr());
return(TRUE);
}
/* Allocate memory for the source buffer. */
if(!(From = AllocMem(FromSize,MEMF_PUBLIC)))
{
Printf("\33[33mout of memory (Error 103)\33[31m\a\n");
return(TRUE);
}
/* Allocate memory for the destination buffer.
* Note: must be 1/8 larger than the source buffer.
*/
if(!(To = AllocMem(FromSize + ENCODEEXTRA(FromSize),MEMF_PUBLIC|MEMF_CLEAR)))
{
FreeMem(From,FromSize);
Printf("\33[33mout of memory (Error 103)\33[31m\a\n");
return(TRUE);
}
/* Open the file for reading. */
if(!(In = Open(Src,MODE_OLDFILE)))
{
FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
Printf("\33[33munable to open file (Error %ld)\33[31m\a\n",IoErr());
return(TRUE);
}
/* Read the data to be encoded. */
if(Read(In,From,FromSize) != FromSize)
{
LONG Error = IoErr();
Close(In);
FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
Printf("\33[33munable to read file (Error %ld)\33[31m\a\n",Error);
return(TRUE);
}
Close(In);
/* Initialize the LhBuffer structure. */
LhBuffer -> lh_Src = From;
LhBuffer -> lh_SrcSize = FromSize;
LhBuffer -> lh_Dst = To;
Printf("\33[33m%07ld\33[31m Encode ",FromSize);
/* If 'faster' encoding selected, disable interrupts
* and system DMA.
*/
if(Faster)
{
custom . dmacon = BITCLR|DMAF_ALL;
Disable();
custom . color[0] = 0;
}
/* Remember starting time. */
DoIO(TimeRequest);
Req1 = TimeRequest -> tr_time;
/* Encode the data. */
LhEncode(LhBuffer);
/* Remember finishing time. */
DoIO(TimeRequest);
Req2 = TimeRequest -> tr_time;
/* Reenable DMA and interrupts. */
if(Faster)
{
custom . dmacon = BITSET|DMAF_ALL;
Enable();
}
/* Subtract both time values. */
SubTime(&Req2,&Req1);
/* Calculate time and compression ration. */
Ratio = 100 - (100 * LhBuffer -> lh_DstSize) / FromSize;
Secs = Req2 . tv_secs;
Micros = Req2 . tv_micro / 10000;
Printf("\33[33m%02ld%%\33[31m %02ld:%02ld:%02ld ",(Ratio < 0 ? 0 : Ratio),Secs / 60,Secs % 60,Micros);
/* File didn't gain any size -> exit. */
if(LhBuffer -> lh_DstSize >= FromSize)
{
FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
Printf("\33[33m-------\33[31m \33[1moverflow!\33[0m\a\n");
return(TRUE);
}
/* Add them for the statistics. */
TotalRatio += Ratio;
TotalSecs += Secs;
TotalMicros += Micros;
NumEntries++;
/* ^C pressed = abort. */
if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
{
FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
SetSignal(0,SIGBREAKF_CTRL_C);
Puts("\n*** BREAK: LhEncode\a");
return(FALSE);
}
/* Check if we are about to overwrite an existing file. */
if(Query)
{
if(CheckLock = Lock(Dst,ACCESS_READ))
{
UnLock(CheckLock);
SetRawMode(TRUE);
Printf("\2331A\n\23332C\233KOverwrite (\33[33mN\33[31mo/\33[33mY\33[31mes/\33[33mC\33[31mhange) ? ");
/* Read a character. */
Ask: if(Read(((struct Process *)SysBase -> ThisTask) -> pr_CIS,TempName,1) > 0)
{
if(toupper(TempName[0]) == 'Y')
{
Printf("\2331A\n\23332C\233K\33[33m%07ld\33[31m Encode \33[33m%02ld%%\33[31m %02ld:%02ld:%02ld ",FromSize,(Ratio < 0 ? 0 : Ratio),Secs / 60,Secs % 60,Micros);
SetRawMode(FALSE);
goto GoOn;
}
if(toupper(TempName[0]) == 'N' || !TempName[0] || TempName[0] == '\n')
goto Nope;
if(toupper(TempName[0]) != 'C')
goto Ask;
/* Ask for a new name to save the file
* under.
*/
Printf("\2331A\n\233KNew Name: %s\2331A\n\23310C",Dst);
SetRawMode(FALSE);
ReadLine(TempName);
if(!TempName[0] || TempName[0] == '\n')
{
strcpy(TempName,Dst);
Printf("\2331A\233K");
}
Dst = TempName;
Printf("\2331A\n\233K%-31.31s \33[33m%07ld\33[31m Encode \33[33m%02ld%%\33[31m %02ld:%02ld:%02ld ",BaseName(Dst),FromSize,(Ratio < 0 ? 0 : Ratio),Secs / 60,Secs % 60,Micros);
goto GoOn;
}
/* Free the buffers and return. */
Nope: FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
Printf("\2331A\n\23332C\33[1m\233KSkipped\33[0m\n");
SetRawMode(FALSE);
return(TRUE);
}
}
/* Open the output file. */
GoOn: if(!(Out = Open(Dst,MODE_NEWFILE)))
{
FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
Printf("\33[33m\nERROR:\33[31m Unable to open file (Error %ld)\a\n",IoErr());
return(TRUE);
}
/* Add a size header. */
if(Header)
{
ULONG TempSize = FromSize | 0xFF000000;
/* Write header, note: size can occupy max. 24
* bits.
*/
if(Write(Out,&TempSize,sizeof(ULONG)) != sizeof(ULONG))
{
LONG Error = IoErr();
Close(Out);
FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
Printf("\33[33m\nERROR:\33[31m Unable to save file (Error %ld)\a\n",Error);
DeleteFile(Dst);
return(TRUE);
}
}
/* Write the file to disk. */
if(Write(Out,To,LhBuffer -> lh_DstSize) != LhBuffer -> lh_DstSize)
{
LONG Error = IoErr();
Close(Out);
FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
Printf("\33[33m\nERROR:\33[31m Unable to save file (Error %ld)\a\n",Error);
DeleteFile(Dst);
return(TRUE);
}
Close(Out);
/* Free the buffers and return. That was pretty painless,
* wasn't it?
*/
FreeMem(From,FromSize);
FreeMem(To,FromSize + ENCODEEXTRA(FromSize));
Printf("\33[33m%07ld\33[31m Done.\n",LhBuffer -> lh_DstSize);
return(TRUE);
}
VOID
main(int argc,char **argv)
{
char Match[DSIZE],TempName[DSIZE * 5 + FCHARS],TempName2[DSIZE * 5 + FCHARS],TempName3[DSIZE * 5 + FCHARS],*ToFile;
BYTE Success = RETURN_FAIL;
if(!argc)
exit(-1);
Enable_Abort = FALSE;
/* Faster decompression? */
if(argv[ARG_FASTER])
Faster = TRUE;
else
Faster = FALSE;
/* Put a 8 + 24 bit size header in front of the
* compressed file?
*/
if(argv[ARG_HEADER])
Header = TRUE;
else
Header = FALSE;
/* Don't ask before overwriting a file? */
if(argv[ARG_NOQUERY])
Query = FALSE;
/* If the destination argument is omitted, we'll assume
* that we will decompress into the current directory.
*/
if(argv[ARG_TO])
ToFile = argv[ARG_TO];
else
{
if(PathName(((struct Process *)SysBase -> ThisTask) -> pr_CurrentDir,TempName3,DSIZE * 5))
ToFile = TempName3;
else
{
Puts("\33[1mLhEncode:\33[0m Destination file/directory name required.\a");
exit(RETURN_ERROR);
}
}
Puts("\n\33[33m\33[1mLhEncode \33[0m\33[31m© Copyright 1990 by Holger P. Krekel & Olaf Barthel,\n All rights reserved.\n");
/* Open lh.library (most important call in this program). */
if(LhBase = (struct Library *)ArpOpenLibrary(LH_NAME,LH_VERSION))
{
/* Create an LhBuffer for data compression. */
if(LhBuffer = (struct LhBuffer *)CreateBuffer(FALSE))
{
if(FileRequester = ArpAllocFreq())
{
if(TimePort = CreatePort(NULL,0))
{
if(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest)))
{
/* Open the timer.device, we will need it for
* stopwatch functions.
*/
if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,0))
{
TimerBase = TimeRequest -> tr_node . io_Device;
TimeRequest -> tr_node . io_Command = TR_GETSYSTIME;
/* We got a source argument, no need to call the
* ARP file requester.
*/
if(argv[ARG_FROM])
{
struct FileInfoBlock *FileInfo;
BPTR FileLock;
BYTE IsDir = FALSE,GotIt = FALSE,IsWild;
/* Check if destination is a file or
* a directory.
*/
if(FileInfo = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
{
if(FileLock = Lock(ToFile,ACCESS_READ))
{
GotIt = TRUE;
if(Examine(FileLock,FileInfo))
IsDir = (FileInfo -> fib_DirEntryType > 0);
UnLock(FileLock);
}
FreeMem(FileInfo,sizeof(struct FileInfoBlock));
}
/* Check if source is a plain file name
* or a wildcard expression.
*/
IsWild = PreParse(argv[ARG_FROM],Match);
/* Strange... */
if(IsWild && !GotIt)
{
Puts("\33[1mLhEncode:\33[0m Unable to find destination directory!\a");
goto Quit;
}
/* Send a bunch of files to a single file? */
if(IsWild && !IsDir)
{
Puts("\33[1mLhEncode:\33[0m Destination is not a directory!\a");
goto Quit;
}
/* Source is a plain file. */
if(!IsWild)
{
Puts("\33[33mEncoding\33[31m - press \33[1mCTRL-C\33[0m to abort.\n");
Puts("File Name Size Mode % Time Result \n------------------------------- ------- ------ --- -------- -------");
strcpy(TempName,ToFile);
if(IsDir)
TackOn(TempName,BaseName(argv[ARG_FROM]));
if(Encode(argv[ARG_FROM],TempName))
Success = RETURN_OK;
}
else
{
LONG i;
Success = RETURN_OK;
Printf("\33[33mScanning\33[31m - press \33[1mCTRL-D\33[0m to stop, \33[1mCTRL-C\33[0m to abort... ");
/* Source is a wildcard expression,
* start the directory scanner.
*/
if(!ScanDir(argv[ARG_FROM]))
exit(RETURN_WARN);
Printf("Sorting.\n");
/* Convert the linked list and sort
* it.
*/
BuildList();
Puts("\2331A\233K\33[33mEncoding\33[31m - press \33[1mCTRL-C\33[0m to abort.\n");
Puts("File Name Size Mode % Time Result \n------------------------------- ------- ------ --- -------- -------");
for(i = 0 ; i < NumNames ; i++)
{
strcpy(TempName,ToFile);
if(IsDir)
TackOn(TempName,BaseName(NameList[i]));
if(!Encode(NameList[i],TempName))
{
Success = RETURN_FAIL;
break;
}
}
FreeLinks();
if(!Success)
{
TotalSecs += TotalMicros / 100;
TotalMicros %= 100;
Printf("\n\33[33mTotal Ratio\33[31m %02ld%%, \33[33mTotal Time\33[31m %02ld:%02ld:%02ld\n",TotalRatio / NumEntries,TotalSecs / 60,TotalSecs % 60,TotalMicros);
}
}
Puts("");
}
else
{
Success = RETURN_OK;
Puts("File Name Size Mode % Time Result \n------------------------------- ------- ------ --- -------- -------");
/* We didn't get a source file and a destination directory,
* so let's bring up the ARP file requester.
*/
for(;;)
{
FileRequester -> fr_Hail = "Select file to encode";
FileRequester -> fr_File[0] = 0;
if(!FileRequest(FileRequester))
break;
strcpy(TempName,FileRequester -> fr_Dir);
TackOn(TempName,FileRequester -> fr_File);
strcpy(FileRequester -> fr_File,"Directories only!");
FileRequester -> fr_Hail = "Select destination directory";
if(!FileRequest(FileRequester))
break;
strcpy(TempName2,FileRequester -> fr_Dir);
TackOn(TempName2,BaseName(TempName));
Encode(TempName,TempName2);
}
}
Quit: CloseDevice(TimeRequest);
}
else
Puts("\33[1mLhEncode:\33[0m Unable to open timer.device!\a");
DeleteExtIO(TimeRequest);
}
else
Puts("\33[1mLhEncode:\33[0m Out of memory!\a");
DeletePort(TimePort);
}
else
Puts("\33[1mLhEncode:\33[0m Unable to create MsgPort!\a");
}
else
Puts("\33[1mLhEncode:\33[0m Unable to allocate Arp Filerequester!\a");
DeleteBuffer(LhBuffer);
}
else
Puts("\33[1mLhEncode:\33[0m Out of memory!\a");
}
else
Printf("\33[1mLhDecode:\33[0m You need \"%s\" V%ld.0 or higher!\a\n",LH_NAME,LH_VERSION);
exit(Success);
}