⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imptool.cpp

📁 一个解压程序,只要设定了解压路径和解压文件的种类,就可以随意解压
💻 CPP
📖 第 1 页 / 共 2 页
字号:

#include "stdafx.h"
#include "ImpTool.h"

/*IMP_DIR_ENTRY flags*/
#define DFLAG_DIR 1
#define DFLAG_E8SHORT 2
#define DFLAG_E8LONG 4

/*IMP_HEADER flags*/
#define HFLAG_MULTIVOL 1
#define HFLAG_LASTVOL 2
#define HFLAG_BLOWFISH 4

/*methods*/
#define METHOD_STORE 0
#define METHOD_LZ77 1
#define METHOD_BWT 2
#define METHOD_LZ77_MM 3

/*LZ77*/
#define NLLCODES 288 /* Number of literal-length codes */
#define NDCODES 42   /* Number of distance codes */
#define ND2CODES 14  /* Number of distance codes for length==2 */
#define ND3CODES 28  /* Number of distance codes for length==3 */
#define MIN_LZ_CODES (NLLCODES+NDCODES+ND2CODES)
#define LONGMATCHBITS 15  /*extra bits for long match*/
#define LONGMATCHMASK ((1<<LONGMATCHBITS)-1)
#define LONGMATCHCODE (NLLCODES-2)
#define MMCODE (NLLCODES-1) /*multimedia code*/
#define LLTTBITS 9
#define DTTBITS 7
#define LLTTSIZE (1<<LLTTBITS)
#define DTTSIZE (1<<DTTBITS)
#define MAX_MM_CODES 1024

/*BWT*/
#define NCODES 258
#define WINDOW 50
#define BWTABLES 6
#define BWTTBITS 9
#define BWTTSIZE (1<<BWTTBITS)

#define MAX_NCODES NLLCODES
#define MAXCODELEN 16
#define NLENCODES (MAXCODELEN+5) /* no. of code length codes */
#define ZRUN (MAXCODELEN+1) /* run of zeros */
#define DZRUN (MAXCODELEN+3)/* run of delta-zeros*/
#define HC_MCL 14    /* max code length for storing Huffman codes */
#define HCTTBITS 6
#define HCTTSIZE (1<<HCTTBITS)

#define USEDBITS(n) {bitpos-=n;bitbuf>>=n;}

//////////////////////////////////////////////////////////////

bool CImpTool::Check( const char* fname, unsigned long fsize )
{
	const unsigned char* hdr = CTool::common_buf;
	unsigned long siz = (fsize>XACR_BUFSIZE ? XACR_BUFSIZE : fsize);
//--------------------------------------------------------------------//

	// 彫偝偡偓
	if( siz<IMP_HEADER_SIZE )
		return false;

	// IMP側傜CRC僠僃僢僋
	if( hdr[0]=='I' && hdr[1]=='M' && hdr[2]=='P' && hdr[3]=='\n' )
		return HeaderCheck( hdr );

	// EXE側傜僿僢僟扵偟
	if( hdr[0]=='M' && hdr[1]=='Z' )
	{
		const unsigned char* src = hdr+2;
		const unsigned char* end
			= hdr+(siz>32768 ? 32768 : siz)-IMP_HEADER_SIZE+1;
		do
		{
			while(src!=end)
				if( *(src++)=='I' )
					break;
			if( src==end )return false;
			if( src[0]=='M' && src[1]=='P' && src[2]=='\n' )
				if( HeaderCheck(src-1) )
					return true;
			src++;
		}while( src<end );
		return false;
	}

	return false;
}

