Last active
March 28, 2020 14:48
-
-
Save lpproj/09ea43ecf64a77b3b81f1877103e1b37 to your computer and use it in GitHub Desktop.
a private fork of unlzexe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* unlzexe.c */ | |
#define VERSION "0.8p1 (2020-03-26)" | |
/* unlzexe ver 0.5 (PC-VAN UTJ44266 Kou ) | |
* UNLZEXE converts the compressed file by lzexe(ver.0.90,0.91) to the | |
* UNcompressed executable one. | |
* | |
* usage: UNLZEXE packedfile[.EXE] [unpackedfile.EXE] | |
v0.6 David Kirschbaum, Toad Hall, kirsch@usasoc.soc.mil, Jul 91 | |
Problem reported by T.Salmi (ts@uwasa.fi) with UNLZEXE when run | |
with TLB-V119 on 386's. | |
Stripping out the iskanji and isjapan() stuff (which uses a somewhat | |
unusual DOS interrupt) to see if that's what's biting us. | |
-- Found it, thanks to Dan Lewis (DLEWIS@SCUACC.SCU.EDU). | |
Silly us: didn't notice the "r.h.al=0x3800;" in isjapan(). | |
Oh, you don't see it either? INT functions are called with AH | |
having the service. Changing to "r.x.ax=0x3800;". | |
v0.7 Alan Modra, amodra@sirius.ucs.adelaide.edu.au, Nov 91 | |
Fixed problem with large files by casting ihead components to long | |
in various expressions. | |
Fixed MinBSS & MaxBSS calculation (ohead[5], ohead[6]). Now UNLZEXE | |
followed by LZEXE should give the original file. | |
v0.8 Vesselin Bontchev, bontchev@fbihh.informatik.uni-hamburg.de, Aug 92 | |
Fixed recognition of EXE files - both 'MZ' and 'ZM' in the header | |
are recognized. | |
Recognition of compressed files made more robust - now just | |
patching the 'LZ90' and 'LZ91' strings will not fool the program. | |
*/ | |
/* | |
v0.8p1 lpproj | |
Minimal modifications for modern platforms: | |
* Compliance with C99 | |
* Avoid warnings (with gcc -Wall -Wextra) | |
* Support non-DOS platform (32~64bits, also big-endian) | |
*/ | |
#include <ctype.h> | |
#include <limits.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#if defined MSDOS || defined __DOS__ | |
#include <dos.h> | |
#ifdef __TURBOC__ | |
#include <dir.h> | |
/* | |
#define MAXPATH 80 | |
#define MAXDRIVE 3 | |
#define MAXDIR 66 | |
#define MAXFILE 9 | |
#define MAXEXT 5 | |
#define FILENAME_MAX MAXPATH | |
*/ | |
#endif | |
#endif /* MSDOS || __DOS__ */ | |
#if __STDC_VERSION__ >= 199901L | |
#include <stdint.h> | |
typedef uint_least16_t WORD; | |
typedef uint_least8_t BYTE; | |
#else | |
typedef unsigned short WORD; | |
typedef unsigned char BYTE; | |
#endif | |
/* target-specific getw/putw */ | |
static int mygetc_debug(FILE *fi, long line){ | |
int c = fgetc(fi); | |
if (c == EOF){ | |
fprintf(stderr, "mygetc: unexpected EOF at line %ld\n", line); | |
exit(-1); | |
} | |
return (c & 0xff); | |
} | |
static int myget_le16_debug(FILE *fi, long line){ | |
int c = mygetc_debug(fi, line); | |
if (c != EOF) c |= (unsigned)mygetc_debug(fi, line) << 8; | |
return c; | |
} | |
static int myputc_debug(int c, FILE *fo, long line){ | |
c = fputc(c, fo); | |
if (c == EOF) { | |
fprintf(stderr, "myputc: unexpected EOF at line %ld\n", line); | |
exit(-1); | |
} | |
return c; | |
} | |
static int myput_le16_debug(WORD c, FILE *fo, long line){ | |
myputc_debug(c & 0xff, fo, line); | |
myputc_debug((c >> 8) & 0xff, fo, line); | |
return c; | |
} | |
static int mystrcasecmp(const char *s1, const char *s2){ | |
int r, c1, c2; | |
do { | |
c1 = toupper((int)(unsigned char)(*s1++)); | |
c2 = toupper((int)(unsigned char)(*s2++)); | |
r = c1 - c2; | |
} while(r == 0 && c1 != 0 && c2 != 0); | |
return r; | |
} | |
#undef getc | |
#undef getw | |
#undef putc | |
#undef putw | |
#define getc(f) mygetc_debug(f,__LINE__) | |
#define getw(f) myget_le16_debug(f,__LINE__) | |
#define putc(c,f) myputc_debug(c,f,__LINE__) | |
#define putw(c,f) myput_le16_debug(c,f,__LINE__) | |
#undef stricmp | |
#define stricmp(s1,s2) mystrcasecmp(s1,s2) | |
#define FAILURE 1 | |
#define SUCCESS 0 | |
int isjapan(void); | |
int japan_f; | |
#define iskanji(c) ((0x81<=(unsigned char)(c)&&(unsigned char)(c)<=0x9f) || (0xe0<=(unsigned char)(c)&&(unsigned char)(c)<=0xfc)) | |
char *tmpfname = "$tmpfil$.exe"; | |
char *backup_ext = ".olz"; | |
char ipath[FILENAME_MAX], | |
opath[FILENAME_MAX], | |
ofname[FILENAME_MAX]; | |
#ifdef __TURBOC__ | |
/* I like prototypes */ | |
int reloc90(FILE *ifile,FILE *ofile,long fpos); | |
int reloc91(FILE *ifile,FILE *ofile,long fpos); | |
#endif | |
int main(int argc,char **argv){ | |
int fnamechk(char*,char*,char*,int,char**); | |
int fnamechg(char*,char*,char*,int); | |
int rdhead(FILE *,int *); | |
int mkreltbl(FILE *,FILE *,int); | |
int unpack(FILE *,FILE *); | |
void wrhead(FILE *); | |
FILE *ifile,*ofile; | |
int ver,rename_sw=0; | |
printf("UNLZEXE Ver. "VERSION"\n"); /* v0.6 */ | |
japan_f=isjapan(); | |
if(argc!=3 && argc!=2){ | |
printf("usage: UNLZEXE packedfile [unpackedfile]\n"); | |
exit(EXIT_FAILURE); | |
} | |
if(argc==2) | |
rename_sw=1; | |
if(fnamechk(ipath,opath,ofname,argc,argv)!=SUCCESS) { | |
exit(EXIT_FAILURE); | |
} | |
if((ifile=fopen(ipath,"rb"))==NULL){ | |
printf("'%s' :not found\n",ipath); | |
exit(EXIT_FAILURE); | |
} | |
if(rdhead(ifile,&ver)!=SUCCESS){ | |
printf("'%s' is not LZEXE file.\n",ipath); | |
fclose(ifile); exit(EXIT_FAILURE); | |
} | |
if((ofile=fopen(opath,"w+b"))==NULL){ | |
printf("can't open '%s'.\n",opath); | |
fclose(ifile); exit(EXIT_FAILURE); | |
} | |
printf("file '%s' is compressed by LZEXE Ver. 0.%d\n",ipath,ver); /* v0.8 */ | |
/* switch(ver){ | |
* case 90: printf("0.90\n"); break; | |
* case 91: printf("0.91\n"); break; | |
* } | |
*/ | |
if(mkreltbl(ifile,ofile,ver)!=SUCCESS) { | |
fclose(ifile); | |
fclose(ofile); | |
remove(opath); | |
exit(EXIT_FAILURE); | |
} | |
if(unpack(ifile,ofile)!=SUCCESS) { | |
fclose(ifile); | |
fclose(ofile); | |
remove(opath); | |
exit(EXIT_FAILURE); | |
} | |
fclose(ifile); | |
wrhead(ofile); | |
fclose(ofile); | |
if(fnamechg(ipath,opath,ofname,rename_sw)!=SUCCESS){ | |
exit(EXIT_FAILURE); | |
} | |
return(EXIT_SUCCESS); | |
} | |
void parsepath(char *pathname, int *fname, int *ext); | |
/* file name check */ | |
int fnamechk(char *ipath,char *opath, char *ofname, | |
int argc,char **argv) { | |
int idx_name,idx_ext; | |
strcpy(ipath,argv[1]); | |
parsepath(ipath,&idx_name,&idx_ext); | |
if (! ipath[idx_ext]) strcpy(ipath+idx_ext,".exe"); | |
if(! stricmp(ipath+idx_name,tmpfname)){ | |
printf("'%s':bad filename.\n",ipath); | |
return(FAILURE); | |
} | |
if(argc==2) | |
strcpy(opath,ipath); | |
else | |
strcpy(opath,argv[2]); | |
parsepath(opath,&idx_name,&idx_ext); | |
if (! opath[idx_ext]) strcpy(opath+idx_ext,".exe"); | |
if (!stricmp(opath+idx_ext,backup_ext)){ | |
printf("'%s':bad filename.\n",opath); | |
return(FAILURE); | |
} | |
strncpy(ofname,opath+idx_name,12); | |
strcpy(opath+idx_name,tmpfname); | |
return(SUCCESS); | |
} | |
int fnamechg(char *ipath,char *opath,char *ofname,int rename_sw) { | |
int idx_name,idx_ext; | |
char tpath[FILENAME_MAX]; | |
if(rename_sw) { | |
strcpy(tpath,ipath); | |
parsepath(tpath,&idx_name,&idx_ext); | |
strcpy(tpath+idx_ext,backup_ext); | |
remove(tpath); | |
if(rename(ipath,tpath)){ | |
printf("can't make '%s'.\n", tpath); | |
remove(opath); | |
return(FAILURE); | |
} | |
printf("'%s' is renamed to '%s'.\n",ipath,tpath); | |
} | |
strcpy(tpath,opath); | |
parsepath(tpath,&idx_name,&idx_ext); | |
strcpy(tpath+idx_name,ofname); | |
remove(tpath); | |
if(rename(opath,tpath)){ | |
if(rename_sw) { | |
strcpy(tpath,ipath); | |
parsepath(tpath,&idx_name,&idx_ext); | |
strcpy(tpath+idx_ext,backup_ext); | |
rename(tpath,ipath); | |
} | |
printf("can't make '%s'. unpacked file '%s' is remained.\n", | |
tpath, tmpfname); | |
return(FAILURE); | |
} | |
printf("unpacked file '%s' is generated.\n",tpath); | |
return(SUCCESS); | |
} | |
int isjapan() { | |
#if (defined MSDOS || defined __DOS__) && INT_MAX <= 0x7fff /* 16bit DOS? */ | |
union REGS r; | |
struct SREGS rs; | |
BYTE buf[34]; | |
rs.ds=FP_SEG(buf); r.x.dx=FP_OFF(buf); | |
/* r.h.al=0x3800; v0.6 */ | |
r.x.ax=0x3800; /* svc 38H, check for country v0.6 */ | |
intdosx(&r,&r,&rs); | |
return (! strcmp ((char *) (buf + 2), "\\")); /* v0.8 */ | |
#else | |
return 0; | |
#endif | |
} | |
void parsepath(char *pathname, int *fname, int *ext) { | |
/* use int japan_f */ | |
char c; | |
int i; | |
*fname=0; *ext=0; | |
for(i=0;(c=pathname[i])!='\0';i++) { | |
if(japan_f && iskanji(c)) | |
i++; | |
else | |
switch(c) { | |
case ':' : | |
case '/' : | |
case '\\': *fname=i+1; break; | |
case '.' : *ext=i; break; | |
default : ; | |
} | |
} | |
if(*ext<=*fname) *ext=i; | |
} | |
/*-------------------------------------------*/ | |
static WORD ihead[0x10],ohead[0x10],inf[8]; | |
static long loadsize; | |
static BYTE sig90 [] = { /* v0.8 */ | |
0x06, 0x0E, 0x1F, 0x8B, 0x0E, 0x0C, 0x00, 0x8B, | |
0xF1, 0x4E, 0x89, 0xF7, 0x8C, 0xDB, 0x03, 0x1E, | |
0x0A, 0x00, 0x8E, 0xC3, 0xB4, 0x00, 0x31, 0xED, | |
0xFD, 0xAC, 0x01, 0xC5, 0xAA, 0xE2, 0xFA, 0x8B, | |
0x16, 0x0E, 0x00, 0x8A, 0xC2, 0x29, 0xC5, 0x8A, | |
0xC6, 0x29, 0xC5, 0x39, 0xD5, 0x74, 0x0C, 0xBA, | |
0x91, 0x01, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0xFF, | |
0x4C, 0xCD, 0x21, 0x53, 0xB8, 0x53, 0x00, 0x50, | |
0xCB, 0x2E, 0x8B, 0x2E, 0x08, 0x00, 0x8C, 0xDA, | |
0x89, 0xE8, 0x3D, 0x00, 0x10, 0x76, 0x03, 0xB8, | |
0x00, 0x10, 0x29, 0xC5, 0x29, 0xC2, 0x29, 0xC3, | |
0x8E, 0xDA, 0x8E, 0xC3, 0xB1, 0x03, 0xD3, 0xE0, | |
0x89, 0xC1, 0xD1, 0xE0, 0x48, 0x48, 0x8B, 0xF0, | |
0x8B, 0xF8, 0xF3, 0xA5, 0x09, 0xED, 0x75, 0xD8, | |
0xFC, 0x8E, 0xC2, 0x8E, 0xDB, 0x31, 0xF6, 0x31, | |
0xFF, 0xBA, 0x10, 0x00, 0xAD, 0x89, 0xC5, 0xD1, | |
0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, 0xB2, | |
0x10, 0x73, 0x03, 0xA4, 0xEB, 0xF1, 0x31, 0xC9, | |
0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, | |
0xB2, 0x10, 0x72, 0x22, 0xD1, 0xED, 0x4A, 0x75, | |
0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0xD1, 0xD1, | |
0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, | |
0xB2, 0x10, 0xD1, 0xD1, 0x41, 0x41, 0xAC, 0xB7, | |
0xFF, 0x8A, 0xD8, 0xE9, 0x13, 0x00, 0xAD, 0x8B, | |
0xD8, 0xB1, 0x03, 0xD2, 0xEF, 0x80, 0xCF, 0xE0, | |
0x80, 0xE4, 0x07, 0x74, 0x0C, 0x88, 0xE1, 0x41, | |
0x41, 0x26, 0x8A, 0x01, 0xAA, 0xE2, 0xFA, 0xEB, | |
0xA6, 0xAC, 0x08, 0xC0, 0x74, 0x40, 0x3C, 0x01, | |
0x74, 0x05, 0x88, 0xC1, 0x41, 0xEB, 0xEA, 0x89 | |
}, sig91 [] = { | |
0x06, 0x0E, 0x1F, 0x8B, 0x0E, 0x0C, 0x00, 0x8B, | |
0xF1, 0x4E, 0x89, 0xF7, 0x8C, 0xDB, 0x03, 0x1E, | |
0x0A, 0x00, 0x8E, 0xC3, 0xFD, 0xF3, 0xA4, 0x53, | |
0xB8, 0x2B, 0x00, 0x50, 0xCB, 0x2E, 0x8B, 0x2E, | |
0x08, 0x00, 0x8C, 0xDA, 0x89, 0xE8, 0x3D, 0x00, | |
0x10, 0x76, 0x03, 0xB8, 0x00, 0x10, 0x29, 0xC5, | |
0x29, 0xC2, 0x29, 0xC3, 0x8E, 0xDA, 0x8E, 0xC3, | |
0xB1, 0x03, 0xD3, 0xE0, 0x89, 0xC1, 0xD1, 0xE0, | |
0x48, 0x48, 0x8B, 0xF0, 0x8B, 0xF8, 0xF3, 0xA5, | |
0x09, 0xED, 0x75, 0xD8, 0xFC, 0x8E, 0xC2, 0x8E, | |
0xDB, 0x31, 0xF6, 0x31, 0xFF, 0xBA, 0x10, 0x00, | |
0xAD, 0x89, 0xC5, 0xD1, 0xED, 0x4A, 0x75, 0x05, | |
0xAD, 0x89, 0xC5, 0xB2, 0x10, 0x73, 0x03, 0xA4, | |
0xEB, 0xF1, 0x31, 0xC9, 0xD1, 0xED, 0x4A, 0x75, | |
0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0x72, 0x22, | |
0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, | |
0xB2, 0x10, 0xD1, 0xD1, 0xD1, 0xED, 0x4A, 0x75, | |
0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0xD1, 0xD1, | |
0x41, 0x41, 0xAC, 0xB7, 0xFF, 0x8A, 0xD8, 0xE9, | |
0x13, 0x00, 0xAD, 0x8B, 0xD8, 0xB1, 0x03, 0xD2, | |
0xEF, 0x80, 0xCF, 0xE0, 0x80, 0xE4, 0x07, 0x74, | |
0x0C, 0x88, 0xE1, 0x41, 0x41, 0x26, 0x8A, 0x01, | |
0xAA, 0xE2, 0xFA, 0xEB, 0xA6, 0xAC, 0x08, 0xC0, | |
0x74, 0x34, 0x3C, 0x01, 0x74, 0x05, 0x88, 0xC1, | |
0x41, 0xEB, 0xEA, 0x89, 0xFB, 0x83, 0xE7, 0x0F, | |
0x81, 0xC7, 0x00, 0x20, 0xB1, 0x04, 0xD3, 0xEB, | |
0x8C, 0xC0, 0x01, 0xD8, 0x2D, 0x00, 0x02, 0x8E, | |
0xC0, 0x89, 0xF3, 0x83, 0xE6, 0x0F, 0xD3, 0xEB, | |
0x8C, 0xD8, 0x01, 0xD8, 0x8E, 0xD8, 0xE9, 0x72 | |
}, sigbuf [sizeof sig90]; | |
/* EXE header test (is it LZEXE file?) */ | |
int rdhead(FILE *ifile ,int *ver){ | |
long entry; /* v0.8 */ | |
/* v0.7 old code */ | |
/* if(fread(ihead,sizeof ihead[0],0x10,ifile)!=0x10) | |
* return FAILURE; | |
* memcpy(ohead,ihead,sizeof ihead[0] * 0x10); | |
* if(ihead[0]!=0x5a4d || ihead[4]!=2 || ihead[0x0d]!=0) | |
* return FAILURE; | |
* if(ihead[0x0c]==0x1c && memcmp(&ihead[0x0e],"LZ09",4)==0){ | |
* *ver=90; return SUCCESS ; | |
* } | |
* | |
* if(ihead[0x0c]==0x1c && memcmp(&ihead[0x0e],"LZ91",4)==0){ | |
* *ver=91; return SUCCESS ; | |
* } | |
*/ | |
int i; | |
for(i=0; i<0x10; ++i){ | |
ihead[i] = getw(ifile); | |
} | |
memcpy (ohead, ihead, sizeof ohead); /* v0.8 */ | |
if((ihead [0] != 0x5a4d && ihead [0] != 0x4d5a) || /* v0.8 */ | |
ihead [0x0d] != 0 || ihead [0x0c] != 0x1c) /* v0.8 */ | |
return FAILURE; /* v0.8 */ | |
entry = ((long) (ihead [4] + ihead[0x0b]) << 4) + ihead[0x0a]; /* v0.8 */ | |
if (fseek (ifile, entry, SEEK_SET) != 0) /* v0.8 */ | |
return FAILURE; /* v0.8 */ | |
if (fread (sigbuf, 1, sizeof sigbuf, ifile) != sizeof sigbuf) /* v0.8 */ | |
return FAILURE; /* v0.8 */ | |
if (memcmp (sigbuf, sig90, sizeof sigbuf) == 0) { /* v0.8 */ | |
*ver = 90; /* v0.8 */ | |
return SUCCESS; /* v0.8 */ | |
} /* v0.8 */ | |
if (memcmp (sigbuf, sig91, sizeof sigbuf) == 0) { /* v0.8 */ | |
*ver = 91; /* v0.8 */ | |
return SUCCESS; /* v0.8 */ | |
} /* v0.8 */ | |
return FAILURE; | |
} | |
/* make relocation table */ | |
int mkreltbl(FILE *ifile,FILE *ofile,int ver) { | |
int reloc90(); | |
int reloc91(); | |
long fpos; | |
int i; | |
/* v0.7 old code | |
* allocsize=((ihead[1]+16-1)>>4) + ((ihead[2]-1)<<5) - ihead[4] + ihead[5]; | |
*/ | |
fpos=(long)(ihead[0x0b]+ihead[4])<<4; /* goto CS:0000 */ | |
fseek(ifile,fpos,SEEK_SET); | |
for(i=0; i<8; ++i) inf[i] = getw(ifile); | |
ohead[0x0a]=inf[0]; /* IP */ | |
ohead[0x0b]=inf[1]; /* CS */ | |
ohead[0x08]=inf[2]; /* SP */ | |
ohead[0x07]=inf[3]; /* SS */ | |
/* inf[4]:size of compressed load module (PARAGRAPH)*/ | |
/* inf[5]:increase of load module size (PARAGRAPH)*/ | |
/* inf[6]:size of decompressor with compressed relocation table (BYTE) */ | |
/* inf[7]:check sum of decompresser with compressd relocation table(Ver.0.90) */ | |
ohead[0x0c]=0x1c; /* start position of relocation table */ | |
fseek(ofile,0x1cL,SEEK_SET); | |
switch(ver){ | |
case 90: i=reloc90(ifile,ofile,fpos); | |
break; | |
case 91: i=reloc91(ifile,ofile,fpos); | |
break; | |
default: i=FAILURE; break; | |
} | |
if(i!=SUCCESS){ | |
printf("error at relocation table.\n"); | |
return (FAILURE); | |
} | |
fpos=ftell(ofile); | |
/* v0.7 old code | |
* i= (int) fpos & 0x1ff; | |
* if(i) i=0x200-i; | |
* ohead[4]= (int) (fpos+i)>>4; | |
*/ | |
i= (0x200 - (int) fpos) & 0x1ff; /* v0.7 */ | |
ohead[4]= (int) ((fpos+i)>>4); /* v0.7 */ | |
for( ; i>0; i--) | |
putc(0, ofile); | |
return(SUCCESS); | |
} | |
/* for LZEXE ver 0.90 */ | |
int reloc90(FILE *ifile,FILE *ofile,long fpos) { | |
unsigned int c; | |
WORD rel_count=0; | |
WORD rel_seg,rel_off; | |
fseek(ifile,fpos+0x19d,SEEK_SET); | |
/* 0x19d=compressed relocation table address */ | |
rel_seg=0; | |
do{ | |
if(feof(ifile) || ferror(ifile) || ferror(ofile)) return(FAILURE); | |
c=getw(ifile); | |
for(;c>0;c--) { | |
rel_off=getw(ifile); | |
putw(rel_off,ofile); | |
putw(rel_seg,ofile); | |
rel_count++; | |
} | |
rel_seg = (rel_seg+0x1000U) & 0xffffU; | |
} while(rel_seg!=0); | |
ohead[3]=rel_count; | |
return(SUCCESS); | |
} | |
/* for LZEXE ver 0.91*/ | |
int reloc91(FILE *ifile,FILE *ofile,long fpos) { | |
WORD span; | |
WORD rel_count=0; | |
WORD rel_seg,rel_off; | |
fseek(ifile,fpos+0x158,SEEK_SET); | |
/* 0x158=compressed relocation table address */ | |
rel_off=0; rel_seg=0; | |
for(;;) { | |
if(feof(ifile) || ferror(ifile) || ferror(ofile)) return(FAILURE); | |
if((span=getc(ifile))==0) { | |
span=getw(ifile); | |
if(span==0){ | |
rel_seg = (rel_seg+0x0fffU) & 0xffffU; | |
continue; | |
} else if(span==1){ | |
break; | |
} | |
} | |
rel_off = (rel_off + span) & 0xffffU; | |
rel_seg = (rel_seg + (rel_off >> 4)) & 0xffffU; | |
rel_off &= 0x0f; | |
putw(rel_off,ofile); | |
putw(rel_seg,ofile); | |
rel_count++; | |
} | |
ohead[3]=rel_count; | |
return(SUCCESS); | |
} | |
/*---------------------*/ | |
typedef struct { | |
FILE *fp; | |
WORD buf; | |
BYTE count; | |
} bitstream; | |
void initbits(bitstream *,FILE *); | |
int getbit(bitstream *); | |
/*---------------------*/ | |
/* decompressor routine */ | |
int unpack(FILE *ifile,FILE *ofile){ | |
const int I16_FF00 = -0x0100; | |
const int I16_E000 = -0x2000; | |
int len; | |
int span; | |
long fpos; | |
bitstream bits; | |
static BYTE data[0x4500], *p=data; | |
fpos=((long)ihead[0x0b]-(long)inf[4]+(long)ihead[4])<<4; | |
fseek(ifile,fpos,SEEK_SET); | |
fpos=(long)ohead[4]<<4; | |
fseek(ofile,fpos,SEEK_SET); | |
initbits(&bits,ifile); | |
printf(" unpacking. "); | |
for(;;){ | |
if(ferror(ifile)) {printf("\nread error\n"); return(FAILURE); } | |
if(ferror(ofile)) {printf("\nwrite error\n"); return(FAILURE); } | |
if(p-data>0x4000){ | |
fwrite(data,sizeof data[0],0x2000,ofile); | |
p-=0x2000; | |
memcpy(data,data+0x2000,p-data); | |
putchar('.'); | |
} | |
if(getbit(&bits)) { | |
*p++=getc(ifile); | |
continue; | |
} | |
if(!getbit(&bits)) { | |
len=getbit(&bits)<<1; | |
len |= getbit(&bits); | |
len += 2; | |
span=getc(ifile) | I16_FF00; | |
} else { | |
span=(BYTE)getc(ifile); | |
len=getc(ifile); | |
span |= ((len & ~0x07)<<5) | I16_E000; | |
len = (len & 0x07)+2; | |
if (len==2) { | |
len=getc(ifile); | |
if(len==0) | |
break; /* end mark of compreesed load module */ | |
if(len==1) | |
continue; /* segment change */ | |
else | |
len++; | |
} | |
} | |
for( ;len>0;len--,p++){ | |
*p=*(p+span); | |
} | |
} | |
if(p!=data) | |
fwrite(data,sizeof data[0],p-data,ofile); | |
loadsize=ftell(ofile)-fpos; | |
printf("end\n"); | |
return(SUCCESS); | |
} | |
/* write EXE header*/ | |
void wrhead(FILE *ofile) { | |
int i; | |
if(ihead[6]!=0) { | |
ohead[5]-= inf[5] + ((inf[6]+16-1)>>4) + 9; /* v0.7 */ | |
if(ihead[6]!=0xffff) | |
ohead[6]-=(ihead[5]-ohead[5]); | |
} | |
ohead[1]=((WORD)loadsize+(ohead[4]<<4)) & 0x1ff; /* v0.7 */ | |
ohead[2]=(WORD)((loadsize+((long)ohead[4]<<4)+0x1ff) >> 9); /* v0.7 */ | |
fseek(ofile,0L,SEEK_SET); | |
for(i=0; i<0x0e; ++i) putw(ohead[i], ofile); | |
} | |
/*-------------------------------------------*/ | |
/* get compress information bit by bit */ | |
void initbits(bitstream *p,FILE *filep){ | |
p->fp=filep; | |
p->count=0x10; | |
p->buf=getw(filep); | |
/* printf("%04x ",p->buf); */ | |
} | |
int getbit(bitstream *p) { | |
int b; | |
b = p->buf & 1; | |
if(--p->count == 0){ | |
(p->buf)=getw(p->fp); | |
/* printf("%04x ",p->buf); */ | |
p->count= 0x10; | |
}else | |
p->buf >>= 1; | |
return b; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
a private modification of unlzexe
reference:
unlzexe 0.5 https://www.vector.co.jp/soft/dos/util/se005117.html
unlzexe 0.8 https://www.vector.co.jp/soft/dos/util/se000341.html
other ports:
OpenBSD http://files.shikadi.net/malv/files/unlzexe.c
C++ verion https://github.com/gerstrong/Commander-Genius/blob/master/tools/unlzexe/unlzexe.cpp