aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp/ServiceManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Winamp/ServiceManager.cpp')
-rw-r--r--Src/Winamp/ServiceManager.cpp285
1 files changed, 285 insertions, 0 deletions
diff --git a/Src/Winamp/ServiceManager.cpp b/Src/Winamp/ServiceManager.cpp
new file mode 100644
index 00000000..5206057e
--- /dev/null
+++ b/Src/Winamp/ServiceManager.cpp
@@ -0,0 +1,285 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "ServiceManager.h"
+#include <api.h>
+#include <api/service/waservicefactory.h>
+#include "../nu/AutoLock.h"
+#include <api/syscb/callbacks/syscb.h>
+#include <api/syscb/callbacks/svccb.h>
+
+using namespace Nullsoft::Utility;
+
+
+struct Counter
+{
+ Counter( waServiceFactory *_owner, void *_ptr ) : ptr( _ptr ), owner( _owner ) {}
+
+ void *ptr;
+ waServiceFactory *owner;
+};
+
+ServiceManager::ServiceManager() : serviceGuard(512)
+{}
+
+int ServiceManager::service_register( waServiceFactory *svc )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_register" ) );
+ FOURCC service_type = svc->getServiceType();
+
+ // add the service to the master list
+ services.push_back( svc );
+
+ // add it to the by-type lookup
+ ServiceList *&type_list = services_by_type[ service_type ];
+ if ( !type_list )
+ type_list = new ServiceList;
+
+ type_list->push_back( svc );
+
+ // send notifications
+ svc->serviceNotify( SvcNotify::ONREGISTERED );
+ WASABI_API_SYSCB->syscb_issueCallback( SysCallback::SERVICE, SvcCallback::ONREGISTER, (intptr_t)service_type, reinterpret_cast<intptr_t>( svc ) );
+
+ return 1;
+}
+
+int ServiceManager::service_deregister( waServiceFactory *svc )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_deregister" ) );
+ FOURCC service_type = svc->getServiceType();
+
+ // remove it from the master list
+ //services.eraseObject(svc);
+ auto it = std::find( services.begin(), services.end(), svc );
+ if ( it != services.end() )
+ services.erase( it );
+
+ // and from the type lookup map
+ ServiceList *type_list = services_by_type[ service_type ];
+ if ( type_list )
+ {
+ //type_list->eraseObject(svc);
+ auto it = std::find( type_list->begin(), type_list->end(), svc );
+ if ( it != type_list->end() )
+ type_list->erase( it );
+ }
+
+ WASABI_API_SYSCB->syscb_issueCallback( SysCallback::SERVICE, SvcCallback::ONDEREGISTER, (intptr_t)service_type, reinterpret_cast<intptr_t>( svc ) );
+ svc->serviceNotify( SvcNotify::ONDEREGISTERED );
+
+ return 1;
+}
+
+size_t ServiceManager::service_getNumServices( FOURCC svc_type )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_getNumServices" ) );
+ if ( svc_type )
+ {
+ ServiceList *type_list = services_by_type[ svc_type ];
+ if ( type_list )
+ return type_list->size();
+ else
+ return 0;
+ }
+ else
+ return services.size();
+}
+
+waServiceFactory *ServiceManager::service_enumService( FOURCC svc_type, size_t n )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_enumService" ) );
+ ServiceList *type_list = 0;
+ if ( svc_type )
+ type_list = services_by_type[ svc_type ];
+ else
+ type_list = &services;
+
+ if ( type_list && n < type_list->size() )
+ return type_list->at( n );
+ else
+ return 0;
+}
+
+waServiceFactory *ServiceManager::service_getServiceByGuid( GUID guid )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_getServiceByGuid" ) );
+ for ( waServiceFactory *l_service : services )
+ {
+ if ( l_service->getGuid() == guid )
+ return l_service;
+ }
+
+ return NULL;
+}
+
+int ServiceManager::service_lock( waServiceFactory *owner, void *svcptr )
+{
+ if ( owner == NULL || svcptr == NULL )
+ return 0;
+
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_lock" ) );
+ locks.push_back( new Counter( owner, svcptr ) );
+
+ return 1;
+}
+
+int ServiceManager::service_clientLock( void *svcptr )
+{
+ return 1;
+}
+
+int ServiceManager::service_release( void *svcptr )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_release" ) );
+ for ( size_t i = 0; i != locks.size(); i++ )
+ {
+ if ( locks[ i ]->ptr == svcptr )
+ {
+ void *ptr = locks[ i ]->ptr;
+ waServiceFactory *owner = locks[ i ]->owner;
+
+ delete locks[ i ];
+
+ locks.erase( locks.begin() + i );
+ owner->releaseInterface( ptr );
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+const char *ServiceManager::service_getTypeName( FOURCC svc_type )
+{
+ return NULL;
+}
+
+int ServiceManager::service_unlock( void *svcptr )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_unlock" ) );
+ for ( size_t i = 0; i != locks.size(); i++ )
+ {
+ if ( locks[ i ]->ptr == svcptr )
+ {
+ delete locks[ i ];
+ locks.erase( locks.begin() + i );
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int ServiceManager::service_isvalid( FOURCC svctype, waServiceFactory *service )
+{
+ AutoLock lock( serviceGuard LOCKNAME( "ServiceManager::service_isvalid" ) );
+ //return !!services.contains(service);
+ return ( services.end() != std::find( services.begin(), services.end(), service ) );
+}
+
+int ServiceManager::service_compactDuplicates( waServiceFactory *me )
+{
+ // first, find 'me'
+ GUID guid = me->getGuid();
+
+ size_t me_index = 0;
+
+ //bool found = services.findItem(me, &me_index);
+ //if (!found)
+ // return 1;
+ if ( services.end() == std::find( services.begin(), services.end(), me ) )
+ return 1;
+
+ ServiceList *type_list = services_by_type[ me->getServiceType() ];
+
+ // go in reverse order because service to compact is likely at the end
+ size_t n = services.size();
+ while ( n-- ) // n is guaranteed to be >0 because otherwise the 'find' loop above would have failed
+ {
+ waServiceFactory *n_service = services[ n ];
+ if ( n != me_index && n_service != me && n_service->getGuid() == guid )
+ {
+ services[ me_index ] = n_service;
+ services.erase( services.begin() + n );
+
+ // fix up our by-type cache
+ if ( type_list )
+ {
+ size_t me_index = 0;
+ size_t n_index = 0;
+
+ //----------------------------------------------------
+ // Replaced with code below this commented code
+ //if (type_list->findItem_reverse(n_service, &n_index) && type_list->findItem(me, &me_index))
+ //{
+ // type_list->at(me_index) = n_service;
+ // type_list->eraseindex(n_index);
+ //}
+
+ bool foundService = false;
+ for ( int idx = type_list->size() - 1; idx >= 0; idx-- )
+ {
+ if ( type_list->at( idx ) == n_service )
+ {
+ foundService = true;
+ n_index = idx;
+ break;
+ }
+ }
+
+ bool foundMe = false;
+ for ( int idx2 = 0; idx2 < type_list->size(); idx2++ )
+ {
+ if ( type_list->at( idx2 ) == me )
+ {
+ foundMe = true;
+ me_index = idx2;
+ break;
+ }
+ }
+
+ if ( foundService && foundMe )
+ {
+ type_list->at( me_index ) = n_service;
+ type_list->erase( type_list->begin() + n_index );
+ }
+ //--------------------------------------------------
+ }
+
+ me->serviceNotify( SvcNotify::ONDEREGISTERED );
+
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS ServiceManager
+START_DISPATCH;
+CB( API_SERVICE_SERVICE_REGISTER, service_register );
+CB( API_SERVICE_SERVICE_DEREGISTER, service_deregister );
+CB( API_SERVICE_SERVICE_GETNUMSERVICES, service_getNumServices );
+CB( API_SERVICE_SERVICE_ENUMSERVICE, service_enumService );
+CB( API_SERVICE_SERVICE_GETSERVICEBYGUID, service_getServiceByGuid );
+CB( API_SERVICE_SERVICE_LOCK, service_lock );
+CB( API_SERVICE_SERVICE_CLIENTLOCK, service_clientLock );
+CB( API_SERVICE_SERVICE_RELEASE, service_release );
+CB( API_SERVICE_SERVICE_GETTYPENAME, service_getTypeName );
+CB( API_SERVICE_SERVICE_UNLOCK, service_unlock );
+CB( API_SERVICE_ISVALID, service_isvalid );
+CB( API_SERVICE_COMPACT_DUPLICATES, service_compactDuplicates );
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file