//////////////////////////////////////////////////////////////////////////////// // Plainamp, Open source Winamp core // // Copyright © 2005 Sebastian Pipping // // --> http://www.hartwork.org // // This source code is released under the GNU General Public License (GPL). // See GPL.txt for details. Any non-GPL usage is strictly forbidden. //////////////////////////////////////////////////////////////////////////////// // ======================================================================================= #include "Global.h" // ======================================================================================= #include "InputPlugin.h" #include "Console.h" #include "Main.h" #include "Input.h" #include "Unicode.h" map ext_map; // extern vector input_plugins; // extern InputPlugin * active_input_plugin = NULL; // extern // ======================================================================================= // The InputPlugin class is inherited from the Plugin class InputPlugin::InputPlugin( TCHAR * szDllpath, bool bKeepLoaded ) : Plugin( szDllpath ) { iHookerIndex = -1; szFilters = NULL; iFiltersLen = 0; plugin = NULL; //NOTICE_LOG(AUDIO,"\InputPlugin::InputPlugin > Begin\n"); if( !Load() ) { return; } if( !bKeepLoaded ) { Unload(); } input_plugins.push_back( this ); } //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// InputPlugin::~InputPlugin() { if( szFilters ) delete [] szFilters; } //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// bool InputPlugin::Load() { printf("InputPlugin::Load() was called. IsLoaded: %i\n", IsLoaded()); if( IsLoaded() ) return true; // (1) Load DLL hDLL = LoadLibrary( GetFullpath() ); if( !hDLL ) return false; // (2) Find export WINAMP_INPUT_GETTER winampGetInModule2 = ( WINAMP_INPUT_GETTER )GetProcAddress( hDLL, "winampGetInModule2" ); if( winampGetInModule2 == NULL ) { FreeLibrary( hDLL ); hDLL = NULL; return false; } // (3) Get module plugin = winampGetInModule2(); if( plugin == NULL ) { FreeLibrary( hDLL ); hDLL = NULL; return false; } // (4) Process module plugin->hDllInstance = hDLL; plugin->hMainWindow = WindowMain; plugin->SAVSAInit = SAVSAInit; plugin->SAVSADeInit = SAVSADeInit; plugin->SAAddPCMData = SAAddPCMData; plugin->SAGetMode = SAGetMode; plugin->SAAdd = SAAdd; plugin->VSAAddPCMData = VSAAddPCMData; plugin->VSAGetMode = VSAGetMode; plugin->VSAAdd = VSAAdd; plugin->VSASetInfo = VSASetInfo; plugin->dsp_dosamples = dsp_dosamples; plugin->dsp_isactive = dsp_isactive; plugin->SetInfo = SetInfo; if( !szName ) { // Note: The prefix is not removed to hide their // origin at Nullsoft! It just reads easier. if( !_strnicmp( plugin->description, "nullsoft ", 9 ) ) { plugin->description += 9; if( !_strnicmp( plugin->description, "mpeg(layer1-3/ct aac+/dolby aac) ", 33 ) ) { plugin->description += ( 33 - 5 ); memcpy( plugin->description, "MPEG", 4 * sizeof( char ) ); } } iNameLen = ( int )strlen( plugin->description ); szName = new TCHAR[ iNameLen + 1 ]; ToTchar( szName, plugin->description, iNameLen ); szName[ iNameLen ] = TEXT( '\0' ); } // (5) Init const WNDPROC WndprocBefore = ( WNDPROC )GetWindowLong( WindowMain, GWL_WNDPROC ); plugin->Init(); const WNDPROC WndprocAfter = ( WNDPROC )GetWindowLong( WindowMain, GWL_WNDPROC ); if( WndprocBefore != WndprocAfter ) { WndprocBackup = WndprocBefore; iHookerIndex = iWndprocHookCounter++; } #ifdef NOGUI printf( "Loading <%s>, %s\n" , GetFilename(), szName ); #else TCHAR szBuffer[ 5000 ]; _stprintf( szBuffer, TEXT( "Loading <%s>, %s" ), GetFilename(), szName ); Console::Append( szBuffer ); #endif Integrate(); // This function is just below // Note: Plugins that use a wndproc hook need // to be unloaded in the inverse loading order. // This is due to the nature of wndproc hooking. if( iHookerIndex != -1 ) { Console::Append( TEXT( "Wndproc hook added (by plugin)" ) ); } return true; } //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// bool InputPlugin::Integrate() { if( !IsLoaded() ) return false; // (6) Build filter // (6a) First pass: get needed buffer length int needed = 0; int len = 0; bool even = false; char * walk = plugin->FileExtensions; while( ( len = ( int )strlen( walk ) ) > 0 ) { len++; // For '\0' if( even ) { // Extensions e.g. "mp3;mp2;mp1" // Worst case "a;b;c" (5) --> "*.a;*.b;*.c" (11) needed += ( 3 * len ); } else { // Filter name e.g. "MPEG audio files" needed += len; } even = !even; walk += len; } szFilters = new TCHAR[ needed + 1 ]; TCHAR * walk_out = szFilters; // (6b) Once again with copy walk = plugin->FileExtensions; even = false; while( true ) { // Check extensions char * start_filter = walk; const int len_filter = ( int )strlen( walk ); if( len_filter == 0 ) { // End reached break; } walk += len_filter + 1; // Check filter name char * start_display = walk; int len_display = ( int )strlen( walk ); if( len_display == 0 ) { break; } walk += ++len_display; // Append filter name ToTchar( walk_out, start_display, len_display ); // ======================================================================================= // Print used filetypes TCHAR szBuffer[ 5000 ]; *(walk_out + len_display) = TEXT( '\0' ); _stprintf( szBuffer, TEXT( " %s" ), walk_out ); Console::Append( szBuffer ); //printf( szBuffer, TEXT( " %s\n" ), walk_out ); // ======================================================================================= walk_out += len_display; // Convert and append extensions char * walk_filter = start_filter; char * last_filter = start_filter; int len; while( true ) { if( ( *walk_filter == ';' ) || ( *walk_filter == '\0' ) ) { len = ( walk_filter - last_filter ); if( len < 1 ) { break; } // Add extension to map TCHAR * szExt = new TCHAR[ len + 1 ]; ToTchar( szExt, last_filter, len ); szExt[ len ] = TEXT( '\0' ); _tcslwr( szExt ); ext_map.insert( pair( szExt, this ) ); // Append extension as "*.ext[;\0]" len++; // Also copy ';' and '\0' memcpy( walk_out, TEXT( "*." ), 2 * sizeof( TCHAR ) ); walk_out += 2; ToTchar( walk_out, last_filter, len ); walk_out += len; // Any more extensions? if( *walk_filter == '\0' ) { break; } last_filter = walk_filter + 1; } walk_filter++; } if( *walk == '\0' ) { *walk_out = TEXT( '\0' ); iFiltersLen = walk_out - szFilters; break; } } Console::Append( TEXT( " " ) ); return true; } //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// bool InputPlugin::DisIntegrate() { return true; } //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// bool InputPlugin::Unload() { if( !IsLoaded() ) return true; DisIntegrate(); #ifndef NOGUI TCHAR szBuffer[ 5000 ]; _stprintf( szBuffer, TEXT( "Unloading '%s'" ), GetFilename() ); Console::Append( szBuffer ); Console::Append( TEXT( " " ) ); #else printf( ">>> Unloading '%s'\n" , GetFilename() ); #endif // Quit if( plugin ) { if( plugin->Quit ) plugin->Quit(); plugin->outMod = NULL; plugin = NULL; } // Remove wndproc hook if( ( iHookerIndex != -1 ) && ( iHookerIndex == iWndprocHookCounter - 1 ) ) { // If we don't restore it the plugins wndproc will // still be called which is not there anymore -> crash SetWindowLong( WindowMain, GWL_WNDPROC, ( LONG )WndprocBackup ); Console::Append( TEXT( "Wndproc hook removed (by host)" ) ); Console::Append( TEXT( " " ) ); iHookerIndex = -1; iWndprocHookCounter--; } FreeLibrary( hDLL ); hDLL = NULL; return true; } //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// bool InputPlugin::About( HWND hParent ) { if( !plugin ) return false; if( !plugin->About ) return false; plugin->About( hParent ); return true; } //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// bool InputPlugin::Config( HWND hParent ) { if( !plugin ) return false; if( !plugin->Config ) return false; plugin->Config( hParent ); // TODO: File extension could have changed (e.g. in_mp3) // So we have to process ext_map here... return true; }