Rev 4905 | 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 | |||
601 | #ifdef FILENAME_CASE_CHECK |
||
602 | // don't free pfn if !=0 AND we Bopen()'ed the file successfully |
||
603 | static int32_t dont_free_pfn; |
||
604 | static char *lastpfn; |
||
605 | #endif |
||
606 | |||
1205 | terminx | 607 | int32_t openfrompath(const char *fn, int32_t flags, int32_t mode) |
99 | terminx | 608 | { |
109 | terminx | 609 | char *pfn; |
1205 | terminx | 610 | int32_t h; |
99 | terminx | 611 | |
109 | terminx | 612 | if (findfrompath(fn, &pfn) < 0) return -1; |
2702 | helixhorne | 613 | |
109 | terminx | 614 | h = Bopen(pfn, flags, mode); |
2692 | helixhorne | 615 | #ifdef FILENAME_CASE_CHECK |
616 | if (h>=0 && dont_free_pfn) |
||
617 | lastpfn = pfn; |
||
618 | else |
||
619 | #endif |
||
620 | Bfree(pfn); |
||
99 | terminx | 621 | |
109 | terminx | 622 | return h; |
99 | terminx | 623 | } |
624 | |||
1762 | terminx | 625 | BFILE *fopenfrompath(const char *fn, const char *mode) |
99 | terminx | 626 | { |
1205 | terminx | 627 | int32_t fh; |
109 | terminx | 628 | BFILE *h; |
1205 | terminx | 629 | int32_t bmode = 0, smode = 0; |
109 | terminx | 630 | const char *c; |
99 | terminx | 631 | |
584 | terminx | 632 | for (c=mode; c[0];) |
633 | { |
||
109 | terminx | 634 | if (c[0] == 'r' && c[1] == '+') { bmode = BO_RDWR; smode = BS_IREAD|BS_IWRITE; c+=2; } |
635 | else if (c[0] == 'r') { bmode = BO_RDONLY; smode = BS_IREAD; c+=1; } |
||
636 | else if (c[0] == 'w' && c[1] == '+') { bmode = BO_RDWR|BO_CREAT|BO_TRUNC; smode = BS_IREAD|BS_IWRITE; c+=2; } |
||
637 | else if (c[0] == 'w') { bmode = BO_WRONLY|BO_CREAT|BO_TRUNC; smode = BS_IREAD|BS_IWRITE; c+=2; } |
||
638 | else if (c[0] == 'a' && c[1] == '+') { bmode = BO_RDWR|BO_CREAT; smode=BS_IREAD|BS_IWRITE; c+=2; } |
||
639 | else if (c[0] == 'a') { bmode = BO_WRONLY|BO_CREAT; smode=BS_IREAD|BS_IWRITE; c+=1; } |
||
640 | else if (c[0] == 'b') { bmode |= BO_BINARY; c+=1; } |
||
641 | else if (c[1] == 't') { bmode |= BO_TEXT; c+=1; } |
||
642 | else c++; |
||
643 | } |
||
644 | fh = openfrompath(fn,bmode,smode); |
||
645 | if (fh < 0) return NULL; |
||
99 | terminx | 646 | |
109 | terminx | 647 | h = fdopen(fh,mode); |
648 | if (!h) close(fh); |
||
649 | |||
650 | return h; |
||
99 | terminx | 651 | } |
652 | |||
5058 | hendricks2 | 653 | #define MAXGROUPFILES 8 // Warning: Fix groupfil if this is changed |
654 | #define MAXOPENFILES 64 // Warning: Fix filehan if this is changed |
||
655 | |||
656 | enum { |
||
657 | GRP_RESERVED_ID_START = 254, |
||
658 | |||
659 | GRP_ZIP = GRP_RESERVED_ID_START, |
||
660 | GRP_FILESYSTEM = GRP_RESERVED_ID_START + 1, |
||
661 | }; |
||
662 | |||
663 | EDUKE32_STATIC_ASSERT(MAXGROUPFILES <= GRP_RESERVED_ID_START); |
||
664 | |||
1205 | terminx | 665 | int32_t numgroupfiles = 0; |
666 | static int32_t gnumfiles[MAXGROUPFILES]; |
||
667 | static int32_t groupfil[MAXGROUPFILES] = {-1,-1,-1,-1,-1,-1,-1,-1}; |
||
668 | static int32_t groupfilpos[MAXGROUPFILES]; |
||
99 | terminx | 669 | static char *gfilelist[MAXGROUPFILES]; |
1205 | terminx | 670 | static int32_t *gfileoffs[MAXGROUPFILES]; |
99 | terminx | 671 | |
5058 | hendricks2 | 672 | static uint8_t filegrp[MAXOPENFILES]; |
1205 | terminx | 673 | static int32_t filepos[MAXOPENFILES]; |
737 | qbix79 | 674 | static intptr_t filehan[MAXOPENFILES] = |
584 | terminx | 675 | { |
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 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 |
||
680 | }; |
||
5058 | hendricks2 | 681 | |
99 | terminx | 682 | #ifdef WITHKPLIB |
683 | static char filenamsav[MAXOPENFILES][260]; |
||
1205 | terminx | 684 | static int32_t kzcurhand = -1; |
3187 | helixhorne | 685 | |
686 | int32_t cache1d_file_fromzip(int32_t fil) |
||
687 | { |
||
5058 | hendricks2 | 688 | return (filegrp[fil] == GRP_ZIP); |
3187 | helixhorne | 689 | } |
99 | terminx | 690 | #endif |
691 | |||
1712 | helixhorne | 692 | int32_t initgroupfile(const char *filename) |
99 | terminx | 693 | { |
109 | terminx | 694 | char buf[16]; |
1205 | terminx | 695 | int32_t i, j, k; |
99 | terminx | 696 | #ifdef WITHKPLIB |
109 | terminx | 697 | char *zfn; |
331 | terminx | 698 | #endif |
99 | terminx | 699 | |
4637 | terminx | 700 | // translate all backslashes (0x5c) to forward slashes (0x2f) |
109 | terminx | 701 | toupperlookup[0x5c] = 0x2f; |
702 | |||
99 | terminx | 703 | #ifdef WITHKPLIB |
109 | terminx | 704 | if (findfrompath(filename, &zfn) < 0) return -1; |
99 | terminx | 705 | |
109 | terminx | 706 | // check to see if the file passed is a ZIP and pass it on to kplib if it is |
707 | i = Bopen(zfn,BO_BINARY|BO_RDONLY,BS_IREAD); |
||
1527 | terminx | 708 | if (i < 0) { Bfree(zfn); return -1; } |
99 | terminx | 709 | |
109 | terminx | 710 | Bread(i, buf, 4); |
584 | terminx | 711 | if (buf[0] == 0x50 && buf[1] == 0x4B && buf[2] == 0x03 && buf[3] == 0x04) |
712 | { |
||
109 | terminx | 713 | Bclose(i); |
714 | j = kzaddstack(zfn); |
||
1527 | terminx | 715 | Bfree(zfn); |
109 | terminx | 716 | return j; |
717 | } |
||
1527 | terminx | 718 | Bfree(zfn); |
99 | terminx | 719 | |
109 | terminx | 720 | if (numgroupfiles >= MAXGROUPFILES) return(-1); |
721 | |||
722 | Blseek(i,0,BSEEK_SET); |
||
723 | groupfil[numgroupfiles] = i; |
||
99 | terminx | 724 | #else |
109 | terminx | 725 | groupfil[numgroupfiles] = openfrompath(filename,BO_BINARY|BO_RDONLY,BS_IREAD); |
726 | if (groupfil[numgroupfiles] != -1) |
||
99 | terminx | 727 | #endif |
109 | terminx | 728 | { |
729 | groupfilpos[numgroupfiles] = 0; |
||
730 | Bread(groupfil[numgroupfiles],buf,16); |
||
2438 | helixhorne | 731 | if (Bmemcmp(buf, "KenSilverman", 12)) |
109 | terminx | 732 | { |
733 | Bclose(groupfil[numgroupfiles]); |
||
734 | groupfil[numgroupfiles] = -1; |
||
735 | return(-1); |
||
736 | } |
||
1205 | terminx | 737 | gnumfiles[numgroupfiles] = B_LITTLE32(*((int32_t *)&buf[12])); |
99 | terminx | 738 | |
4491 | helixhorne | 739 | gfilelist[numgroupfiles] = (char *)Xmalloc(gnumfiles[numgroupfiles]<<4); |
740 | gfileoffs[numgroupfiles] = (int32_t *)Xmalloc((gnumfiles[numgroupfiles]+1)<<2); |
||
99 | terminx | 741 | |
109 | terminx | 742 | Bread(groupfil[numgroupfiles],gfilelist[numgroupfiles],gnumfiles[numgroupfiles]<<4); |
99 | terminx | 743 | |
109 | terminx | 744 | j = 0; |
1229 | terminx | 745 | for (i=0; i<gnumfiles[numgroupfiles]; i++) |
109 | terminx | 746 | { |
1205 | terminx | 747 | k = B_LITTLE32(*((int32_t *)&gfilelist[numgroupfiles][(i<<4)+12])); |
109 | terminx | 748 | gfilelist[numgroupfiles][(i<<4)+12] = 0; |
749 | gfileoffs[numgroupfiles][i] = j; |
||
750 | j += k; |
||
751 | } |
||
752 | gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j; |
||
753 | } |
||
754 | numgroupfiles++; |
||
755 | return(groupfil[numgroupfiles-1]); |
||
99 | terminx | 756 | } |
757 | |||
1205 | terminx | 758 | void uninitsinglegroupfile(int32_t grphandle) |
99 | terminx | 759 | { |
1205 | terminx | 760 | int32_t i, grpnum = -1; |
99 | terminx | 761 | |
1229 | terminx | 762 | for (i=numgroupfiles-1; i>=0; i--) |
109 | terminx | 763 | if (groupfil[i] != -1 && groupfil[i] == grphandle) |
764 | { |
||
1586 | terminx | 765 | Bfree(gfilelist[i]); |
766 | Bfree(gfileoffs[i]); |
||
109 | terminx | 767 | Bclose(groupfil[i]); |
768 | groupfil[i] = -1; |
||
769 | grpnum = i; |
||
770 | break; |
||
771 | } |
||
99 | terminx | 772 | |
109 | terminx | 773 | if (grpnum == -1) return; |
99 | terminx | 774 | |
109 | terminx | 775 | // JBF 20040111 |
776 | numgroupfiles--; |
||
99 | terminx | 777 | |
109 | terminx | 778 | // move any group files following this one back |
779 | for (i=grpnum+1; i<MAXGROUPFILES; i++) |
||
584 | terminx | 780 | if (groupfil[i] != -1) |
781 | { |
||
109 | terminx | 782 | groupfil[i-1] = groupfil[i]; |
783 | gnumfiles[i-1] = gnumfiles[i]; |
||
784 | groupfilpos[i-1] = groupfilpos[i]; |
||
785 | gfilelist[i-1] = gfilelist[i]; |
||
786 | gfileoffs[i-1] = gfileoffs[i]; |
||
787 | groupfil[i] = -1; |
||
788 | } |
||
99 | terminx | 789 | |
109 | terminx | 790 | // fix up the open files that need attention |
1229 | terminx | 791 | for (i=0; i<MAXOPENFILES; i++) |
584 | terminx | 792 | { |
5058 | hendricks2 | 793 | if (filegrp[i] >= GRP_RESERVED_ID_START) // external file or ZIPped file |
109 | terminx | 794 | continue; |
795 | else if (filegrp[i] == grpnum) // close file in group we closed |
||
796 | filehan[i] = -1; |
||
797 | else if (filegrp[i] > grpnum) // move back a file in a group after the one we closed |
||
798 | filegrp[i]--; |
||
799 | } |
||
99 | terminx | 800 | } |
801 | |||
802 | void uninitgroupfile(void) |
||
803 | { |
||
1205 | terminx | 804 | int32_t i; |
99 | terminx | 805 | |
1229 | terminx | 806 | for (i=numgroupfiles-1; i>=0; i--) |
109 | terminx | 807 | if (groupfil[i] != -1) |
808 | { |
||
1586 | terminx | 809 | Bfree(gfilelist[i]); |
810 | Bfree(gfileoffs[i]); |
||
109 | terminx | 811 | Bclose(groupfil[i]); |
812 | groupfil[i] = -1; |
||
813 | } |
||
814 | numgroupfiles = 0; |
||
99 | terminx | 815 | |
109 | terminx | 816 | // JBF 20040111: "close" any files open in groups |
1229 | terminx | 817 | for (i=0; i<MAXOPENFILES; i++) |
584 | terminx | 818 | { |
5058 | hendricks2 | 819 | if (filegrp[i] < GRP_RESERVED_ID_START) // JBF 20040130: not external or ZIPped |
109 | terminx | 820 | filehan[i] = -1; |
821 | } |
||
99 | terminx | 822 | } |
823 | |||
2692 | helixhorne | 824 | #ifdef FILENAME_CASE_CHECK |
825 | // See |
||
826 | // http://stackoverflow.com/questions/74451/getting-actual-file-name-with-proper-casing-on-windows |
||
827 | // for relevant discussion. |
||
828 | |||
829 | static SHFILEINFO shinf; |
||
830 | |||
2702 | helixhorne | 831 | int32_t (*check_filename_casing_fn)(void) = NULL; |
832 | |||
2692 | helixhorne | 833 | // -1: failure, 0: match, 1: mismatch |
834 | static int32_t check_filename_mismatch(const char *filename, int32_t ofs) |
||
835 | { |
||
2702 | helixhorne | 836 | const char *fn = filename+ofs; |
3068 | terminx | 837 | int32_t len; |
2702 | helixhorne | 838 | |
2692 | helixhorne | 839 | // we assume that UNICODE is not #defined, winlayer.c errors out else |
840 | if (!SHGetFileInfo(filename, -1, &shinf, sizeof(shinf), SHGFI_DISPLAYNAME)) |
||
841 | return -1; |
||
842 | |||
3068 | terminx | 843 | len = Bstrlen(shinf.szDisplayName); |
844 | |||
845 | if (!Bstrncmp(shinf.szDisplayName, fn, len)) |
||
2702 | helixhorne | 846 | return 0; |
847 | |||
848 | { |
||
4491 | helixhorne | 849 | char *tfn = Bstrtolower(Xstrdup(fn)); |
2702 | helixhorne | 850 | |
3068 | terminx | 851 | if (!Bstrncmp(shinf.szDisplayName, tfn, len)) |
2702 | helixhorne | 852 | { |
853 | Bfree(tfn); |
||
854 | return 0; |
||
855 | } |
||
856 | |||
857 | Bstrupr(tfn); |
||
858 | |||
3068 | terminx | 859 | if (!Bstrncmp(shinf.szDisplayName, tfn, len)) |
2702 | helixhorne | 860 | { |
861 | Bfree(tfn); |
||
862 | return 0; |
||
863 | } |
||
864 | |||
865 | Bfree(tfn); |
||
866 | } |
||
867 | |||
868 | return 1; |
||
2692 | helixhorne | 869 | } |
870 | #endif |
||
871 | |||
1712 | helixhorne | 872 | int32_t kopen4load(const char *filename, char searchfirst) |
99 | terminx | 873 | { |
1592 | terminx | 874 | int32_t j, k, fil, newhandle = MAXOPENFILES-1; |
109 | terminx | 875 | char bad, *gfileptr; |
737 | qbix79 | 876 | intptr_t i; |
99 | terminx | 877 | |
2702 | helixhorne | 878 | #ifdef FILENAME_CASE_CHECK |
879 | const int32_t do_case_check = check_filename_casing_fn && check_filename_casing_fn(); |
||
880 | #endif |
||
881 | |||
1760 | helixhorne | 882 | if (filename==NULL) |
883 | return -1; |
||
884 | |||
109 | terminx | 885 | while (filehan[newhandle] != -1) |
886 | { |
||
887 | newhandle--; |
||
888 | if (newhandle < 0) |
||
889 | { |
||
890 | Bprintf("TOO MANY FILES OPEN IN FILE GROUPING SYSTEM!"); |
||
4502 | hendricks2 | 891 | Bexit(0); |
109 | terminx | 892 | } |
893 | } |
||
99 | terminx | 894 | |
2692 | helixhorne | 895 | #ifdef FILENAME_CASE_CHECK |
2702 | helixhorne | 896 | dont_free_pfn = do_case_check; |
2692 | helixhorne | 897 | #endif |
898 | |||
2776 | terminx | 899 | if (searchfirst == 0 && (fil = openfrompath(filename,BO_BINARY|BO_RDONLY,BS_IREAD)) >= 0) |
1592 | terminx | 900 | { |
2692 | helixhorne | 901 | #ifdef FILENAME_CASE_CHECK |
2702 | helixhorne | 902 | if (check_filename_casing_fn && check_filename_casing_fn()) |
903 | { |
||
904 | int32_t status; |
||
905 | char *cp, *lastslash; |
||
2692 | helixhorne | 906 | |
2702 | helixhorne | 907 | // convert all slashes to backslashes because SHGetFileInfo() |
908 | // complains else! |
||
909 | lastslash = lastpfn; |
||
910 | for (cp=lastpfn; *cp; cp++) |
||
911 | if (*cp=='/') |
||
912 | { |
||
913 | *cp = '\\'; |
||
914 | lastslash = cp; |
||
915 | } |
||
916 | if (lastslash != lastpfn) |
||
917 | lastslash++; |
||
918 | |||
919 | status = check_filename_mismatch(lastpfn, lastslash-lastpfn); |
||
920 | |||
921 | dont_free_pfn = 0; |
||
922 | |||
923 | if (status == -1) |
||
2692 | helixhorne | 924 | { |
3385 | helixhorne | 925 | // initprintf("SHGetFileInfo failed with error code %lu\n", GetLastError()); |
2692 | helixhorne | 926 | } |
2702 | helixhorne | 927 | else if (status == 1) |
928 | { |
||
929 | initprintf("warning: case mismatch: passed \"%s\", real \"%s\"\n", |
||
930 | lastslash, shinf.szDisplayName); |
||
931 | } |
||
2692 | helixhorne | 932 | |
2702 | helixhorne | 933 | Bfree(lastpfn); |
934 | lastpfn=NULL; |
||
2692 | helixhorne | 935 | } |
936 | #endif |
||
5058 | hendricks2 | 937 | filegrp[newhandle] = GRP_FILESYSTEM; |
1592 | terminx | 938 | filehan[newhandle] = fil; |
939 | filepos[newhandle] = 0; |
||
940 | return(newhandle); |
||
941 | } |
||
99 | terminx | 942 | |
2692 | helixhorne | 943 | #ifdef FILENAME_CASE_CHECK |
944 | dont_free_pfn = 0; |
||
945 | #endif |
||
946 | |||
109 | terminx | 947 | for (; toupperlookup[*filename] == '/'; filename++); |
948 | |||
99 | terminx | 949 | #ifdef WITHKPLIB |
109 | terminx | 950 | if ((kzcurhand != newhandle) && (kztell() >= 0)) |
951 | { |
||
952 | if (kzcurhand >= 0) filepos[kzcurhand] = kztell(); |
||
953 | kzclose(); |
||
954 | } |
||
584 | terminx | 955 | if (searchfirst != 1 && (i = kzipopen(filename)) != 0) |
956 | { |
||
109 | terminx | 957 | kzcurhand = newhandle; |
5058 | hendricks2 | 958 | filegrp[newhandle] = GRP_ZIP; |
109 | terminx | 959 | filehan[newhandle] = i; |
960 | filepos[newhandle] = 0; |
||
961 | strcpy(filenamsav[newhandle],filename); |
||
962 | return newhandle; |
||
963 | } |
||
99 | terminx | 964 | #endif |
965 | |||
1229 | terminx | 966 | for (k=numgroupfiles-1; k>=0; k--) |
109 | terminx | 967 | { |
968 | if (searchfirst == 1) k = 0; |
||
969 | if (groupfil[k] >= 0) |
||
970 | { |
||
1229 | terminx | 971 | for (i=gnumfiles[k]-1; i>=0; i--) |
109 | terminx | 972 | { |
973 | gfileptr = (char *)&gfilelist[k][i<<4]; |
||
99 | terminx | 974 | |
109 | terminx | 975 | bad = 0; |
1229 | terminx | 976 | for (j=0; j<13; j++) |
109 | terminx | 977 | { |
978 | if (!filename[j]) break; |
||
979 | if (toupperlookup[filename[j]] != toupperlookup[gfileptr[j]]) |
||
2438 | helixhorne | 980 | { |
981 | bad = 1; |
||
982 | break; |
||
983 | } |
||
109 | terminx | 984 | } |
985 | if (bad) continue; |
||
986 | if (j<13 && gfileptr[j]) continue; // JBF: because e1l1.map might exist before e1l1 |
||
1592 | terminx | 987 | if (j==13 && filename[j]) continue; // JBF: long file name |
99 | terminx | 988 | |
109 | terminx | 989 | filegrp[newhandle] = k; |
990 | filehan[newhandle] = i; |
||
991 | filepos[newhandle] = 0; |
||
992 | return(newhandle); |
||
993 | } |
||
994 | } |
||
995 | } |
||
996 | return(-1); |
||
99 | terminx | 997 | } |
998 | |||
1205 | terminx | 999 | int32_t kread(int32_t handle, void *buffer, int32_t leng) |
99 | terminx | 1000 | { |
1592 | terminx | 1001 | int32_t i; |
1002 | int32_t filenum = filehan[handle]; |
||
1003 | int32_t groupnum = filegrp[handle]; |
||
99 | terminx | 1004 | |
5058 | hendricks2 | 1005 | if (groupnum == GRP_FILESYSTEM) return(Bread(filenum,buffer,leng)); |
99 | terminx | 1006 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1007 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1008 | { |
1009 | if (kzcurhand != handle) |
||
1010 | { |
||
1011 | if (kztell() >= 0) { filepos[kzcurhand] = kztell(); kzclose(); } |
||
1012 | kzcurhand = handle; |
||
1013 | kzipopen(filenamsav[handle]); |
||
1014 | kzseek(filepos[handle],SEEK_SET); |
||
1015 | } |
||
1016 | return(kzread(buffer,leng)); |
||
1017 | } |
||
99 | terminx | 1018 | #endif |
1019 | |||
109 | terminx | 1020 | if (groupfil[groupnum] != -1) |
1021 | { |
||
1022 | i = gfileoffs[groupnum][filenum]+filepos[handle]; |
||
1023 | if (i != groupfilpos[groupnum]) |
||
1024 | { |
||
1025 | Blseek(groupfil[groupnum],i+((gnumfiles[groupnum]+1)<<4),BSEEK_SET); |
||
1026 | groupfilpos[groupnum] = i; |
||
1027 | } |
||
1028 | leng = min(leng,(gfileoffs[groupnum][filenum+1]-gfileoffs[groupnum][filenum])-filepos[handle]); |
||
1029 | leng = Bread(groupfil[groupnum],buffer,leng); |
||
1030 | filepos[handle] += leng; |
||
1031 | groupfilpos[groupnum] += leng; |
||
1032 | return(leng); |
||
1033 | } |
||
99 | terminx | 1034 | |
109 | terminx | 1035 | return(0); |
99 | terminx | 1036 | } |
1037 | |||
1205 | terminx | 1038 | int32_t klseek(int32_t handle, int32_t offset, int32_t whence) |
99 | terminx | 1039 | { |
1205 | terminx | 1040 | int32_t i, groupnum; |
99 | terminx | 1041 | |
109 | terminx | 1042 | groupnum = filegrp[handle]; |
99 | terminx | 1043 | |
5058 | hendricks2 | 1044 | if (groupnum == GRP_FILESYSTEM) return(Blseek(filehan[handle],offset,whence)); |
99 | terminx | 1045 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1046 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1047 | { |
1048 | if (kzcurhand != handle) |
||
1049 | { |
||
1050 | if (kztell() >= 0) { filepos[kzcurhand] = kztell(); kzclose(); } |
||
1051 | kzcurhand = handle; |
||
1052 | kzipopen(filenamsav[handle]); |
||
1053 | kzseek(filepos[handle],SEEK_SET); |
||
1054 | } |
||
1055 | return(kzseek(offset,whence)); |
||
1056 | } |
||
99 | terminx | 1057 | #endif |
1058 | |||
109 | terminx | 1059 | if (groupfil[groupnum] != -1) |
1060 | { |
||
331 | terminx | 1061 | switch (whence) |
109 | terminx | 1062 | { |
331 | terminx | 1063 | case BSEEK_SET: |
1064 | filepos[handle] = offset; break; |
||
1065 | case BSEEK_END: |
||
1066 | i = filehan[handle]; |
||
109 | terminx | 1067 | filepos[handle] = (gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i])+offset; |
1068 | break; |
||
331 | terminx | 1069 | case BSEEK_CUR: |
1070 | filepos[handle] += offset; break; |
||
109 | terminx | 1071 | } |
1072 | return(filepos[handle]); |
||
1073 | } |
||
1074 | return(-1); |
||
99 | terminx | 1075 | } |
1076 | |||
1205 | terminx | 1077 | int32_t kfilelength(int32_t handle) |
99 | terminx | 1078 | { |
1205 | terminx | 1079 | int32_t i, groupnum; |
99 | terminx | 1080 | |
109 | terminx | 1081 | groupnum = filegrp[handle]; |
5058 | hendricks2 | 1082 | if (groupnum == GRP_FILESYSTEM) |
584 | terminx | 1083 | { |
109 | terminx | 1084 | // return(filelength(filehan[handle])) |
1085 | return Bfilelength(filehan[handle]); |
||
1086 | } |
||
99 | terminx | 1087 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1088 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1089 | { |
1090 | if (kzcurhand != handle) |
||
1091 | { |
||
1092 | if (kztell() >= 0) { filepos[kzcurhand] = kztell(); kzclose(); } |
||
1093 | kzcurhand = handle; |
||
1094 | kzipopen(filenamsav[handle]); |
||
1095 | kzseek(filepos[handle],SEEK_SET); |
||
1096 | } |
||
1097 | return kzfilelength(); |
||
1098 | } |
||
99 | terminx | 1099 | #endif |
109 | terminx | 1100 | i = filehan[handle]; |
1101 | return(gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i]); |
||
99 | terminx | 1102 | } |
1103 | |||
1205 | terminx | 1104 | int32_t ktell(int32_t handle) |
99 | terminx | 1105 | { |
1205 | terminx | 1106 | int32_t groupnum = filegrp[handle]; |
99 | terminx | 1107 | |
5058 | hendricks2 | 1108 | if (groupnum == GRP_FILESYSTEM) return(Blseek(filehan[handle],0,BSEEK_CUR)); |
99 | terminx | 1109 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1110 | else if (groupnum == GRP_ZIP) |
109 | terminx | 1111 | { |
1112 | if (kzcurhand != handle) |
||
1113 | { |
||
1114 | if (kztell() >= 0) { filepos[kzcurhand] = kztell(); kzclose(); } |
||
1115 | kzcurhand = handle; |
||
1116 | kzipopen(filenamsav[handle]); |
||
1117 | kzseek(filepos[handle],SEEK_SET); |
||
1118 | } |
||
1119 | return kztell(); |
||
1120 | } |
||
99 | terminx | 1121 | #endif |
109 | terminx | 1122 | if (groupfil[groupnum] != -1) |
1123 | return filepos[handle]; |
||
1124 | return(-1); |
||
99 | terminx | 1125 | } |
1126 | |||
1205 | terminx | 1127 | void kclose(int32_t handle) |
99 | terminx | 1128 | { |
109 | terminx | 1129 | if (handle < 0) return; |
5058 | hendricks2 | 1130 | if (filegrp[handle] == GRP_FILESYSTEM) Bclose(filehan[handle]); |
99 | terminx | 1131 | #ifdef WITHKPLIB |
5058 | hendricks2 | 1132 | else if (filegrp[handle] == GRP_ZIP) |
109 | terminx | 1133 | { |
1134 | kzclose(); |
||
1135 | kzcurhand = -1; |
||
1136 | } |
||
99 | terminx | 1137 | #endif |
109 | terminx | 1138 | filehan[handle] = -1; |
99 | terminx | 1139 | } |
1140 | |||
1799 | helixhorne | 1141 | static int32_t klistaddentry(CACHE1D_FIND_REC **rec, const char *name, int32_t type, int32_t source) |
99 | terminx | 1142 | { |
109 | terminx | 1143 | CACHE1D_FIND_REC *r = NULL, *attach = NULL; |
99 | terminx | 1144 | |
584 | terminx | 1145 | if (*rec) |
1146 | { |
||
1205 | terminx | 1147 | int32_t insensitive, v; |
109 | terminx | 1148 | CACHE1D_FIND_REC *last = NULL; |
1149 | |||
584 | terminx | 1150 | for (attach = *rec; attach; last = attach, attach = attach->next) |
1151 | { |
||
109 | terminx | 1152 | if (type == CACHE1D_FIND_DRIVE) continue; // we just want to get to the end for drives |
99 | terminx | 1153 | #ifdef _WIN32 |
109 | terminx | 1154 | insensitive = 1; |
99 | terminx | 1155 | #else |
109 | terminx | 1156 | if (source == CACHE1D_SOURCE_GRP || attach->source == CACHE1D_SOURCE_GRP) |
1157 | insensitive = 1; |
||
1158 | else if (source == CACHE1D_SOURCE_ZIP || attach->source == CACHE1D_SOURCE_ZIP) |
||
1159 | insensitive = 1; |
||
1160 | else |
||
2356 | helixhorne | 1161 | { |
1162 | extern int16_t editstatus; // XXX |
||
1163 | insensitive = !editstatus; |
||
1164 | } |
||
1165 | // ^ in the game, don't show file list case-sensitive |
||
99 | terminx | 1166 | #endif |
109 | terminx | 1167 | if (insensitive) v = Bstrcasecmp(name, attach->name); |
1168 | else v = Bstrcmp(name, attach->name); |
||
99 | terminx | 1169 | |
109 | terminx | 1170 | // sorted list |
1171 | if (v > 0) continue; // item to add is bigger than the current one |
||
1172 | // so look for something bigger than us |
||
584 | terminx | 1173 | if (v < 0) // item to add is smaller than the current one |
1174 | { |
||
109 | terminx | 1175 | attach = NULL; // so wedge it between the current item and the one before |
1176 | break; |
||
1177 | } |
||
99 | terminx | 1178 | |
109 | terminx | 1179 | // matched |
1180 | if (source >= attach->source) return 1; // item to add is of lower priority |
||
1181 | r = attach; |
||
1182 | break; |
||
1183 | } |
||
99 | terminx | 1184 | |
109 | terminx | 1185 | // wasn't found in the list, so attach to the end |
1186 | if (!attach) attach = last; |
||
1187 | } |
||
99 | terminx | 1188 | |
584 | terminx | 1189 | if (r) |
1190 | { |
||
109 | terminx | 1191 | r->type = type; |
1192 | r->source = source; |
||
1193 | return 0; |
||
1194 | } |
||
99 | terminx | 1195 | |
4491 | helixhorne | 1196 | r = (CACHE1D_FIND_REC *)Xmalloc(sizeof(CACHE1D_FIND_REC)+strlen(name)+1); |
1197 | |||
1762 | terminx | 1198 | r->name = (char *)r + sizeof(CACHE1D_FIND_REC); strcpy(r->name, name); |
109 | terminx | 1199 | r->type = type; |
1200 | r->source = source; |
||
1201 | r->usera = r->userb = NULL; |
||
1202 | |||
584 | terminx | 1203 | if (!attach) // we are the first item |
1204 | { |
||
109 | terminx | 1205 | r->prev = NULL; |
1206 | r->next = *rec; |
||
584 | terminx | 1207 | if (*rec)(*rec)->prev = r; |
109 | terminx | 1208 | *rec = r; |
584 | terminx | 1209 | } |
1210 | else |
||
1211 | { |
||
109 | terminx | 1212 | r->prev = attach; |
1213 | r->next = attach->next; |
||
1214 | if (attach->next) attach->next->prev = r; |
||
1215 | attach->next = r; |
||
1216 | } |
||
1217 | |||
1218 | return 0; |
||
99 | terminx | 1219 | } |
1220 | |||
1221 | void klistfree(CACHE1D_FIND_REC *rec) |
||
1222 | { |
||
109 | terminx | 1223 | CACHE1D_FIND_REC *n; |
1224 | |||
584 | terminx | 1225 | while (rec) |
1226 | { |
||
109 | terminx | 1227 | n = rec->next; |
1527 | terminx | 1228 | Bfree(rec); |
109 | terminx | 1229 | rec = n; |
1230 | } |
||
99 | terminx | 1231 | } |
1232 | |||
1205 | terminx | 1233 | CACHE1D_FIND_REC *klistpath(const char *_path, const char *mask, int32_t type) |
99 | terminx | 1234 | { |
109 | terminx | 1235 | CACHE1D_FIND_REC *rec = NULL; |
1236 | char *path; |
||
99 | terminx | 1237 | |
109 | terminx | 1238 | // pathsearchmode == 0: enumerates a path in the virtual filesystem |
1239 | // pathsearchmode == 1: enumerates the system filesystem path passed in |
||
99 | terminx | 1240 | |
4491 | helixhorne | 1241 | path = Xstrdup(_path); |
99 | terminx | 1242 | |
109 | terminx | 1243 | // we don't need any leading dots and slashes or trailing slashes either |
1244 | { |
||
1205 | terminx | 1245 | int32_t i,j; |
584 | terminx | 1246 | for (i=0; path[i] == '.' || toupperlookup[path[i]] == '/';) i++; |
109 | terminx | 1247 | for (j=0; (path[j] = path[i]); j++,i++) ; |
1248 | while (j>0 && toupperlookup[path[j-1]] == '/') j--; |
||
1249 | path[j] = 0; |
||
1250 | //initprintf("Cleaned up path = \"%s\"\n",path); |
||
1251 | } |
||
99 | terminx | 1252 | |
584 | terminx | 1253 | if (*path && (type & CACHE1D_FIND_DIR)) |
1254 | { |
||
109 | terminx | 1255 | if (klistaddentry(&rec, "..", CACHE1D_FIND_DIR, CACHE1D_SOURCE_CURDIR) < 0) goto failure; |
1256 | } |
||
99 | terminx | 1257 | |
584 | terminx | 1258 | if (!(type & CACHE1D_OPT_NOSTACK)) // current directory and paths in the search stack |
1259 | { |
||
109 | terminx | 1260 | searchpath_t *search = NULL; |
1261 | BDIR *dir; |
||
1262 | struct Bdirent *dirent; |
||
4188 | helixhorne | 1263 | |
1264 | static const char *const CUR_DIR = "./"; |
||
932 | terminx | 1265 | // Adjusted for the following "autoload" dir fix - NY00123 |
4188 | helixhorne | 1266 | const char *d = pathsearchmode ? _path : CUR_DIR; |
1205 | terminx | 1267 | int32_t stackdepth = CACHE1D_SOURCE_CURDIR; |
109 | terminx | 1268 | char buf[BMAX_PATH]; |
99 | terminx | 1269 | |
584 | terminx | 1270 | do |
1271 | { |
||
4188 | helixhorne | 1272 | if (d==CUR_DIR && (type & CACHE1D_FIND_NOCURDIR)) |
1273 | goto next; |
||
1274 | |||
2010 | helixhorne | 1275 | strcpy(buf, d); |
584 | terminx | 1276 | if (!pathsearchmode) |
1277 | { |
||
932 | terminx | 1278 | // Fix for "autoload" dir in multi-user environments - NY00123 |
1279 | strcat(buf, path); |
||
109 | terminx | 1280 | if (*path) strcat(buf, "/"); |
584 | terminx | 1281 | } |
2010 | helixhorne | 1282 | |
109 | terminx | 1283 | dir = Bopendir(buf); |
584 | terminx | 1284 | if (dir) |
1285 | { |
||
1286 | while ((dirent = Breaddir(dir))) |
||
1287 | { |
||
109 | terminx | 1288 | if ((dirent->name[0] == '.' && dirent->name[1] == 0) || |
1289 | (dirent->name[0] == '.' && dirent->name[1] == '.' && dirent->name[2] == 0)) |
||
1290 | continue; |
||
1291 | if ((type & CACHE1D_FIND_DIR) && !(dirent->mode & BS_IFDIR)) continue; |
||
1292 | if ((type & CACHE1D_FIND_FILE) && (dirent->mode & BS_IFDIR)) continue; |
||
1293 | if (!Bwildmatch(dirent->name, mask)) continue; |
||
1294 | switch (klistaddentry(&rec, dirent->name, |
||
1295 | (dirent->mode & BS_IFDIR) ? CACHE1D_FIND_DIR : CACHE1D_FIND_FILE, |
||
584 | terminx | 1296 | stackdepth)) |
1297 | { |
||
109 | terminx | 1298 | case -1: goto failure; |
1299 | //case 1: initprintf("%s:%s dropped for lower priority\n", d,dirent->name); break; |
||
1300 | //case 0: initprintf("%s:%s accepted\n", d,dirent->name); break; |
||
331 | terminx | 1301 | default: |
1302 | break; |
||
109 | terminx | 1303 | } |
1304 | } |
||
1305 | Bclosedir(dir); |
||
1306 | } |
||
4188 | helixhorne | 1307 | next: |
1308 | if (pathsearchmode) |
||
1309 | break; |
||
99 | terminx | 1310 | |
584 | terminx | 1311 | if (!search) |
1312 | { |
||
109 | terminx | 1313 | search = searchpathhead; |
1314 | stackdepth = CACHE1D_SOURCE_PATH; |
||
584 | terminx | 1315 | } |
1316 | else |
||
1317 | { |
||
109 | terminx | 1318 | search = search->next; |
1319 | stackdepth++; |
||
1320 | } |
||
4188 | helixhorne | 1321 | |
1322 | if (search) |
||
1323 | d = search->path; |
||
584 | terminx | 1324 | } |
1325 | while (search); |
||
109 | terminx | 1326 | } |
1327 | |||
3484 | helixhorne | 1328 | #ifdef WITHKPLIB |
4188 | helixhorne | 1329 | if (!(type & CACHE1D_FIND_NOCURDIR)) // TEMP, until we have sorted out fs.listpath() API |
584 | terminx | 1330 | if (!pathsearchmode) // next, zip files |
1331 | { |
||
1479 | terminx | 1332 | char buf[BMAX_PATH+4]; |
1205 | terminx | 1333 | int32_t i, j, ftype; |
109 | terminx | 1334 | strcpy(buf,path); |
1335 | if (*path) strcat(buf,"/"); |
||
1336 | strcat(buf,mask); |
||
584 | terminx | 1337 | for (kzfindfilestart(buf); kzfindfile(buf);) |
1338 | { |
||
109 | terminx | 1339 | if (buf[0] != '|') continue; // local files we don't need |
1340 | |||
1341 | // scan for the end of the string and shift |
||
1342 | // everything left a char in the process |
||
2416 | helixhorne | 1343 | for (i=1; (buf[i-1]=buf[i]); i++) |
1344 | { |
||
1345 | /* do nothing */ |
||
1346 | } |
||
1347 | i-=2; |
||
4543 | hendricks2 | 1348 | if (i < 0) |
1349 | i = 0; |
||
109 | terminx | 1350 | |
1351 | // if there's a slash at the end, this is a directory entry |
||
584 | terminx | 1352 | if (toupperlookup[buf[i]] == '/') { ftype = CACHE1D_FIND_DIR; buf[i] = 0; } |
109 | terminx | 1353 | else ftype = CACHE1D_FIND_FILE; |
1354 | |||
1355 | // skip over the common characters at the beginning of the base path and the zip entry |
||
584 | terminx | 1356 | for (j=0; buf[j] && path[j]; j++) |
1357 | { |
||
109 | terminx | 1358 | if (toupperlookup[ path[j] ] == toupperlookup[ buf[j] ]) continue; |
1359 | break; |
||
1360 | } |
||
1361 | // we've now hopefully skipped the common path component at the beginning. |
||
1362 | // if that's true, we should be staring at a null byte in path and either any character in buf |
||
1363 | // if j==0, or a slash if j>0 |
||
584 | terminx | 1364 | if ((!path[0] && buf[j]) || (!path[j] && toupperlookup[ buf[j] ] == '/')) |
1365 | { |
||
109 | terminx | 1366 | if (j>0) j++; |
1367 | |||
1368 | // yep, so now we shift what follows back to the start of buf and while we do that, |
||
1369 | // keep an eye out for any more slashes which would mean this entry has sub-entities |
||
1370 | // and is useless to us. |
||
1371 | for (i = 0; (buf[i] = buf[j]) && toupperlookup[buf[j]] != '/'; i++,j++) ; |
||
1372 | if (toupperlookup[buf[j]] == '/') continue; // damn, try next entry |
||
584 | terminx | 1373 | } |
1374 | else |
||
1375 | { |
||
109 | terminx | 1376 | // if we're here it means we have a situation where: |
1377 | // path = foo |
||
1378 | // buf = foobar... |
||
1379 | // or |
||
1380 | // path = foobar |
||
1381 | // buf = foo... |
||
1382 | // which would mean the entry is higher up in the directory tree and is also useless |
||
1383 | continue; |
||
1384 | } |
||
1385 | |||
1386 | if ((type & CACHE1D_FIND_DIR) && ftype != CACHE1D_FIND_DIR) continue; |
||
1387 | if ((type & CACHE1D_FIND_FILE) && ftype != CACHE1D_FIND_FILE) continue; |
||
1388 | |||
1389 | // the entry is in the clear |
||
584 | terminx | 1390 | switch (klistaddentry(&rec, buf, ftype, CACHE1D_SOURCE_ZIP)) |
1391 | { |
||
331 | terminx | 1392 | case -1: |
1393 | goto failure; |
||
109 | terminx | 1394 | //case 1: initprintf("<ZIP>:%s dropped for lower priority\n", buf); break; |
1395 | //case 0: initprintf("<ZIP>:%s accepted\n", buf); break; |
||
331 | terminx | 1396 | default: |
1397 | break; |
||
109 | terminx | 1398 | } |
1399 | } |
||
1400 | } |
||
3484 | helixhorne | 1401 | #endif |
109 | terminx | 1402 | // then, grp files |
4188 | helixhorne | 1403 | if (!(type & CACHE1D_FIND_NOCURDIR)) // TEMP, until we have sorted out fs.listpath() API |
584 | terminx | 1404 | if (!pathsearchmode && !*path && (type & CACHE1D_FIND_FILE)) |
1405 | { |
||
109 | terminx | 1406 | char buf[13]; |
1205 | terminx | 1407 | int32_t i,j; |
109 | terminx | 1408 | buf[12] = 0; |
1229 | terminx | 1409 | for (i=0; i<MAXGROUPFILES; i++) |
584 | terminx | 1410 | { |
109 | terminx | 1411 | if (groupfil[i] == -1) continue; |
1229 | terminx | 1412 | for (j=gnumfiles[i]-1; j>=0; j--) |
109 | terminx | 1413 | { |
1414 | Bmemcpy(buf,&gfilelist[i][j<<4],12); |
||
1415 | if (!Bwildmatch(buf,mask)) continue; |
||
584 | terminx | 1416 | switch (klistaddentry(&rec, buf, CACHE1D_FIND_FILE, CACHE1D_SOURCE_GRP)) |
1417 | { |
||
331 | terminx | 1418 | case -1: |
1419 | goto failure; |
||
109 | terminx | 1420 | //case 1: initprintf("<GRP>:%s dropped for lower priority\n", workspace); break; |
1421 | //case 0: initprintf("<GRP>:%s accepted\n", workspace); break; |
||
331 | terminx | 1422 | default: |
1423 | break; |
||
109 | terminx | 1424 | } |
1425 | } |
||
1426 | } |
||
1427 | } |
||
1428 | |||
584 | terminx | 1429 | if (pathsearchmode && (type & CACHE1D_FIND_DRIVE)) |
1430 | { |
||
109 | terminx | 1431 | char *drives, *drp; |
1432 | drives = Bgetsystemdrives(); |
||
584 | terminx | 1433 | if (drives) |
1434 | { |
||
1435 | for (drp=drives; *drp; drp+=strlen(drp)+1) |
||
1436 | { |
||
1437 | if (klistaddentry(&rec, drp, CACHE1D_FIND_DRIVE, CACHE1D_SOURCE_DRIVE) < 0) |
||
1438 | { |
||
1527 | terminx | 1439 | Bfree(drives); |
109 | terminx | 1440 | goto failure; |
1441 | } |
||
1442 | } |
||
1527 | terminx | 1443 | Bfree(drives); |
109 | terminx | 1444 | } |
1445 | } |
||
1446 | |||
1527 | terminx | 1447 | Bfree(path); |
4175 | helixhorne | 1448 | // XXX: may be NULL if no file was listed, and thus indistinguishable from |
1449 | // an error condition. |
||
109 | terminx | 1450 | return rec; |
99 | terminx | 1451 | failure: |
1527 | terminx | 1452 | Bfree(path); |
109 | terminx | 1453 | klistfree(rec); |
1454 | return NULL; |
||
99 | terminx | 1455 | } |
1456 | |||
3153 | helixhorne | 1457 | |
1458 | #endif // #ifdef CACHE1D_COMPRESS_ONLY / else |
||
1459 | |||
1460 | |||
109 | terminx | 1461 | //Internal LZW variables |
99 | terminx | 1462 | #define LZWSIZE 16384 //Watch out for shorts! |
2366 | helixhorne | 1463 | #define LZWSIZEPAD (LZWSIZE+(LZWSIZE>>4)) |
99 | terminx | 1464 | |
3880 | helixhorne | 1465 | // lzwrawbuf LZWSIZE+1 (formerly): see (*) below |
1466 | // XXX: lzwrawbuf size increased again :-/ |
||
1467 | static char lzwtmpbuf[LZWSIZEPAD], lzwrawbuf[LZWSIZEPAD], lzwcompbuf[LZWSIZEPAD]; |
||
2366 | helixhorne | 1468 | static int16_t lzwbuf2[LZWSIZEPAD], lzwbuf3[LZWSIZEPAD]; |
1469 | |||
2361 | helixhorne | 1470 | static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf); |
1471 | static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf); |
||
99 | terminx | 1472 | |
3153 | helixhorne | 1473 | #ifndef CACHE1D_COMPRESS_ONLY |
1474 | static int32_t kdfread_func(intptr_t fil, void *outbuf, int32_t length) |
||
99 | terminx | 1475 | { |
3153 | helixhorne | 1476 | return kread((int32_t)fil, outbuf, length); |
1477 | } |
||
1478 | |||
1479 | static void dfwrite_func(intptr_t fp, const void *inbuf, int32_t length) |
||
1480 | { |
||
1481 | Bfwrite(inbuf, length, 1, (BFILE *)fp); |
||
1482 | } |
||
1483 | #else |
||
1484 | # define kdfread_func NULL |
||
1485 | # define dfwrite_func NULL |
||
1486 | #endif |
||
1487 | |||
1488 | // These two follow the argument order of the C functions "read" and "write": |
||
1489 | // handle, buffer, length. |
||
1490 | C1D_STATIC int32_t (*c1d_readfunc)(intptr_t, void *, int32_t) = kdfread_func; |
||
1491 | C1D_STATIC void (*c1d_writefunc)(intptr_t, const void *, int32_t) = dfwrite_func; |
||
1492 | |||
1493 | |||
1494 | ////////// COMPRESSED READ ////////// |
||
1495 | |||
3879 | helixhorne | 1496 | static uint32_t decompress_part(intptr_t f, uint32_t *kgoalptr) |
3153 | helixhorne | 1497 | { |
3879 | helixhorne | 1498 | int16_t leng; |
1499 | |||
1500 | // Read compressed length first. |
||
1501 | if (c1d_readfunc(f, &leng, 2) != 2) |
||
3153 | helixhorne | 1502 | return 1; |
3879 | helixhorne | 1503 | leng = B_LITTLE16(leng); |
1504 | |||
3153 | helixhorne | 1505 | if (c1d_readfunc(f,lzwcompbuf, leng) != leng) |
1506 | return 1; |
||
3879 | helixhorne | 1507 | |
1508 | *kgoalptr = lzwuncompress(lzwcompbuf, leng, lzwrawbuf); |
||
3153 | helixhorne | 1509 | return 0; |
1510 | } |
||
1511 | |||
1512 | // Read from 'f' into 'buffer'. |
||
1513 | C1D_STATIC int32_t c1d_read_compressed(void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f) |
||
1514 | { |
||
4837 | helixhorne | 1515 | char *ptr = (char *)buffer; |
99 | terminx | 1516 | |
2369 | helixhorne | 1517 | if (dasizeof > LZWSIZE) |
1518 | { |
||
4838 | helixhorne | 1519 | count *= dasizeof; |
1520 | dasizeof = 1; |
||
2369 | helixhorne | 1521 | } |
1522 | |||
4837 | helixhorne | 1523 | uint32_t kgoal; |
99 | terminx | 1524 | |
4837 | helixhorne | 1525 | if (decompress_part(f, &kgoal)) |
1526 | return -1; |
||
99 | terminx | 1527 | |
3153 | helixhorne | 1528 | Bmemcpy(ptr, lzwrawbuf, (int32_t)dasizeof); |
99 | terminx | 1529 | |
4837 | helixhorne | 1530 | uint32_t k = (int32_t)dasizeof; |
1531 | |||
1532 | for (uint32_t i=1; i<count; i++) |
||
109 | terminx | 1533 | { |
1534 | if (k >= kgoal) |
||
1535 | { |
||
3879 | helixhorne | 1536 | k = decompress_part(f, &kgoal); |
3153 | helixhorne | 1537 | if (k) return -1; |
109 | terminx | 1538 | } |
2368 | helixhorne | 1539 | |
4837 | helixhorne | 1540 | uint32_t j = 0; |
4665 | terminx | 1541 | |
1542 | if (dasizeof >= 4) |
||
1543 | { |
||
1544 | for (; j<dasizeof-4; j+=4) |
||
1545 | { |
||
4837 | helixhorne | 1546 | ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255); |
1547 | ptr[j+1+dasizeof] = ((ptr[j+1]+lzwrawbuf[j+1+k])&255); |
||
1548 | ptr[j+2+dasizeof] = ((ptr[j+2]+lzwrawbuf[j+2+k])&255); |
||
1549 | ptr[j+3+dasizeof] = ((ptr[j+3]+lzwrawbuf[j+3+k])&255); |
||
4665 | terminx | 1550 | } |
1551 | } |
||
1552 | |||
1553 | for (; j<dasizeof; j++) |
||
2368 | helixhorne | 1554 | ptr[j+dasizeof] = ((ptr[j]+lzwrawbuf[j+k])&255); |
1555 | |||
109 | terminx | 1556 | k += dasizeof; |
1557 | ptr += dasizeof; |
||
1558 | } |
||
2366 | helixhorne | 1559 | |
109 | terminx | 1560 | return count; |
99 | terminx | 1561 | } |
1562 | |||
3153 | helixhorne | 1563 | int32_t kdfread(void *buffer, bsize_t dasizeof, bsize_t count, int32_t fil) |
2369 | helixhorne | 1564 | { |
3153 | helixhorne | 1565 | return c1d_read_compressed(buffer, dasizeof, count, (intptr_t)fil); |
1566 | } |
||
2369 | helixhorne | 1567 | |
1568 | |||
3153 | helixhorne | 1569 | ////////// COMPRESSED WRITE ////////// |
1570 | |||
1571 | static uint32_t compress_part(uint32_t k, intptr_t f) |
||
1572 | { |
||
3879 | helixhorne | 1573 | const int16_t leng = (int16_t)lzwcompress(lzwrawbuf, k, lzwcompbuf); |
1574 | const int16_t swleng = B_LITTLE16(leng); |
||
1575 | |||
3153 | helixhorne | 1576 | c1d_writefunc(f, &swleng, 2); |
1577 | c1d_writefunc(f, lzwcompbuf, leng); |
||
3879 | helixhorne | 1578 | |
2369 | helixhorne | 1579 | return 0; |
1580 | } |
||
1581 | |||
3153 | helixhorne | 1582 | // Write from 'buffer' to 'f'. |
1583 | C1D_STATIC void c1d_write_compressed(const void *buffer, bsize_t dasizeof, bsize_t count, intptr_t f) |
||
99 | terminx | 1584 | { |
4665 | terminx | 1585 | const char *ptr = (char*)buffer; |
99 | terminx | 1586 | |
4838 | helixhorne | 1587 | if (dasizeof > LZWSIZE) |
2369 | helixhorne | 1588 | { |
4838 | helixhorne | 1589 | count *= dasizeof; |
1590 | dasizeof = 1; |
||
2369 | helixhorne | 1591 | } |
1592 | |||
1593 | Bmemcpy(lzwrawbuf, ptr, (int32_t)dasizeof); |
||
1594 | |||
4837 | helixhorne | 1595 | uint32_t k = dasizeof; |
109 | terminx | 1596 | if (k > LZWSIZE-dasizeof) |
3153 | helixhorne | 1597 | k = compress_part(k, f); |
99 | terminx | 1598 | |
4837 | helixhorne | 1599 | for (uint32_t i=1; i<count; i++) |
109 | terminx | 1600 | { |
4837 | helixhorne | 1601 | uint32_t j = 0; |
4665 | terminx | 1602 | |
1603 | if (dasizeof >= 4) |
||
1604 | { |
||
1605 | for (; j<dasizeof-4; j+=4) |
||
1606 | { |
||
4837 | helixhorne | 1607 | lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255); |
1608 | lzwrawbuf[j+1+k] = ((ptr[j+1+dasizeof]-ptr[j+1])&255); |
||
1609 | lzwrawbuf[j+2+k] = ((ptr[j+2+dasizeof]-ptr[j+2])&255); |
||
1610 | lzwrawbuf[j+3+k] = ((ptr[j+3+dasizeof]-ptr[j+3])&255); |
||
4665 | terminx | 1611 | } |
1612 | } |
||
1613 | |||
1614 | for (; j<dasizeof; j++) |
||
2368 | helixhorne | 1615 | lzwrawbuf[j+k] = ((ptr[j+dasizeof]-ptr[j])&255); |
2369 | helixhorne | 1616 | |
109 | terminx | 1617 | k += dasizeof; |
1618 | if (k > LZWSIZE-dasizeof) |
||
3153 | helixhorne | 1619 | k = compress_part(k, f); |
2369 | helixhorne | 1620 | |
109 | terminx | 1621 | ptr += dasizeof; |
1622 | } |
||
2369 | helixhorne | 1623 | |
109 | terminx | 1624 | if (k > 0) |
3153 | helixhorne | 1625 | compress_part(k, f); |
99 | terminx | 1626 | } |
1627 | |||
3153 | helixhorne | 1628 | void dfwrite(const void *buffer, bsize_t dasizeof, bsize_t count, BFILE *fil) |
1629 | { |
||
1630 | c1d_write_compressed(buffer, dasizeof, count, (intptr_t)fil); |
||
1631 | } |
||
1632 | |||
1633 | ////////// CORE COMPRESSION FUNCTIONS ////////// |
||
1634 | |||
2361 | helixhorne | 1635 | static int32_t lzwcompress(const char *lzwinbuf, int32_t uncompleng, char *lzwoutbuf) |
99 | terminx | 1636 | { |
2369 | helixhorne | 1637 | int32_t i, addr, addrcnt, *intptr; |
1205 | terminx | 1638 | int32_t bytecnt1, bitcnt, numbits, oneupnumbits; |
1639 | int16_t *shortptr; |
||
99 | terminx | 1640 | |
2369 | helixhorne | 1641 | int16_t *const lzwcodehead = lzwbuf2; |
1642 | int16_t *const lzwcodenext = lzwbuf3; |
||
1643 | |||
4665 | terminx | 1644 | for (i=255; i>=4; i-=4) |
2368 | helixhorne | 1645 | { |
4665 | terminx | 1646 | lzwtmpbuf[i] = i, lzwcodenext[i] = (i+1)&255; |
1647 | lzwtmpbuf[i-1] = i-1, lzwcodenext[i-1] = (i) &255; |
||
1648 | lzwtmpbuf[i-2] = i-2, lzwcodenext[i-2] = (i-1)&255; |
||
1649 | lzwtmpbuf[i-3] = i-3, lzwcodenext[i-3] = (i-2)&255; |
||
1650 | lzwcodehead[i] = lzwcodehead[i-1] = lzwcodehead[i-2] = lzwcodehead[i-3] = -1; |
||
1651 | } |
||
1652 | |||
1653 | for (; i>=0; i--) |
||
1654 | { |
||
2368 | helixhorne | 1655 | lzwtmpbuf[i] = i; |
2369 | helixhorne | 1656 | lzwcodenext[i] = (i+1)&255; |
1657 | lzwcodehead[i] = -1; |
||
2368 | helixhorne | 1658 | } |
1659 | |||
2369 | helixhorne | 1660 | Bmemset(lzwoutbuf, 0, 4+uncompleng+1); |
1661 | // clearbuf(lzwoutbuf,((uncompleng+15)+3)>>2,0L); |
||
99 | terminx | 1662 | |
109 | terminx | 1663 | addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3); |
1664 | numbits = 8; oneupnumbits = (1<<8); |
||
1665 | do |
||
1666 | { |
||
1667 | addr = lzwinbuf[bytecnt1]; |
||
1668 | do |
||
1669 | { |
||
2369 | helixhorne | 1670 | int32_t newaddr; |
1671 | |||
4665 | terminx | 1672 | if (++bytecnt1 == uncompleng) |
2369 | helixhorne | 1673 | break; // (*) see XXX below |
2368 | helixhorne | 1674 | |
2369 | helixhorne | 1675 | if (lzwcodehead[addr] < 0) |
1676 | { |
||
1677 | lzwcodehead[addr] = addrcnt; |
||
1678 | break; |
||
1679 | } |
||
2368 | helixhorne | 1680 | |
2369 | helixhorne | 1681 | newaddr = lzwcodehead[addr]; |
2367 | helixhorne | 1682 | while (lzwtmpbuf[newaddr] != lzwinbuf[bytecnt1]) |
109 | terminx | 1683 | { |
2369 | helixhorne | 1684 | if (lzwcodenext[newaddr] < 0) |
1685 | { |
||
1686 | lzwcodenext[newaddr] = addrcnt; |
||
1687 | break; |
||
1688 | } |
||
1689 | newaddr = lzwcodenext[newaddr]; |
||
109 | terminx | 1690 | } |
2368 | helixhorne | 1691 | |
2369 | helixhorne | 1692 | if (lzwcodenext[newaddr] == addrcnt) |
1693 | break; |
||
109 | terminx | 1694 | addr = newaddr; |
584 | terminx | 1695 | } |
1696 | while (addr >= 0); |
||
2368 | helixhorne | 1697 | |
2369 | helixhorne | 1698 | lzwtmpbuf[addrcnt] = lzwinbuf[bytecnt1]; // XXX: potential oob access of lzwinbuf via (*) above |
1699 | lzwcodehead[addrcnt] = -1; |
||
1700 | lzwcodenext[addrcnt] = -1; |
||
99 | terminx | 1701 | |
1205 | terminx | 1702 | intptr = (int32_t *)&lzwoutbuf[bitcnt>>3]; |
109 | terminx | 1703 | intptr[0] |= B_LITTLE32(addr<<(bitcnt&7)); |
1704 | bitcnt += numbits; |
||
1705 | if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1))) |
||
1706 | bitcnt--; |
||
99 | terminx | 1707 | |
109 | terminx | 1708 | addrcnt++; |
2368 | helixhorne | 1709 | if (addrcnt > oneupnumbits) |
1710 | { numbits++; oneupnumbits <<= 1; } |
||
584 | terminx | 1711 | } |
1712 | while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3))); |
||
99 | terminx | 1713 | |
1205 | terminx | 1714 | intptr = (int32_t *)&lzwoutbuf[bitcnt>>3]; |
109 | terminx | 1715 | intptr[0] |= B_LITTLE32(addr<<(bitcnt&7)); |
1716 | bitcnt += numbits; |
||
1717 | if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1))) |
||
1718 | bitcnt--; |
||
99 | terminx | 1719 | |
1205 | terminx | 1720 | shortptr = (int16_t *)lzwoutbuf; |
1721 | shortptr[0] = B_LITTLE16((int16_t)uncompleng); |
||
3879 | helixhorne | 1722 | |
109 | terminx | 1723 | if (((bitcnt+7)>>3) < uncompleng) |
1724 | { |
||
1205 | terminx | 1725 | shortptr[1] = B_LITTLE16((int16_t)addrcnt); |
3879 | helixhorne | 1726 | return (bitcnt+7)>>3; |
109 | terminx | 1727 | } |
2368 | helixhorne | 1728 | |
3879 | helixhorne | 1729 | // Failed compressing, mark this in the stream. |
2368 | helixhorne | 1730 | shortptr[1] = 0; |
4665 | terminx | 1731 | |
1732 | for (i=0; i<uncompleng-4; i+=4) |
||
1733 | { |
||
2368 | helixhorne | 1734 | lzwoutbuf[i+4] = lzwinbuf[i]; |
4665 | terminx | 1735 | lzwoutbuf[i+5] = lzwinbuf[i+1]; |
1736 | lzwoutbuf[i+6] = lzwinbuf[i+2]; |
||
1737 | lzwoutbuf[i+7] = lzwinbuf[i+3]; |
||
1738 | } |
||
2368 | helixhorne | 1739 | |
4665 | terminx | 1740 | for (; i<uncompleng; i++) |
1741 | lzwoutbuf[i+4] = lzwinbuf[i]; |
||
1742 | |||
3879 | helixhorne | 1743 | return uncompleng+4; |
99 | terminx | 1744 | } |
1745 | |||
2361 | helixhorne | 1746 | static int32_t lzwuncompress(const char *lzwinbuf, int32_t compleng, char *lzwoutbuf) |
99 | terminx | 1747 | { |
2368 | helixhorne | 1748 | int32_t currstr, numbits, oneupnumbits; |
3879 | helixhorne | 1749 | int32_t i, bitcnt, outbytecnt; |
99 | terminx | 1750 | |
2368 | helixhorne | 1751 | const int16_t *const shortptr = (const int16_t *)lzwinbuf; |
1752 | const int32_t strtot = B_LITTLE16(shortptr[1]); |
||
1753 | const int32_t uncompleng = B_LITTLE16(shortptr[0]); |
||
1754 | |||
109 | terminx | 1755 | if (strtot == 0) |
1756 | { |
||
3879 | helixhorne | 1757 | if (lzwoutbuf==lzwrawbuf && lzwinbuf==lzwcompbuf) |
1758 | { |
||
1759 | Bassert((compleng-4)+3+0u < sizeof(lzwrawbuf)); |
||
1760 | Bassert((compleng-4)+3+0u < sizeof(lzwcompbuf)-4); |
||
1761 | } |
||
1762 | |||
3153 | helixhorne | 1763 | Bmemcpy(lzwoutbuf, lzwinbuf+4, (compleng-4)+3); |
2368 | helixhorne | 1764 | return uncompleng; |
109 | terminx | 1765 | } |
2368 | helixhorne | 1766 | |
4665 | terminx | 1767 | for (i=255; i>=4; i-=4) |
2368 | helixhorne | 1768 | { |
4665 | terminx | 1769 | lzwbuf2[i] = lzwbuf3[i] = i; |
1770 | lzwbuf2[i-1] = lzwbuf3[i-1] = i-1; |
||
1771 | lzwbuf2[i-2] = lzwbuf3[i-2] = i-2; |
||
1772 | lzwbuf2[i-3] = lzwbuf3[i-3] = i-3; |
||
2368 | helixhorne | 1773 | } |
1774 | |||
4665 | terminx | 1775 | lzwbuf2[i] = lzwbuf3[i] = i; |
1776 | lzwbuf2[i-1] = lzwbuf3[i-1] = i-1; |
||
1777 | lzwbuf2[i-2] = lzwbuf3[i-2] = i-2; |
||
1778 | |||
109 | terminx | 1779 | currstr = 256; bitcnt = (4<<3); outbytecnt = 0; |
1780 | numbits = 8; oneupnumbits = (1<<8); |
||
1781 | do |
||
1782 | { |
||
2368 | helixhorne | 1783 | const int32_t *const intptr = (const int32_t *)&lzwinbuf[bitcnt>>3]; |
1784 | |||
3879 | helixhorne | 1785 | int32_t dat = ((B_LITTLE32(intptr[0])>>(bitcnt&7)) & (oneupnumbits-1)); |
1786 | int32_t leng; |
||
1787 | |||
109 | terminx | 1788 | bitcnt += numbits; |
1789 | if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1))) |
||
584 | terminx | 1790 | { dat &= ((oneupnumbits>>1)-1); bitcnt--; } |
99 | terminx | 1791 | |
109 | terminx | 1792 | lzwbuf3[currstr] = dat; |
99 | terminx | 1793 | |
1229 | terminx | 1794 | for (leng=0; dat>=256; leng++,dat=lzwbuf3[dat]) |
2367 | helixhorne | 1795 | lzwtmpbuf[leng] = lzwbuf2[dat]; |
99 | terminx | 1796 | |
109 | terminx | 1797 | lzwoutbuf[outbytecnt++] = dat; |
4665 | terminx | 1798 | |
1799 | for (i=leng-1; i>=4; i-=4, outbytecnt+=4) |
||
1800 | { |
||
1801 | lzwoutbuf[outbytecnt] = lzwtmpbuf[i]; |
||
1802 | lzwoutbuf[outbytecnt+1] = lzwtmpbuf[i-1]; |
||
1803 | lzwoutbuf[outbytecnt+2] = lzwtmpbuf[i-2]; |
||
1804 | lzwoutbuf[outbytecnt+3] = lzwtmpbuf[i-3]; |
||
1805 | } |
||
1806 | |||
1807 | for (; i>=0; i--) |
||
2368 | helixhorne | 1808 | lzwoutbuf[outbytecnt++] = lzwtmpbuf[i]; |
99 | terminx | 1809 | |
109 | terminx | 1810 | lzwbuf2[currstr-1] = dat; lzwbuf2[currstr] = dat; |
1811 | currstr++; |
||
2368 | helixhorne | 1812 | if (currstr > oneupnumbits) |
1813 | { numbits++; oneupnumbits <<= 1; } |
||
584 | terminx | 1814 | } |
1815 | while (currstr < strtot); |
||
2368 | helixhorne | 1816 | |
1817 | return uncompleng; |
||
99 | terminx | 1818 | } |
1819 | |||
1820 | /* |
||
1821 | * vim:ts=4:sw=4: |
||
1822 | */ |