duke3d/buildengine/cache1d.c

986 lines
26 KiB
C
Raw Normal View History

/*
* "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
* Ken Silverman's official web site: "http://www.advsys.net/ken"
* See the included license file "BUILDLIC.TXT" for license info.
* This file has been modified from Ken Silverman's original release
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "platform.h"
#include "display.h"
#include "pragmas.h"
#include "cache1d.h"
#if (defined USE_PHYSICSFS)
#include "physfs.h"
#endif
/*
* This module keeps track of a standard linear cacheing system.
* To use this module, here's all you need to do:
*
* Step 1: Allocate a nice BIG buffer, like from 1MB-4MB and
* Call initcache(long cachestart, long cachesize) where
*
* cachestart = (long)(pointer to start of BIG buffer)
* cachesize = length of BIG buffer
*
* Step 2: Call allocache(long *bufptr, long bufsiz, char *lockptr)
* whenever you need to allocate a buffer, where:
*
* *bufptr = pointer to 4-byte pointer to buffer
* Confused? Using this method, cache2d can remove
* previously allocated things from the cache safely by
* setting the 4-byte pointer to 0.
* bufsiz = number of bytes to allocate
* *lockptr = pointer to locking char which tells whether
* the region can be removed or not. If *lockptr = 0 then
* the region is not locked else its locked.
*
* Step 3: If you need to remove everything from the cache, or every
* unlocked item from the cache, you can call uninitcache();
* Call uninitcache(0) to remove all unlocked items, or
* Call uninitcache(1) to remove everything.
* After calling uninitcache, it is still ok to call allocache
* without first calling initcache.
*/
#define MAXCACHEOBJECTS 9216
static long cachesize = 0;
long cachecount = 0;
unsigned char zerochar = 0;
long cachestart = 0, cacnum = 0, agecount = 0;
typedef struct { long *hand, leng; unsigned char *lock; } cactype;
cactype cac[MAXCACHEOBJECTS];
static long lockrecip[200];
void initcache(long dacachestart, long dacachesize)
{
long i;
for(i=1;i<200;i++) lockrecip[i] = (1<<28)/(200-i);
cachestart = dacachestart;
cachesize = dacachesize;
cac[0].leng = cachesize;
cac[0].lock = &zerochar;
cacnum = 1;
}
void allocache (long *newhandle, long newbytes, unsigned char *newlockptr)
{
long i, z, zz, bestz=0, daval, bestval, besto=0, o1, o2, sucklen, suckz;
newbytes = ((newbytes+15)&0xfffffff0);
if ((unsigned)newbytes > (unsigned)cachesize)
{
printf("Cachesize: %ld\n",cachesize);
printf("*Newhandle: 0x%x, Newbytes: %ld, *Newlock: %d\n",(unsigned int)newhandle,newbytes,*newlockptr);
reportandexit("BUFFER TOO BIG TO FIT IN CACHE!\n");
}
if (*newlockptr == 0)
{
reportandexit("ALLOCACHE CALLED WITH LOCK OF 0!\n");
}
/* Find best place */
bestval = 0x7fffffff; o1 = cachesize;
for(z=cacnum-1;z>=0;z--)
{
o1 -= cac[z].leng;
o2 = o1+newbytes; if (o2 > cachesize) continue;
daval = 0;
for(i=o1,zz=z;i<o2;i+=cac[zz++].leng)
{
if (*cac[zz].lock == 0) continue;
if (*cac[zz].lock >= 200) { daval = 0x7fffffff; break; }
daval += (long) mulscale32(cac[zz].leng+65536,lockrecip[*cac[zz].lock]);
if (daval >= bestval) break;
}
if (daval < bestval)
{
bestval = daval; besto = o1; bestz = z;
if (bestval == 0) break;
}
}
/*printf("%ld %ld %ld\n",besto,newbytes,*newlockptr);*/
if (bestval == 0x7fffffff)
reportandexit("CACHE SPACE ALL LOCKED UP!\n");
/* Suck things out */
for(sucklen=-newbytes,suckz=bestz;sucklen<0;sucklen+=cac[suckz++].leng)
if (*cac[suckz].lock) *cac[suckz].hand = 0;
/* Remove all blocks except 1 */
suckz -= (bestz+1); cacnum -= suckz;
if (suckz != 0)
copybufbyte(&cac[bestz+suckz],&cac[bestz],(cacnum-bestz)*sizeof(cactype));
cac[bestz].hand = newhandle; *newhandle = cachestart+besto;
cac[bestz].leng = newbytes;
cac[bestz].lock = newlockptr;
cachecount++;
/* Add new empty block if necessary */
if (sucklen <= 0) return;
bestz++;
if (bestz == cacnum)
{
cacnum++; if (cacnum > MAXCACHEOBJECTS) reportandexit("Too many objects in cache! (cacnum > MAXCACHEOBJECTS)\n");
cac[bestz].leng = sucklen;
cac[bestz].lock = &zerochar;
return;
}
if (*cac[bestz].lock == 0) { cac[bestz].leng += sucklen; return; }
cacnum++; if (cacnum > MAXCACHEOBJECTS) reportandexit("Too many objects in cache! (cacnum > MAXCACHEOBJECTS)\n");
for(z=cacnum-1;z>bestz;z--) cac[z] = cac[z-1];
cac[bestz].leng = sucklen;
cac[bestz].lock = &zerochar;
}
void suckcache (long *suckptr)
{
long i;
/* Can't exit early, because invalid pointer might be same even though lock = 0 */
for(i=0;i<cacnum;i++)
if ((long)(*cac[i].hand) == (long)suckptr)
{
if (*cac[i].lock) *cac[i].hand = 0;
cac[i].lock = &zerochar;
cac[i].hand = 0;
/* Combine empty blocks */
if ((i > 0) && (*cac[i-1].lock == 0))
{
cac[i-1].leng += cac[i].leng;
cacnum--; copybuf(&cac[i+1],&cac[i],(cacnum-i)*sizeof(cactype));
}
else if ((i < cacnum-1) && (*cac[i+1].lock == 0))
{
cac[i+1].leng += cac[i].leng;
cacnum--; copybuf(&cac[i+1],&cac[i],(cacnum-i)*sizeof(cactype));
}
}
}
void agecache(void)
{
long cnt;
char ch;
if (agecount >= cacnum) agecount = cacnum-1;
assert(agecount >= 0);
for(cnt=(cacnum>>4);cnt>=0;cnt--)
{
ch = (*cac[agecount].lock);
if (((ch-2)&255) < 198)
(*cac[agecount].lock) = (unsigned char) (ch-1);
agecount--; if (agecount < 0) agecount = cacnum-1;
}
}
void reportandexit(char *errormessage)
{
long i, j;
setvmode(0x3);
j = 0;
for(i=0;i<cacnum;i++)
{
printf("%ld- ",i);
printf("ptr: 0x%lx, ",*cac[i].hand);
printf("leng: %ld, ",cac[i].leng);
printf("lock: %d\n",*cac[i].lock);
j += cac[i].leng;
}
printf("Cachesize = %ld\n",cachesize);
printf("Cacnum = %ld\n",cacnum);
printf("Cache length sum = %ld\n",j);
printf("ERROR: %s",errormessage);
exit(0);
}
#define MAXGROUPFILES 4 /* Warning: Fix groupfil if this is changed */
#define MAXOPENFILES 64 /* Warning: Fix filehan if this is changed */
#if (!defined USE_PHYSICSFS)
static unsigned char toupperlookup[256] =
{
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
};
static long numgroupfiles = 0;
static long gnumfiles[MAXGROUPFILES];
static long groupfil[MAXGROUPFILES] = {-1,-1,-1,-1};
static long groupfilpos[MAXGROUPFILES];
static char *gfilelist[MAXGROUPFILES];
static long *gfileoffs[MAXGROUPFILES];
static unsigned char filegrp[MAXOPENFILES];
static long filepos[MAXOPENFILES];
static long filehan[MAXOPENFILES] =
{
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};
#else
static PHYSFS_file *filehan[MAXOPENFILES] =
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
#endif
long initgroupfile(const char *filename)
{
#if (defined USE_PHYSICSFS)
static int initted_physfs = 0;
static int added_cwd = 0;
if (!initted_physfs)
{
if (!PHYSFS_init(_argv[0]))
return(-1);
initted_physfs = 1;
} /* if */
if (!added_cwd)
{
if (!PHYSFS_addToSearchPath(".", 0))
return(-1);
added_cwd = 1;
} /* if */
if (!PHYSFS_addToSearchPath(filename, 1))
return(-1);
return(1); /* uhh...? */
#else
char buf[16];
long i, j, k;
if (numgroupfiles >= MAXGROUPFILES) return(-1);
groupfil[numgroupfiles] = open(filename,O_BINARY|O_RDONLY,S_IREAD);
if (groupfil[numgroupfiles] < 0) {
fprintf(stderr, "Unable to open %s\n", filename);
exit(0);
} // if
else {
groupfilpos[numgroupfiles] = 0;
read(groupfil[numgroupfiles],buf,16);
if ((buf[0] != 'K') || (buf[1] != 'e') || (buf[2] != 'n') ||
(buf[3] != 'S') || (buf[4] != 'i') || (buf[5] != 'l') ||
(buf[6] != 'v') || (buf[7] != 'e') || (buf[8] != 'r') ||
(buf[9] != 'm') || (buf[10] != 'a') || (buf[11] != 'n'))
{
close(groupfil[numgroupfiles]);
groupfil[numgroupfiles] = -1;
return(-1);
}
gnumfiles[numgroupfiles] = BUILDSWAP_INTEL32(*((long *)&buf[12]));
if ((gfilelist[numgroupfiles] = (char *)kmalloc(gnumfiles[numgroupfiles]<<4)) == 0)
{ printf("Not enough memory for file grouping system\n"); exit(0); }
if ((gfileoffs[numgroupfiles] = (long *)kmalloc((gnumfiles[numgroupfiles]+1)<<2)) == 0)
{ printf("Not enough memory for file grouping system\n"); exit(0); }
read(groupfil[numgroupfiles],gfilelist[numgroupfiles],gnumfiles[numgroupfiles]<<4);
j = 0;
for(i=0;i<gnumfiles[numgroupfiles];i++)
{
k = BUILDSWAP_INTEL32(*((long *)&gfilelist[numgroupfiles][(i<<4)+12]));
gfilelist[numgroupfiles][(i<<4)+12] = 0;
gfileoffs[numgroupfiles][i] = j;
j += k;
}
gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j;
}
numgroupfiles++;
return(groupfil[numgroupfiles-1]);
#endif
}
void uninitgroupfile(void)
{
#if (defined USE_PHYSICSFS)
PHYSFS_deinit();
memset(filehan, '\0', sizeof (filehan));
#else
long i;
for(i=numgroupfiles-1;i>=0;i--)
if (groupfil[i] != -1)
{
kfree(gfilelist[i]);
kfree(gfileoffs[i]);
close(groupfil[i]);
groupfil[i] = -1;
}
#endif
}
#if (defined USE_PHYSICSFS)
static int locateOneElement(char *buf)
{
char *ptr;
char **rc;
char **i;
if (PHYSFS_exists(buf))
return(1); /* quick rejection: exists in current case. */
ptr = strrchr(buf, '/'); /* find entry at end of path. */
if (ptr == NULL)
{
rc = PHYSFS_enumerateFiles("/");
ptr = buf;
} /* if */
else
{
*ptr = '\0';
rc = PHYSFS_enumerateFiles(buf);
*ptr = '/';
ptr++; /* point past dirsep to entry itself. */
} /* else */
for (i = rc; *i != NULL; i++)
{
if (stricmp(*i, ptr) == 0)
{
strcpy(ptr, *i); /* found a match. Overwrite with this case. */
PHYSFS_freeList(rc);
return(1);
} /* if */
} /* for */
/* no match at all... */
PHYSFS_freeList(rc);
return(0);
} /* locateOneElement */
int PHYSFSEXT_locateCorrectCase(char *buf)
{
int rc;
char *ptr;
char *prevptr;
while (*buf == '/') /* skip any '/' at start of string... */
buf++;
ptr = prevptr = buf;
if (*ptr == '\0')
return(0); /* Uh...I guess that's success. */
while ((ptr = strchr(ptr + 1, '/')) != NULL)
{
*ptr = '\0'; /* block this path section off */
rc = locateOneElement(buf);
*ptr = '/'; /* restore path separator */
if (!rc)
return(-2); /* missing element in path. */
} /* while */
/* check final element... */
return(locateOneElement(buf) ? 0 : -1);
} /* PHYSFSEXT_locateCorrectCase */
#endif
long kopen4load(const char *filename, char searchfirst)
{
#if (defined USE_PHYSICSFS)
int i;
PHYSFS_file *rc;
char _filename[64];
assert(strlen(filename) < sizeof (_filename));
strcpy(_filename, filename);
PHYSFSEXT_locateCorrectCase(_filename);
rc = PHYSFS_openRead(_filename);
if (rc == NULL)
return(-1);
for (i = 0; i < MAXOPENFILES; i++)
{
if (filehan[i] == NULL)
{
filehan[i] = rc;
return(i);
}
}
PHYSFS_close(rc); /* oh well. */
return(-1);
#else
long i, j, k, fil, newhandle;
unsigned char bad;
char *gfileptr;
newhandle = MAXOPENFILES-1;
while (filehan[newhandle] != -1)
{
newhandle--;
if (newhandle < 0)
{
printf("TOO MANY FILES OPEN IN FILE GROUPING SYSTEM!");
exit(0);
}
}
if (searchfirst == 0)
if ((fil = open(filename,O_BINARY|O_RDONLY)) != -1)
{
filegrp[newhandle] = 255;
filehan[newhandle] = fil;
filepos[newhandle] = 0;
return(newhandle);
}
for(k=numgroupfiles-1;k>=0;k--)
{
if (searchfirst != 0) k = 0;
if (groupfil[k] != -1)
{
for(i=gnumfiles[k]-1;i>=0;i--)
{
gfileptr = (char *)&gfilelist[k][i<<4];
bad = 0;
for(j=0;j<13;j++)
{
if (!filename[j]) break;
if (toupperlookup[(int) filename[j]] != toupperlookup[(int) gfileptr[j]])
{ bad = 1; break; }
}
if (bad) continue;
filegrp[newhandle] = (unsigned char) k;
filehan[newhandle] = i;
filepos[newhandle] = 0;
return(newhandle);
}
}
}
return(-1);
#endif
}
long kread(long handle, void *buffer, long leng)
{
#if (defined USE_PHYSICSFS)
return(PHYSFS_read(filehan[handle], buffer, 1, leng));
return(leng);
#else
long i, filenum, groupnum;
filenum = filehan[handle];
groupnum = filegrp[handle];
if (groupnum == 255) return(read(filenum,buffer,leng));
if (groupfil[groupnum] != -1)
{
i = gfileoffs[groupnum][filenum]+filepos[handle];
if (i != groupfilpos[groupnum])
{
lseek(groupfil[groupnum],i+((gnumfiles[groupnum]+1)<<4),SEEK_SET);
groupfilpos[groupnum] = i;
}
leng = min(leng,(gfileoffs[groupnum][filenum+1]-gfileoffs[groupnum][filenum])-filepos[handle]);
leng = read(groupfil[groupnum],buffer,leng);
filepos[handle] += leng;
groupfilpos[groupnum] += leng;
return(leng);
}
return(0);
#endif
}
int kread16(long handle, short *buffer)
{
if (kread(handle, buffer, 2) != 2)
return(0);
*buffer = BUILDSWAP_INTEL16(*(unsigned short *)buffer);
return(1);
}
int kread32(long handle, long *buffer)
{
if (kread(handle, buffer, 4) != 4)
return(0);
*buffer = BUILDSWAP_INTEL32(*(unsigned long *)buffer);
return(1);
}
int kread8(long handle, char *buffer)
{
if (kread(handle, buffer, 1) != 1)
return(0);
return(1);
}
long klseek(long handle, long offset, long whence)
{
#if (defined USE_PHYSICSFS)
if (whence == SEEK_END) /* !!! FIXME: You can try PHYSFS_filelength(). */
{
printf("UNSUPPORTED SEEK SEMANTIC!\n");
exit(42);
} /* if */
if (whence == SEEK_CUR)
offset += PHYSFS_tell(filehan[handle]);
if (!PHYSFS_seek(filehan[handle], offset))
return(-1);
return(offset);
#else
long i, groupnum;
groupnum = filegrp[handle];
if (groupnum == 255) return(lseek(filehan[handle],offset,whence));
if (groupfil[groupnum] != -1)
{
switch(whence)
{
case SEEK_SET: filepos[handle] = offset; break;
case SEEK_END: i = filehan[handle];
filepos[handle] = (gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i])+offset;
break;
case SEEK_CUR: filepos[handle] += offset; break;
}
return(filepos[handle]);
}
return(-1);
#endif
}
long kfilelength(long handle)
{
#if (defined USE_PHYSICSFS)
return(PHYSFS_fileLength(filehan[handle]));
#else
long i, groupnum;
groupnum = filegrp[handle];
if (groupnum == 255) return(filelength(filehan[handle]));
i = filehan[handle];
return(gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i]);
#endif
}
void kclose(long handle)
{
#if (defined USE_PHYSICSFS)
if (filehan[handle] != NULL)
{
PHYSFS_close(filehan[handle]);
filehan[handle] = NULL;
} /* if */
#else
if (handle < 0) return;
if (filegrp[handle] == 255) close(filehan[handle]);
filehan[handle] = -1;
#endif
}
/* Internal LZW variables */
#define LZWSIZE 16384 /* Watch out for shorts! */
static char *lzwbuf1, *lzwbuf4, *lzwbuf5;
static unsigned char lzwbuflock[5];
static short *lzwbuf2, *lzwbuf3;
void kdfread(void *buffer, size_t dasizeof, size_t count, long fil)
{
size_t i, j;
long k, kgoal;
short leng;
char *ptr;
lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
if (lzwbuf1 == NULL) allocache((long *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
if (lzwbuf2 == NULL) allocache((long *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
if (lzwbuf3 == NULL) allocache((long *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
if (lzwbuf4 == NULL) allocache((long *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
if (lzwbuf5 == NULL) allocache((long *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
ptr = (char *)buffer;
kread16(fil,&leng); kread(fil,lzwbuf5,(long)leng);
k = 0;
kgoal = uncompress(lzwbuf5,(long)leng,lzwbuf4);
copybufbyte(lzwbuf4,ptr,(long)dasizeof);
k += (long)dasizeof;
for(i=1;i<count;i++)
{
if (k >= kgoal)
{
kread16(fil,&leng); kread(fil,lzwbuf5,(long)leng);
k = 0; kgoal = uncompress(lzwbuf5,(long)leng,lzwbuf4);
}
for(j=0;j<dasizeof;j++) ptr[j+dasizeof] = (unsigned char) ((ptr[j]+lzwbuf4[j+k])&255);
k += dasizeof;
ptr += dasizeof;
}
lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
}
void kdfread8(char *_buffer, size_t count, long fil)
{
kdfread(_buffer, 1, count, fil);
}
void kdfread16(short *_buffer, size_t count, long fil)
{
kdfread(_buffer, 2, count, fil);
#if PLATFORM_BIGENDIAN
{
int i;
unsigned short *buffer = (unsigned short *) _buffer;
for (i = 0; i < count; i++)
buffer[i] = BUILDSWAP_INTEL16(buffer[i]);
}
#endif
}
void kdfread32(long *_buffer, size_t count, long fil)
{
kdfread(_buffer, 4, count, fil);
#if PLATFORM_BIGENDIAN
{
int i;
unsigned long *buffer = (unsigned long *) _buffer;
for (i = 0; i < count; i++)
buffer[i] = BUILDSWAP_INTEL32(buffer[i]);
}
#endif
}
void dfread(void *buffer, size_t dasizeof, size_t count, FILE *fil)
{
size_t i, j;
long k, kgoal;
short leng;
char *ptr;
lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
if (lzwbuf1 == NULL) allocache((long *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
if (lzwbuf2 == NULL) allocache((long *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
if (lzwbuf3 == NULL) allocache((long *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
if (lzwbuf4 == NULL) allocache((long *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
if (lzwbuf5 == NULL) allocache((long *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
ptr = (char *)buffer;
fread(&leng,2,1,fil);
leng = BUILDSWAP_INTEL16(leng);
fread(lzwbuf5,(long)leng,1,fil);
k = 0; kgoal = uncompress(lzwbuf5,(long)leng,lzwbuf4);
copybufbyte(lzwbuf4,ptr,(long)dasizeof);
k += (long)dasizeof;
for(i=1;i<count;i++)
{
if (k >= kgoal)
{
fread(&leng,2,1,fil);
leng = BUILDSWAP_INTEL16(leng);
fread(lzwbuf5,(long)leng,1,fil);
k = 0; kgoal = uncompress(lzwbuf5,(long)leng,lzwbuf4);
}
for(j=0;j<dasizeof;j++) ptr[j+dasizeof] = (unsigned char) ((ptr[j]+lzwbuf4[j+k])&255);
k += dasizeof;
ptr += dasizeof;
}
lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
}
void dfread8(char *buffer, size_t count, FILE *fil)
{
dfread(buffer, 1, count, fil);
}
void dfread16(short *_buffer, size_t count, FILE *fil)
{
dfread(_buffer, 2, count, fil);
#if PLATFORM_BIGENDIAN
{
int i;
unsigned short *buffer = (unsigned short *) _buffer;
for (i = 0; i < count; i++)
buffer[i] = BUILDSWAP_INTEL16(buffer[i]);
}
#endif
}
void dfread32(long *_buffer, size_t count, FILE *fil)
{
dfread(_buffer, 4, count, fil);
#if PLATFORM_BIGENDIAN
{
int i;
unsigned long *buffer = (unsigned long *) _buffer;
for (i = 0; i < count; i++)
buffer[i] = BUILDSWAP_INTEL32(buffer[i]);
}
#endif
}
void dfwrite(void *buffer, size_t dasizeof, size_t count, FILE *fil)
{
size_t i, j, k;
short leng, byteswapped;
char *ptr;
lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200;
if (lzwbuf1 == NULL) allocache((long *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]);
if (lzwbuf2 == NULL) allocache((long *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]);
if (lzwbuf3 == NULL) allocache((long *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]);
if (lzwbuf4 == NULL) allocache((long *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]);
if (lzwbuf5 == NULL) allocache((long *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]);
if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; }
ptr = (char *)buffer;
copybufbyte(ptr,lzwbuf4,(long)dasizeof);
k = dasizeof;
if (k > LZWSIZE-dasizeof)
{
leng = (short)compress(lzwbuf4,k,lzwbuf5); k = 0;
byteswapped = BUILDSWAP_INTEL16(leng);
fwrite(&byteswapped,2,1,fil); fwrite(lzwbuf5,(long)leng,1,fil);
}
for(i=1;i<count;i++)
{
for(j=0;j<dasizeof;j++) lzwbuf4[j+k] = (unsigned char) ((ptr[j+dasizeof]-ptr[j])&255);
k += dasizeof;
if (k > LZWSIZE-dasizeof)
{
leng = (short)compress(lzwbuf4,k,lzwbuf5); k = 0;
byteswapped = BUILDSWAP_INTEL16(leng);
fwrite(&byteswapped,2,1,fil); fwrite(lzwbuf5,(long)leng,1,fil);
}
ptr += dasizeof;
}
if (k > 0)
{
leng = (short)compress(lzwbuf4,k,lzwbuf5);
byteswapped = BUILDSWAP_INTEL16(leng);
fwrite(&byteswapped,2,1,fil); fwrite(lzwbuf5,(long)leng,1,fil);
}
lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1;
}
void dfwrite8(char *_buffer, size_t count, FILE *fil)
{
dfwrite(_buffer, 1, count, fil);
}
void dfwrite16(short *_buffer, size_t count, FILE *fil)
{
#if PLATFORM_BIGENDIAN
unsigned short *buffer = (unsigned short *) _buffer;
int i;
for (i = 0; i < count; i++)
buffer[i] = BUILDSWAP_INTEL16(buffer[i]);
#endif
dfwrite(_buffer, 2, count, fil);
#if PLATFORM_BIGENDIAN
for (i = 0; i < count; i++)
buffer[i] = BUILDSWAP_INTEL16(buffer[i]);
#endif
}
void dfwrite32(long *_buffer, size_t count, FILE *fil)
{
#if PLATFORM_BIGENDIAN
unsigned long *buffer = (unsigned long *) _buffer;
int i;
for (i = 0; i < count; i++)
buffer[i] = BUILDSWAP_INTEL32(buffer[i]);
#endif
dfwrite(_buffer, 4, count, fil);
#if PLATFORM_BIGENDIAN
for (i = 0; i < count; i++)
buffer[i] = BUILDSWAP_INTEL32(buffer[i]);
#endif
}
long compress(char *lzwinbuf, long uncompleng, char *lzwoutbuf)
{
long i, addr, newaddr, addrcnt, zx, *longptr;
long bytecnt1, bitcnt, numbits, oneupnumbits;
short *shortptr;
for(i=255;i>=0;i--) { lzwbuf1[i] = (char) i; lzwbuf3[i] = (short) ((i+1)&255); }
clearbuf((void *) FP_OFF(lzwbuf2),256>>1,0xffffffff);
clearbuf((void *) FP_OFF(lzwoutbuf),((uncompleng+15)+3)>>2,0L);
addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3);
numbits = 8; oneupnumbits = (1<<8);
do
{
addr = lzwinbuf[bytecnt1];
do
{
bytecnt1++;
if (bytecnt1 == uncompleng) break;
if (lzwbuf2[addr] < 0) {lzwbuf2[addr] = (short) addrcnt; break;}
newaddr = lzwbuf2[addr];
while (lzwbuf1[newaddr] != lzwinbuf[bytecnt1])
{
zx = lzwbuf3[newaddr];
if (zx < 0) {lzwbuf3[newaddr] = (short) addrcnt; break;}
newaddr = zx;
}
if (lzwbuf3[newaddr] == addrcnt) break;
addr = newaddr;
} while (addr >= 0);
lzwbuf1[addrcnt] = lzwinbuf[bytecnt1];
lzwbuf2[addrcnt] = -1;
lzwbuf3[addrcnt] = -1;
longptr = (long *)&lzwoutbuf[bitcnt>>3];
*longptr = BUILDSWAP_INTEL32(*longptr); //convert to native format.
*longptr |= (addr<<(bitcnt&7)); // add new data.
*longptr = BUILDSWAP_INTEL32(*longptr); //convert back to littleendian
bitcnt += numbits;
if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
bitcnt--;
addrcnt++;
if (addrcnt > oneupnumbits) { numbits++; oneupnumbits <<= 1; }
} while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3)));
longptr = (long *)&lzwoutbuf[bitcnt>>3];
*longptr = BUILDSWAP_INTEL32(*longptr); //convert to native format.
*longptr |= (addr<<(bitcnt&7));
*longptr = BUILDSWAP_INTEL32(*longptr); //convert back.
bitcnt += numbits;
if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
bitcnt--;
shortptr = (short *)lzwoutbuf;
*shortptr = (short)uncompleng;
*shortptr = BUILDSWAP_INTEL16(*shortptr);
if (((bitcnt+7)>>3) < uncompleng)
{
shortptr[1] = (short)addrcnt;
shortptr[1] = BUILDSWAP_INTEL16(shortptr[1]);
return((bitcnt+7)>>3);
}
shortptr[1] = (short)0;
for(i=0;i<uncompleng;i++) lzwoutbuf[i+4] = lzwinbuf[i];
return(uncompleng+4);
}
long uncompress(char *lzwinbuf, long compleng, char *lzwoutbuf)
{
long strtot, currstr, numbits, oneupnumbits;
long i, dat, leng, bitcnt, outbytecnt, *longptr;
short *shortptr;
shortptr = (short *)lzwinbuf;
strtot = (long) BUILDSWAP_INTEL16(shortptr[1]);
if (strtot == 0)
{
copybuf((void *)(FP_OFF(lzwinbuf)+4),(void *)(FP_OFF(lzwoutbuf)),((compleng-4)+3)>>2);
return((long) BUILDSWAP_INTEL16(shortptr[0])); /* uncompleng */
}
for(i=255;i>=0;i--) { lzwbuf2[i] = (short) i; lzwbuf3[i] = (short) i; }
currstr = 256; bitcnt = (4<<3); outbytecnt = 0;
numbits = 8; oneupnumbits = (1<<8);
do
{
longptr = (long *)&lzwinbuf[bitcnt>>3];
dat = ((BUILDSWAP_INTEL32(longptr[0])>>(bitcnt&7)) & (oneupnumbits-1));
bitcnt += numbits;
if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1)))
{ dat &= ((oneupnumbits>>1)-1); bitcnt--; }
lzwbuf3[currstr] = (short) dat;
for(leng=0;dat>=256;leng++,dat=lzwbuf3[dat])
lzwbuf1[leng] = (char) lzwbuf2[dat];
lzwoutbuf[outbytecnt++] = (char) dat;
for(i=leng-1;i>=0;i--) lzwoutbuf[outbytecnt++] = lzwbuf1[i];
lzwbuf2[currstr-1] = (short) dat; lzwbuf2[currstr] = (short) dat;
currstr++;
if (currstr > oneupnumbits) { numbits++; oneupnumbits <<= 1; }
} while (currstr < strtot);
return((long) BUILDSWAP_INTEL16(shortptr[0])); /* uncompleng */
}