Artifact 1c734ac63ab4804070c22d394a9f79db988ce5a5
- File
src/qbga32.d
-
2015-05-05 06:49:05
- part of checkin
[9b639cf2d6]
on branch trunk
- Working version for update to 2.067.
The problem was __gshared. Replacing it with TLS fixed the issue. Remaining problem is that "hack.d"'s CloseHandle hack is not working anymore.
(user: kinaba) [annotate]
-
2015-05-05 06:49:05
- part of checkin
[9b639cf2d6]
on branch trunk
- Working version for update to 2.067.
import win32.windows; import std.string; import std.file; import util; import windll; import bga_melter; import qbga_gui; //---------------------------------------------------------------- // API転送処理 //---------------------------------------------------------------- WinDLL g_orig_dll = null; UINT WM_ARCEXTRACT; static this() { g_orig_dll = WinDLL.load( "_Bga32.DLL" ); WM_ARCEXTRACT = RegisterWindowMessage("wm_arcextract"); } static ~this() { g_orig_dll.close(); } template api(FnT) { FnT api( string name ) { return g_orig_dll.get_api!(FnT)( name ); } } //---------------------------------------------------------------- // 統合アーカイバAPI:転送 //---------------------------------------------------------------- extern(Windows) { int Bga( HWND a, immutable char* b, char* c, DWORD d ) { int r = Bga_impl( a, b.fromStringz() ); if( r < 0 ) // このダミーDLLでは処理できないコマンドだった時 return api!(typeof(&Bga))("Bga")(a,b,c,d); return r; } WORD QBgaGetVersion() { return 5; } WORD BgaGetVersion() { return api!(typeof(&BgaGetVersion))("BgaGetVersion")(); } BOOL BgaGetRunning() { return api!(typeof(&BgaGetRunning))("BgaGetRunning")(); } BOOL BgaCheckArchive( char* a, int b ) { return api!(typeof(&BgaCheckArchive))("BgaCheckArchive")(a,b); } BOOL BgaConfigDialog( HWND a, char* b, int c ) { return api!(typeof(&BgaConfigDialog))("BgaConfigDialog")(a,b,c); } int BgaGetFileCount( char* a ) { return api!(typeof(&BgaGetFileCount))("BgaGetFileCount")(a); } BOOL BgaQueryFunctionList( int a ) { return api!(typeof(&BgaQueryFunctionList))("BgaQueryFunctionList")(a); } alias void* HARC; HARC BgaOpenArchive( HWND a, char* b, DWORD c ) { return api!(typeof(&BgaOpenArchive))("BgaOpenArchive")(a,b,c); } int BgaCloseArchive( HARC a ) { return api!(typeof(&BgaCloseArchive))("BgaCloseArchive")(a); } alias void* LPINDIVIDUALINFO; int BgaFindFirst( HARC a, char* b, LPINDIVIDUALINFO c ) { return api!(typeof(&BgaFindFirst))("BgaFindFirst")(a,b,c); } int BgaFindNext( HARC a, LPINDIVIDUALINFO b ) { return api!(typeof(&BgaFindNext))("BgaFindNext")(a,b); } DWORD BgaGetArcOriginalSize( HARC a ) { return api!(typeof(&BgaGetArcOriginalSize))("BgaGetArcOriginalSize")(a); } DWORD BgaGetArcCompressedSize( HARC a ) { return api!(typeof(&BgaGetArcCompressedSize))("BgaGetArcCompressedSize")(a); } WORD BgaGetArcRatio( HARC a ) { return api!(typeof(&BgaGetArcRatio))("BgaGetArcRatio")(a); } BOOL BgaSetOwnerWindow( HWND a ) { BOOL r = api!(typeof(&BgaSetOwnerWindow))("BgaSetOwnerWindow")(a); if( r ) BgaSetOwnerWindow_impl(a); return r; } BOOL BgaClearOwnerWindow() { BOOL r = api!(typeof(&BgaClearOwnerWindow))("BgaClearOwnerWindow")(); BgaClearOwnerWindow_impl(); return r; } alias BOOL function(HWND,UINT,UINT,EXTRACTINGINFOEX*) ARCHIVERPROC; BOOL BgaSetOwnerWindowEx( HWND a, ARCHIVERPROC* b ) { BOOL r = api!(typeof(&BgaSetOwnerWindowEx))("BgaSetOwnerWindowEx")(a,b); if( r ) BgaSetOwnerWindowEx_impl(a,b); return r; } BOOL BgaKillOwnerWindowEx( HWND a ) { BOOL r = api!(typeof(&BgaKillOwnerWindowEx))("BgaKillOwnerWindowEx")(a); BgaClearOwnerWindow_impl(); return r; } alias void* UNLHA_WND_ENUMMEMBPROC; BOOL BgaSetEnumMembersProc( UNLHA_WND_ENUMMEMBPROC a ) { return api!(typeof(&BgaSetEnumMembersProc))("BgaSetEnumMembersProc")(a); } BOOL BgaClearEnumMembersProc() { return api!(typeof(&BgaClearEnumMembersProc))("BgaClearEnumMembersProc")(); } } //---------------------------------------------------------------- // 統合アーカイバAPI:実装( Bga ) //---------------------------------------------------------------- int Bga_impl( HWND wnd, string cmd_str ) { enum { UNSUPPORTED = -1 } // // コマンドライン解析 // string[] cmd = cmd_parse(cmd_str); // x以外のコマンドは扱わないで本物DLLに回します。注意点として: // > command はコマンドラインの最初の引数としてください。なお、command を省略 // > した場合は 'x' command が指定されたものとみなします。 if( cmd.length == 0 ) return UNSUPPORTED; if( cmd[0].length == 1 ) { if( 0 <= "adjlmnstvADJLMNSTV".indexOf(cmd[0][0]) ) return UNSUPPORTED; if( cmd[0][0]=='x' || cmd[0][0]=='X' ) cmd = cmd[1 .. $]; } // ※ この時点で、cmdにはcommandを除いた残りの引数が入っているはず // // スイッチ解析、引数解析 // bool all_attrs = false; // -a bool silent = false; // -i bool ignore_dir = false; // -j bool newfile_only = false; // -n bool force_overwrite = false; // -o bool recursive = false; // -r bool sanitize_path = true; string arc_name = null; string base_dir = null; string[] paths; foreach( string param ; cmd ) if( param[0] == '-' ) switch( param[1] ) { case 'a','A': all_attrs = true; break; case 'i','I': silent = true; break; case 'j','J': ignore_dir = true; break; case 'n','N': newfile_only = true; break; case 'o','O': force_overwrite = true; break; case 'r','R': recursive = true; break; default: break; } else if( arc_name is null ) { arc_name = param; } else if( base_dir is null ) { if( lastChar(param) == '\\' ) base_dir = param; else { char[] buf; buf.length = GetCurrentDirectoryA(0,null)+1; GetCurrentDirectoryA(buf.length, buf.ptr); base_dir = buf.ptr.fromStringz().idup; if( lastChar(base_dir) != '\\' ) base_dir ~= '\\'; } } else paths ~= param; // // 展開処理にGo! // ProgressDlg dlg = null; if( !do_ownerwnd_proc( OP_ARC_BEGIN, null, 0, arc_name ) ) return 0x8020; try { if( !silent && g_handler is null ) // -i / OwnerWndProc { dlg = new ProgressDlg( cast(DLGTEMPLATE*) g_orig_dll.load_dialog("#2025"), wnd ); dlg.set_arcname(arc_name); } string src_fname; // OwnerWndProc関係 BgaHeader cur_hdr; // OwnerWndProc関係 BgaAnswer handler( ref BgaHeader hdr ) { src_fname = hdr.fname; process_messages(); // paths if( paths.length > 0 ) { string fname = // -r (recursive ? hdr.fname[hdr.dir_name_len..$] : hdr.fname); foreach( string w ; paths ) if( wild_match( w, fname ) ) goto ok; return BgaAnswer.SkipIt; ok:; } // -a if( !all_attrs && (hdr.attrib&6) ) return BgaAnswer.SkipIt; // dialog if( dlg ) if( dlg.closed ) return BgaAnswer.Abort; else dlg.set_filename( hdr.fname[hdr.dir_name_len..$] ); // -j if( ignore_dir ) hdr.fname = hdr.fname[hdr.dir_name_len .. $]; // sanitize if( sanitize_path ) hdr.fname = check_path(hdr.fname); // base_dir hdr.fname = (base_dir ~ hdr.fname).dup; // -o if( !force_overwrite ) try { if( std.file.exists(hdr.fname) && std.file.isFile(hdr.fname) ) // -n if( newfile_only ) { if( newer_than(hdr.date,hdr.time,hdr.fname) ) return BgaAnswer.SkipIt; } else { int r = MessageBoxA( dlg?dlg.hwnd:wnd, toStringz("Overwrite "~hdr.fname~" ?"), "QBga32.dll", MB_YESNOCANCEL ); if( r == IDNO ) return BgaAnswer.SkipIt; if( r == IDCANCEL ) return BgaAnswer.Abort; } } catch {} cur_hdr = hdr; if( !do_ownerwnd_proc( OP_FILE_BEGIN, &cur_hdr, 0, src_fname ) ) return BgaAnswer.Abort; return BgaAnswer.MeltIt; } BgaAnswer progress_handler( int cur, int max ) { process_messages(); if( dlg ) if( dlg.closed ) return BgaAnswer.Abort; else dlg.set_pos( cast(real)(cur)/max ); if( !do_ownerwnd_proc( OP_FILE_MIDDLE, &cur_hdr, cur, src_fname ) ) return BgaAnswer.Abort; return BgaAnswer.MeltIt; } (new BgaMelter(arc_name)).start(&handler,&progress_handler); } catch( BgaMelterError e ) { return e.errcode; } finally { do_ownerwnd_proc( OP_ARC_END, null, 0, arc_name ); if( dlg ) dlg.close(); } return 0; } //---------------------------------------------------------------- // 統合アーカイバAPI:実装( SetOwnerWindow ) //---------------------------------------------------------------- align(1) struct EXTRACTINGINFO { DWORD dwFileSize; DWORD dwWriteSize; char szSourceFileName[512 + 1]; char dummy1[3]; char szDestFileName[512 + 1]; char dummy[3]; } align(1) struct EXTRACTINGINFOEX { EXTRACTINGINFO exinfo; DWORD dwCompressedSize; DWORD dwCRC; UINT uOSType; WORD wRatio; WORD wDate; WORD wTime; char szAttribute[8]; char szMode[8]; } HWND g_owner_window; extern(Windows) BOOL function(HWND,UINT,UINT,EXTRACTINGINFOEX*) g_handler; extern(Windows) BOOL noex_handler( HWND w,UINT m,UINT s, EXTRACTINGINFOEX* e ) { return !SendMessageA( w, m, s, cast(LPARAM) &e.exinfo ); } void BgaSetOwnerWindow_impl( HWND wnd ) { g_owner_window = wnd; g_handler = &noex_handler; } void BgaClearOwnerWindow_impl() { g_owner_window = null; g_handler = null; } void BgaSetOwnerWindowEx_impl( HWND wnd, ARCHIVERPROC* proc ) { g_owner_window = wnd; g_handler = *proc; } enum { OP_FILE_BEGIN, OP_FILE_MIDDLE, OP_ARC_END, OP_ARC_BEGIN } bool do_ownerwnd_proc( UINT uState, BgaHeader* hdr, int cur, string src_fname ) { if( g_handler is null ) return true; EXTRACTINGINFOEX ex; if( uState == OP_ARC_BEGIN || uState == OP_ARC_END ) { lstrcpynA( ex.exinfo.szSourceFileName.ptr, toStringz(src_fname), 512 ); } else { ex.exinfo.dwFileSize = hdr.original_size; ex.exinfo.dwWriteSize = cur; lstrcpynA( ex.exinfo.szSourceFileName.ptr, toStringz(src_fname), 512 ); lstrcpynA( ex.exinfo.szDestFileName.ptr, toStringz(hdr.fname), 512 ); ex.dwCompressedSize = hdr.compressed_size; ex.wRatio = cast(ushort)( (cast(real)hdr.compressed_size)/hdr.original_size*1000 ); ex.wDate = hdr.date; ex.wTime = hdr.time; ex.szAttribute[0] = (hdr.attrib&32 ? 'A': '-'); ex.szAttribute[1] = (hdr.attrib&1 ? 'R': '-'); ex.szAttribute[2] = (hdr.attrib&2 ? 'H': '-'); ex.szAttribute[3] = (hdr.attrib&4 ? 'S': '-'); ex.szAttribute[4] = (hdr.attrib&16 ? 'D': '-'); ex.szAttribute[5] = '\0'; if( hdr.method[0]=='G' ) lstrcpyA(ex.szMode.ptr,"-gzip-"); else lstrcpyA(ex.szMode.ptr,"-bzip2-"); } return false != g_handler( g_owner_window, WM_ARCEXTRACT, uState, &ex ); } //---------------------------------------------------------------- // パス検査系 //---------------------------------------------------------------- alias core.sys.windows.windows.IsDBCSLeadByte isDL; string replace_yen( string s ) { string ans; int j=0; for(int i=0; i!=s.length; i=i+(isDL(s[i])?2:1)) if( s[i] == '\\' ) ans~=s[j .. i], ans~='/', j=i+1; ans ~= s[j .. $]; return ans; } bool wild_match( string wild, string name ) { bool wild_match_nopath( string w, string s ) { string advance( string s ) { return s[(IsDBCSLeadByte(s[0])?2:1) .. $]; } while( w.length>0 ) switch( w[0] ) { case '?': if( s.length==0 ) return false; w = advance(w); s = advance(s); break; case '*': if( s.length==0 ) return false; w = advance(w); if( w.length == 0 ) return true; for( ; s.length!=0; s=advance(s) ) if( wild_match_nopath(w,s) ) return true; return false; default: if( s.length==0 ) return false; if( isDL(w[0]) ) { if( w[0..2] != s[0..2] ) return false; } else { if( w[0] != s[0] ) return false; } w = advance(w); s = advance(s); break; } return s.length==0; } if( wild=="" || wild=="*.*" || wild=="*" || wild=="**" ) return true; string[] wilds = split( replace_yen( toLower(wild) ), "/" ); string[] names = split( replace_yen( toLower(name) ), "/" ); if( wilds.length != names.length ) return false; for(int i=0; i!=wilds.length; ++i) if( wilds[i]!="*.*" && wilds[i]!="*" && wilds[i]!="**" ) if( !wild_match_nopath( wilds[i], names[i] ) ) return false; return true; } string check_path( string in_path ) { char[] path = in_path.dup; // C:\ ==> C_\ if( path.length>=2 && path[1]==':' ) path[1] = '_'; // \\hoge ==> hoge // /hoge ==> hoge while( path.length>0 && (path[0]=='\\'||path[0]=='/') ) path = path[1..$]; // .. ==> __ string[] paths = split( replace_yen(path.idup), "/" ); L1: foreach( ref string pc ; paths ) if( pc.length >= 2 ) { foreach( char c ; pc ) if( c != '.' ) continue L1; pc = replace( pc, ".", "_" ); } return join( paths, "\\" ); } //---------------------------------------------------------------- // 簡易テスト@もっとマジメに書かなきゃ… //---------------------------------------------------------------- unittest { assert( check_path(`\\\\hoge\fuga`)==`hoge\fuga` ); assert( check_path(`/usr/local/`)==`usr\local\` ); assert( check_path(`..\abc def\...\.\g`)==`__\abc def\___\.\g` ); assert( wild_match(`a/b/c`,`A\b\C`) ); assert( wild_match(`a/*.*/a?x`,`A\hoge\Afx`) ); assert( Bga_impl(null,"a hoge") < 0 ); }