Rev 5064 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
99 | terminx | 1 | // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman |
2 | // Ken Silverman's official web site: "http://www.advsys.net/ken" |
||
3 | // See the included license file "BUILDLIC.TXT" for license info. |
||
4 | // |
||
5 | // This file has been modified from Ken Silverman's original release |
||
2456 | hendricks2 | 6 | // by Jonathon Fowler (jf@jonof.id.au) |
99 | terminx | 7 | |
3153 | helixhorne | 8 | |
9 | #ifdef CACHE1D_COMPRESS_ONLY |
||
10 | // Standalone libcache1d.so containing only the compression/decompression |
||
11 | // functions. |
||
12 | # include <stdint.h> |
||
13 | # include <stdio.h> |
||
14 | # include <string.h> |
||
15 | # include <stddef.h> |
||
4187 | helixhorne | 16 | # include <assert.h> |
3153 | helixhorne | 17 | |
18 | # define BFILE FILE |
||
19 | # define C1D_STATIC |
||
20 | # define B_LITTLE16(x) (x) |
||
21 | # define B_LITTLE32(x) (x) |
||
22 | # define Bmemset memset |
||
23 | # define Bmemcpy memcpy |
||
4187 | helixhorne | 24 | # define Bassert assert |
3153 | helixhorne | 25 | # define bsize_t size_t |
26 | #else |
||
27 | // cache1d.o for EDuke32 |
||
28 | # define C1D_STATIC static |
||
29 | |||
99 | terminx | 30 | #include "compat.h" |
2692 | helixhorne | 31 | #ifdef _WIN32 |
32 | // for FILENAME_CASE_CHECK |
||
33 | # include <shellapi.h> |
||
34 | #endif |
||
99 | terminx | 35 | #include "cache1d.h" |
36 | #include "pragmas.h" |
||
37 | #include "baselayer.h" |
||
5064 | hendricks2 | 38 | #include "crc32.h" |
99 | terminx | 39 | |
40 | #ifdef WITHKPLIB |
||
41 | #include "kplib.h" |
||
42 | |||
4637 | terminx | 43 | char *kpzbuf = NULL; |
44 | int32_t kpzbufsiz = 0; |
||
45 | |||
109 | terminx | 46 | //Insert '|' in front of filename |
47 | //Doing this tells kzopen to load the file only if inside a .ZIP file |
||
1712 | helixhorne | 48 | static intptr_t kzipopen(const char *filnam) |
99 | terminx | 49 | { |
1205 | terminx | 50 | uint32_t i; |
1479 | terminx | 51 | char newst[BMAX_PATH+8]; |
99 | terminx | 52 | |
109 | terminx | 53 | newst[0] = '|'; |
1229 | terminx | 54 | for (i=0; filnam[i] && (i < sizeof(newst)-2); i++) newst[i+1] = filnam[i]; |
109 | terminx | 55 | newst[i+1] = 0; |
56 | return(kzopen(newst)); |
||
99 | terminx | 57 | } |
58 | |||
59 | #endif |
||
60 | |||
61 | |||
62 | // This module keeps track of a standard linear cacheing system. |
||
63 | // To use this module, here's all you need to do: |
||
64 | // |
||
65 | // Step 1: Allocate a nice BIG buffer, like from 1MB-4MB and |
||
1205 | terminx | 66 | // Call initcache(int32_t cachestart, int32_t cachesize) where |
99 | terminx | 67 | // |
618 | terminx | 68 | // cachestart = (intptr_t)(pointer to start of BIG buffer) |
99 | terminx | 69 | // cachesize = length of BIG buffer |
70 | // |
||
1205 | terminx | 71 | // Step 2: Call allocache(intptr_t *bufptr, int32_t bufsiz, char *lockptr) |
99 | terminx | 72 | // whenever you need to allocate a buffer, where: |
73 | // |
||
618 | terminx | 74 | // *bufptr = pointer to multi-byte pointer to buffer |
99 | terminx | 75 | // Confused? Using this method, cache2d can remove |
76 | // previously allocated things from the cache safely by |
||
618 | terminx | 77 | // setting the multi-byte pointer to 0. |
99 | terminx | 78 | // bufsiz = number of bytes to allocate |
79 | // *lockptr = pointer to locking char which tells whether |
||
80 | // the region can be removed or not. If *lockptr = 0 then |
||
81 | // the region is not locked else its locked. |
||
82 | // |
||
83 | // Step 3: If you need to remove everything from the cache, or every |
||
84 | // unlocked item from the cache, you can call uninitcache(); |
||
85 | // Call uninitcache(0) to remove all unlocked items, or |
||
86 | // Call uninitcache(1) to remove everything. |
||
87 | // After calling uninitcache, it is still ok to call allocache |
||
88 | // without first calling initcache. |
||
89 | |||
90 | #define MAXCACHEOBJECTS 9216 |
||
91 | |||
4255 | helixhorne | 92 | #if !defined DEBUG_ALLOCACHE_AS_MALLOC |
1205 | terminx | 93 | static int32_t cachesize = 0; |
2438 | helixhorne | 94 | static char zerochar = 0; |
95 | static intptr_t cachestart = 0; |
||
96 | static int32_t agecount = 0; |
||
1205 | terminx | 97 | static int32_t lockrecip[200]; |
99 | terminx | 98 | |
2438 | helixhorne | 99 | int32_t cacnum = 0; |
100 | cactype cac[MAXCACHEOBJECTS]; |
||
4255 | helixhorne | 101 | #endif |
2438 | helixhorne | 102 | |
4637 | terminx | 103 | char toupperlookup[256] = |
3116 | hendricks2 | 104 | { |
105 | 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, |
||
106 | 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, |
||
107 | 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, |
||
108 | 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, |
||
109 | 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, |
||
110 | 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, |
||
111 | 0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, |
||
112 | 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f, |
||
113 | 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, |
||
114 | 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, |
||
115 | 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, |
||
116 | 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, |
||
117 | 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, |
||
118 | 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, |
||
119 | 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, |
||
120 | 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff |
||
121 | }; |
||
99 | terminx | 122 | |
1799 | helixhorne | 123 | static void reportandexit(const char *errormessage); |
99 | terminx | 124 | |
125 | |||
1205 | terminx | 126 | void initcache(intptr_t dacachestart, int32_t dacachesize) |
99 | terminx | 127 | { |
2438 | helixhorne | 128 | #ifndef DEBUG_ALLOCACHE_AS_MALLOC |
1205 | terminx | 129 | int32_t i; |
99 | terminx | 130 | |
4255 | helixhorne | 131 | for (i=1; i<200; i++) |
4658 | terminx | 132 | lockrecip[i] = tabledivide32_noinline(1<<28, 200-i); |
99 | terminx | 133 | |
618 | terminx | 134 | // The following code was relocated here from engine.c, since this |
135 | // function is only ever called once (from there), and it seems to |
||
136 | // really belong here: |
||
137 | // |
||
138 | // initcache((FP_OFF(pic)+15)&0xfffffff0,(cachesize-((-FP_OFF(pic))&15))&0xfffffff0); |
||
139 | // |
||
140 | // I'm not sure why it's necessary, but the code is making sure the |
||
1540 | terminx | 141 | // cache starts on a multiple of 16 bytes? -- SA |
99 | terminx | 142 | |
618 | terminx | 143 | //printf("BEFORE: cachestart = %x, cachesize = %d\n", dacachestart, dacachesize); |
144 | cachestart = ((uintptr_t)dacachestart+15)&~(uintptr_t)0xf; |
||
1346 | terminx | 145 | cachesize = (dacachesize-(((uintptr_t)(dacachestart))&0xf))&~(uintptr_t)0xf; |
618 | terminx | 146 | //printf("AFTER : cachestart = %x, cachesize = %d\n", cachestart, cachesize); |
147 | |||
109 | terminx | 148 | cac[0].leng = cachesize; |
149 | cac[0].lock = &zerochar; |
||
150 | cacnum = 1; |
||
99 | terminx | 151 | |
1178 | terminx | 152 | initprintf("Initialized %.1fM cache\n", (float)(dacachesize/1024.f/1024.f)); |
2438 | helixhorne | 153 | #else |
154 | UNREFERENCED_PARAMETER(dacachestart); |
||
155 | UNREFERENCED_PARAMETER(dacachesize); |
||
156 | #endif |
||
99 | terminx | 157 | } |
158 | |||
2360 | helixhorne | 159 | #ifdef DEBUG_ALLOCACHE_AS_MALLOC |
1205 | terminx | 160 | void allocache(intptr_t *newhandle, int32_t newbytes, char *newlockptr) |
99 | terminx | 161 | { |
2360 | helixhorne | 162 | UNREFERENCED_PARAMETER(newlockptr); |
163 | |||
4491 | helixhorne | 164 | *newhandle = (intptr_t)Xmalloc(newbytes); |
2360 | helixhorne | 165 | } |
166 | #else |
||
4661 | terminx | 167 | static inline void inc_and_check_cacnum(void) |
4255 | helixhorne | 168 | { |
4661 | terminx | 169 | if (++cacnum > MAXCACHEOBJECTS) |
4255 | helixhorne | 170 | reportandexit("Too many objects in cache! (cacnum > MAXCACHEOBJECTS)"); |
171 | } |
||
172 | |||
2360 | helixhorne | 173 | void allocache(intptr_t *newhandle, int32_t newbytes, char *newlockptr) |
174 | { |
||
4255 | helixhorne | 175 | int32_t i, z, bestz=0, bestval, besto=0, o1, sucklen, suckz; |
99 | terminx | 176 | |
618 | terminx | 177 | //printf(" ==> asking for %d bytes, ", newbytes); |
178 | // Make all requests a multiple of 16 bytes |
||
179 | newbytes = (newbytes+15)&0xfffffff0; |
||
180 | //printf("allocated %d bytes\n", newbytes); |
||
723 | terminx | 181 | |
109 | terminx | 182 | if ((unsigned)newbytes > (unsigned)cachesize) |
183 | { |
||
584 | terminx | 184 | Bprintf("Cachesize: %d\n",cachesize); |
795 | terminx | 185 | Bprintf("*Newhandle: 0x%" PRIxPTR ", Newbytes: %d, *Newlock: %d\n",(intptr_t)newhandle,newbytes,*newlockptr); |
109 | terminx | 186 | reportandexit("BUFFER TOO BIG TO FIT IN CACHE!"); |
187 | } |
||
99 | terminx | 188 | |
109 | terminx | 189 | if (*newlockptr == 0) |
190 | { |
||
191 | reportandexit("ALLOCACHE CALLED WITH LOCK OF 0!"); |
||
192 | } |
||
99 | terminx | 193 | |
109 | terminx | 194 | //Find best place |
195 | bestval = 0x7fffffff; o1 = cachesize; |
||
1229 | terminx | 196 | for (z=cacnum-1; z>=0; z--) |
109 | terminx | 197 | { |
4255 | helixhorne | 198 | int32_t zz, o2, daval; |
199 | |||
109 | terminx | 200 | o1 -= cac[z].leng; |
4255 | helixhorne | 201 | o2 = o1+newbytes; |
99 | terminx | 202 | |
4255 | helixhorne | 203 | if (o2 > cachesize) |
204 | continue; |
||
205 | |||
109 | terminx | 206 | daval = 0; |
1229 | terminx | 207 | for (i=o1,zz=z; i<o2; i+=cac[zz++].leng) |
109 | terminx | 208 | { |
4255 | helixhorne | 209 | if (*cac[zz].lock == 0) |
210 | continue; |
||
211 | |||
212 | if (*cac[zz].lock >= 200) |
||
213 | { |
||
214 | daval = 0x7fffffff; |
||
215 | break; |
||
216 | } |
||
217 | |||
218 | // Potential for eviction increases with |
||
219 | // - smaller item size |
||
220 | // - smaller lock byte value (but in [1 .. 199]) |
||
221 | daval += mulscale32(cac[zz].leng+65536, lockrecip[*cac[zz].lock]); |
||
222 | if (daval >= bestval) |
||
223 | break; |
||
109 | terminx | 224 | } |
4255 | helixhorne | 225 | |
109 | terminx | 226 | if (daval < bestval) |
227 | { |
||
228 | bestval = daval; besto = o1; bestz = z; |
||
229 | if (bestval == 0) break; |
||
230 | } |
||
231 | } |
||
99 | terminx | 232 | |
584 | terminx | 233 | //printf("%d %d %d\n",besto,newbytes,*newlockptr); |
99 | terminx | 234 | |
109 | terminx | 235 | if (bestval == 0x7fffffff) |
236 | reportandexit("CACHE SPACE ALL LOCKED UP!"); |
||
99 | terminx | 237 | |
109 | terminx | 238 | //Suck things out |
1229 | terminx | 239 | for (sucklen=-newbytes,suckz=bestz; sucklen<0; sucklen+=cac[suckz++].leng) |
4255 | helixhorne | 240 | if (*cac[suckz].lock) |
241 | *cac[suckz].hand = 0; |
||
99 | terminx | 242 | |
109 | terminx | 243 | //Remove all blocks except 1 |
4255 | helixhorne | 244 | suckz -= bestz+1; |
245 | cacnum -= suckz; |
||
246 | |||
2361 | helixhorne | 247 | Bmemmove(&cac[bestz], &cac[bestz+suckz], (cacnum-bestz)*sizeof(cactype)); |
4255 | helixhorne | 248 | cac[bestz].hand = newhandle; |
249 | *newhandle = cachestart + besto; |
||
109 | terminx | 250 | cac[bestz].leng = newbytes; |
251 | cac[bestz].lock = newlockptr; |
||
99 | terminx | 252 | |
109 | terminx | 253 | //Add new empty block if necessary |
4255 | helixhorne | 254 | if (sucklen <= 0) |
255 | return; |
||
99 | terminx | 256 | |
109 | terminx | 257 | bestz++; |
258 | if (bestz == cacnum) |
||
259 | { |
||
4255 | helixhorne | 260 | inc_and_check_cacnum(); |
261 | |||
109 | terminx | 262 | cac[bestz].leng = sucklen; |
263 | cac[bestz].lock = &zerochar; |
||
264 | return; |
||
265 | } |
||
99 | terminx | 266 | |
4255 | helixhorne | 267 | if (*cac[bestz].lock == 0) |
268 | { |
||
269 | cac[bestz].leng += sucklen; |
||
270 | return; |
||
271 | } |
||
99 | terminx | 272 | |
4255 | helixhorne | 273 | inc_and_check_cacnum(); |
274 | |||
275 | for (z=cacnum-1; z>bestz; z--) |
||
276 | cac[z] = cac[z-1]; |
||
109 | terminx | 277 | cac[bestz].leng = sucklen; |
278 | cac[bestz].lock = &zerochar; |
||
99 | terminx | 279 | } |
2360 | helixhorne | 280 | #endif |
99 | terminx | 281 | |
282 | void agecache(void) |
||
283 | { |
||
2360 | helixhorne | 284 | #ifndef DEBUG_ALLOCACHE_AS_MALLOC |
1592 | terminx | 285 | int32_t cnt = (cacnum>>4); |
99 | terminx | 286 | |
4255 | helixhorne | 287 | if (agecount >= cacnum) |
288 | agecount = cacnum-1; |
||
1658 | terminx | 289 | |
4255 | helixhorne | 290 | if (agecount < 0 || !cnt) |
291 | return; |
||
292 | |||
1592 | terminx | 293 | for (; cnt>=0; cnt--) |
109 | terminx | 294 | { |
4255 | helixhorne | 295 | // If we have pointer to lock char and it's in [2 .. 199], decrease. |
1657 | terminx | 296 | if (cac[agecount].lock && (((*cac[agecount].lock)-2)&255) < 198) |
1592 | terminx | 297 | (*cac[agecount].lock)--; |
99 | terminx | 298 | |
1592 | terminx | 299 | agecount--; |
4255 | helixhorne | 300 | if (agecount < 0) |
301 | agecount = cacnum-1; |
||
109 | terminx | 302 | } |
2360 | helixhorne | 303 | #endif |
99 | terminx | 304 | } |
305 | |||
1799 | helixhorne | 306 | static void reportandexit(const char *errormessage) |
99 | terminx | 307 | { |
2360 | helixhorne | 308 | #ifndef DEBUG_ALLOCACHE_AS_MALLOC |
1205 | terminx | 309 | int32_t i, j; |
99 | terminx | 310 | |
109 | terminx | 311 | //setvmode(0x3); |
312 | j = 0; |
||
1229 | terminx | 313 | for (i=0; i<cacnum; i++) |
109 | terminx | 314 | { |
584 | terminx | 315 | Bprintf("%d- ",i); |
795 | terminx | 316 | if (cac[i].hand) Bprintf("ptr: 0x%" PRIxPTR ", ",*cac[i].hand); |
109 | terminx | 317 | else Bprintf("ptr: NULL, "); |
584 | terminx | 318 | Bprintf("leng: %d, ",cac[i].leng); |
109 | terminx | 319 | if (cac[i].lock) Bprintf("lock: %d\n",*cac[i].lock); |
320 | else Bprintf("lock: NULL\n"); |
||
321 | j += cac[i].leng; |
||
322 | } |
||
584 | terminx | 323 | Bprintf("Cachesize = %d\n",cachesize); |
324 | Bprintf("Cacnum = %d\n",cacnum); |
||
325 | Bprintf("Cache length sum = %d\n",j); |
||
2360 | helixhorne | 326 | #endif |
109 | terminx | 327 | initprintf("ERROR: %s\n",errormessage); |
4502 | hendricks2 | 328 | Bexit(1); |
99 | terminx | 329 | } |
330 | |||
331 | #include <errno.h> |
||
332 | |||
584 | terminx | 333 | typedef struct _searchpath |
334 | { |
||
109 | terminx | 335 | struct _searchpath *next; |
336 | char *path; |
||
337 | size_t pathlen; // to save repeated calls to strlen() |
||
4886 | hendricks2 | 338 | int32_t user; |
99 | terminx | 339 | } searchpath_t; |
340 | static searchpath_t *searchpathhead = NULL; |
||
341 | static size_t maxsearchpathlen = 0; |
||
1205 | terminx | 342 | int32_t pathsearchmode = 0; |
99 | terminx | 343 | |
3059 | helixhorne | 344 | char *listsearchpath(int32_t initp) |
345 | { |
||
346 | static searchpath_t *sp; |
||
347 | |||
348 | if (initp) |
||
349 | sp = searchpathhead; |
||
350 | else if (sp != NULL) |
||
351 | sp = sp->next; |
||
352 | |||
353 | return sp ? sp->path : NULL; |
||
354 | } |
||
355 | |||
4886 | hendricks2 | 356 | int32_t addsearchpath_user(const char *p, int32_t user) |
99 | terminx | 357 | { |
3168 | helixhorne | 358 | struct Bstat st; |
109 | terminx | 359 | char *s; |
360 | searchpath_t *srch; |
||
4491 | helixhorne | 361 | char *path = Xstrdup(p); |
99 | terminx | 362 | |
3615 | terminx | 363 | if (path[Bstrlen(path)-1] == '\\') |
3619 | hendricks2 | 364 | path[Bstrlen(path)-1] = 0; // hack for stat() returning ENOENT on paths ending in a backslash |
3615 | terminx | 365 | |
366 | if (Bstat(path, &st) < 0) |
||
584 | terminx | 367 | { |
3615 | terminx | 368 | Bfree(path); |
109 | terminx | 369 | if (errno == ENOENT) return -2; |
370 | return -1; |
||
371 | } |
||
3615 | terminx | 372 | if (!(st.st_mode & BS_IFDIR)) |
373 | { |
||
374 | Bfree(path); |
||
375 | return -1; |
||
376 | } |
||
99 | terminx | 377 | |
4491 | helixhorne | 378 | srch = (searchpath_t *)Xmalloc(sizeof(searchpath_t)); |
99 | terminx | 379 | |
109 | terminx | 380 | srch->next = searchpathhead; |
3615 | terminx | 381 | srch->pathlen = Bstrlen(path)+1; |
4491 | helixhorne | 382 | srch->path = (char *)Xmalloc(srch->pathlen + 1); |
99 | terminx | 383 | |
3615 | terminx | 384 | Bstrcpy(srch->path, path); |
3637 | terminx | 385 | for (s=srch->path; *s; s++); |
2416 | helixhorne | 386 | s--; |
3637 | terminx | 387 | |
2416 | helixhorne | 388 | if (s<srch->path || toupperlookup[*s] != '/') |
389 | Bstrcat(srch->path, "/"); |
||
390 | |||
109 | terminx | 391 | searchpathhead = srch; |
2416 | helixhorne | 392 | if (srch->pathlen > maxsearchpathlen) |
393 | maxsearchpathlen = srch->pathlen; |
||
584 | terminx | 394 | |
421 | terminx | 395 | Bcorrectfilename(srch->path,0); |
584 | terminx | 396 | |
4886 | hendricks2 | 397 | srch->user = user; |
398 | |||
1645 | terminx | 399 | initprintf("Using %s for game data\n", srch->path); |
99 | terminx | 400 | |
3615 | terminx | 401 | Bfree(path); |
109 | terminx | 402 | return 0; |
99 | terminx | 403 | } |
404 | |||
3637 | terminx | 405 | int32_t removesearchpath(const char *p) |
406 | { |
||
407 | searchpath_t *srch; |
||
408 | char *s; |
||
4491 | helixhorne | 409 | char *path = (char *)Xmalloc(Bstrlen(p) + 2); |
3637 | terminx | 410 | |
411 | Bstrcpy(path, p); |
||
412 | |||
413 | if (path[Bstrlen(path)-1] == '\\') |
||
414 | path[Bstrlen(path)-1] = 0; |
||
415 | |||
416 | for (s=path; *s; s++); |
||
417 | s--; |
||
418 | |||
419 | if (s<path || toupperlookup[*s] != '/') |
||
420 | Bstrcat(path, "/"); |
||
421 | |||
422 | Bcorrectfilename(path,0); |
||
423 | |||
424 | for (srch = searchpathhead; srch; srch = srch->next) |
||
425 | { |
||
426 | if (!Bstrncmp(path, srch->path, srch->pathlen)) |
||
427 | { |
||
428 | // initprintf("Removing %s from path stack\n", path); |
||
429 | |||
430 | if (srch == searchpathhead) |
||
431 | searchpathhead = srch->next; |
||
432 | else |
||
433 | { |
||
434 | searchpath_t *sp; |
||
435 | |||
436 | for (sp = searchpathhead; sp; sp = sp->next) |
||
437 | { |
||
438 | if (sp->next == srch) |
||
439 | { |
||
440 | // initprintf("matched %s\n", srch->path); |
||
441 | sp->next = srch->next; |
||
442 | break; |
||
443 | } |
||
444 | } |
||
445 | } |
||
446 | |||
447 | Bfree(srch->path); |
||
448 | Bfree(srch); |
||
449 | break; |
||
450 | } |
||
451 | } |
||
452 | |||
453 | Bfree(path); |
||
454 | return 0; |
||
455 | } |
||
456 | |||
4886 | hendricks2 | 457 | void removesearchpaths_withuser(int32_t usermask) |
458 | { |
||
4905 | terminx | 459 | searchpath_t *next; |
460 | |||
461 | for (searchpath_t *srch = searchpathhead; srch; srch = next) |
||
4886 | hendricks2 | 462 | { |
4905 | terminx | 463 | next = srch->next; |
464 | |||
4886 | hendricks2 | 465 | if (srch->user & usermask) |
466 | { |
||
4905 | terminx | 467 | |
4886 | hendricks2 | 468 | if (srch == searchpathhead) |
469 | searchpathhead = srch->next; |
||
470 | else |
||
471 | { |
||
472 | searchpath_t *sp; |
||
473 | |||
474 | for (sp = searchpathhead; sp; sp = sp->next) |
||
475 | { |
||
476 | if (sp->next == srch) |
||
477 | { |
||
478 | sp->next = srch->next; |
||
479 | break; |
||
480 | } |
||
481 | } |
||
482 | } |
||
483 | |||
484 | Bfree(srch->path); |
||
485 | Bfree(srch); |
||
486 | } |
||
487 | } |
||
488 | } |
||
489 | |||
1205 | terminx | 490 | int32_t findfrompath(const char *fn, char **where) |
99 | terminx | 491 | { |
109 | terminx | 492 | searchpath_t *sp; |
493 | char *pfn, *ffn; |
||
1205 | terminx | 494 | int32_t allocsiz; |
99 | terminx | 495 | |
109 | terminx | 496 | // pathsearchmode == 0: tests current dir and then the dirs of the path stack |
497 | // pathsearchmode == 1: tests fn without modification, then like for pathsearchmode == 0 |
||
99 | terminx | 498 | |
584 | terminx | 499 | if (pathsearchmode) |
500 | { |
||
109 | terminx | 501 | // test unmolested filename first |
584 | terminx | 502 | if (access(fn, F_OK) >= 0) |
503 | { |
||
4491 | helixhorne | 504 | *where = Xstrdup(fn); |
109 | terminx | 505 | return 0; |
506 | } |
||
2693 | helixhorne | 507 | #ifndef _WIN32 |
1695 | helixhorne | 508 | else |
509 | { |
||
4491 | helixhorne | 510 | char *tfn = Bstrtolower(Xstrdup(fn)); |
1695 | helixhorne | 511 | |
512 | if (access(tfn, F_OK) >= 0) |
||
513 | { |
||
514 | *where = tfn; |
||
515 | return 0; |
||
516 | } |
||
517 | |||
518 | Bstrupr(tfn); |
||
519 | |||
520 | if (access(tfn, F_OK) >= 0) |
||
521 | { |
||
522 | *where = tfn; |
||
523 | return 0; |
||
524 | } |
||
525 | |||
526 | Bfree(tfn); |
||
527 | } |
||
2693 | helixhorne | 528 | #endif |
109 | terminx | 529 | } |
99 | terminx | 530 | |
1762 | terminx | 531 | for (pfn = (char *)fn; toupperlookup[*pfn] == '/'; pfn++); |
4491 | helixhorne | 532 | ffn = Xstrdup(pfn); |
533 | |||
109 | terminx | 534 | Bcorrectfilename(ffn,0); // compress relative paths |
535 | |||
536 | allocsiz = max(maxsearchpathlen, 2); // "./" (aka. curdir) |
||
537 | allocsiz += strlen(ffn); |
||
538 | allocsiz += 1; // a nul |
||
539 | |||
4491 | helixhorne | 540 | pfn = (char *)Xmalloc(allocsiz); |
109 | terminx | 541 | |
542 | strcpy(pfn, "./"); |
||
543 | strcat(pfn, ffn); |
||
584 | terminx | 544 | if (access(pfn, F_OK) >= 0) |
545 | { |
||
109 | terminx | 546 | *where = pfn; |
1527 | terminx | 547 | Bfree(ffn); |
109 | terminx | 548 | return 0; |
549 | } |
||
550 | |||
584 | terminx | 551 | for (sp = searchpathhead; sp; sp = sp->next) |
552 | { |
||
4491 | helixhorne | 553 | char *tfn = Xstrdup(ffn); |
1642 | terminx | 554 | |
109 | terminx | 555 | strcpy(pfn, sp->path); |
556 | strcat(pfn, ffn); |
||
557 | //initprintf("Trying %s\n", pfn); |
||
584 | terminx | 558 | if (access(pfn, F_OK) >= 0) |
559 | { |
||
109 | terminx | 560 | *where = pfn; |
1527 | terminx | 561 | Bfree(ffn); |
1642 | terminx | 562 | Bfree(tfn); |
109 | terminx | 563 | return 0; |
564 | } |
||
1642 | terminx | 565 | |
2693 | helixhorne | 566 | #ifndef _WIN32 |
1695 | helixhorne | 567 | //Check with all lowercase |
568 | strcpy(pfn, sp->path); |
||
569 | Bstrtolower(tfn); |
||
570 | strcat(pfn, tfn); |
||
571 | if (access(pfn, F_OK) >= 0) |
||
572 | { |
||
573 | *where = pfn; |
||
574 | Bfree(ffn); |
||
575 | Bfree(tfn); |
||
576 | return 0; |
||
577 | } |
||
578 | |||
579 | //Check again with uppercase |
||
580 | strcpy(pfn, sp->path); |
||
581 | Bstrupr(tfn); |
||
582 | strcat(pfn, tfn); |
||
583 | if (access(pfn, F_OK) >= 0) |
||
584 | { |
||
585 | *where = pfn; |
||
586 | Bfree(ffn); |
||
587 | Bfree(tfn); |
||
588 | return 0; |
||
589 | } |
||
2693 | helixhorne | 590 | #endif |
1642 | terminx | 591 | Bfree(tfn); |
109 | terminx | 592 | } |
2693 | helixhorne | 593 | |
1527 | terminx | 594 | Bfree(pfn); Bfree(ffn); |
109 | terminx | 595 | return -1; |
99 | terminx | 596 | } |
597 | |||
4680 | terminx | 598 | #if defined(_WIN32) && defined(DEBUGGINGAIDS) |
2692 | helixhorne | 599 | # define FILENAME_CASE_CHECK |
600 | #endif |
||
601 | |||
5059 | hendricks2 | 602 | static int32_t openfrompath_internal(const char *fn, char **where, int32_t flags, int32_t mode) |
603 | { |
||
604 | if (findfrompath(fn, where) < 0) |
||
605 | return -1; |
||
2692 | helixhorne | 606 | |
5059 | hendricks2 | 607 | return Bopen(*where, flags, mode); |
608 | } |
||
609 | |||
1205 | terminx | 610 | int32_t openfrompath(const char *fn, int32_t flags, int32_t mode) |
99 | terminx | 611 | { |
5059 | hendricks2 | 612 | char *pfn = NULL; |
99 | terminx | 613 | |
5059 | hendricks2 | 614 | int32_t h = openfrompath_internal(fn, &pfn, flags, mode); |
2702 | helixhorne | 615 | |
5059 | hendricks2 | 616 | if (pfn) |
2692 | helixhorne | 617 | Bfree(pfn); |
99 | terminx | 618 | |
109 | terminx | 619 | return h; |
99 | terminx | 620 | } |
621 | |||
1762 | terminx | 622 | BFILE *fopenfrompath(const char *fn, const char *mode) |
99 | terminx | 623 | { |
1205 | terminx | 624 | int32_t fh; |
109 | terminx | 625 | BFILE *h; |
1205 | terminx | 626 | int32_t bmode = 0, smode = 0; |
109 | terminx | 627 | const char *c; |
99 | terminx | 628 | |
584 | terminx | 629 | for (c=mode; c[0];) |
630 | { |
||
109 | terminx | 631 | if (c[0] == 'r' && c[1] == '+') { bmode = BO_RDWR; smode = BS_IREAD|BS_IWRITE; c+=2; } |
632 | else if (c[0] == 'r') { bmode = BO_RDONLY; smode = BS_IREAD; c+=1; } |
||
633 | else if (c[0] == 'w' && c[1] == '+') { bmode = BO_RDWR|BO_CREAT|BO_TRUNC; smode = BS_IREAD|BS_IWRITE; c+=2; } |
||
634 | else if (c[0] == 'w') { bmode = BO_WRONLY|BO_CREAT|BO_TRUNC; smode = BS_IREAD|BS_IWRITE; c+=2; } |
||
635 | else if (c[0] == 'a' && c[1] == '+') { bmode = BO_RDWR|BO_CREAT; smode=BS_IREAD|BS_IWRITE; c+=2; } |
||
636 | else if (c[0] == 'a') { bmode = BO_WRONLY|BO_CREAT; smode=BS_IREAD|BS_IWRITE; c+=1; } |
||
637 | else if (c[0] == 'b') { bmode |= BO_BINARY; c+=1; } |
||
638 | else if (c[1] == 't') { bmode |= BO_TEXT; c+=1; } |
||
639 | else c++; |
||
640 | } |
||
641 | fh = openfrompath(fn,bmode,smode); |
||
642 | if (fh < 0) return NULL; |
||
99 | terminx | 643 | |
109 | terminx | 644 | h = fdopen(fh,mode); |
645 | if (!h) close(fh); |
||
646 | |||
647 | return h; |
||
99 | terminx | 648 | } |
649 | |||
5058 | hendricks2 | 650 | #define MAXGROUPFILES 8 // Warning: Fix groupfil if this is changed |
651 | #define MAXOPENFILES 64 // Warning: Fix filehan if this is changed |
||
652 | |||
653 | enum { |
||
654 | GRP_RESERVED_ID_START = 254, |
||
655 | |||
656 | GRP_ZIP = GRP_RESERVED_ID_START, |
||
657 | GRP_FILESYSTEM = GRP_RESERVED_ID_START + 1, |
||
658 | }; |
||
659 | |||
660 | EDUKE32_STATIC_ASSERT(MAXGROUPFILES <= GRP_RESERVED_ID_START); |
||
661 | |||
1205 | terminx | 662 | int32_t numgroupfiles = 0; |
663 | static int32_t gnumfiles[MAXGROUPFILES]; |
||
5059 | hendricks2 | 664 | static intptr_t groupfil[MAXGROUPFILES] = {-1,-1,-1,-1,-1,-1,-1,-1}; |
1205 | terminx | 665 | static int32_t groupfilpos[MAXGROUPFILES]; |
5059 | hendricks2 | 666 | static uint8_t groupfilgrp[MAXGROUPFILES]; |
99 | terminx | 667 | static char *gfilelist[MAXGROUPFILES]; |
1205 | terminx | 668 | static int32_t *gfileoffs[MAXGROUPFILES]; |
5064 | hendricks2 | 669 | static int32_t groupcrc[MAXGROUPFILES]; |
99 | terminx | 670 | |
5058 | hendricks2 | 671 | static uint8_t filegrp[MAXOPENFILES]; |
1205 | terminx | 672 | static int32_t filepos[MAXOPENFILES]; |
737 | qbix79 | 673 | static intptr_t filehan[MAXOPENFILES] = |
584 | terminx | 674 | { |
675 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
||
676 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
||
677 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, |
||
678 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 |
||
679 | }; |
||
5058 | hendricks2 | 680 | |
99 | terminx | 681 | #ifdef WITHKPLIB |
682 | static char filenamsav[MAXOPENFILES][260]; |
||
1205 | terminx | 683 | static int32_t kzcurhand = -1; |
3187 | helixhorne | 684 | |
685 | int32_t cache1d_file_fromzip(int32_t fil) |
||
686 | { |
||
5058 | hendricks2 | 687 | return (filegrp[fil] == GRP_ZIP); |
3187 | helixhorne | 688 | } |
99 | terminx | 689 | #endif |
690 | |||
5059 | hendricks2 | 691 | 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); |
692 | static int32_t kread_grp(int32_t handle, void *buffer, int32_t leng); |
||
693 | static int32_t klseek_grp(int32_t handle, int32_t offset, int32_t whence); |
||
694 | static void kclose_grp(int32_t handle); |
||
695 | |||
5064 | hendricks2 | 696 | static void initgroupfile_crc32(int32_t handle) |
697 | { |
||
698 | int32_t b, crcval = 0; |
||
699 | #define BUFFER_SIZE (1024 * 1024 * 8) |
||
700 | uint8_t *buf = (uint8_t *)Xmalloc(BUFFER_SIZE); |
||
701 | klseek_grp(handle, 0, BSEEK_SET); |
||
702 | |||
703 | do |
||
704 | { |
||
705 | b = kread_grp(handle, buf, BUFFER_SIZE); |
||
706 | if (b > 0) crcval = Bcrc32((uint8_t *)buf, b, crcval); |
||
707 | } |
||
708 | while (b == BUFFER_SIZE); |
||
709 | |||
710 | groupcrc[handle] = crcval; |
||
711 | klseek_grp(handle, 0, BSEEK_SET); |
||
712 | Bfree(buf); |
||
713 | } |
||
714 | |||
1712 | helixhorne | 715 | int32_t initgroupfile(const char *filename) |
99 | terminx | 716 | { |
5060 | hendricks2 | 717 | char buf[70]; |
99 | terminx | 718 | |
4637 | terminx | 719 | // translate all backslashes (0x5c) to forward slashes (0x2f) |
109 | terminx | 720 | toupperlookup[0x5c] = 0x2f; |
721 | |||
5059 | hendricks2 | 722 | if (filename == NULL) |
723 | return -1; |
||
724 | |||
725 | // Technically you should be able to load more zips even if your GRPs are maxed out, |
||
726 | // but this system is already enough of a disaster. |
||
727 | if (numgroupfiles >= MAXGROUPFILES) |
||
728 | return -1; |
||
729 | |||
730 | char *zfn = NULL; |
||
731 | |||
732 | if (kopen_internal(filename, &zfn, 0, 0, 0, numgroupfiles, groupfilgrp, groupfil, groupfilpos) < 0) |
||
733 | return -1; |
||
734 | |||
99 | terminx | 735 | #ifdef WITHKPLIB |
5059 | hendricks2 | 736 | // check if ZIP |
737 | if (zfn) |
||
738 | { |
||
739 | kread_grp(numgroupfiles, buf, 4); |
||
740 | if (buf[0] == 0x50 && buf[1] == 0x4B && buf[2] == 0x03 && buf[3] == 0x04) |
||
741 | { |
||
742 | kclose_grp(numgroupfiles); |
||
99 | terminx | 743 | |
5059 | hendricks2 | 744 | kzaddstack(zfn); |
745 | Bfree(zfn); |
||
746 | return 0; |
||
747 | } |
||
748 | klseek_grp(numgroupfiles,0,BSEEK_SET); |
||
99 | terminx | 749 | |
1527 | terminx | 750 | Bfree(zfn); |
109 | terminx | 751 | } |
99 | terminx | 752 | #else |
5059 | hendricks2 | 753 | if (zfn) |
754 | Bfree(zfn); |
||
99 | terminx | 755 | #endif |
5059 | hendricks2 | 756 | |
757 | // check if GRP |
||
758 | kread_grp(numgroupfiles,buf,16); |
||
759 | if (!Bmemcmp(buf, "KenSilverman", 12)) |
||
109 | terminx | 760 | { |
1205 | terminx | 761 | gnumfiles[numgroupfiles] = B_LITTLE32(*((int32_t *)&buf[12])); |
99 | terminx | 762 | |
4491 | helixhorne | 763 | gfilelist[numgroupfiles] = (char *)Xmalloc(gnumfiles[numgroupfiles]<<4); |
764 | gfileoffs[numgroupfiles] = (int32_t *)Xmalloc((gnumfiles[numgroupfiles]+1)<<2); |
||
99 | terminx | 765 | |
5059 | hendricks2 | 766 | kread_grp(numgroupfiles,gfilelist[numgroupfiles],gnumfiles[numgroupfiles]<<4); |
99 | terminx | 767 | |
5059 | hendricks2 | 768 | int32_t j = (gnumfiles[numgroupfiles]+1)<<4, k; |
769 | for (int32_t i=0; i<gnumfiles[numgroupfiles]; i++) |
||
109 | terminx | 770 | { |
1205 | terminx | 771 | k = B_LITTLE32(*((int32_t *)&gfilelist[numgroupfiles][(i<<4)+12])); |
109 | terminx | 772 | gfilelist[numgroupfiles][(i<<4)+12] = 0; |
773 | gfileoffs[numgroupfiles][i] = j; |
||
774 | j += k; |
||
775 | } |
||
776 | gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j; |
||
5064 | hendricks2 | 777 | initgroupfile_crc32(numgroupfiles); |
5059 | hendricks2 | 778 | numgroupfiles++; |
779 | return 0; |
||
109 | terminx | 780 | } |
5060 | hendricks2 | 781 | klseek_grp(numgroupfiles, 0, BSEEK_SET); |
99 | terminx | 782 | |
5060 | hendricks2 | 783 | // check if SSI |
784 | // this performs several checks because there is no "SSI" magic |
||
785 | int32_t version; |
||
786 | kread_grp(numgroupfiles, &version, 4); |
||
787 | version = B_LITTLE32(version); |
||
788 | while (version == 1 || version == 2) // if |
||
789 | { |
||
790 | char zerobuf[70]; |
||
791 | Bmemset(zerobuf, 0, 70); |
||
792 | |||
793 | int32_t numfiles; |
||
794 | kread_grp(numgroupfiles, &numfiles, 4); |
||
795 | numfiles = B_LITTLE32(numfiles); |
||
796 | |||
797 | uint8_t temp, temp2; |
||
798 | |||
799 | // get the string length |
||
800 | kread_grp(numgroupfiles, &temp, 1); |
||
801 | if (temp > 31) // 32 bytes allocated for the string |
||
802 | break; |
||
803 | // seek to the end of the string |
||
804 | klseek_grp(numgroupfiles, temp, BSEEK_CUR); |
||
805 | // verify everything remaining is a null terminator |
||
806 | temp = 32 - temp; |
||
807 | kread_grp(numgroupfiles, buf, temp); |
||
808 | if (Bmemcmp(buf, zerobuf, temp)) |
||
809 | break; |
||
810 | |||
811 | if (version == 2) |
||
812 | { |
||
813 | // get the string length |
||
814 | kread_grp(numgroupfiles, &temp, 1); |
||
815 | if (temp > 11) // 12 bytes allocated for the string |
||
816 | break; |
||
817 | // seek to the end of the string |
||
818 | klseek_grp(numgroupfiles, temp, BSEEK_CUR); |
||
819 | // verify everything remaining is a null terminator |
||
820 | temp = 12 - temp; |
||
821 | kread_grp(numgroupfiles, buf, temp); |
||
822 | if (Bmemcmp(buf, zerobuf, temp)) |
||
823 | break; |
||
824 | } |
||
825 | |||
826 | temp2 = 0; |
||
827 | for (uint8_t i=0;i<3;i++) |
||
828 | { |
||
829 | // get the string length |
||
830 | kread_grp(numgroupfiles, &temp, 1); |
||
831 | if (temp > 70) // 70 bytes allocated for the string |
||
832 | { |
||
833 | temp2 = 1; |
||
834 | break; |
||
835 | } |
||
836 | // seek to the end of the string |
||
837 | klseek_grp(numgroupfiles, temp, BSEEK_CUR); |
||
838 | // verify everything remaining is a null terminator |
||
839 | temp = 70 - temp; |
||
840 | if (temp == 0) |
||
841 | continue; |
||
842 | kread_grp(numgroupfiles, buf, temp); |
||
843 | temp2 |= Bmemcmp(buf, zerobuf, temp); |
||
844 | } |
||
845 | if (temp2) |
||
846 | break; |
||
847 | |||
848 | // Passed all the tests: read data. |
||
849 | |||
850 | gnumfiles[numgroupfiles] = numfiles; |
||
851 | |||
852 | gfilelist[numgroupfiles] = (char *)Xmalloc(gnumfiles[numgroupfiles]<<4); |
||
853 | gfileoffs[numgroupfiles] = (int32_t *)Xmalloc((gnumfiles[numgroupfiles]+1)<<2); |
||
854 | |||
855 | int32_t j = (version == 2 ? 267 : 254) + (numfiles * 121), k; |
||
856 | for (int32_t i = 0; i < numfiles; i++) |
||
857 | { |
||
858 | // get the string length |
||
859 | kread_grp(numgroupfiles, &temp, 1); |
||
860 | if (temp > 12) |
||
861 | temp = 12; |
||
862 | // read the file name |
||
863 | kread_grp(numgroupfiles, &gfilelist[numgroupfiles][i<<4], temp); |
||
864 | gfilelist[numgroupfiles][(i<<4)+temp] = 0; |
||
865 | |||
866 | // skip to the end of the 12 bytes |
||
867 | klseek_grp(numgroupfiles, 12-temp, BSEEK_CUR); |
||
868 | |||
869 | // get the file size |
||
870 | kread_grp(numgroupfiles, &k, 4); |
||
871 | k = B_LITTLE32(k); |
||
872 | |||
873 | // record the offset of the file in the SSI |
||
874 | gfileoffs[numgroupfiles][i] = j; |
||
875 | j += k; |
||
876 | |||
877 | // skip unknown data |
||
878 | klseek_grp(numgroupfiles, 104, BSEEK_CUR); |
||
879 | } |
||
880 | gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j; |
||
5064 | hendricks2 | 881 | initgroupfile_crc32(numgroupfiles); |
5060 | hendricks2 | 882 | numgroupfiles++; |
883 | return 0; |
||
884 | } |
||
885 | |||
5059 | hendricks2 | 886 | kclose_grp(numgroupfiles); |
887 | return -1; |
||
99 | terminx | 888 | } |
889 | |||
890 | void uninitgroupfile(void) |
||
891 | { |
||
1205 | terminx | 892 | int32_t i; |
99 | terminx | 893 | |
1229 | terminx | 894 | for (i=numgroupfiles-1; i>=0; i--) |
109 | terminx | 895 | if (groupfil[i] != -1) |
896 | { |
||
1586 | terminx | 897 | Bfree(gfilelist[i]); |
898 | Bfree(gfileoffs[i]); |
||
109 | terminx | 899 | Bclose(groupfil[i]); |
900 | groupfil[i] = -1; |
||
901 | } |
||
902 | numgroupfiles = 0; |
||
99 | terminx | 903 | |
109 | terminx | 904 | // JBF 20040111: "close" any files open in groups |
1229 | terminx | 905 | for (i=0; i<MAXOPENFILES; i++) |
584 | terminx | 906 | { |
5058 | hendricks2 | 907 | if (filegrp[i] < GRP_RESERVED_ID_START) // JBF 20040130: not external or ZIPped |
109 | terminx | 908 | filehan[i] = -1; |
909 | } |
||
99 | terminx | 910 | } |
911 | |||
2692 | helixhorne | 912 | #ifdef FILENAME_CASE_CHECK |
913 | // See |
||
914 | // http://stackoverflow.com/questions/74451/getting-actual-file-name-with-proper-casing-on-windows |
||
915 | // for relevant discussion. |
||
916 | |||
5076 | terminx | 917 | static char fnbuf[BMAX_PATH]; |
918 | int fnofs; |
||
2692 | helixhorne | 919 | |
2702 | helixhorne | 920 | int32_t (*check_filename_casing_fn)(void) = NULL; |
921 | |||
2692 | helixhorne | 922 | // -1: failure, 0: match, 1: mismatch |
5076 | terminx | 923 | static int32_t check_filename_mismatch(const char * const filename, int ofs) |
2692 | helixhorne | 924 | { |
5076 | terminx | 925 | if (!GetShortPathNameA(filename, fnbuf, BMAX_PATH)) return -1; |
926 | if (!GetLongPathNameA(fnbuf, fnbuf, BMAX_PATH)) return -1; |
||
2702 | helixhorne | 927 | |
5076 | terminx | 928 | fnofs = ofs; |
2692 | helixhorne | 929 | |
5076 | terminx | 930 | int len = Bstrlen(fnbuf+ofs); |
3068 | terminx | 931 | |
5076 | terminx | 932 | char const * const fn = filename+ofs; |
933 | |||
934 | if (!Bstrncmp(fnbuf+ofs, fn, len)) |
||
2702 | helixhorne | 935 | return 0; |
936 | |||
5076 | terminx | 937 | char * const tfn = Bstrtolower(Xstrdup(fn)); |
938 | |||
939 | if (!Bstrncmp(fnbuf+ofs, tfn, len)) |
||
2702 | helixhorne | 940 | { |
5076 | terminx | 941 | Bfree(tfn); |
942 | return 0; |
||
943 | } |
||
2702 | helixhorne | 944 | |
5076 | terminx | 945 | Bstrupr(tfn); |
2702 | helixhorne | 946 | |
5076 | terminx | 947 | if (!Bstrncmp(fnbuf+ofs, tfn, len)) |
948 | { |
||
2702 | helixhorne | 949 | Bfree(tfn); |
5076 | terminx | 950 | return 0; |
2702 | helixhorne | 951 | } |
952 | |||
5076 | terminx | 953 | Bfree(tfn); |
954 | |||
2702 | helixhorne | 955 | return 1; |
2692 | helixhorne | 956 | } |
957 | #endif |
||
958 | |||
5059 | hendricks2 | 959 | 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) |
99 | terminx | 960 | { |
5059 | hendricks2 | 961 | int32_t j, k, fil; |
109 | terminx | 962 | char bad, *gfileptr; |
737 | qbix79 | 963 | intptr_t i; |
99 | terminx | 964 | |
5059 | hendricks2 | 965 | if (searchfirst == 0 && (fil = openfrompath_internal(filename, lastpfn, BO_BINARY|BO_RDONLY, BS_IREAD)) >= 0) |
109 | terminx | 966 | { |
2692 | helixhorne | 967 | #ifdef FILENAME_CASE_CHECK |
5059 | hendricks2 | 968 | if (checkcase && check_filename_casing_fn && check_filename_casing_fn()) |
2702 | helixhorne | 969 | { |
970 | int32_t status; |
||
971 | char *cp, *lastslash; |
||
2692 | helixhorne | 972 | |
2702 | helixhorne | 973 | // convert all slashes to backslashes because SHGetFileInfo() |
974 | // complains else! |
||
5059 | hendricks2 | 975 | lastslash = *lastpfn; |
976 | for (cp=*lastpfn; *cp; cp++) |
||
2702 | helixhorne | 977 | if (*cp=='/') |
978 | { |
||
979 | *cp = '\\'; |
||
980 | lastslash = cp; |
||
981 | } |
||
5059 | hendricks2 | 982 | if (lastslash != *lastpfn) |
2702 | helixhorne | 983 | lastslash++; |
984 | |||
5059 | hendricks2 | 985 | status = check_filename_mismatch(*lastpfn, lastslash-*lastpfn); |
2702 | helixhorne | 986 | |
987 | if (status == -1) |
||
2692 | helixhorne | 988 | { |
3385 | helixhorne | 989 | // initprintf("SHGetFileInfo failed with error code %lu\n", GetLastError()); |
2692 | helixhorne | 990 | } |
2702 | helixhorne | 991 | else if (status == 1) |
992 | { |
||
993 | initprintf("warning: case mismatch: passed \"%s\", real \"%s\"\n", |
||
5076 | terminx | 994 | lastslash, fnbuf+fnofs); |
2702 | helixhorne | 995 | } |
2692 | helixhorne | 996 | } |
5059 | hendricks2 | 997 | #else |
998 | UNREFERENCED_PARAMETER(checkcase); |
||
2692 | helixhorne | 999 | #endif |
5059 | hendricks2 | 1000 | arraygrp[newhandle] = GRP_FILESYSTEM; |
1001 | arrayhan[newhandle] = fil; |
||
1002 | arraypos[newhandle] = 0; |
||
1003 | return newhandle; |
||
1592 | terminx | 1004 | } |
99 | terminx | 1005 | |
109 | terminx | 1006 | for (; toupperlookup[*filename] == '/'; filename++); |
1007 | |||
99 | terminx | 1008 | #ifdef WITHKPLIB |
5059 | hendricks2 | 1009 | if (tryzip) |
109 | terminx | 1010 | { |
5059 | hendricks2 | 1011 | if ((kzcurhand != newhandle) && (kztell() >= 0)) |
1012 | { |
||
1013 | if (kzcurhand >= 0) arraypos[kzcurhand] = kztell(); |
||
1014 | kzclose(); |
||
1015 | } |
||
1016 | if (searchfirst != 1 && (i = kzipopen(filename)) != 0) |
||
1017 | { |
||
1018 | kzcurhand = newhandle; |
||
1019 | arraygrp[newhandle] = GRP_ZIP; |
||
1020 | arrayhan[newhandle] = i; |
||
1021 | arraypos[newhandle] = 0; |
||
1022 | strcpy(filenamsav[newhandle],filename); |
||
1023 | return newhandle; |
||
1024 | } |
||
109 | terminx | 1025 | } |
5059 | hendricks2 | 1026 | #else |
1027 | UNREFERENCED_PARAMETER(tryzip); |
||
99 | terminx | 1028 | #endif |
1029 | |||
1229 | terminx | 1030 | for (k=numgroupfiles-1; k>=0; k--) |
109 | terminx | 1031 | { |
1032 | if (searchfirst == 1) k = 0; |
||
1033 | if (groupfil[k] >= 0) |
||
1034 | { |
||
1229 | terminx | 1035 | for (i=gnumfiles[k]-1; i>=0; i--) |
109 | terminx | 1036 | { |
1037 | gfileptr = (char *)&gfilelist[k][i<<4]; |
||
99 | terminx | 1038 | |
109 | terminx | 1039 | bad = 0; |
1229 | terminx | 1040 | for (j=0; j<13; j++) |
109 | terminx | 1041 | { |
1042 | if (!filename[j]) break; |
||
1043 | if (toupperlookup[filename[j]] != toupperlookup[gfileptr[j]]) |
||
2438 | helixhorne | 1044 | { |
1045 | bad = 1; |
||
1046 | break; |
||
1047 | } |
||
109 | terminx | 1048 | } |
1049 | if (bad) continue; |
||
1050 | if (j<13 && gfileptr[j]) continue; // JBF: because e1l1.map might exist before e1l1 |
||
1592 | terminx | 1051 | if (j==13 && filename[j]) continue; // JBF: long file name |
99 | terminx | 1052 | |
5059 | hendricks2 | 1053 | arraygrp[newhandle] = k; |
1054 | arrayhan[newhandle] = i; |
||
1055 | arraypos[newhandle] = 0; |
||
1056 | return newhandle; |
||
109 | terminx | 1057 | } |
1058 | } |
||
1059 | } |
||
5059 | hendricks2 | 1060 | |
1061 | return -1; |
||
99 | terminx | 1062 | } |
1063 | |||
5064 | hendricks2 | 1064 | void krename(int32_t crcval, int32_t filenum, const char *newname) |
5061 | hendricks2 | 1065 | { |
5064 | hendricks2 | 1066 | for (int32_t k=numgroupfiles-1; k>=0; k--) |
5061 | hendricks2 | 1067 | { |
5064 | hendricks2 | 1068 | if (groupfil[k] >= 0 && groupcrc[k] == crcval) |
5061 | hendricks2 | 1069 | { |
5064 | hendricks2 | 1070 | Bstrncpy((char *)&gfilelist[k][filenum<<4], newname, 12); |
1071 | return; |
||
5061 | hendricks2 | 1072 | } |
1073 | } |
||
1074 | } |
||
1075 | |||
5059 | hendricks2 | 1076 | int32_t kopen4load(const char *filename, char searchfirst) |
99 | terminx | 1077 | { |
5059 | hendricks2 | 1078 | int32_t newhandle = MAXOPENFILES-1; |
99 | terminx | 1079 | |
5059 | hendricks2 | 1080 | if (filename==NULL) |
1081 | return -1; |
||
1082 | |||
1083 | while (filehan[newhandle] != -1) |
||
1084 | { |
||
1085 | newhandle--; |
||
1086 | if (newhandle < 0) |
||
1087 | { |
||
1088 | Bprintf("TOO MANY FILES OPEN IN FILE GROUPING SYSTEM!"); |
||
1089 | Bexit(0); |
||
1090 | } |
||
1091 | } |
||
1092 | |||
1093 | char *lastpfn = NULL; |
||
1094 | |||
1095 | int32_t h = kopen_internal(filename, &lastpfn, searchfirst, 1, 1, newhandle, filegrp, filehan, filepos); |
||
1096 | |||
1097 | if (lastpfn) |
||
1098 | Bfree(lastpfn); |
||
1099 | |||
1100 | return h; |
||
1101 | } |
||
1102 | |||
1103 | int32_t kread_internal(int32_t handle, void *buffer, int32_t leng, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos) |
||
1104 | { |
||
1105 | int32_t filenum = arrayhan[handle]; |
||
1106 | int32_t groupnum = arraygrp[handle]; |
||
1107 | |||
5058 | hendricks2 | 1108 | if (groupnum == GRP_FILESYSTEM) return(Bread(filenum,buffer,leng)); |
99 | terminx | 1109 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1110 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1111 | { |
1112 | if (kzcurhand != handle) |
||
1113 | { |
||
5059 | hendricks2 | 1114 | if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); } |
109 | terminx | 1115 | kzcurhand = handle; |
1116 | kzipopen(filenamsav[handle]); |
||
5059 | hendricks2 | 1117 | kzseek(arraypos[handle],SEEK_SET); |
109 | terminx | 1118 | } |
1119 | return(kzread(buffer,leng)); |
||
1120 | } |
||
99 | terminx | 1121 | #endif |
1122 | |||
5059 | hendricks2 | 1123 | if (EDUKE32_PREDICT_FALSE(groupfil[groupnum] == -1)) |
1124 | return 0; |
||
1125 | |||
1126 | int32_t rootgroupnum = groupnum; |
||
1127 | int32_t i = 0; |
||
1128 | while (groupfilgrp[rootgroupnum] != GRP_FILESYSTEM) |
||
109 | terminx | 1129 | { |
5059 | hendricks2 | 1130 | i += gfileoffs[groupfilgrp[rootgroupnum]][groupfil[rootgroupnum]]; |
1131 | rootgroupnum = groupfilgrp[rootgroupnum]; |
||
1132 | } |
||
1133 | if (EDUKE32_PREDICT_TRUE(groupfil[rootgroupnum] != -1)) |
||
1134 | { |
||
1135 | i += gfileoffs[groupnum][filenum]+arraypos[handle]; |
||
1136 | if (i != groupfilpos[rootgroupnum]) |
||
109 | terminx | 1137 | { |
5059 | hendricks2 | 1138 | Blseek(groupfil[rootgroupnum],i,BSEEK_SET); |
1139 | groupfilpos[rootgroupnum] = i; |
||
109 | terminx | 1140 | } |
5059 | hendricks2 | 1141 | leng = min(leng,(gfileoffs[groupnum][filenum+1]-gfileoffs[groupnum][filenum])-arraypos[handle]); |
1142 | leng = Bread(groupfil[rootgroupnum],buffer,leng); |
||
1143 | arraypos[handle] += leng; |
||
1144 | groupfilpos[rootgroupnum] += leng; |
||
109 | terminx | 1145 | return(leng); |
1146 | } |
||
99 | terminx | 1147 | |
109 | terminx | 1148 | return(0); |
99 | terminx | 1149 | } |
1150 | |||
5059 | hendricks2 | 1151 | int32_t klseek_internal(int32_t handle, int32_t offset, int32_t whence, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos) |
99 | terminx | 1152 | { |
1205 | terminx | 1153 | int32_t i, groupnum; |
99 | terminx | 1154 | |
5059 | hendricks2 | 1155 | groupnum = arraygrp[handle]; |
99 | terminx | 1156 | |
5059 | hendricks2 | 1157 | if (groupnum == GRP_FILESYSTEM) return(Blseek(arrayhan[handle],offset,whence)); |
99 | terminx | 1158 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1159 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1160 | { |
1161 | if (kzcurhand != handle) |
||
1162 | { |
||
5059 | hendricks2 | 1163 | if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); } |
109 | terminx | 1164 | kzcurhand = handle; |
1165 | kzipopen(filenamsav[handle]); |
||
5059 | hendricks2 | 1166 | kzseek(arraypos[handle],SEEK_SET); |
109 | terminx | 1167 | } |
1168 | return(kzseek(offset,whence)); |
||
1169 | } |
||
99 | terminx | 1170 | #endif |
1171 | |||
109 | terminx | 1172 | if (groupfil[groupnum] != -1) |
1173 | { |
||
331 | terminx | 1174 | switch (whence) |
109 | terminx | 1175 | { |
331 | terminx | 1176 | case BSEEK_SET: |
5059 | hendricks2 | 1177 | arraypos[handle] = offset; break; |
331 | terminx | 1178 | case BSEEK_END: |
5059 | hendricks2 | 1179 | i = arrayhan[handle]; |
1180 | arraypos[handle] = (gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i])+offset; |
||
109 | terminx | 1181 | break; |
331 | terminx | 1182 | case BSEEK_CUR: |
5059 | hendricks2 | 1183 | arraypos[handle] += offset; break; |
109 | terminx | 1184 | } |
5059 | hendricks2 | 1185 | return(arraypos[handle]); |
109 | terminx | 1186 | } |
1187 | return(-1); |
||
99 | terminx | 1188 | } |
1189 | |||
5059 | hendricks2 | 1190 | int32_t kfilelength_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos) |
99 | terminx | 1191 | { |
1205 | terminx | 1192 | int32_t i, groupnum; |
99 | terminx | 1193 | |
5059 | hendricks2 | 1194 | groupnum = arraygrp[handle]; |
5058 | hendricks2 | 1195 | if (groupnum == GRP_FILESYSTEM) |
584 | terminx | 1196 | { |
5059 | hendricks2 | 1197 | // return(filelength(arrayhan[handle])) |
1198 | return Bfilelength(arrayhan[handle]); |
||
109 | terminx | 1199 | } |
99 | terminx | 1200 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1201 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1202 | { |
1203 | if (kzcurhand != handle) |
||
1204 | { |
||
5059 | hendricks2 | 1205 | if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); } |
109 | terminx | 1206 | kzcurhand = handle; |
1207 | kzipopen(filenamsav[handle]); |
||
5059 | hendricks2 | 1208 | kzseek(arraypos[handle],SEEK_SET); |
109 | terminx | 1209 | } |
1210 | return kzfilelength(); |
||
1211 | } |
||
99 | terminx | 1212 | #endif |
5059 | hendricks2 | 1213 | i = arrayhan[handle]; |
109 | terminx | 1214 | return(gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i]); |
99 | terminx | 1215 | } |
1216 | |||
5059 | hendricks2 | 1217 | int32_t ktell_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos) |
99 | terminx | 1218 | { |
5059 | hendricks2 | 1219 | int32_t groupnum = arraygrp[handle]; |
99 | terminx | 1220 | |
5059 | hendricks2 | 1221 | if (groupnum == GRP_FILESYSTEM) return(Blseek(arrayhan[handle],0,BSEEK_CUR)); |
99 | terminx | 1222 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1223 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1224 | { |
1225 | if (kzcurhand != handle) |
||
1226 | { |
||
5059 | hendricks2 | 1227 | if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); } |
109 | terminx | 1228 | kzcurhand = handle; |
1229 | kzipopen(filenamsav[handle]); |
||
5059 | hendricks2 | 1230 | kzseek(arraypos[handle],SEEK_SET); |
109 | terminx | 1231 | } |
1232 | return kztell(); |
||
1233 | } |
||
99 | terminx | 1234 | #endif |
109 | terminx | 1235 | if (groupfil[groupnum] != -1) |
5059 | hendricks2 | 1236 | return arraypos[handle]; |
109 | terminx | 1237 | return(-1); |
99 | terminx | 1238 | } |
1239 | |||
5059 | hendricks2 | 1240 | void kclose_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan) |
99 | terminx | 1241 | { |
109 | terminx | 1242 | if (handle < 0) return; |
5059 | hendricks2 | 1243 | if (arraygrp[handle] == GRP_FILESYSTEM) Bclose(arrayhan[handle]); |
99 | terminx | 1244 | #ifdef WITHKPLIB |
5059 | hendricks2 | 1245 | else if (arraygrp[handle] == GRP_ZIP) |
109 | terminx | 1246 | { |
1247 | kzclose(); |
||
1248 | kzcurhand = -1; |
||
1249 | } |
||
99 | terminx | 1250 | #endif |
5059 | hendricks2 | 1251 | arrayhan[handle] = -1; |
99 | terminx | 1252 | } |
1253 | |||
5059 | hendricks2 | 1254 | int32_t kread(int32_t handle, void *buffer, int32_t leng) |
1255 | { |
||
1256 | return kread_internal(handle, buffer, leng, filegrp, filehan, filepos); |
||
1257 | } |
||
1258 | int32_t klseek(int32_t handle, int32_t offset, int32_t whence) |
||
1259 | { |
||
1260 | return klseek_internal(handle, offset, whence, filegrp, filehan, filepos); |
||
1261 | } |
||
1262 | int32_t kfilelength(int32_t handle) |
||
1263 | { |
||
1264 | return kfilelength_internal(handle, filegrp, filehan, filepos); |
||
1265 | } |
||
1266 | int32_t ktell(int32_t handle) |
||
1267 | { |
||
1268 | return ktell_internal(handle, filegrp, filehan, filepos); |
||
1269 | } |
||
1270 | void kclose(int32_t handle) |
||
1271 | { |
||
1272 | return kclose_internal(handle, filegrp, filehan); |
||
1273 | } |
||
1274 | |||
1275 | static int32_t kread_grp(int32_t handle, void *buffer, int32_t leng) |
||
1276 | { |
||
1277 | return kread_internal(handle, buffer, leng, groupfilgrp, groupfil, groupfilpos); |
||
1278 | } |
||
1279 | static int32_t klseek_grp(int32_t handle, int32_t offset, int32_t whence) |
||
1280 | { |
||
1281 | return klseek_internal(handle, offset, whence, groupfilgrp, groupfil, groupfilpos); |
||
1282 | } |
||
1283 | static void kclose_grp(int32_t handle) |
||
1284 | { |
||
1285 | return kclose_internal(handle, groupfilgrp, groupfil); |
||
1286 | } |
||
1287 | |||
1799 | helixhorne | 1288 | static int32_t klistaddentry(CACHE1D_FIND_REC **rec, const char *name, int32_t type, int32_t source) |
99 | terminx | 1289 | { |
109 | terminx | 1290 | CACHE1D_FIND_REC *r = NULL, *attach = NULL; |
99 | terminx | 1291 | |
584 | terminx | 1292 | if (*rec) |
1293 | { |
||
1205 | terminx | 1294 | int32_t insensitive, v; |
109 | terminx | 1295 | CACHE1D_FIND_REC *last = NULL; |
1296 | |||
584 | terminx | 1297 | for (attach = *rec; attach; last = attach, attach = attach->next) |
1298 | { |
||
109 | terminx | 1299 | if (type == CACHE1D_FIND_DRIVE) continue; // we just want to get to the end for drives |
99 | terminx | 1300 | #ifdef _WIN32 |
109 | terminx | 1301 | insensitive = 1; |
99 | terminx | 1302 | #else |
109 | terminx | 1303 | if (source == CACHE1D_SOURCE_GRP || attach->source == CACHE1D_SOURCE_GRP) |
1304 | insensitive = 1; |
||
1305 | else if (source == CACHE1D_SOURCE_ZIP || attach->source == CACHE1D_SOURCE_ZIP) |
||
1306 | insensitive = 1; |
||
1307 | else |
||
2356 | helixhorne | 1308 | { |
1309 | extern int16_t editstatus; // XXX |
||
1310 | insensitive = !editstatus; |
||
1311 | } |
||
1312 | // ^ in the game, don't show file list case-sensitive |
||
99 | terminx | 1313 | #endif |
109 | terminx | 1314 | if (insensitive) v = Bstrcasecmp(name, attach->name); |
1315 | else v = Bstrcmp(name, attach->name); |
||
99 | terminx | 1316 | |
109 | terminx | 1317 | // sorted list |
1318 | if (v > 0) continue; // item to add is bigger than the current one |
||
1319 | // so look for something bigger than us |
||
584 | terminx | 1320 | if (v < 0) // item to add is smaller than the current one |
1321 | { |
||
109 | terminx | 1322 | attach = NULL; // so wedge it between the current item and the one before |
1323 | break; |
||
1324 | } |
||
99 | terminx | 1325 | |
109 | terminx | 1326 | // matched |
1327 | if (source >= attach->source) return 1; // item to add is of lower priority |
||
1328 | r = attach; |
||
1329 | break; |
||
1330 | } |
||
99 | terminx | 1331 | |
109 | terminx | 1332 | // wasn't found in the list, so attach to the end |
1333 | if (!attach) attach = last; |
||
1334 | } |
||
99 | terminx | 1335 | |
584 | terminx | 1336 | if (r) |
1337 | { |
||
109 | terminx | 1338 | r->type = type; |
1339 | r->source = source; |
||
1340 | return 0; |
||
1341 | } |
||
99 | terminx | 1342 | |
4491 | helixhorne | 1343 | r = (CACHE1D_FIND_REC *)Xmalloc(sizeof(CACHE1D_FIND_REC)+strlen(name)+1); |
1344 | |||
1762 | terminx | 1345 | r->name = (char *)r + sizeof(CACHE1D_FIND_REC); strcpy(r->name, name); |
109 | terminx | 1346 | r->type = type; |
1347 | r->source = source; |
||
1348 | r->usera = r->userb = NULL; |
||
1349 | |||
584 | terminx | 1350 | if (!attach) // we are the first item |
1351 | { |
||
109 | terminx | 1352 | r->prev = NULL; |
1353 | r->next = *rec; |
||
584 | terminx | 1354 | if (*rec)(*rec)->prev = r; |
109 | terminx | 1355 | *rec = r; |
584 | terminx | 1356 | } |
1357 | else |
||
1358 | { |
||
109 | terminx | 1359 | r->prev = attach; |
1360 | r->next = attach->next; |
||
1361 | if (attach->next) attach->next->prev = r; |
||
1362 | attach->next = r; |
||
1363 | } |
||
1364 | |||
1365 | return 0; |
||
99 | terminx | 1366 | } |
1367 | |||
1368 | void klistfree(CACHE1D_FIND_REC *rec) |
||
1369 | { |
||
109 | terminx | 1370 | CACHE1D_FIND_REC *n; |
1371 | |||
584 | terminx | 1372 | while (rec) |
1373 | { |
||
109 | terminx | 1374 | n = rec->next; |
1527 | terminx | 1375 | Bfree(rec); |
109 | terminx | 1376 | rec = n; |
1377 | } |
||
99 | terminx | 1378 | } |
1379 | |||
1205 | terminx | 1380 | CACHE1D_FIND_REC *klistpath(const char *_path, const char *mask, int32_t type) |
99 | terminx | 1381 | { |
109 | terminx | 1382 | CACHE1D_FIND_REC *rec = NULL; |
1383 | char *path; |
||
99 | terminx | 1384 | |
109 | terminx | 1385 | // pathsearchmode == 0: enumerates a path in the virtual filesystem |
1386 | // pathsearchmode == 1: enumerates the system filesystem path passed in |
||
99 | terminx | 1387 | |
4491 | helixhorne | 1388 | path = Xstrdup(_path); |
99 | terminx | 1389 | |
109 | terminx | 1390 | // we don't need any leading dots and slashes or trailing slashes either |
1391 | { |
||
1205 | terminx | 1392 | int32_t i,j; |
584 | terminx | 1393 | for (i=0; path[i] == '.' || toupperlookup[path[i]] == '/';) i++; |
109 | terminx | 1394 | for (j=0; (path[j] = path[i]); j++,i++) ; |
1395 | while (j>0 && toupperlookup[path[j-1]] == '/') j--; |
||
1396 | path[j] = 0; |
||
1397 | //initprintf("Cleaned up path = \"%s\"\n",path); |
||
1398 | } |
||
99 | terminx | 1399 | |
584 | terminx | 1400 | if (*path && (type & CACHE1D_FIND_DIR)) |
1401 | { |
||
109 | terminx | 1402 | if (klistaddentry(&rec, "..", CACHE1D_FIND_DIR, CACHE1D_SOURCE_CURDIR) < 0) goto failure; |
1403 | } |
||
99 | terminx | 1404 | |
584 | terminx | 1405 | if (!(type & CACHE1D_OPT_NOSTACK)) // current directory and paths in the search stack |
1406 | { |
||
109 | terminx | 1407 | searchpath_t *search = NULL; |
1408 | BDIR *dir; |
||
1409 | struct Bdirent *dirent; |
||
4188 | helixhorne | 1410 | |
1411 | static const char *const CUR_DIR = "./"; |
||
932 | terminx | 1412 | // Adjusted for the following "autoload" dir fix - NY00123 |
4188 | helixhorne | 1413 | const char *d = pathsearchmode ? _path : CUR_DIR; |
1205 | terminx | 1414 | int32_t stackdepth = CACHE1D_SOURCE_CURDIR; |
109 | terminx | 1415 | char buf[BMAX_PATH]; |
99 | terminx | 1416 | |
584 | terminx | 1417 | do |
1418 | { |
||
4188 | helixhorne | 1419 | if (d==CUR_DIR && (type & CACHE1D_FIND_NOCURDIR)) |
1420 | goto next; |
||
1421 | |||
2010 | helixhorne | 1422 | strcpy(buf, d); |
584 | terminx | 1423 | if (!pathsearchmode) |
1424 | { |
||
932 | terminx | 1425 | // Fix for "autoload" dir in multi-user environments - NY00123 |
1426 | strcat(buf, path); |
||
109 | terminx | 1427 | if (*path) strcat(buf, "/"); |
584 | terminx | 1428 | } |
2010 | helixhorne | 1429 | |
109 | terminx | 1430 | dir = Bopendir(buf); |
584 | terminx | 1431 | if (dir) |
1432 | { |
||
1433 | while ((dirent = Breaddir(dir))) |
||
1434 | { |
||
109 | terminx | 1435 | if ((dirent->name[0] == '.' && dirent->name[1] == 0) || |
1436 | (dirent->name[0] == '.' && dirent->name[1] == '.' && dirent->name[2] == 0)) |
||
1437 | continue; |
||
1438 | if ((type & CACHE1D_FIND_DIR) && !(dirent->mode & BS_IFDIR)) continue; |
||
1439 | if ((type & CACHE1D_FIND_FILE) && (dirent->mode & BS_IFDIR)) continue; |
||
1440 | if (!Bwildmatch(dirent->name, mask)) continue; |
||
1441 | switch (klistaddentry(&rec, dirent->name, |
||
1442 | (dirent->mode & BS_IFDIR) ? CACHE1D_FIND_DIR : CACHE1D_FIND_FILE, |
||
584 | terminx | 1443 | stackdepth)) |
1444 | { |
||
109 | terminx | 1445 | case -1: goto failure; |
1446 | //case 1: initprintf("%s:%s dropped for lower priority\n", d,dirent->name); break; |
||
1447 | //case 0: initprintf("%s:%s accepted\n", d,dirent->name); break; |
||
331 | terminx | 1448 | default: |
1449 | break; |
||
109 | terminx | 1450 | } |
1451 | } |
||
1452 | Bclosedir(dir); |
||
1453 | } |
||
4188 | helixhorne | 1454 | next: |
1455 | if (pathsearchmode) |
||
1456 | break; |
||
99 | terminx | 1457 | |
584 | terminx | 1458 | if (!search) |
1459 | { |
||
109 | terminx | 1460 | search = searchpathhead; |
1461 | stackdepth = CACHE1D_SOURCE_PATH; |
||
584 | terminx | 1462 | } |
1463 | else |
||
1464 | { |
||
109 | terminx | 1465 | search = search->next; |
1466 | stackdepth++; |
||
1467 | } |
||
4188 | helixhorne | 1468 | |
1469 | if (search) |
||
1470 | d = search->path; |
||
584 | terminx | 1471 | } |
1472 | while (search); |
||
109 | terminx | 1473 | } |
1474 | |||
3484 | helixhorne | 1475 | #ifdef WITHKPLIB |
4188 | helixhorne | 1476 | if (!(type & CACHE1D_FIND_NOCURDIR)) // TEMP, until we have sorted out fs.listpath() API |
584 | terminx | 1477 | if (!pathsearchmode) // next, zip files |
1478 | { |
||
1479 | terminx | 1479 | char buf[BMAX_PATH+4]; |
1205 | terminx | 1480 | int32_t i, j, ftype; |
109 | terminx | 1481 | strcpy(buf,path); |
1482 | if (*path) strcat(buf,"/"); |
||
1483 | strcat(buf,mask); |
||
584 | terminx | 1484 | for (kzfindfilestart(buf); kzfindfile(buf);) |
1485 | { |
||
109 | terminx | 1486 | if (buf[0] != '|') continue; // local files we don't need |
1487 | |||
1488 | // scan for the end of the string and shift |
||
1489 | // everything left a char in the process |
||
2416 | helixhorne | 1490 | for (i=1; (buf[i-1]=buf[i]); i++) |
1491 | { |
||
1492 | /* do nothing */ |
||
1493 | } |
||
1494 | i-=2; |
||
4543 | hendricks2 | 1495 | if (i < 0) |
1496 | i = 0; |
||
109 | terminx | 1497 | |
1498 | // if there's a slash at the end, this is a directory entry |
||
584 | terminx | 1499 | if (toupperlookup[buf[i]] == '/') { ftype = CACHE1D_FIND_DIR; buf[i] = 0; } |
109 | terminx | 1500 | else ftype = CACHE1D_FIND_FILE; |
1501 | |||
1502 | // skip over the common characters at the beginning of the base path and the zip entry |
||
584 | terminx | 1503 | for (j=0; buf[j] && path[j]; j++) |
1504 | { |
||
109 | terminx | 1505 | if (toupperlookup[ path[j] ] == toupperlookup[ buf[j] ]) continue; |
1506 | break; |
||
1507 | } |
||
1508 | // we've now hopefully skipped the common path component at the beginning. |
||
1509 | // if that's true, we should be staring at a null byte in path and either any character in buf |
||
1510 | // if j==0, or a slash if j>0 |
||
584 | terminx | 1511 | if ((!path[0] && buf[j]) || (!path[j] && toupperlookup[ buf[j] ] == '/')) |
1512 | { |
||
109 | terminx | 1513 | if (j>0) j++; |
1514 | |||
1515 | // yep, so now we shift what follows back to the start of buf and while we do that, |
||
1516 | // keep an eye out for any more slashes which would mean this entry has sub-entities |
||
1517 | // and is useless to us. |
||
1518 | for (i = 0; (buf[i] = buf[j]) && toupperlookup[buf[j]] != '/'; i++,j++) ; |
||
1519 | if (toupperlookup[buf[j]] == '/') continue; // damn, try next entry |
||
584 | terminx | 1520 | } |
1521 | else |
||
1522 | { |
||
109 | terminx | 1523 | // if we're here it means we have a situation where: |
1524 | // path = foo |
||
1525 | // buf = foobar... |
||
1526 | // or |
||
1527 | // path = foobar |
||
1528 | // buf = foo... |
||
1529 | // which would mean the entry is higher up in the directory tree and is also useless |
||
1530 | continue; |
||
1531 | } |
||
1532 | |||
1533 | if ((type & CACHE1D_FIND_DIR) && ftype != CACHE1D_FIND_DIR) continue; |
||
1534 | if ((type & CACHE1D_FIND_FILE) && ftype != CACHE1D_FIND_FILE) continue; |
||
1535 | |||
1536 | // the entry is in the clear |
||
584 | terminx | 1537 | switch (klistaddentry(&rec, buf, ftype, CACHE1D_SOURCE_ZIP)) |
1538 | { |
||
331 | terminx | 1539 | case -1: |
1540 | goto failure; |
||
109 | terminx | 1541 | //case 1: initprintf("<ZIP>:%s dropped for lower priority\n", buf); break; |
1542 | //case 0: initprintf("<ZIP>:%s accepted\n", buf); break; |
||
331 | terminx | 1543 | default: |
1544 | break; |
||
109 | terminx | 1545 | } |
1546 | } |
||
1547 | } |
||
3484 | helixhorne | 1548 | #endif |
109 | terminx | 1549 | // then, grp files |
4188 | helixhorne | 1550 | if (!(type & CACHE1D_FIND_NOCURDIR)) // TEMP, until we have sorted out fs.listpath() API |
584 | terminx | 1551 | if (!pathsearchmode && !*path && (type & CACHE1D_FIND_FILE)) |
1552 | { |
||
109 | terminx | 1553 | char buf[13]; |
1205 | terminx | 1554 | int32_t i,j; |
109 | terminx | 1555 | buf[12] = 0; |
1229 | terminx | 1556 | for (i=0; i<MAXGROUPFILES; i++) |
584 | terminx | 1557 | { |
109 | terminx | 1558 | if (groupfil[i] == -1) continue; |
1229 | terminx | 1559 | for (j=gnumfiles[i]-1; j>=0; j--) |
109 | terminx | 1560 | { |
1561 | Bmemcpy(buf,&gfilelist[i][j<<4],12); |
||
1562 | if (!Bwildmatch(buf,mask)) continue; |
||
584 | terminx | 1563 | switch (klistaddentry(&rec, buf, CACHE1D_FIND_FILE, CACHE1D_SOURCE_GRP)) |
1564 | { |
||
331 | terminx | 1565 | case -1: |
1566 | goto failure; |
||
109 | terminx | 1567 | //case 1: initprintf("<GRP>:%s dropped for lower priority\n", workspace); break; |
1568 | //case 0: initprintf("<GRP>:%s accepted\n", workspace); break; |
||
331 | terminx | 1569 | default: |
1570 | break; |
||
109 | terminx | 1571 | } |
1572 | } |
||
1573 | } |
||
1574 | } |
||
1575 | |||
584 | terminx | 1576 | if (pathsearchmode && (type & CACHE1D_FIND_DRIVE)) |
1577 | { |
||
109 | terminx | 1578 | char *drives, *drp; |
1579 | drives = Bgetsystemdrives(); |
||
584 | terminx | 1580 | if (drives) |
1581 | { |
||
1582 | for (drp=drives; *drp; drp+=strlen(drp)+1) |
||
1583 | { |
||
1584 | if (klistaddentry(&rec, drp, CACHE1D_FIND_DRIVE, CACHE1D_SOURCE_DRIVE) < 0) |
||
1585 | { |
||
1527 | terminx | 1586 | Bfree(drives); |
109 | terminx | 1587 | goto failure; |
1588 | } |
||
1589 | } |
||
1527 | terminx | 1590 | Bfree(drives); |
109 | terminx | 1591 | } |
1592 | } |
||
1593 | |||
1527 | terminx | 1594 | Bfree(path); |
4175 | helixhorne | 1595 | // XXX: may be NULL if no file was listed, and thus indistinguishable from |
1596 | // an error condition. |
||
109 | terminx | 1597 | return rec; |
99 | terminx | 1598 | failure: |
1527 | terminx | 1599 | Bfree(path); |
109 | terminx | 1600 | klistfree(rec); |
1601 | return NULL; |
||
99 | terminx | 1602 | } |
1603 | |||
3153 | helixhorne | 1604 | |
1605 | #endif // #ifdef CACHE1D_COMPRESS_ONLY / else |
||
1606 | |||
1607 | |||
109 | terminx | 1608 | //Internal LZW variables |
99 | terminx | 1609 | #define LZWSIZE 16384 //Watch out for shorts! |
2366 | helixhorne | 1610 | #define LZWSIZEPAD (LZWSIZE+(LZWSIZE>>4)) |
99 | terminx | 1611 | |
3880 | helixhorne | 1612 | // lzwrawbuf LZWSIZE+1 (formerly): see (*) below |
1613 | // XXX: lzwrawbuf size increased again :-/ |
||
1614 | static char lzwtmpbuf[LZWSIZEPAD], lzwrawbuf[LZWSIZEPAD], lzwcompbuf[LZWSIZEPAD]; |
||
2366 | helixhorne | 1615 | static int16_t lzwbuf2[LZWSIZEPAD], lzwbuf3[LZWSIZEPAD]; |
1616 | |||
2361 | helixhorne | 1617 | static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf); |
1618 | static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf); |
||
99 | terminx | 1619 | |
3153 | helixhorne | 1620 | #ifndef CACHE1D_COMPRESS_ONLY |
1621 | static int32_t kdfread_func(intptr_t fil, void *outbuf, int32_t length) |
||
99 | terminx | 1622 | { |
3153 | helixhorne | 1623 | return kread((int32_t)fil, outbuf, length); |
1624 | } |
||
1625 | |||
1626 | static void dfwrite_func(intptr_t fp, const void *inbuf, int32_t length) |
||
1627 | { |
||
1628 | Bfwrite(inbuf, length, 1, (BFILE *)fp); |
||
1629 | } |
||
1630 | #else |
||
1631 | # define kdfread_func NULL |
||
1632 | # define dfwrite_func NULL |
||
1633 | #endif |
||
1634 | |||
1635 | // These two follow the argument order of the C functions "read" and "write": |
||
1636 | // handle, buffer, length. |
||
1637 | C1D_STATIC int32_t (*c1d_readfunc)(intptr_t, void *, int32_t) = kdfread_func; |
||
1638 | C1D_STATIC void (*c1d_writefunc)(intptr_t, const void *, int32_t) = dfwrite_func; |
||
1639 | |||
1640 | |||
1641 | ////////// COMPRESSED READ ////////// |
||
1642 | |||
3879 | helixhorne | 1643 | static uint32_t decompress_part(intptr_t f, uint32_t *kgoalptr) |
3153 | helixhorne | 1644 | { |
3879 | helixhorne | 1645 | int16_t leng; |
1646 | |||
1647 | // Read compressed length first. |
||
1648 | if (c1d_readfunc(f, &leng, 2) != 2) |
||
3153 | helixhorne | 1649 | return 1; |
3879 | helixhorne | 1650 | leng = B_LITTLE16(leng); |
1651 | |||
3153 | helixhorne | 1652 | if (c1d_readfunc(f,lzwcompbuf, leng) != leng) |
1653 | return 1; |
||
3879 | helixhorne | 1654 | |
1655 | *kgoalptr = lzwuncompress(lzwcompbuf, leng, lzwrawbuf); |
||
3153 | helixhorne | 1656 | return 0; |
1657 | } |
||
1658 | |||
1659 | // Read from 'f' into 'buffer'. |
||
1660 | C1D_STATIC int32_t c1d_read_compressed(void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f) |
||
1661 | { |
||
4837 | helixhorne | 1662 | char *ptr = (char *)buffer; |
99 | terminx | 1663 | |
2369 | helixhorne | 1664 | if (dasizeof > LZWSIZE) |
1665 | { |
||
4838 | helixhorne | 1666 | count *= dasizeof; |
1667 | dasizeof = 1; |
||
2369 | helixhorne | 1668 | } |
1669 | |||
4837 | helixhorne | 1670 | uint32_t kgoal; |
99 | terminx | 1671 | |
4837 | helixhorne | 1672 | if (decompress_part(f, &kgoal)) |
1673 | return -1; |
||
99 | terminx | 1674 | |
3153 | helixhorne | 1675 | Bmemcpy(ptr, lzwrawbuf, (int32_t)dasizeof); |
99 | terminx | 1676 | |
4837 | helixhorne | 1677 | uint32_t k = (int32_t)dasizeof; |
1678 | |||
1679 | for (uint32_t i=1; i<count; i++) |
||
109 | terminx | 1680 | { |
1681 | if (k >= kgoal) |
||
1682 | { |
||
3879 | helixhorne | 1683 | k = decompress_part(f, &kgoal); |
3153 | helixhorne | 1684 | if (k) return -1; |
109 | terminx | 1685 | } |
2368 | helixhorne | 1686 | |
4837 | helixhorne | 1687 | uint32_t j = 0; |
4665 | terminx | 1688 | |
1689 | if (dasizeof >= 4) |
||
1690 | { |
||
1691 | for (; j<dasizeof-4; j+=4) |
||
1692 | { |
||
4837 | helixhorne | 1693 | ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255); |
1694 | ptr[j+1+dasizeof] = ((ptr[j+1]+lzwrawbuf[j+1+k])&255); |
||
1695 | ptr[j+2+dasizeof] = ((ptr[j+2]+lzwrawbuf[j+2+k])&255); |
||
1696 | ptr[j+3+dasizeof] = ((ptr[j+3]+lzwrawbuf[j+3+k])&255); |
||
4665 | terminx | 1697 | } |
1698 | } |
||
1699 | |||
1700 | for (; j<dasizeof; j++) |
||
2368 | helixhorne | 1701 | ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255); |
1702 | |||
109 | terminx | 1703 | k += dasizeof; |
1704 | ptr += dasizeof; |
||
1705 | } |
||
2366 | helixhorne | 1706 | |
109 | terminx | 1707 | return count; |
99 | terminx | 1708 | } |
1709 | |||
3153 | helixhorne | 1710 | int32_t kdfread(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil) |
2369 | helixhorne | 1711 | { |
3153 | helixhorne | 1712 | return c1d_read_compressed(buffer, dasizeof, count, (intptr_t)fil); |
1713 | } |
||
2369 | helixhorne | 1714 | |
1715 | |||
3153 | helixhorne | 1716 | ////////// COMPRESSED WRITE ////////// |
1717 | |||
1718 | static uint32_t compress_part(uint32_t k, intptr_t f) |
||
1719 | { |
||
3879 | helixhorne | 1720 | const int16_t leng = (int16_t)lzwcompress(lzwrawbuf, k, lzwcompbuf); |
1721 | const int16_t swleng = B_LITTLE16(leng); |
||
1722 | |||
3153 | helixhorne | 1723 | c1d_writefunc(f, &swleng, 2); |
1724 | c1d_writefunc(f, lzwcompbuf, leng); |
||
3879 | helixhorne | 1725 | |
2369 | helixhorne | 1726 | return 0; |
1727 | } |
||
1728 | |||
3153 | helixhorne | 1729 | // Write from 'buffer' to 'f'. |
1730 | C1D_STATIC void c1d_write_compressed(const void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f) |
||
99 | terminx | 1731 | { |
4665 | terminx | 1732 | const char *ptr = (char*)buffer; |
99 | terminx | 1733 | |
4838 | helixhorne | 1734 | if (dasizeof > LZWSIZE) |
2369 | helixhorne | 1735 | { |
4838 | helixhorne | 1736 | count *= dasizeof; |
1737 | dasizeof = 1; |
||
2369 | helixhorne | 1738 | } |
1739 | |||
1740 | Bmemcpy(lzwrawbuf, ptr, (int32_t)dasizeof); |
||
1741 | |||
4837 | helixhorne | 1742 | uint32_t k = dasizeof; |
109 | terminx | 1743 | if (k > LZWSIZE-dasizeof) |
3153 | helixhorne | 1744 | k = compress_part(k, f); |
99 | terminx | 1745 | |
4837 | helixhorne | 1746 | for (uint32_t i=1; i<count; i++) |
109 | terminx | 1747 | { |
4837 | helixhorne | 1748 | uint32_t j = 0; |
4665 | terminx | 1749 | |
1750 | if (dasizeof >= 4) |
||
1751 | { |
||
1752 | for (; j<dasizeof-4; j+=4) |
||
1753 | { |
||
4837 | helixhorne | 1754 | lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255); |
1755 | lzwrawbuf[j+1+k] = ((ptr[j+1+dasizeof]-ptr[j+1])&255); |
||
1756 | lzwrawbuf[j+2+k] = ((ptr[j+2+dasizeof]-ptr[j+2])&255); |
||
1757 | lzwrawbuf[j+3+k] = ((ptr[j+3+dasizeof]-ptr[j+3])&255); |
||
4665 | terminx | 1758 | } |
1759 | } |
||
1760 | |||
1761 | for (; j<dasizeof; j++) |
||
2368 | helixhorne | 1762 | lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255); |
2369 | helixhorne | 1763 | |
109 | terminx | 1764 | k += dasizeof; |
1765 | if (k > LZWSIZE-dasizeof) |
||
3153 | helixhorne | 1766 | k = compress_part(k, f); |
2369 | helixhorne | 1767 | |
109 | terminx | 1768 | ptr += dasizeof; |
1769 | } |
||
2369 | helixhorne | 1770 | |
109 | terminx | 1771 | if (k > 0) |
3153 | helixhorne | 1772 | compress_part(k, f); |
99 | terminx | 1773 | } |
1774 | |||
3153 | helixhorne | 1775 | void dfwrite(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil) |
1776 | { |
||
1777 | c1d_write_compressed(buffer, dasizeof, count, (intptr_t)fil); |
||
1778 | } |
||
1779 | |||
1780 | ////////// CORE COMPRESSION FUNCTIONS ////////// |
||
1781 | |||
2361 | helixhorne | 1782 | static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf) |
99 | terminx | 1783 | { |
2369 | helixhorne | 1784 | int32_t i, addr, addrcnt, *intptr; |
1205 | terminx | 1785 | int32_t bytecnt1, bitcnt, numbits, oneupnumbits; |
1786 | int16_t *shortptr; |
||
99 | terminx | 1787 | |
2369 | helixhorne | 1788 | int16_t *const lzwcodehead = lzwbuf2; |
1789 | int16_t *const lzwcodenext = lzwbuf3; |
||
1790 | |||
4665 | terminx | 1791 | for (i=255; i>=4; i-=4) |
2368 | helixhorne | 1792 | { |
4665 | terminx | 1793 | lzwtmpbuf[i] = i, lzwcodenext[i] = (i+1)&255; |
1794 | lzwtmpbuf[i-1] = i-1, lzwcodenext[i-1] = (i) &255; |
||
1795 | lzwtmpbuf[i-2] = i-2, lzwcodenext[i-2] = (i-1)&255; |
||
1796 | lzwtmpbuf[i-3] = i-3, lzwcodenext[i-3] = (i-2)&255; |
||
1797 | lzwcodehead[i] = lzwcodehead[i-1] = lzwcodehead[i-2] = lzwcodehead[i-3] = -1; |
||
1798 | } |
||
1799 | |||
1800 | for (; i>=0; i--) |
||
1801 | { |
||
2368 | helixhorne | 1802 | lzwtmpbuf[i] = i; |
2369 | helixhorne | 1803 | lzwcodenext[i] = (i+1)&255; |
1804 | lzwcodehead[i] = -1; |
||
2368 | helixhorne | 1805 | } |
1806 | |||
2369 | helixhorne | 1807 | Bmemset(lzwoutbuf, 0, 4+uncompleng+1); |
1808 | // clearbuf(lzwoutbuf,((uncompleng+15)+3)>>2,0L); |
||
99 | terminx | 1809 | |
109 | terminx | 1810 | addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3); |
1811 | numbits = 8; oneupnumbits = (1<<8); |
||
1812 | do |
||
1813 | { |
||
1814 | addr = lzwinbuf[bytecnt1]; |
||
1815 | do |
||
1816 | { |
||
2369 | helixhorne | 1817 | int32_t newaddr; |
1818 | |||
4665 | terminx | 1819 | if (++bytecnt1 == uncompleng) |
2369 | helixhorne | 1820 | break; // (*) see XXX below |
2368 | helixhorne | 1821 | |
2369 | helixhorne | 1822 | if (lzwcodehead[addr] < 0) |
1823 | { |
||
1824 | lzwcodehead[addr] = addrcnt; |
||
1825 | break; |
||
1826 | } |
||
2368 | helixhorne | 1827 | |
2369 | helixhorne | 1828 | newaddr = lzwcodehead[addr]; |
2367 | helixhorne | 1829 | while (lzwtmpbuf[newaddr] != lzwinbuf[bytecnt1]) |
109 | terminx | 1830 | { |
2369 | helixhorne | 1831 | if (lzwcodenext[newaddr] < 0) |
1832 | { |
||
1833 | lzwcodenext[newaddr] = addrcnt; |
||
1834 | break; |
||
1835 | } |
||
1836 | newaddr = lzwcodenext[newaddr]; |
||
109 | terminx | 1837 | } |
2368 | helixhorne | 1838 | |
2369 | helixhorne | 1839 | if (lzwcodenext[newaddr] == addrcnt) |
1840 | break; |
||
109 | terminx | 1841 | addr = newaddr; |
584 | terminx | 1842 | } |
1843 | while (addr >= 0); |
||
2368 | helixhorne | 1844 | |
2369 | helixhorne | 1845 | lzwtmpbuf[addrcnt] = lzwinbuf[bytecnt1]; // XXX: potential oob access of lzwinbuf via (*) above |
1846 | lzwcodehead[addrcnt] = -1; |
||
1847 | lzwcodenext[addrcnt] = -1; |
||
99 | terminx | 1848 | |
1205 | terminx | 1849 | intptr = (int32_t *)&lzwoutbuf[bitcnt>>3]; |
109 | terminx | 1850 | intptr[0] |= B_LITTLE32(addr<<(bitcnt&7)); |
1851 | bitcnt += numbits; |
||
1852 | if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1))) |
||
1853 | bitcnt--; |
||
99 | terminx | 1854 | |
109 | terminx | 1855 | addrcnt++; |
2368 | helixhorne | 1856 | if (addrcnt > oneupnumbits) |
1857 | { numbits++; oneupnumbits <<= 1; } |
||
584 | terminx | 1858 | } |
1859 | while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3))); |
||
99 | terminx | 1860 | |
1205 | terminx | 1861 | intptr = (int32_t *)&lzwoutbuf[bitcnt>>3]; |
109 | terminx | 1862 | intptr[0] |= B_LITTLE32(addr<<(bitcnt&7)); |
1863 | bitcnt += numbits; |
||
1864 | if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1))) |
||
1865 | bitcnt--; |
||
99 | terminx | 1866 | |
1205 | terminx | 1867 | shortptr = (int16_t *)lzwoutbuf; |
1868 | shortptr[0] = B_LITTLE16((int16_t)uncompleng); |
||
3879 | helixhorne | 1869 | |
109 | terminx | 1870 | if (((bitcnt+7)>>3) < uncompleng) |
1871 | { |
||
1205 | terminx | 1872 | shortptr[1] = B_LITTLE16((int16_t)addrcnt); |
3879 | helixhorne | 1873 | return (bitcnt+7)>>3; |
109 | terminx | 1874 | } |
2368 | helixhorne | 1875 | |
3879 | helixhorne | 1876 | // Failed compressing, mark this in the stream. |
2368 | helixhorne | 1877 | shortptr[1] = 0; |
4665 | terminx | 1878 | |
1879 | for (i=0; i<uncompleng-4; i+=4) |
||
1880 | { |
||
2368 | helixhorne | 1881 | lzwoutbuf[i+4] = lzwinbuf[i]; |
4665 | terminx | 1882 | lzwoutbuf[i+5] = lzwinbuf[i+1]; |
1883 | lzwoutbuf[i+6] = lzwinbuf[i+2]; |
||
1884 | lzwoutbuf[i+7] = lzwinbuf[i+3]; |
||
1885 | } |
||
2368 | helixhorne | 1886 | |
4665 | terminx | 1887 | for (; i<uncompleng; i++) |
1888 | lzwoutbuf[i+4] = lzwinbuf[i]; |
||
1889 | |||
3879 | helixhorne | 1890 | return uncompleng+4; |
99 | terminx | 1891 | } |
1892 | |||
2361 | helixhorne | 1893 | static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf) |
99 | terminx | 1894 | { |
2368 | helixhorne | 1895 | int32_t currstr, numbits, oneupnumbits; |
3879 | helixhorne | 1896 | int32_t i, bitcnt, outbytecnt; |
99 | terminx | 1897 | |
2368 | helixhorne | 1898 | const int16_t *const shortptr = (const int16_t *)lzwinbuf; |
1899 | const int32_t strtot = B_LITTLE16(shortptr[1]); |
||
1900 | const int32_t uncompleng = B_LITTLE16(shortptr[0]); |
||
1901 | |||
109 | terminx | 1902 | if (strtot == 0) |
1903 | { |
||
3879 | helixhorne | 1904 | if (lzwoutbuf==lzwrawbuf && lzwinbuf==lzwcompbuf) |
1905 | { |
||
1906 | Bassert((compleng-4)+3+0u < sizeof(lzwrawbuf)); |
||
1907 | Bassert((compleng-4)+3+0u < sizeof(lzwcompbuf)-4); |
||
1908 | } |
||
1909 | |||
3153 | helixhorne | 1910 | Bmemcpy(lzwoutbuf, lzwinbuf+4, (compleng-4)+3); |
2368 | helixhorne | 1911 | return uncompleng; |
109 | terminx | 1912 | } |
2368 | helixhorne | 1913 | |
4665 | terminx | 1914 | for (i=255; i>=4; i-=4) |
2368 | helixhorne | 1915 | { |
4665 | terminx | 1916 | lzwbuf2[i] = lzwbuf3[i] = i; |
1917 | lzwbuf2[i-1] = lzwbuf3[i-1] = i-1; |
||
1918 | lzwbuf2[i-2] = lzwbuf3[i-2] = i-2; |
||
1919 | lzwbuf2[i-3] = lzwbuf3[i-3] = i-3; |
||
2368 | helixhorne | 1920 | } |
1921 | |||
4665 | terminx | 1922 | lzwbuf2[i] = lzwbuf3[i] = i; |
1923 | lzwbuf2[i-1] = lzwbuf3[i-1] = i-1; |
||
1924 | lzwbuf2[i-2] = lzwbuf3[i-2] = i-2; |
||
1925 | |||
109 | terminx | 1926 | currstr = 256; bitcnt = (4<<3); outbytecnt = 0; |
1927 | numbits = 8; oneupnumbits = (1<<8); |
||
1928 | do |
||
1929 | { |
||
2368 | helixhorne | 1930 | const int32_t *const intptr = (const int32_t *)&lzwinbuf[bitcnt>>3]; |
1931 | |||
3879 | helixhorne | 1932 | int32_t dat = ((B_LITTLE32(intptr[0])>>(bitcnt&7)) & (oneupnumbits-1)); |
1933 | int32_t leng; |
||
1934 | |||
109 | terminx | 1935 | bitcnt += numbits; |
1936 | if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1))) |
||
584 | terminx | 1937 | { dat &= ((oneupnumbits>>1)-1); bitcnt--; } |
99 | terminx | 1938 | |
109 | terminx | 1939 | lzwbuf3[currstr] = dat; |
99 | terminx | 1940 | |
1229 | terminx | 1941 | for (leng=0; dat>=256; leng++,dat=lzwbuf3[dat]) |
2367 | helixhorne | 1942 | lzwtmpbuf[leng] = lzwbuf2[dat]; |
99 | terminx | 1943 | |
109 | terminx | 1944 | lzwoutbuf[outbytecnt++] = dat; |
4665 | terminx | 1945 | |
1946 | for (i=leng-1; i>=4; i-=4, outbytecnt+=4) |
||
1947 | { |
||
1948 | lzwoutbuf[outbytecnt] = lzwtmpbuf[i]; |
||
1949 | lzwoutbuf[outbytecnt+1] = lzwtmpbuf[i-1]; |
||
1950 | lzwoutbuf[outbytecnt+2] = lzwtmpbuf[i-2]; |
||
1951 | lzwoutbuf[outbytecnt+3] = lzwtmpbuf[i-3]; |
||
1952 | } |
||
1953 | |||
1954 | for (; i>=0; i--) |
||
2368 | helixhorne | 1955 | lzwoutbuf[outbytecnt++] = lzwtmpbuf[i]; |
99 | terminx | 1956 | |
109 | terminx | 1957 | lzwbuf2[currstr-1] = dat; lzwbuf2[currstr] = dat; |
1958 | currstr++; |
||
2368 | helixhorne | 1959 | if (currstr > oneupnumbits) |
1960 | { numbits++; oneupnumbits <<= 1; } |
||
584 | terminx | 1961 | } |
1962 | while (currstr < strtot); |
||
2368 | helixhorne | 1963 | |
1964 | return uncompleng; |
||
99 | terminx | 1965 | } |
1966 | |||
1967 | /* |
||
1968 | * vim:ts=4:sw=4: |
||
1969 | */ |