#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;
}