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