home *** CD-ROM | disk | FTP | other *** search
- /*
- PAKSORTM.C Sort contents of .ARC archive.
- Copyright 1989 by Jeffrey J. Nonken
- Released to public domain.
-
- Modified from PAKSORT.C: Copyright 1988, Michael J. Housky
- Released to the Public Domain ... *no* rights reserved.
-
- I ripped off Mike's code from the stand-alone program PAKSORT in
- order to include it into PolyXarc as a module. The only changes I
- made were: stripped the main() function out, removed the order[]
- variable and hard-coded the sort order, and added code to record
- the highest compression type value (so I can tell whether to use
- ARCE, PKUNPAK, or PAK) to discombobulate. I also now allocate the
- buffer, rather than having a fixed buffer size.
- */
-
- /*
- Update log:
-
- 12 May 1991: Separated header errors from open/read errors; header
- errors now return 6 instead of 1 so we know that we can rename
- them and go on if we're doing bundles.
- 18 September 1990: added support for type 1 headers (which are 4 bytes
- shorter than all other header types); added support for version 6
- archives. Version 6 archives have some advanced stuff that version
- 5 archives don't have, and some of it is position dependent, so we
- WON'T sort version 6 archives. Since PKPAK never got past version 5
- headers, that's not a problem. Type 1 headers are considered obsolete,
- but I wouldn't want this to bomb for such a stupid reason. Removed
- .olen from the local header stuff; it's not used for anything once
- we've tested the header for validity. jjn
- 22 March 1990: added Amiga stuff. jjn & smp
- 14 November 1989: modified from PAKSORT.C. jjn
-
- PAKSORT.C update log:
- Version 1.1, 24 January 1989: changed default extension .PAK to .ARC. jjn
- Version 1.0, 25 August 1988: First version.
- */
-
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #ifndef AMIGA
- # include <io.h>
- #endif
-
- #ifdef AMIGA
- #define _NEAR_
- #endif
-
- #ifdef TURBOC
- #define _NEAR_
- #endif
-
- #ifdef MSC
- #include <malloc.h>
- #define _NEAR_ near
- #endif
-
-
- #include "p_common.h"
- #include "pakmdefn.h"
-
- #define MAX_BUFSIZE 32760
-
- typedef struct /* stored directory format: */
- {
- int32 floc; /* byte location of header in file */
- int32 slen; /* stored (packed) length of file */
- /* int32 olen; * original (unpacked) length of file */
- word16 ddate; /* DOS date of update */
- word16 dtime; /* DOS time of update */
- char fname[13]; /* filename */
- unsigned char type; /* Header type. */
- } pak_dir;
-
- /* ------------ Global data: */
-
-
- byte * _NEAR_ pak_buf; /* buffer for reading pakfile data */
- pak_hdr _NEAR_ fhdr; /* buffer for reading pakfile header */
- long _NEAR_ pakloc; /* location in input file */
- long _NEAR_ pakloc,
- _NEAR_ paklen; /* length of input file */
- int _NEAR_ memory;
- int16 _NEAR_ highest_type;
- int16 _NEAR_ version6; /* True if version 6 header. */
-
- extern int _NEAR_ quiet;
-
-
-
- /*****************************************************************************
- This will turn an Intel-format integer into a Motorola-format integer.
- *****************************************************************************/
- #ifdef MOTOROLA
- void swap_Intel(char *address, int numbytes)
- {
- register int i; /* Ascending index. */
- register int j; /* Descending index. */
- char c; /* Temporary storage for the swap. */
-
- for (i = 0, j = numbytes - 1; i < j; ++i, --j)
- {
- c = address[i];
- address[i] = address[j];
- address[j] = c;
- }
- }
- #endif
-
- /*
- read_pakhdr: Read header of .ARC member file
-
- Reads next header sequentially from file.
-
- Returns 0 if good header, and global fhdr has header.
- Returns +1 if end of file marker found.
- Returns -1 if bad header or read error.
-
- */
-
- int read_pakhdr(FILE *fp)
- {
- register int i;
-
- i = fgetc(fp); /* get file marker */
- if ( i != PAK_MARK ) /* error if not correct */
- return -1;
-
- i = fread( (char*)&fhdr, 1, PAK_HDRLEN, fp );
- /* read header, follows mark */
- #ifdef MOTOROLA
- swap_Intel((char *)&fhdr.slen ,sizeof(fhdr.slen) );
- swap_Intel((char *)&fhdr.ddate,sizeof(fhdr.ddate));
- swap_Intel((char *)&fhdr.dtime,sizeof(fhdr.dtime));
- swap_Intel((char *)&fhdr.crc ,sizeof(fhdr.crc) );
- swap_Intel((char *)&fhdr.olen ,sizeof(fhdr.olen) );
- #endif
-
- if ( i>=1 && fhdr.type==0 ) /* type 0 header is an EOF mark */
- return 1; /* end of file mark seen */
-
- if (fhdr.type == 1) /* Header type 1 is 4 bytes short. */
- {
- fhdr.olen = fhdr.slen; /* Use the stored length. */
- fseek(fp,-4l,1); /* Seek relative backwards by 4. */
- }
-
- if ( i!=PAK_HDRLEN || fhdr.slen<0L)
- return -1; /* invalid header seen */
-
- if (fhdr.type < 20 && fhdr.olen < fhdr.slen)
- return -1; /* invalid header seen */
-
- pakloc = ftell(fp); /* note start of data and test */
- if ( pakloc+fhdr.slen > paklen ) /* for all data present */
- return -1; /* no: presume truncated file */
- return 0;
-
- } /* read_pakhdr */
-
-
- /*
- pak_getdir: Build directory of .ARC file headers.
-
- Sequentially read and validate all headers within pakfile. Build malloc-ed
- table of headers found.
-
- Returns:
- 0 = success, *pdirp = pointer to malloc-ed directory.
- 1 = out of memory;
- -1 = read/seek error or bad header.
- */
-
- int pak_getdir( FILE *fp, pak_dir **pdirp )
- {
- register int i;
- int n,k;
- long hdrloc;
- pak_dir *pd;
-
- /* Read the first header: */
-
- highest_type = 0; /* Init the highest compression type. */
- version6 = FALSE; /* Haven't found version 6 stuff yet. */
- hdrloc = ftell(fp);
-
- i = read_pakhdr(fp); /* Get the first header. */
- if ( i )
- {
- printf("Invalid header seen.\n");
- return -1;
- }
-
- pd = (pak_dir*) malloc( (k=32)*sizeof(pak_dir) );
- if ( pd==NULL )
- {
- printf("Out of memory.\n");
- memory = 1;
- return -1; /* out of memory error */
- }
- n = 0;
-
- do /* loop once for each new entry found, with */
- { /* n=#headers found, k=directory size */
-
- if ( n >= k ) /* test for current table full */
- {
- /* add 10 more entries to directory: */
- pd = (pak_dir*) realloc( (char*)pd, (k+=16)*sizeof(pak_dir) );
- if ( pd==NULL )
- {
- printf("Out of memory.\n");
- memory = 1;
- return -1; /* out of memory error */
- }
- }
-
- if (fhdr.type < 20)
- {
- if (fhdr.type > (char)highest_type)
- highest_type = fhdr.type;
- }
- else
- version6 = TRUE;
- pd[n].type = fhdr.type; /* Copy header type. */
- pd[n].floc = hdrloc; /* store header location */
- pd[n].slen = fhdr.slen; /* copy stored length */
- /* pd[n].olen = fhdr.olen; * copy original length */
- pd[n].ddate = fhdr.ddate; /* copy DOS date */
- pd[n].dtime = fhdr.dtime; /* copy DOS time */
- strcpy(pd[n].fname,fhdr.fname); /* copy file name */
- ++n; /* and increment file count */
-
- hdrloc += fhdr.slen+PAK_HDRLEN+1;
- if (fhdr.type == 1) /* Type 1 header is shorter! */
- hdrloc -= 4; /* If type 1, reduce by 4. */
-
- i = fseek( fp, hdrloc, SEEK_SET );
- if ( i )
- {
- printf("Seek error.\n");
- free( (char*)pd );
- return -1;
- }
-
- i = read_pakhdr(fp);
-
- } while ( i==0 );
-
- if ( i<0 ) /* test for error */
- {
- printf("Invalid header seen.\n");
- free( (char*)pd );
- return -1;
- }
- *pdirp = pd;
- return n;
-
- } /* pak_getdir */
-
-
- /*
- dir_cmp: Directory entry compare function for sort.
-
- Input:
- lp: pointer to "left" entry
- rp: pointer to "right" entry
- Return:
- 0 if entries are equal
- positive if left "greater than" right
- negative if left "less than" right
- */
-
- int dir_cmp(pak_dir *lp, pak_dir *rp)
- {
- register int j;
-
- /* compare unsigned date: */
- j = (lp->ddate > rp->ddate) - (lp->ddate < rp->ddate);
- if (!j)
- /* compare unsigned time: */
- j = (lp->dtime > rp->dtime) - (lp->dtime < rp->dtime);
- if (!j)
- /* compare full fileid */
- j = strcmp( lp->fname, rp->fname );
- return j;
-
- } /* dir_cmp */
-
-
- /*
- pak_sort: Sort one .ARC file.
-
- A simple (slow, but small and sure) routine is used here to
- sort the directory without the overhead of qsort and recursion.
-
- If this sort is replaced with an unstable sort (like quicksort) then
- the dir_cmp function should be changed to return compare of original
- file location if all fields compare equal. This will preserve
- sort stability ... i.e. input order is preserved on equal entries.
-
- Return value is 0 if all files were originally in order,
- or 1 if output order is different from input order.
-
- */
-
- int pak_sort( pak_dir *pdir, int n)
- {
- register int i,j;
- int i0,j0,k,r;
- pak_dir tdir;
-
- r = 0;
- for ( j0=1; j0<n; ++j0 )
- {
- i = i0 = j0-1; /* starting entry # to compare */
- for ( j=j0; j<n; ++j )
- {
- k = dir_cmp( pdir+i, pdir+j);
- if ( k>0 )
- { /* out of order */
- i = j; /* will swap at end */
- }
- }
- if ( i != i0 ) /* if out of order */
- {
- tdir = pdir[i]; /* swap smallest entry */
- pdir[i] = pdir[i0]; /* (at most n-1 times) */
- pdir[i0] = tdir;
- r = 1; /* tell caller that input was */
- /* not in order */
- }
- }
- return r;
-
- } /* pak_sort */
-
-
- /*
- pak_write: Copy packed source files to dest in sorted order.
- */
-
- int pak_write( FILE *src, FILE *dst, pak_dir* dirp, int n )
-
- /* FILE *src; * opened source file */
- /* FILE *dst; * opened dest file */
- /* pak_dir *dirp; * sorted directory of source */
- /* int n; * number of entries in source directory */
- {
- register int i,j;
- int k;
- int buf_size;
- long len,start,end;
-
- buf_size = MAX_BUFSIZE;
- do
- {
- pak_buf = malloc(buf_size);
- if (pak_buf == NULL)
- buf_size >>= 1;
- } while (pak_buf == NULL && buf_size > 0);
- if (pak_buf == NULL)
- {
- printf("Out of memory.\n");
- memory = 1;
- return -1;
- }
-
- for ( i=0; i<n; ++i )
- { /* once for each member file */
-
- len = dirp[i].slen + 1 +
- ((1 == dirp[i].type) ? (PAK_HDRLEN - 4) : PAK_HDRLEN);
-
- if (!quiet)
- {
- printf(" Copying: %-13s - loc=%-6ld len=%-6ld\n",
- dirp[i].fname,
- dirp[i].floc,
- len);
- }
-
- /* point to start of member, test for error: */
- j = fseek(src, dirp[i].floc, SEEK_SET);
- if ( j )
- {
- printf("Seek error.\n");
- free(pak_buf);
- return -1;
- }
-
- /* copy member to destination: */
- for ( end=0; end<len; )
- {
- start = end;
- end = start+(k=buf_size);
- if (end>len)
- k = (int)((end=len)-start);
- j = fread( pak_buf, 1, k, src );
- if ( j != k )
- {
- printf("Read error.\n");
- free(pak_buf);
- return -1;
- }
- j = fwrite( pak_buf, 1, k, dst );
- if ( j != k )
- {
- printf("Write error.\n");
- free(pak_buf);
- return -1;
- }
- }
- }
-
- free(pak_buf);
- /* Add EOF mark to (end of) destination: */
- fputc( PAK_MARK, dst );
- fputc( '\0', dst );
- if ( ferror(dst) )
- {
- printf("Write error.\n");
- return -1;
- }
-
- return 0;
-
- } /* pak_write */
-
-
-
- /*
- pak_dosort: Read/sort/rewrite one .ARC file.
-
- Returns 0 if successful, or error:
- 1 = Can't open/read source. (missing pakfile or DOS error)
- 2 = Can't create/write dest. (maybe disk or directory full)
- 3 = Can't delete old source file. (read-only)
- 4 = Can't rename temp file to source name. (DOS error)
- 5 = Out of memory.
- 6 = Invalid pakfile. (Header error)
- */
-
- int pak_dosort(char *fpath, char *fn, int sort)
- {
- register int i,j;
- int n;
- pak_dir *pdir; /* pointer to (malloced) directory */
- /* built by pak_getdir */
- FILE *src; /* source file */
- FILE *dst; /* source file */
- char *fnptr; /* location of filename in fname */
-
- #ifdef AMIGA
- char srcname[108];
- char fname[108];
- #else
- char srcname[64]; /* save source filename */
- char fname[64];
- #endif
- memory = 0;
- strcpy(fname,fpath);
- fnptr = fname + strlen(fname);
- strcpy(fnptr,fn); /* make full path to file */
- if (!quiet)
- printf("Searching: %s\n",fname); /* and identify */
- src = fopen( fname, "rb" ); /* and open file */
- if ( src==NULL )
- {
- printf("Can't open %s.\n", fname);
- return 1;
- }
- #ifdef AMIGA
- fseek (src, 0L, SEEK_END);
- paklen = ftell(src);
- fseek (src, 0L, SEEK_SET);
- #else
- paklen = filelength(fileno(src)); /* get file length in global */
- #endif
- pdir = NULL; /* clear directory pointer */
- n = pak_getdir( src, &pdir ); /* get directory */
- if (memory)
- return 5;
- if ( n<1 )
- {
- printf("Invalid file format, not changed.\n");
- fclose(src);
- return 6;
- }
- if (version6 || !sort) /* Don't sort if version 6 format. */
- {
- free( (char*)pdir );
- fclose(src); /* unconditionally close source */
- return 0;
- }
-
- i = pak_sort( pdir, n);
- if ( i==0 )
- {
- printf("Already in order, not changed.\n");
- free( (char*)pdir );
- fclose(src); /* unconditionally close source */
- return 0;
- }
-
- /* pakfile is not in order, create sorted copy & rename: */
-
- strcpy( srcname, fname );
- strcpy( fnptr, "PAKSRTMP.$$$" );
- dst = fopen( fname, "wb" );
- if ( dst==NULL )
- {
- printf("Can't create: %s\n", fname );
- free( (char*)pdir );
- return 1;
- }
-
- j = pak_write( src, dst, pdir, n ); /* copy source to dest tempfile */
- fclose(src); /* unconditionally close source */
- free( (char*)pdir ); /* and release directory mem */
- i = fclose(dst); /* close dest file */
-
- if ( j || i ) /* if error on write or close */
- {
- if ( !j ) /* identify close error */
- printf("Can't close: %s\n",fname);
- unlink(fname);
- return 2;
- }
-
- j = unlink(srcname); /* delete source */
- if ( j )
- { /* can't delete, read-only? */
- printf( "Can't delete original.\n");
- unlink(fname); /* delete sorted temp copy */
- return 3; /* return error */
- }
- j = rename( fname, srcname );
- if ( j )
- {
- printf("Rename error: %d, original unsorted data lost!\n");
- printf("Sorted data retained in temp output file for recovery:\n");
- printf("%s\n",fname);
- return 4;
- }
-
- return 0;
-
- } /* pak_dosort */