|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 nsPluginsDirDarwin.cpp |
|
8 |
|
9 Mac OS X implementation of the nsPluginsDir/nsPluginsFile classes. |
|
10 |
|
11 by Patrick C. Beard. |
|
12 */ |
|
13 |
|
14 #include "GeckoChildProcessHost.h" |
|
15 #include "base/process_util.h" |
|
16 |
|
17 #include "prlink.h" |
|
18 #include "prnetdb.h" |
|
19 #include "nsXPCOM.h" |
|
20 |
|
21 #include "nsPluginsDir.h" |
|
22 #include "nsNPAPIPlugin.h" |
|
23 #include "nsPluginsDirUtils.h" |
|
24 |
|
25 #include "nsILocalFileMac.h" |
|
26 |
|
27 #include <string.h> |
|
28 #include <stdio.h> |
|
29 #include <unistd.h> |
|
30 #include <fcntl.h> |
|
31 |
|
32 #include <Carbon/Carbon.h> |
|
33 #include <CoreServices/CoreServices.h> |
|
34 #include <mach-o/loader.h> |
|
35 #include <mach-o/fat.h> |
|
36 |
|
37 typedef NS_NPAPIPLUGIN_CALLBACK(const char *, NP_GETMIMEDESCRIPTION) (); |
|
38 typedef NS_NPAPIPLUGIN_CALLBACK(OSErr, BP_GETSUPPORTEDMIMETYPES) (BPSupportedMIMETypes *mimeInfo, UInt32 flags); |
|
39 |
|
40 |
|
41 /* |
|
42 ** Returns a CFBundleRef if the path refers to a Mac OS X bundle directory. |
|
43 ** The caller is responsible for calling CFRelease() to deallocate. |
|
44 */ |
|
45 static CFBundleRef getPluginBundle(const char* path) |
|
46 { |
|
47 CFBundleRef bundle = nullptr; |
|
48 CFStringRef pathRef = ::CFStringCreateWithCString(nullptr, path, |
|
49 kCFStringEncodingUTF8); |
|
50 if (pathRef) { |
|
51 CFURLRef bundleURL = ::CFURLCreateWithFileSystemPath(nullptr, pathRef, |
|
52 kCFURLPOSIXPathStyle, |
|
53 true); |
|
54 if (bundleURL) { |
|
55 bundle = ::CFBundleCreate(nullptr, bundleURL); |
|
56 ::CFRelease(bundleURL); |
|
57 } |
|
58 ::CFRelease(pathRef); |
|
59 } |
|
60 return bundle; |
|
61 } |
|
62 |
|
63 static nsresult toCFURLRef(nsIFile* file, CFURLRef& outURL) |
|
64 { |
|
65 nsCOMPtr<nsILocalFileMac> lfm = do_QueryInterface(file); |
|
66 if (!lfm) |
|
67 return NS_ERROR_FAILURE; |
|
68 CFURLRef url; |
|
69 nsresult rv = lfm->GetCFURL(&url); |
|
70 if (NS_SUCCEEDED(rv)) |
|
71 outURL = url; |
|
72 |
|
73 return rv; |
|
74 } |
|
75 |
|
76 bool nsPluginsDir::IsPluginFile(nsIFile* file) |
|
77 { |
|
78 nsCString fileName; |
|
79 file->GetNativeLeafName(fileName); |
|
80 /* |
|
81 * Don't load the VDP fake plugin, to avoid tripping a bad bug in OS X |
|
82 * 10.5.3 (see bug 436575). |
|
83 */ |
|
84 if (!strcmp(fileName.get(), "VerifiedDownloadPlugin.plugin")) { |
|
85 NS_WARNING("Preventing load of VerifiedDownloadPlugin.plugin (see bug 436575)"); |
|
86 return false; |
|
87 } |
|
88 return true; |
|
89 } |
|
90 |
|
91 // Caller is responsible for freeing returned buffer. |
|
92 static char* CFStringRefToUTF8Buffer(CFStringRef cfString) |
|
93 { |
|
94 const char* buffer = ::CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8); |
|
95 if (buffer) { |
|
96 return PL_strdup(buffer); |
|
97 } |
|
98 |
|
99 int bufferLength = |
|
100 ::CFStringGetMaximumSizeForEncoding(::CFStringGetLength(cfString), |
|
101 kCFStringEncodingUTF8) + 1; |
|
102 char* newBuffer = static_cast<char*>(NS_Alloc(bufferLength)); |
|
103 if (!newBuffer) { |
|
104 return nullptr; |
|
105 } |
|
106 |
|
107 if (!::CFStringGetCString(cfString, newBuffer, bufferLength, |
|
108 kCFStringEncodingUTF8)) { |
|
109 NS_Free(newBuffer); |
|
110 return nullptr; |
|
111 } |
|
112 |
|
113 newBuffer = static_cast<char*>(NS_Realloc(newBuffer, |
|
114 strlen(newBuffer) + 1)); |
|
115 return newBuffer; |
|
116 } |
|
117 |
|
118 class AutoCFTypeObject { |
|
119 public: |
|
120 AutoCFTypeObject(CFTypeRef object) |
|
121 { |
|
122 mObject = object; |
|
123 } |
|
124 ~AutoCFTypeObject() |
|
125 { |
|
126 ::CFRelease(mObject); |
|
127 } |
|
128 private: |
|
129 CFTypeRef mObject; |
|
130 }; |
|
131 |
|
132 static Boolean MimeTypeEnabled(CFDictionaryRef mimeDict) { |
|
133 if (!mimeDict) { |
|
134 return true; |
|
135 } |
|
136 |
|
137 CFTypeRef value; |
|
138 if (::CFDictionaryGetValueIfPresent(mimeDict, CFSTR("WebPluginTypeEnabled"), &value)) { |
|
139 if (value && ::CFGetTypeID(value) == ::CFBooleanGetTypeID()) { |
|
140 return ::CFBooleanGetValue(static_cast<CFBooleanRef>(value)); |
|
141 } |
|
142 } |
|
143 return true; |
|
144 } |
|
145 |
|
146 static CFDictionaryRef ParsePlistForMIMETypesFilename(CFBundleRef bundle) |
|
147 { |
|
148 CFTypeRef mimeFileName = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypesFilename")); |
|
149 if (!mimeFileName || ::CFGetTypeID(mimeFileName) != ::CFStringGetTypeID()) { |
|
150 return nullptr; |
|
151 } |
|
152 |
|
153 FSRef homeDir; |
|
154 if (::FSFindFolder(kUserDomain, kCurrentUserFolderType, kDontCreateFolder, &homeDir) != noErr) { |
|
155 return nullptr; |
|
156 } |
|
157 |
|
158 CFURLRef userDirURL = ::CFURLCreateFromFSRef(kCFAllocatorDefault, &homeDir); |
|
159 if (!userDirURL) { |
|
160 return nullptr; |
|
161 } |
|
162 |
|
163 AutoCFTypeObject userDirURLAutorelease(userDirURL); |
|
164 CFStringRef mimeFilePath = ::CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("Library/Preferences/%@"), static_cast<CFStringRef>(mimeFileName)); |
|
165 if (!mimeFilePath) { |
|
166 return nullptr; |
|
167 } |
|
168 |
|
169 AutoCFTypeObject mimeFilePathAutorelease(mimeFilePath); |
|
170 CFURLRef mimeFileURL = ::CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault, mimeFilePath, kCFURLPOSIXPathStyle, false, userDirURL); |
|
171 if (!mimeFileURL) { |
|
172 return nullptr; |
|
173 } |
|
174 |
|
175 AutoCFTypeObject mimeFileURLAutorelease(mimeFileURL); |
|
176 SInt32 errorCode = 0; |
|
177 CFDataRef mimeFileData = nullptr; |
|
178 Boolean result = ::CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, mimeFileURL, &mimeFileData, nullptr, nullptr, &errorCode); |
|
179 if (!result) { |
|
180 return nullptr; |
|
181 } |
|
182 |
|
183 AutoCFTypeObject mimeFileDataAutorelease(mimeFileData); |
|
184 if (errorCode != 0) { |
|
185 return nullptr; |
|
186 } |
|
187 |
|
188 CFPropertyListRef propertyList = ::CFPropertyListCreateFromXMLData(kCFAllocatorDefault, mimeFileData, kCFPropertyListImmutable, nullptr); |
|
189 if (!propertyList) { |
|
190 return nullptr; |
|
191 } |
|
192 |
|
193 AutoCFTypeObject propertyListAutorelease(propertyList); |
|
194 if (::CFGetTypeID(propertyList) != ::CFDictionaryGetTypeID()) { |
|
195 return nullptr; |
|
196 } |
|
197 |
|
198 CFTypeRef mimeTypes = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(propertyList), CFSTR("WebPluginMIMETypes")); |
|
199 if (!mimeTypes || ::CFGetTypeID(mimeTypes) != ::CFDictionaryGetTypeID() || ::CFDictionaryGetCount(static_cast<CFDictionaryRef>(mimeTypes)) == 0) { |
|
200 return nullptr; |
|
201 } |
|
202 |
|
203 return static_cast<CFDictionaryRef>(::CFRetain(mimeTypes)); |
|
204 } |
|
205 |
|
206 static void ParsePlistPluginInfo(nsPluginInfo& info, CFBundleRef bundle) |
|
207 { |
|
208 CFDictionaryRef mimeDict = ParsePlistForMIMETypesFilename(bundle); |
|
209 |
|
210 if (!mimeDict) { |
|
211 CFTypeRef mimeTypes = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginMIMETypes")); |
|
212 if (!mimeTypes || ::CFGetTypeID(mimeTypes) != ::CFDictionaryGetTypeID() || ::CFDictionaryGetCount(static_cast<CFDictionaryRef>(mimeTypes)) == 0) |
|
213 return; |
|
214 mimeDict = static_cast<CFDictionaryRef>(::CFRetain(mimeTypes)); |
|
215 } |
|
216 |
|
217 AutoCFTypeObject mimeDictAutorelease(mimeDict); |
|
218 int mimeDictKeyCount = ::CFDictionaryGetCount(mimeDict); |
|
219 |
|
220 // Allocate memory for mime data |
|
221 int mimeDataArraySize = mimeDictKeyCount * sizeof(char*); |
|
222 info.fMimeTypeArray = static_cast<char**>(NS_Alloc(mimeDataArraySize)); |
|
223 if (!info.fMimeTypeArray) |
|
224 return; |
|
225 memset(info.fMimeTypeArray, 0, mimeDataArraySize); |
|
226 info.fExtensionArray = static_cast<char**>(NS_Alloc(mimeDataArraySize)); |
|
227 if (!info.fExtensionArray) |
|
228 return; |
|
229 memset(info.fExtensionArray, 0, mimeDataArraySize); |
|
230 info.fMimeDescriptionArray = static_cast<char**>(NS_Alloc(mimeDataArraySize)); |
|
231 if (!info.fMimeDescriptionArray) |
|
232 return; |
|
233 memset(info.fMimeDescriptionArray, 0, mimeDataArraySize); |
|
234 |
|
235 // Allocate memory for mime dictionary keys and values |
|
236 nsAutoArrayPtr<CFTypeRef> keys(new CFTypeRef[mimeDictKeyCount]); |
|
237 if (!keys) |
|
238 return; |
|
239 nsAutoArrayPtr<CFTypeRef> values(new CFTypeRef[mimeDictKeyCount]); |
|
240 if (!values) |
|
241 return; |
|
242 |
|
243 info.fVariantCount = 0; |
|
244 |
|
245 ::CFDictionaryGetKeysAndValues(mimeDict, keys, values); |
|
246 for (int i = 0; i < mimeDictKeyCount; i++) { |
|
247 CFTypeRef mimeString = keys[i]; |
|
248 if (!mimeString || ::CFGetTypeID(mimeString) != ::CFStringGetTypeID()) { |
|
249 continue; |
|
250 } |
|
251 CFTypeRef mimeDict = values[i]; |
|
252 if (mimeDict && ::CFGetTypeID(mimeDict) == ::CFDictionaryGetTypeID()) { |
|
253 if (!MimeTypeEnabled(static_cast<CFDictionaryRef>(mimeDict))) { |
|
254 continue; |
|
255 } |
|
256 info.fMimeTypeArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(mimeString)); |
|
257 if (!info.fMimeTypeArray[info.fVariantCount]) { |
|
258 continue; |
|
259 } |
|
260 CFTypeRef extensions = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginExtensions")); |
|
261 if (extensions && ::CFGetTypeID(extensions) == ::CFArrayGetTypeID()) { |
|
262 int extensionCount = ::CFArrayGetCount(static_cast<CFArrayRef>(extensions)); |
|
263 CFMutableStringRef extensionList = ::CFStringCreateMutable(kCFAllocatorDefault, 0); |
|
264 for (int j = 0; j < extensionCount; j++) { |
|
265 CFTypeRef extension = ::CFArrayGetValueAtIndex(static_cast<CFArrayRef>(extensions), j); |
|
266 if (extension && ::CFGetTypeID(extension) == ::CFStringGetTypeID()) { |
|
267 if (j > 0) |
|
268 ::CFStringAppend(extensionList, CFSTR(",")); |
|
269 ::CFStringAppend(static_cast<CFMutableStringRef>(extensionList), static_cast<CFStringRef>(extension)); |
|
270 } |
|
271 } |
|
272 info.fExtensionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(extensionList)); |
|
273 ::CFRelease(extensionList); |
|
274 } |
|
275 CFTypeRef description = ::CFDictionaryGetValue(static_cast<CFDictionaryRef>(mimeDict), CFSTR("WebPluginTypeDescription")); |
|
276 if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID()) |
|
277 info.fMimeDescriptionArray[info.fVariantCount] = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description)); |
|
278 } |
|
279 info.fVariantCount++; |
|
280 } |
|
281 } |
|
282 |
|
283 nsPluginFile::nsPluginFile(nsIFile *spec) |
|
284 : mPlugin(spec) |
|
285 { |
|
286 } |
|
287 |
|
288 nsPluginFile::~nsPluginFile() {} |
|
289 |
|
290 nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) |
|
291 { |
|
292 if (!mPlugin) |
|
293 return NS_ERROR_NULL_POINTER; |
|
294 |
|
295 // 64-bit NSPR does not (yet) support bundles. So in 64-bit builds we need |
|
296 // (for now) to load the bundle's executable. However this can cause |
|
297 // problems: CFBundleCreate() doesn't run the bundle's executable's |
|
298 // initialization code, while NSAddImage() and dlopen() do run it. So using |
|
299 // NSPR's dyld loading mechanisms here (NSAddImage() or dlopen()) can cause |
|
300 // a bundle's initialization code to run earlier than expected, and lead to |
|
301 // crashes. See bug 577967. |
|
302 #ifdef __LP64__ |
|
303 char executablePath[PATH_MAX]; |
|
304 executablePath[0] = '\0'; |
|
305 nsAutoCString bundlePath; |
|
306 mPlugin->GetNativePath(bundlePath); |
|
307 CFStringRef pathRef = ::CFStringCreateWithCString(nullptr, bundlePath.get(), |
|
308 kCFStringEncodingUTF8); |
|
309 if (pathRef) { |
|
310 CFURLRef bundleURL = ::CFURLCreateWithFileSystemPath(nullptr, pathRef, |
|
311 kCFURLPOSIXPathStyle, |
|
312 true); |
|
313 if (bundleURL) { |
|
314 CFBundleRef bundle = ::CFBundleCreate(nullptr, bundleURL); |
|
315 if (bundle) { |
|
316 CFURLRef executableURL = ::CFBundleCopyExecutableURL(bundle); |
|
317 if (executableURL) { |
|
318 if (!::CFURLGetFileSystemRepresentation(executableURL, true, (UInt8*)&executablePath, PATH_MAX)) |
|
319 executablePath[0] = '\0'; |
|
320 ::CFRelease(executableURL); |
|
321 } |
|
322 ::CFRelease(bundle); |
|
323 } |
|
324 ::CFRelease(bundleURL); |
|
325 } |
|
326 ::CFRelease(pathRef); |
|
327 } |
|
328 #else |
|
329 nsAutoCString bundlePath; |
|
330 mPlugin->GetNativePath(bundlePath); |
|
331 const char *executablePath = bundlePath.get(); |
|
332 #endif |
|
333 |
|
334 *outLibrary = PR_LoadLibrary(executablePath); |
|
335 pLibrary = *outLibrary; |
|
336 if (!pLibrary) { |
|
337 return NS_ERROR_FAILURE; |
|
338 } |
|
339 #ifdef DEBUG |
|
340 printf("[loaded plugin %s]\n", bundlePath.get()); |
|
341 #endif |
|
342 return NS_OK; |
|
343 } |
|
344 |
|
345 static char* p2cstrdup(StringPtr pstr) |
|
346 { |
|
347 int len = pstr[0]; |
|
348 char* cstr = static_cast<char*>(NS_Alloc(len + 1)); |
|
349 if (cstr) { |
|
350 memmove(cstr, pstr + 1, len); |
|
351 cstr[len] = '\0'; |
|
352 } |
|
353 return cstr; |
|
354 } |
|
355 |
|
356 static char* GetNextPluginStringFromHandle(Handle h, short *index) |
|
357 { |
|
358 char *ret = p2cstrdup((unsigned char*)(*h + *index)); |
|
359 *index += (ret ? strlen(ret) : 0) + 1; |
|
360 return ret; |
|
361 } |
|
362 |
|
363 static bool IsCompatibleArch(nsIFile *file) |
|
364 { |
|
365 CFURLRef pluginURL = nullptr; |
|
366 if (NS_FAILED(toCFURLRef(file, pluginURL))) |
|
367 return false; |
|
368 |
|
369 bool isPluginFile = false; |
|
370 |
|
371 CFBundleRef pluginBundle = ::CFBundleCreate(kCFAllocatorDefault, pluginURL); |
|
372 if (pluginBundle) { |
|
373 UInt32 packageType, packageCreator; |
|
374 ::CFBundleGetPackageInfo(pluginBundle, &packageType, &packageCreator); |
|
375 if (packageType == 'BRPL' || packageType == 'IEPL' || packageType == 'NSPL') { |
|
376 // Get path to plugin as a C string. |
|
377 char executablePath[PATH_MAX]; |
|
378 executablePath[0] = '\0'; |
|
379 if (!::CFURLGetFileSystemRepresentation(pluginURL, true, (UInt8*)&executablePath, PATH_MAX)) { |
|
380 executablePath[0] = '\0'; |
|
381 } |
|
382 |
|
383 uint32_t pluginLibArchitectures; |
|
384 nsresult rv = mozilla::ipc::GeckoChildProcessHost::GetArchitecturesForBinary(executablePath, &pluginLibArchitectures); |
|
385 if (NS_FAILED(rv)) { |
|
386 return false; |
|
387 } |
|
388 |
|
389 uint32_t supportedArchitectures = |
|
390 #ifdef __LP64__ |
|
391 mozilla::ipc::GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType_Plugin); |
|
392 #else |
|
393 base::GetCurrentProcessArchitecture(); |
|
394 #endif |
|
395 |
|
396 // Consider the plugin architecture valid if there is any overlap in the masks. |
|
397 isPluginFile = !!(supportedArchitectures & pluginLibArchitectures); |
|
398 } |
|
399 ::CFRelease(pluginBundle); |
|
400 } |
|
401 |
|
402 ::CFRelease(pluginURL); |
|
403 return isPluginFile; |
|
404 } |
|
405 |
|
406 /** |
|
407 * Obtains all of the information currently available for this plugin. |
|
408 */ |
|
409 nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary) |
|
410 { |
|
411 *outLibrary = nullptr; |
|
412 |
|
413 nsresult rv = NS_OK; |
|
414 |
|
415 if (!IsCompatibleArch(mPlugin)) { |
|
416 return NS_ERROR_FAILURE; |
|
417 } |
|
418 |
|
419 // clear out the info, except for the first field. |
|
420 memset(&info, 0, sizeof(info)); |
|
421 |
|
422 // Try to get a bundle reference. |
|
423 nsAutoCString path; |
|
424 if (NS_FAILED(rv = mPlugin->GetNativePath(path))) |
|
425 return rv; |
|
426 CFBundleRef bundle = getPluginBundle(path.get()); |
|
427 |
|
428 // fill in full path |
|
429 info.fFullPath = PL_strdup(path.get()); |
|
430 |
|
431 // fill in file name |
|
432 nsAutoCString fileName; |
|
433 if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName))) |
|
434 return rv; |
|
435 info.fFileName = PL_strdup(fileName.get()); |
|
436 |
|
437 // Get fName |
|
438 if (bundle) { |
|
439 CFTypeRef name = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginName")); |
|
440 if (name && ::CFGetTypeID(name) == ::CFStringGetTypeID()) |
|
441 info.fName = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(name)); |
|
442 } |
|
443 |
|
444 // Get fDescription |
|
445 if (bundle) { |
|
446 CFTypeRef description = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("WebPluginDescription")); |
|
447 if (description && ::CFGetTypeID(description) == ::CFStringGetTypeID()) |
|
448 info.fDescription = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(description)); |
|
449 } |
|
450 |
|
451 // Get fVersion |
|
452 if (bundle) { |
|
453 // Look for the release version first |
|
454 CFTypeRef version = ::CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString")); |
|
455 if (!version) // try the build version |
|
456 version = ::CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey); |
|
457 if (version && ::CFGetTypeID(version) == ::CFStringGetTypeID()) |
|
458 info.fVersion = CFStringRefToUTF8Buffer(static_cast<CFStringRef>(version)); |
|
459 } |
|
460 |
|
461 // The last thing we need to do is get MIME data |
|
462 // fVariantCount, fMimeTypeArray, fExtensionArray, fMimeDescriptionArray |
|
463 |
|
464 // First look for data in a bundle plist |
|
465 if (bundle) { |
|
466 ParsePlistPluginInfo(info, bundle); |
|
467 ::CFRelease(bundle); |
|
468 if (info.fVariantCount > 0) |
|
469 return NS_OK; |
|
470 } |
|
471 |
|
472 // It's possible that our plugin has 2 entry points that'll give us mime type |
|
473 // info. Quicktime does this to get around the need of having admin rights to |
|
474 // change mime info in the resource fork. We need to use this info instead of |
|
475 // the resource. See bug 113464. |
|
476 |
|
477 // Sadly we have to load the library for this to work. |
|
478 rv = LoadPlugin(outLibrary); |
|
479 if (NS_FAILED(rv)) |
|
480 return rv; |
|
481 |
|
482 // Try to get data from NP_GetMIMEDescription |
|
483 if (pLibrary) { |
|
484 NP_GETMIMEDESCRIPTION pfnGetMimeDesc = (NP_GETMIMEDESCRIPTION)PR_FindFunctionSymbol(pLibrary, NP_GETMIMEDESCRIPTION_NAME); |
|
485 if (pfnGetMimeDesc) |
|
486 ParsePluginMimeDescription(pfnGetMimeDesc(), info); |
|
487 if (info.fVariantCount) |
|
488 return NS_OK; |
|
489 } |
|
490 |
|
491 // We'll fill this in using BP_GetSupportedMIMETypes and/or resource fork data |
|
492 BPSupportedMIMETypes mi = {kBPSupportedMIMETypesStructVers_1, nullptr, nullptr}; |
|
493 |
|
494 // Try to get data from BP_GetSupportedMIMETypes |
|
495 if (pLibrary) { |
|
496 BP_GETSUPPORTEDMIMETYPES pfnMime = (BP_GETSUPPORTEDMIMETYPES)PR_FindFunctionSymbol(pLibrary, "BP_GetSupportedMIMETypes"); |
|
497 if (pfnMime && noErr == pfnMime(&mi, 0) && mi.typeStrings) { |
|
498 info.fVariantCount = (**(short**)mi.typeStrings) / 2; |
|
499 ::HLock(mi.typeStrings); |
|
500 if (mi.infoStrings) // it's possible some plugins have infoStrings missing |
|
501 ::HLock(mi.infoStrings); |
|
502 } |
|
503 } |
|
504 |
|
505 // Fill in the info struct based on the data in the BPSupportedMIMETypes struct |
|
506 int variantCount = info.fVariantCount; |
|
507 info.fMimeTypeArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*))); |
|
508 if (!info.fMimeTypeArray) |
|
509 return NS_ERROR_OUT_OF_MEMORY; |
|
510 info.fExtensionArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*))); |
|
511 if (!info.fExtensionArray) |
|
512 return NS_ERROR_OUT_OF_MEMORY; |
|
513 if (mi.infoStrings) { |
|
514 info.fMimeDescriptionArray = static_cast<char**>(NS_Alloc(variantCount * sizeof(char*))); |
|
515 if (!info.fMimeDescriptionArray) |
|
516 return NS_ERROR_OUT_OF_MEMORY; |
|
517 } |
|
518 short mimeIndex = 2; |
|
519 short descriptionIndex = 2; |
|
520 for (int i = 0; i < variantCount; i++) { |
|
521 info.fMimeTypeArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex); |
|
522 info.fExtensionArray[i] = GetNextPluginStringFromHandle(mi.typeStrings, &mimeIndex); |
|
523 if (mi.infoStrings) |
|
524 info.fMimeDescriptionArray[i] = GetNextPluginStringFromHandle(mi.infoStrings, &descriptionIndex); |
|
525 } |
|
526 |
|
527 ::HUnlock(mi.typeStrings); |
|
528 ::DisposeHandle(mi.typeStrings); |
|
529 if (mi.infoStrings) { |
|
530 ::HUnlock(mi.infoStrings); |
|
531 ::DisposeHandle(mi.infoStrings); |
|
532 } |
|
533 |
|
534 return NS_OK; |
|
535 } |
|
536 |
|
537 nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info) |
|
538 { |
|
539 NS_Free(info.fName); |
|
540 NS_Free(info.fDescription); |
|
541 int variantCount = info.fVariantCount; |
|
542 for (int i = 0; i < variantCount; i++) { |
|
543 NS_Free(info.fMimeTypeArray[i]); |
|
544 NS_Free(info.fExtensionArray[i]); |
|
545 NS_Free(info.fMimeDescriptionArray[i]); |
|
546 } |
|
547 NS_Free(info.fMimeTypeArray); |
|
548 NS_Free(info.fMimeDescriptionArray); |
|
549 NS_Free(info.fExtensionArray); |
|
550 NS_Free(info.fFileName); |
|
551 NS_Free(info.fFullPath); |
|
552 NS_Free(info.fVersion); |
|
553 |
|
554 return NS_OK; |
|
555 } |