Rev 5061 | 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 | |||
917 | static SHFILEINFO shinf; |
||
918 | |||
2702 | helixhorne | 919 | int32_t (*check_filename_casing_fn)(void) = NULL; |
920 | |||
2692 | helixhorne | 921 | // -1: failure, 0: match, 1: mismatch |
922 | static int32_t check_filename_mismatch(const char *filename, int32_t ofs) |
||
923 | { |
||
2702 | helixhorne | 924 | const char *fn = filename+ofs; |
3068 | terminx | 925 | int32_t len; |
2702 | helixhorne | 926 | |
2692 | helixhorne | 927 | // we assume that UNICODE is not #defined, winlayer.c errors out else |
928 | if (!SHGetFileInfo(filename, -1, &shinf, sizeof(shinf), SHGFI_DISPLAYNAME)) |
||
929 | return -1; |
||
930 | |||
3068 | terminx | 931 | len = Bstrlen(shinf.szDisplayName); |
932 | |||
933 | if (!Bstrncmp(shinf.szDisplayName, fn, len)) |
||
2702 | helixhorne | 934 | return 0; |
935 | |||
936 | { |
||
4491 | helixhorne | 937 | char *tfn = Bstrtolower(Xstrdup(fn)); |
2702 | helixhorne | 938 | |
3068 | terminx | 939 | if (!Bstrncmp(shinf.szDisplayName, tfn, len)) |
2702 | helixhorne | 940 | { |
941 | Bfree(tfn); |
||
942 | return 0; |
||
943 | } |
||
944 | |||
945 | Bstrupr(tfn); |
||
946 | |||
3068 | terminx | 947 | if (!Bstrncmp(shinf.szDisplayName, tfn, len)) |
2702 | helixhorne | 948 | { |
949 | Bfree(tfn); |
||
950 | return 0; |
||
951 | } |
||
952 | |||
953 | Bfree(tfn); |
||
954 | } |
||
955 | |||
956 | return 1; |
||
2692 | helixhorne | 957 | } |
958 | #endif |
||
959 | |||
5059 | hendricks2 | 960 | 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 | 961 | { |
5059 | hendricks2 | 962 | int32_t j, k, fil; |
109 | terminx | 963 | char bad, *gfileptr; |
737 | qbix79 | 964 | intptr_t i; |
99 | terminx | 965 | |
5059 | hendricks2 | 966 | if (searchfirst == 0 && (fil = openfrompath_internal(filename, lastpfn, BO_BINARY|BO_RDONLY, BS_IREAD)) >= 0) |
109 | terminx | 967 | { |
2692 | helixhorne | 968 | #ifdef FILENAME_CASE_CHECK |
5059 | hendricks2 | 969 | if (checkcase && check_filename_casing_fn && check_filename_casing_fn()) |
2702 | helixhorne | 970 | { |
971 | int32_t status; |
||
972 | char *cp, *lastslash; |
||
2692 | helixhorne | 973 | |
2702 | helixhorne | 974 | // convert all slashes to backslashes because SHGetFileInfo() |
975 | // complains else! |
||
5059 | hendricks2 | 976 | lastslash = *lastpfn; |
977 | for (cp=*lastpfn; *cp; cp++) |
||
2702 | helixhorne | 978 | if (*cp=='/') |
979 | { |
||
980 | *cp = '\\'; |
||
981 | lastslash = cp; |
||
982 | } |
||
5059 | hendricks2 | 983 | if (lastslash != *lastpfn) |
2702 | helixhorne | 984 | lastslash++; |
985 | |||
5059 | hendricks2 | 986 | status = check_filename_mismatch(*lastpfn, lastslash-*lastpfn); |
2702 | helixhorne | 987 | |
988 | if (status == -1) |
||
2692 | helixhorne | 989 | { |
3385 | helixhorne | 990 | // initprintf("SHGetFileInfo failed with error code %lu\n", GetLastError()); |
2692 | helixhorne | 991 | } |
2702 | helixhorne | 992 | else if (status == 1) |
993 | { |
||
994 | initprintf("warning: case mismatch: passed \"%s\", real \"%s\"\n", |
||
995 | lastslash, shinf.szDisplayName); |
||
996 | } |
||
2692 | helixhorne | 997 | } |
5059 | hendricks2 | 998 | #else |
999 | UNREFERENCED_PARAMETER(checkcase); |
||
2692 | helixhorne | 1000 | #endif |
5059 | hendricks2 | 1001 | arraygrp[newhandle] = GRP_FILESYSTEM; |
1002 | arrayhan[newhandle] = fil; |
||
1003 | arraypos[newhandle] = 0; |
||
1004 | return newhandle; |
||
1592 | terminx | 1005 | } |
99 | terminx | 1006 | |
109 | terminx | 1007 | for (; toupperlookup[*filename] == '/'; filename++); |
1008 | |||
99 | terminx | 1009 | #ifdef WITHKPLIB |
5059 | hendricks2 | 1010 | if (tryzip) |
109 | terminx | 1011 | { |
5059 | hendricks2 | 1012 | if ((kzcurhand != newhandle) && (kztell() >= 0)) |
1013 | { |
||
1014 | if (kzcurhand >= 0) arraypos[kzcurhand] = kztell(); |
||
1015 | kzclose(); |
||
1016 | } |
||
1017 | if (searchfirst != 1 && (i = kzipopen(filename)) != 0) |
||
1018 | { |
||
1019 | kzcurhand = newhandle; |
||
1020 | arraygrp[newhandle] = GRP_ZIP; |
||
1021 | arrayhan[newhandle] = i; |
||
1022 | arraypos[newhandle] = 0; |
||
1023 | strcpy(filenamsav[newhandle],filename); |
||
1024 | return newhandle; |
||
1025 | } |
||
109 | terminx | 1026 | } |
5059 | hendricks2 | 1027 | #else |
1028 | UNREFERENCED_PARAMETER(tryzip); |
||
99 | terminx | 1029 | #endif |
1030 | |||
1229 | terminx | 1031 | for (k=numgroupfiles-1; k>=0; k--) |
109 | terminx | 1032 | { |
1033 | if (searchfirst == 1) k = 0; |
||
1034 | if (groupfil[k] >= 0) |
||
1035 | { |
||
1229 | terminx | 1036 | for (i=gnumfiles[k]-1; i>=0; i--) |
109 | terminx | 1037 | { |
1038 | gfileptr = (char *)&gfilelist[k][i<<4]; |
||
99 | terminx | 1039 | |
109 | terminx | 1040 | bad = 0; |
1229 | terminx | 1041 | for (j=0; j<13; j++) |
109 | terminx | 1042 | { |
1043 | if (!filename[j]) break; |
||
1044 | if (toupperlookup[filename[j]] != toupperlookup[gfileptr[j]]) |
||
2438 | helixhorne | 1045 | { |
1046 | bad = 1; |
||
1047 | break; |
||
1048 | } |
||
109 | terminx | 1049 | } |
1050 | if (bad) continue; |
||
1051 | if (j<13 && gfileptr[j]) continue; // JBF: because e1l1.map might exist before e1l1 |
||
1592 | terminx | 1052 | if (j==13 && filename[j]) continue; // JBF: long file name |
99 | terminx | 1053 | |
5059 | hendricks2 | 1054 | arraygrp[newhandle] = k; |
1055 | arrayhan[newhandle] = i; |
||
1056 | arraypos[newhandle] = 0; |
||
1057 | return newhandle; |
||
109 | terminx | 1058 | } |
1059 | } |
||
1060 | } |
||
5059 | hendricks2 | 1061 | |
1062 | return -1; |
||
99 | terminx | 1063 | } |
1064 | |||
5064 | hendricks2 | 1065 | void krename(int32_t crcval, int32_t filenum, const char *newname) |
5061 | hendricks2 | 1066 | { |
5064 | hendricks2 | 1067 | for (int32_t k=numgroupfiles-1; k>=0; k--) |
5061 | hendricks2 | 1068 | { |
5064 | hendricks2 | 1069 | if (groupfil[k] >= 0 && groupcrc[k] == crcval) |
5061 | hendricks2 | 1070 | { |
5064 | hendricks2 | 1071 | Bstrncpy((char *)&gfilelist[k][filenum<<4], newname, 12); |
1072 | return; |
||
5061 | hendricks2 | 1073 | } |
1074 | } |
||
1075 | } |
||
1076 | |||
5059 | hendricks2 | 1077 | int32_t kopen4load(const char *filename, char searchfirst) |
99 | terminx | 1078 | { |
5059 | hendricks2 | 1079 | int32_t newhandle = MAXOPENFILES-1; |
99 | terminx | 1080 | |
5059 | hendricks2 | 1081 | if (filename==NULL) |
1082 | return -1; |
||
1083 | |||
1084 | while (filehan[newhandle] != -1) |
||
1085 | { |
||
1086 | newhandle--; |
||
1087 | if (newhandle < 0) |
||
1088 | { |
||
1089 | Bprintf("TOO MANY FILES OPEN IN FILE GROUPING SYSTEM!"); |
||
1090 | Bexit(0); |
||
1091 | } |
||
1092 | } |
||
1093 | |||
1094 | char *lastpfn = NULL; |
||
1095 | |||
1096 | int32_t h = kopen_internal(filename, &lastpfn, searchfirst, 1, 1, newhandle, filegrp, filehan, filepos); |
||
1097 | |||
1098 | if (lastpfn) |
||
1099 | Bfree(lastpfn); |
||
1100 | |||
1101 | return h; |
||
1102 | } |
||
1103 | |||
1104 | int32_t kread_internal(int32_t handle, void *buffer, int32_t leng, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos) |
||
1105 | { |
||
1106 | int32_t filenum = arrayhan[handle]; |
||
1107 | int32_t groupnum = arraygrp[handle]; |
||
1108 | |||
5058 | hendricks2 | 1109 | if (groupnum == GRP_FILESYSTEM) return(Bread(filenum,buffer,leng)); |
99 | terminx | 1110 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1111 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1112 | { |
1113 | if (kzcurhand != handle) |
||
1114 | { |
||
5059 | hendricks2 | 1115 | if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); } |
109 | terminx | 1116 | kzcurhand = handle; |
1117 | kzipopen(filenamsav[handle]); |
||
5059 | hendricks2 | 1118 | kzseek(arraypos[handle],SEEK_SET); |
109 | terminx | 1119 | } |
1120 | return(kzread(buffer,leng)); |
||
1121 | } |
||
99 | terminx | 1122 | #endif |
1123 | |||
5059 | hendricks2 | 1124 | if (EDUKE32_PREDICT_FALSE(groupfil[groupnum] == -1)) |
1125 | return 0; |
||
1126 | |||
1127 | int32_t rootgroupnum = groupnum; |
||
1128 | int32_t i = 0; |
||
1129 | while (groupfilgrp[rootgroupnum] != GRP_FILESYSTEM) |
||
109 | terminx | 1130 | { |
5059 | hendricks2 | 1131 | i += gfileoffs[groupfilgrp[rootgroupnum]][groupfil[rootgroupnum]]; |
1132 | rootgroupnum = groupfilgrp[rootgroupnum]; |
||
1133 | } |
||
1134 | if (EDUKE32_PREDICT_TRUE(groupfil[rootgroupnum] != -1)) |
||
1135 | { |
||
1136 | i += gfileoffs[groupnum][filenum]+arraypos[handle]; |
||
1137 | if (i != groupfilpos[rootgroupnum]) |
||
109 | terminx | 1138 | { |
5059 | hendricks2 | 1139 | Blseek(groupfil[rootgroupnum],i,BSEEK_SET); |
1140 | groupfilpos[rootgroupnum] = i; |
||
109 | terminx | 1141 | } |
5059 | hendricks2 | 1142 | leng = min(leng,(gfileoffs[groupnum][filenum+1]-gfileoffs[groupnum][filenum])-arraypos[handle]); |
1143 | leng = Bread(groupfil[rootgroupnum],buffer,leng); |
||
1144 | arraypos[handle] += leng; |
||
1145 | groupfilpos[rootgroupnum] += leng; |
||
109 | terminx | 1146 | return(leng); |
1147 | } |
||
99 | terminx | 1148 | |
109 | terminx | 1149 | return(0); |
99 | terminx | 1150 | } |
1151 | |||
5059 | hendricks2 | 1152 | int32_t klseek_internal(int32_t handle, int32_t offset, int32_t whence, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos) |
99 | terminx | 1153 | { |
1205 | terminx | 1154 | int32_t i, groupnum; |
99 | terminx | 1155 | |
5059 | hendricks2 | 1156 | groupnum = arraygrp[handle]; |
99 | terminx | 1157 | |
5059 | hendricks2 | 1158 | if (groupnum == GRP_FILESYSTEM) return(Blseek(arrayhan[handle],offset,whence)); |
99 | terminx | 1159 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1160 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1161 | { |
1162 | if (kzcurhand != handle) |
||
1163 | { |
||
5059 | hendricks2 | 1164 | if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); } |
109 | terminx | 1165 | kzcurhand = handle; |
1166 | kzipopen(filenamsav[handle]); |
||
5059 | hendricks2 | 1167 | kzseek(arraypos[handle],SEEK_SET); |
109 | terminx | 1168 | } |
1169 | return(kzseek(offset,whence)); |
||
1170 | } |
||
99 | terminx | 1171 | #endif |
1172 | |||
109 | terminx | 1173 | if (groupfil[groupnum] != -1) |
1174 | { |
||
331 | terminx | 1175 | switch (whence) |
109 | terminx | 1176 | { |
331 | terminx | 1177 | case BSEEK_SET: |
5059 | hendricks2 | 1178 | arraypos[handle] = offset; break; |
331 | terminx | 1179 | case BSEEK_END: |
5059 | hendricks2 | 1180 | i = arrayhan[handle]; |
1181 | arraypos[handle] = (gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i])+offset; |
||
109 | terminx | 1182 | break; |
331 | terminx | 1183 | case BSEEK_CUR: |
5059 | hendricks2 | 1184 | arraypos[handle] += offset; break; |
109 | terminx | 1185 | } |
5059 | hendricks2 | 1186 | return(arraypos[handle]); |
109 | terminx | 1187 | } |
1188 | return(-1); |
||
99 | terminx | 1189 | } |
1190 | |||
5059 | hendricks2 | 1191 | int32_t kfilelength_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos) |
99 | terminx | 1192 | { |
1205 | terminx | 1193 | int32_t i, groupnum; |
99 | terminx | 1194 | |
5059 | hendricks2 | 1195 | groupnum = arraygrp[handle]; |
5058 | hendricks2 | 1196 | if (groupnum == GRP_FILESYSTEM) |
584 | terminx | 1197 | { |
5059 | hendricks2 | 1198 | // return(filelength(arrayhan[handle])) |
1199 | return Bfilelength(arrayhan[handle]); |
||
109 | terminx | 1200 | } |
99 | terminx | 1201 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1202 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1203 | { |
1204 | if (kzcurhand != handle) |
||
1205 | { |
||
5059 | hendricks2 | 1206 | if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); } |
109 | terminx | 1207 | kzcurhand = handle; |
1208 | kzipopen(filenamsav[handle]); |
||
5059 | hendricks2 | 1209 | kzseek(arraypos[handle],SEEK_SET); |
109 | terminx | 1210 | } |
1211 | return kzfilelength(); |
||
1212 | } |
||
99 | terminx | 1213 | #endif |
5059 | hendricks2 | 1214 | i = arrayhan[handle]; |
109 | terminx | 1215 | return(gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i]); |
99 | terminx | 1216 | } |
1217 | |||
5059 | hendricks2 | 1218 | int32_t ktell_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan, int32_t *arraypos) |
99 | terminx | 1219 | { |
5059 | hendricks2 | 1220 | int32_t groupnum = arraygrp[handle]; |
99 | terminx | 1221 | |
5059 | hendricks2 | 1222 | if (groupnum == GRP_FILESYSTEM) return(Blseek(arrayhan[handle],0,BSEEK_CUR)); |
99 | terminx | 1223 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1224 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1225 | { |
1226 | if (kzcurhand != handle) |
||
1227 | { |
||
5059 | hendricks2 | 1228 | if (kztell() >= 0) { arraypos[kzcurhand] = kztell(); kzclose(); } |
109 | terminx | 1229 | kzcurhand = handle; |
1230 | kzipopen(filenamsav[handle]); |
||
5059 | hendricks2 | 1231 | kzseek(arraypos[handle],SEEK_SET); |
109 | terminx | 1232 | } |
1233 | return kztell(); |
||
1234 | } |
||
99 | terminx | 1235 | #endif |
109 | terminx | 1236 | if (groupfil[groupnum] != -1) |
5059 | hendricks2 | 1237 | return arraypos[handle]; |
109 | terminx | 1238 | return(-1); |
99 | terminx | 1239 | } |
1240 | |||
5059 | hendricks2 | 1241 | void kclose_internal(int32_t handle, uint8_t *arraygrp, intptr_t *arrayhan) |
99 | terminx | 1242 | { |
109 | terminx | 1243 | if (handle < 0) return; |
5059 | hendricks2 | 1244 | if (arraygrp[handle] == GRP_FILESYSTEM) Bclose(arrayhan[handle]); |
99 | terminx | 1245 | #ifdef WITHKPLIB |
5059 | hendricks2 | 1246 | else if (arraygrp[handle] == GRP_ZIP) |
109 | terminx | 1247 | { |
1248 | kzclose(); |
||
1249 | kzcurhand = -1; |
||
1250 | } |
||
99 | terminx | 1251 | #endif |
5059 | hendricks2 | 1252 | arrayhan[handle] = -1; |
99 | terminx | 1253 | } |
1254 | |||
5059 | hendricks2 | 1255 | int32_t kread(int32_t handle, void *buffer, int32_t leng) |
1256 | { |
||
1257 | return kread_internal(handle, buffer, leng, filegrp, filehan, filepos); |
||
1258 | } |
||
1259 | int32_t klseek(int32_t handle, int32_t offset, int32_t whence) |
||
1260 | { |
||
1261 | return klseek_internal(handle, offset, whence, filegrp, filehan, filepos); |
||
1262 | } |
||
1263 | int32_t kfilelength(int32_t handle) |
||
1264 | { |
||
1265 | return kfilelength_internal(handle, filegrp, filehan, filepos); |
||
1266 | } |
||
1267 | int32_t ktell(int32_t handle) |
||
1268 | { |
||
1269 | return ktell_internal(handle, filegrp, filehan, filepos); |
||
1270 | } |
||
1271 | void kclose(int32_t handle) |
||
1272 | { |
||
1273 | return kclose_internal(handle, filegrp, filehan); |
||
1274 | } |
||
1275 | |||
1276 | static int32_t kread_grp(int32_t handle, void *buffer, int32_t leng) |
||
1277 | { |
||
1278 | return kread_internal(handle, buffer, leng, groupfilgrp, groupfil, groupfilpos); |
||
1279 | } |
||
1280 | static int32_t klseek_grp(int32_t handle, int32_t offset, int32_t whence) |
||
1281 | { |
||
1282 | return klseek_internal(handle, offset, whence, groupfilgrp, groupfil, groupfilpos); |
||
1283 | } |
||
1284 | static void kclose_grp(int32_t handle) |
||
1285 | { |
||
1286 | return kclose_internal(handle, groupfilgrp, groupfil); |
||
1287 | } |
||
1288 | |||
1799 | helixhorne | 1289 | static int32_t klistaddentry(CACHE1D_FIND_REC **rec, const char *name, int32_t type, int32_t source) |
99 | terminx | 1290 | { |
109 | terminx | 1291 | CACHE1D_FIND_REC *r = NULL, *attach = NULL; |
99 | terminx | 1292 | |
584 | terminx | 1293 | if (*rec) |
1294 | { |
||
1205 | terminx | 1295 | int32_t insensitive, v; |
109 | terminx | 1296 | CACHE1D_FIND_REC *last = NULL; |
1297 | |||
584 | terminx | 1298 | for (attach = *rec; attach; last = attach, attach = attach->next) |
1299 | { |
||
109 | terminx | 1300 | if (type == CACHE1D_FIND_DRIVE) continue; // we just want to get to the end for drives |
99 | terminx | 1301 | #ifdef _WIN32 |
109 | terminx | 1302 | insensitive = 1; |
99 | terminx | 1303 | #else |
109 | terminx | 1304 | if (source == CACHE1D_SOURCE_GRP || attach->source == CACHE1D_SOURCE_GRP) |
1305 | insensitive = 1; |
||
1306 | else if (source == CACHE1D_SOURCE_ZIP || attach->source == CACHE1D_SOURCE_ZIP) |
||
1307 | insensitive = 1; |
||
1308 | else |
||
2356 | helixhorne | 1309 | { |
1310 | extern int16_t editstatus; // XXX |
||
1311 | insensitive = !editstatus; |
||
1312 | } |
||
1313 | // ^ in the game, don't show file list case-sensitive |
||
99 | terminx | 1314 | #endif |
109 | terminx | 1315 | if (insensitive) v = Bstrcasecmp(name, attach->name); |
1316 | else v = Bstrcmp(name, attach->name); |
||
99 | terminx | 1317 | |
109 | terminx | 1318 | // sorted list |
1319 | if (v > 0) continue; // item to add is bigger than the current one |
||
1320 | // so look for something bigger than us |
||
584 | terminx | 1321 | if (v < 0) // item to add is smaller than the current one |
1322 | { |
||
109 | terminx | 1323 | attach = NULL; // so wedge it between the current item and the one before |
1324 | break; |
||
1325 | } |
||
99 | terminx | 1326 | |
109 | terminx | 1327 | // matched |
1328 | if (source >= attach->source) return 1; // item to add is of lower priority |
||
1329 | r = attach; |
||
1330 | break; |
||
1331 | } |
||
99 | terminx | 1332 | |
109 | terminx | 1333 | // wasn't found in the list, so attach to the end |
1334 | if (!attach) attach = last; |
||
1335 | } |
||
99 | terminx | 1336 | |
584 | terminx | 1337 | if (r) |
1338 | { |
||
109 | terminx | 1339 | r->type = type; |
1340 | r->source = source; |
||
1341 | return 0; |
||
1342 | } |
||
99 | terminx | 1343 | |
4491 | helixhorne | 1344 | r = (CACHE1D_FIND_REC *)Xmalloc(sizeof(CACHE1D_FIND_REC)+strlen(name)+1); |
1345 | |||
1762 | terminx | 1346 | r->name = (char *)r + sizeof(CACHE1D_FIND_REC); strcpy(r->name, name); |
109 | terminx | 1347 | r->type = type; |
1348 | r->source = source; |
||
1349 | r->usera = r->userb = NULL; |
||
1350 | |||
584 | terminx | 1351 | if (!attach) // we are the first item |
1352 | { |
||
109 | terminx | 1353 | r->prev = NULL; |
1354 | r->next = *rec; |
||
584 | terminx | 1355 | if (*rec)(*rec)->prev = r; |
109 | terminx | 1356 | *rec = r; |
584 | terminx | 1357 | } |
1358 | else |
||
1359 | { |
||
109 | terminx | 1360 | r->prev = attach; |
1361 | r->next = attach->next; |
||
1362 | if (attach->next) attach->next->prev = r; |
||
1363 | attach->next = r; |
||
1364 | } |
||
1365 | |||
1366 | return 0; |
||
99 | terminx | 1367 | } |
1368 | |||
1369 | void klistfree(CACHE1D_FIND_REC *rec) |
||
1370 | { |
||
109 | terminx | 1371 | CACHE1D_FIND_REC *n; |
1372 | |||
584 | terminx | 1373 | while (rec) |
1374 | { |
||
109 | terminx | 1375 | n = rec->next; |
1527 | terminx | 1376 | Bfree(rec); |
109 | terminx | 1377 | rec = n; |
1378 | } |
||
99 | terminx | 1379 | } |
1380 | |||
1205 | terminx | 1381 | CACHE1D_FIND_REC *klistpath(const char *_path, const char *mask, int32_t type) |
99 | terminx | 1382 | { |
109 | terminx | 1383 | CACHE1D_FIND_REC *rec = NULL; |
1384 | char *path; |
||
99 | terminx | 1385 | |
109 | terminx | 1386 | // pathsearchmode == 0: enumerates a path in the virtual filesystem |
1387 | // pathsearchmode == 1: enumerates the system filesystem path passed in |
||
99 | terminx | 1388 | |
4491 | helixhorne | 1389 | path = Xstrdup(_path); |
99 | terminx | 1390 | |
109 | terminx | 1391 | // we don't need any leading dots and slashes or trailing slashes either |
1392 | { |
||
1205 | terminx | 1393 | int32_t i,j; |
584 | terminx | 1394 | for (i=0; path[i] == '.' || toupperlookup[path[i]] == '/';) i++; |
109 | terminx | 1395 | for (j=0; (path[j] = path[i]); j++,i++) ; |
1396 | while (j>0 && toupperlookup[path[j-1]] == '/') j--; |
||
1397 | path[j] = 0; |
||
1398 | //initprintf("Cleaned up path = \"%s\"\n",path); |
||
1399 | } |
||
99 | terminx | 1400 | |
584 | terminx | 1401 | if (*path && (type & CACHE1D_FIND_DIR)) |
1402 | { |
||
109 | terminx | 1403 | if (klistaddentry(&rec, "..", CACHE1D_FIND_DIR, CACHE1D_SOURCE_CURDIR) < 0) goto failure; |
1404 | } |
||
99 | terminx | 1405 | |
584 | terminx | 1406 | if (!(type & CACHE1D_OPT_NOSTACK)) // current directory and paths in the search stack |
1407 | { |
||
109 | terminx | 1408 | searchpath_t *search = NULL; |
1409 | BDIR *dir; |
||
1410 | struct Bdirent *dirent; |
||
4188 | helixhorne | 1411 | |
1412 | static const char *const CUR_DIR = "./"; |
||
932 | terminx | 1413 | // Adjusted for the following "autoload" dir fix - NY00123 |
4188 | helixhorne | 1414 | const char *d = pathsearchmode ? _path : CUR_DIR; |
1205 | terminx | 1415 | int32_t stackdepth = CACHE1D_SOURCE_CURDIR; |
109 | terminx | 1416 | char buf[BMAX_PATH]; |
99 | terminx | 1417 | |
584 | terminx | 1418 | do |
1419 | { |
||
4188 | helixhorne | 1420 | if (d==CUR_DIR && (type & CACHE1D_FIND_NOCURDIR)) |
1421 | goto next; |
||
1422 | |||
2010 | helixhorne | 1423 | strcpy(buf, d); |
584 | terminx | 1424 | if (!pathsearchmode) |
1425 | { |
||
932 | terminx | 1426 | // Fix for "autoload" dir in multi-user environments - NY00123 |
1427 | strcat(buf, path); |
||
109 | terminx | 1428 | if (*path) strcat(buf, "/"); |
584 | terminx | 1429 | } |
2010 | helixhorne | 1430 | |
109 | terminx | 1431 | dir = Bopendir(buf); |
584 | terminx | 1432 | if (dir) |
1433 | { |
||
1434 | while ((dirent = Breaddir(dir))) |
||
1435 | { |
||
109 | terminx | 1436 | if ((dirent->name[0] == '.' && dirent->name[1] == 0) || |
1437 | (dirent->name[0] == '.' && dirent->name[1] == '.' && dirent->name[2] == 0)) |
||
1438 | continue; |
||
1439 | if ((type & CACHE1D_FIND_DIR) && !(dirent->mode & BS_IFDIR)) continue; |
||
1440 | if ((type & CACHE1D_FIND_FILE) && (dirent->mode & BS_IFDIR)) continue; |
||
1441 | if (!Bwildmatch(dirent->name, mask)) continue; |
||
1442 | switch (klistaddentry(&rec, dirent->name, |
||
1443 | (dirent->mode & BS_IFDIR) ? CACHE1D_FIND_DIR : CACHE1D_FIND_FILE, |
||
584 | terminx | 1444 | stackdepth)) |
1445 | { |
||
109 | terminx | 1446 | case -1: goto failure; |
1447 | //case 1: initprintf("%s:%s dropped for lower priority\n", d,dirent->name); break; |
||
1448 | //case 0: initprintf("%s:%s accepted\n", d,dirent->name); break; |
||
331 | terminx | 1449 | default: |
1450 | break; |
||
109 | terminx | 1451 | } |
1452 | } |
||
1453 | Bclosedir(dir); |
||
1454 | } |
||
4188 | helixhorne | 1455 | next: |
1456 | if (pathsearchmode) |
||
1457 | break; |
||
99 | terminx | 1458 | |
584 | terminx | 1459 | if (!search) |
1460 | { |
||
109 | terminx | 1461 | search = searchpathhead; |
1462 | stackdepth = CACHE1D_SOURCE_PATH; |
||
584 | terminx | 1463 | } |
1464 | else |
||
1465 | { |
||
109 | terminx | 1466 | search = search->next; |
1467 | stackdepth++; |
||
1468 | } |
||
4188 | helixhorne | 1469 | |
1470 | if (search) |
||
1471 | d = search->path; |
||
584 | terminx | 1472 | } |
1473 | while (search); |
||
109 | terminx | 1474 | } |
1475 | |||
3484 | helixhorne | 1476 | #ifdef WITHKPLIB |
4188 | helixhorne | 1477 | if (!(type & CACHE1D_FIND_NOCURDIR)) // TEMP, until we have sorted out fs.listpath() API |
584 | terminx | 1478 | if (!pathsearchmode) // next, zip files |
1479 | { |
||
1479 | terminx | 1480 | char buf[BMAX_PATH+4]; |
1205 | terminx | 1481 | int32_t i, j, ftype; |
109 | terminx | 1482 | strcpy(buf,path); |
1483 | if (*path) strcat(buf,"/"); |
||
1484 | strcat(buf,mask); |
||
584 | terminx | 1485 | for (kzfindfilestart(buf); kzfindfile(buf);) |
1486 | { |
||
109 | terminx | 1487 | if (buf[0] != '|') continue; // local files we don't need |
1488 | |||
1489 | // scan for the end of the string and shift |
||
1490 | // everything left a char in the process |
||
2416 | helixhorne | 1491 | for (i=1; (buf[i-1]=buf[i]); i++) |
1492 | { |
||
1493 | /* do nothing */ |
||
1494 | } |
||
1495 | i-=2; |
||
4543 | hendricks2 | 1496 | if (i < 0) |
1497 | i = 0; |
||
109 | terminx | 1498 | |
1499 | // if there's a slash at the end, this is a directory entry |
||
584 | terminx | 1500 | if (toupperlookup[buf[i]] == '/') { ftype = CACHE1D_FIND_DIR; buf[i] = 0; } |
109 | terminx | 1501 | else ftype = CACHE1D_FIND_FILE; |
1502 | |||
1503 | // skip over the common characters at the beginning of the base path and the zip entry |
||
584 | terminx | 1504 | for (j=0; buf[j] && path[j]; j++) |
1505 | { |
||
109 | terminx | 1506 | if (toupperlookup[ path[j] ] == toupperlookup[ buf[j] ]) continue; |
1507 | break; |
||
1508 | } |
||
1509 | // we've now hopefully skipped the common path component at the beginning. |
||
1510 | // if that's true, we should be staring at a null byte in path and either any character in buf |
||
1511 | // if j==0, or a slash if j>0 |
||
584 | terminx | 1512 | if ((!path[0] && buf[j]) || (!path[j] && toupperlookup[ buf[j] ] == '/')) |
1513 | { |
||
109 | terminx | 1514 | if (j>0) j++; |
1515 | |||
1516 | // yep, so now we shift what follows back to the start of buf and while we do that, |
||
1517 | // keep an eye out for any more slashes which would mean this entry has sub-entities |
||
1518 | // and is useless to us. |
||
1519 | for (i = 0; (buf[i] = buf[j]) && toupperlookup[buf[j]] != '/'; i++,j++) ; |
||
1520 | if (toupperlookup[buf[j]] == '/') continue; // damn, try next entry |
||
584 | terminx | 1521 | } |
1522 | else |
||
1523 | { |
||
109 | terminx | 1524 | // if we're here it means we have a situation where: |
1525 | // path = foo |
||
1526 | // buf = foobar... |
||
1527 | // or |
||
1528 | // path = foobar |
||
1529 | // buf = foo... |
||
1530 | // which would mean the entry is higher up in the directory tree and is also useless |
||
1531 | continue; |
||
1532 | } |
||
1533 | |||
1534 | if ((type & CACHE1D_FIND_DIR) && ftype != CACHE1D_FIND_DIR) continue; |
||
1535 | if ((type & CACHE1D_FIND_FILE) && ftype != CACHE1D_FIND_FILE) continue; |
||
1536 | |||
1537 | // the entry is in the clear |
||
584 | terminx | 1538 | switch (klistaddentry(&rec, buf, ftype, CACHE1D_SOURCE_ZIP)) |
1539 | { |
||
331 | terminx | 1540 | case -1: |
1541 | goto failure; |
||
109 | terminx | 1542 | //case 1: initprintf("<ZIP>:%s dropped for lower priority\n", buf); break; |
1543 | //case 0: initprintf("<ZIP>:%s accepted\n", buf); break; |
||
331 | terminx | 1544 | default: |
1545 | break; |
||
109 | terminx | 1546 | } |
1547 | } |
||
1548 | } |
||
3484 | helixhorne | 1549 | #endif |
109 | terminx | 1550 | // then, grp files |
4188 | helixhorne | 1551 | if (!(type & CACHE1D_FIND_NOCURDIR)) // TEMP, until we have sorted out fs.listpath() API |
584 | terminx | 1552 | if (!pathsearchmode && !*path && (type & CACHE1D_FIND_FILE)) |
1553 | { |
||
109 | terminx | 1554 | char buf[13]; |
1205 | terminx | 1555 | int32_t i,j; |
109 | terminx | 1556 | buf[12] = 0; |
1229 | terminx | 1557 | for (i=0; i<MAXGROUPFILES; i++) |
584 | terminx | 1558 | { |
109 | terminx | 1559 | if (groupfil[i] == -1) continue; |
1229 | terminx | 1560 | for (j=gnumfiles[i]-1; j>=0; j--) |
109 | terminx | 1561 | { |
1562 | Bmemcpy(buf,&gfilelist[i][j<<4],12); |
||
1563 | if (!Bwildmatch(buf,mask)) continue; |
||
584 | terminx | 1564 | switch (klistaddentry(&rec, buf, CACHE1D_FIND_FILE, CACHE1D_SOURCE_GRP)) |
1565 | { |
||
331 | terminx | 1566 | case -1: |
1567 | goto failure; |
||
109 | terminx | 1568 | //case 1: initprintf("<GRP>:%s dropped for lower priority\n", workspace); break; |
1569 | //case 0: initprintf("<GRP>:%s accepted\n", workspace); break; |
||
331 | terminx | 1570 | default: |
1571 | break; |
||
109 | terminx | 1572 | } |
1573 | } |
||
1574 | } |
||
1575 | } |
||
1576 | |||
584 | terminx | 1577 | if (pathsearchmode && (type & CACHE1D_FIND_DRIVE)) |
1578 | { |
||
109 | terminx | 1579 | char *drives, *drp; |
1580 | drives = Bgetsystemdrives(); |
||
584 | terminx | 1581 | if (drives) |
1582 | { |
||
1583 | for (drp=drives; *drp; drp+=strlen(drp)+1) |
||
1584 | { |
||
1585 | if (klistaddentry(&rec, drp, CACHE1D_FIND_DRIVE, CACHE1D_SOURCE_DRIVE) < 0) |
||
1586 | { |
||
1527 | terminx | 1587 | Bfree(drives); |
109 | terminx | 1588 | goto failure; |
1589 | } |
||
1590 | } |
||
1527 | terminx | 1591 | Bfree(drives); |
109 | terminx | 1592 | } |
1593 | } |
||
1594 | |||
1527 | terminx | 1595 | Bfree(path); |
4175 | helixhorne | 1596 | // XXX: may be NULL if no file was listed, and thus indistinguishable from |
1597 | // an error condition. |
||
109 | terminx | 1598 | return rec; |
99 | terminx | 1599 | failure: |
1527 | terminx | 1600 | Bfree(path); |
109 | terminx | 1601 | klistfree(rec); |
1602 | return NULL; |
||
99 | terminx | 1603 | } |
1604 | |||
3153 | helixhorne | 1605 | |
1606 | #endif // #ifdef CACHE1D_COMPRESS_ONLY / else |
||
1607 | |||
1608 | |||
109 | terminx | 1609 | //Internal LZW variables |
99 | terminx | 1610 | #define LZWSIZE 16384 //Watch out for shorts! |
2366 | helixhorne | 1611 | #define LZWSIZEPAD (LZWSIZE+(LZWSIZE>>4)) |
99 | terminx | 1612 | |
3880 | helixhorne | 1613 | // lzwrawbuf LZWSIZE+1 (formerly): see (*) below |
1614 | // XXX: lzwrawbuf size increased again :-/ |
||
1615 | static char lzwtmpbuf[LZWSIZEPAD], lzwrawbuf[LZWSIZEPAD], lzwcompbuf[LZWSIZEPAD]; |
||
2366 | helixhorne | 1616 | static int16_t lzwbuf2[LZWSIZEPAD], lzwbuf3[LZWSIZEPAD]; |
1617 | |||
2361 | helixhorne | 1618 | static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf); |
1619 | static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf); |
||
99 | terminx | 1620 | |
3153 | helixhorne | 1621 | #ifndef CACHE1D_COMPRESS_ONLY |
1622 | static int32_t kdfread_func(intptr_t fil, void *outbuf, int32_t length) |
||
99 | terminx | 1623 | { |
3153 | helixhorne | 1624 | return kread((int32_t)fil, outbuf, length); |
1625 | } |
||
1626 | |||
1627 | static void dfwrite_func(intptr_t fp, const void *inbuf, int32_t length) |
||
1628 | { |
||
1629 | Bfwrite(inbuf, length, 1, (BFILE *)fp); |
||
1630 | } |
||
1631 | #else |
||
1632 | # define kdfread_func NULL |
||
1633 | # define dfwrite_func NULL |
||
1634 | #endif |
||
1635 | |||
1636 | // These two follow the argument order of the C functions "read" and "write": |
||
1637 | // handle, buffer, length. |
||
1638 | C1D_STATIC int32_t (*c1d_readfunc)(intptr_t, void *, int32_t) = kdfread_func; |
||
1639 | C1D_STATIC void (*c1d_writefunc)(intptr_t, const void *, int32_t) = dfwrite_func; |
||
1640 | |||
1641 | |||
1642 | ////////// COMPRESSED READ ////////// |
||
1643 | |||
3879 | helixhorne | 1644 | static uint32_t decompress_part(intptr_t f, uint32_t *kgoalptr) |
3153 | helixhorne | 1645 | { |
3879 | helixhorne | 1646 | int16_t leng; |
1647 | |||
1648 | // Read compressed length first. |
||
1649 | if (c1d_readfunc(f, &leng, 2) != 2) |
||
3153 | helixhorne | 1650 | return 1; |
3879 | helixhorne | 1651 | leng = B_LITTLE16(leng); |
1652 | |||
3153 | helixhorne | 1653 | if (c1d_readfunc(f,lzwcompbuf, leng) != leng) |
1654 | return 1; |
||
3879 | helixhorne | 1655 | |
1656 | *kgoalptr = lzwuncompress(lzwcompbuf, leng, lzwrawbuf); |
||
3153 | helixhorne | 1657 | return 0; |
1658 | } |
||
1659 | |||
1660 | // Read from 'f' into 'buffer'. |
||
1661 | C1D_STATIC int32_t c1d_read_compressed(void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f) |
||
1662 | { |
||
4837 | helixhorne | 1663 | char *ptr = (char *)buffer; |
99 | terminx | 1664 | |
2369 | helixhorne | 1665 | if (dasizeof > LZWSIZE) |
1666 | { |
||
4838 | helixhorne | 1667 | count *= dasizeof; |
1668 | dasizeof = 1; |
||
2369 | helixhorne | 1669 | } |
1670 | |||
4837 | helixhorne | 1671 | uint32_t kgoal; |
99 | terminx | 1672 | |
4837 | helixhorne | 1673 | if (decompress_part(f, &kgoal)) |
1674 | return -1; |
||
99 | terminx | 1675 | |
3153 | helixhorne | 1676 | Bmemcpy(ptr, lzwrawbuf, (int32_t)dasizeof); |
99 | terminx | 1677 | |
4837 | helixhorne | 1678 | uint32_t k = (int32_t)dasizeof; |
1679 | |||
1680 | for (uint32_t i=1; i<count; i++) |
||
109 | terminx | 1681 | { |
1682 | if (k >= kgoal) |
||
1683 | { |
||
3879 | helixhorne | 1684 | k = decompress_part(f, &kgoal); |
3153 | helixhorne | 1685 | if (k) return -1; |
109 | terminx | 1686 | } |
2368 | helixhorne | 1687 | |
4837 | helixhorne | 1688 | uint32_t j = 0; |
4665 | terminx | 1689 | |
1690 | if (dasizeof >= 4) |
||
1691 | { |
||
1692 | for (; j<dasizeof-4; j+=4) |
||
1693 | { |
||
4837 | helixhorne | 1694 | ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255); |
1695 | ptr[j+1+dasizeof] = ((ptr[j+1]+lzwrawbuf[j+1+k])&255); |
||
1696 | ptr[j+2+dasizeof] = ((ptr[j+2]+lzwrawbuf[j+2+k])&255); |
||
1697 | ptr[j+3+dasizeof] = ((ptr[j+3]+lzwrawbuf[j+3+k])&255); |
||
4665 | terminx | 1698 | } |
1699 | } |
||
1700 | |||
1701 | for (; j<dasizeof; j++) |
||
2368 | helixhorne | 1702 | ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255); |
1703 | |||
109 | terminx | 1704 | k += dasizeof; |
1705 | ptr += dasizeof; |
||
1706 | } |
||
2366 | helixhorne | 1707 | |
109 | terminx | 1708 | return count; |
99 | terminx | 1709 | } |
1710 | |||
3153 | helixhorne | 1711 | int32_t kdfread(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil) |
2369 | helixhorne | 1712 | { |
3153 | helixhorne | 1713 | return c1d_read_compressed(buffer, dasizeof, count, (intptr_t)fil); |
1714 | } |
||
2369 | helixhorne | 1715 | |
1716 | |||
3153 | helixhorne | 1717 | ////////// COMPRESSED WRITE ////////// |
1718 | |||
1719 | static uint32_t compress_part(uint32_t k, intptr_t f) |
||
1720 | { |
||
3879 | helixhorne | 1721 | const int16_t leng = (int16_t)lzwcompress(lzwrawbuf, k, lzwcompbuf); |
1722 | const int16_t swleng = B_LITTLE16(leng); |
||
1723 | |||
3153 | helixhorne | 1724 | c1d_writefunc(f, &swleng, 2); |
1725 | c1d_writefunc(f, lzwcompbuf, leng); |
||
3879 | helixhorne | 1726 | |
2369 | helixhorne | 1727 | return 0; |
1728 | } |
||
1729 | |||
3153 | helixhorne | 1730 | // Write from 'buffer' to 'f'. |
1731 | C1D_STATIC void c1d_write_compressed(const void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f) |
||
99 | terminx | 1732 | { |
4665 | terminx | 1733 | const char *ptr = (char*)buffer; |
99 | terminx | 1734 | |
4838 | helixhorne | 1735 | if (dasizeof > LZWSIZE) |
2369 | helixhorne | 1736 | { |
4838 | helixhorne | 1737 | count *= dasizeof; |
1738 | dasizeof = 1; |
||
2369 | helixhorne | 1739 | } |
1740 | |||
1741 | Bmemcpy(lzwrawbuf, ptr, (int32_t)dasizeof); |
||
1742 | |||
4837 | helixhorne | 1743 | uint32_t k = dasizeof; |
109 | terminx | 1744 | if (k > LZWSIZE-dasizeof) |
3153 | helixhorne | 1745 | k = compress_part(k, f); |
99 | terminx | 1746 | |
4837 | helixhorne | 1747 | for (uint32_t i=1; i<count; i++) |
109 | terminx | 1748 | { |
4837 | helixhorne | 1749 | uint32_t j = 0; |
4665 | terminx | 1750 | |
1751 | if (dasizeof >= 4) |
||
1752 | { |
||
1753 | for (; j<dasizeof-4; j+=4) |
||
1754 | { |
||
4837 | helixhorne | 1755 | lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255); |
1756 | lzwrawbuf[j+1+k] = ((ptr[j+1+dasizeof]-ptr[j+1])&255); |
||
1757 | lzwrawbuf[j+2+k] = ((ptr[j+2+dasizeof]-ptr[j+2])&255); |
||
1758 | lzwrawbuf[j+3+k] = ((ptr[j+3+dasizeof]-ptr[j+3])&255); |
||
4665 | terminx | 1759 | } |
1760 | } |
||
1761 | |||
1762 | for (; j<dasizeof; j++) |
||
2368 | helixhorne | 1763 | lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255); |
2369 | helixhorne | 1764 | |
109 | terminx | 1765 | k += dasizeof; |
1766 | if (k > LZWSIZE-dasizeof) |
||
3153 | helixhorne | 1767 | k = compress_part(k, f); |
2369 | helixhorne | 1768 | |
109 | terminx | 1769 | ptr += dasizeof; |
1770 | } |
||
2369 | helixhorne | 1771 | |
109 | terminx | 1772 | if (k > 0) |
3153 | helixhorne | 1773 | compress_part(k, f); |
99 | terminx | 1774 | } |
1775 | |||
3153 | helixhorne | 1776 | void dfwrite(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil) |
1777 | { |
||
1778 | c1d_write_compressed(buffer, dasizeof, count, (intptr_t)fil); |
||
1779 | } |
||
1780 | |||
1781 | ////////// CORE COMPRESSION FUNCTIONS ////////// |
||
1782 | |||
2361 | helixhorne | 1783 | static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf) |
99 | terminx | 1784 | { |
2369 | helixhorne | 1785 | int32_t i, addr, addrcnt, *intptr; |
1205 | terminx | 1786 | int32_t bytecnt1, bitcnt, numbits, oneupnumbits; |
1787 | int16_t *shortptr; |
||
99 | terminx | 1788 | |
2369 | helixhorne | 1789 | int16_t *const lzwcodehead = lzwbuf2; |
1790 | int16_t *const lzwcodenext = lzwbuf3; |
||
1791 | |||
4665 | terminx | 1792 | for (i=255; i>=4; i-=4) |
2368 | helixhorne | 1793 | { |
4665 | terminx | 1794 | lzwtmpbuf[i] = i, lzwcodenext[i] = (i+1)&255; |
1795 | lzwtmpbuf[i-1] = i-1, lzwcodenext[i-1] = (i) &255; |
||
1796 | lzwtmpbuf[i-2] = i-2, lzwcodenext[i-2] = (i-1)&255; |
||
1797 | lzwtmpbuf[i-3] = i-3, lzwcodenext[i-3] = (i-2)&255; |
||
1798 | lzwcodehead[i] = lzwcodehead[i-1] = lzwcodehead[i-2] = lzwcodehead[i-3] = -1; |
||
1799 | } |
||
1800 | |||
1801 | for (; i>=0; i--) |
||
1802 | { |
||
2368 | helixhorne | 1803 | lzwtmpbuf[i] = i; |
2369 | helixhorne | 1804 | lzwcodenext[i] = (i+1)&255; |
1805 | lzwcodehead[i] = -1; |
||
2368 | helixhorne | 1806 | } |
1807 | |||
2369 | helixhorne | 1808 | Bmemset(lzwoutbuf, 0, 4+uncompleng+1); |
1809 | // clearbuf(lzwoutbuf,((uncompleng+15)+3)>>2,0L); |
||
99 | terminx | 1810 | |
109 | terminx | 1811 | addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3); |
1812 | numbits = 8; oneupnumbits = (1<<8); |
||
1813 | do |
||
1814 | { |
||
1815 | addr = lzwinbuf[bytecnt1]; |
||
1816 | do |
||
1817 | { |
||
2369 | helixhorne | 1818 | int32_t newaddr; |
1819 | |||
4665 | terminx | 1820 | if (++bytecnt1 == uncompleng) |
2369 | helixhorne | 1821 | break; // (*) see XXX below |
2368 | helixhorne | 1822 | |
2369 | helixhorne | 1823 | if (lzwcodehead[addr] < 0) |
1824 | { |
||
1825 | lzwcodehead[addr] = addrcnt; |
||
1826 | break; |
||
1827 | } |
||
2368 | helixhorne | 1828 | |
2369 | helixhorne | 1829 | newaddr = lzwcodehead[addr]; |
2367 | helixhorne | 1830 | while (lzwtmpbuf[newaddr] != lzwinbuf[bytecnt1]) |
109 | terminx | 1831 | { |
2369 | helixhorne | 1832 | if (lzwcodenext[newaddr] < 0) |
1833 | { |
||
1834 | lzwcodenext[newaddr] = addrcnt; |
||
1835 | break; |
||
1836 | } |
||
1837 | newaddr = lzwcodenext[newaddr]; |
||
109 | terminx | 1838 | } |
2368 | helixhorne | 1839 | |
2369 | helixhorne | 1840 | if (lzwcodenext[newaddr] == addrcnt) |
1841 | break; |
||
109 | terminx | 1842 | addr = newaddr; |
584 | terminx | 1843 | } |
1844 | while (addr >= 0); |
||
2368 | helixhorne | 1845 | |
2369 | helixhorne | 1846 | lzwtmpbuf[addrcnt] = lzwinbuf[bytecnt1]; // XXX: potential oob access of lzwinbuf via (*) above |
1847 | lzwcodehead[addrcnt] = -1; |
||
1848 | lzwcodenext[addrcnt] = -1; |
||
99 | terminx | 1849 | |
1205 | terminx | 1850 | intptr = (int32_t *)&lzwoutbuf[bitcnt>>3]; |
109 | terminx | 1851 | intptr[0] |= B_LITTLE32(addr<<(bitcnt&7)); |
1852 | bitcnt += numbits; |
||
1853 | if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1))) |
||
1854 | bitcnt--; |
||
99 | terminx | 1855 | |
109 | terminx | 1856 | addrcnt++; |
2368 | helixhorne | 1857 | if (addrcnt > oneupnumbits) |
1858 | { numbits++; oneupnumbits <<= 1; } |
||
584 | terminx | 1859 | } |
1860 | while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3))); |
||
99 | terminx | 1861 | |
1205 | terminx | 1862 | intptr = (int32_t *)&lzwoutbuf[bitcnt>>3]; |
109 | terminx | 1863 | intptr[0] |= B_LITTLE32(addr<<(bitcnt&7)); |
1864 | bitcnt += numbits; |
||
1865 | if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1))) |
||
1866 | bitcnt--; |
||
99 | terminx | 1867 | |
1205 | terminx | 1868 | shortptr = (int16_t *)lzwoutbuf; |
1869 | shortptr[0] = B_LITTLE16((int16_t)uncompleng); |
||
3879 | helixhorne | 1870 | |
109 | terminx | 1871 | if (((bitcnt+7)>>3) < uncompleng) |
1872 | { |
||
1205 | terminx | 1873 | shortptr[1] = B_LITTLE16((int16_t)addrcnt); |
3879 | helixhorne | 1874 | return (bitcnt+7)>>3; |
109 | terminx | 1875 | } |
2368 | helixhorne | 1876 | |
3879 | helixhorne | 1877 | // Failed compressing, mark this in the stream. |
2368 | helixhorne | 1878 | shortptr[1] = 0; |
4665 | terminx | 1879 | |
1880 | for (i=0; i<uncompleng-4; i+=4) |
||
1881 | { |
||
2368 | helixhorne | 1882 | lzwoutbuf[i+4] = lzwinbuf[i]; |
4665 | terminx | 1883 | lzwoutbuf[i+5] = lzwinbuf[i+1]; |
1884 | lzwoutbuf[i+6] = lzwinbuf[i+2]; |
||
1885 | lzwoutbuf[i+7] = lzwinbuf[i+3]; |
||
1886 | } |
||
2368 | helixhorne | 1887 | |
4665 | terminx | 1888 | for (; i<uncompleng; i++) |
1889 | lzwoutbuf[i+4] = lzwinbuf[i]; |
||
1890 | |||
3879 | helixhorne | 1891 | return uncompleng+4; |
99 | terminx | 1892 | } |
1893 | |||
2361 | helixhorne | 1894 | static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf) |
99 | terminx | 1895 | { |
2368 | helixhorne | 1896 | int32_t currstr, numbits, oneupnumbits; |
3879 | helixhorne | 1897 | int32_t i, bitcnt, outbytecnt; |
99 | terminx | 1898 | |
2368 | helixhorne | 1899 | const int16_t *const shortptr = (const int16_t *)lzwinbuf; |
1900 | const int32_t strtot = B_LITTLE16(shortptr[1]); |
||
1901 | const int32_t uncompleng = B_LITTLE16(shortptr[0]); |
||
1902 | |||
109 | terminx | 1903 | if (strtot == 0) |
1904 | { |
||
3879 | helixhorne | 1905 | if (lzwoutbuf==lzwrawbuf && lzwinbuf==lzwcompbuf) |
1906 | { |
||
1907 | Bassert((compleng-4)+3+0u < sizeof(lzwrawbuf)); |
||
1908 | Bassert((compleng-4)+3+0u < sizeof(lzwcompbuf)-4); |
||
1909 | } |
||
1910 | |||
3153 | helixhorne | 1911 | Bmemcpy(lzwoutbuf, lzwinbuf+4, (compleng-4)+3); |
2368 | helixhorne | 1912 | return uncompleng; |
109 | terminx | 1913 | } |
2368 | helixhorne | 1914 | |
4665 | terminx | 1915 | for (i=255; i>=4; i-=4) |
2368 | helixhorne | 1916 | { |
4665 | terminx | 1917 | lzwbuf2[i] = lzwbuf3[i] = i; |
1918 | lzwbuf2[i-1] = lzwbuf3[i-1] = i-1; |
||
1919 | lzwbuf2[i-2] = lzwbuf3[i-2] = i-2; |
||
1920 | lzwbuf2[i-3] = lzwbuf3[i-3] = i-3; |
||
2368 | helixhorne | 1921 | } |
1922 | |||
4665 | terminx | 1923 | lzwbuf2[i] = lzwbuf3[i] = i; |
1924 | lzwbuf2[i-1] = lzwbuf3[i-1] = i-1; |
||
1925 | lzwbuf2[i-2] = lzwbuf3[i-2] = i-2; |
||
1926 | |||
109 | terminx | 1927 | currstr = 256; bitcnt = (4<<3); outbytecnt = 0; |
1928 | numbits = 8; oneupnumbits = (1<<8); |
||
1929 | do |
||
1930 | { |
||
2368 | helixhorne | 1931 | const int32_t *const intptr = (const int32_t *)&lzwinbuf[bitcnt>>3]; |
1932 | |||
3879 | helixhorne | 1933 | int32_t dat = ((B_LITTLE32(intptr[0])>>(bitcnt&7)) & (oneupnumbits-1)); |
1934 | int32_t leng; |
||
1935 | |||
109 | terminx | 1936 | bitcnt += numbits; |
1937 | if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1))) |
||
584 | terminx | 1938 | { dat &= ((oneupnumbits>>1)-1); bitcnt--; } |
99 | terminx | 1939 | |
109 | terminx | 1940 | lzwbuf3[currstr] = dat; |
99 | terminx | 1941 | |
1229 | terminx | 1942 | for (leng=0; dat>=256; leng++,dat=lzwbuf3[dat]) |
2367 | helixhorne | 1943 | lzwtmpbuf[leng] = lzwbuf2[dat]; |
99 | terminx | 1944 | |
109 | terminx | 1945 | lzwoutbuf[outbytecnt++] = dat; |
4665 | terminx | 1946 | |
1947 | for (i=leng-1; i>=4; i-=4, outbytecnt+=4) |
||
1948 | { |
||
1949 | lzwoutbuf[outbytecnt] = lzwtmpbuf[i]; |
||
1950 | lzwoutbuf[outbytecnt+1] = lzwtmpbuf[i-1]; |
||
1951 | lzwoutbuf[outbytecnt+2] = lzwtmpbuf[i-2]; |
||
1952 | lzwoutbuf[outbytecnt+3] = lzwtmpbuf[i-3]; |
||
1953 | } |
||
1954 | |||
1955 | for (; i>=0; i--) |
||
2368 | helixhorne | 1956 | lzwoutbuf[outbytecnt++] = lzwtmpbuf[i]; |
99 | terminx | 1957 | |
109 | terminx | 1958 | lzwbuf2[currstr-1] = dat; lzwbuf2[currstr] = dat; |
1959 | currstr++; |
||
2368 | helixhorne | 1960 | if (currstr > oneupnumbits) |
1961 | { numbits++; oneupnumbits <<= 1; } |
||
584 | terminx | 1962 | } |
1963 | while (currstr < strtot); |
||
2368 | helixhorne | 1964 | |
1965 | return uncompleng; |
||
99 | terminx | 1966 | } |
1967 | |||
1968 | /* |
||
1969 | * vim:ts=4:sw=4: |
||
1970 | */ |