f1cada866de2fdf3ca6959f5820b7be06d7a5b09
[WebKit-https.git] / WebKit / Plugins.subproj / WebBasePluginPackage.m
1 //
2 //  WebBasePluginPackage.m
3 //  WebKit
4 //
5 //  Created by Chris Blumenberg on Tue Oct 22 2002.
6 //  Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
7 //
8
9 #import <WebKit/WebBasePluginPackage.h>
10
11 #import <WebKit/WebKitNSStringExtras.h>
12 #import <WebKit/WebNetscapePluginPackage.h>
13 #import <WebKit/WebNSObjectExtras.h>
14 #import <WebKit/WebPluginPackage.h>
15
16 #import <Foundation/NSPrivateDecls.h>
17
18 #import <CoreFoundation/CFBundlePriv.h>
19
20 #define JavaCocoaPluginIdentifier       @"com.apple.JavaPluginCocoa"
21 #define JavaCarbonPluginIdentifier      @"com.apple.JavaAppletPlugin"
22 #define JavaCFMPluginFilename           @"Java Applet Plugin Enabler"
23
24 #define QuickTimeCarbonPluginIdentifier       @"com.apple.QuickTime Plugin.plugin"
25 #define QuickTimeCocoaPluginIdentifier        @"com.apple.quicktime.webplugin"
26
27 @interface NSArray (WebPluginExtensions)
28 - (NSArray *)_web_lowercaseStrings;
29 @end;
30
31 @implementation WebBasePluginPackage
32
33 + (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath
34 {
35     WebBasePluginPackage *pluginPackage = [[WebPluginPackage alloc] initWithPath:pluginPath];
36
37     if (!pluginPackage) {
38         pluginPackage = [[WebNetscapePluginPackage alloc] initWithPath:pluginPath];
39     }
40
41     return [pluginPackage autorelease];
42 }
43
44 + (NSString *)preferredLocalizationName
45 {
46     SInt32 languageCode;
47     SInt32 regionCode;
48     SInt32 scriptCode;
49     CFStringEncoding stringEncoding;
50     
51     CFBundleGetLocalizationInfoForLocalization(NULL, &languageCode, &regionCode, &scriptCode, &stringEncoding);
52     return WebCFAutorelease(CFBundleCopyLocalizationForLocalizationInfo(languageCode, regionCode, scriptCode, stringEncoding));
53 }
54
55 - (NSString *)pathByResolvingSymlinksAndAliasesInPath:(NSString *)thePath
56 {
57     NSString *newPath = [thePath stringByResolvingSymlinksInPath];
58
59     FSRef fref;
60     OSStatus err;
61
62     err = FSPathMakeRef((const UInt8 *)[thePath fileSystemRepresentation], &fref, NULL);
63     if (err != noErr) {
64         return newPath;
65     }
66
67     Boolean targetIsFolder;
68     Boolean wasAliased;
69     err = FSResolveAliasFileWithMountFlags(&fref, TRUE, &targetIsFolder, &wasAliased, kResolveAliasFileNoUI);
70     if (err != noErr) {
71         return newPath;
72     }
73
74     if (wasAliased) {
75         CFURLRef URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fref);
76         newPath = [(NSURL *)URL path];
77         CFRelease(URL);
78     }
79
80     return newPath;
81 }
82
83 - initWithPath:(NSString *)pluginPath
84 {
85     [super init];
86     extensionToMIME = [[NSMutableDictionary alloc] init];
87     path = [[self pathByResolvingSymlinksAndAliasesInPath:pluginPath] retain];
88     bundle = [[NSBundle alloc] initWithPath:path];
89     lastModifiedDate = [[[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES] objectForKey:NSFileModificationDate] retain];
90     return self;
91 }
92
93 - (BOOL)getPluginInfoFromBundleAndMIMEDictionary:(NSDictionary *)MIMETypes
94 {
95     if (!bundle) {
96         return NO;
97     }
98     
99     if (!MIMETypes) {
100         MIMETypes = [bundle objectForInfoDictionaryKey:WebPluginMIMETypesKey];
101         if (!MIMETypes) {
102             return NO;
103         }
104     }
105
106     NSMutableDictionary *MIMEToExtensionsDictionary = [NSMutableDictionary dictionary];
107     NSMutableDictionary *MIMEToDescriptionDictionary = [NSMutableDictionary dictionary];
108     NSEnumerator *keyEnumerator = [MIMETypes keyEnumerator];
109     NSDictionary *MIMEDictionary;
110     NSString *MIME, *description;
111     NSArray *extensions;
112
113     while ((MIME = [keyEnumerator nextObject]) != nil) {
114         MIMEDictionary = [MIMETypes objectForKey:MIME];
115         
116         // FIXME: Consider storing disabled MIME types.
117         NSNumber *isEnabled = [MIMEDictionary objectForKey:WebPluginTypeEnabledKey];
118         if (isEnabled && [isEnabled boolValue] == NO) {
119             continue;
120         }
121
122         extensions = [[MIMEDictionary objectForKey:WebPluginExtensionsKey] _web_lowercaseStrings];
123         if ([extensions count] == 0) {
124             extensions = [NSArray arrayWithObject:@""];
125         }
126
127         MIME = [MIME lowercaseString];
128
129         [MIMEToExtensionsDictionary setObject:extensions forKey:MIME];
130
131         description = [MIMEDictionary objectForKey:WebPluginTypeDescriptionKey];
132         if (!description) {
133             description = @"";
134         }
135
136         [MIMEToDescriptionDictionary setObject:description forKey:MIME];
137     }
138
139     [self setMIMEToExtensionsDictionary:MIMEToExtensionsDictionary];
140     [self setMIMEToDescriptionDictionary:MIMEToDescriptionDictionary];
141
142     NSString *filename = [self filename];
143
144     NSString *theName = [bundle objectForInfoDictionaryKey:WebPluginNameKey];
145     if (!theName) {
146         theName = filename;
147     }
148     [self setName:theName];
149
150     description = [bundle objectForInfoDictionaryKey:WebPluginDescriptionKey];
151     if (!description) {
152         description = filename;
153     }
154     [self setPluginDescription:description];
155
156     return YES;
157 }
158
159 - (NSDictionary *)pListForPath:(NSString *)pListPath createFile:(BOOL)createFile
160 {
161     if (createFile && [self load] && BP_CreatePluginMIMETypesPreferences) {
162         BP_CreatePluginMIMETypesPreferences();
163     }
164     
165     NSDictionary *pList = nil;
166     NSData *data = [NSData dataWithContentsOfFile:pListPath];
167     if (data) {
168         pList = [NSPropertyListSerialization propertyListFromData:data
169                                                  mutabilityOption:NSPropertyListImmutable
170                                                            format:nil
171                                                  errorDescription:nil];
172     }
173     
174     return pList;
175 }
176
177 - (BOOL)getPluginInfoFromPLists
178 {
179     if (!bundle) {
180         return NO;
181     }
182     
183     NSDictionary *MIMETypes = nil;
184     NSString *pListFilename = [bundle objectForInfoDictionaryKey:WebPluginMIMETypesFilenameKey];
185     
186     // Check if the MIME types are claimed in a plist in the user's preferences directory.
187     if (pListFilename) {
188         NSString *pListPath = [NSString stringWithFormat:@"%@/Library/Preferences/%@", NSHomeDirectory(), pListFilename];
189         NSDictionary *pList = [self pListForPath:pListPath createFile:NO];
190         if (pList) {
191             // If the plist isn't localized, have the plug-in recreate it in the preferred language.
192             NSString *localizationName = [pList objectForKey:WebPluginLocalizationNameKey];
193             if (![localizationName isEqualToString:[[self class] preferredLocalizationName]]) {
194                 pList = [self pListForPath:pListPath createFile:YES];
195             }
196             MIMETypes = [pList objectForKey:WebPluginMIMETypesKey];
197         } else {
198             // Plist doesn't exist, ask the plug-in to create it.
199             MIMETypes = [[self pListForPath:pListPath createFile:YES] objectForKey:WebPluginMIMETypesKey];
200         }
201     }
202     
203     // Pass the MIME dictionary to the superclass to parse it.
204     return [self getPluginInfoFromBundleAndMIMEDictionary:MIMETypes];
205 }
206
207 - (BOOL)isLoaded
208 {
209     return isLoaded;
210 }
211
212 - (BOOL)load
213 {
214     if (isLoaded && bundle != nil && BP_CreatePluginMIMETypesPreferences == NULL) {
215         BP_CreatePluginMIMETypesPreferences = (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName([bundle _cfBundle], CFSTR("BP_CreatePluginMIMETypesPreferences"));
216     }
217     return isLoaded;
218 }
219
220 - (void)unload
221 {
222 }
223
224 - (void)dealloc
225 {
226     [self unload];
227     
228     [name release];
229     [path release];
230     [pluginDescription release];
231
232     [MIMEToDescription release];
233     [MIMEToExtensions release];
234     [extensionToMIME release];
235
236     [bundle release];
237
238     [lastModifiedDate release];
239     
240     [super dealloc];
241 }
242
243 - (void)finalize
244 {
245     // FIXME: Bad design to unload at dealloc/finalize time.
246     // Must be fixed for GC.
247     [self unload];
248     [super finalize];
249 }
250
251 - (NSString *)name
252 {
253     return name;
254 }
255
256 - (NSString *)path
257 {
258     return path;
259 }
260
261 - (NSString *)filename
262 {
263     return [path lastPathComponent];
264 }
265
266 - (NSString *)pluginDescription
267 {
268     return pluginDescription;
269 }
270
271 - (NSEnumerator *)extensionEnumerator
272 {
273     return [extensionToMIME keyEnumerator];
274 }
275
276 - (NSEnumerator *)MIMETypeEnumerator
277 {
278     return [MIMEToExtensions keyEnumerator];
279 }
280
281 - (NSString *)descriptionForMIMEType:(NSString *)MIMEType
282 {
283     return [MIMEToDescription objectForKey:MIMEType];
284 }
285
286 - (NSString *)MIMETypeForExtension:(NSString *)extension
287 {
288     return [extensionToMIME objectForKey:extension];
289 }
290
291 - (NSArray *)extensionsForMIMEType:(NSString *)MIMEType
292 {
293     return [MIMEToExtensions objectForKey:MIMEType];
294 }
295
296 - (NSBundle *)bundle
297 {
298     return bundle;
299 }
300
301 - (NSDate *)lastModifiedDate
302 {
303     return lastModifiedDate;
304 }
305
306 - (void)setName:(NSString *)theName
307 {
308     [name release];
309     name = [theName retain];
310 }
311
312 - (void)setPath:(NSString *)thePath
313 {
314     [path release];
315     path = [thePath retain];
316 }
317
318 - (void)setPluginDescription:(NSString *)description
319 {
320     [pluginDescription release];
321     pluginDescription = [description retain];
322 }
323
324 - (void)setMIMEToDescriptionDictionary:(NSDictionary *)MIMEToDescriptionDictionary
325 {
326     [MIMEToDescription release];
327     MIMEToDescription = [MIMEToDescriptionDictionary retain];
328 }
329
330 - (void)setMIMEToExtensionsDictionary:(NSDictionary *)MIMEToExtensionsDictionary
331 {
332     [MIMEToExtensions release];
333     MIMEToExtensions = [MIMEToExtensionsDictionary retain];
334
335     // Reverse the mapping
336     [extensionToMIME removeAllObjects];
337
338     NSEnumerator *MIMEEnumerator = [MIMEToExtensions keyEnumerator], *extensionEnumerator;
339     NSString *MIME, *extension;
340     NSArray *extensions;
341     
342     while ((MIME = [MIMEEnumerator nextObject]) != nil) {
343         extensions = [MIMEToExtensions objectForKey:MIME];
344         extensionEnumerator = [extensions objectEnumerator];
345
346         while ((extension = [extensionEnumerator nextObject]) != nil) {
347             if (![extension isEqualToString:@""]) {
348                 [extensionToMIME setObject:MIME forKey:extension];
349             }
350         }
351     }
352 }
353
354 - (NSString *)description
355 {
356     return [NSString stringWithFormat:@"name: %@\npath: %@\nmimeTypes:\n%@\npluginDescription:%@",
357         name, path, [MIMEToExtensions description], [MIMEToDescription description], pluginDescription];
358 }
359
360 - (BOOL)isEqual:(id)object
361 {
362     return ([object isKindOfClass:[WebBasePluginPackage class]] &&
363             [[object name] isEqualToString:name] &&
364             [[object lastModifiedDate] isEqual:lastModifiedDate]);
365 }
366
367 - (unsigned)hash
368 {
369     return [[name stringByAppendingString:[lastModifiedDate description]] hash];
370 }
371
372 - (BOOL)isQuickTimePlugIn
373 {
374     NSString *bundleIdentifier = [[self bundle] bundleIdentifier];
375     return [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:QuickTimeCarbonPluginIdentifier] || 
376         [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:QuickTimeCocoaPluginIdentifier];
377 }
378
379 - (BOOL)isJavaPlugIn
380 {
381     NSString *bundleIdentifier = [[self bundle] bundleIdentifier];
382     return [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:JavaCocoaPluginIdentifier] || 
383         [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:JavaCarbonPluginIdentifier] ||
384         [[path lastPathComponent] _webkit_isCaseInsensitiveEqualToString:JavaCFMPluginFilename];
385 }
386
387 @end
388
389 @implementation NSArray (WebPluginExtensions)
390
391 - (NSArray *)_web_lowercaseStrings
392 {
393     NSMutableArray *lowercaseStrings = [NSMutableArray arrayWithCapacity:[self count]];
394     NSEnumerator *strings = [self objectEnumerator];
395     NSString *string;
396
397     while ((string = [strings nextObject]) != nil) {
398         if ([string isKindOfClass:[NSString class]]) {
399             [lowercaseStrings addObject:[string lowercaseString]];
400         }
401     }
402
403     return lowercaseStrings;
404 }
405
406 @end;