// // PluginList.m // Pcsxr // // Created by Gil Pedersen on Sun Sep 21 2003. // Copyright (c) 2003 __MyCompanyName__. All rights reserved. // #import "EmuThread.h" #import "PluginList.h" #import "PcsxrPlugin.h" #include "psxcommon.h" #include "plugins.h" #import "ARCBridge.h" //NSMutableArray *plugins; static PluginList __arcweak *sPluginList = nil; const static int typeList[] = {PSE_LT_GPU, PSE_LT_SPU, PSE_LT_CDR, PSE_LT_PAD, PSE_LT_NET, PSE_LT_SIO1}; @implementation PluginList + (PluginList *)list { return sPluginList; } - (id)init { NSUInteger i; if (!(self = [super init])) { return nil; } NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; pluginList = [[NSMutableArray alloc] initWithCapacity:20]; activeGpuPlugin = activeSpuPlugin = activeCdrPlugin = activePadPlugin = activeNetPlugin = activeSIO1Plugin = nil; missingPlugins = NO; for (i = 0; i < sizeof(typeList) / sizeof(typeList[0]); i++) { NSString *path = [defaults stringForKey:[PcsxrPlugin defaultKeyForType:typeList[i]]]; if (nil == path) { missingPlugins = YES; continue; } if ([path isEqualToString:@"Disabled"]) continue; if (![self hasPluginAtPath:path]) { @autoreleasepool { PcsxrPlugin *plugin = [[PcsxrPlugin alloc] initWithPath:path]; if (plugin) { [pluginList addObject:plugin]; if (![self setActivePlugin:plugin forType:typeList[i]]) missingPlugins = YES; RELEASEOBJ(plugin); } else { missingPlugins = YES; } } } } if (missingPlugins) { [self refreshPlugins]; } sPluginList = self; return self; } #if !__has_feature(objc_arc) - (void)dealloc { if (sPluginList == self) sPluginList = nil; [activeGpuPlugin release]; [activeSpuPlugin release]; [activeCdrPlugin release]; [activePadPlugin release]; [activeNetPlugin release]; [activeSIO1Plugin release]; [pluginList release]; [super dealloc]; } #endif - (void)refreshPlugins { NSDirectoryEnumerator *dirEnum; NSString *pname; NSUInteger i; // verify that the ones that are in list still works for (i=0; i < [pluginList count]; i++) { if (![[pluginList objectAtIndex:i] verifyOK]) { [pluginList removeObjectAtIndex:i]; i--; } } for (NSString *plugDir in [PcsxrPlugin pluginsPaths]) { // look for new ones in the plugin directory dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:plugDir]; while ((pname = [dirEnum nextObject])) { if ([[pname pathExtension] isEqualToString:@"psxplugin"] || [[pname pathExtension] isEqualToString:@"so"]) { [dirEnum skipDescendents]; /* don't enumerate this directory */ if (![self hasPluginAtPath:pname]) { @autoreleasepool { PcsxrPlugin *plugin = [[PcsxrPlugin alloc] initWithPath:pname]; if (plugin != nil) { [pluginList addObject:plugin]; RELEASEOBJ(plugin); } } } } } } // check the we have the needed plugins missingPlugins = NO; for (i=0; i < 4 /*sizeof(*typeList)*/; i++) { PcsxrPlugin *plugin = [self activePluginForType:typeList[i]]; if (nil == plugin) { NSArray *list = [self pluginsForType:typeList[i]]; NSUInteger j; for (j=0; j < [list count]; j++) { if ([self setActivePlugin:[list objectAtIndex:j] forType:typeList[i]]) break; } if (j == [list count]) missingPlugins = YES; } } } - (NSArray *)pluginsForType:(int)typeMask { NSMutableArray *types = [NSMutableArray array]; for (PcsxrPlugin *plugin in pluginList) { if ([plugin type] & typeMask) { [types addObject:plugin]; } } return types; } - (BOOL)hasPluginAtPath:(NSString *)path { if (nil == path) return NO; for (PcsxrPlugin *plugin in pluginList) { if ([[plugin path] isEqualToString:path]) return YES; } return NO; } // returns if all the required plugins are available - (BOOL)configured { return !missingPlugins; } - (BOOL)doInitPlugins { BOOL bad = NO; if ([activeGpuPlugin runAs:PSE_LT_GPU] != 0) bad = YES; if ([activeSpuPlugin runAs:PSE_LT_SPU] != 0) bad = YES; if ([activeCdrPlugin runAs:PSE_LT_CDR] != 0) bad = YES; if ([activePadPlugin runAs:PSE_LT_PAD] != 0) bad = YES; if ([activeNetPlugin runAs:PSE_LT_NET] != 0) bad = YES; if ([activeSIO1Plugin runAs:PSE_LT_SIO1] != 0) bad = YES; return !bad; } - (PcsxrPlugin *)activePluginForType:(int)type { switch (type) { case PSE_LT_GPU: return activeGpuPlugin; break; case PSE_LT_CDR: return activeCdrPlugin; break; case PSE_LT_SPU: return activeSpuPlugin; break; case PSE_LT_PAD: return activePadPlugin; break; case PSE_LT_NET: return activeNetPlugin; break; case PSE_LT_SIO1: return activeSIO1Plugin; break; } return nil; } - (BOOL)setActivePlugin:(PcsxrPlugin *)plugin forType:(int)type { PcsxrPlugin *pluginPtr = nil; switch (type) { case PSE_LT_SIO1: case PSE_LT_GPU: case PSE_LT_CDR: case PSE_LT_SPU: case PSE_LT_PAD: case PSE_LT_NET: pluginPtr = [self activePluginForType:type]; break; default: return NO; break; } if (plugin == pluginPtr) { return YES; } BOOL active = pluginPtr && [EmuThread active]; BOOL wasPaused = NO; if (active) { // TODO: temporary freeze? wasPaused = [EmuThread pauseSafe]; ClosePlugins(); ReleasePlugins(); } // stop the old plugin and start the new one if (pluginPtr) { [pluginPtr shutdownAs:type]; //NOTE: We can ignore Clang's "Incorrect Decrement" here RELEASEOBJ(pluginPtr); } if ([plugin runAs:type] != 0) { plugin = nil; } switch (type) { case PSE_LT_GPU: activeGpuPlugin = RETAINOBJ(plugin); break; case PSE_LT_CDR: activeCdrPlugin = RETAINOBJ(plugin); break; case PSE_LT_SPU: activeSpuPlugin = RETAINOBJ(plugin); break; case PSE_LT_PAD: activePadPlugin = RETAINOBJ(plugin); break; case PSE_LT_NET: activeNetPlugin = RETAINOBJ(plugin); break; case PSE_LT_SIO1: activeSIO1Plugin = RETAINOBJ(plugin); break; } // write path to the correct config entry const char *str; if (plugin != nil) { str = [[plugin path] fileSystemRepresentation]; if (str == NULL) { str = "Invalid Plugin"; } } else { str = "Invalid Plugin"; } char **dst = [PcsxrPlugin configEntriesForType:type]; while (*dst) { strlcpy(*dst, str, MAXPATHLEN); dst++; } if (active) { LoadPlugins(); OpenPlugins(); if (!wasPaused) { [EmuThread resume]; } } return plugin != nil; } - (void)disableNetPlug { char **dst = [PcsxrPlugin configEntriesForType:PSE_LT_NET]; while (*dst) { strcpy(*dst, "Disabled"); dst++; } } - (void)enableNetPlug { PcsxrPlugin *netPlug = [self activePluginForType:PSE_LT_NET]; const char *str = NULL; if (netPlug) { str = [[netPlug path] fileSystemRepresentation]; } if (str) { char **dst = [PcsxrPlugin configEntriesForType:PSE_LT_NET]; while (*dst) { strlcpy(*dst, str, MAXPATHLEN); dst++; } } } @end