bool CImpTool::Extract( const char* fname,const char* ddir )
{
	imp = fopen(fname,"rb");
	if( imp==NULL )return false;

	if( !ReadImpHead() )
		{fclose(imp);return false;}
	if(ih.flags&HFLAG_MULTIVOL)
		{fclose(imp);return false;}
	if(ih.flags&HFLAG_BLOWFISH)
		{fclose(imp);return false;}

	g_blockbuffer=0;g_prevfpos=0xffffffff;
	dirbufsrc = dirbufend = dirbuf;

	char outname[MAX_PATH], *name;
	char tmpname[MAX_PATH]; //by uema2.
	IMP_DIR_ENTRY dirent;
	for( unsigned long ent=0; ent!=ih.direntries; ent++ )
	{
		if( !get_dir_entry(&dirent,outname) )
			return false;

		sprintf(tmpname, "%s\\%s", ueutil::GetExtractPath(),
			name=kiutil::pathMake(outname)); // by uema2.
		strcpy(name, tmpname);
//		name = kiutil::pathMake( outname );

		if( dirent.flags&DFLAG_DIR )continue;
		out = fopen( name,"wb" );
		if( !out ) continue;

		decomp( out, dirent.fpos,
			dirent.unitpos, dirent.esize, dirent.flags );
		fclose( out );

		kiutil::timeSet( name,(WORD)(dirent.mdate),(WORD)dirent.mtime );
		//name傪t_name(TCHAR)偵 by uema2.
		TCHAR *t_name = (TCHAR*)LocalAlloc(LPTR, (strlen(name)+1)*sizeof(TCHAR));
		_MultiByteToWideChar(CP_ACP, 0, name, strlen(name)+1,
			t_name, strlen(name)+1);
//		SetFileAttributes( name,dirent.attrib );
		SetFileAttributes( t_name,dirent.attrib );
		LocalFree(t_name);
	}

	return true;
}


/********************************/
static const int g_ncodes[3]={NDCODES,ND2CODES,ND3CODES},
				 g_ncoffset[3]={NLLCODES,NLLCODES+NDCODES,NLLCODES+NDCODES+ND2CODES};
static const unsigned long g_overlaps[3][8]=
   {{32768,65536,73728,98304,122880,147456,172032,196608}, /*normal*/
    {32768,65536,73728,98304,122880,147456,172032,196608}, /*normal*/
    {32768,131072,196608,262144,327680,393216,458752,524288}}; /*best*/

bool CImpTool::ReadImpHead()
{
	unsigned char ihbuf[IMP_HEADER_SIZE];
	g_exesize=0;

	// 僿僢僟暘撉傓
	if( IMP_HEADER_SIZE!=fread(ihbuf,1,IMP_HEADER_SIZE,imp) )
		return false;

	// IMP側傜CRC僠僃僢僋
	if( ihbuf[0]=='I' && ihbuf[1]=='M' && ihbuf[2]=='P' && ihbuf[3]=='\n' )
	{if( !HeaderCheck(ihbuf) )return false;}
	// EXE側傜僿僢僟扵偟
	else if( ihbuf[0]=='M' && ihbuf[1]=='Z' )
	{
		unsigned char *buffer=new unsigned char[32768],*src,*end;
		int nread = fread(buffer,1,32768,imp);
		if( nread<IMP_HEADER_SIZE )return false;
		src=buffer;
		end=buffer+nread-IMP_HEADER_SIZE+1;
		do
		{
			while(src!=end)
				if( *(src++)=='I' )
					break;
			if( src==end )return false;
			if( src[0]=='M' && src[1]=='P' && src[2]=='\n' )
				if( HeaderCheck(src-1) )
				{
					g_exesize = src-1-buffer+IMP_HEADER_SIZE;
					memcpy(ihbuf,src-1,IMP_HEADER_SIZE);
					break;
				}
			src++;
		}while( src<end );
		if( src>=end )return false;
		delete [] buffer;
	}
	// 偱側偗傝傖幐攕
	else
		return false;

	// 撉傓
	ih.diroffset = ihbuf[ 4] + (ihbuf[ 5]<<8) + (ihbuf[ 6]<<16) + (ihbuf[ 7]<<24);
	ih.direntries= ihbuf[ 8] + (ihbuf[ 9]<<8) + (ihbuf[10]<<16) + (ihbuf[11]<<24);
	ih.cmoffset  = ihbuf[16] + (ihbuf[17]<<8) + (ihbuf[18]<<16) + (ihbuf[19]<<24);
	ih.flags     = ihbuf[38] + (ihbuf[39]<<8);
	ih.crc       = ihbuf[40] + (ihbuf[41]<<8);

	dirfpos=ih.diroffset+g_exesize;
	return true;
}

bool CImpTool::HeaderCheck(const unsigned char* p)
{
	const unsigned char dm[2]={0,0};
	DWORD crc=0xffffffff;

	crc = calc_crc( p,40,crc );
	crc = calc_crc( dm,2,crc );

	return ((~crc)&0xffff) == (unsigned)(p[40]|(p[41]<<8));
}

