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