1 | /* $Id: lz32.cpp,v 1.9 2000-06-13 06:40:41 phaller Exp $ */
|
---|
2 |
|
---|
3 | /*
|
---|
4 | * Project Odin Software License can be found in LICENSE.TXT
|
---|
5 | *
|
---|
6 | * LZ Decompression functions
|
---|
7 | *
|
---|
8 | * Copyright 1996 Marcus Meissner
|
---|
9 | * Copyright 1999 Patrick Haller
|
---|
10 | *
|
---|
11 | * FIXME: return values might be wrong
|
---|
12 | */
|
---|
13 |
|
---|
14 | #include <string.h>
|
---|
15 | #include <ctype.h>
|
---|
16 | #include <odin.h>
|
---|
17 | #include <os2sel.h>
|
---|
18 | #include <odinwrap.h>
|
---|
19 | #include <windef.h>
|
---|
20 | #include <winbase.h>
|
---|
21 | #include <heap.h>
|
---|
22 | #include <heapstring.h>
|
---|
23 | #include <lz32.h>
|
---|
24 | #include "debugtools.h"
|
---|
25 | #include <misc.h>
|
---|
26 |
|
---|
27 | ODINDEBUGCHANNEL(LZ32)
|
---|
28 |
|
---|
29 | #define SystemHeap GetProcessHeap()
|
---|
30 |
|
---|
31 |
|
---|
32 | /****************************************************************************
|
---|
33 | * Defines *
|
---|
34 | ****************************************************************************/
|
---|
35 |
|
---|
36 | /* The readahead length of the decompressor. Reading single bytes
|
---|
37 | * using _lread() would be SLOW.
|
---|
38 | */
|
---|
39 | #define GETLEN 2048
|
---|
40 |
|
---|
41 |
|
---|
42 | /****************************************************************************
|
---|
43 | * Structures *
|
---|
44 | ****************************************************************************/
|
---|
45 |
|
---|
46 | /* Format of first 14 byte of LZ compressed file */
|
---|
47 | struct lzfileheader {
|
---|
48 | BYTE magic[8];
|
---|
49 | BYTE compressiontype;
|
---|
50 | CHAR lastchar;
|
---|
51 | DWORD reallength;
|
---|
52 | };
|
---|
53 | static BYTE LZMagic[8]={'S','Z','D','D',0x88,0xf0,0x27,0x33};
|
---|
54 |
|
---|
55 | struct lzstate {
|
---|
56 | HFILE realfd; /* the real filedescriptor */
|
---|
57 | CHAR lastchar; /* the last char of the filename */
|
---|
58 |
|
---|
59 | DWORD reallength; /* the decompressed length of the file */
|
---|
60 | DWORD realcurrent; /* the position the decompressor currently is */
|
---|
61 | DWORD realwanted; /* the position the user wants to read from */
|
---|
62 |
|
---|
63 | BYTE table[0x1000]; /* the rotating LZ table */
|
---|
64 | UINT curtabent; /* CURrent TABle ENTry */
|
---|
65 |
|
---|
66 | BYTE stringlen; /* length and position of current string */
|
---|
67 | DWORD stringpos; /* from stringtable */
|
---|
68 |
|
---|
69 |
|
---|
70 | WORD bytetype; /* bitmask within blocks */
|
---|
71 |
|
---|
72 | BYTE *get; /* GETLEN bytes */
|
---|
73 | DWORD getcur; /* current read */
|
---|
74 | DWORD getlen; /* length last got */
|
---|
75 | };
|
---|
76 |
|
---|
77 | #define MAX_LZSTATES 16
|
---|
78 | static struct lzstate *lzstates[MAX_LZSTATES];
|
---|
79 |
|
---|
80 | #define IS_LZ_HANDLE(h) (((h) >= 0x400) && ((h) < 0x400+MAX_LZSTATES))
|
---|
81 | #define GET_LZ_STATE(h) (IS_LZ_HANDLE(h) ? lzstates[(h)-0x400] : NULL)
|
---|
82 |
|
---|
83 | /* reads one compressed byte, including buffering */
|
---|
84 | #define GET(lzs,b) _lzget(lzs,&b)
|
---|
85 | #define GET_FLUSH(lzs) lzs->getcur=lzs->getlen;
|
---|
86 |
|
---|
87 |
|
---|
88 | /****************************************************************************
|
---|
89 | * Internal Prototypes *
|
---|
90 | ****************************************************************************/
|
---|
91 |
|
---|
92 | static int _lzget(struct lzstate *lzs,BYTE *b);
|
---|
93 | static INT read_header(HFILE fd,struct lzfileheader *head);
|
---|
94 |
|
---|
95 |
|
---|
96 | /****************************************************************************
|
---|
97 | * Implementation *
|
---|
98 | ****************************************************************************/
|
---|
99 |
|
---|
100 | static int _lzget(struct lzstate *lzs,BYTE *b)
|
---|
101 | {
|
---|
102 | if (lzs->getcur<lzs->getlen) {
|
---|
103 | *b = lzs->get[lzs->getcur++];
|
---|
104 | return 1;
|
---|
105 | } else {
|
---|
106 | int ret = _lread(lzs->realfd,lzs->get,GETLEN);
|
---|
107 | if (ret==HFILE_ERROR)
|
---|
108 | return HFILE_ERROR;
|
---|
109 | if (ret==0)
|
---|
110 | return 0;
|
---|
111 | lzs->getlen = ret;
|
---|
112 | lzs->getcur = 1;
|
---|
113 | *b = *(lzs->get);
|
---|
114 | return 1;
|
---|
115 | }
|
---|
116 | }
|
---|
117 |
|
---|
118 |
|
---|
119 | /* internal function, reads lzheader
|
---|
120 | * returns BADINHANDLE for non filedescriptors
|
---|
121 | * return 0 for file not compressed using LZ
|
---|
122 | * return UNKNOWNALG for unknown algorithm
|
---|
123 | * returns lzfileheader in *head
|
---|
124 | */
|
---|
125 | static INT read_header(HFILE fd,struct lzfileheader *head)
|
---|
126 | {
|
---|
127 | BYTE buf[14];
|
---|
128 |
|
---|
129 | if (_llseek(fd,0,SEEK_SET)==-1)
|
---|
130 | return LZERROR_BADINHANDLE;
|
---|
131 |
|
---|
132 | /* We can't directly read the lzfileheader struct due to
|
---|
133 | * structure element alignment
|
---|
134 | */
|
---|
135 | if (_lread(fd,buf,14)<14)
|
---|
136 | return 0;
|
---|
137 | memcpy(head->magic,buf,8);
|
---|
138 | memcpy(&(head->compressiontype),buf+8,1);
|
---|
139 | memcpy(&(head->lastchar),buf+9,1);
|
---|
140 |
|
---|
141 | /* FIXME: consider endianess on non-intel architectures */
|
---|
142 | memcpy(&(head->reallength),buf+10,4);
|
---|
143 |
|
---|
144 | if (memcmp(head->magic,LZMagic,8))
|
---|
145 | return 0;
|
---|
146 | if (head->compressiontype!='A')
|
---|
147 | return LZERROR_UNKNOWNALG;
|
---|
148 | return 1;
|
---|
149 | }
|
---|
150 |
|
---|
151 |
|
---|
152 | /***********************************************************************
|
---|
153 | * LZStart32 (LZ32.6)
|
---|
154 | */
|
---|
155 |
|
---|
156 | ODINFUNCTION0(INT,LZStart)
|
---|
157 | {
|
---|
158 | dprintf(("LZ32: LZStart32()\n"));
|
---|
159 | return 1;
|
---|
160 | }
|
---|
161 |
|
---|
162 |
|
---|
163 | /***********************************************************************
|
---|
164 | * LZInit32 (LZ32.2)
|
---|
165 | *
|
---|
166 | * initializes internal decompression buffers, returns lzfiledescriptor.
|
---|
167 | * (return value the same as hfSrc, if hfSrc is not compressed)
|
---|
168 | * on failure, returns error code <0
|
---|
169 | * lzfiledescriptors range from 0x400 to 0x410 (only 16 open files per process)
|
---|
170 | *
|
---|
171 | * since _llseek uses the same types as libc.lseek, we just use the macros of
|
---|
172 | * libc
|
---|
173 | */
|
---|
174 | ODINFUNCTION1(HFILE,LZInit,HFILE,hfSrc)
|
---|
175 | {
|
---|
176 | struct lzfileheader head;
|
---|
177 | struct lzstate *lzs;
|
---|
178 | DWORD ret;
|
---|
179 | int i;
|
---|
180 |
|
---|
181 | dprintf(("LZ32: LZInit(%08xh)\n",
|
---|
182 | hfSrc));
|
---|
183 |
|
---|
184 | ret=read_header(hfSrc,&head);
|
---|
185 | if (ret<=0) {
|
---|
186 | _llseek(hfSrc,0,SEEK_SET);
|
---|
187 | return ret?ret:hfSrc;
|
---|
188 | }
|
---|
189 | for (i = 0; i < MAX_LZSTATES; i++) if (!lzstates[i]) break;
|
---|
190 | if (i == MAX_LZSTATES) return LZERROR_GLOBALLOC;
|
---|
191 |
|
---|
192 | lzstates[i] = lzs = (lzstate*)HeapAlloc( GetProcessHeap(), 0, sizeof(struct lzstate) );
|
---|
193 | if (lzs == NULL) return LZERROR_GLOBALLOC;
|
---|
194 |
|
---|
195 | memset(lzs,'\0',sizeof(*lzs));
|
---|
196 | lzs->realfd = hfSrc;
|
---|
197 | lzs->lastchar = head.lastchar;
|
---|
198 | lzs->reallength = head.reallength;
|
---|
199 |
|
---|
200 | lzs->get = (BYTE*)HeapAlloc( GetProcessHeap(), 0, GETLEN );
|
---|
201 | lzs->getlen = 0;
|
---|
202 | lzs->getcur = 0;
|
---|
203 |
|
---|
204 | if (lzs->get == NULL) {
|
---|
205 | HeapFree(GetProcessHeap(), 0, lzs);
|
---|
206 | lzstates[i] = NULL;
|
---|
207 | return LZERROR_GLOBALLOC;
|
---|
208 | }
|
---|
209 |
|
---|
210 | /* Yes, preinitialize with spaces */
|
---|
211 | memset(lzs->table,' ',0x1000);
|
---|
212 | /* Yes, start 16 byte from the END of the table */
|
---|
213 | lzs->curtabent = 0xff0;
|
---|
214 | return 0x400 + i;
|
---|
215 | }
|
---|
216 |
|
---|
217 |
|
---|
218 | /***********************************************************************
|
---|
219 | * LZDone (LZEXPAND.9) (LZ32.8)
|
---|
220 | */
|
---|
221 | ODINPROCEDURE0(LZDone)
|
---|
222 | {
|
---|
223 | TRACE("(void)\n");
|
---|
224 | }
|
---|
225 |
|
---|
226 | /***********************************************************************
|
---|
227 | * GetExpandedName32A (LZ32.9)
|
---|
228 | *
|
---|
229 | * gets the full filename of the compressed file 'in' by opening it
|
---|
230 | * and reading the header
|
---|
231 | *
|
---|
232 | * "file." is being translated to "file"
|
---|
233 | * "file.bl_" (with lastchar 'a') is being translated to "file.bla"
|
---|
234 | * "FILE.BL_" (with lastchar 'a') is being translated to "FILE.BLA"
|
---|
235 | */
|
---|
236 |
|
---|
237 | ODINFUNCTION2(INT,GetExpandedNameA,LPCSTR,in,LPSTR,out)
|
---|
238 | {
|
---|
239 | struct lzfileheader head;
|
---|
240 | HFILE fd;
|
---|
241 | OFSTRUCT ofs;
|
---|
242 | INT fnislowercased,ret,len;
|
---|
243 | LPSTR s,t;
|
---|
244 |
|
---|
245 | dprintf(("LZ32: GetExpandedNameA(%s,%08xh)\n",
|
---|
246 | in,
|
---|
247 | out));
|
---|
248 |
|
---|
249 | fd=OpenFile(in,&ofs,OF_READ);
|
---|
250 | if (fd==HFILE_ERROR)
|
---|
251 | return (INT)(INT16)LZERROR_BADINHANDLE;
|
---|
252 | strcpy(out,in);
|
---|
253 | ret=read_header(fd,&head);
|
---|
254 | if (ret<=0) {
|
---|
255 | /* not a LZ compressed file, so the expanded name is the same
|
---|
256 | * as the input name */
|
---|
257 | _lclose(fd);
|
---|
258 | return 1;
|
---|
259 | }
|
---|
260 |
|
---|
261 |
|
---|
262 | /* look for directory prefix and skip it. */
|
---|
263 | s=out;
|
---|
264 | while (NULL!=(t=strpbrk(s,"/\\:")))
|
---|
265 | s=t+1;
|
---|
266 |
|
---|
267 | /* now mangle the basename */
|
---|
268 | if (!*s) {
|
---|
269 | /* FIXME: hmm. shouldn't happen? */
|
---|
270 | WARN("Specified a directory or what? (%s)\n",in);
|
---|
271 | _lclose(fd);
|
---|
272 | return 1;
|
---|
273 | }
|
---|
274 | /* see if we should use lowercase or uppercase on the last char */
|
---|
275 | fnislowercased=1;
|
---|
276 | t=s+strlen(s)-1;
|
---|
277 | while (t>=out) {
|
---|
278 | if (!isalpha(*t)) {
|
---|
279 | t--;
|
---|
280 | continue;
|
---|
281 | }
|
---|
282 | fnislowercased=islower(*t);
|
---|
283 | break;
|
---|
284 | }
|
---|
285 | if (isalpha(head.lastchar)) {
|
---|
286 | if (fnislowercased)
|
---|
287 | head.lastchar=tolower(head.lastchar);
|
---|
288 | else
|
---|
289 | head.lastchar=toupper(head.lastchar);
|
---|
290 | }
|
---|
291 |
|
---|
292 | /* now look where to replace the last character */
|
---|
293 | if (NULL!=(t=strchr(s,'.'))) {
|
---|
294 | if (t[1]=='\0') {
|
---|
295 | t[0]='\0';
|
---|
296 | } else {
|
---|
297 | len=strlen(t)-1;
|
---|
298 | if (t[len]=='_')
|
---|
299 | t[len]=head.lastchar;
|
---|
300 | }
|
---|
301 | } /* else no modification necessary */
|
---|
302 | _lclose(fd);
|
---|
303 | return 1;
|
---|
304 | }
|
---|
305 |
|
---|
306 |
|
---|
307 | /***********************************************************************
|
---|
308 | * GetExpandedName32W (LZ32.11)
|
---|
309 | */
|
---|
310 | ODINFUNCTION2(INT,GetExpandedNameW,LPCWSTR,in,LPWSTR,out)
|
---|
311 | {
|
---|
312 | char *xin,*xout;
|
---|
313 | INT ret;
|
---|
314 |
|
---|
315 | dprintf(("LZ32: GetExpandedNameW(%08xh,%08xh)\n",
|
---|
316 | in,
|
---|
317 | out));
|
---|
318 |
|
---|
319 | xout = (char*)HeapAlloc( GetProcessHeap(), 0, lstrlenW(in)+3 );
|
---|
320 | xin = HEAP_strdupWtoA( GetProcessHeap(), 0, in );
|
---|
321 | ret = GetExpandedNameA(xin,xout);
|
---|
322 | if (ret>0) lstrcpyAtoW(out,xout);
|
---|
323 | HeapFree( GetProcessHeap(), 0, xin );
|
---|
324 | HeapFree( GetProcessHeap(), 0, xout );
|
---|
325 | return ret;
|
---|
326 | }
|
---|
327 |
|
---|
328 |
|
---|
329 | /***********************************************************************
|
---|
330 | * LZRead32 (LZ32.4)
|
---|
331 | */
|
---|
332 | ODINFUNCTION3(INT,LZRead,HFILE,fd,LPVOID,vbuf,UINT,toread)
|
---|
333 | {
|
---|
334 | int howmuch;
|
---|
335 | BYTE b,*buf;
|
---|
336 | struct lzstate *lzs;
|
---|
337 |
|
---|
338 | dprintf(("LZ32: LZRead(%08xh,%08xh,%08h)\n",
|
---|
339 | fd,
|
---|
340 | vbuf,
|
---|
341 | toread));
|
---|
342 |
|
---|
343 | buf=(LPBYTE)vbuf;
|
---|
344 | howmuch=toread;
|
---|
345 | if (!(lzs = GET_LZ_STATE(fd))) return _lread(fd,buf,toread);
|
---|
346 |
|
---|
347 | /* The decompressor itself is in a define, cause we need it twice
|
---|
348 | * in this function. (the decompressed byte will be in b)
|
---|
349 | */
|
---|
350 | #define DECOMPRESS_ONE_BYTE \
|
---|
351 | if (lzs->stringlen) { \
|
---|
352 | b = lzs->table[lzs->stringpos]; \
|
---|
353 | lzs->stringpos = (lzs->stringpos+1)&0xFFF; \
|
---|
354 | lzs->stringlen--; \
|
---|
355 | } else { \
|
---|
356 | if (!(lzs->bytetype&0x100)) { \
|
---|
357 | if (1!=GET(lzs,b)) \
|
---|
358 | return toread-howmuch; \
|
---|
359 | lzs->bytetype = b|0xFF00; \
|
---|
360 | } \
|
---|
361 | if (lzs->bytetype & 1) { \
|
---|
362 | if (1!=GET(lzs,b)) \
|
---|
363 | return toread-howmuch; \
|
---|
364 | } else { \
|
---|
365 | BYTE b1,b2; \
|
---|
366 | \
|
---|
367 | if (1!=GET(lzs,b1)) \
|
---|
368 | return toread-howmuch; \
|
---|
369 | if (1!=GET(lzs,b2)) \
|
---|
370 | return toread-howmuch; \
|
---|
371 | /* Format: \
|
---|
372 | * b1 b2 \
|
---|
373 | * AB CD \
|
---|
374 | * where CAB is the stringoffset in the table\
|
---|
375 | * and D+3 is the len of the string \
|
---|
376 | */ \
|
---|
377 | lzs->stringpos = b1|((b2&0xf0)<<4); \
|
---|
378 | lzs->stringlen = (b2&0xf)+2; \
|
---|
379 | /* 3, but we use a byte already below ... */\
|
---|
380 | b = lzs->table[lzs->stringpos];\
|
---|
381 | lzs->stringpos = (lzs->stringpos+1)&0xFFF;\
|
---|
382 | } \
|
---|
383 | lzs->bytetype>>=1; \
|
---|
384 | } \
|
---|
385 | /* store b in table */ \
|
---|
386 | lzs->table[lzs->curtabent++]= b; \
|
---|
387 | lzs->curtabent &= 0xFFF; \
|
---|
388 | lzs->realcurrent++;
|
---|
389 |
|
---|
390 | /* if someone has seeked, we have to bring the decompressor
|
---|
391 | * to that position
|
---|
392 | */
|
---|
393 | if (lzs->realcurrent!=lzs->realwanted) {
|
---|
394 | /* if the wanted position is before the current position
|
---|
395 | * I see no easy way to unroll ... We have to restart at
|
---|
396 | * the beginning. *sigh*
|
---|
397 | */
|
---|
398 | if (lzs->realcurrent>lzs->realwanted) {
|
---|
399 | /* flush decompressor state */
|
---|
400 | _llseek(lzs->realfd,14,SEEK_SET);
|
---|
401 | GET_FLUSH(lzs);
|
---|
402 | lzs->realcurrent= 0;
|
---|
403 | lzs->bytetype = 0;
|
---|
404 | lzs->stringlen = 0;
|
---|
405 | memset(lzs->table,' ',0x1000);
|
---|
406 | lzs->curtabent = 0xFF0;
|
---|
407 | }
|
---|
408 | while (lzs->realcurrent<lzs->realwanted) {
|
---|
409 | DECOMPRESS_ONE_BYTE;
|
---|
410 | }
|
---|
411 | }
|
---|
412 |
|
---|
413 | while (howmuch) {
|
---|
414 | DECOMPRESS_ONE_BYTE;
|
---|
415 | lzs->realwanted++;
|
---|
416 | *buf++ = b;
|
---|
417 | howmuch--;
|
---|
418 | }
|
---|
419 | return toread;
|
---|
420 | #undef DECOMPRESS_ONE_BYTE
|
---|
421 | }
|
---|
422 |
|
---|
423 |
|
---|
424 | /***********************************************************************
|
---|
425 | * LZSeek32 (LZ32.3)
|
---|
426 | */
|
---|
427 |
|
---|
428 | ODINFUNCTION3(LONG,LZSeek,HFILE,fd,LONG,off,INT,type)
|
---|
429 | {
|
---|
430 | struct lzstate *lzs;
|
---|
431 | LONG newwanted;
|
---|
432 |
|
---|
433 | dprintf(("LZ32: LZSeek(%08xh,%08xh,%08xh)\n",
|
---|
434 | fd,
|
---|
435 | off,
|
---|
436 | type));
|
---|
437 |
|
---|
438 | /* not compressed? just use normal _llseek() */
|
---|
439 | if (!(lzs = GET_LZ_STATE(fd))) return _llseek(fd,off,type);
|
---|
440 | newwanted = lzs->realwanted;
|
---|
441 | switch (type) {
|
---|
442 | case 1: /* SEEK_CUR */
|
---|
443 | newwanted += off;
|
---|
444 | break;
|
---|
445 | case 2: /* SEEK_END */
|
---|
446 | newwanted = lzs->reallength-off;
|
---|
447 | break;
|
---|
448 | default:/* SEEK_SET */
|
---|
449 | newwanted = off;
|
---|
450 | break;
|
---|
451 | }
|
---|
452 | if (newwanted>lzs->reallength)
|
---|
453 | return LZERROR_BADVALUE;
|
---|
454 | if (newwanted<0)
|
---|
455 | return LZERROR_BADVALUE;
|
---|
456 | lzs->realwanted = newwanted;
|
---|
457 | return newwanted;
|
---|
458 | }
|
---|
459 |
|
---|
460 |
|
---|
461 | /***********************************************************************
|
---|
462 | * LZCopy32 (LZ32.0)
|
---|
463 | *
|
---|
464 | * Copies everything from src to dest
|
---|
465 | * if src is a LZ compressed file, it will be uncompressed.
|
---|
466 | * will return the number of bytes written to dest or errors.
|
---|
467 | */
|
---|
468 |
|
---|
469 | typedef UINT (WINAPI *_readfun)(HFILE,LPVOID,UINT);
|
---|
470 |
|
---|
471 | ODINFUNCTION2(LONG,LZCopy,HFILE,src,HFILE,dest)
|
---|
472 | {
|
---|
473 | int usedlzinit=0,ret,wret;
|
---|
474 | LONG len;
|
---|
475 | HFILE oldsrc = src;
|
---|
476 | #define BUFLEN 1000
|
---|
477 | BYTE buf[BUFLEN];
|
---|
478 | /* we need that weird typedef, for i can't seem to get function pointer
|
---|
479 | * casts right. (Or they probably just do not like WINAPI in general)
|
---|
480 | */
|
---|
481 | _readfun xread;
|
---|
482 |
|
---|
483 | dprintf(("LZ32: LZCopy(%08x,h%08xh)\n",
|
---|
484 | src,
|
---|
485 | dest));
|
---|
486 |
|
---|
487 | if (!IS_LZ_HANDLE(src)) {
|
---|
488 | src = LZInit(src);
|
---|
489 | if ((INT)src <= 0) return 0;
|
---|
490 | if (src != oldsrc) usedlzinit=1;
|
---|
491 | }
|
---|
492 |
|
---|
493 | /* not compressed? just copy */
|
---|
494 | if (!IS_LZ_HANDLE(src))
|
---|
495 | xread=_lread;
|
---|
496 | else
|
---|
497 | xread=(_readfun)LZRead;
|
---|
498 | len=0;
|
---|
499 | while (1) {
|
---|
500 | ret=xread(src,buf,BUFLEN);
|
---|
501 | if (ret<=0) {
|
---|
502 | if (ret==0)
|
---|
503 | break;
|
---|
504 | if (ret==-1)
|
---|
505 | return LZERROR_READ;
|
---|
506 | return ret;
|
---|
507 | }
|
---|
508 | len += ret;
|
---|
509 | wret = _lwrite(dest,(LPCSTR)buf,ret);
|
---|
510 | if (wret!=ret)
|
---|
511 | return LZERROR_WRITE;
|
---|
512 | }
|
---|
513 | if (usedlzinit)
|
---|
514 | LZClose(src);
|
---|
515 | return len;
|
---|
516 | #undef BUFLEN
|
---|
517 | }
|
---|
518 |
|
---|
519 | /* reverses GetExpandedPathname */
|
---|
520 | static LPSTR LZEXPAND_MangleName( LPCSTR fn )
|
---|
521 | {
|
---|
522 | char *p;
|
---|
523 | char *mfn = (char *)HeapAlloc( GetProcessHeap(), 0,
|
---|
524 | strlen(fn) + 3 ); /* "._" and \0 */
|
---|
525 | if (mfn == NULL) return NULL;
|
---|
526 | strcpy( mfn, fn );
|
---|
527 | if (!(p = strrchr( mfn, '\\' ))) p = mfn;
|
---|
528 | if ((p = strchr( p, '.' )) != NULL)
|
---|
529 | {
|
---|
530 | p++;
|
---|
531 | if (strlen(p) < 3) strcat( p, "_" ); /* append '_' */
|
---|
532 | else p[strlen(p)-1] = '_'; /* replace last character */
|
---|
533 | }
|
---|
534 | else strcat( mfn, "._" ); /* append "._" */
|
---|
535 | return mfn;
|
---|
536 | }
|
---|
537 |
|
---|
538 |
|
---|
539 | /***********************************************************************
|
---|
540 | * LZOpenFile32A (LZ32.1)
|
---|
541 | *
|
---|
542 | * Opens a file. If not compressed, open it as a normal file.
|
---|
543 | */
|
---|
544 |
|
---|
545 | ODINFUNCTION3(HFILE,LZOpenFileA,LPCSTR,fn,LPOFSTRUCT,ofs,UINT,mode)
|
---|
546 | {
|
---|
547 | HFILE fd,cfd;
|
---|
548 |
|
---|
549 | dprintf(("LZ32: LZOpenFileA(%s,%08xh,%08xh)\n",
|
---|
550 | fn,
|
---|
551 | ofs,
|
---|
552 | mode));
|
---|
553 |
|
---|
554 | /* 0x70 represents all OF_SHARE_* flags, ignore them for the check */
|
---|
555 | fd=OpenFile(fn,ofs,mode);
|
---|
556 | if (fd==HFILE_ERROR)
|
---|
557 | {
|
---|
558 | LPSTR mfn = LZEXPAND_MangleName(fn);
|
---|
559 | fd = OpenFile(mfn,ofs,mode);
|
---|
560 | HeapFree( GetProcessHeap(), 0, mfn );
|
---|
561 | }
|
---|
562 | if ((mode&~0x70)!=OF_READ)
|
---|
563 | return fd;
|
---|
564 | if (fd==HFILE_ERROR)
|
---|
565 | return HFILE_ERROR;
|
---|
566 | cfd=LZInit(fd);
|
---|
567 | if ((INT)cfd <= 0) return fd;
|
---|
568 | return cfd;
|
---|
569 | }
|
---|
570 |
|
---|
571 |
|
---|
572 | /***********************************************************************
|
---|
573 | * LZOpenFile32W (LZ32.10)
|
---|
574 | */
|
---|
575 | ODINFUNCTION3(HFILE,LZOpenFileW,LPCWSTR,fn,LPOFSTRUCT,ofs,UINT,mode)
|
---|
576 | {
|
---|
577 | LPSTR xfn;
|
---|
578 | LPWSTR yfn;
|
---|
579 | HFILE ret;
|
---|
580 |
|
---|
581 | dprintf(("LZ32: LZOpenFileW(%08xh,%08xh,%08xh)\n",
|
---|
582 | fn,
|
---|
583 | ofs,
|
---|
584 | mode));
|
---|
585 |
|
---|
586 | xfn = HEAP_strdupWtoA( GetProcessHeap(), 0, fn);
|
---|
587 | ret = LZOpenFileA(xfn,ofs,mode);
|
---|
588 | HeapFree( GetProcessHeap(), 0, xfn );
|
---|
589 | if (ret!=HFILE_ERROR) {
|
---|
590 | /* ofs->szPathName is an array with the OFSTRUCT */
|
---|
591 | yfn = HEAP_strdupAtoW( GetProcessHeap(), 0, (LPCSTR)ofs->szPathName );
|
---|
592 | memcpy(ofs->szPathName,yfn,lstrlenW(yfn)*2+2);
|
---|
593 | HeapFree( GetProcessHeap(), 0, yfn );
|
---|
594 | }
|
---|
595 | return ret;
|
---|
596 | }
|
---|
597 |
|
---|
598 |
|
---|
599 | /***********************************************************************
|
---|
600 | * LZClose32 (LZ32.5)
|
---|
601 | */
|
---|
602 |
|
---|
603 | ODINPROCEDURE1(LZClose,HFILE,fd)
|
---|
604 | {
|
---|
605 | struct lzstate *lzs;
|
---|
606 |
|
---|
607 | dprintf(("LZ32: LZClose(%08xh)\n",
|
---|
608 | fd));
|
---|
609 |
|
---|
610 | if (!(lzs = GET_LZ_STATE(fd))) _lclose(fd);
|
---|
611 | else
|
---|
612 | {
|
---|
613 | if (lzs->get) HeapFree( GetProcessHeap(), 0, lzs->get );
|
---|
614 | CloseHandle(lzs->realfd);
|
---|
615 | lzstates[fd - 0x400] = NULL;
|
---|
616 | HeapFree( GetProcessHeap(), 0, lzs );
|
---|
617 | }
|
---|
618 | }
|
---|
619 |
|
---|
620 |
|
---|
621 | /***********************************************************************
|
---|
622 | * CopyLZFile32 (LZ32.7)
|
---|
623 | *
|
---|
624 | * Copy src to dest (including uncompressing src).
|
---|
625 | * NOTE: Yes. This is exactly the same function as LZCopy.
|
---|
626 | */
|
---|
627 |
|
---|
628 | ODINFUNCTION2(LONG,CopyLZFile,HFILE,src,HFILE,dest)
|
---|
629 | {
|
---|
630 | dprintf(("LZ32: CopyLZFile(%08xh,%08xh)\n",
|
---|
631 | src,
|
---|
632 | dest));
|
---|
633 |
|
---|
634 | return LZCopy(src,dest);
|
---|
635 | }
|
---|