├── README.md └── unlzexe.c /README.md: -------------------------------------------------------------------------------- 1 | # UNLZEXE 2 | 3 | UNLZEXE is a utility to decompress EXE files that are compressed with LZEXE Ver. 0.90/0.91 4 | 5 | 6 | ## Getting started 7 | 8 | Orignal source code is written for C-compilers that compiles to 16bit-MSDOS. Source code has been slightly patched to work on POSIX systems. 9 | 10 | ## Copyright 11 | 12 | Code is orignally written by Mitugu(Kou) Kurizono 13 | 14 | LZEXE was written by Fabrice Bellard, fabrice.bellard at free.fr. 15 | 16 | ## References 17 | 18 | https://bellard.org/lzexe.html 19 | 20 | https://bellard.org/lzexe/lzexe91e.zip 21 | 22 | https://github.com/thbar/demomaking/blob/master/tools/unlzexe/UNLZEXE.C 23 | -------------------------------------------------------------------------------- /unlzexe.c: -------------------------------------------------------------------------------- 1 | #define VERSION "0.9" 2 | /* 3 | * unlzexe ver 0.5 (PC-VAN UTJ44266 Kou ) 4 | * UNLZEXE converts the compressed file by lzexe(ver.0.90,0.91) to the 5 | * UNcompressed executable one. 6 | * 7 | * usage: UNLZEXE packedfile[.EXE] [unpackedfile.EXE] 8 | 9 | v0.6 David Kirschbaum, Toad Hall, kirsch@usasoc.soc.mil, Jul 91 10 | Problem reported by T.Salmi (ts@uwasa.fi) with UNLZEXE when run 11 | with TLB-V119 on 386's. 12 | Stripping out the iskanji and isjapan() stuff (which uses a somewhat 13 | unusual DOS interrupt) to see if that's what's biting us. 14 | 15 | -- Found it, thanks to Dan Lewis (DLEWIS@SCUACC.SCU.EDU). 16 | Silly us: didn't notice the "r.h.al=0x3800;" in isjapan(). 17 | Oh, you don't see it either? INT functions are called with AH 18 | having the service. Changing to "r.x.ax=0x3800;". 19 | 20 | v0.7 Alan Modra, amodra@sirius.ucs.adelaide.edu.au, Nov 91 21 | Fixed problem with large files by casting ihead components to long 22 | in various expressions. 23 | Fixed MinBSS & MaxBSS calculation (ohead[5], ohead[6]). Now UNLZEXE 24 | followed by LZEXE should give the original file. 25 | 26 | v0.8 Vesselin Bontchev, bontchev@fbihh.informatik.uni-hamburg.de, Aug 92 27 | Fixed recognition of EXE files - both 'MZ' and 'ZM' in the header 28 | are recognized. 29 | Recognition of compressed files made more robust - now just 30 | patching the 'LZ90' and 'LZ91' strings will not fool the program. 31 | 32 | v0.9 Stian Skjelstad, stian.skjelstad@gmail.com, Aug 2019 33 | Use memmove when memory-regions overlap 34 | Do not use putw/getw, since they on modern systems do not read/write 16bit 35 | getc() return char, which might be signed. 36 | Include POSIX headers 37 | span + pointer, was expected to wrap 16bit 38 | */ 39 | 40 | #include 41 | #include 42 | #include 43 | #ifdef __TURBOC__ 44 | #include 45 | #include 46 | /* 47 | #define MAXPATH 80 48 | #define MAXDRIVE 3 49 | #define MAXDIR 66 50 | #define MAXFILE 9 51 | #define MAXEXT 5 52 | #define FILENAME_MAX MAXPATH 53 | */ 54 | #else 55 | #include /* v0.9 */ 56 | typedef uint16_t WORD; /* v0.9 */ 57 | typedef uint8_t BYTE; /* v0.9 */ 58 | #define stricmp strcasecmp /* v0.9 */ 59 | #endif 60 | 61 | #define FAILURE 1 62 | #define SUCCESS 0 63 | 64 | int isjapan(void); 65 | int japan_f; 66 | #define iskanji(c) ('\x81'<=(c)&&(c)<='\x9f' || '\xe0'<=(c)&&(c)<='\xfc') 67 | 68 | char *tmpfname = "$tmpfil$.exe"; 69 | char *backup_ext = ".olz"; 70 | char ipath[FILENAME_MAX], 71 | opath[FILENAME_MAX], 72 | ofname[13]; 73 | 74 | int fnamechk(char*,char*,char*,int,char**); 75 | int fnamechg(char*,char*,char*,int); 76 | int rdhead(FILE *,int *); 77 | int mkreltbl(FILE *,FILE *,int); 78 | int unpack(FILE *,FILE *); 79 | void wrhead(FILE *); 80 | int reloc90(FILE *ifile,FILE *ofile,long fpos); 81 | int reloc91(FILE *ifile,FILE *ofile,long fpos); 82 | 83 | int main(int argc,char **argv){ 84 | FILE *ifile,*ofile; 85 | int ver,rename_sw=0; 86 | 87 | printf("UNLZEXE Ver. "VERSION"\n"); /* v0.6 */ 88 | japan_f=isjapan(); 89 | if(argc!=3 && argc!=2){ 90 | printf("usage: UNLZEXE packedfile [unpackedfile]\n"); 91 | exit(EXIT_FAILURE); 92 | } 93 | if(argc==2) 94 | rename_sw=1; 95 | if(fnamechk(ipath,opath,ofname,argc,argv)!=SUCCESS) { 96 | exit(EXIT_FAILURE); 97 | } 98 | if((ifile=fopen(ipath,"rb"))==NULL){ 99 | printf("'%s' :not found\n",ipath); 100 | exit(EXIT_FAILURE); 101 | } 102 | 103 | if(rdhead(ifile,&ver)!=SUCCESS){ 104 | printf("'%s' is not LZEXE file.\n",ipath); 105 | fclose(ifile); exit(EXIT_FAILURE); 106 | } 107 | if((ofile=fopen(opath,"w+b"))==NULL){ 108 | printf("can't open '%s'.\n",opath); 109 | fclose(ifile); exit(EXIT_FAILURE); 110 | } 111 | printf("file '%s' is compressed by LZEXE Ver. 0.%d\n",ipath,ver); /* v0.8 */ 112 | if(mkreltbl(ifile,ofile,ver)!=SUCCESS) { 113 | fclose(ifile); 114 | fclose(ofile); 115 | remove(opath); 116 | exit(EXIT_FAILURE); 117 | } 118 | if(unpack(ifile,ofile)!=SUCCESS) { 119 | fclose(ifile); 120 | fclose(ofile); 121 | remove(opath); 122 | exit(EXIT_FAILURE); 123 | } 124 | fclose(ifile); 125 | wrhead(ofile); 126 | fclose(ofile); 127 | 128 | if(fnamechg(ipath,opath,ofname,rename_sw)!=SUCCESS){ 129 | exit(EXIT_FAILURE); 130 | } 131 | exit(EXIT_SUCCESS); 132 | } 133 | 134 | 135 | 136 | void parsepath(char *pathname, int *fname, int *ext); 137 | 138 | /* file name check */ 139 | int fnamechk(char *ipath,char *opath, char *ofname, 140 | int argc,char **argv) { 141 | int idx_name,idx_ext; 142 | 143 | strcpy(ipath,argv[1]); 144 | parsepath(ipath,&idx_name,&idx_ext); 145 | if (! ipath[idx_ext]) strcpy(ipath+idx_ext,".exe"); 146 | if(! stricmp(ipath+idx_name,tmpfname)){ 147 | printf("'%s':bad filename.\n",ipath); 148 | return(FAILURE); 149 | } 150 | if(argc==2) 151 | strcpy(opath,ipath); 152 | else 153 | strcpy(opath,argv[2]); 154 | parsepath(opath,&idx_name,&idx_ext); 155 | if (! opath[idx_ext]) strcpy(opath+idx_ext,".exe"); 156 | if (!stricmp(opath+idx_ext,backup_ext)){ 157 | printf("'%s':bad filename.\n",opath); 158 | return(FAILURE); 159 | } 160 | strncpy(ofname,opath+idx_name,12); 161 | strcpy(opath+idx_name,tmpfname); 162 | return(SUCCESS); 163 | } 164 | 165 | 166 | int fnamechg(char *ipath,char *opath,char *ofname,int rename_sw) { 167 | int idx_name,idx_ext; 168 | char tpath[FILENAME_MAX]; 169 | 170 | if(rename_sw) { 171 | strcpy(tpath,ipath); 172 | parsepath(tpath,&idx_name,&idx_ext); 173 | strcpy(tpath+idx_ext,backup_ext); 174 | remove(tpath); 175 | if(rename(ipath,tpath)){ 176 | printf("can't make '%s'.\n", tpath); 177 | remove(opath); 178 | return(FAILURE); 179 | } 180 | printf("'%s' is renamed to '%s'.\n",ipath,tpath); 181 | } 182 | strcpy(tpath,opath); 183 | parsepath(tpath,&idx_name,&idx_ext); 184 | strcpy(tpath+idx_name,ofname); 185 | remove(tpath); 186 | if(rename(opath,tpath)){ 187 | if(rename_sw) { 188 | strcpy(tpath,ipath); 189 | parsepath(tpath,&idx_name,&idx_ext); 190 | strcpy(tpath+idx_ext,backup_ext); 191 | rename(tpath,ipath); 192 | } 193 | printf("can't make '%s'. unpacked file '%s' is remained.\n", 194 | tpath, tmpfname); 195 | 196 | return(FAILURE); 197 | } 198 | printf("unpacked file '%s' is generated.\n",tpath); 199 | return(SUCCESS); 200 | } 201 | 202 | int isjapan() { 203 | #ifdef __TURBOC__ 204 | union REGS r; 205 | struct SREGS rs; 206 | BYTE buf[34]; 207 | 208 | segread(&rs); 209 | rs.ds=rs.ss; r.x.dx=(WORD)buf; 210 | /* r.h.al=0x3800; v0.6 */ 211 | r.x.ax=0x3800; /* svc 38H, check for country v0.6 */ 212 | intdosx(&r,&r,&rs); 213 | return (! strcmp ((char *) (buf + 2), "\\")); /* v0.8 */ 214 | #else 215 | return 0; 216 | #endif 217 | } 218 | 219 | void parsepath(char *pathname, int *fname, int *ext) { 220 | /* use int japan_f */ 221 | char c; 222 | int i; 223 | 224 | *fname=0; *ext=0; 225 | for(i=0;c=pathname[i];i++) { 226 | if(japan_f && iskanji(c)) 227 | i++; 228 | else 229 | switch(c) { 230 | case ':' : 231 | case '\\': *fname=i+1; break; 232 | case '.' : *ext=i; break; 233 | default : ; 234 | } 235 | } 236 | if(*ext<=*fname) *ext=i; 237 | } 238 | /*-------------------------------------------*/ 239 | static WORD ihead[0x10],ohead[0x10],inf[8]; 240 | static long loadsize; 241 | static BYTE sig90 [] = { /* v0.8 */ 242 | 0x06, 0x0E, 0x1F, 0x8B, 0x0E, 0x0C, 0x00, 0x8B, 243 | 0xF1, 0x4E, 0x89, 0xF7, 0x8C, 0xDB, 0x03, 0x1E, 244 | 0x0A, 0x00, 0x8E, 0xC3, 0xB4, 0x00, 0x31, 0xED, 245 | 0xFD, 0xAC, 0x01, 0xC5, 0xAA, 0xE2, 0xFA, 0x8B, 246 | 0x16, 0x0E, 0x00, 0x8A, 0xC2, 0x29, 0xC5, 0x8A, 247 | 0xC6, 0x29, 0xC5, 0x39, 0xD5, 0x74, 0x0C, 0xBA, 248 | 0x91, 0x01, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0xFF, 249 | 0x4C, 0xCD, 0x21, 0x53, 0xB8, 0x53, 0x00, 0x50, 250 | 0xCB, 0x2E, 0x8B, 0x2E, 0x08, 0x00, 0x8C, 0xDA, 251 | 0x89, 0xE8, 0x3D, 0x00, 0x10, 0x76, 0x03, 0xB8, 252 | 0x00, 0x10, 0x29, 0xC5, 0x29, 0xC2, 0x29, 0xC3, 253 | 0x8E, 0xDA, 0x8E, 0xC3, 0xB1, 0x03, 0xD3, 0xE0, 254 | 0x89, 0xC1, 0xD1, 0xE0, 0x48, 0x48, 0x8B, 0xF0, 255 | 0x8B, 0xF8, 0xF3, 0xA5, 0x09, 0xED, 0x75, 0xD8, 256 | 0xFC, 0x8E, 0xC2, 0x8E, 0xDB, 0x31, 0xF6, 0x31, 257 | 0xFF, 0xBA, 0x10, 0x00, 0xAD, 0x89, 0xC5, 0xD1, 258 | 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, 0xB2, 259 | 0x10, 0x73, 0x03, 0xA4, 0xEB, 0xF1, 0x31, 0xC9, 260 | 0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, 261 | 0xB2, 0x10, 0x72, 0x22, 0xD1, 0xED, 0x4A, 0x75, 262 | 0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0xD1, 0xD1, 263 | 0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, 264 | 0xB2, 0x10, 0xD1, 0xD1, 0x41, 0x41, 0xAC, 0xB7, 265 | 0xFF, 0x8A, 0xD8, 0xE9, 0x13, 0x00, 0xAD, 0x8B, 266 | 0xD8, 0xB1, 0x03, 0xD2, 0xEF, 0x80, 0xCF, 0xE0, 267 | 0x80, 0xE4, 0x07, 0x74, 0x0C, 0x88, 0xE1, 0x41, 268 | 0x41, 0x26, 0x8A, 0x01, 0xAA, 0xE2, 0xFA, 0xEB, 269 | 0xA6, 0xAC, 0x08, 0xC0, 0x74, 0x40, 0x3C, 0x01, 270 | 0x74, 0x05, 0x88, 0xC1, 0x41, 0xEB, 0xEA, 0x89 271 | }, sig91 [] = { 272 | 0x06, 0x0E, 0x1F, 0x8B, 0x0E, 0x0C, 0x00, 0x8B, 273 | 0xF1, 0x4E, 0x89, 0xF7, 0x8C, 0xDB, 0x03, 0x1E, 274 | 0x0A, 0x00, 0x8E, 0xC3, 0xFD, 0xF3, 0xA4, 0x53, 275 | 0xB8, 0x2B, 0x00, 0x50, 0xCB, 0x2E, 0x8B, 0x2E, 276 | 0x08, 0x00, 0x8C, 0xDA, 0x89, 0xE8, 0x3D, 0x00, 277 | 0x10, 0x76, 0x03, 0xB8, 0x00, 0x10, 0x29, 0xC5, 278 | 0x29, 0xC2, 0x29, 0xC3, 0x8E, 0xDA, 0x8E, 0xC3, 279 | 0xB1, 0x03, 0xD3, 0xE0, 0x89, 0xC1, 0xD1, 0xE0, 280 | 0x48, 0x48, 0x8B, 0xF0, 0x8B, 0xF8, 0xF3, 0xA5, 281 | 0x09, 0xED, 0x75, 0xD8, 0xFC, 0x8E, 0xC2, 0x8E, 282 | 0xDB, 0x31, 0xF6, 0x31, 0xFF, 0xBA, 0x10, 0x00, 283 | 0xAD, 0x89, 0xC5, 0xD1, 0xED, 0x4A, 0x75, 0x05, 284 | 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0x73, 0x03, 0xA4, 285 | 0xEB, 0xF1, 0x31, 0xC9, 0xD1, 0xED, 0x4A, 0x75, 286 | 0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0x72, 0x22, 287 | 0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, 288 | 0xB2, 0x10, 0xD1, 0xD1, 0xD1, 0xED, 0x4A, 0x75, 289 | 0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0xD1, 0xD1, 290 | 0x41, 0x41, 0xAC, 0xB7, 0xFF, 0x8A, 0xD8, 0xE9, 291 | 0x13, 0x00, 0xAD, 0x8B, 0xD8, 0xB1, 0x03, 0xD2, 292 | 0xEF, 0x80, 0xCF, 0xE0, 0x80, 0xE4, 0x07, 0x74, 293 | 0x0C, 0x88, 0xE1, 0x41, 0x41, 0x26, 0x8A, 0x01, 294 | 0xAA, 0xE2, 0xFA, 0xEB, 0xA6, 0xAC, 0x08, 0xC0, 295 | 0x74, 0x34, 0x3C, 0x01, 0x74, 0x05, 0x88, 0xC1, 296 | 0x41, 0xEB, 0xEA, 0x89, 0xFB, 0x83, 0xE7, 0x0F, 297 | 0x81, 0xC7, 0x00, 0x20, 0xB1, 0x04, 0xD3, 0xEB, 298 | 0x8C, 0xC0, 0x01, 0xD8, 0x2D, 0x00, 0x02, 0x8E, 299 | 0xC0, 0x89, 0xF3, 0x83, 0xE6, 0x0F, 0xD3, 0xEB, 300 | 0x8C, 0xD8, 0x01, 0xD8, 0x8E, 0xD8, 0xE9, 0x72 301 | }, sigbuf [sizeof sig90]; 302 | 303 | /* EXE header test (is it LZEXE file?) */ 304 | int rdhead(FILE *ifile ,int *ver){ 305 | long entry; /* v0.8 */ 306 | /* v0.7 old code */ 307 | /* if(fread(ihead,sizeof ihead[0],0x10,ifile)!=0x10) 308 | * return FAILURE; 309 | * memcpy(ohead,ihead,sizeof ihead[0] * 0x10); 310 | * if(ihead[0]!=0x5a4d || ihead[4]!=2 || ihead[0x0d]!=0) 311 | * return FAILURE; 312 | * if(ihead[0x0c]==0x1c && memcmp(&ihead[0x0e],"LZ09",4)==0){ 313 | * *ver=90; return SUCCESS ; 314 | * } 315 | * if(ihead[0x0c]==0x1c && memcmp(&ihead[0x0e],"LZ91",4)==0){ 316 | * *ver=91; return SUCCESS ; 317 | * } 318 | */ 319 | if (fread (ihead, 1, sizeof ihead, ifile) != sizeof ihead) /* v0.8 */ 320 | return FAILURE; /* v0.8 */ 321 | memcpy (ohead, ihead, sizeof ohead); /* v0.8 */ 322 | if((ihead [0] != 0x5a4d && ihead [0] != 0x4d5a) || /* v0.8 */ 323 | ihead [0x0d] != 0 || ihead [0x0c] != 0x1c) /* v0.8 */ 324 | return FAILURE; /* v0.8 */ 325 | entry = ((long) (ihead [4] + ihead[0x0b]) << 4) + ihead[0x0a]; /* v0.8 */ 326 | if (fseek (ifile, entry, SEEK_SET) != 0) /* v0.8 */ 327 | return FAILURE; /* v0.8 */ 328 | if (fread (sigbuf, 1, sizeof sigbuf, ifile) != sizeof sigbuf) /* v0.8 */ 329 | return FAILURE; /* v0.8 */ 330 | if (memcmp (sigbuf, sig90, sizeof sigbuf) == 0) { /* v0.8 */ 331 | *ver = 90; /* v0.8 */ 332 | return SUCCESS; /* v0.8 */ 333 | } /* v0.8 */ 334 | if (memcmp (sigbuf, sig91, sizeof sigbuf) == 0) { /* v0.8 */ 335 | *ver = 91; /* v0.8 */ 336 | return SUCCESS; /* v0.8 */ 337 | } /* v0.8 */ 338 | return FAILURE; 339 | } 340 | 341 | /* make relocation table */ 342 | int mkreltbl(FILE *ifile,FILE *ofile,int ver) { 343 | long fpos; 344 | int i; 345 | 346 | /* v0.7 old code 347 | * allocsize=((ihead[1]+16-1)>>4) + ((ihead[2]-1)<<5) - ihead[4] + ihead[5]; 348 | */ 349 | fpos=(long)(ihead[0x0b]+ihead[4])<<4; /* goto CS:0000 */ 350 | fseek(ifile,fpos,SEEK_SET); 351 | fread(inf, sizeof inf[0], 0x08, ifile); 352 | ohead[0x0a]=inf[0]; /* IP */ 353 | ohead[0x0b]=inf[1]; /* CS */ 354 | ohead[0x08]=inf[2]; /* SP */ 355 | ohead[0x07]=inf[3]; /* SS */ 356 | /* inf[4]:size of compressed load module (PARAGRAPH)*/ 357 | /* inf[5]:increase of load module size (PARAGRAPH)*/ 358 | /* inf[6]:size of decompressor with compressed relocation table (BYTE) */ 359 | /* inf[7]:check sum of decompresser with compressd relocation table(Ver.0.90) */ 360 | ohead[0x0c]=0x1c; /* start position of relocation table */ 361 | fseek(ofile,0x1cL,SEEK_SET); 362 | switch(ver){ 363 | case 90: i=reloc90(ifile,ofile,fpos); 364 | break; 365 | case 91: i=reloc91(ifile,ofile,fpos); 366 | break; 367 | default: i=FAILURE; break; 368 | } 369 | if(i!=SUCCESS){ 370 | printf("error at relocation table.\n"); 371 | return (FAILURE); 372 | } 373 | fpos=ftell(ofile); 374 | /* v0.7 old code 375 | * i= (int) fpos & 0x1ff; 376 | * if(i) i=0x200-i; 377 | * ohead[4]= (int) (fpos+i)>>4; 378 | */ 379 | i= (0x200 - (int) fpos) & 0x1ff; /* v0.7 */ 380 | ohead[4]= (int) ((fpos+i)>>4); /* v0.7 */ 381 | 382 | for( ; i>0; i--) 383 | putc(0, ofile); 384 | return(SUCCESS); 385 | } 386 | /* for LZEXE ver 0.90 */ 387 | int reloc90(FILE *ifile,FILE *ofile,long fpos) { 388 | unsigned int c; 389 | WORD rel_count=0; 390 | WORD rel_seg,rel_off; 391 | 392 | fseek(ifile,fpos+0x19d,SEEK_SET); 393 | /* 0x19d=compressed relocation table address */ 394 | rel_seg=0; 395 | do{ 396 | if(feof(ifile) || ferror(ifile) || ferror(ofile)) return(FAILURE); 397 | fread (&c, 2, 1, ifile); /* v0.9 */ 398 | for(;c>0;c--) { 399 | fread (&rel_off, 2, 1, ifile); /* v0.9 */ 400 | fwrite (&rel_off, 2, 1, ofile); /* v0.9 */ 401 | fwrite (&rel_seg, 2, 1, ofile); /* v0.9 */ 402 | rel_count++; 403 | } 404 | rel_seg += 0x1000; 405 | } while(rel_seg!=(0xf000+0x1000)); 406 | ohead[3]=rel_count; 407 | return(SUCCESS); 408 | } 409 | /* for LZEXE ver 0.91*/ 410 | int reloc91(FILE *ifile,FILE *ofile,long fpos) { 411 | WORD span; 412 | WORD rel_count=0; 413 | WORD rel_seg,rel_off; 414 | 415 | fseek(ifile,fpos+0x158,SEEK_SET); 416 | /* 0x158=compressed relocation table address */ 417 | rel_off=0; rel_seg=0; 418 | for(;;) { 419 | if (feof(ifile) || ferror(ifile) || ferror(ofile)) return(FAILURE); 420 | if((span=(BYTE)getc(ifile))==0) { /* v0.9 */ 421 | fread(&span, 2, 1, ifile); /* v0.9 */ 422 | if(span==0){ 423 | rel_seg += 0x0fff; 424 | continue; 425 | } else if(span==1){ 426 | break; 427 | } 428 | } 429 | rel_off += span; 430 | rel_seg += (rel_off & ~0x0f)>>4; 431 | rel_off &= 0x0f; 432 | fwrite(&rel_off, 2, 1, ofile); /* v0.9 */ 433 | fwrite(&rel_seg, 2, 1, ofile); /* v0.9 */ 434 | rel_count++; 435 | } 436 | ohead[3]=rel_count; 437 | return(SUCCESS); 438 | } 439 | 440 | /*---------------------*/ 441 | typedef struct { 442 | FILE *fp; 443 | WORD buf; 444 | BYTE count; 445 | } bitstream; 446 | 447 | void initbits(bitstream *,FILE *); 448 | int getbit(bitstream *); 449 | 450 | /*---------------------*/ 451 | /* decompressor routine */ 452 | int unpack(FILE *ifile,FILE *ofile){ 453 | int len; 454 | WORD span; 455 | long fpos; 456 | bitstream bits; 457 | static BYTE data[0x4500], *p=data; 458 | 459 | fpos=((long)ihead[0x0b]-(long)inf[4]+(long)ihead[4])<<4; 460 | fseek(ifile,fpos,SEEK_SET); 461 | fpos=(long)ohead[4]<<4; 462 | fseek(ofile,fpos,SEEK_SET); 463 | initbits(&bits,ifile); 464 | printf(" unpacking. "); 465 | for(;;){ 466 | if(ferror(ifile)) {printf("\nread error\n"); return(FAILURE); } 467 | if(ferror(ofile)) {printf("\nwrite error\n"); return(FAILURE); } 468 | if(p-data>0x4000){ 469 | fwrite(data,sizeof data[0],0x2000,ofile); 470 | p-=0x2000; 471 | memmove(data,data+0x2000,p-data); /* v0.9 */ 472 | putchar('.'); 473 | } 474 | if(getbit(&bits)) { 475 | *p++=(BYTE)getc(ifile); /* v0.9 */ 476 | continue; 477 | } 478 | if(!getbit(&bits)) { 479 | len=getbit(&bits)<<1; 480 | len |= getbit(&bits); 481 | len += 2; 482 | span=(BYTE)getc(ifile) | 0xff00; /* v0.9 */ 483 | } else { 484 | span=(BYTE)getc(ifile); 485 | len=(BYTE)getc(ifile); /* v0.9 */ 486 | span |= ((len & ~0x07)<<5) | 0xe000; 487 | len = (len & 0x07)+2; 488 | if (len==2) { 489 | len=(BYTE)getc(ifile); /* v0.9 */ 490 | 491 | if(len==0) 492 | break; /* end mark of compreesed load module */ 493 | 494 | if(len==1) 495 | continue; /* segment change */ 496 | else 497 | len++; 498 | } 499 | } 500 | for( ;len>0;len--,p++){ 501 | *p=*(p+(int16_t)span); /* v0.9 */ 502 | } 503 | } 504 | if(p!=data) 505 | fwrite(data,sizeof data[0],p-data,ofile); 506 | loadsize=ftell(ofile)-fpos; 507 | printf("end\n"); 508 | return(SUCCESS); 509 | } 510 | 511 | /* write EXE header*/ 512 | void wrhead(FILE *ofile) { 513 | if(ihead[6]!=0) { 514 | ohead[5]-= inf[5] + ((inf[6]+16-1)>>4) + 9; /* v0.7 */ 515 | if(ihead[6]!=0xffff) 516 | ohead[6]-=(ihead[5]-ohead[5]); 517 | } 518 | ohead[1]=((WORD)loadsize+(ohead[4]<<4)) & 0x1ff; /* v0.7 */ 519 | ohead[2]=(WORD)((loadsize+((long)ohead[4]<<4)+0x1ff) >> 9); /* v0.7 */ 520 | fseek(ofile,0L,SEEK_SET); 521 | fwrite(ohead,sizeof ohead[0],0x0e,ofile); 522 | } 523 | 524 | 525 | /*-------------------------------------------*/ 526 | 527 | /* get compress information bit by bit */ 528 | void initbits(bitstream *p,FILE *filep){ 529 | p->fp=filep; 530 | p->count=0x10; 531 | fread(&p->buf, 2, 1, p->fp); /* v0.9 */ 532 | /* printf("%04x ",p->buf); */ 533 | } 534 | 535 | int getbit(bitstream *p) { 536 | int b; 537 | b = p->buf & 1; 538 | if(--p->count == 0){ 539 | fread(&p->buf, 2, 1, p->fp); /* v0.9 */ 540 | /* printf("%04x ",p->buf); */ 541 | p->count= 0x10; 542 | }else 543 | p->buf >>= 1; 544 | 545 | return b; 546 | } 547 | --------------------------------------------------------------------------------