
/*--------------------------------------------------------------------------*/
/* Another semi-useful utility by Doug Boone. Lists the contents of all the */
/* archive programs I am currently aware of:                                */
/*                                                                          */
/*      ARC     Systems Enhancements Associates                             */
/*      PAK     NoGate Consulting's PAK                                     */
/*      ZOO     Rahul Dhesi                                                 */
/*      DWC     Dean Cooper                                                 */
/*                                                                          */
/* Compiled with Turbo C 2.0, will work with either the Tiny or Small model */
/* assuming you have the ARCVIEW.COM file, it was generated with:           */
/*                                                                          */
/*      tcc -a- -f- -G -K -lt -mt -Z arcview.c                              */
/*                                                                          */
/*      -a- Byte align characters                                           */
/*      -f- No floating point numbers                                       */
/*      -G  Optomize for speed                                              */
/*      -K  Chars are unsigned                                              */
/*      -lt Tell tlink to make it a COM file                                */
/*      -mt Tiny memory model                                               */
/*      -Z  Use register optomization                                       */
/*                                                                          */
/* If you find any problems, or are want to send a "thank you", or whatever */
/* I can be reached at FidoNet 119/5, (916) 893-9019 24 hrs HST             */
/* Copyright 1988.                                                          */
/*                                                                          */
/* "Don't rip me off."  - Tom Jennings, FidoNet's founder                   */
/*--------------------------------------------------------------------------*/

#include    <stdio.h>
#include    <string.h>
#include    <ctype.h>
#include    <time.h>
#include	<signal.h>
#include	<dos.h>
#include	<dir.h>
#include    <io.h>
#include    <fcntl.h>
#include    <dos.h>
#include    <sys\types.h>
#include    <sys\stat.h>
#include	"archdr.h"


char*   _Cdecl      memrstr(char *,char *,int);
int     _Cdecl      read_dwc(char *);

main(int argc, char *argv[])
{
    int     i;
    int     done;
    struct  ffblk   ffblk;
	char    name[80];
    int     infile;		/* file handle */
	char    *firstchar;
	char	apath[80];
	char	*result;
    int     success;

    if (argc < 2) {
		printf ("\nView the contents of ARC, PAK, ZOO, and DWC files\n\n");
        exit(1);
		}
	firstchar = (char *) malloc(1);

	for (i=1; i<argc; i++) {
		strcpy(apath,argv[i]);
		result = strrchr(apath,'\\');
		if (result != NULL)
			*++result = '\0';
		else {
			result = strrchr(apath,':');
			if (result !=NULL)
				*++result = '\0';
			else
				apath[0] = '\0';
			}
		if (strncmp(argv[i],".",1)==0)
			strcpy(argv[i],"*.*");
        done = findfirst(argv[i],&ffblk,0);
		while (done == 0) {
			strcpy(name,apath);
			strcat(name,ffblk.ff_name);
            infile = open(name,O_RDONLY|O_BINARY);
            if (infile > 0)
				success = read(infile,firstchar,1);
			close(infile);
			firstchar[0] = toupper(firstchar[0]);
			if (firstchar[0] == 0x1a)
				success = lstarc(name);
			else if (firstchar[0] == 'Z')
                success = do_zoo(name);
			else success = read_dwc(name);
            if (success<0)
                printf("\n%s Not an archive file\n\n",name);
            done = findnext(&ffblk);
            }		/* end of findfirst/findnext loop */
		}		/* end of for loop */
	free(firstchar);
	exit(0);
}

/* ====================================================================
 * start a new screen full while listing the contents of an arc file
 * ====================================================================
 */
arc_header(char *packer,char *name)

{
	printf("\n %s  Contents of %s\n",packer,name);
	printf("Filename        Length   Method     Size   Ratio    Date      Time    CRC\n");
	printf("--------        ------   ------    ------  -----    ----      ----    ---\n");
	return;
}

/* ====================================================================
 * start of list arc contents processing
 * ====================================================================
 */
