AxibugEmuOnline/References/VirtuaNESex_src_191105/Archive.cpp
2024-08-05 17:58:53 +08:00

333 lines
7.7 KiB
C++

//
// アーカイブファイル操作
//
// Original:NesterJ arc.cpp arc.h by Mikami Kana
// Original:NNNesterJ ulunzip.cpp
//
// Zlib use!
// Reprogrammed by Norix
//
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mbstring.h>
#include <time.h>
#include "typedef.h"
#include "macro.h"
#include "DebugOut.h"
#include "App.h"
#include "Pathlib.h"
#include "VirtuaNESres.h"
#define UNZ_BUFSIZE (65536)
#include "unzip.h"
#ifdef __cplusplus
extern "C" {
#endif
int SevenZipUnCompress( char *fname, unsigned char ** ppBuf,size_t * lpdwSize);
#ifdef __cplusplus
}
#endif
#pragma pack(1)
#define FNAME_MAX32 512
typedef struct {
DWORD dwOriginalSize;
DWORD dwCompressedSize;
DWORD dwCRC;
UINT uFlag;
UINT uOSType;
WORD wRatio;
WORD wDate;
WORD wTime;
char szFileName[FNAME_MAX32 + 1];
char dummy1[3];
char szAttribute[8];
char szMode[8];
} INDIVIDUALINFO, *LPINDIVIDUALINFO;
#pragma pack()
// Un??? use function
typedef int(WINAPI *EXECUTECOMMAND)(HWND,LPCSTR,LPSTR,const DWORD);
typedef BOOL(WINAPI *CHECKARCHIVE)(LPCSTR,const int);
typedef int(WINAPI *EXTRACTMEM)(HWND,LPCSTR,LPBYTE,const DWORD,time_t,LPWORD,LPDWORD);
typedef HGLOBAL(WINAPI *OPENARCHIVE)(HWND,LPCSTR,const DWORD);
typedef int(WINAPI *CLOSEARCHIVE)(HGLOBAL);
typedef int(WINAPI *FINDFIRST)(HGLOBAL,LPCSTR,INDIVIDUALINFO*);
static LPCSTR pszArchiver[] = {
"UNLHA32",
"UNZIP32",
"UNRAR32",
"CAB32",
NULL
};
static LPCSTR pszFuncPrefix[] = {
"Unlha",
"UnZip",
"Unrar",
"Cab",
};
static LPCSTR pszCommand[] = {
NULL,
NULL,
"-e -u \"%s\" \"%s\" \"%s\"",
"-x -j \"%s\" \"%s\" \"%s\"",
};
static LPCSTR pszExtension[] = {
"*.nes",
"*.fds",
"*.nsf",
NULL
};
static BOOL bFileMatching[] = {
FALSE,
TRUE,
FALSE,
FALSE,
};
#define FREEDLL(h) if( h ) { FreeLibrary(h);h=NULL; }
#define M_ERROR_MESSAGE_OFF 0x00800000L
// zlibを使用したZIP解凍ルーチン
BOOL ZlibUnZip( LPCSTR fname, LPBYTE* ppBuf, LPDWORD lpdwSize )
{
unzFile unzipFile = NULL;
unz_global_info unzipGlobalInfo;
unz_file_info unzipFileInfo;
char fname_buf[256];
*ppBuf = NULL;
*lpdwSize = 0;
if( !(unzipFile = unzOpen( (const char*)fname )) )
return FALSE;
if( unzGetGlobalInfo( unzipFile, &unzipGlobalInfo ) != UNZ_OK ) {
unzClose( unzipFile );
return FALSE;
}
for( uLong i = 0; i < unzipGlobalInfo.number_entry; i++ ) {
if( unzGetCurrentFileInfo( unzipFile, &unzipFileInfo, fname_buf, sizeof(fname_buf), NULL, 0, NULL, 0 ) != UNZ_OK )
break;
char* pExt = ::PathFindExtension( fname_buf );
if( _stricmp( pExt, ".nes" ) == 0 || _stricmp( pExt, ".fds" ) == 0 || _stricmp( pExt, ".nsf" ) == 0 ) {
if( unzipFileInfo.uncompressed_size ) {
if( unzOpenCurrentFile( unzipFile ) != UNZ_OK )
break;
if( unzipFileInfo.uncompressed_size > 0 ) {
if( !(*ppBuf = (LPBYTE)::malloc( unzipFileInfo.uncompressed_size )) )
break;
uInt size = unzReadCurrentFile( unzipFile, *ppBuf, unzipFileInfo.uncompressed_size );
if( size != unzipFileInfo.uncompressed_size )
break;
}
*lpdwSize = unzipFileInfo.uncompressed_size;
if( unzCloseCurrentFile( unzipFile ) != UNZ_OK )
break;
unzClose( unzipFile );
return TRUE;
}
}
// Next file
if( (i+1) < unzipGlobalInfo.number_entry ) {
if( unzGoToNextFile( unzipFile ) != UNZ_OK ) {
break;
}
}
}
FREE( *ppBuf );
if( unzipFile ) {
unzCloseCurrentFile( unzipFile );
unzClose( unzipFile );
}
return FALSE;
}
BOOL UnCompress( LPCSTR fname, LPBYTE* ppBuf, LPDWORD lpdwSize )
{
HMODULE hDLL;
INDIVIDUALINFO idvinfo;
char* pExt = ::PathFindExtension( fname );
if( _stricmp( pExt, ".zip" ) == 0 ) {
// ZIPならまずzlibライブラリの解凍を使ってみる
if( ZlibUnZip( fname, ppBuf, lpdwSize ) ) {
// DEBUGOUT( "zlib unzip ok! [%s]\n", fname );
return TRUE;
}
} else if( _stricmp( pExt, ".7z" ) == 0 ) {
return SevenZipUnCompress((char*)fname, ppBuf, (size_t*)lpdwSize);
}
hDLL = NULL;
for( INT i = 0; pszArchiver[i]; i++ ) {
// DLLアンロード
FREEDLL( hDLL );
// DLLロード
if( !(hDLL = LoadLibrary( pszArchiver[i] )) )
continue;
CHAR szTemp[256];
sprintf( szTemp, "%sCheckArchive", pszFuncPrefix[i] );
CHECKARCHIVE CheckArchive;
if( !(CheckArchive = (CHECKARCHIVE)GetProcAddress( hDLL, szTemp )) )
continue;
// 対応するアーカイブかチェックする
if( !CheckArchive( fname, 1 ) )
continue;
// アーカイブ内に対応するファイルがあるかのチェック
OPENARCHIVE OpenArchive;
CLOSEARCHIVE CloseArchive;
FINDFIRST FindFirst;
sprintf( szTemp, "%sOpenArchive", pszFuncPrefix[i] );
OpenArchive = (OPENARCHIVE)GetProcAddress( hDLL, szTemp );
sprintf( szTemp, "%sFindFirst", pszFuncPrefix[i] );
FindFirst = (FINDFIRST)GetProcAddress( hDLL, szTemp );
sprintf( szTemp, "%sCloseArchive", pszFuncPrefix[i] );
CloseArchive = (CLOSEARCHIVE)GetProcAddress( hDLL, szTemp );
HGLOBAL hARC;
BOOL bFound = FALSE;
for( INT j = 0; pszExtension[j]; j++ ) {
if( !(hARC = OpenArchive( NULL, fname, M_ERROR_MESSAGE_OFF ) ) ) {
CloseArchive( hARC );
break;
}
INT ret = FindFirst( hARC, pszExtension[j], &idvinfo );
CloseArchive( hARC );
if( ret == 0 ) { // Found!!
bFound = TRUE;
break;
} else if( ret == -1 ) { // Not found.
} else { // 異常終了
break;
}
}
if( !bFound )
continue;
if( !pszCommand[i] ) {
// メモリ解凍あり(UNLHA32,UNZIP32)
*lpdwSize = idvinfo.dwOriginalSize;
*ppBuf = (LPBYTE)malloc( *lpdwSize );
CHAR szCmd [256];
CHAR szFunc[256];
if( !bFileMatching[i] ) {
sprintf( szCmd, "\"%s\" \"%s\"", fname, idvinfo.szFileName );
} else {
// UNZIP32 only
BYTE szFile[FNAME_MAX32+1];
LPBYTE lpF0, lpF1;
// 正規表現を切るオプションが欲しかった....
lpF0 = (LPBYTE)idvinfo.szFileName;
lpF1 = szFile;
while( *lpF0 ) {
if( *lpF0 == '[' || *lpF0 == ']' ) {
*lpF1++ = '\\';
}
_mbsncpy( lpF1, lpF0, 1 );
lpF0 = _mbsinc( lpF0 );
lpF1 = _mbsinc( lpF1 );
}
*lpF1 = '\0';
sprintf( szCmd, "\"%s\" \"%s\"", fname, szFile );
}
sprintf( szFunc, "%sExtractMem", pszFuncPrefix[i] );
EXTRACTMEM ExtractMem;
ExtractMem = (EXTRACTMEM)GetProcAddress( hDLL, szFunc );
INT ret = ExtractMem( NULL, szCmd, (LPBYTE)(*ppBuf), *lpdwSize, NULL, NULL, NULL );
FREEDLL( hDLL );
if( ret == 0 )
return TRUE;
} else {
// メモリ解凍が無い場合
CHAR szCmd [256];
CHAR szTempPath[_MAX_PATH];
EXECUTECOMMAND ExecuteCommand;
GetTempPath( _MAX_PATH, szTempPath );
//DEBUGOUT( "TempPath:%s\n", szTempPath );
sprintf( szCmd, pszCommand[i], fname, szTempPath, idvinfo.szFileName );
ExecuteCommand = (EXECUTECOMMAND)GetProcAddress( hDLL, pszFuncPrefix[i] );
ExecuteCommand( NULL, szCmd, NULL, 0 );
FREEDLL( hDLL );
string FileName = CPathlib::MakePath( szTempPath, idvinfo.szFileName );
FILE *fp = NULL;
if( (fp = fopen( FileName.c_str(), "rb" )) ) {
// ファイルサイズ取得
fseek( fp, 0, SEEK_END );
*lpdwSize = ftell( fp );
fseek( fp, 0, SEEK_SET );
if( *lpdwSize < 17 ) {
// ファイルサイズが小さすぎます
throw CApp::GetErrorString( IDS_ERROR_SMALLFILE );
}
// テンポラリメモリ確保
if( !(*ppBuf = (LPBYTE)malloc( *lpdwSize )) ) {
FCLOSE( fp );
// メモリを確保出来ません
throw CApp::GetErrorString( IDS_ERROR_OUTOFMEMORY );
}
// サイズ分読み込み
if( fread( *ppBuf, *lpdwSize, 1, fp ) != 1 ) {
FCLOSE( fp );
FREE( *ppBuf );
// ファイルの読み込みに失敗しました
throw CApp::GetErrorString( IDS_ERROR_READ );
}
FCLOSE( fp );
DeleteFile( FileName.c_str() );
} else {
// xxx ファイルを開けません
LPCSTR szErrStr = CApp::GetErrorString( IDS_ERROR_OPEN );
sprintf( szErrorString, szErrStr, fname );
throw szErrorString;
}
return TRUE;
}
}
FREEDLL( hDLL );
return FALSE;
}
// Archive