bool CImpTool::get_dir_entry( IMP_DIR_ENTRY *pdirent,char *name )
{
	if( dirbufsrc >= dirbufend )
		if( !extract_dir() )
			return false;
	if( dirbufend-dirbufsrc<IMP_DIR_ENTRY_SIZE )
		return false;

	pdirent->ver	= dirbufsrc[0] + (dirbufsrc[1]<<8);
	pdirent->fpos	= dirbufsrc[4] + (dirbufsrc[5]<<8) + (dirbufsrc[6]<<16) + (dirbufsrc[7]<<24);
	pdirent->commlen= dirbufsrc[10];
	pdirent->flags	= dirbufsrc[11];
	pdirent->unitpos= dirbufsrc[12] + (dirbufsrc[13]<<8) + (dirbufsrc[14]<<16) + (dirbufsrc[15]<<24);
	pdirent->esize	= dirbufsrc[16] + (dirbufsrc[17]<<8) + (dirbufsrc[18]<<16) + (dirbufsrc[19]<<24);
	pdirent->crc	= dirbufsrc[20] + (dirbufsrc[21]<<8) + (dirbufsrc[22]<<16) + (dirbufsrc[23]<<24);
	pdirent->extra	= dirbufsrc[24] + (dirbufsrc[25]<<8);
	pdirent->namelen= dirbufsrc[26] + (dirbufsrc[27]<<8);
	pdirent->mtime	= dirbufsrc[32] + (dirbufsrc[33]<<8);
	pdirent->mdate	= dirbufsrc[34] + (dirbufsrc[35]<<8);
	pdirent->entcrc	= dirbufsrc[36] + (dirbufsrc[37]<<8);

	if( (pdirent->ver&0xfff)>0x10A/*MAX_VERSION*/ )
		return false;
	int i=IMP_DIR_ENTRY_SIZE+pdirent->namelen+pdirent->commlen+pdirent->extra;
	if( dirbufend-dirbufsrc<i )
		return false;
	dirbufsrc[36]=0;
	dirbufsrc[37]=0;
	if( (~calc_crc(dirbufsrc,i,0xffffffff)&0xffff)!=pdirent->entcrc )
		return false;
	memcpy( name,dirbufsrc+IMP_DIR_ENTRY_SIZE,pdirent->namelen );
	name[ pdirent->namelen ]=0;
//	for(char*p=name;*p;p=CharNext(p))if(*p=='/')*p='\\';
	for(char*p=name;*p;p=ueutil::CharNext(p))if(*p=='/')*p='\\'; // by uema2.

	dirbufsrc+=i;
	return true;
}

bool CImpTool::extract_dir()
{
	int i,method;
	unsigned long csize,exsize;
	unsigned char sig[6];
	static const unsigned char dirsig[]={0x49,0x4D,0x50,0x44,0x45,0};
 
	unsigned long fpos=ftell(imp);
	fseek( imp,dirfpos,SEEK_SET );

	dirbufsrc=dirbuf;
	dirbufend=dirbuf;
	if( 6!=fread(sig,1,6,imp) )		return false;
	if( 0!=memcmp(sig,&dirsig,6) )	return false;

	init_getbits();
	method=getbits(5)&15;
	USEDBITS(5);
	if(method>METHOD_LZ77)return false;
	exsize=getbits(20)&((1L<<20)-1);
	USEDBITS(20);
	if(exsize>8192)return false;
	csize=getbits(20)&((1L<<20)-1);
	USEDBITS(20);
	if(method==METHOD_LZ77)
	{
		USEDBITS(5);
		i=expand_lz((unsigned char*)dirbuf,0,exsize,0);
	}
	else i=unstore((unsigned char*)dirbuf,exsize);
	dirfpos+=6+csize;

	fseek( imp,fpos,SEEK_SET );
	dirbufend+=i;
	return true;
}

void CImpTool::init_getbits()
{
	dcsrc=dcend=dcbuffer;
	bitpos=0;
	bitbuf=0;
}

