Commit | Line | Data |
---|---|---|
ef79bbde P |
1 | // |
2 | // PcsxPlugin.m | |
3 | // Pcsx | |
4 | // | |
5 | // Created by Gil Pedersen on Fri Oct 03 2003. | |
6 | // Copyright (c) 2003 __MyCompanyName__. All rights reserved. | |
7 | // | |
8 | ||
9 | #import <Cocoa/Cocoa.h> | |
10 | #import "PcsxPlugin.h" | |
11 | #include "psxcommon.h" | |
12 | #include "plugins.h" | |
13 | ||
14 | @implementation PcsxPlugin | |
15 | ||
16 | + (NSString *)getPrefixForType:(int)aType | |
17 | { | |
18 | switch (aType) { | |
19 | case PSE_LT_GPU: return @"GPU"; | |
20 | case PSE_LT_CDR: return @"CDR"; | |
21 | case PSE_LT_SPU: return @"SPU"; | |
22 | case PSE_LT_PAD: return @"PAD"; | |
23 | case PSE_LT_NET: return @"NET"; | |
24 | } | |
25 | ||
26 | return @""; | |
27 | } | |
28 | ||
29 | + (NSString *)getDefaultKeyForType:(int)aType | |
30 | { | |
31 | //return @"Plugin" [PcsxPlugin getPrefixForType:aType]; | |
32 | switch (aType) { | |
33 | case PSE_LT_GPU: return @"PluginGPU"; | |
34 | case PSE_LT_CDR: return @"PluginCDR"; | |
35 | case PSE_LT_SPU: return @"PluginSPU"; | |
36 | case PSE_LT_PAD: return @"PluginPAD"; | |
37 | case PSE_LT_NET: return @"PluginNET"; | |
38 | } | |
39 | ||
40 | return @""; | |
41 | } | |
42 | ||
43 | + (char **)getConfigEntriesForType:(int)aType | |
44 | { | |
45 | static char *gpu[2] = {(char *)&Config.Gpu, NULL}; | |
46 | static char *cdr[2] = {(char *)&Config.Cdr, NULL}; | |
47 | static char *spu[2] = {(char *)&Config.Spu, NULL}; | |
48 | static char *pad[3] = {(char *)&Config.Pad1, (char *)&Config.Pad2, NULL}; | |
49 | static char *net[2] = {(char *)&Config.Net, NULL}; | |
50 | ||
51 | switch (aType) { | |
52 | case PSE_LT_GPU: return (char **)gpu; | |
53 | case PSE_LT_CDR: return (char **)cdr; | |
54 | case PSE_LT_SPU: return (char **)spu; | |
55 | case PSE_LT_PAD: return (char **)pad; | |
56 | case PSE_LT_NET: return (char **)net; | |
57 | } | |
58 | ||
59 | return nil; | |
60 | } | |
61 | ||
62 | - (id)initWithPath:(NSString *)aPath | |
63 | { | |
64 | if (!(self = [super init])) { | |
65 | return nil; | |
66 | } | |
67 | ||
68 | PSEgetLibType PSE_getLibType = NULL; | |
69 | PSEgetLibVersion PSE_getLibVersion = NULL; | |
70 | PSEgetLibName PSE_getLibName = NULL; | |
71 | ||
72 | pluginRef = nil; | |
73 | name = nil; | |
74 | path = [aPath retain]; | |
75 | NSString *fullPath = [[NSString stringWithCString:Config.PluginsDir] stringByAppendingPathComponent:path]; | |
76 | ||
77 | pluginRef = SysLoadLibrary([fullPath fileSystemRepresentation]); | |
78 | if (pluginRef == nil) { | |
79 | [self release]; | |
80 | return nil; | |
81 | } | |
82 | ||
83 | // TODO: add support for plugins with multiple functionalities??? | |
84 | PSE_getLibType = (PSEgetLibType) SysLoadSym(pluginRef, "PSEgetLibType"); | |
85 | if (SysLibError() != nil) { | |
86 | if (([path rangeOfString: @"gpu" options:NSCaseInsensitiveSearch]).length != 0) | |
87 | type = PSE_LT_GPU; | |
88 | else if (([path rangeOfString: @"cdr" options:NSCaseInsensitiveSearch]).length != 0) | |
89 | type = PSE_LT_CDR; | |
90 | else if (([path rangeOfString: @"spu" options:NSCaseInsensitiveSearch]).length != 0) | |
91 | type = PSE_LT_SPU; | |
92 | else if (([path rangeOfString: @"pad" options:NSCaseInsensitiveSearch]).length != 0) | |
93 | type = PSE_LT_PAD; | |
94 | else { | |
95 | [self release]; | |
96 | return nil; | |
97 | } | |
98 | } else { | |
99 | type = (int)PSE_getLibType(); | |
100 | if (type != PSE_LT_GPU && type != PSE_LT_CDR && type != PSE_LT_SPU && type != PSE_LT_PAD) { | |
101 | [self release]; | |
102 | return nil; | |
103 | } | |
104 | } | |
105 | ||
106 | PSE_getLibName = (PSEgetLibName) SysLoadSym(pluginRef, "PSEgetLibName"); | |
107 | if (SysLibError() == nil) { | |
108 | name = [[NSString alloc] initWithCString:PSE_getLibName()]; | |
109 | } | |
110 | ||
111 | PSE_getLibVersion = (PSEgetLibVersion) SysLoadSym(pluginRef, "PSEgetLibVersion"); | |
112 | if (SysLibError() == nil) { | |
113 | version = PSE_getLibVersion(); | |
114 | } | |
115 | else { | |
116 | version = -1; | |
117 | } | |
118 | ||
119 | // save the current modification date | |
120 | NSDictionary *fattrs = [[NSFileManager defaultManager] fileAttributesAtPath:fullPath traverseLink:YES]; | |
121 | modDate = [[fattrs fileModificationDate] retain]; | |
122 | ||
123 | active = 0; | |
124 | ||
125 | return self; | |
126 | } | |
127 | ||
128 | - (void)dealloc | |
129 | { | |
130 | int i; | |
131 | ||
132 | // shutdown if we had previously been inited | |
133 | for (i=0; i<32; i++) { | |
134 | if (active & (1 << i)) { | |
135 | [self shutdownAs:(1 << i)]; | |
136 | } | |
137 | } | |
138 | ||
139 | if (pluginRef) SysCloseLibrary(pluginRef); | |
140 | ||
141 | [path release]; | |
142 | [name release]; | |
143 | ||
144 | [super dealloc]; | |
145 | } | |
146 | ||
147 | - (void)runCommand:(id)arg | |
148 | { | |
149 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
150 | NSString *funcName = [arg objectAtIndex:0]; | |
151 | long (*func)(void); | |
152 | ||
153 | func = SysLoadSym(pluginRef, [funcName lossyCString]); | |
154 | if (SysLibError() == nil) { | |
155 | func(); | |
156 | } else { | |
157 | NSBeep(); | |
158 | } | |
159 | ||
160 | [arg release]; | |
161 | [pool release]; | |
162 | return; | |
163 | } | |
164 | ||
165 | - (long)initAs:(int)aType | |
166 | { | |
167 | char symbol[255]; | |
168 | long (*init)(void); | |
169 | long (*initArg)(long arg); | |
170 | int res = PSE_ERR_FATAL; | |
171 | ||
172 | if ((active & aType) == aType) { | |
173 | return 0; | |
174 | } | |
175 | ||
176 | sprintf(symbol, "%sinit", [[PcsxPlugin getPrefixForType:aType] lossyCString]); | |
177 | init = initArg = SysLoadSym(pluginRef, symbol); | |
178 | if (SysLibError() == nil) { | |
179 | if (aType != PSE_LT_PAD) | |
180 | res = init(); | |
181 | else | |
182 | res = initArg(1|2); | |
183 | } | |
184 | ||
185 | if (0 == res) { | |
186 | active |= aType; | |
187 | } else { | |
188 | NSRunCriticalAlertPanel(NSLocalizedString(@"Plugin Initialization Failed!", nil), | |
189 | [NSString stringWithFormat:NSLocalizedString(@"Pcsx failed to initialize the selected %s plugin (error=%i).\nThe plugin might not work with your system.", nil), [PcsxPlugin getPrefixForType:aType], res], | |
190 | nil, nil, nil); | |
191 | } | |
192 | ||
193 | return res; | |
194 | } | |
195 | ||
196 | - (long)shutdownAs:(int)aType | |
197 | { | |
198 | char symbol[255]; | |
199 | long (*shutdown)(void); | |
200 | ||
201 | sprintf(symbol, "%sshutdown", [[PcsxPlugin getPrefixForType:aType] lossyCString]); | |
202 | shutdown = SysLoadSym(pluginRef, symbol); | |
203 | if (SysLibError() == nil) { | |
204 | active &= ~aType; | |
205 | return shutdown(); | |
206 | } | |
207 | ||
208 | return PSE_ERR_FATAL; | |
209 | } | |
210 | ||
211 | - (BOOL)hasAboutAs:(int)aType | |
212 | { | |
213 | char symbol[255]; | |
214 | ||
215 | sprintf(symbol, "%sabout", [[PcsxPlugin getPrefixForType:aType] lossyCString]); | |
216 | SysLoadSym(pluginRef, symbol); | |
217 | ||
218 | return (SysLibError() == nil); | |
219 | } | |
220 | ||
221 | - (BOOL)hasConfigureAs:(int)aType | |
222 | { | |
223 | char symbol[255]; | |
224 | ||
225 | sprintf(symbol, "%sconfigure", [[PcsxPlugin getPrefixForType:aType] lossyCString]); | |
226 | SysLoadSym(pluginRef, symbol); | |
227 | ||
228 | return (SysLibError() == nil); | |
229 | } | |
230 | ||
231 | - (void)aboutAs:(int)aType | |
232 | { | |
233 | NSArray *arg; | |
234 | char symbol[255]; | |
235 | ||
236 | sprintf(symbol, "%sabout", [[PcsxPlugin getPrefixForType:aType] lossyCString]); | |
237 | arg = [[NSArray alloc] initWithObjects:[NSString stringWithCString:symbol], | |
238 | [NSNumber numberWithInt:0], nil]; | |
239 | ||
240 | // detach a new thread | |
241 | [NSThread detachNewThreadSelector:@selector(runCommand:) toTarget:self | |
242 | withObject:arg]; | |
243 | } | |
244 | ||
245 | - (void)configureAs:(int)aType | |
246 | { | |
247 | NSArray *arg; | |
248 | char symbol[255]; | |
249 | ||
250 | sprintf(symbol, "%sconfigure", [[PcsxPlugin getPrefixForType:aType] lossyCString]); | |
251 | arg = [[NSArray alloc] initWithObjects:[NSString stringWithCString:symbol], | |
252 | [NSNumber numberWithInt:1], nil]; | |
253 | ||
254 | // detach a new thread | |
255 | [NSThread detachNewThreadSelector:@selector(runCommand:) toTarget:self | |
256 | withObject:arg]; | |
257 | } | |
258 | ||
259 | - (NSString *)getDisplayVersion | |
260 | { | |
261 | if (version == -1) | |
262 | return @""; | |
263 | ||
264 | return [NSString stringWithFormat:@"v%ld.%ld.%ld", version>>16,(version>>8)&0xff,version&0xff]; | |
265 | } | |
266 | ||
267 | - (int)getType | |
268 | { | |
269 | return type; | |
270 | } | |
271 | ||
272 | - (NSString *)path | |
273 | { | |
274 | return path; | |
275 | } | |
276 | ||
277 | - (unsigned)hash | |
278 | { | |
279 | return [path hash]; | |
280 | } | |
281 | ||
282 | - (NSString *)description | |
283 | { | |
284 | if (name == nil) | |
285 | return [path lastPathComponent]; | |
286 | ||
287 | return [NSString stringWithFormat:@"%@ %@ [%@]", name, [self getDisplayVersion], [path lastPathComponent]]; | |
288 | } | |
289 | ||
290 | // the plugin will check if it's still valid and return the status | |
291 | - (BOOL)verifyOK | |
292 | { | |
293 | // check that the file is still there with the same modification date | |
294 | NSFileManager *dfm = [NSFileManager defaultManager]; | |
295 | NSString *fullPath = [[NSString stringWithCString:Config.PluginsDir] stringByAppendingPathComponent:path]; | |
296 | if (![dfm fileExistsAtPath:fullPath]) | |
297 | return NO; | |
298 | ||
299 | NSDictionary *fattrs = [dfm fileAttributesAtPath:fullPath traverseLink:YES]; | |
300 | return [[fattrs fileModificationDate] isEqualToDate:modDate]; | |
301 | } | |
302 | ||
303 | @end |