// // アーカイブファイル操作 // // Original:NesterJ arc.cpp arc.h by Mikami Kana // Original:NNNesterJ ulunzip.cpp // // Zlib use! // Reprogrammed by Norix // #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #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