int lstarc(char *arcname)		/* list files in archive */
{
	struct 	heads *hdr;		/* header data */
	int 	totmbrs;		/* total members in arc */
	long	totlen;			/* total of file lengths */
	long	totsize;		/* total of file sizes */
	long	totsf;
	int	    ver;
    long    new_pos;
    register int done;		/* result */
	FILE 	 *arc;			/* archive file */
    char    date[9];
    char    time[9];
    char    method[11];

	totmbrs = totlen = totsize = 0L;	/* reset totals */

    hdr = (struct heads *) malloc(sizeof(struct heads));

    if((arc=fopen(arcname,"rb")) == NULL ) {
    	perror("  Cannot read archive: ");
	    return(-1);
        }
    done = fseek(arc,1L,SEEK_SET);
    ver = fgetc(arc);
    arc_header("ARC/PAK",arcname);
    while (ver > 0 && ver < 11) {
        done = fread(hdr,sizeof(struct heads),1,arc);
        totlen += hdr->mbrlen;
        totsize += hdr->mbrsize;
        totmbrs++;
        sprintf(date,"%02d-%02d-%02d",
			((hdr->mbrdate >> MONTH_SHIFT) & MONTH_MASK),
				(hdr->mbrdate & DAY_MASK),
					((hdr->mbrdate >> YEAR_SHIFT) + DOS_EPOCH));

		sprintf(time,"%02d:%02d:%02d",((hdr->mbrtime >> 11) & 0x1f),
			((hdr->mbrtime >> 5) & 0x3f),(hdr->mbrtime &0x1f)*2);
        switch(ver) {
			case 1:	strcpy(method,"    --    ");	/* 1 - old, no compression */
                    break;
			case 2: strcpy(method,"  Stored  ");	/* 2 - new, no compression */
                    break;
			case 3: strcpy(method,"  Packed  ");	/* 3 - dle for repeat chars */
                    break;
			case 4: strcpy(method," Squeezed ");	/* 4 - huffman encodeing */
                    break;
			case 5: strcpy(method," Crunched ");	/* 5 - lz, no dle */
                    break;
			case 6: strcpy(method," Crunched ");	/* 6 - lz with dle */
                    break;
			case 7: strcpy(method," Crunched ");	/* 7 - lz with readjust */
                    break;
			case 8: strcpy(method," Crunched ");	/* 8 - lz with readjust and dle */
                    break;
			case 9: strcpy(method," Squashed ");	/* 9 - modified lzw, no dle */
                    break;
			case 10: strcpy(method,"  Crushed ");    /* PAK's new method */
                        break;
			default: strcpy(method," Unknown! ");/* future? */
                    break;
             }		/* End of version switch */
		one_line(hdr->mbrname,hdr->mbrlen,hdr->mbrsize,method,date,time,hdr->mbrcrc);
		done = fseek(arc,hdr->mbrsize+1L,SEEK_CUR);
        ver = fgetc(arc);
        };		/* End of while loop */
	fclose(arc);		/* then close it */
	totsf = 0L;
	if(totlen>0L)
		totsf = (int)(100L - ((100L*totsize)/totlen));
	printf("----\t\t------\t\t   ------  -----\n");
	printf("Total %6d  %8ld  ",totmbrs,totlen);
	printf("\t %8ld   %3d%%\n",totsize,totsf);
	free(hdr);
    return(0);
}

/* Handle a ZOO archive */

int do_zoo(char *filename)
{
	FILE	*fhandle;
	struct	zoo_header	*main_head;
	struct	direntry	*one_head;
	int 	result;
	long		moving;
    unsigned    totmbr=0;		/* number of members in Zoo */
    long    totlen=0L;		/* total of all file sizes */
    long    totsize = 0L;
	int     totsf;
	char	method[11];
	char	time[9];
	char	date[9];

	main_head = (struct zoo_header *) malloc(sizeof(struct zoo_header));
	one_head = (struct direntry *) malloc(sizeof(struct direntry));

	fhandle = fopen(filename,"rb");
	result = fread(main_head,sizeof(struct zoo_header),1,fhandle);
	if ((strnicmp(main_head->text,"ZOO",3)) != 0) {
		printf("  Not a Zoo archive!  ");
		fclose(fhandle);
		return(-1);
		}
    arc_header("ZOO",filename);
	moving = fseek(fhandle,main_head->zoo_start,SEEK_SET);
	result = fread(one_head,sizeof(struct direntry),1,fhandle);
	do {
		if (result == 1) {
            totmbr++;
            totsize += one_head->org_size;
            totlen += one_head->size_now;
            switch(one_head->packing_method) {
                case 0:
                            strcpy(method,"  Stored  ");
                            break;
                case 1:
                            strcpy(method," Norm LZW ");
                            break;
                default:
                            strcpy(method,"  Unknown ");
                            break;
                }
            sprintf(date,"%02d-%02d-%02d",
				((one_head->date >> MONTH_SHIFT) & MONTH_MASK),
                    (one_head->date & DAY_MASK),
						((one_head->date >> YEAR_SHIFT) + DOS_EPOCH));

            sprintf(time,"%02d:%02d:%02d",((one_head->time >> 11) & 0x1f),
				((one_head->time >> 5) & 0x3f),(one_head->time &0x1f)*2);

			one_line(one_head->fname,one_head->org_size,one_head->size_now,
				method,date,time,one_head->dir_crc);

			moving = fseek(fhandle,one_head->next,SEEK_SET);
			}
		result = fread(one_head,sizeof(struct direntry),1,fhandle);
		} while ((one_head->offset != 0L) &&
			(result == 1));
    free(one_head);
	free(main_head);
    result = fclose(fhandle);
    if (totlen>0)
        totsf=(int)(100L - ((100L*totlen)/totsize));
    else
        totsf = 0;
    printf("----\t\t------\t\t   ------  -----\n");
    printf("Total %6d  %8ld  ",totmbr,totlen);
	printf("\t %8ld   %3d%%\n",totsize,totsf);
    return(0);
}

