2006-04-23 06:44:19 +00:00
|
|
|
// "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
|
2012-03-12 04:47:04 +00:00
|
|
|
// by Jonathon Fowler (jf@jonof.id.au)
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
|
|
|
|
#ifdef CACHE1D_COMPRESS_ONLY
|
|
|
|
// Standalone libcache1d.so containing only the compression/decompression
|
|
|
|
// functions.
|
|
|
|
# include <stdint.h>
|
|
|
|
# include <stdio.h>
|
|
|
|
# include <string.h>
|
|
|
|
# include <stddef.h>
|
2013-12-01 18:27:57 +00:00
|
|
|
# include <assert.h>
|
2012-11-11 17:57:13 +00:00
|
|
|
|
|
|
|
# define BFILE FILE
|
|
|
|
# define C1D_STATIC
|
|
|
|
# define B_LITTLE16(x) (x)
|
|
|
|
# define B_LITTLE32(x) (x)
|
|
|
|
# define Bmemset memset
|
|
|
|
# define Bmemcpy memcpy
|
2013-12-01 18:27:57 +00:00
|
|
|
# define Bassert assert
|
2012-11-11 17:57:13 +00:00
|
|
|
# define bsize_t size_t
|
|
|
|
#else
|
|
|
|
// cache1d.o for EDuke32
|
|
|
|
# define C1D_STATIC static
|
|
|
|
|
2006-04-23 06:44:19 +00:00
|
|
|
#include "compat.h"
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
// for FILENAME_CASE_CHECK
|
|
|
|
# include <shellapi.h>
|
|
|
|
#endif
|
2006-04-23 06:44:19 +00:00
|
|
|
#include "cache1d.h"
|
|
|
|
#include "pragmas.h"
|
|
|
|
#include "baselayer.h"
|
2015-03-23 08:30:41 +00:00
|
|
|
#include "crc32.h"
|
2006-04-23 06:44:19 +00:00
|
|
|
|
|
|
|
#ifdef WITHKPLIB
|
|
|
|
#include "kplib.h"
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
//Insert '|' in front of filename
|
|
|
|
//Doing this tells kzopen to load the file only if inside a .ZIP file
|
2010-10-17 14:49:39 +00:00
|
|
|
static intptr_t kzipopen(const char *filnam)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
uint32_t i;
|
2009-07-29 21:56:56 +00:00
|
|
|
char newst[BMAX_PATH+8];
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
newst[0] = '|';
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=0; filnam[i] && (i < sizeof(newst)-2); i++) newst[i+1] = filnam[i];
|
2006-04-24 19:04:22 +00:00
|
|
|
newst[i+1] = 0;
|
2016-06-21 00:34:41 +00:00
|
|
|
return kzopen(newst);
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2015-05-03 07:04:11 +00:00
|
|
|
char *kpzbuf = NULL;
|
2015-05-27 08:47:03 +00:00
|
|
|
int32_t kpzbufsiz;
|
2015-05-03 07:04:11 +00:00
|
|
|
|
|
|
|
int32_t kpzbufloadfil(int32_t const handle)
|
|
|
|
{
|
|
|
|
int32_t const leng = kfilelength(handle);
|
|
|
|
if (leng > kpzbufsiz)
|
|
|
|
{
|
|
|
|
kpzbuf = (char *) Xrealloc(kpzbuf, leng+1);
|
|
|
|
kpzbufsiz = leng;
|
|
|
|
if (!kpzbuf)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
kpzbuf[leng] = 0; // FIXME: buf[leng] read in kpegrend(), see BUF_LENG_READ
|
|
|
|
kread(handle, kpzbuf, leng);
|
|
|
|
|
|
|
|
return leng;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t kpzbufload(char const * const filnam)
|
|
|
|
{
|
|
|
|
int32_t const handle = kopen4load(filnam, 0);
|
|
|
|
if (handle < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int32_t const leng = kpzbufloadfil(handle);
|
|
|
|
|
|
|
|
kclose(handle);
|
|
|
|
|
|
|
|
return leng;
|
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
|
|
|
|
// 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
|
2009-01-09 09:29:17 +00:00
|
|
|
// Call initcache(int32_t cachestart, int32_t cachesize) where
|
2006-04-23 06:44:19 +00:00
|
|
|
//
|
2008-02-16 22:27:08 +00:00
|
|
|
// cachestart = (intptr_t)(pointer to start of BIG buffer)
|
2006-04-23 06:44:19 +00:00
|
|
|
// cachesize = length of BIG buffer
|
|
|
|
//
|
2009-01-09 09:29:17 +00:00
|
|
|
// Step 2: Call allocache(intptr_t *bufptr, int32_t bufsiz, char *lockptr)
|
2006-04-23 06:44:19 +00:00
|
|
|
// whenever you need to allocate a buffer, where:
|
|
|
|
//
|
2008-02-16 22:27:08 +00:00
|
|
|
// *bufptr = pointer to multi-byte pointer to buffer
|
2006-04-23 06:44:19 +00:00
|
|
|
// Confused? Using this method, cache2d can remove
|
|
|
|
// previously allocated things from the cache safely by
|
2008-02-16 22:27:08 +00:00
|
|
|
// setting the multi-byte pointer to 0.
|
2006-04-23 06:44:19 +00:00
|
|
|
// 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
|
|
|
|
|
2014-01-12 14:54:33 +00:00
|
|
|
#if !defined DEBUG_ALLOCACHE_AS_MALLOC
|
2009-01-09 09:29:17 +00:00
|
|
|
static int32_t cachesize = 0;
|
2012-03-10 21:21:20 +00:00
|
|
|
static char zerochar = 0;
|
|
|
|
static intptr_t cachestart = 0;
|
|
|
|
static int32_t agecount = 0;
|
2009-01-09 09:29:17 +00:00
|
|
|
static int32_t lockrecip[200];
|
2012-03-10 21:21:20 +00:00
|
|
|
|
|
|
|
int32_t cacnum = 0;
|
|
|
|
cactype cac[MAXCACHEOBJECTS];
|
2014-01-12 14:54:33 +00:00
|
|
|
#endif
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2014-09-30 04:17:53 +00:00
|
|
|
char toupperlookup[256] =
|
2012-11-05 02:49:08 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
};
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2011-02-21 23:08:21 +00:00
|
|
|
static void reportandexit(const char *errormessage);
|
2006-04-23 06:44:19 +00:00
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
void initcache(intptr_t dacachestart, int32_t dacachesize)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2012-03-10 21:21:20 +00:00
|
|
|
#ifndef DEBUG_ALLOCACHE_AS_MALLOC
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i;
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2014-01-12 14:54:33 +00:00
|
|
|
for (i=1; i<200; i++)
|
2014-10-25 03:29:21 +00:00
|
|
|
lockrecip[i] = tabledivide32_noinline(1<<28, 200-i);
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2008-02-16 22:27:08 +00:00
|
|
|
// The following code was relocated here from engine.c, since this
|
|
|
|
// function is only ever called once (from there), and it seems to
|
|
|
|
// really belong here:
|
|
|
|
//
|
|
|
|
// initcache((FP_OFF(pic)+15)&0xfffffff0,(cachesize-((-FP_OFF(pic))&15))&0xfffffff0);
|
|
|
|
//
|
|
|
|
// I'm not sure why it's necessary, but the code is making sure the
|
2009-11-14 02:30:47 +00:00
|
|
|
// cache starts on a multiple of 16 bytes? -- SA
|
2008-02-16 22:27:08 +00:00
|
|
|
|
|
|
|
//printf("BEFORE: cachestart = %x, cachesize = %d\n", dacachestart, dacachesize);
|
|
|
|
cachestart = ((uintptr_t)dacachestart+15)&~(uintptr_t)0xf;
|
2009-04-26 05:57:42 +00:00
|
|
|
cachesize = (dacachesize-(((uintptr_t)(dacachestart))&0xf))&~(uintptr_t)0xf;
|
2008-02-16 22:27:08 +00:00
|
|
|
//printf("AFTER : cachestart = %x, cachesize = %d\n", cachestart, cachesize);
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
cac[0].leng = cachesize;
|
|
|
|
cac[0].lock = &zerochar;
|
|
|
|
cacnum = 1;
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2008-12-10 11:36:53 +00:00
|
|
|
initprintf("Initialized %.1fM cache\n", (float)(dacachesize/1024.f/1024.f));
|
2012-03-10 21:21:20 +00:00
|
|
|
#else
|
|
|
|
UNREFERENCED_PARAMETER(dacachestart);
|
|
|
|
UNREFERENCED_PARAMETER(dacachesize);
|
|
|
|
#endif
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2012-02-18 17:57:07 +00:00
|
|
|
#ifdef DEBUG_ALLOCACHE_AS_MALLOC
|
|
|
|
void allocache(intptr_t *newhandle, int32_t newbytes, char *newlockptr)
|
|
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(newlockptr);
|
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
*newhandle = (intptr_t)Xmalloc(newbytes);
|
2012-02-18 17:57:07 +00:00
|
|
|
}
|
|
|
|
#else
|
2014-10-25 03:30:38 +00:00
|
|
|
static inline void inc_and_check_cacnum(void)
|
2014-01-12 14:54:33 +00:00
|
|
|
{
|
2014-10-25 03:30:38 +00:00
|
|
|
if (++cacnum > MAXCACHEOBJECTS)
|
2014-01-12 14:54:33 +00:00
|
|
|
reportandexit("Too many objects in cache! (cacnum > MAXCACHEOBJECTS)");
|
|
|
|
}
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
void allocache(intptr_t *newhandle, int32_t newbytes, char *newlockptr)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2014-01-12 14:54:33 +00:00
|
|
|
int32_t i, z, bestz=0, bestval, besto=0, o1, sucklen, suckz;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2008-02-16 22:27:08 +00:00
|
|
|
//printf(" ==> asking for %d bytes, ", newbytes);
|
|
|
|
// Make all requests a multiple of 16 bytes
|
|
|
|
newbytes = (newbytes+15)&0xfffffff0;
|
|
|
|
//printf("allocated %d bytes\n", newbytes);
|
2008-05-10 01:29:37 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
if ((unsigned)newbytes > (unsigned)cachesize)
|
|
|
|
{
|
2007-12-12 17:42:14 +00:00
|
|
|
Bprintf("Cachesize: %d\n",cachesize);
|
2008-06-11 02:33:23 +00:00
|
|
|
Bprintf("*Newhandle: 0x%" PRIxPTR ", Newbytes: %d, *Newlock: %d\n",(intptr_t)newhandle,newbytes,*newlockptr);
|
2006-04-24 19:04:22 +00:00
|
|
|
reportandexit("BUFFER TOO BIG TO FIT IN CACHE!");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*newlockptr == 0)
|
|
|
|
{
|
|
|
|
reportandexit("ALLOCACHE CALLED WITH LOCK OF 0!");
|
|
|
|
}
|
|
|
|
|
|
|
|
//Find best place
|
|
|
|
bestval = 0x7fffffff; o1 = cachesize;
|
2009-02-19 16:47:54 +00:00
|
|
|
for (z=cacnum-1; z>=0; z--)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2014-01-12 14:54:33 +00:00
|
|
|
int32_t zz, o2, daval;
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
o1 -= cac[z].leng;
|
2014-01-12 14:54:33 +00:00
|
|
|
o2 = o1+newbytes;
|
|
|
|
|
|
|
|
if (o2 > cachesize)
|
|
|
|
continue;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
daval = 0;
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=o1,zz=z; i<o2; i+=cac[zz++].leng)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2014-01-12 14:54:33 +00:00
|
|
|
if (*cac[zz].lock == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (*cac[zz].lock >= 200)
|
|
|
|
{
|
|
|
|
daval = 0x7fffffff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Potential for eviction increases with
|
|
|
|
// - smaller item size
|
|
|
|
// - smaller lock byte value (but in [1 .. 199])
|
|
|
|
daval += mulscale32(cac[zz].leng+65536, lockrecip[*cac[zz].lock]);
|
|
|
|
if (daval >= bestval)
|
|
|
|
break;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2014-01-12 14:54:33 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
if (daval < bestval)
|
|
|
|
{
|
|
|
|
bestval = daval; besto = o1; bestz = z;
|
|
|
|
if (bestval == 0) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
//printf("%d %d %d\n",besto,newbytes,*newlockptr);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
if (bestval == 0x7fffffff)
|
|
|
|
reportandexit("CACHE SPACE ALL LOCKED UP!");
|
|
|
|
|
|
|
|
//Suck things out
|
2009-02-19 16:47:54 +00:00
|
|
|
for (sucklen=-newbytes,suckz=bestz; sucklen<0; sucklen+=cac[suckz++].leng)
|
2014-01-12 14:54:33 +00:00
|
|
|
if (*cac[suckz].lock)
|
|
|
|
*cac[suckz].hand = 0;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
//Remove all blocks except 1
|
2014-01-12 14:54:33 +00:00
|
|
|
suckz -= bestz+1;
|
|
|
|
cacnum -= suckz;
|
|
|
|
|
2012-02-18 22:14:45 +00:00
|
|
|
Bmemmove(&cac[bestz], &cac[bestz+suckz], (cacnum-bestz)*sizeof(cactype));
|
2014-01-12 14:54:33 +00:00
|
|
|
cac[bestz].hand = newhandle;
|
|
|
|
*newhandle = cachestart + besto;
|
2006-04-24 19:04:22 +00:00
|
|
|
cac[bestz].leng = newbytes;
|
|
|
|
cac[bestz].lock = newlockptr;
|
|
|
|
|
|
|
|
//Add new empty block if necessary
|
2014-01-12 14:54:33 +00:00
|
|
|
if (sucklen <= 0)
|
|
|
|
return;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
bestz++;
|
|
|
|
if (bestz == cacnum)
|
|
|
|
{
|
2014-01-12 14:54:33 +00:00
|
|
|
inc_and_check_cacnum();
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
cac[bestz].leng = sucklen;
|
|
|
|
cac[bestz].lock = &zerochar;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-12 14:54:33 +00:00
|
|
|
if (*cac[bestz].lock == 0)
|
|
|
|
{
|
|
|
|
cac[bestz].leng += sucklen;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
inc_and_check_cacnum();
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-01-12 14:54:33 +00:00
|
|
|
for (z=cacnum-1; z>bestz; z--)
|
|
|
|
cac[z] = cac[z-1];
|
2006-04-24 19:04:22 +00:00
|
|
|
cac[bestz].leng = sucklen;
|
|
|
|
cac[bestz].lock = &zerochar;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
2012-02-18 17:57:07 +00:00
|
|
|
#endif
|
2006-04-23 06:44:19 +00:00
|
|
|
|
|
|
|
void agecache(void)
|
|
|
|
{
|
2012-02-18 17:57:07 +00:00
|
|
|
#ifndef DEBUG_ALLOCACHE_AS_MALLOC
|
2010-01-21 10:02:04 +00:00
|
|
|
int32_t cnt = (cacnum>>4);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-01-12 14:54:33 +00:00
|
|
|
if (agecount >= cacnum)
|
|
|
|
agecount = cacnum-1;
|
|
|
|
|
|
|
|
if (agecount < 0 || !cnt)
|
|
|
|
return;
|
2010-06-22 21:50:01 +00:00
|
|
|
|
2010-01-21 10:02:04 +00:00
|
|
|
for (; cnt>=0; cnt--)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2014-01-12 14:54:33 +00:00
|
|
|
// If we have pointer to lock char and it's in [2 .. 199], decrease.
|
2010-06-07 09:03:16 +00:00
|
|
|
if (cac[agecount].lock && (((*cac[agecount].lock)-2)&255) < 198)
|
2010-01-21 10:02:04 +00:00
|
|
|
(*cac[agecount].lock)--;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2010-01-21 10:02:04 +00:00
|
|
|
agecount--;
|
2014-01-12 14:54:33 +00:00
|
|
|
if (agecount < 0)
|
|
|
|
agecount = cacnum-1;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2012-02-18 17:57:07 +00:00
|
|
|
#endif
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2011-02-21 23:08:21 +00:00
|
|
|
static void reportandexit(const char *errormessage)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2012-02-18 17:57:07 +00:00
|
|
|
#ifndef DEBUG_ALLOCACHE_AS_MALLOC
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i, j;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
//setvmode(0x3);
|
|
|
|
j = 0;
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=0; i<cacnum; i++)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2007-12-12 17:42:14 +00:00
|
|
|
Bprintf("%d- ",i);
|
2008-06-11 02:33:23 +00:00
|
|
|
if (cac[i].hand) Bprintf("ptr: 0x%" PRIxPTR ", ",*cac[i].hand);
|
2006-04-24 19:04:22 +00:00
|
|
|
else Bprintf("ptr: NULL, ");
|
2007-12-12 17:42:14 +00:00
|
|
|
Bprintf("leng: %d, ",cac[i].leng);
|
2006-04-24 19:04:22 +00:00
|
|
|
if (cac[i].lock) Bprintf("lock: %d\n",*cac[i].lock);
|
|
|
|
else Bprintf("lock: NULL\n");
|
|
|
|
j += cac[i].leng;
|
|
|
|
}
|
2007-12-12 17:42:14 +00:00
|
|
|
Bprintf("Cachesize = %d\n",cachesize);
|
|
|
|
Bprintf("Cacnum = %d\n",cacnum);
|
|
|
|
Bprintf("Cache length sum = %d\n",j);
|
2012-02-18 17:57:07 +00:00
|
|
|
#endif
|
2006-04-24 19:04:22 +00:00
|
|
|
initprintf("ERROR: %s\n",errormessage);
|
2014-06-13 09:02:37 +00:00
|
|
|
Bexit(1);
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
typedef struct _searchpath
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
struct _searchpath *next;
|
|
|
|
char *path;
|
|
|
|
size_t pathlen; // to save repeated calls to strlen()
|
2015-01-08 15:14:47 +00:00
|
|
|
int32_t user;
|
2006-04-23 06:44:19 +00:00
|
|
|
} searchpath_t;
|
|
|
|
static searchpath_t *searchpathhead = NULL;
|
|
|
|
static size_t maxsearchpathlen = 0;
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t pathsearchmode = 0;
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2012-10-07 15:26:09 +00:00
|
|
|
char *listsearchpath(int32_t initp)
|
|
|
|
{
|
|
|
|
static searchpath_t *sp;
|
|
|
|
|
|
|
|
if (initp)
|
|
|
|
sp = searchpathhead;
|
|
|
|
else if (sp != NULL)
|
|
|
|
sp = sp->next;
|
|
|
|
|
|
|
|
return sp ? sp->path : NULL;
|
|
|
|
}
|
|
|
|
|
2015-01-08 15:14:47 +00:00
|
|
|
int32_t addsearchpath_user(const char *p, int32_t user)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2012-11-15 14:27:57 +00:00
|
|
|
struct Bstat st;
|
2006-04-24 19:04:22 +00:00
|
|
|
char *s;
|
|
|
|
searchpath_t *srch;
|
2014-05-30 00:02:19 +00:00
|
|
|
char *path = Xstrdup(p);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2013-03-27 01:39:18 +00:00
|
|
|
if (path[Bstrlen(path)-1] == '\\')
|
2013-03-28 09:05:36 +00:00
|
|
|
path[Bstrlen(path)-1] = 0; // hack for stat() returning ENOENT on paths ending in a backslash
|
2013-03-27 01:39:18 +00:00
|
|
|
|
|
|
|
if (Bstat(path, &st) < 0)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2013-03-27 01:39:18 +00:00
|
|
|
Bfree(path);
|
2006-04-24 19:04:22 +00:00
|
|
|
if (errno == ENOENT) return -2;
|
|
|
|
return -1;
|
|
|
|
}
|
2013-03-27 01:39:18 +00:00
|
|
|
if (!(st.st_mode & BS_IFDIR))
|
|
|
|
{
|
|
|
|
Bfree(path);
|
|
|
|
return -1;
|
|
|
|
}
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
srch = (searchpath_t *)Xmalloc(sizeof(searchpath_t));
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
srch->next = searchpathhead;
|
2013-03-27 01:39:18 +00:00
|
|
|
srch->pathlen = Bstrlen(path)+1;
|
2014-05-30 00:02:19 +00:00
|
|
|
srch->path = (char *)Xmalloc(srch->pathlen + 1);
|
2012-03-04 20:15:22 +00:00
|
|
|
|
2013-03-27 01:39:18 +00:00
|
|
|
Bstrcpy(srch->path, path);
|
2016-01-12 10:31:12 +00:00
|
|
|
for (s=srch->path; *s; s++) { }
|
2012-03-04 20:15:22 +00:00
|
|
|
s--;
|
2013-04-05 07:48:20 +00:00
|
|
|
|
2012-03-04 20:15:22 +00:00
|
|
|
if (s<srch->path || toupperlookup[*s] != '/')
|
|
|
|
Bstrcat(srch->path, "/");
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
searchpathhead = srch;
|
2012-03-04 20:15:22 +00:00
|
|
|
if (srch->pathlen > maxsearchpathlen)
|
|
|
|
maxsearchpathlen = srch->pathlen;
|
2007-12-12 17:42:14 +00:00
|
|
|
|
2006-12-17 01:08:39 +00:00
|
|
|
Bcorrectfilename(srch->path,0);
|
2007-12-12 17:42:14 +00:00
|
|
|
|
2015-01-08 15:14:47 +00:00
|
|
|
srch->user = user;
|
|
|
|
|
2010-05-19 10:02:35 +00:00
|
|
|
initprintf("Using %s for game data\n", srch->path);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2013-03-27 01:39:18 +00:00
|
|
|
Bfree(path);
|
2006-04-24 19:04:22 +00:00
|
|
|
return 0;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2013-04-05 07:48:20 +00:00
|
|
|
int32_t removesearchpath(const char *p)
|
|
|
|
{
|
|
|
|
searchpath_t *srch;
|
|
|
|
char *s;
|
2014-05-30 00:02:19 +00:00
|
|
|
char *path = (char *)Xmalloc(Bstrlen(p) + 2);
|
2013-04-05 07:48:20 +00:00
|
|
|
|
|
|
|
Bstrcpy(path, p);
|
|
|
|
|
|
|
|
if (path[Bstrlen(path)-1] == '\\')
|
|
|
|
path[Bstrlen(path)-1] = 0;
|
|
|
|
|
2016-01-12 10:31:12 +00:00
|
|
|
for (s=path; *s; s++) { }
|
2013-04-05 07:48:20 +00:00
|
|
|
s--;
|
|
|
|
|
|
|
|
if (s<path || toupperlookup[*s] != '/')
|
|
|
|
Bstrcat(path, "/");
|
|
|
|
|
|
|
|
Bcorrectfilename(path,0);
|
|
|
|
|
|
|
|
for (srch = searchpathhead; srch; srch = srch->next)
|
|
|
|
{
|
|
|
|
if (!Bstrncmp(path, srch->path, srch->pathlen))
|
|
|
|
{
|
|
|
|
// initprintf("Removing %s from path stack\n", path);
|
|
|
|
|
|
|
|
if (srch == searchpathhead)
|
|
|
|
searchpathhead = srch->next;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
searchpath_t *sp;
|
|
|
|
|
|
|
|
for (sp = searchpathhead; sp; sp = sp->next)
|
|
|
|
{
|
|
|
|
if (sp->next == srch)
|
|
|
|
{
|
|
|
|
// initprintf("matched %s\n", srch->path);
|
|
|
|
sp->next = srch->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Bfree(srch->path);
|
|
|
|
Bfree(srch);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Bfree(path);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-08 15:14:47 +00:00
|
|
|
void removesearchpaths_withuser(int32_t usermask)
|
|
|
|
{
|
2015-01-12 01:53:55 +00:00
|
|
|
searchpath_t *next;
|
|
|
|
|
|
|
|
for (searchpath_t *srch = searchpathhead; srch; srch = next)
|
2015-01-08 15:14:47 +00:00
|
|
|
{
|
2015-01-12 01:53:55 +00:00
|
|
|
next = srch->next;
|
|
|
|
|
2015-01-08 15:14:47 +00:00
|
|
|
if (srch->user & usermask)
|
|
|
|
{
|
2015-01-12 01:53:55 +00:00
|
|
|
|
2015-01-08 15:14:47 +00:00
|
|
|
if (srch == searchpathhead)
|
|
|
|
searchpathhead = srch->next;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
searchpath_t *sp;
|
|
|
|
|
|
|
|
for (sp = searchpathhead; sp; sp = sp->next)
|
|
|
|
{
|
|
|
|
if (sp->next == srch)
|
|
|
|
{
|
|
|
|
sp->next = srch->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Bfree(srch->path);
|
|
|
|
Bfree(srch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t findfrompath(const char *fn, char **where)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
// pathsearchmode == 0: tests current dir and then the dirs of the path stack
|
|
|
|
// pathsearchmode == 1: tests fn without modification, then like for pathsearchmode == 0
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
if (pathsearchmode)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
// test unmolested filename first
|
2007-12-12 17:42:14 +00:00
|
|
|
if (access(fn, F_OK) >= 0)
|
|
|
|
{
|
2014-05-30 00:02:19 +00:00
|
|
|
*where = Xstrdup(fn);
|
2006-04-24 19:04:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-25 15:23:58 +00:00
|
|
|
#ifndef _WIN32
|
2010-08-14 21:32:28 +00:00
|
|
|
else
|
|
|
|
{
|
2014-05-30 00:02:19 +00:00
|
|
|
char *tfn = Bstrtolower(Xstrdup(fn));
|
2010-08-14 21:32:28 +00:00
|
|
|
|
|
|
|
if (access(tfn, F_OK) >= 0)
|
|
|
|
{
|
|
|
|
*where = tfn;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bstrupr(tfn);
|
|
|
|
|
|
|
|
if (access(tfn, F_OK) >= 0)
|
|
|
|
{
|
|
|
|
*where = tfn;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bfree(tfn);
|
|
|
|
}
|
2012-05-25 15:23:58 +00:00
|
|
|
#endif
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
char const *cpfn;
|
|
|
|
|
2016-01-12 10:31:12 +00:00
|
|
|
for (cpfn = fn; toupperlookup[*cpfn] == '/'; cpfn++) { }
|
2016-01-11 05:05:38 +00:00
|
|
|
char *ffn = Xstrdup(cpfn);
|
2014-05-30 00:02:19 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
Bcorrectfilename(ffn,0); // compress relative paths
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
int32_t allocsiz = max(maxsearchpathlen, 2); // "./" (aka. curdir)
|
2006-04-24 19:04:22 +00:00
|
|
|
allocsiz += strlen(ffn);
|
|
|
|
allocsiz += 1; // a nul
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
char *pfn = (char *)Xmalloc(allocsiz);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
strcpy(pfn, "./");
|
|
|
|
strcat(pfn, ffn);
|
2007-12-12 17:42:14 +00:00
|
|
|
if (access(pfn, F_OK) >= 0)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
*where = pfn;
|
2009-10-07 06:47:35 +00:00
|
|
|
Bfree(ffn);
|
2006-04-24 19:04:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-11 05:05:38 +00:00
|
|
|
for (searchpath_t *sp = searchpathhead; sp; sp = sp->next)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2014-05-30 00:02:19 +00:00
|
|
|
char *tfn = Xstrdup(ffn);
|
2010-05-16 22:53:08 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
strcpy(pfn, sp->path);
|
|
|
|
strcat(pfn, ffn);
|
|
|
|
//initprintf("Trying %s\n", pfn);
|
2007-12-12 17:42:14 +00:00
|
|
|
if (access(pfn, F_OK) >= 0)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
*where = pfn;
|
2009-10-07 06:47:35 +00:00
|
|
|
Bfree(ffn);
|
2010-05-16 22:53:08 +00:00
|
|
|
Bfree(tfn);
|
2010-08-14 21:32:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-25 15:23:58 +00:00
|
|
|
#ifndef _WIN32
|
2010-08-14 21:32:28 +00:00
|
|
|
//Check with all lowercase
|
|
|
|
strcpy(pfn, sp->path);
|
|
|
|
Bstrtolower(tfn);
|
|
|
|
strcat(pfn, tfn);
|
|
|
|
if (access(pfn, F_OK) >= 0)
|
|
|
|
{
|
|
|
|
*where = pfn;
|
|
|
|
Bfree(ffn);
|
|
|
|
Bfree(tfn);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Check again with uppercase
|
|
|
|
strcpy(pfn, sp->path);
|
|
|
|
Bstrupr(tfn);
|
|
|
|
strcat(pfn, tfn);
|
|
|
|
if (access(pfn, F_OK) >= 0)
|
|
|
|
{
|
|
|
|
*where = pfn;
|
|
|
|
Bfree(ffn);
|
|
|
|
Bfree(tfn);
|
2006-04-24 19:04:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-25 15:23:58 +00:00
|
|
|
#endif
|
2010-05-16 22:53:08 +00:00
|
|
|
Bfree(tfn);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2012-05-25 15:23:58 +00:00
|
|
|
|
2009-10-07 06:47:35 +00:00
|
|
|
Bfree(pfn); Bfree(ffn);
|
2006-04-24 19:04:22 +00:00
|
|
|
return -1;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2014-10-25 03:36:34 +00:00
|
|
|
#if defined(_WIN32) && defined(DEBUGGINGAIDS)
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
# define FILENAME_CASE_CHECK
|
|
|
|
#endif
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
static int32_t openfrompath_internal(const char *fn, char **where, int32_t flags, int32_t mode)
|
|
|
|
{
|
|
|
|
if (findfrompath(fn, where) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return Bopen(*where, flags, mode);
|
|
|
|
}
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t openfrompath(const char *fn, int32_t flags, int32_t mode)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
char *pfn = NULL;
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
int32_t h = openfrompath_internal(fn, &pfn, flags, mode);
|
2012-05-28 18:15:19 +00:00
|
|
|
|
2015-09-23 17:55:31 +00:00
|
|
|
Bfree(pfn);
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
return h;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2011-01-16 02:50:27 +00:00
|
|
|
BFILE *fopenfrompath(const char *fn, const char *mode)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t fh;
|
2006-04-24 19:04:22 +00:00
|
|
|
BFILE *h;
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t bmode = 0, smode = 0;
|
2006-04-24 19:04:22 +00:00
|
|
|
const char *c;
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
for (c=mode; c[0];)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if (c[0] == 'r' && c[1] == '+') { bmode = BO_RDWR; smode = BS_IREAD|BS_IWRITE; c+=2; }
|
|
|
|
else if (c[0] == 'r') { bmode = BO_RDONLY; smode = BS_IREAD; c+=1; }
|
|
|
|
else if (c[0] == 'w' && c[1] == '+') { bmode = BO_RDWR|BO_CREAT|BO_TRUNC; smode = BS_IREAD|BS_IWRITE; c+=2; }
|
|
|
|
else if (c[0] == 'w') { bmode = BO_WRONLY|BO_CREAT|BO_TRUNC; smode = BS_IREAD|BS_IWRITE; c+=2; }
|
|
|
|
else if (c[0] == 'a' && c[1] == '+') { bmode = BO_RDWR|BO_CREAT; smode=BS_IREAD|BS_IWRITE; c+=2; }
|
|
|
|
else if (c[0] == 'a') { bmode = BO_WRONLY|BO_CREAT; smode=BS_IREAD|BS_IWRITE; c+=1; }
|
|
|
|
else if (c[0] == 'b') { bmode |= BO_BINARY; c+=1; }
|
|
|
|
else if (c[1] == 't') { bmode |= BO_TEXT; c+=1; }
|
|
|
|
else c++;
|
|
|
|
}
|
|
|
|
fh = openfrompath(fn,bmode,smode);
|
|
|
|
if (fh < 0) return NULL;
|
|
|
|
|
|
|
|
h = fdopen(fh,mode);
|
|
|
|
if (!h) close(fh);
|
|
|
|
|
|
|
|
return h;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 06:27:18 +00:00
|
|
|
#define MAXGROUPFILES 8 // Warning: Fix groupfil if this is changed
|
|
|
|
#define MAXOPENFILES 64 // Warning: Fix filehan if this is changed
|
|
|
|
|
|
|
|
enum {
|
|
|
|
GRP_RESERVED_ID_START = 254,
|
|
|
|
|
|
|
|
GRP_ZIP = GRP_RESERVED_ID_START,
|
|
|
|
GRP_FILESYSTEM = GRP_RESERVED_ID_START + 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
EDUKE32_STATIC_ASSERT(MAXGROUPFILES <= GRP_RESERVED_ID_START);
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t numgroupfiles = 0;
|
|
|
|
static int32_t gnumfiles[MAXGROUPFILES];
|
2015-03-23 06:27:35 +00:00
|
|
|
static intptr_t groupfil[MAXGROUPFILES] = {-1,-1,-1,-1,-1,-1,-1,-1};
|
2009-01-09 09:29:17 +00:00
|
|
|
static int32_t groupfilpos[MAXGROUPFILES];
|
2015-03-23 06:27:35 +00:00
|
|
|
static uint8_t groupfilgrp[MAXGROUPFILES];
|
2006-04-23 06:44:19 +00:00
|
|
|
static char *gfilelist[MAXGROUPFILES];
|
2015-11-25 12:07:54 +00:00
|
|
|
static char *groupname[MAXGROUPFILES];
|
2009-01-09 09:29:17 +00:00
|
|
|
static int32_t *gfileoffs[MAXGROUPFILES];
|
2015-03-23 08:30:41 +00:00
|
|
|
static int32_t groupcrc[MAXGROUPFILES];
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2015-03-23 06:27:18 +00:00
|
|
|
static uint8_t filegrp[MAXOPENFILES];
|
2009-01-09 09:29:17 +00:00
|
|
|
static int32_t filepos[MAXOPENFILES];
|
2008-05-23 10:00:43 +00:00
|
|
|
static intptr_t filehan[MAXOPENFILES] =
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
|
|
|
-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
|
|
|
|
};
|
2015-03-23 06:27:18 +00:00
|
|
|
|
2006-04-23 06:44:19 +00:00
|
|
|
#ifdef WITHKPLIB
|
|
|
|
static char filenamsav[MAXOPENFILES][260];
|
2009-01-09 09:29:17 +00:00
|
|
|
static int32_t kzcurhand = -1;
|
2012-11-15 21:09:56 +00:00
|
|
|
|
|
|
|
int32_t cache1d_file_fromzip(int32_t fil)
|
|
|
|
{
|
2015-03-23 06:27:18 +00:00
|
|
|
return (filegrp[fil] == GRP_ZIP);
|
2012-11-15 21:09:56 +00:00
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
static int32_t kopen_internal(const char *filename, char **lastpfn, char searchfirst, char checkcase, char tryzip, int32_t newhandle, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos);
|
|
|
|
static int32_t kread_grp(int32_t handle, void *buffer, int32_t leng);
|
|
|
|
static int32_t klseek_grp(int32_t handle, int32_t offset, int32_t whence);
|
|
|
|
static void kclose_grp(int32_t handle);
|
|
|
|
|
2015-03-23 08:30:41 +00:00
|
|
|
static void initgroupfile_crc32(int32_t handle)
|
|
|
|
{
|
|
|
|
int32_t b, crcval = 0;
|
|
|
|
#define BUFFER_SIZE (1024 * 1024 * 8)
|
|
|
|
uint8_t *buf = (uint8_t *)Xmalloc(BUFFER_SIZE);
|
|
|
|
klseek_grp(handle, 0, BSEEK_SET);
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
b = kread_grp(handle, buf, BUFFER_SIZE);
|
|
|
|
if (b > 0) crcval = Bcrc32((uint8_t *)buf, b, crcval);
|
|
|
|
}
|
|
|
|
while (b == BUFFER_SIZE);
|
|
|
|
|
|
|
|
groupcrc[handle] = crcval;
|
|
|
|
klseek_grp(handle, 0, BSEEK_SET);
|
|
|
|
Bfree(buf);
|
|
|
|
}
|
|
|
|
|
2010-10-17 14:49:39 +00:00
|
|
|
int32_t initgroupfile(const char *filename)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2015-03-23 06:27:49 +00:00
|
|
|
char buf[70];
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2014-09-30 04:17:53 +00:00
|
|
|
// translate all backslashes (0x5c) to forward slashes (0x2f)
|
2006-04-24 19:04:22 +00:00
|
|
|
toupperlookup[0x5c] = 0x2f;
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
if (filename == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
// Technically you should be able to load more zips even if your GRPs are maxed out,
|
|
|
|
// but this system is already enough of a disaster.
|
|
|
|
if (numgroupfiles >= MAXGROUPFILES)
|
|
|
|
return -1;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
char *zfn = NULL;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
if (kopen_internal(filename, &zfn, 0, 0, 0, numgroupfiles, groupfilgrp, groupfil, groupfilpos) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
#ifdef WITHKPLIB
|
|
|
|
// check if ZIP
|
|
|
|
if (zfn)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
kread_grp(numgroupfiles, buf, 4);
|
|
|
|
if (buf[0] == 0x50 && buf[1] == 0x4B && buf[2] == 0x03 && buf[3] == 0x04)
|
|
|
|
{
|
|
|
|
kclose_grp(numgroupfiles);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
kzaddstack(zfn);
|
|
|
|
Bfree(zfn);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
klseek_grp(numgroupfiles,0,BSEEK_SET);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
Bfree(zfn);
|
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
#else
|
2015-09-23 17:55:31 +00:00
|
|
|
Bfree(zfn);
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
2015-03-23 06:27:35 +00:00
|
|
|
|
|
|
|
// check if GRP
|
|
|
|
kread_grp(numgroupfiles,buf,16);
|
|
|
|
if (!Bmemcmp(buf, "KenSilverman", 12))
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
gnumfiles[numgroupfiles] = B_LITTLE32(*((int32_t *)&buf[12]));
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
gfilelist[numgroupfiles] = (char *)Xmalloc(gnumfiles[numgroupfiles]<<4);
|
|
|
|
gfileoffs[numgroupfiles] = (int32_t *)Xmalloc((gnumfiles[numgroupfiles]+1)<<2);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
kread_grp(numgroupfiles,gfilelist[numgroupfiles],gnumfiles[numgroupfiles]<<4);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
int32_t j = (gnumfiles[numgroupfiles]+1)<<4, k;
|
|
|
|
for (int32_t i=0; i<gnumfiles[numgroupfiles]; i++)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
k = B_LITTLE32(*((int32_t *)&gfilelist[numgroupfiles][(i<<4)+12]));
|
2006-04-24 19:04:22 +00:00
|
|
|
gfilelist[numgroupfiles][(i<<4)+12] = 0;
|
|
|
|
gfileoffs[numgroupfiles][i] = j;
|
|
|
|
j += k;
|
|
|
|
}
|
|
|
|
gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j;
|
2015-03-23 08:30:41 +00:00
|
|
|
initgroupfile_crc32(numgroupfiles);
|
2015-11-25 12:07:54 +00:00
|
|
|
groupname[numgroupfiles] = Xstrdup(filename);
|
2015-03-23 06:27:35 +00:00
|
|
|
numgroupfiles++;
|
|
|
|
return 0;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2015-03-23 06:27:49 +00:00
|
|
|
klseek_grp(numgroupfiles, 0, BSEEK_SET);
|
|
|
|
|
|
|
|
// check if SSI
|
|
|
|
// this performs several checks because there is no "SSI" magic
|
|
|
|
int32_t version;
|
|
|
|
kread_grp(numgroupfiles, &version, 4);
|
|
|
|
version = B_LITTLE32(version);
|
|
|
|
while (version == 1 || version == 2) // if
|
|
|
|
{
|
|
|
|
char zerobuf[70];
|
|
|
|
Bmemset(zerobuf, 0, 70);
|
|
|
|
|
|
|
|
int32_t numfiles;
|
|
|
|
kread_grp(numgroupfiles, &numfiles, 4);
|
|
|
|
numfiles = B_LITTLE32(numfiles);
|
|
|
|
|
|
|
|
uint8_t temp, temp2;
|
|
|
|
|
|
|
|
// get the string length
|
|
|
|
kread_grp(numgroupfiles, &temp, 1);
|
|
|
|
if (temp > 31) // 32 bytes allocated for the string
|
|
|
|
break;
|
|
|
|
// seek to the end of the string
|
|
|
|
klseek_grp(numgroupfiles, temp, BSEEK_CUR);
|
|
|
|
// verify everything remaining is a null terminator
|
|
|
|
temp = 32 - temp;
|
|
|
|
kread_grp(numgroupfiles, buf, temp);
|
|
|
|
if (Bmemcmp(buf, zerobuf, temp))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (version == 2)
|
|
|
|
{
|
|
|
|
// get the string length
|
|
|
|
kread_grp(numgroupfiles, &temp, 1);
|
|
|
|
if (temp > 11) // 12 bytes allocated for the string
|
|
|
|
break;
|
|
|
|
// seek to the end of the string
|
|
|
|
klseek_grp(numgroupfiles, temp, BSEEK_CUR);
|
|
|
|
// verify everything remaining is a null terminator
|
|
|
|
temp = 12 - temp;
|
|
|
|
kread_grp(numgroupfiles, buf, temp);
|
|
|
|
if (Bmemcmp(buf, zerobuf, temp))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp2 = 0;
|
|
|
|
for (uint8_t i=0;i<3;i++)
|
|
|
|
{
|
|
|
|
// get the string length
|
|
|
|
kread_grp(numgroupfiles, &temp, 1);
|
|
|
|
if (temp > 70) // 70 bytes allocated for the string
|
|
|
|
{
|
|
|
|
temp2 = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// seek to the end of the string
|
|
|
|
klseek_grp(numgroupfiles, temp, BSEEK_CUR);
|
|
|
|
// verify everything remaining is a null terminator
|
|
|
|
temp = 70 - temp;
|
|
|
|
if (temp == 0)
|
|
|
|
continue;
|
|
|
|
kread_grp(numgroupfiles, buf, temp);
|
|
|
|
temp2 |= Bmemcmp(buf, zerobuf, temp);
|
|
|
|
}
|
|
|
|
if (temp2)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Passed all the tests: read data.
|
|
|
|
|
|
|
|
gnumfiles[numgroupfiles] = numfiles;
|
|
|
|
|
|
|
|
gfilelist[numgroupfiles] = (char *)Xmalloc(gnumfiles[numgroupfiles]<<4);
|
|
|
|
gfileoffs[numgroupfiles] = (int32_t *)Xmalloc((gnumfiles[numgroupfiles]+1)<<2);
|
|
|
|
|
|
|
|
int32_t j = (version == 2 ? 267 : 254) + (numfiles * 121), k;
|
|
|
|
for (int32_t i = 0; i < numfiles; i++)
|
|
|
|
{
|
|
|
|
// get the string length
|
|
|
|
kread_grp(numgroupfiles, &temp, 1);
|
|
|
|
if (temp > 12)
|
|
|
|
temp = 12;
|
|
|
|
// read the file name
|
|
|
|
kread_grp(numgroupfiles, &gfilelist[numgroupfiles][i<<4], temp);
|
|
|
|
gfilelist[numgroupfiles][(i<<4)+temp] = 0;
|
|
|
|
|
|
|
|
// skip to the end of the 12 bytes
|
|
|
|
klseek_grp(numgroupfiles, 12-temp, BSEEK_CUR);
|
|
|
|
|
|
|
|
// get the file size
|
|
|
|
kread_grp(numgroupfiles, &k, 4);
|
|
|
|
k = B_LITTLE32(k);
|
|
|
|
|
|
|
|
// record the offset of the file in the SSI
|
|
|
|
gfileoffs[numgroupfiles][i] = j;
|
|
|
|
j += k;
|
|
|
|
|
|
|
|
// skip unknown data
|
|
|
|
klseek_grp(numgroupfiles, 104, BSEEK_CUR);
|
|
|
|
}
|
|
|
|
gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j;
|
2015-03-23 08:30:41 +00:00
|
|
|
initgroupfile_crc32(numgroupfiles);
|
2015-11-25 12:07:54 +00:00
|
|
|
groupname[numgroupfiles] = Xstrdup(filename);
|
2015-03-23 06:27:49 +00:00
|
|
|
numgroupfiles++;
|
|
|
|
return 0;
|
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
kclose_grp(numgroupfiles);
|
|
|
|
return -1;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void uninitgroupfile(void)
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=numgroupfiles-1; i>=0; i--)
|
2006-04-24 19:04:22 +00:00
|
|
|
if (groupfil[i] != -1)
|
|
|
|
{
|
2015-11-25 12:07:54 +00:00
|
|
|
DO_FREE_AND_NULL(gfilelist[i]);
|
|
|
|
DO_FREE_AND_NULL(gfileoffs[i]);
|
|
|
|
DO_FREE_AND_NULL(groupname[i]);
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
Bclose(groupfil[i]);
|
|
|
|
groupfil[i] = -1;
|
|
|
|
}
|
|
|
|
numgroupfiles = 0;
|
|
|
|
|
|
|
|
// JBF 20040111: "close" any files open in groups
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=0; i<MAXOPENFILES; i++)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2015-03-23 06:27:18 +00:00
|
|
|
if (filegrp[i] < GRP_RESERVED_ID_START) // JBF 20040130: not external or ZIPped
|
2006-04-24 19:04:22 +00:00
|
|
|
filehan[i] = -1;
|
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
#ifdef FILENAME_CASE_CHECK
|
|
|
|
// See
|
|
|
|
// http://stackoverflow.com/questions/74451/getting-actual-file-name-with-proper-casing-on-windows
|
|
|
|
// for relevant discussion.
|
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
static char fnbuf[BMAX_PATH];
|
|
|
|
int fnofs;
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
|
2012-05-28 18:15:19 +00:00
|
|
|
int32_t (*check_filename_casing_fn)(void) = NULL;
|
|
|
|
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
// -1: failure, 0: match, 1: mismatch
|
2015-03-24 00:40:36 +00:00
|
|
|
static int32_t check_filename_mismatch(const char * const filename, int ofs)
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
{
|
2015-03-24 00:40:36 +00:00
|
|
|
if (!GetShortPathNameA(filename, fnbuf, BMAX_PATH)) return -1;
|
|
|
|
if (!GetLongPathNameA(fnbuf, fnbuf, BMAX_PATH)) return -1;
|
2012-05-28 18:15:19 +00:00
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
fnofs = ofs;
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
int len = Bstrlen(fnbuf+ofs);
|
2012-10-13 14:53:26 +00:00
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
char const * const fn = filename+ofs;
|
2012-05-28 18:15:19 +00:00
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
if (!Bstrncmp(fnbuf+ofs, fn, len))
|
|
|
|
return 0;
|
2012-05-28 18:15:19 +00:00
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
char * const tfn = Bstrtolower(Xstrdup(fn));
|
2012-05-28 18:15:19 +00:00
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
if (!Bstrncmp(fnbuf+ofs, tfn, len))
|
|
|
|
{
|
|
|
|
Bfree(tfn);
|
|
|
|
return 0;
|
|
|
|
}
|
2012-05-28 18:15:19 +00:00
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
Bstrupr(tfn);
|
2012-05-28 18:15:19 +00:00
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
if (!Bstrncmp(fnbuf+ofs, tfn, len))
|
|
|
|
{
|
2012-05-28 18:15:19 +00:00
|
|
|
Bfree(tfn);
|
2015-03-24 00:40:36 +00:00
|
|
|
return 0;
|
2012-05-28 18:15:19 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 00:40:36 +00:00
|
|
|
Bfree(tfn);
|
|
|
|
|
2012-05-28 18:15:19 +00:00
|
|
|
return 1;
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
static int32_t kopen_internal(const char *filename, char **lastpfn, char searchfirst, char checkcase, char tryzip, int32_t newhandle, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2015-11-25 12:07:57 +00:00
|
|
|
int32_t fil;
|
2015-03-23 06:27:35 +00:00
|
|
|
if (searchfirst == 0 && (fil = openfrompath_internal(filename, lastpfn, BO_BINARY|BO_RDONLY, BS_IREAD)) >= 0)
|
2010-01-21 10:02:04 +00:00
|
|
|
{
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
#ifdef FILENAME_CASE_CHECK
|
2015-03-23 06:27:35 +00:00
|
|
|
if (checkcase && check_filename_casing_fn && check_filename_casing_fn())
|
2012-05-28 18:15:19 +00:00
|
|
|
{
|
|
|
|
int32_t status;
|
|
|
|
char *cp, *lastslash;
|
|
|
|
|
|
|
|
// convert all slashes to backslashes because SHGetFileInfo()
|
|
|
|
// complains else!
|
2015-03-23 06:27:35 +00:00
|
|
|
lastslash = *lastpfn;
|
|
|
|
for (cp=*lastpfn; *cp; cp++)
|
2012-05-28 18:15:19 +00:00
|
|
|
if (*cp=='/')
|
|
|
|
{
|
|
|
|
*cp = '\\';
|
|
|
|
lastslash = cp;
|
|
|
|
}
|
2015-03-23 06:27:35 +00:00
|
|
|
if (lastslash != *lastpfn)
|
2012-05-28 18:15:19 +00:00
|
|
|
lastslash++;
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
status = check_filename_mismatch(*lastpfn, lastslash-*lastpfn);
|
2012-05-28 18:15:19 +00:00
|
|
|
|
|
|
|
if (status == -1)
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
{
|
2013-01-08 23:12:53 +00:00
|
|
|
// initprintf("SHGetFileInfo failed with error code %lu\n", GetLastError());
|
2012-05-28 18:15:19 +00:00
|
|
|
}
|
|
|
|
else if (status == 1)
|
|
|
|
{
|
|
|
|
initprintf("warning: case mismatch: passed \"%s\", real \"%s\"\n",
|
2015-03-24 00:40:36 +00:00
|
|
|
lastslash, fnbuf+fnofs);
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-23 06:27:35 +00:00
|
|
|
#else
|
|
|
|
UNREFERENCED_PARAMETER(checkcase);
|
On Windows, check for case-mismatched file names on successful kopen4load().
When a file from the local file system is opened, its real file name is gotten
with SHGetFileInfo() and compared against the one that was passed. In the case
they're not identical, a warning is issued.
This is one step towards eliminating mismatched file names in DEFs etc., which
cause trouble on systems that look them up case-sensitively. However, it's not
perfect because the issue is trickier than it appears on first sight.
For one thing, this will only check the last (i.e. file) part in the path,
falsely accepting mismatched directory names. However for these, it reports
them ruthlessly, even for those names where the try-other-case hack (try all
uppercase, all lowercase) would find the correctly-cased file.
git-svn-id: https://svn.eduke32.com/eduke32@2692 1a8010ca-5511-0410-912e-c29ae57300e0
2012-05-25 15:23:55 +00:00
|
|
|
#endif
|
2015-03-23 06:27:35 +00:00
|
|
|
arraygrp[newhandle] = GRP_FILESYSTEM;
|
|
|
|
arrayhan[newhandle] = fil;
|
|
|
|
arraypos[newhandle] = 0;
|
|
|
|
return newhandle;
|
2010-01-21 10:02:04 +00:00
|
|
|
}
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2016-01-12 10:31:12 +00:00
|
|
|
for (; toupperlookup[*filename] == '/'; filename++) { }
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2006-04-23 06:44:19 +00:00
|
|
|
#ifdef WITHKPLIB
|
2015-03-23 06:27:35 +00:00
|
|
|
if (tryzip)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2015-11-25 12:07:57 +00:00
|
|
|
intptr_t i;
|
2015-03-23 06:27:35 +00:00
|
|
|
if ((kzcurhand != newhandle) && (kztell() >= 0))
|
|
|
|
{
|
|
|
|
if (kzcurhand >= 0) arraypos[kzcurhand] = kztell();
|
|
|
|
kzclose();
|
2016-04-01 23:02:23 +00:00
|
|
|
kzcurhand = -1;
|
2015-03-23 06:27:35 +00:00
|
|
|
}
|
|
|
|
if (searchfirst != 1 && (i = kzipopen(filename)) != 0)
|
|
|
|
{
|
|
|
|
kzcurhand = newhandle;
|
|
|
|
arraygrp[newhandle] = GRP_ZIP;
|
|
|
|
arrayhan[newhandle] = i;
|
|
|
|
arraypos[newhandle] = 0;
|
|
|
|
strcpy(filenamsav[newhandle],filename);
|
|
|
|
return newhandle;
|
|
|
|
}
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2015-03-23 06:27:35 +00:00
|
|
|
#else
|
|
|
|
UNREFERENCED_PARAMETER(tryzip);
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
|
|
|
|
2015-11-25 12:07:57 +00:00
|
|
|
for (int32_t k = searchfirst != 1 ? numgroupfiles-1 : 0; k >= 0; --k)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2015-11-25 12:07:57 +00:00
|
|
|
if (groupfil[k] < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (int32_t i = gnumfiles[k]-1; i >= 0; --i)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2015-11-25 12:07:57 +00:00
|
|
|
char const * const gfileptr = (char *)&gfilelist[k][i<<4];
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2015-11-25 12:07:57 +00:00
|
|
|
unsigned int j;
|
|
|
|
for (j = 0; j < 13; ++j)
|
|
|
|
{
|
|
|
|
if (!filename[j]) break;
|
|
|
|
if (toupperlookup[filename[j]] != toupperlookup[gfileptr[j]])
|
|
|
|
goto gnumfiles_continue;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2015-11-25 12:07:57 +00:00
|
|
|
if (j<13 && gfileptr[j]) continue; // JBF: because e1l1.map might exist before e1l1
|
|
|
|
if (j==13 && filename[j]) continue; // JBF: long file name
|
|
|
|
|
|
|
|
arraygrp[newhandle] = k;
|
|
|
|
arrayhan[newhandle] = i;
|
|
|
|
arraypos[newhandle] = 0;
|
|
|
|
return newhandle;
|
|
|
|
|
|
|
|
gnumfiles_continue: ;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-23 06:27:35 +00:00
|
|
|
|
|
|
|
return -1;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 08:30:41 +00:00
|
|
|
void krename(int32_t crcval, int32_t filenum, const char *newname)
|
2015-03-23 06:28:08 +00:00
|
|
|
{
|
2015-03-23 08:30:41 +00:00
|
|
|
for (int32_t k=numgroupfiles-1; k>=0; k--)
|
2015-03-23 06:28:08 +00:00
|
|
|
{
|
2015-03-23 08:30:41 +00:00
|
|
|
if (groupfil[k] >= 0 && groupcrc[k] == crcval)
|
2015-03-23 06:28:08 +00:00
|
|
|
{
|
2015-03-23 08:30:41 +00:00
|
|
|
Bstrncpy((char *)&gfilelist[k][filenum<<4], newname, 12);
|
|
|
|
return;
|
2015-03-23 06:28:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-25 12:08:00 +00:00
|
|
|
char const * kfileparent(int32_t const handle)
|
|
|
|
{
|
|
|
|
int32_t const groupnum = filegrp[handle];
|
|
|
|
|
|
|
|
if ((unsigned)groupnum >= MAXGROUPFILES || groupfil[groupnum] == -1)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return groupname[groupnum];
|
|
|
|
}
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
int32_t kopen4load(const char *filename, char searchfirst)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
int32_t newhandle = MAXOPENFILES-1;
|
|
|
|
|
|
|
|
if (filename==NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (filehan[newhandle] != -1)
|
|
|
|
{
|
|
|
|
newhandle--;
|
|
|
|
if (newhandle < 0)
|
|
|
|
{
|
|
|
|
Bprintf("TOO MANY FILES OPEN IN FILE GROUPING SYSTEM!");
|
|
|
|
Bexit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char *lastpfn = NULL;
|
|
|
|
|
|
|
|
int32_t h = kopen_internal(filename, &lastpfn, searchfirst, 1, 1, newhandle, filegrp, filehan, filepos);
|
|
|
|
|
2015-09-23 17:55:31 +00:00
|
|
|
Bfree(lastpfn);
|
2015-03-23 06:27:35 +00:00
|
|
|
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t kread_internal(int32_t handle, void *buffer, int32_t leng, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos)
|
|
|
|
{
|
|
|
|
int32_t filenum = arrayhan[handle];
|
|
|
|
int32_t groupnum = arraygrp[handle];
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2016-06-21 00:34:41 +00:00
|
|
|
if (groupnum == GRP_FILESYSTEM) return Bread(filenum,buffer,leng);
|
2006-04-23 06:44:19 +00:00
|
|
|
#ifdef WITHKPLIB
|
2015-03-23 06:27:18 +00:00
|
|
|
else if (groupnum == GRP_ZIP)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
|
|
|
if (kzcurhand != handle)
|
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); }
|
2006-04-24 19:04:22 +00:00
|
|
|
kzcurhand = handle;
|
|
|
|
kzipopen(filenamsav[handle]);
|
2015-03-23 06:27:35 +00:00
|
|
|
kzseek(arraypos[handle],SEEK_SET);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2016-06-21 00:34:41 +00:00
|
|
|
return kzread(buffer,leng);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
if (EDUKE32_PREDICT_FALSE(groupfil[groupnum] == -1))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int32_t rootgroupnum = groupnum;
|
|
|
|
int32_t i = 0;
|
|
|
|
while (groupfilgrp[rootgroupnum] != GRP_FILESYSTEM)
|
|
|
|
{
|
|
|
|
i += gfileoffs[groupfilgrp[rootgroupnum]][groupfil[rootgroupnum]];
|
|
|
|
rootgroupnum = groupfilgrp[rootgroupnum];
|
|
|
|
}
|
|
|
|
if (EDUKE32_PREDICT_TRUE(groupfil[rootgroupnum] != -1))
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
i += gfileoffs[groupnum][filenum]+arraypos[handle];
|
|
|
|
if (i != groupfilpos[rootgroupnum])
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
Blseek(groupfil[rootgroupnum],i,BSEEK_SET);
|
|
|
|
groupfilpos[rootgroupnum] = i;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2015-03-23 06:27:35 +00:00
|
|
|
leng = min(leng,(gfileoffs[groupnum][filenum+1]-gfileoffs[groupnum][filenum])-arraypos[handle]);
|
|
|
|
leng = Bread(groupfil[rootgroupnum],buffer,leng);
|
|
|
|
arraypos[handle] += leng;
|
|
|
|
groupfilpos[rootgroupnum] += leng;
|
2016-06-21 00:34:41 +00:00
|
|
|
return leng;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
|
2016-06-21 00:34:41 +00:00
|
|
|
return 0;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
int32_t klseek_internal(int32_t handle, int32_t offset, int32_t whence, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i, groupnum;
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
groupnum = arraygrp[handle];
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2016-06-21 00:34:41 +00:00
|
|
|
if (groupnum == GRP_FILESYSTEM) return Blseek(arrayhan[handle],offset,whence);
|
2006-04-23 06:44:19 +00:00
|
|
|
#ifdef WITHKPLIB
|
2015-03-23 06:27:18 +00:00
|
|
|
else if (groupnum == GRP_ZIP)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
|
|
|
if (kzcurhand != handle)
|
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); }
|
2006-04-24 19:04:22 +00:00
|
|
|
kzcurhand = handle;
|
|
|
|
kzipopen(filenamsav[handle]);
|
2015-03-23 06:27:35 +00:00
|
|
|
kzseek(arraypos[handle],SEEK_SET);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2016-06-21 00:34:41 +00:00
|
|
|
return kzseek(offset,whence);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
if (groupfil[groupnum] != -1)
|
|
|
|
{
|
2006-11-13 23:12:47 +00:00
|
|
|
switch (whence)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2006-11-13 23:12:47 +00:00
|
|
|
case BSEEK_SET:
|
2015-03-23 06:27:35 +00:00
|
|
|
arraypos[handle] = offset; break;
|
2006-11-13 23:12:47 +00:00
|
|
|
case BSEEK_END:
|
2015-03-23 06:27:35 +00:00
|
|
|
i = arrayhan[handle];
|
|
|
|
arraypos[handle] = (gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i])+offset;
|
2006-04-24 19:04:22 +00:00
|
|
|
break;
|
2006-11-13 23:12:47 +00:00
|
|
|
case BSEEK_CUR:
|
2015-03-23 06:27:35 +00:00
|
|
|
arraypos[handle] += offset; break;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2016-06-21 00:34:41 +00:00
|
|
|
return arraypos[handle];
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2016-06-21 00:34:41 +00:00
|
|
|
return -1;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
int32_t kfilelength_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i, groupnum;
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
groupnum = arraygrp[handle];
|
2015-03-23 06:27:18 +00:00
|
|
|
if (groupnum == GRP_FILESYSTEM)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2016-06-21 00:34:41 +00:00
|
|
|
// return (filelength(arrayhan[handle]))
|
2015-03-23 06:27:35 +00:00
|
|
|
return Bfilelength(arrayhan[handle]);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
#ifdef WITHKPLIB
|
2015-03-23 06:27:18 +00:00
|
|
|
else if (groupnum == GRP_ZIP)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
|
|
|
if (kzcurhand != handle)
|
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); }
|
2006-04-24 19:04:22 +00:00
|
|
|
kzcurhand = handle;
|
|
|
|
kzipopen(filenamsav[handle]);
|
2015-03-23 06:27:35 +00:00
|
|
|
kzseek(arraypos[handle],SEEK_SET);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
return kzfilelength();
|
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
2015-03-23 06:27:35 +00:00
|
|
|
i = arrayhan[handle];
|
2016-06-21 00:34:41 +00:00
|
|
|
return gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i];
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
int32_t ktell_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
int32_t groupnum = arraygrp[handle];
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2016-06-21 00:34:41 +00:00
|
|
|
if (groupnum == GRP_FILESYSTEM) return Blseek(arrayhan[handle],0,BSEEK_CUR);
|
2006-04-23 06:44:19 +00:00
|
|
|
#ifdef WITHKPLIB
|
2015-03-23 06:27:18 +00:00
|
|
|
else if (groupnum == GRP_ZIP)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
|
|
|
if (kzcurhand != handle)
|
|
|
|
{
|
2015-03-23 06:27:35 +00:00
|
|
|
if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); }
|
2006-04-24 19:04:22 +00:00
|
|
|
kzcurhand = handle;
|
|
|
|
kzipopen(filenamsav[handle]);
|
2015-03-23 06:27:35 +00:00
|
|
|
kzseek(arraypos[handle],SEEK_SET);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
return kztell();
|
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
2006-04-24 19:04:22 +00:00
|
|
|
if (groupfil[groupnum] != -1)
|
2015-03-23 06:27:35 +00:00
|
|
|
return arraypos[handle];
|
2016-06-21 00:34:41 +00:00
|
|
|
return -1;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 06:27:35 +00:00
|
|
|
void kclose_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if (handle < 0) return;
|
2015-03-23 06:27:35 +00:00
|
|
|
if (arraygrp[handle] == GRP_FILESYSTEM) Bclose(arrayhan[handle]);
|
2006-04-23 06:44:19 +00:00
|
|
|
#ifdef WITHKPLIB
|
2015-03-23 06:27:35 +00:00
|
|
|
else if (arraygrp[handle] == GRP_ZIP)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
|
|
|
kzclose();
|
|
|
|
kzcurhand = -1;
|
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
2015-03-23 06:27:35 +00:00
|
|
|
arrayhan[handle] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t kread(int32_t handle, void *buffer, int32_t leng)
|
|
|
|
{
|
|
|
|
return kread_internal(handle, buffer, leng, filegrp, filehan, filepos);
|
|
|
|
}
|
|
|
|
int32_t klseek(int32_t handle, int32_t offset, int32_t whence)
|
|
|
|
{
|
|
|
|
return klseek_internal(handle, offset, whence, filegrp, filehan, filepos);
|
|
|
|
}
|
|
|
|
int32_t kfilelength(int32_t handle)
|
|
|
|
{
|
|
|
|
return kfilelength_internal(handle, filegrp, filehan, filepos);
|
|
|
|
}
|
|
|
|
int32_t ktell(int32_t handle)
|
|
|
|
{
|
|
|
|
return ktell_internal(handle, filegrp, filehan, filepos);
|
|
|
|
}
|
|
|
|
void kclose(int32_t handle)
|
|
|
|
{
|
|
|
|
return kclose_internal(handle, filegrp, filehan);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32_t kread_grp(int32_t handle, void *buffer, int32_t leng)
|
|
|
|
{
|
|
|
|
return kread_internal(handle, buffer, leng, groupfilgrp, groupfil, groupfilpos);
|
|
|
|
}
|
|
|
|
static int32_t klseek_grp(int32_t handle, int32_t offset, int32_t whence)
|
|
|
|
{
|
|
|
|
return klseek_internal(handle, offset, whence, groupfilgrp, groupfil, groupfilpos);
|
|
|
|
}
|
|
|
|
static void kclose_grp(int32_t handle)
|
|
|
|
{
|
|
|
|
return kclose_internal(handle, groupfilgrp, groupfil);
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2011-02-21 23:08:21 +00:00
|
|
|
static int32_t klistaddentry(CACHE1D_FIND_REC **rec, const char *name, int32_t type, int32_t source)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
CACHE1D_FIND_REC *r = NULL, *attach = NULL;
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
if (*rec)
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t insensitive, v;
|
2006-04-24 19:04:22 +00:00
|
|
|
CACHE1D_FIND_REC *last = NULL;
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
for (attach = *rec; attach; last = attach, attach = attach->next)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if (type == CACHE1D_FIND_DRIVE) continue; // we just want to get to the end for drives
|
2006-04-23 06:44:19 +00:00
|
|
|
#ifdef _WIN32
|
2006-04-24 19:04:22 +00:00
|
|
|
insensitive = 1;
|
2006-04-23 06:44:19 +00:00
|
|
|
#else
|
2006-04-24 19:04:22 +00:00
|
|
|
if (source == CACHE1D_SOURCE_GRP || attach->source == CACHE1D_SOURCE_GRP)
|
|
|
|
insensitive = 1;
|
|
|
|
else if (source == CACHE1D_SOURCE_ZIP || attach->source == CACHE1D_SOURCE_ZIP)
|
|
|
|
insensitive = 1;
|
|
|
|
else
|
2012-02-18 17:56:13 +00:00
|
|
|
{
|
|
|
|
extern int16_t editstatus; // XXX
|
|
|
|
insensitive = !editstatus;
|
|
|
|
}
|
|
|
|
// ^ in the game, don't show file list case-sensitive
|
2006-04-23 06:44:19 +00:00
|
|
|
#endif
|
2006-04-24 19:04:22 +00:00
|
|
|
if (insensitive) v = Bstrcasecmp(name, attach->name);
|
|
|
|
else v = Bstrcmp(name, attach->name);
|
|
|
|
|
|
|
|
// sorted list
|
|
|
|
if (v > 0) continue; // item to add is bigger than the current one
|
|
|
|
// so look for something bigger than us
|
2007-12-12 17:42:14 +00:00
|
|
|
if (v < 0) // item to add is smaller than the current one
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
attach = NULL; // so wedge it between the current item and the one before
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// matched
|
|
|
|
if (source >= attach->source) return 1; // item to add is of lower priority
|
|
|
|
r = attach;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// wasn't found in the list, so attach to the end
|
|
|
|
if (!attach) attach = last;
|
|
|
|
}
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
if (r)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
r->type = type;
|
|
|
|
r->source = source;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
r = (CACHE1D_FIND_REC *)Xmalloc(sizeof(CACHE1D_FIND_REC)+strlen(name)+1);
|
|
|
|
|
2011-01-16 02:50:27 +00:00
|
|
|
r->name = (char *)r + sizeof(CACHE1D_FIND_REC); strcpy(r->name, name);
|
2006-04-24 19:04:22 +00:00
|
|
|
r->type = type;
|
|
|
|
r->source = source;
|
|
|
|
r->usera = r->userb = NULL;
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
if (!attach) // we are the first item
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
r->prev = NULL;
|
|
|
|
r->next = *rec;
|
2007-12-12 17:42:14 +00:00
|
|
|
if (*rec)(*rec)->prev = r;
|
2006-04-24 19:04:22 +00:00
|
|
|
*rec = r;
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
r->prev = attach;
|
|
|
|
r->next = attach->next;
|
|
|
|
if (attach->next) attach->next->prev = r;
|
|
|
|
attach->next = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void klistfree(CACHE1D_FIND_REC *rec)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
CACHE1D_FIND_REC *n;
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
while (rec)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
n = rec->next;
|
2009-10-07 06:47:35 +00:00
|
|
|
Bfree(rec);
|
2006-04-24 19:04:22 +00:00
|
|
|
rec = n;
|
|
|
|
}
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
CACHE1D_FIND_REC *klistpath(const char *_path, const char *mask, int32_t type)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
CACHE1D_FIND_REC *rec = NULL;
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
// pathsearchmode == 0: enumerates a path in the virtual filesystem
|
|
|
|
// pathsearchmode == 1: enumerates the system filesystem path passed in
|
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
path = Xstrdup(_path);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
// we don't need any leading dots and slashes or trailing slashes either
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i,j;
|
2007-12-12 17:42:14 +00:00
|
|
|
for (i=0; path[i] == '.' || toupperlookup[path[i]] == '/';) i++;
|
2006-04-24 19:04:22 +00:00
|
|
|
for (j=0; (path[j] = path[i]); j++,i++) ;
|
|
|
|
while (j>0 && toupperlookup[path[j-1]] == '/') j--;
|
|
|
|
path[j] = 0;
|
|
|
|
//initprintf("Cleaned up path = \"%s\"\n",path);
|
|
|
|
}
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
if (*path && (type & CACHE1D_FIND_DIR))
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if (klistaddentry(&rec, "..", CACHE1D_FIND_DIR, CACHE1D_SOURCE_CURDIR) < 0) goto failure;
|
|
|
|
}
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
if (!(type & CACHE1D_OPT_NOSTACK)) // current directory and paths in the search stack
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
searchpath_t *search = NULL;
|
|
|
|
BDIR *dir;
|
|
|
|
struct Bdirent *dirent;
|
2013-12-01 18:27:59 +00:00
|
|
|
|
|
|
|
static const char *const CUR_DIR = "./";
|
2008-08-04 03:48:46 +00:00
|
|
|
// Adjusted for the following "autoload" dir fix - NY00123
|
2013-12-01 18:27:59 +00:00
|
|
|
const char *d = pathsearchmode ? _path : CUR_DIR;
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t stackdepth = CACHE1D_SOURCE_CURDIR;
|
2006-04-24 19:04:22 +00:00
|
|
|
char buf[BMAX_PATH];
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
do
|
|
|
|
{
|
2013-12-01 18:27:59 +00:00
|
|
|
if (d==CUR_DIR && (type & CACHE1D_FIND_NOCURDIR))
|
|
|
|
goto next;
|
|
|
|
|
2011-09-06 17:46:34 +00:00
|
|
|
strcpy(buf, d);
|
2007-12-12 17:42:14 +00:00
|
|
|
if (!pathsearchmode)
|
|
|
|
{
|
2008-08-04 03:48:46 +00:00
|
|
|
// Fix for "autoload" dir in multi-user environments - NY00123
|
|
|
|
strcat(buf, path);
|
2006-04-24 19:04:22 +00:00
|
|
|
if (*path) strcat(buf, "/");
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
2011-09-06 17:46:34 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
dir = Bopendir(buf);
|
2007-12-12 17:42:14 +00:00
|
|
|
if (dir)
|
|
|
|
{
|
|
|
|
while ((dirent = Breaddir(dir)))
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if ((dirent->name[0] == '.' && dirent->name[1] == 0) ||
|
|
|
|
(dirent->name[0] == '.' && dirent->name[1] == '.' && dirent->name[2] == 0))
|
|
|
|
continue;
|
|
|
|
if ((type & CACHE1D_FIND_DIR) && !(dirent->mode & BS_IFDIR)) continue;
|
|
|
|
if ((type & CACHE1D_FIND_FILE) && (dirent->mode & BS_IFDIR)) continue;
|
|
|
|
if (!Bwildmatch(dirent->name, mask)) continue;
|
|
|
|
switch (klistaddentry(&rec, dirent->name,
|
|
|
|
(dirent->mode & BS_IFDIR) ? CACHE1D_FIND_DIR : CACHE1D_FIND_FILE,
|
2007-12-12 17:42:14 +00:00
|
|
|
stackdepth))
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
case -1: goto failure;
|
|
|
|
//case 1: initprintf("%s:%s dropped for lower priority\n", d,dirent->name); break;
|
|
|
|
//case 0: initprintf("%s:%s accepted\n", d,dirent->name); break;
|
2006-11-13 23:12:47 +00:00
|
|
|
default:
|
|
|
|
break;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Bclosedir(dir);
|
|
|
|
}
|
2013-12-01 18:27:59 +00:00
|
|
|
next:
|
|
|
|
if (pathsearchmode)
|
|
|
|
break;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
if (!search)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
search = searchpathhead;
|
|
|
|
stackdepth = CACHE1D_SOURCE_PATH;
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
search = search->next;
|
|
|
|
stackdepth++;
|
|
|
|
}
|
2013-12-01 18:27:59 +00:00
|
|
|
|
|
|
|
if (search)
|
|
|
|
d = search->path;
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
|
|
|
while (search);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
|
2013-02-14 16:02:16 +00:00
|
|
|
#ifdef WITHKPLIB
|
2013-12-01 18:27:59 +00:00
|
|
|
if (!(type & CACHE1D_FIND_NOCURDIR)) // TEMP, until we have sorted out fs.listpath() API
|
2007-12-12 17:42:14 +00:00
|
|
|
if (!pathsearchmode) // next, zip files
|
|
|
|
{
|
2009-07-29 21:56:56 +00:00
|
|
|
char buf[BMAX_PATH+4];
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i, j, ftype;
|
2006-04-24 19:04:22 +00:00
|
|
|
strcpy(buf,path);
|
|
|
|
if (*path) strcat(buf,"/");
|
|
|
|
strcat(buf,mask);
|
2007-12-12 17:42:14 +00:00
|
|
|
for (kzfindfilestart(buf); kzfindfile(buf);)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if (buf[0] != '|') continue; // local files we don't need
|
|
|
|
|
|
|
|
// scan for the end of the string and shift
|
|
|
|
// everything left a char in the process
|
2012-03-04 20:15:22 +00:00
|
|
|
for (i=1; (buf[i-1]=buf[i]); i++)
|
|
|
|
{
|
|
|
|
/* do nothing */
|
|
|
|
}
|
|
|
|
i-=2;
|
2014-07-22 07:25:54 +00:00
|
|
|
if (i < 0)
|
|
|
|
i = 0;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
// if there's a slash at the end, this is a directory entry
|
2007-12-12 17:42:14 +00:00
|
|
|
if (toupperlookup[buf[i]] == '/') { ftype = CACHE1D_FIND_DIR; buf[i] = 0; }
|
2006-04-24 19:04:22 +00:00
|
|
|
else ftype = CACHE1D_FIND_FILE;
|
|
|
|
|
|
|
|
// skip over the common characters at the beginning of the base path and the zip entry
|
2007-12-12 17:42:14 +00:00
|
|
|
for (j=0; buf[j] && path[j]; j++)
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if (toupperlookup[ path[j] ] == toupperlookup[ buf[j] ]) continue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// we've now hopefully skipped the common path component at the beginning.
|
|
|
|
// if that's true, we should be staring at a null byte in path and either any character in buf
|
|
|
|
// if j==0, or a slash if j>0
|
2007-12-12 17:42:14 +00:00
|
|
|
if ((!path[0] && buf[j]) || (!path[j] && toupperlookup[ buf[j] ] == '/'))
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if (j>0) j++;
|
|
|
|
|
|
|
|
// yep, so now we shift what follows back to the start of buf and while we do that,
|
|
|
|
// keep an eye out for any more slashes which would mean this entry has sub-entities
|
|
|
|
// and is useless to us.
|
|
|
|
for (i = 0; (buf[i] = buf[j]) && toupperlookup[buf[j]] != '/'; i++,j++) ;
|
|
|
|
if (toupperlookup[buf[j]] == '/') continue; // damn, try next entry
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
// if we're here it means we have a situation where:
|
|
|
|
// path = foo
|
|
|
|
// buf = foobar...
|
|
|
|
// or
|
|
|
|
// path = foobar
|
|
|
|
// buf = foo...
|
|
|
|
// which would mean the entry is higher up in the directory tree and is also useless
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((type & CACHE1D_FIND_DIR) && ftype != CACHE1D_FIND_DIR) continue;
|
|
|
|
if ((type & CACHE1D_FIND_FILE) && ftype != CACHE1D_FIND_FILE) continue;
|
|
|
|
|
|
|
|
// the entry is in the clear
|
2007-12-12 17:42:14 +00:00
|
|
|
switch (klistaddentry(&rec, buf, ftype, CACHE1D_SOURCE_ZIP))
|
|
|
|
{
|
2006-11-13 23:12:47 +00:00
|
|
|
case -1:
|
|
|
|
goto failure;
|
2006-04-24 19:04:22 +00:00
|
|
|
//case 1: initprintf("<ZIP>:%s dropped for lower priority\n", buf); break;
|
|
|
|
//case 0: initprintf("<ZIP>:%s accepted\n", buf); break;
|
2006-11-13 23:12:47 +00:00
|
|
|
default:
|
|
|
|
break;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-14 16:02:16 +00:00
|
|
|
#endif
|
2006-04-24 19:04:22 +00:00
|
|
|
// then, grp files
|
2013-12-01 18:27:59 +00:00
|
|
|
if (!(type & CACHE1D_FIND_NOCURDIR)) // TEMP, until we have sorted out fs.listpath() API
|
2007-12-12 17:42:14 +00:00
|
|
|
if (!pathsearchmode && !*path && (type & CACHE1D_FIND_FILE))
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
char buf[13];
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i,j;
|
2006-04-24 19:04:22 +00:00
|
|
|
buf[12] = 0;
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=0; i<MAXGROUPFILES; i++)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
if (groupfil[i] == -1) continue;
|
2009-02-19 16:47:54 +00:00
|
|
|
for (j=gnumfiles[i]-1; j>=0; j--)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
|
|
|
Bmemcpy(buf,&gfilelist[i][j<<4],12);
|
|
|
|
if (!Bwildmatch(buf,mask)) continue;
|
2007-12-12 17:42:14 +00:00
|
|
|
switch (klistaddentry(&rec, buf, CACHE1D_FIND_FILE, CACHE1D_SOURCE_GRP))
|
|
|
|
{
|
2006-11-13 23:12:47 +00:00
|
|
|
case -1:
|
|
|
|
goto failure;
|
2006-04-24 19:04:22 +00:00
|
|
|
//case 1: initprintf("<GRP>:%s dropped for lower priority\n", workspace); break;
|
|
|
|
//case 0: initprintf("<GRP>:%s accepted\n", workspace); break;
|
2006-11-13 23:12:47 +00:00
|
|
|
default:
|
|
|
|
break;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
if (pathsearchmode && (type & CACHE1D_FIND_DRIVE))
|
|
|
|
{
|
2006-04-24 19:04:22 +00:00
|
|
|
char *drives, *drp;
|
|
|
|
drives = Bgetsystemdrives();
|
2007-12-12 17:42:14 +00:00
|
|
|
if (drives)
|
|
|
|
{
|
|
|
|
for (drp=drives; *drp; drp+=strlen(drp)+1)
|
|
|
|
{
|
|
|
|
if (klistaddentry(&rec, drp, CACHE1D_FIND_DRIVE, CACHE1D_SOURCE_DRIVE) < 0)
|
|
|
|
{
|
2009-10-07 06:47:35 +00:00
|
|
|
Bfree(drives);
|
2006-04-24 19:04:22 +00:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
2009-10-07 06:47:35 +00:00
|
|
|
Bfree(drives);
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-07 06:47:35 +00:00
|
|
|
Bfree(path);
|
2013-11-22 19:26:52 +00:00
|
|
|
// XXX: may be NULL if no file was listed, and thus indistinguishable from
|
|
|
|
// an error condition.
|
2006-04-24 19:04:22 +00:00
|
|
|
return rec;
|
2006-04-23 06:44:19 +00:00
|
|
|
failure:
|
2009-10-07 06:47:35 +00:00
|
|
|
Bfree(path);
|
2006-04-24 19:04:22 +00:00
|
|
|
klistfree(rec);
|
|
|
|
return NULL;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
|
|
|
|
#endif // #ifdef CACHE1D_COMPRESS_ONLY / else
|
|
|
|
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
//Internal LZW variables
|
2006-04-23 06:44:19 +00:00
|
|
|
#define LZWSIZE 16384 //Watch out for shorts!
|
2012-02-20 19:52:04 +00:00
|
|
|
#define LZWSIZEPAD (LZWSIZE+(LZWSIZE>>4))
|
|
|
|
|
2013-06-13 17:11:04 +00:00
|
|
|
// lzwrawbuf LZWSIZE+1 (formerly): see (*) below
|
|
|
|
// XXX: lzwrawbuf size increased again :-/
|
|
|
|
static char lzwtmpbuf[LZWSIZEPAD], lzwrawbuf[LZWSIZEPAD], lzwcompbuf[LZWSIZEPAD];
|
2012-02-20 19:52:04 +00:00
|
|
|
static int16_t lzwbuf2[LZWSIZEPAD], lzwbuf3[LZWSIZEPAD];
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2012-02-18 22:14:45 +00:00
|
|
|
static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf);
|
|
|
|
static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf);
|
2006-04-23 06:44:19 +00:00
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
#ifndef CACHE1D_COMPRESS_ONLY
|
|
|
|
static int32_t kdfread_func(intptr_t fil, void *outbuf, int32_t length)
|
|
|
|
{
|
|
|
|
return kread((int32_t)fil, outbuf, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dfwrite_func(intptr_t fp, const void *inbuf, int32_t length)
|
|
|
|
{
|
|
|
|
Bfwrite(inbuf, length, 1, (BFILE *)fp);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
# define kdfread_func NULL
|
|
|
|
# define dfwrite_func NULL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// These two follow the argument order of the C functions "read" and "write":
|
|
|
|
// handle, buffer, length.
|
|
|
|
C1D_STATIC int32_t (*c1d_readfunc)(intptr_t, void *, int32_t) = kdfread_func;
|
|
|
|
C1D_STATIC void (*c1d_writefunc)(intptr_t, const void *, int32_t) = dfwrite_func;
|
|
|
|
|
|
|
|
|
|
|
|
////////// COMPRESSED READ //////////
|
|
|
|
|
2013-06-13 17:11:02 +00:00
|
|
|
static uint32_t decompress_part(intptr_t f, uint32_t *kgoalptr)
|
2012-11-11 17:57:13 +00:00
|
|
|
{
|
2013-06-13 17:11:02 +00:00
|
|
|
int16_t leng;
|
|
|
|
|
|
|
|
// Read compressed length first.
|
|
|
|
if (c1d_readfunc(f, &leng, 2) != 2)
|
2012-11-11 17:57:13 +00:00
|
|
|
return 1;
|
2013-06-13 17:11:02 +00:00
|
|
|
leng = B_LITTLE16(leng);
|
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
if (c1d_readfunc(f,lzwcompbuf, leng) != leng)
|
|
|
|
return 1;
|
2013-06-13 17:11:02 +00:00
|
|
|
|
|
|
|
*kgoalptr = lzwuncompress(lzwcompbuf, leng, lzwrawbuf);
|
2012-11-11 17:57:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read from 'f' into 'buffer'.
|
|
|
|
C1D_STATIC int32_t c1d_read_compressed(void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2014-12-26 17:29:54 +00:00
|
|
|
char *ptr = (char *)buffer;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
if (dasizeof > LZWSIZE)
|
|
|
|
{
|
2014-12-26 17:29:55 +00:00
|
|
|
count *= dasizeof;
|
|
|
|
dasizeof = 1;
|
2012-02-20 19:52:53 +00:00
|
|
|
}
|
|
|
|
|
2014-12-26 17:29:54 +00:00
|
|
|
uint32_t kgoal;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-12-26 17:29:54 +00:00
|
|
|
if (decompress_part(f, &kgoal))
|
|
|
|
return -1;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
Bmemcpy(ptr, lzwrawbuf, (int32_t)dasizeof);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-12-26 17:29:54 +00:00
|
|
|
uint32_t k = (int32_t)dasizeof;
|
|
|
|
|
|
|
|
for (uint32_t i=1; i<count; i++)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
|
|
|
if (k >= kgoal)
|
|
|
|
{
|
2013-06-13 17:11:02 +00:00
|
|
|
k = decompress_part(f, &kgoal);
|
2012-11-11 17:57:13 +00:00
|
|
|
if (k) return -1;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2012-02-20 19:52:38 +00:00
|
|
|
|
2014-12-26 17:29:54 +00:00
|
|
|
uint32_t j = 0;
|
2014-10-25 03:31:41 +00:00
|
|
|
|
|
|
|
if (dasizeof >= 4)
|
|
|
|
{
|
|
|
|
for (; j<dasizeof-4; j+=4)
|
|
|
|
{
|
2014-12-26 17:29:54 +00:00
|
|
|
ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255);
|
|
|
|
ptr[j+1+dasizeof] = ((ptr[j+1]+lzwrawbuf[j+1+k])&255);
|
|
|
|
ptr[j+2+dasizeof] = ((ptr[j+2]+lzwrawbuf[j+2+k])&255);
|
|
|
|
ptr[j+3+dasizeof] = ((ptr[j+3]+lzwrawbuf[j+3+k])&255);
|
2014-10-25 03:31:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; j<dasizeof; j++)
|
2012-02-20 19:52:38 +00:00
|
|
|
ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255);
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
k += dasizeof;
|
|
|
|
ptr += dasizeof;
|
|
|
|
}
|
2012-02-20 19:52:04 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
return count;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
int32_t kdfread(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil)
|
2012-02-20 19:52:53 +00:00
|
|
|
{
|
2012-11-11 17:57:13 +00:00
|
|
|
return c1d_read_compressed(buffer, dasizeof, count, (intptr_t)fil);
|
|
|
|
}
|
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
////////// COMPRESSED WRITE //////////
|
2012-02-20 19:52:53 +00:00
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
static uint32_t compress_part(uint32_t k, intptr_t f)
|
|
|
|
{
|
2013-06-13 17:11:02 +00:00
|
|
|
const int16_t leng = (int16_t)lzwcompress(lzwrawbuf, k, lzwcompbuf);
|
|
|
|
const int16_t swleng = B_LITTLE16(leng);
|
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
c1d_writefunc(f, &swleng, 2);
|
|
|
|
c1d_writefunc(f, lzwcompbuf, leng);
|
2013-06-13 17:11:02 +00:00
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
// Write from 'buffer' to 'f'.
|
|
|
|
C1D_STATIC void c1d_write_compressed(const void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2016-01-11 05:05:38 +00:00
|
|
|
char const *ptr = (char const *)buffer;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-12-26 17:29:55 +00:00
|
|
|
if (dasizeof > LZWSIZE)
|
2012-02-20 19:52:53 +00:00
|
|
|
{
|
2014-12-26 17:29:55 +00:00
|
|
|
count *= dasizeof;
|
|
|
|
dasizeof = 1;
|
2012-02-20 19:52:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Bmemcpy(lzwrawbuf, ptr, (int32_t)dasizeof);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-12-26 17:29:54 +00:00
|
|
|
uint32_t k = dasizeof;
|
2006-04-24 19:04:22 +00:00
|
|
|
if (k > LZWSIZE-dasizeof)
|
2012-11-11 17:57:13 +00:00
|
|
|
k = compress_part(k, f);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2014-12-26 17:29:54 +00:00
|
|
|
for (uint32_t i=1; i<count; i++)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2014-12-26 17:29:54 +00:00
|
|
|
uint32_t j = 0;
|
2014-10-25 03:31:41 +00:00
|
|
|
|
|
|
|
if (dasizeof >= 4)
|
|
|
|
{
|
|
|
|
for (; j<dasizeof-4; j+=4)
|
|
|
|
{
|
2014-12-26 17:29:54 +00:00
|
|
|
lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255);
|
|
|
|
lzwrawbuf[j+1+k] = ((ptr[j+1+dasizeof]-ptr[j+1])&255);
|
|
|
|
lzwrawbuf[j+2+k] = ((ptr[j+2+dasizeof]-ptr[j+2])&255);
|
|
|
|
lzwrawbuf[j+3+k] = ((ptr[j+3+dasizeof]-ptr[j+3])&255);
|
2014-10-25 03:31:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; j<dasizeof; j++)
|
2012-02-20 19:52:38 +00:00
|
|
|
lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255);
|
2012-02-20 19:52:53 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
k += dasizeof;
|
|
|
|
if (k > LZWSIZE-dasizeof)
|
2012-11-11 17:57:13 +00:00
|
|
|
k = compress_part(k, f);
|
2012-02-20 19:52:53 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
ptr += dasizeof;
|
|
|
|
}
|
2012-02-20 19:52:53 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
if (k > 0)
|
2012-11-11 17:57:13 +00:00
|
|
|
compress_part(k, f);
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
void dfwrite(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil)
|
|
|
|
{
|
|
|
|
c1d_write_compressed(buffer, dasizeof, count, (intptr_t)fil);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////// CORE COMPRESSION FUNCTIONS //////////
|
|
|
|
|
2012-02-18 22:14:45 +00:00
|
|
|
static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2012-02-20 19:52:53 +00:00
|
|
|
int32_t i, addr, addrcnt, *intptr;
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t bytecnt1, bitcnt, numbits, oneupnumbits;
|
|
|
|
int16_t *shortptr;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
int16_t *const lzwcodehead = lzwbuf2;
|
|
|
|
int16_t *const lzwcodenext = lzwbuf3;
|
|
|
|
|
2014-10-25 03:31:41 +00:00
|
|
|
for (i=255; i>=4; i-=4)
|
|
|
|
{
|
|
|
|
lzwtmpbuf[i] = i, lzwcodenext[i] = (i+1)&255;
|
|
|
|
lzwtmpbuf[i-1] = i-1, lzwcodenext[i-1] = (i) &255;
|
|
|
|
lzwtmpbuf[i-2] = i-2, lzwcodenext[i-2] = (i-1)&255;
|
|
|
|
lzwtmpbuf[i-3] = i-3, lzwcodenext[i-3] = (i-2)&255;
|
|
|
|
lzwcodehead[i] = lzwcodehead[i-1] = lzwcodehead[i-2] = lzwcodehead[i-3] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i>=0; i--)
|
2012-02-20 19:52:38 +00:00
|
|
|
{
|
|
|
|
lzwtmpbuf[i] = i;
|
2012-02-20 19:52:53 +00:00
|
|
|
lzwcodenext[i] = (i+1)&255;
|
|
|
|
lzwcodehead[i] = -1;
|
2012-02-20 19:52:38 +00:00
|
|
|
}
|
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
Bmemset(lzwoutbuf, 0, 4+uncompleng+1);
|
|
|
|
// clearbuf(lzwoutbuf,((uncompleng+15)+3)>>2,0L);
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3);
|
|
|
|
numbits = 8; oneupnumbits = (1<<8);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
addr = lzwinbuf[bytecnt1];
|
|
|
|
do
|
|
|
|
{
|
2012-02-20 19:52:53 +00:00
|
|
|
int32_t newaddr;
|
|
|
|
|
2014-10-25 03:31:41 +00:00
|
|
|
if (++bytecnt1 == uncompleng)
|
2012-02-20 19:52:53 +00:00
|
|
|
break; // (*) see XXX below
|
2012-02-20 19:52:38 +00:00
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
if (lzwcodehead[addr] < 0)
|
|
|
|
{
|
|
|
|
lzwcodehead[addr] = addrcnt;
|
|
|
|
break;
|
|
|
|
}
|
2012-02-20 19:52:38 +00:00
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
newaddr = lzwcodehead[addr];
|
2012-02-20 19:52:22 +00:00
|
|
|
while (lzwtmpbuf[newaddr] != lzwinbuf[bytecnt1])
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
2012-02-20 19:52:53 +00:00
|
|
|
if (lzwcodenext[newaddr] < 0)
|
|
|
|
{
|
|
|
|
lzwcodenext[newaddr] = addrcnt;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
newaddr = lzwcodenext[newaddr];
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2012-02-20 19:52:38 +00:00
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
if (lzwcodenext[newaddr] == addrcnt)
|
|
|
|
break;
|
2006-04-24 19:04:22 +00:00
|
|
|
addr = newaddr;
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
|
|
|
while (addr >= 0);
|
2012-02-20 19:52:38 +00:00
|
|
|
|
2012-02-20 19:52:53 +00:00
|
|
|
lzwtmpbuf[addrcnt] = lzwinbuf[bytecnt1]; // XXX: potential oob access of lzwinbuf via (*) above
|
|
|
|
lzwcodehead[addrcnt] = -1;
|
|
|
|
lzwcodenext[addrcnt] = -1;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
intptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
|
2006-04-24 19:04:22 +00:00
|
|
|
intptr[0] |= B_LITTLE32(addr<<(bitcnt&7));
|
|
|
|
bitcnt += numbits;
|
|
|
|
if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
|
|
|
|
bitcnt--;
|
|
|
|
|
|
|
|
addrcnt++;
|
2012-02-20 19:52:38 +00:00
|
|
|
if (addrcnt > oneupnumbits)
|
|
|
|
{ numbits++; oneupnumbits <<= 1; }
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
|
|
|
while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3)));
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
intptr = (int32_t *)&lzwoutbuf[bitcnt>>3];
|
2006-04-24 19:04:22 +00:00
|
|
|
intptr[0] |= B_LITTLE32(addr<<(bitcnt&7));
|
|
|
|
bitcnt += numbits;
|
|
|
|
if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1)))
|
|
|
|
bitcnt--;
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
shortptr = (int16_t *)lzwoutbuf;
|
|
|
|
shortptr[0] = B_LITTLE16((int16_t)uncompleng);
|
2013-06-13 17:11:02 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
if (((bitcnt+7)>>3) < uncompleng)
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
shortptr[1] = B_LITTLE16((int16_t)addrcnt);
|
2013-06-13 17:11:02 +00:00
|
|
|
return (bitcnt+7)>>3;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2012-02-20 19:52:38 +00:00
|
|
|
|
2013-06-13 17:11:02 +00:00
|
|
|
// Failed compressing, mark this in the stream.
|
2012-02-20 19:52:38 +00:00
|
|
|
shortptr[1] = 0;
|
2014-10-25 03:31:41 +00:00
|
|
|
|
|
|
|
for (i=0; i<uncompleng-4; i+=4)
|
|
|
|
{
|
|
|
|
lzwoutbuf[i+4] = lzwinbuf[i];
|
|
|
|
lzwoutbuf[i+5] = lzwinbuf[i+1];
|
|
|
|
lzwoutbuf[i+6] = lzwinbuf[i+2];
|
|
|
|
lzwoutbuf[i+7] = lzwinbuf[i+3];
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i<uncompleng; i++)
|
2012-02-20 19:52:38 +00:00
|
|
|
lzwoutbuf[i+4] = lzwinbuf[i];
|
|
|
|
|
2013-06-13 17:11:02 +00:00
|
|
|
return uncompleng+4;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
2012-02-18 22:14:45 +00:00
|
|
|
static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf)
|
2006-04-23 06:44:19 +00:00
|
|
|
{
|
2012-02-20 19:52:38 +00:00
|
|
|
int32_t currstr, numbits, oneupnumbits;
|
2013-06-13 17:11:02 +00:00
|
|
|
int32_t i, bitcnt, outbytecnt;
|
2006-04-24 19:04:22 +00:00
|
|
|
|
2012-02-20 19:52:38 +00:00
|
|
|
const int16_t *const shortptr = (const int16_t *)lzwinbuf;
|
|
|
|
const int32_t strtot = B_LITTLE16(shortptr[1]);
|
|
|
|
const int32_t uncompleng = B_LITTLE16(shortptr[0]);
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
if (strtot == 0)
|
|
|
|
{
|
2013-06-13 17:11:02 +00:00
|
|
|
if (lzwoutbuf==lzwrawbuf && lzwinbuf==lzwcompbuf)
|
|
|
|
{
|
|
|
|
Bassert((compleng-4)+3+0u < sizeof(lzwrawbuf));
|
|
|
|
Bassert((compleng-4)+3+0u < sizeof(lzwcompbuf)-4);
|
|
|
|
}
|
|
|
|
|
2012-11-11 17:57:13 +00:00
|
|
|
Bmemcpy(lzwoutbuf, lzwinbuf+4, (compleng-4)+3);
|
2012-02-20 19:52:38 +00:00
|
|
|
return uncompleng;
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2012-02-20 19:52:38 +00:00
|
|
|
|
2014-10-25 03:31:41 +00:00
|
|
|
for (i=255; i>=4; i-=4)
|
2012-02-20 19:52:38 +00:00
|
|
|
{
|
2014-10-25 03:31:41 +00:00
|
|
|
lzwbuf2[i] = lzwbuf3[i] = i;
|
|
|
|
lzwbuf2[i-1] = lzwbuf3[i-1] = i-1;
|
|
|
|
lzwbuf2[i-2] = lzwbuf3[i-2] = i-2;
|
|
|
|
lzwbuf2[i-3] = lzwbuf3[i-3] = i-3;
|
2012-02-20 19:52:38 +00:00
|
|
|
}
|
|
|
|
|
2014-10-25 03:31:41 +00:00
|
|
|
lzwbuf2[i] = lzwbuf3[i] = i;
|
|
|
|
lzwbuf2[i-1] = lzwbuf3[i-1] = i-1;
|
|
|
|
lzwbuf2[i-2] = lzwbuf3[i-2] = i-2;
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
currstr = 256; bitcnt = (4<<3); outbytecnt = 0;
|
|
|
|
numbits = 8; oneupnumbits = (1<<8);
|
|
|
|
do
|
|
|
|
{
|
2012-02-20 19:52:38 +00:00
|
|
|
const int32_t *const intptr = (const int32_t *)&lzwinbuf[bitcnt>>3];
|
|
|
|
|
2013-06-13 17:11:02 +00:00
|
|
|
int32_t dat = ((B_LITTLE32(intptr[0])>>(bitcnt&7)) & (oneupnumbits-1));
|
|
|
|
int32_t leng;
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
bitcnt += numbits;
|
|
|
|
if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1)))
|
2007-12-12 17:42:14 +00:00
|
|
|
{ dat &= ((oneupnumbits>>1)-1); bitcnt--; }
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
lzwbuf3[currstr] = dat;
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
for (leng=0; dat>=256; leng++,dat=lzwbuf3[dat])
|
2012-02-20 19:52:22 +00:00
|
|
|
lzwtmpbuf[leng] = lzwbuf2[dat];
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
lzwoutbuf[outbytecnt++] = dat;
|
2014-10-25 03:31:41 +00:00
|
|
|
|
|
|
|
for (i=leng-1; i>=4; i-=4, outbytecnt+=4)
|
|
|
|
{
|
|
|
|
lzwoutbuf[outbytecnt] = lzwtmpbuf[i];
|
|
|
|
lzwoutbuf[outbytecnt+1] = lzwtmpbuf[i-1];
|
|
|
|
lzwoutbuf[outbytecnt+2] = lzwtmpbuf[i-2];
|
|
|
|
lzwoutbuf[outbytecnt+3] = lzwtmpbuf[i-3];
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i>=0; i--)
|
2012-02-20 19:52:38 +00:00
|
|
|
lzwoutbuf[outbytecnt++] = lzwtmpbuf[i];
|
2006-04-24 19:04:22 +00:00
|
|
|
|
|
|
|
lzwbuf2[currstr-1] = dat; lzwbuf2[currstr] = dat;
|
|
|
|
currstr++;
|
2012-02-20 19:52:38 +00:00
|
|
|
if (currstr > oneupnumbits)
|
|
|
|
{ numbits++; oneupnumbits <<= 1; }
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
|
|
|
while (currstr < strtot);
|
2012-02-20 19:52:38 +00:00
|
|
|
|
|
|
|
return uncompleng;
|
2006-04-23 06:44:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vim:ts=4:sw=4:
|
|
|
|
*/
|