home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ANews 1
/
AnewsCD01.iso
/
Indispensables
/
Compression
/
xad
/
Developer
/
Sources
/
tools
/
xadUnFile.c
< prev
Wrap
C/C++ Source or Header
|
1999-08-09
|
19KB
|
616 lines
#ifdef MULTIFILE
#define NAME "xadUnFileM"
#else
#define NAME "xadUnFile"
#endif
#define DISTRIBUTION "(Freeware) "
#define REVISION "7"
/* Programmheader
Name: xadUnFile
Author: SDI
Distribution: Freeware
Description: dearchives file archives
Compileropts: -
Linkeropts: -gsi -l amiga
1.0 13.09.98 : first version
1.1 18.11.98 : added FILE parameter and directory creation
1.2 03.02.99 : added corrupt message
1.3 07.02.99 : added missing "group crunched" handling
1.4 16.03.99 : errors no longer abort decrunching
1.5 21.06.99 : added support for multiple input files and renaming
1.6 04.07.99 : bug fix
1.7 18.07.99 : added SHOWPROT, reduced status prints, added QUIT,
splitted in xadUnFile and xadUnFileM
*/
#include <proto/xadmaster.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <exec/memory.h>
#include <dos/dosasl.h>
#include <utility/hooks.h>
#include "SDI_defines.h"
#include "SDI_compiler.h"
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
struct xadMasterBase * xadMasterBase = 0;
struct DosLibrary * DOSBase = 0;
struct ExecBase * SysBase = 0;
#define MINPRINTSIZE 51200 /* 50KB */
#ifdef MULTIFILE
#define PARAM "FROM/A/M,DEST=DESTDIR/K,PASSWORD/K,FILE/K,NE=NOEXTERN/S,"\
"INFO=LIST/S,OW=OVERWRITE/S,NOTREE/S,ASKMAKEDIR/S," \
"NOCOMMENT/S,NOPROT/S,NODATE/S,NOABS/S,SHOWPROT/S,QUIET/S"
#else
#define PARAM "FROM/A,DEST=DESTDIR,PASSWORD/K,FILE/M,NE=NOEXTERN/S,"\
"INFO=LIST/S,OW=OVERWRITE/S,NOTREE/S,ASKMAKEDIR/S," \
"NOCOMMENT/S,NOPROT/S,NODATE/S,NOABS/S,SHOWPROT/S,QUIET/S"
#endif
#ifdef MULTIFILE
#define OPTIONS \
"FROM The input archive file(s) (no patterns allowed)\n" \
"DESTDIR The destination directory, not needed with INFO\n" \
"PASSWORD A password for encrypted archives\n" \
"FILE Filename (with patterns) to be extracted\n" \
"NOEXTERN Turns off usage of external clients\n" \
"INFO Shows archive information without extracting\n" \
"OVERWRITE Files are overwritten without asking\n" \
"NOTREE Files are extracted without subdirectories\n" \
"ASKMAKEDIR You get asked before a directory is created\n" \
"NOCOMMENT No filenote comments are extracted or displayed\n" \
"NOPROT Protection information gets not extracted\n" \
"NODATE Creation date information gets not extracted\n" \
"NOABS Do not extract absolute path name parts\n" \
"SHOWPROT Show protection information with LIST\n" \
"QUIET Turns of progress report and user interaction!\n"
#else
#define OPTIONS \
"FROM The input archive file (no patterns allowed)\n" \
"DESTDIR The destination directory, not needed with INFO\n" \
"PASSWORD A password for encrypted archives\n" \
"FILE Filename(s) (with patterns) to be extracted\n" \
"NOEXTERN Turns off usage of external clients\n" \
"INFO Shows archive information without extracting\n" \
"OVERWRITE Files are overwritten without asking\n" \
"NOTREE Files are extracted without subdirectories\n" \
"ASKMAKEDIR You get asked before a directory is created\n" \
"NOCOMMENT No filenote comments are extracted or displayed\n" \
"NOPROT Protection information gets not extracted\n" \
"NODATE Creation date information gets not extracted\n" \
"NOABS Do not extract absolute path name parts\n" \
"SHOWPROT Show protection information with LIST\n" \
"QUIET Turns of progress report and user interaction!\n"
#endif
struct xHookArgs {
STRPTR name;
ULONG flags;
ULONG finish;
ULONG lastprint;
};
#ifdef MULTIFILE
struct Args {
STRPTR * from;
STRPTR destdir;
STRPTR password;
STRPTR file;
ULONG noextern;
ULONG info;
ULONG overwrite;
ULONG notree;
ULONG askmakedir;
ULONG nocomment;
ULONG noprot;
ULONG nodate;
ULONG noabs;
ULONG showprot;
ULONG quiet;
};
#else
struct Args {
STRPTR from;
STRPTR destdir;
STRPTR password;
STRPTR * file;
ULONG noextern;
ULONG info;
ULONG overwrite;
ULONG notree;
ULONG askmakedir;
ULONG nocomment;
ULONG noprot;
ULONG nodate;
ULONG noabs;
ULONG showprot;
ULONG quiet;
};
LONG CheckName(STRPTR *pat, STRPTR name);
#endif
ASM(ULONG) progrhook(REG(a0, struct Hook *),
REG(a1, struct xadProgressInfo *));
void ShowProt(ULONG i);
ULONG start(void)
{
ULONG ret = RETURN_FAIL;
struct DosLibrary *dosbase;
SysBase = (*((struct ExecBase **) 4));
{ /* test for WB and reply startup-message */
struct Process *task;
if(!(task = (struct Process *) FindTask(0))->pr_CLI)
{
WaitPort(&task->pr_MsgPort);
Forbid();
ReplyMsg(GetMsg(&task->pr_MsgPort));
return RETURN_FAIL;
}
}
if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
{
LONG err = 0;
struct xadMasterBase *xadmasterbase;
DOSBase = dosbase;
if((xadmasterbase = (struct xadMasterBase *)
OpenLibrary("xadmaster.library", 1)))
{
struct Args args;
struct RDArgs *rda;
memset(&args, 0, sizeof(struct Args));
xadMasterBase = xadmasterbase;
if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
{
rda->RDA_ExtHelp = OPTIONS;
if(ReadArgs(PARAM, (LONG *) &args, rda))
{
if(args.destdir || args.info)
{
struct xadArchiveInfo *ai;
if((ai = (struct xadArchiveInfo *)
xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
{
#ifdef MULTIFILE
if(*(args.from+1))
{
struct xadSplitFile *sf = 0, *sf2, *sf0 = 0;
while(*args.from && !err)
{
if((sf2 = xadAllocObjectA(XADOBJ_SPLITFILE, 0)))
{
if(sf)
{
sf->xsf_Next = sf2; sf = sf2;
}
else
sf0 = sf = sf2;
sf->xsf_Type = XAD_INFILENAME;
sf->xsf_Data = (ULONG) *(args.from++);
}
else
err = XADERR_NOMEMORY;
}
if(!err)
err = xadGetInfo(ai, XAD_INSPLITTED, sf0, XAD_NOEXTERN,
args.noextern, args.password ? XAD_PASSWORD : TAG_IGNORE,
args.password, TAG_DONE);
while(sf0)
{
sf2 = sf0; sf0 = sf0->xsf_Next;
xadFreeObjectA(sf2, 0);
}
}
else
err = xadGetInfo(ai, XAD_INFILENAME, *args.from,
XAD_NOEXTERN, args.noextern, args.password ? XAD_PASSWORD :
TAG_IGNORE, args.password, TAG_DONE);
#else
err = xadGetInfo(ai, XAD_INFILENAME, args.from,
XAD_NOEXTERN, args.noextern, args.password ? XAD_PASSWORD :
TAG_IGNORE, args.password, TAG_DONE);
#endif
if(!err)
{
if(ai->xai_Flags & XADAIF_FILECORRUPT)
Printf("!!! The archive file has some corrupt data. !!!\n");
if(args.info)
{
struct xadFileInfo *xfi;
ULONG grsize = 0;
Printf("ArchiverName: %s\n"
"Size CrndSize Ratio Date Time %sName\n",
ai->xai_Client->xc_ArchiverName, args.showprot ? "Protection " : "");
xfi = ai->xai_FileInfo;
while(xfi && !CTRL_C)
{
if(!(xfi->xfi_Flags & XADFIF_GROUPED))
grsize = 0;
if(xfi->xfi_Flags & XADFIF_DIRECTORY)
{
Printf(" <dir> <dir> %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
if(args.showprot)
ShowProt(xfi->xfi_Protection);
Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
xfi->xfi_FileName);
}
else if(xfi->xfi_Flags & XADFIF_GROUPED)
{
Printf("%8ld merged n/a %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
xfi->xfi_Size, xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
if(args.showprot)
ShowProt(xfi->xfi_Protection);
Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
xfi->xfi_FileName);
grsize += xfi->xfi_Size;
if(xfi->xfi_Flags & XADFIF_ENDOFGROUP)
{
ULONG i = 0, j = 0;
if(xfi->xfi_GroupCrSize < grsize)
{
i = ((grsize - xfi->xfi_GroupCrSize)*1000)/grsize;
j = i % 10;
i /= 10;
}
Printf("%8ld %8ld %2ld.%1ld%%\n", grsize, xfi->xfi_GroupCrSize,
i, j);
grsize = 0;
}
}
else
{
ULONG i = 0, j = 0;
if(xfi->xfi_CrunchSize < xfi->xfi_Size)
{
i = ((xfi->xfi_Size - xfi->xfi_CrunchSize)*1000)/xfi->xfi_Size;
j = i % 10;
i /= 10;
}
Printf("%8ld %8ld %2ld.%1ld%% %02ld.%02ld.%04ld %02ld:%02ld:%02ld ",
xfi->xfi_Size, xfi->xfi_CrunchSize, i, j,
xfi->xfi_Date.xd_Day, xfi->xfi_Date.xd_Month,
xfi->xfi_Date.xd_Year, xfi->xfi_Date.xd_Hour,
xfi->xfi_Date.xd_Minute, xfi->xfi_Date.xd_Second);
if(args.showprot)
ShowProt(xfi->xfi_Protection);
Printf("%s\n", args.notree ? FilePart(xfi->xfi_FileName) :
xfi->xfi_FileName);
}
if(xfi->xfi_Comment && !args.nocomment)
Printf(": %s\n", xfi->xfi_Comment);
#ifdef DEBUG
if(xfi->xfi_Flags)
{
Printf("Flags: ");
if(xfi->xfi_Flags & XADFIF_CRYPTED)
Printf("XADFIF_CRYPTED ");
if(xfi->xfi_Flags & XADFIF_DIRECTORY)
Printf("XADFIF_DIRECTORY ");
if(xfi->xfi_Flags & XADFIF_LINK)
Printf("XADFIF_LINK ");
if(xfi->xfi_Flags & XADFIF_INFOTEXT)
Printf("XADFIF_INFOTEXT ");
if(xfi->xfi_Flags & XADFIF_GROUPED)
Printf("XADFIF_GROUPED ");
if(xfi->xfi_Flags & XADFIF_ENDOFGROUP)
Printf("XADFIF_ENDOFGROUP ");
if(xfi->xfi_Flags & XADFIF_NODATE)
Printf("XADFIF_NODATE ");
Printf("\n");
}
#endif
if(xfi->xfi_Flags & XADFIF_CRYPTED)
Printf("The entry is encrypted\n");
xfi = xfi->xfi_Next;
}
ret = 0;
}
else
{
struct Hook prhook;
struct xadFileInfo *fi;
UBYTE filename[256];
#ifdef MULTIFILE
UBYTE parsebuf[1024];
#endif
struct xHookArgs xh;
ret = 0;
xh.name = filename;
xh.flags = xh.finish = xh.lastprint = 0;
/* Note! The hook may change the filename!!! */
memset(&prhook, 0, sizeof(struct Hook));
prhook.h_Entry = (ULONG (*)()) progrhook;
prhook.h_Data = &xh;
fi = ai->xai_FileInfo;
#ifdef MULTIFILE
if(!args.file || ParsePatternNoCase(args.file, parsebuf, 1024) >= 0)
#endif
{
while(fi && !CTRL_C && !xh.finish)
{
#ifdef MULTIFILE
if(!args.file || MatchPatternNoCase(parsebuf, args.notree ?
FilePart(fi->xfi_FileName) : fi->xfi_FileName))
#else
if(!args.file || CheckName(args.file, args.notree ?
FilePart(fi->xfi_FileName) : fi->xfi_FileName))
#endif
{
CopyMem(args.destdir, filename, strlen(args.destdir)+1);
if(args.notree)
AddPart(filename, FilePart(fi->xfi_FileName), 256);
else if(!args.noabs)
AddPart(filename, fi->xfi_FileName, 256);
else
{
STRPTR fname = filename, f;
if(*args.destdir)
{
fname += strlen(args.destdir)-1;
if(*fname != ':' && *fname != '/')
*(++fname) = '/';
++fname;
}
for(f = fi->xfi_FileName; *f; ++f)
*(fname++) = *f == ':' ? '/' : *f;
*fname = 0;
}
if(fi->xfi_Flags & XADFIF_DIRECTORY)
{
if(!args.notree)
{
BPTR a;
LONG err = 0, i = 0;
UBYTE r;
while(filename[i] && !err)
{
for(;filename[i] && filename[i] != '/'; ++i)
;
r = filename[i];
filename[i] = 0;
if((a = Lock(filename, SHARED_LOCK)))
UnLock(a);
else if((a = CreateDir(filename)))
UnLock(a);
else
err = 1;
filename[i++] = r;
}
if(!args.quiet)
{
if(err)
Printf("failed to create directory '%s'\n",
fi->xfi_FileName);
else
Printf("Created directory : %s\n", filename);
}
}
}
else if(fi->xfi_Flags & XADFIF_LINK)
{
if(!args.quiet)
Printf("Skipped Link\n");
}
else
{
struct DateStamp d;
if(!xadFileUnArc(ai, XAD_OUTFILENAME, filename,
XAD_ENTRYNUMBER, fi->xfi_EntryNumber, XAD_MAKEDIRECTORY,
!args.askmakedir, XAD_OVERWRITE, args.overwrite,
args.quiet ? TAG_IGNORE : XAD_PROGRESSHOOK, &prhook, TAG_DONE))
{
if(!args.nodate && !(fi->xfi_Flags & XADFIF_NODATE)
&& !xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date,
XAD_GETDATEDATESTAMP, &d, TAG_DONE))
SetFileDate(filename, &d);
if(!args.noprot)
SetProtection(filename, fi->xfi_Protection);
if(fi->xfi_Comment && !args.nocomment)
SetComment(filename, fi->xfi_Comment);
/* SetOwner ??? */
}
}
}
fi = fi->xfi_Next;
}
}
}
xadFreeInfo(ai);
} /* xadGetInfo */
xadFreeObjectA(ai, 0);
} /* xadAllocObject */
}
else
SetIoErr(ERROR_REQUIRED_ARG_MISSING);
FreeArgs(rda);
} /* ReadArgs */
FreeDosObject(DOS_RDARGS, rda);
} /* AllocDosObject */
if(CTRL_C)
SetIoErr(ERROR_BREAK);
if(!args.quiet)
{
if(err)
Printf("An error occured: %s\n", xadGetErrorText(err));
else if(ret)
PrintFault(IoErr(), 0);
}
CloseLibrary((struct Library *) xadmasterbase);
} /* OpenLibrary xadmaster */
else
Printf("Could not open xadmaster.library\n");
CloseLibrary((struct Library *) dosbase);
} /* OpenLibrary dos */
return ret;
}
/* Because of SAS-err, this cannot be SAVEDS */
ASM(ULONG) progrhook(REG(a0, struct Hook *hook),
REG(a1, struct xadProgressInfo *pi))
{
ULONG ret = 0;
STRPTR name = ((struct xHookArgs *) (hook->h_Data))->name;
switch(pi->xpi_Mode)
{
case XADPMODE_ASK:
ret |= ((struct xHookArgs *) (hook->h_Data))->flags;
if((pi->xpi_Status & XADPIF_OVERWRITE) && !(ret & XADPIF_OVERWRITE))
{
LONG r;
Printf("File '%s' already exists, overwrite? (Y|A|S|\033[1mN\033[0m|Q|R): ",
pi->xpi_FileName);
Flush(Output());
SetMode(Input(), TRUE);
r = FGetC(Input());
SetMode(Input(), FALSE);
switch(r)
{
case 'a': case 'A':
((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_OVERWRITE;
case 'y': case 'Y': ret |= XADPIF_OVERWRITE; break;
case 's': case 'S': ret |= XADPIF_SKIP; break;
case 'q': case 'Q': ((struct xHookArgs *) (hook->h_Data))->finish = 1; break;
case 'r': case 'R':
Printf("\r\033[KEnter new (full) name for '%s':", pi->xpi_FileName);
Flush(Output());
FGets(Input(), name, 255); /* 1 byte less to correct bug before V39 */
r = strlen(name);
if(name[r-1] == '\n') /* skip return character */
name[--r] = 0;
Printf("\033[1F\033[K"); /* go up one line and clear it */
if(pi->xpi_NewName = xadAllocVec(++r, MEMF_PUBLIC))
{
while(r--)
pi->xpi_NewName[r] = name[r];
ret |= XADPIF_RENAME;
}
else
Printf("No memory to store new name\n");
}
}
if((pi->xpi_Status & XADPIF_MAKEDIRECTORY) &&
!(ret & XADPIF_MAKEDIRECTORY))
{
Printf("Directory of file '%s' does not exist, create? (Y|A|S|\033[1mN\033[0m|Q): ",
name);
Flush(Output());
SetMode(Input(), TRUE);
switch(FGetC(Input()))
{
case 'a': case 'A':
((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_MAKEDIRECTORY;
case 'y': case 'Y': ret |= XADPIF_MAKEDIRECTORY; break;
case 's': case 'S': ret |= XADPIF_SKIP; break;
case 'q': case 'Q': ((struct xHookArgs *) (hook->h_Data))->finish = 1;
}
SetMode(Input(), FALSE);
}
break;
case XADPMODE_PROGRESS:
if(pi->xpi_CurrentSize - ((struct xHookArgs *) (hook->h_Data))->lastprint >= MINPRINTSIZE)
{
Printf("\r\033[KWrote %8ld of %8ld bytes: %s",
pi->xpi_CurrentSize, pi->xpi_FileInfo->xfi_Size, name);
Flush(Output());
((struct xHookArgs *) (hook->h_Data))->lastprint = pi->xpi_CurrentSize;
}
break;
case XADPMODE_END: Printf("\r\033[KWrote %8ld bytes: %s\n",
pi->xpi_CurrentSize, name);
break;
case XADPMODE_ERROR: Printf("\r\033[K%s: %s\n", name,
xadGetErrorText(pi->xpi_Error));
break;
}
if(!CTRL_C) /* clear ok flag */
ret |= XADPIF_OK;
return ret;
}
void ShowProt(ULONG i)
{
LONG j;
UBYTE buf[18];
for(j = 0; j < 16; ++j)
buf[j] = '-';
buf[j++] = ' ';
buf[j] = 0;
if(i & FIBF_OTR_READ) buf[0] = 'r';
if(i & FIBF_OTR_WRITE) buf[1] = 'w';
if(i & FIBF_OTR_EXECUTE) buf[2] = 'e';
if(i & FIBF_OTR_DELETE) buf[3] = 'd';
if(i & FIBF_GRP_READ) buf[4] = 'r';
if(i & FIBF_GRP_WRITE) buf[5] = 'w';
if(i & FIBF_GRP_EXECUTE) buf[6] = 'e';
if(i & FIBF_GRP_DELETE) buf[7] = 'd';
if(i & (1<<7)) buf[8] = 'h';
if(i & FIBF_SCRIPT) buf[9] = 's';
if(i & FIBF_PURE) buf[10] = 'p';
if(i & FIBF_ARCHIVE) buf[11] = 'a';
if(!(i & FIBF_READ)) buf[12] = 'r';
if(!(i & FIBF_WRITE)) buf[13] = 'w';
if(!(i & FIBF_EXECUTE)) buf[14] = 'e';
if(!(i & FIBF_DELETE)) buf[15] = 'd';
Printf(buf);
}
#ifndef MULTIFILE
/* would be better to store the pattern parse stuff and do it only once,
but so it is a lot easier */
LONG CheckName(STRPTR *pat, STRPTR name)
{
UBYTE buf[500];
while(*pat)
{
if(ParsePatternNoCase(*(pat++), buf, 500) >= 0)
{
if(MatchPatternNoCase(buf, name))
return 1;
} /* A scan failure means no recognition, should be an error print here */
}
return 0;
}
#endif