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