Artifact Content

Not logged in

Artifact f2120072ecb51fca5030df67ba55212e29a69ab8



#include "stdafx.h"
#include "CabTool.h"
#include "kiutil.h"
#include "fdi/fdi.h"
#include "kilib/kilib.h"

// 無理矢理SFXも解凍
static int seeker=0;
static int offhan=-1;
static int offhan2=-1;
static const char* sdll;
static kiPath* sdllr;

// CallBack 定義
static FNALLOC(mymalloc)
{
	return (void*)new BYTE[cb];
}
static FNFREE(mymfree)
{
	delete [] (BYTE*)pv;
}
static FNOPEN(myfopen)
{
	int han=_open( pszFile, oflag, pmode );
	if( han!=-1 && seeker!=0 && !(oflag&_O_WRONLY) )
	{
		_lseek( han,seeker,SEEK_SET );
		if( offhan==-1 )offhan=han;
		else if( offhan2==-1 )offhan2=han;
	}
	return han;
}
static FNREAD(myfread)
{
	return _read( hf, pv, cb );
}
static FNWRITE(myfwrite)
{
	return _write( hf, pv, cb );
}
static FNCLOSE(myfclose)
{
	if( hf==offhan )offhan=-1;
	else if( hf==offhan2 )offhan2=-1;
	return _close(hf);
}
static FNSEEK(myfseek)
{
	if( hf==offhan || hf==offhan2 )
	{
		if( seektype==SEEK_SET )
			return _lseek( hf, dist+seeker, SEEK_SET ) - seeker;
		return _lseek( hf, dist, seektype ) - seeker;
	}
	return _lseek( hf, dist, seektype );
}
static FNFDINOTIFY(mynotif)
{
	switch( fdint )
	{
	case fdintCOPY_FILE:
		{
			char* name = kiutil::pathMake(pfdin->psz1);
			if( 0==strcmpi( kiPath::name(name), sdll ) ) // DLLの位置を記憶
				*sdllr = name;

			return myfopen( name,
				_O_BINARY|_O_CREAT|_O_TRUNC|_O_WRONLY|_O_SEQUENTIAL,
				_S_IREAD|_S_IWRITE );
		}

	case fdintCLOSE_FILE_INFO:
		myfclose( pfdin->hf );
		kiutil::timeSet( pfdin->psz1, pfdin->date, pfdin->time );
		SetFileAttributes( pfdin->psz1,
			pfdin->attribs&(_A_RDONLY| _A_HIDDEN|_A_SYSTEM|_A_ARCH) );
		return TRUE;
	}
	return 0;
}

int CCabTool::FindHeader( const char* fname, const BYTE* hdr, DWORD siz )
{
	// FDI初期化
	FDICABINETINFO info;
	ERF erf;
	HFDI fdi=FDICreate( mymalloc,mymfree,myfopen,myfread,
					myfwrite,myfclose,myfseek,cpuUNKNOWN,&erf );
	if( fdi==NULL )
		return false;

	// 開く
	int ans=-1, han=myfopen( const_cast<char*>(fname),
					_O_BINARY|_O_RDONLY|_O_SEQUENTIAL,0 );

	// ヘッダ検索
	if( -1!=han )
	{
		if( siz>10 && hdr[0]=='M' && hdr[1]=='Z' )
		{
			for( DWORD i=2; i<siz; i++ )
				if( hdr[i+0]=='M' && hdr[i+1]=='S' && hdr[i+2]=='C' &&
					hdr[i+3]=='F' && hdr[i+4]== 0  && hdr[i+5]== 0  &&
					hdr[i+6]== 0  && hdr[i+7]==0 )
				{
					myfseek( han,i,SEEK_SET );
					if( FDIIsCabinet(fdi,han,&info) )
					{
						ans=i;
						break;
					}
				}
		}
		else
		{
			if( FDIIsCabinet( fdi,han,&info ) )
				ans = 0;
		}
		myfclose(han);
	}

	FDIDestroy( fdi );
	return ans;
}

bool CCabTool::Extract( const char* aname, const char* dll, kiPath& dll_rel_path )
{
	sdll = dll, sdllr = &dll_rel_path;

	// ヘッダを探す
	FILE* fp = fopen( aname,"rb" );
	if( !fp )
		return false;
	unsigned char* buff = new unsigned char[128<<10];
	DWORD siz = fread( buff, 1, 128<<10, fp );
	fclose( fp );

	seeker = 0;
	seeker = FindHeader( aname,buff,siz );
	delete [] buff;
	if( seeker==-1 )
		return false;

	// FDI初期化
	ERF erf;
	HFDI fdi=FDICreate( mymalloc,mymfree,myfopen,myfread,
					myfwrite,myfclose,myfseek,cpuUNKNOWN,&erf );
	if( fdi==NULL )
		return false;

	// FDIに渡すためにファイル名分割
	int y,d;
	kiutil::pathSplit( aname,&y,&d );

	char fbody[MAX_PATH], fdir[MAX_PATH]={0};
	strcpy( fbody,&aname[y+1] );
	if( y!=-1 )
		strncpy( fdir,aname,y+1 );

	// 展開
	BOOL ans=FDICopy( fdi,fbody,fdir,0,mynotif,NULL,NULL );

	// 終了
	FDIDestroy(fdi);
	return ans!=FALSE;
}