home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
packery
/
xpk_source
/
xpack
/
xpack.c
< prev
Wrap
C/C++ Source or Header
|
1996-10-19
|
11KB
|
476 lines
#include <exec/alerts.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <dos/dosextens.h>
#include <dos/dosasl.h>
#include <dos/rdargs.h>
#include <xpk/xpk.h>
#define _USEOLDEXEC_ 1
#include <proto/dos.h>
#include <proto/exec.h>
#include <string.h>
#define XFH_ID "XFH A"
void PrintF(char *,...);
LONG __regargs PackFile(struct DosLibrary *DOSBase,struct Library *XpkBase,
char *,struct FileInfoBlock *,char *,char *,LONG,char *,
LONG,LONG,LONG,LONG,LONG);
LONG __regargs UnPackFile(struct DosLibrary *DOSBase,struct Library *XpkBase,
char *,char *,struct FileInfoBlock *,char *,LONG);
LONG __asm __saveds ChunkFunc(register __a1 struct XpkProgress *);
struct Hook ChunkHook = {{0L},ChunkFunc};
struct xPackArgs
{
char **Files;
char *Method;
ULONG *MinSize;
char *Suffix,*Password;
LONG All,Force,Program,xScan,Lossy,Quiet;
};
char *VersionString = "$VER: xPack 1.5 ("__DATE__")";
char *Template =
"FILE/M/A,METHOD/K,MINSIZE/N/K,SUFFIX/K,PASSWORD/K,"
"ALL/S,FORCE/S,PROGRAM/S,XSCAN/S,LOSSY/S,QUIET/S";
LONG __saveds main(void)
{
struct DosLibrary *DOSBase;
struct Library *XpkBase;
struct Process *MyProc;
struct RDArgs *RDArgs;
char ProgName[32];
LONG Result;
struct xPackArgs Args;
char **Files;
struct AnchorPath *AnchorPath;
ULONG MinSize;
if ((MyProc=(struct Process *)FindTask(NULL))->pr_CLI==NULL)
{
(void)WaitPort(&MyProc->pr_MsgPort);
Forbid();
ReplyMsg (GetMsg(&MyProc->pr_MsgPort));
return 0L;
}
if ((DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",33L))==NULL)
{
Alert (AT_Recovery|AG_OpenLib|AO_DOSLib);
return 20L;
}
if (DOSBase->dl_lib.lib_Version<37L)
{
(void)Write(Output(),"This program requires OS 2.04 or newer.\n",40L);
CloseLibrary (&DOSBase->dl_lib);
return 20L;
}
if (!GetProgramName(ProgName,32L)) (void)strcpy(ProgName,"xPack");
Result=10L;
if ((XpkBase=OpenLibrary(XPKNAME,2L))==NULL)
{
PrintF ("%s: %s V2 or newer required !\n",ProgName,XPKNAME);
goto Close1;
}
Args.Files=NULL;
Args.Method=Args.Suffix=Args.Password=NULL;
Args.MinSize=NULL;
Args.All=Args.Force=Args.Program=Args.xScan=Args.Lossy=Args.Quiet=FALSE;
if ((RDArgs=ReadArgs(Template,(LONG *)&Args,NULL))==NULL)
{
PrintFault (IoErr(),ProgName);
goto Close2;
}
if (Args.MinSize) MinSize=*Args.MinSize;
else MinSize=512L;
if (Args.Password) Args.Force=TRUE;
if ((AnchorPath=(struct AnchorPath *)AllocVec(sizeof(struct AnchorPath)+256L,
MEMF_PUBLIC|MEMF_CLEAR))==NULL)
{
PrintFault (ERROR_NO_FREE_STORE,ProgName);
goto Close3;
}
AnchorPath->ap_BreakBits=SIGBREAKF_CTRL_C;
AnchorPath->ap_Strlen=256;
Files=Args.Files;
while (*Files)
{
LONG RetVal;
for (RetVal=MatchFirst(*Files,AnchorPath); RetVal==0L; RetVal=MatchNext(AnchorPath))
{
if (AnchorPath->ap_Info.fib_DirEntryType>0L)
{
if (((AnchorPath->ap_Flags&APF_DIDDIR)==0L)&&Args.All)
AnchorPath->ap_Flags|=APF_DODIR;
AnchorPath->ap_Flags&=~APF_DIDDIR;
}
else
{
BPTR DirLock;
LONG Result;
DirLock=CurrentDir(AnchorPath->ap_Current->an_Lock);
if (Args.Method==NULL)
Result=UnPackFile(DOSBase,XpkBase,
AnchorPath->ap_Buf,Args.Suffix,&AnchorPath->ap_Info,
Args.Password,Args.Quiet);
else
Result=PackFile(DOSBase,XpkBase,
AnchorPath->ap_Buf,&AnchorPath->ap_Info,Args.Method,
Args.Suffix,MinSize,Args.Password,
Args.Force,Args.Program,Args.xScan,Args.Lossy,Args.Quiet);
(void)CurrentDir(DirLock);
if (!Result)
{
PrintF ("\n*** Aborting\n");
MatchEnd (AnchorPath);
goto Close4;
}
}
}
MatchEnd (AnchorPath);
if (RetVal!=ERROR_NO_MORE_ENTRIES)
{
PrintF ("%s: %s - ",ProgName,*Files);
PrintFault (RetVal,NULL);
goto Close4;
}
else Files++;
}
Result=0L;
Close4: /* I hate "goto"s, but it's the only way to keep it short. */
FreeVec ((APTR)AnchorPath);
Close3:
FreeArgs (RDArgs);
Close2:
CloseLibrary (XpkBase);
Close1:
CloseLibrary (&DOSBase->dl_lib);
return Result;
}
void PrintF(char *FormatString,...)
{
struct DosLibrary *DOSBase;
if (DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37L))
{
(void)VPrintf(FormatString,(LONG *)&FormatString+1L);
(void)Flush(Output());
CloseLibrary (&DOSBase->dl_lib);
}
}
void __regargs TempName(char *Name)
{
UWORD Index;
ULONG Addr;
for (Index=0, Addr=(ULONG)FindTask(NULL); Index<8; Index++, Addr>>=4)
*Name++='A'+(char)(Addr&15);
(void)strcpy(Name,".zop");
}
LONG __asm __saveds ChunkFunc(register __a1 struct XpkProgress *Prog)
{
if (Prog->Type==XPKPROG_START ) PrintF ("\x1B[0 p");
PrintF ("\r%-9s %-12s (%6ld bytes, %3ld%% done, %2ld%% CF) ",
Prog->Activity,Prog->FileName,Prog->ULen,Prog->Done,Prog->CF);
if (Prog->Type==XPKPROG_END) PrintF ("\n\x1B[1 p");
return (LONG)SetSignal(0L,SIGBREAKF_CTRL_C)&SIGBREAKF_CTRL_C;
}
char *ULTA(char *Ptr,ULONG LW)
{
UWORD Index;
*Ptr++=' ';
for (Index=0; Index<8; Index++, LW>>=4) Ptr[7-Index]='A'+(char)(LW&15);
return &Ptr[8];
}
#define TAGIT(i,t,d) XpkTags[i].ti_Tag=t; XpkTags[i].ti_Data=(ULONG)d;
#define ENDIT(i) XpkTags[i].ti_Tag=TAG_DONE;
LONG __regargs PackFile(struct DosLibrary *DOSBase,struct Library *XpkBase,
char *SourceName,struct FileInfoBlock *FIB,char *Method,
char *Suffix,LONG MinSize,char *Password,
LONG Force,LONG Program,LONG xScan,LONG Lossy,LONG Quiet)
{
BPTR Handle;
struct TagItem XpkTags[10];
struct XpkFib XpkFib;
char ErrorBuffer[XPKERRMSGSIZE],TargetName[108];
LONG Error,Size;
if (FIB->fib_Protection&FIBF_DELETE)
{
PrintF ("Skipping %s (delete protected)\n",SourceName);
return TRUE;
}
if (FIB->fib_Size<=MinSize)
{
PrintF ("Skipping %s (too small)\n",SourceName);
return TRUE;
}
if ((Handle=Open(FIB->fib_FileName,MODE_OLDFILE))==NULL)
{
PrintF ("Can't open %s\n",SourceName);
return TRUE;
}
if (!Force)
{
TAGIT(0,XPK_GetError,ErrorBuffer);
TAGIT(1,XPK_InFH,Handle);
ENDIT(2);
if (XpkExamine(&XpkFib,XpkTags))
{
Close (Handle);
PrintF ("%s\n",ErrorBuffer);
return TRUE;
}
if (XpkFib.Type!=XPKTYPE_UNPACKED)
{
Close (Handle);
PrintF ("Skipping %s (already crunched)\n",SourceName);
return TRUE;
}
}
if (Program)
{
LONG Buffer[5];
if (Read(Handle,Buffer,20L)!=20L)
{
Close (Handle);
PrintF ("Skipping %s (to small for executable)\n",SourceName);
return TRUE;
}
if (Buffer[0]!=0x3F3L)
{
Close (Handle);
PrintF ("Skipping %s (not executable)\n",SourceName);
return TRUE;
}
if ((Buffer[3]!=0L)||((Buffer[4]+1L)!=Buffer[2]))
{
Close (Handle);
PrintF ("Skipping %s (overlayed)\n",SourceName);
return TRUE;
}
(void)Seek(Handle,0L,OFFSET_BEGINNING);
}
if (Suffix)
{
ULONG Length;
Length=strlen(strcpy(TargetName,FIB->fib_FileName));
(void)strcpy(&TargetName[Length],Suffix);
}
else TempName (TargetName);
Size=0L;
TAGIT(0,XPK_GetError,ErrorBuffer);
TAGIT(1,XPK_Password,Password);
TAGIT(2,XPK_FindMethod,Method);
TAGIT(3,XPK_ChunkHook,&ChunkHook);
if (Quiet) XpkTags[3].ti_Tag=TAG_IGNORE;
TAGIT(4,XPK_FileName,FIB->fib_FileName);
TAGIT(5,XPK_InFH,Handle);
TAGIT(6,XPK_OutName,TargetName);
TAGIT(7,XPK_GetOutLen,&Size);
TAGIT(8,XPK_LossyOK,Lossy);
if (!Lossy) XpkTags[8].ti_Tag=TAG_IGNORE;
ENDIT(9);
if (Error=XpkPack(XpkTags))
{
Close (Handle);
PrintF ("%s\n",ErrorBuffer);
return (Error!=XPKERR_ABORTED);
}
Close (Handle);
if ((Size>FIB->fib_Size)&&(!Force))
{
(void)DeleteFile(TargetName);
PrintF ("Skipping %s (unable to reduce size)\n",SourceName);
return TRUE;
}
if (FIB->fib_Comment[0]=='\0')
if (xScan)
{
char *Ptr;
Ptr=strcpy(FIB->fib_Comment,XFH_ID)+strlen(XFH_ID);
Ptr=ULTA(Ptr,FIB->fib_Date.ds_Days);
Ptr=ULTA(Ptr,FIB->fib_Date.ds_Minute);
Ptr=ULTA(Ptr,FIB->fib_Date.ds_Tick);
Ptr=ULTA(Ptr,Size);
*ULTA(Ptr,FIB->fib_Size)='\0';
}
if (FIB->fib_Comment[0]) (void)SetComment(TargetName,FIB->fib_Comment);
if (FIB->fib_Protection) (void)SetProtection(TargetName,FIB->fib_Protection);
(void)SetFileDate(TargetName,&FIB->fib_Date);
if (Suffix) return TRUE;
if (!DeleteFile(FIB->fib_FileName))
{
(void)DeleteFile(TargetName);
PrintF ("Unable to delete %s\n",SourceName);
return TRUE;
}
if (!Rename(TargetName,FIB->fib_FileName))
{
PrintF ("Unable to rename %s to %s\n",TargetName,FIB->fib_FileName);
return FALSE;
}
return TRUE;
}
LONG __regargs UnPackFile(struct DosLibrary *DOSBase,struct Library *XpkBase,
char *SourceName,char *Suffix,
struct FileInfoBlock *FIB,char *Password,LONG Quiet)
{
BPTR Handle;
struct TagItem XpkTags[7];
struct XpkFib XpkFib;
char ErrorBuffer[XPKERRMSGSIZE],TargetName[108];
LONG SameFile,Error;
if (FIB->fib_Protection&FIBF_DELETE)
{
PrintF ("Skipping %s (delete protected)\n",SourceName);
return TRUE;
}
if ((Handle=Open(FIB->fib_FileName,MODE_OLDFILE))==NULL)
{
PrintF ("Can't open %s\n",SourceName);
return TRUE;
}
TAGIT(0,XPK_GetError,ErrorBuffer);
TAGIT(1,XPK_InFH,Handle);
ENDIT(2);
if (XpkExamine(&XpkFib,XpkTags))
{
Close (Handle);
PrintF ("%s\n",ErrorBuffer);
return TRUE;
}
if (XpkFib.Type!=XPKTYPE_PACKED)
{
Close (Handle);
PrintF ("Skipping %s (not crunched)\n",SourceName);
return TRUE;
}
TempName (TargetName);
SameFile=TRUE;
if (Suffix)
{
LONG Len1,Len2;
Len1=strlen(FIB->fib_FileName);
Len2=strlen(Suffix);
if (Len1>Len2)
if (stricmp(&FIB->fib_FileName[Len1-Len2],Suffix)==0)
{
strcpy(TargetName,FIB->fib_FileName)[Len1-Len2]='\0';
SameFile=FALSE;
}
}
TAGIT(0,XPK_GetError,ErrorBuffer);
TAGIT(1,XPK_Password,Password);
TAGIT(2,XPK_ChunkHook,&ChunkHook);
if (Quiet) XpkTags[2].ti_Tag=TAG_IGNORE;
TAGIT(3,XPK_FileName,FIB->fib_FileName);
TAGIT(4,XPK_InFH,Handle);
TAGIT(5,XPK_OutName,TargetName);
ENDIT(6);
if (Error=XpkUnpack(XpkTags)) {
Close (Handle);
PrintF ("%s\n",ErrorBuffer);
return (Error!=XPKERR_ABORTED);
}
Close (Handle);
if (FIB->fib_Comment[0])
if (strncmp(FIB->fib_Comment,XFH_ID,strlen(XFH_ID))!=0)
(void)SetComment(TargetName,FIB->fib_Comment);
if (FIB->fib_Protection) (void)SetProtection(TargetName,FIB->fib_Protection);
(void)SetFileDate(TargetName,&FIB->fib_Date);
if (!SameFile) return TRUE;
if (!DeleteFile(FIB->fib_FileName))
{
(void)DeleteFile(TargetName);
PrintF ("Unable to delete %s\n",SourceName);
return TRUE;
}
if (!Rename(TargetName,FIB->fib_FileName))
{
PrintF ("Unable to rename %s to %s\n",TargetName,FIB->fib_FileName);
return FALSE;
}
return TRUE;
}