|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
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 #include "nsPluginDirServiceProvider.h" |
|
7 |
|
8 #include "nsCRT.h" |
|
9 #include "nsIFile.h" |
|
10 #include "nsDependentString.h" |
|
11 #include "nsArrayEnumerator.h" |
|
12 #include "mozilla/Preferences.h" |
|
13 |
|
14 #include <windows.h> |
|
15 #include "nsIWindowsRegKey.h" |
|
16 |
|
17 using namespace mozilla; |
|
18 |
|
19 typedef struct structVer |
|
20 { |
|
21 WORD wMajor; |
|
22 WORD wMinor; |
|
23 WORD wRelease; |
|
24 WORD wBuild; |
|
25 } verBlock; |
|
26 |
|
27 static void |
|
28 ClearVersion(verBlock *ver) |
|
29 { |
|
30 ver->wMajor = 0; |
|
31 ver->wMinor = 0; |
|
32 ver->wRelease = 0; |
|
33 ver->wBuild = 0; |
|
34 } |
|
35 |
|
36 static BOOL |
|
37 FileExists(LPCWSTR szFile) |
|
38 { |
|
39 return GetFileAttributesW(szFile) != 0xFFFFFFFF; |
|
40 } |
|
41 |
|
42 // Get file version information from a file |
|
43 static BOOL |
|
44 GetFileVersion(LPCWSTR szFile, verBlock *vbVersion) |
|
45 { |
|
46 UINT uLen; |
|
47 UINT dwLen; |
|
48 BOOL bRv; |
|
49 DWORD dwHandle; |
|
50 LPVOID lpData; |
|
51 LPVOID lpBuffer; |
|
52 VS_FIXEDFILEINFO *lpBuffer2; |
|
53 |
|
54 ClearVersion(vbVersion); |
|
55 if (FileExists(szFile)) { |
|
56 bRv = TRUE; |
|
57 LPCWSTR lpFilepath = szFile; |
|
58 dwLen = GetFileVersionInfoSizeW(lpFilepath, &dwHandle); |
|
59 lpData = (LPVOID)malloc(dwLen); |
|
60 uLen = 0; |
|
61 |
|
62 if (lpData && GetFileVersionInfoW(lpFilepath, dwHandle, dwLen, lpData) != 0) { |
|
63 if (VerQueryValueW(lpData, L"\\", &lpBuffer, &uLen) != 0) { |
|
64 lpBuffer2 = (VS_FIXEDFILEINFO *)lpBuffer; |
|
65 |
|
66 vbVersion->wMajor = HIWORD(lpBuffer2->dwFileVersionMS); |
|
67 vbVersion->wMinor = LOWORD(lpBuffer2->dwFileVersionMS); |
|
68 vbVersion->wRelease = HIWORD(lpBuffer2->dwFileVersionLS); |
|
69 vbVersion->wBuild = LOWORD(lpBuffer2->dwFileVersionLS); |
|
70 } |
|
71 } |
|
72 |
|
73 free(lpData); |
|
74 } else { |
|
75 /* File does not exist */ |
|
76 bRv = FALSE; |
|
77 } |
|
78 |
|
79 return bRv; |
|
80 } |
|
81 |
|
82 // Will deep copy ver2 into ver1 |
|
83 static void |
|
84 CopyVersion(verBlock *ver1, verBlock *ver2) |
|
85 { |
|
86 ver1->wMajor = ver2->wMajor; |
|
87 ver1->wMinor = ver2->wMinor; |
|
88 ver1->wRelease = ver2->wRelease; |
|
89 ver1->wBuild = ver2->wBuild; |
|
90 } |
|
91 |
|
92 // Convert a string version to a version struct |
|
93 static void |
|
94 TranslateVersionStr(const WCHAR* szVersion, verBlock *vbVersion) |
|
95 { |
|
96 WCHAR* szNum1 = nullptr; |
|
97 WCHAR* szNum2 = nullptr; |
|
98 WCHAR* szNum3 = nullptr; |
|
99 WCHAR* szNum4 = nullptr; |
|
100 WCHAR* szJavaBuild = nullptr; |
|
101 |
|
102 WCHAR *strVer = nullptr; |
|
103 if (szVersion) { |
|
104 strVer = wcsdup(szVersion); |
|
105 } |
|
106 |
|
107 if (!strVer) { |
|
108 // Out of memory |
|
109 ClearVersion(vbVersion); |
|
110 return; |
|
111 } |
|
112 |
|
113 // Java may be using an underscore instead of a dot for the build ID |
|
114 szJavaBuild = wcschr(strVer, '_'); |
|
115 if (szJavaBuild) { |
|
116 szJavaBuild[0] = '.'; |
|
117 } |
|
118 |
|
119 szNum1 = wcstok(strVer, L"."); |
|
120 szNum2 = wcstok(nullptr, L"."); |
|
121 szNum3 = wcstok(nullptr, L"."); |
|
122 szNum4 = wcstok(nullptr, L"."); |
|
123 |
|
124 vbVersion->wMajor = szNum1 ? (WORD) _wtoi(szNum1) : 0; |
|
125 vbVersion->wMinor = szNum2 ? (WORD) _wtoi(szNum2) : 0; |
|
126 vbVersion->wRelease = szNum3 ? (WORD) _wtoi(szNum3) : 0; |
|
127 vbVersion->wBuild = szNum4 ? (WORD) _wtoi(szNum4) : 0; |
|
128 |
|
129 free(strVer); |
|
130 } |
|
131 |
|
132 // Compare two version struct, return zero if the same |
|
133 static int |
|
134 CompareVersion(verBlock vbVersionOld, verBlock vbVersionNew) |
|
135 { |
|
136 if (vbVersionOld.wMajor > vbVersionNew.wMajor) { |
|
137 return 4; |
|
138 } else if (vbVersionOld.wMajor < vbVersionNew.wMajor) { |
|
139 return -4; |
|
140 } |
|
141 |
|
142 if (vbVersionOld.wMinor > vbVersionNew.wMinor) { |
|
143 return 3; |
|
144 } else if (vbVersionOld.wMinor < vbVersionNew.wMinor) { |
|
145 return -3; |
|
146 } |
|
147 |
|
148 if (vbVersionOld.wRelease > vbVersionNew.wRelease) { |
|
149 return 2; |
|
150 } else if (vbVersionOld.wRelease < vbVersionNew.wRelease) { |
|
151 return -2; |
|
152 } |
|
153 |
|
154 if (vbVersionOld.wBuild > vbVersionNew.wBuild) { |
|
155 return 1; |
|
156 } else if (vbVersionOld.wBuild < vbVersionNew.wBuild) { |
|
157 return -1; |
|
158 } |
|
159 |
|
160 /* the versions are all the same */ |
|
161 return 0; |
|
162 } |
|
163 |
|
164 //***************************************************************************** |
|
165 // nsPluginDirServiceProvider::Constructor/Destructor |
|
166 //***************************************************************************** |
|
167 |
|
168 nsPluginDirServiceProvider::nsPluginDirServiceProvider() |
|
169 { |
|
170 } |
|
171 |
|
172 nsPluginDirServiceProvider::~nsPluginDirServiceProvider() |
|
173 { |
|
174 } |
|
175 |
|
176 //***************************************************************************** |
|
177 // nsPluginDirServiceProvider::nsISupports |
|
178 //***************************************************************************** |
|
179 |
|
180 NS_IMPL_ISUPPORTS(nsPluginDirServiceProvider, |
|
181 nsIDirectoryServiceProvider) |
|
182 |
|
183 //***************************************************************************** |
|
184 // nsPluginDirServiceProvider::nsIDirectoryServiceProvider |
|
185 //***************************************************************************** |
|
186 |
|
187 NS_IMETHODIMP |
|
188 nsPluginDirServiceProvider::GetFile(const char *charProp, bool *persistant, |
|
189 nsIFile **_retval) |
|
190 { |
|
191 nsCOMPtr<nsIFile> localFile; |
|
192 nsresult rv = NS_ERROR_FAILURE; |
|
193 |
|
194 NS_ENSURE_ARG(charProp); |
|
195 |
|
196 *_retval = nullptr; |
|
197 *persistant = false; |
|
198 |
|
199 nsCOMPtr<nsIWindowsRegKey> regKey = |
|
200 do_CreateInstance("@mozilla.org/windows-registry-key;1"); |
|
201 NS_ENSURE_TRUE(regKey, NS_ERROR_FAILURE); |
|
202 |
|
203 if (nsCRT::strcmp(charProp, NS_WIN_QUICKTIME_SCAN_KEY) == 0) { |
|
204 nsAdoptingCString strVer = Preferences::GetCString(charProp); |
|
205 if (!strVer) { |
|
206 return NS_ERROR_FAILURE; |
|
207 } |
|
208 verBlock minVer; |
|
209 TranslateVersionStr(NS_ConvertASCIItoUTF16(strVer).get(), &minVer); |
|
210 |
|
211 // Look for the Quicktime system installation plugins directory |
|
212 verBlock qtVer; |
|
213 ClearVersion(&qtVer); |
|
214 |
|
215 // First we need to check the version of Quicktime via checking |
|
216 // the EXE's version table |
|
217 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, |
|
218 NS_LITERAL_STRING("software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\QuickTimePlayer.exe"), |
|
219 nsIWindowsRegKey::ACCESS_READ); |
|
220 if (NS_SUCCEEDED(rv)) { |
|
221 nsAutoString path; |
|
222 rv = regKey->ReadStringValue(NS_LITERAL_STRING(""), path); |
|
223 if (NS_SUCCEEDED(rv)) { |
|
224 GetFileVersion(path.get(), &qtVer); |
|
225 } |
|
226 regKey->Close(); |
|
227 } |
|
228 if (CompareVersion(qtVer, minVer) < 0) |
|
229 return rv; |
|
230 |
|
231 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, |
|
232 NS_LITERAL_STRING("software\\Apple Computer, Inc.\\QuickTime"), |
|
233 nsIWindowsRegKey::ACCESS_READ); |
|
234 if (NS_SUCCEEDED(rv)) { |
|
235 nsAutoString path; |
|
236 rv = regKey->ReadStringValue(NS_LITERAL_STRING("InstallDir"), path); |
|
237 if (NS_SUCCEEDED(rv)) { |
|
238 path += NS_LITERAL_STRING("\\Plugins"); |
|
239 rv = NS_NewLocalFile(path, true, |
|
240 getter_AddRefs(localFile)); |
|
241 } |
|
242 } |
|
243 } else if (nsCRT::strcmp(charProp, NS_WIN_WMP_SCAN_KEY) == 0) { |
|
244 nsAdoptingCString strVer = Preferences::GetCString(charProp); |
|
245 if (!strVer) { |
|
246 return NS_ERROR_FAILURE; |
|
247 } |
|
248 verBlock minVer; |
|
249 TranslateVersionStr(NS_ConvertASCIItoUTF16(strVer).get(), &minVer); |
|
250 |
|
251 // Look for Windows Media Player system installation plugins directory |
|
252 verBlock wmpVer; |
|
253 ClearVersion(&wmpVer); |
|
254 |
|
255 // First we need to check the version of WMP |
|
256 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, |
|
257 NS_LITERAL_STRING("software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\wmplayer.exe"), |
|
258 nsIWindowsRegKey::ACCESS_READ); |
|
259 if (NS_SUCCEEDED(rv)) { |
|
260 nsAutoString path; |
|
261 rv = regKey->ReadStringValue(NS_LITERAL_STRING(""), path); |
|
262 if (NS_SUCCEEDED(rv)) { |
|
263 GetFileVersion(path.get(), &wmpVer); |
|
264 } |
|
265 regKey->Close(); |
|
266 } |
|
267 if (CompareVersion(wmpVer, minVer) < 0) |
|
268 return rv; |
|
269 |
|
270 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, |
|
271 NS_LITERAL_STRING("software\\Microsoft\\MediaPlayer"), |
|
272 nsIWindowsRegKey::ACCESS_READ); |
|
273 if (NS_SUCCEEDED(rv)) { |
|
274 nsAutoString path; |
|
275 rv = regKey->ReadStringValue(NS_LITERAL_STRING("Installation Directory"), |
|
276 path); |
|
277 if (NS_SUCCEEDED(rv)) { |
|
278 rv = NS_NewLocalFile(path, true, |
|
279 getter_AddRefs(localFile)); |
|
280 } |
|
281 } |
|
282 } else if (nsCRT::strcmp(charProp, NS_WIN_ACROBAT_SCAN_KEY) == 0) { |
|
283 nsAdoptingCString strVer = Preferences::GetCString(charProp); |
|
284 if (!strVer) { |
|
285 return NS_ERROR_FAILURE; |
|
286 } |
|
287 |
|
288 verBlock minVer; |
|
289 TranslateVersionStr(NS_ConvertASCIItoUTF16(strVer).get(), &minVer); |
|
290 |
|
291 // Look for Adobe Acrobat system installation plugins directory |
|
292 verBlock maxVer; |
|
293 ClearVersion(&maxVer); |
|
294 |
|
295 nsAutoString newestPath; |
|
296 |
|
297 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, |
|
298 NS_LITERAL_STRING("software\\Adobe\\Acrobat Reader"), |
|
299 nsIWindowsRegKey::ACCESS_READ); |
|
300 if (NS_FAILED(rv)) { |
|
301 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, |
|
302 NS_LITERAL_STRING("software\\Adobe\\Adobe Acrobat"), |
|
303 nsIWindowsRegKey::ACCESS_READ); |
|
304 if (NS_FAILED(rv)) { |
|
305 return NS_ERROR_FAILURE; |
|
306 } |
|
307 } |
|
308 |
|
309 // We must enumerate through the keys because what if there is |
|
310 // more than one version? |
|
311 uint32_t childCount = 0; |
|
312 regKey->GetChildCount(&childCount); |
|
313 |
|
314 for (uint32_t index = 0; index < childCount; ++index) { |
|
315 nsAutoString childName; |
|
316 rv = regKey->GetChildName(index, childName); |
|
317 if (NS_SUCCEEDED(rv)) { |
|
318 verBlock curVer; |
|
319 TranslateVersionStr(childName.get(), &curVer); |
|
320 |
|
321 childName += NS_LITERAL_STRING("\\InstallPath"); |
|
322 |
|
323 nsCOMPtr<nsIWindowsRegKey> childKey; |
|
324 rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE, |
|
325 getter_AddRefs(childKey)); |
|
326 if (NS_SUCCEEDED(rv)) { |
|
327 // We have a sub key |
|
328 nsAutoString path; |
|
329 rv = childKey->ReadStringValue(NS_LITERAL_STRING(""), path); |
|
330 if (NS_SUCCEEDED(rv)) { |
|
331 if (CompareVersion(curVer, maxVer) >= 0 && |
|
332 CompareVersion(curVer, minVer) >= 0) { |
|
333 newestPath = path; |
|
334 CopyVersion(&maxVer, &curVer); |
|
335 } |
|
336 } |
|
337 } |
|
338 } |
|
339 } |
|
340 |
|
341 if (!newestPath.IsEmpty()) { |
|
342 newestPath += NS_LITERAL_STRING("\\browser"); |
|
343 rv = NS_NewLocalFile(newestPath, true, |
|
344 getter_AddRefs(localFile)); |
|
345 } |
|
346 } |
|
347 |
|
348 if (NS_FAILED(rv)) { |
|
349 return rv; |
|
350 } |
|
351 |
|
352 localFile.forget(_retval); |
|
353 return NS_OK; |
|
354 } |
|
355 |
|
356 nsresult |
|
357 nsPluginDirServiceProvider::GetPLIDDirectories(nsISimpleEnumerator **aEnumerator) |
|
358 { |
|
359 NS_ENSURE_ARG_POINTER(aEnumerator); |
|
360 *aEnumerator = nullptr; |
|
361 |
|
362 nsCOMArray<nsIFile> dirs; |
|
363 |
|
364 GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, dirs); |
|
365 GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, dirs); |
|
366 |
|
367 return NS_NewArrayEnumerator(aEnumerator, dirs); |
|
368 } |
|
369 |
|
370 nsresult |
|
371 nsPluginDirServiceProvider::GetPLIDDirectoriesWithRootKey(uint32_t aKey, nsCOMArray<nsIFile> &aDirs) |
|
372 { |
|
373 nsCOMPtr<nsIWindowsRegKey> regKey = |
|
374 do_CreateInstance("@mozilla.org/windows-registry-key;1"); |
|
375 NS_ENSURE_TRUE(regKey, NS_ERROR_FAILURE); |
|
376 |
|
377 nsresult rv = regKey->Open(aKey, |
|
378 NS_LITERAL_STRING("Software\\MozillaPlugins"), |
|
379 nsIWindowsRegKey::ACCESS_READ); |
|
380 if (NS_FAILED(rv)) { |
|
381 return rv; |
|
382 } |
|
383 |
|
384 uint32_t childCount = 0; |
|
385 regKey->GetChildCount(&childCount); |
|
386 |
|
387 for (uint32_t index = 0; index < childCount; ++index) { |
|
388 nsAutoString childName; |
|
389 rv = regKey->GetChildName(index, childName); |
|
390 if (NS_SUCCEEDED(rv)) { |
|
391 nsCOMPtr<nsIWindowsRegKey> childKey; |
|
392 rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE, |
|
393 getter_AddRefs(childKey)); |
|
394 if (NS_SUCCEEDED(rv) && childKey) { |
|
395 nsAutoString path; |
|
396 rv = childKey->ReadStringValue(NS_LITERAL_STRING("Path"), path); |
|
397 if (NS_SUCCEEDED(rv)) { |
|
398 nsCOMPtr<nsIFile> localFile; |
|
399 if (NS_SUCCEEDED(NS_NewLocalFile(path, true, |
|
400 getter_AddRefs(localFile))) && |
|
401 localFile) { |
|
402 // Some vendors use a path directly to the DLL so chop off |
|
403 // the filename |
|
404 bool isDir = false; |
|
405 if (NS_SUCCEEDED(localFile->IsDirectory(&isDir)) && !isDir) { |
|
406 nsCOMPtr<nsIFile> temp; |
|
407 localFile->GetParent(getter_AddRefs(temp)); |
|
408 if (temp) |
|
409 localFile = temp; |
|
410 } |
|
411 |
|
412 // Now we check to make sure it's actually on disk and |
|
413 // To see if we already have this directory in the array |
|
414 bool isFileThere = false; |
|
415 bool isDupEntry = false; |
|
416 if (NS_SUCCEEDED(localFile->Exists(&isFileThere)) && isFileThere) { |
|
417 int32_t c = aDirs.Count(); |
|
418 for (int32_t i = 0; i < c; i++) { |
|
419 nsIFile *dup = static_cast<nsIFile*>(aDirs[i]); |
|
420 if (dup && |
|
421 NS_SUCCEEDED(dup->Equals(localFile, &isDupEntry)) && |
|
422 isDupEntry) { |
|
423 break; |
|
424 } |
|
425 } |
|
426 |
|
427 if (!isDupEntry) { |
|
428 aDirs.AppendObject(localFile); |
|
429 } |
|
430 } |
|
431 } |
|
432 } |
|
433 } |
|
434 } |
|
435 } |
|
436 return NS_OK; |
|
437 } |
|
438 |