unsigned long CImpTool::getbits(int nbits)
{
	int iseof=0;
	if( nbits>bitpos )
		while( bitpos<25 )
		{
			if(dcsrc>=dcend)
			{
				dcsrc=dcbuffer;
				if(!iseof)
				{
					dcend=dcbuffer+fread(dcbuffer,1,sizeof(dcbuffer),imp);
					iseof=feof(imp);
				}
			}
			bitbuf+=(*dcsrc++)<<bitpos;
			bitpos+=8;
		}
	return bitbuf;
}

int CImpTool::unstore(unsigned char *output,int size)
{
	fseek(imp,dcsrc-dcend-(bitpos>>3),SEEK_CUR);
	return fread(output,1,size,imp);
}

int CImpTool::decomp( FILE *outfile,unsigned long fpos,unsigned long unitpos,unsigned long togo,unsigned char flags)
{
	unsigned char lhbuf[LOCAL_HEADER_SIZE];
	unsigned short namelen;
	int i,lhptr,nameptr;
	unsigned long method,level,ovlevel;
	int nread,written;
	unsigned long overlap,e8offset,srcsize,block_csize;
	unsigned char *blocksrc;
 
	if(!togo){g_crc=0;return 0;}
	g_crc=0xFFFFFFFF;
	g_e8extra=0;
	srcsize=togo;
	e8offset=0;
	g_exlast=0;
	lhptr=0;nameptr=0;
	g_e8t=0;
	if(flags&DFLAG_E8SHORT)g_e8t=2;
	else if(flags&DFLAG_E8LONG)g_e8t=4;
	fpos+=6+g_exesize;
	if(fpos!=g_prevfpos || unitpos<g_unitoffset)
	{
		g_blockstart=0;
		g_blocksize=0;
		g_exlast=0;
		g_exprev=0;
		g_unitoffset=0;
		g_exerror=0;
		g_mmptr=0;
		g_prevfpos=fpos;
		fseek(imp,fpos,SEEK_SET);
		if(g_blockbuffer){delete [] g_blockbuffer;g_blockbuffer=NULL;}
	}

	while(togo)
	{
		if(g_exerror)return -3;
		if(unitpos<g_unitoffset+g_blocksize)
		{
			blocksrc=g_blockbuffer+g_blockstart+unitpos-g_unitoffset;
			nread=g_blocksize-(unitpos-g_unitoffset);
			if(lhptr<LOCAL_HEADER_SIZE)
			{
				i=LOCAL_HEADER_SIZE-lhptr;
				if(i>nread)i=nread;
				memcpy(lhbuf+lhptr,blocksrc,i);
				lhptr+=i;
				unitpos+=i;
				nread-=i;
				if(lhptr<LOCAL_HEADER_SIZE)continue;
			}
			namelen=lhbuf[4]+(lhbuf[5]<<8);
			if(nameptr<namelen)
			{
				i=namelen-nameptr;
				if(i>nread)i=nread;
				nameptr+=i;
				unitpos+=i;
				continue;
			}
			if((unsigned)nread>togo)nread=togo;
			if(!g_e8t)
			{
				g_crc=calc_crc(blocksrc,nread,g_crc);
				written=fwrite(blocksrc,1,nread,outfile);
			}
			else
			{
				i=e8ut_crc_write(outfile,blocksrc,nread,e8offset,srcsize,(unsigned)nread==togo);
				if(i<0)return i;
				written=nread;
				e8offset+=nread;
			}
			togo-=nread;
			unitpos+=nread;
		}
		if(togo)
		{
			g_exerror=1;
			if(g_exlast)return 0;
			g_blockstart+=g_blocksize;
			g_unitoffset+=g_blocksize;
			fpos=ftell(imp);
			init_getbits();
			method=getbits(4)&15;
			USEDBITS(4);
			if(method>METHOD_LZ77_MM)return -3;
			g_exlast=(unsigned char)getbits(1)&1;
			USEDBITS(1);
			g_blocksize=getbits(20)&((1L<<20)-1);
			USEDBITS(20);
			block_csize=getbits(20)&((1L<<20)-1);
			USEDBITS(20);
			if(!g_blockbuffer)
			{
				g_exmemory=g_blocksize+512;
				g_blockbuffer=new unsigned char[g_exmemory];
			}
			if(method==METHOD_LZ77 || method==METHOD_LZ77_MM)
			{
				if(g_exprev)
				{
					level=getbits(2)&3;
					USEDBITS(2);
					if(level>2)return -3;
					ovlevel=getbits(3)&7;
					USEDBITS(3);
					overlap=g_overlaps[level][ovlevel];
					redo_mm(overlap);
					if(g_blockstart>overlap)
					{
						memmove(g_blockbuffer,g_blockbuffer+g_blockstart-overlap,overlap);
						g_blockstart=overlap;
					}
					if(g_blocksize+g_blockstart>g_exmemory)
					{
						unsigned long old_ex = g_exmemory;
						g_exmemory=g_blocksize+g_blockstart+512;
						unsigned char *t = new unsigned char[g_exmemory];
						memcpy(t,g_blockbuffer,old_ex);
						g_blockbuffer=t;
					}
				}
				else USEDBITS(5);
				written=expand_lz(g_blockbuffer,g_blockstart,g_blocksize,1);
				if(written<0)return written;
				if((unsigned long)written<g_blocksize){g_blocksize=(unsigned long)written;g_exlast=1;}
			}
			else
			{
				if(g_blocksize>g_exmemory)
				{
					unsigned long old_ex = g_exmemory;
					g_exmemory=g_blocksize+512;
					unsigned char *t = new unsigned char[g_exmemory];
					memcpy(t,g_blockbuffer,old_ex);
					g_blockbuffer=t;
				}
				if(!g_exlast)
				{
					overlap=524288-g_blocksize;
					if((int)overlap<0)overlap=0;
					else if(overlap>g_exmemory-g_blocksize)overlap=g_exmemory-g_blocksize;
					redo_mm(overlap);
					if(g_blockstart>overlap)
					{
						memmove(g_blockbuffer,g_blockbuffer+g_blockstart-overlap,overlap);
						g_blockstart=overlap;
					}
				}
				else g_blockstart=0;
				g_mmptr=0;
				if(method==METHOD_BWT)
				{
					i=expand_bwt(g_blockbuffer+g_blockstart,g_blocksize);
					if(i<0)return i;
				}
				else
				{
					i=unstore(g_blockbuffer+g_blockstart,g_blocksize);
					if(i<0)return i;
					if((unsigned long)i<g_blocksize){g_blocksize=(unsigned long)i;g_exlast=1;}
				}
			}
			fseek(imp,fpos+block_csize,SEEK_SET);
			g_exerror=0;
			g_exprev=1;
		}
	}
	g_crc=~g_crc;
	return 0;
}