/* Read a DWC archive. These are the hardest ones to get into. */

int read_dwc(char *name)
{
	long	size;
	int		infile;
	unsigned	int		result;
	struct	dwc_entry	*one_entry;
	struct	dwc_arc	*one_archive;
    struct  tm *t;
	char	junkbuffer[256];
	char	*dwc;
	unsigned int	junkoffset;
	int		count;  /* total number of files in this archive */
    long    totsize = 0L;
    long    totlen = 0L;
    int     totmbr = 0;
    int     totsf;
    char    date[9];
    char    time[9];
    char    method[11];

	if((infile = open(name,O_BINARY|O_RDONLY)) < 0) {
		printf("Couldn't open file %s\n",name);
		return(-1);
		}
	one_entry = (struct dwc_entry *) malloc(sizeof(struct dwc_entry));
	one_archive = (struct dwc_arc *) malloc(sizeof(struct dwc_arc));
	count = 0;
	do {
        totlen = (long) (++count * sizeof(junkbuffer));
		size = lseek(infile,-totlen,SEEK_END);
        if (size > 0L)
    		result = read(infile,junkbuffer,sizeof(junkbuffer));
        else result = 0;
		} while (result == sizeof(junkbuffer) &&
			((dwc = memrstr(junkbuffer,"DWC",result)) == NULL));

	if (result < sizeof(junkbuffer)) { /* Failed to find "DWC", not DWC file */
        close (infile);
        free(one_archive);
        free(one_entry);
		return(-1);
        }
	junkoffset = count * sizeof(junkbuffer)  /* start of this buffer block */
		- (dwc-junkbuffer)  /* minus the offset to the "DWC" in the buffer */
		+ sizeof(struct dwc_arc) - 3;
	size = lseek (infile,-(long)junkoffset,SEEK_END);
	result = read(infile,one_archive,sizeof(struct dwc_arc));
	if (one_archive->size != sizeof(struct dwc_arc)) {
		close(infile);
		free(one_archive);
		free(one_entry);
		return(-1);
		}
	arc_header("DWC",name);
	count = (int) one_archive->entries;
    totmbr = count;
    totlen = 0L;
	size = lseek(infile,-(long)(count*one_archive->ent_sz+junkoffset),SEEK_END);
	while (count>0) {
		result = read(infile,one_entry,sizeof(struct dwc_entry));
        totsize += one_entry->size;
        totlen += one_entry->new_size;
        switch(one_entry->method) {
            case 0:
						strcpy(method,"  Stored  ");
                        break;
            case 1:
						strcpy(method," Norm LZW ");
                        break;
            default:
						strcpy(method,"  Unknown ");
                        break;
            }
        totsf = 0;
        t = localtime(&one_entry->time);
        sprintf(time,"%02d-%02d-%02d",
            (t->tm_mon+1),t->tm_mday,t->tm_year);

        sprintf(date,"%02d:%02d:%02d",
            t->tm_hour,t->tm_min,t->tm_sec);

        one_line(one_entry->name,one_entry->size,one_entry->new_size,
			method,time,date,one_entry->crc);
		count--;
		};
    close (infile);
    free(one_archive);
    free(one_entry);
    if (totlen>0)
        totsf=(int)(100L - ((100L*totlen)/totsize));
    else
        totsf = 0;
    printf("----\t\t------\t\t   ------  -----\n");
    printf("Total %6d  %8ld  ",totmbr,totlen);
	printf("\t %8ld   %3d%%\n",totsize,totsf);
	return(0);
}

/* memrstr searches backwards through a chunk of memory called "buffer"     */
/* that is "buflen" long, looking for a string "target". The search is from */
/* the end of "buffer" forward. It returns a pointer to the start of the    */
/* target string                                                            */

char *memrstr(char *buffer,char *target,int buflen)
{

	char	c = ' ';
	char	*ptr;
	int		found = 1;

	c = target[strlen(target)-1];
	ptr = buffer+buflen;
	do {
		if (c != *ptr)
			ptr--;
		else {
			ptr -= strlen(target)-1;
			found = strnicmp(target,ptr,sizeof(target));
			if (found != 0)
				ptr += strlen(target) - 2;
			}
		if (ptr < buffer)
			ptr = NULL;
		} while (found !=0 && ptr != NULL);
	return(ptr);
}

one_line(char *name,long org_len,long new_len,char *pack,char *date,char *time,int crc)
{
    int     factor;

    if (new_len > 0)
        factor = (100 * new_len)/org_len;

	printf("%-12s  %8ld %10s%8ld   %3d%%",name,org_len,pack,new_len,factor);
	printf("  %8s  %8s  %04X\n",date,time,crc);
    return;
}
