[3695] | 1 | /* $Id: lz32.cpp,v 1.9 2000-06-13 06:40:41 phaller Exp $ */
|
---|
[468] | 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>
|
---|
[484] | 16 | #include <odin.h>
|
---|
[537] | 17 | #include <os2sel.h>
|
---|
| 18 | #include <odinwrap.h>
|
---|
[468] | 19 | #include <windef.h>
|
---|
| 20 | #include <winbase.h>
|
---|
| 21 | #include <heap.h>
|
---|
| 22 | #include <heapstring.h>
|
---|
[21916] | 23 | #include "lz32.h"
|
---|
[468] | 24 | #include "debugtools.h"
|
---|
[2306] | 25 | #include <misc.h>
|
---|
[468] | 26 |
|
---|
[477] | 27 | ODINDEBUGCHANNEL(LZ32)
|
---|
| 28 |
|
---|
[468] | 29 | #define SystemHeap GetProcessHeap()
|
---|
| 30 |
|
---|
[474] | 31 |
|
---|
[468] | 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 | /****************************************************************************
|
---|
[474] | 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 | /****************************************************************************
|
---|
[468] | 97 | * Implementation *
|
---|
| 98 | ****************************************************************************/
|
---|
| 99 |
|
---|
[474] | 100 | static int _lzget(struct lzstate *lzs,BYTE *b)
|
---|
| 101 | {
|
---|
[468] | 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 | }
|
---|
[474] | 117 |
|
---|
| 118 |
|
---|
[468] | 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 | */
|
---|
[474] | 155 |
|
---|
| 156 | ODINFUNCTION0(INT,LZStart)
|
---|
[468] | 157 | {
|
---|
[474] | 158 | dprintf(("LZ32: LZStart32()\n"));
|
---|
| 159 | return 1;
|
---|
[468] | 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 | */
|
---|
[474] | 174 | ODINFUNCTION1(HFILE,LZInit,HFILE,hfSrc)
|
---|
[468] | 175 | {
|
---|
| 176 | struct lzfileheader head;
|
---|
| 177 | struct lzstate *lzs;
|
---|
| 178 | DWORD ret;
|
---|
| 179 | int i;
|
---|
| 180 |
|
---|
[474] | 181 | dprintf(("LZ32: LZInit(%08xh)\n",
|
---|
| 182 | hfSrc));
|
---|
| 183 |
|
---|
[468] | 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 |
|
---|
[3695] | 192 | lzstates[i] = lzs = (lzstate*)HeapAlloc( GetProcessHeap(), 0, sizeof(struct lzstate) );
|
---|
| 193 | if (lzs == NULL) return LZERROR_GLOBALLOC;
|
---|
| 194 |
|
---|
[468] | 195 | memset(lzs,'\0',sizeof(*lzs));
|
---|
| 196 | lzs->realfd = hfSrc;
|
---|
| 197 | lzs->lastchar = head.lastchar;
|
---|
| 198 | lzs->reallength = head.reallength;
|
---|
| 199 |
|
---|
[3695] | 200 | lzs->get = (BYTE*)HeapAlloc( GetProcessHeap(), 0, GETLEN );
|
---|
[468] | 201 | lzs->getlen = 0;
|
---|
| 202 | lzs->getcur = 0;
|
---|
[3695] | 203 |
|
---|
| 204 | if (lzs->get == NULL) {
|
---|
| 205 | HeapFree(GetProcessHeap(), 0, lzs);
|
---|
| 206 | lzstates[i] = NULL;
|
---|
| 207 | return LZERROR_GLOBALLOC;
|
---|
| 208 | }
|
---|
| 209 |
|
---|
[468] | 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 | */
|
---|
[474] | 221 | ODINPROCEDURE0(LZDone)
|
---|
[468] | 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 |
|
---|
[474] | 237 | ODINFUNCTION2(INT,GetExpandedNameA,LPCSTR,in,LPSTR,out)
|
---|
[468] | 238 | {
|
---|
| 239 | struct lzfileheader head;
|
---|
| 240 | HFILE fd;
|
---|
| 241 | OFSTRUCT ofs;
|
---|
| 242 | INT fnislowercased,ret,len;
|
---|
| 243 | LPSTR s,t;
|
---|
| 244 |
|
---|
[474] | 245 | dprintf(("LZ32: GetExpandedNameA(%s,%08xh)\n",
|
---|
| 246 | in,
|
---|
| 247 | out));
|
---|
| 248 |
|
---|
[468] | 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 | */
|
---|
[474] | 310 | ODINFUNCTION2(INT,GetExpandedNameW,LPCWSTR,in,LPWSTR,out)
|
---|
[468] | 311 | {
|
---|
| 312 | char *xin,*xout;
|
---|
| 313 | INT ret;
|
---|
| 314 |
|
---|
[474] | 315 | dprintf(("LZ32: GetExpandedNameW(%08xh,%08xh)\n",
|
---|
| 316 | in,
|
---|
| 317 | out));
|
---|
| 318 |
|
---|
[468] | 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 | */
|
---|
[474] | 332 | ODINFUNCTION3(INT,LZRead,HFILE,fd,LPVOID,vbuf,UINT,toread)
|
---|
[468] | 333 | {
|
---|
| 334 | int howmuch;
|
---|
| 335 | BYTE b,*buf;
|
---|
| 336 | struct lzstate *lzs;
|
---|
| 337 |
|
---|
[474] | 338 | dprintf(("LZ32: LZRead(%08xh,%08xh,%08h)\n",
|
---|
| 339 | fd,
|
---|
| 340 | vbuf,
|
---|
| 341 | toread));
|
---|
| 342 |
|
---|
[468] | 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 | */
|
---|
[474] | 427 |
|
---|
| 428 | ODINFUNCTION3(LONG,LZSeek,HFILE,fd,LONG,off,INT,type)
|
---|
[468] | 429 | {
|
---|
| 430 | struct lzstate *lzs;
|
---|
| 431 | LONG newwanted;
|
---|
| 432 |
|
---|
[474] | 433 | dprintf(("LZ32: LZSeek(%08xh,%08xh,%08xh)\n",
|
---|
| 434 | fd,
|
---|
| 435 | off,
|
---|
| 436 | type));
|
---|
| 437 |
|
---|
[468] | 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 |
|
---|
[474] | 471 | ODINFUNCTION2(LONG,LZCopy,HFILE,src,HFILE,dest)
|
---|
[468] | 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 |
|
---|
[474] | 483 | dprintf(("LZ32: LZCopy(%08x,h%08xh)\n",
|
---|
| 484 | src,
|
---|
| 485 | dest));
|
---|
| 486 |
|
---|
[468] | 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;
|
---|
[3695] | 523 | char *mfn = (char *)HeapAlloc( GetProcessHeap(), 0,
|
---|
| 524 | strlen(fn) + 3 ); /* "._" and \0 */
|
---|
| 525 | if (mfn == NULL) return NULL;
|
---|
[468] | 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 | */
|
---|
[474] | 544 |
|
---|
| 545 | ODINFUNCTION3(HFILE,LZOpenFileA,LPCSTR,fn,LPOFSTRUCT,ofs,UINT,mode)
|
---|
[468] | 546 | {
|
---|
| 547 | HFILE fd,cfd;
|
---|
| 548 |
|
---|
[474] | 549 | dprintf(("LZ32: LZOpenFileA(%s,%08xh,%08xh)\n",
|
---|
| 550 | fn,
|
---|
| 551 | ofs,
|
---|
| 552 | mode));
|
---|
| 553 |
|
---|
[468] | 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 | */
|
---|
[474] | 575 | ODINFUNCTION3(HFILE,LZOpenFileW,LPCWSTR,fn,LPOFSTRUCT,ofs,UINT,mode)
|
---|
[468] | 576 | {
|
---|
| 577 | LPSTR xfn;
|
---|
| 578 | LPWSTR yfn;
|
---|
| 579 | HFILE ret;
|
---|
| 580 |
|
---|
[474] | 581 | dprintf(("LZ32: LZOpenFileW(%08xh,%08xh,%08xh)\n",
|
---|
| 582 | fn,
|
---|
| 583 | ofs,
|
---|
| 584 | mode));
|
---|
| 585 |
|
---|
[468] | 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 | */
|
---|
[474] | 602 |
|
---|
| 603 | ODINPROCEDURE1(LZClose,HFILE,fd)
|
---|
[468] | 604 | {
|
---|
| 605 | struct lzstate *lzs;
|
---|
| 606 |
|
---|
[474] | 607 | dprintf(("LZ32: LZClose(%08xh)\n",
|
---|
| 608 | fd));
|
---|
| 609 |
|
---|
[468] | 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;
|
---|
[3695] | 616 | HeapFree( GetProcessHeap(), 0, lzs );
|
---|
[468] | 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 | */
|
---|
[474] | 627 |
|
---|
| 628 | ODINFUNCTION2(LONG,CopyLZFile,HFILE,src,HFILE,dest)
|
---|
[468] | 629 | {
|
---|
[474] | 630 | dprintf(("LZ32: CopyLZFile(%08xh,%08xh)\n",
|
---|
| 631 | src,
|
---|
| 632 | dest));
|
---|
| 633 |
|
---|
| 634 | return LZCopy(src,dest);
|
---|
[468] | 635 | }
|
---|