int CImpTool::expand_bwt(unsigned char *output, int exsize)
{
 int count[257];
 unsigned char hclengths[BWTABLES][NCODES];
 unsigned long huffcodes[NCODES];
 int ttable[BWTABLES][BWTTSIZE];
 int hdchain[BWTABLES][NCODES][2];
 unsigned char mtf[256],treemtf[BWTABLES];
 unsigned long *links;
 unsigned char *dest,*output_end;
 int i,treenum,code,codes,numtrees;
 int rptbase,rpt,link,start;
 unsigned long hcode;
 unsigned char rc;
 
 rc=(unsigned char)getbits(8)&0xFF;
 USEDBITS(8);
 numtrees=getbits(3)&7;
 USEDBITS(3);
 if(numtrees<1)return -3;
 for(treenum=0;treenum<numtrees;treenum++)
  {
   i=load_hcodes(hclengths[treenum],NCODES,1,0);
   if(i<0)return i;
   make_codes(huffcodes,hclengths[treenum],NCODES);
   make_decode_tables(ttable[treenum],hdchain[treenum],huffcodes,hclengths[treenum],BWTTBITS,NCODES);
  }
 bitpos&=~7;
 for(i=0;i<256;i++)mtf[i]=i;
 for(i=0;i<BWTABLES;i++)treemtf[i]=i;
 memset(count,0,sizeof(count));
 rptbase=1;codes=WINDOW;
 dest=output;
 output_end=output+exsize+1;
 start=0; /*prevent crash from invalid data*/
 while(dest<output_end)
  {
   if(codes==WINDOW)
    {
     hcode=getbits(numtrees);
     code=0;
     while(hcode&1){hcode>>=1;code++;}
     if(code>=numtrees)return -3;
     USEDBITS(code+1);
     treenum=treemtf[code];
     if(code)
      {
       for(;code;code--)treemtf[code]=treemtf[code-1];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -