michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsPluginDirServiceProvider.h" michael@0: michael@0: #include "nsCRT.h" michael@0: #include "nsIFile.h" michael@0: #include "nsDependentString.h" michael@0: #include "nsArrayEnumerator.h" michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: #include michael@0: #include "nsIWindowsRegKey.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: typedef struct structVer michael@0: { michael@0: WORD wMajor; michael@0: WORD wMinor; michael@0: WORD wRelease; michael@0: WORD wBuild; michael@0: } verBlock; michael@0: michael@0: static void michael@0: ClearVersion(verBlock *ver) michael@0: { michael@0: ver->wMajor = 0; michael@0: ver->wMinor = 0; michael@0: ver->wRelease = 0; michael@0: ver->wBuild = 0; michael@0: } michael@0: michael@0: static BOOL michael@0: FileExists(LPCWSTR szFile) michael@0: { michael@0: return GetFileAttributesW(szFile) != 0xFFFFFFFF; michael@0: } michael@0: michael@0: // Get file version information from a file michael@0: static BOOL michael@0: GetFileVersion(LPCWSTR szFile, verBlock *vbVersion) michael@0: { michael@0: UINT uLen; michael@0: UINT dwLen; michael@0: BOOL bRv; michael@0: DWORD dwHandle; michael@0: LPVOID lpData; michael@0: LPVOID lpBuffer; michael@0: VS_FIXEDFILEINFO *lpBuffer2; michael@0: michael@0: ClearVersion(vbVersion); michael@0: if (FileExists(szFile)) { michael@0: bRv = TRUE; michael@0: LPCWSTR lpFilepath = szFile; michael@0: dwLen = GetFileVersionInfoSizeW(lpFilepath, &dwHandle); michael@0: lpData = (LPVOID)malloc(dwLen); michael@0: uLen = 0; michael@0: michael@0: if (lpData && GetFileVersionInfoW(lpFilepath, dwHandle, dwLen, lpData) != 0) { michael@0: if (VerQueryValueW(lpData, L"\\", &lpBuffer, &uLen) != 0) { michael@0: lpBuffer2 = (VS_FIXEDFILEINFO *)lpBuffer; michael@0: michael@0: vbVersion->wMajor = HIWORD(lpBuffer2->dwFileVersionMS); michael@0: vbVersion->wMinor = LOWORD(lpBuffer2->dwFileVersionMS); michael@0: vbVersion->wRelease = HIWORD(lpBuffer2->dwFileVersionLS); michael@0: vbVersion->wBuild = LOWORD(lpBuffer2->dwFileVersionLS); michael@0: } michael@0: } michael@0: michael@0: free(lpData); michael@0: } else { michael@0: /* File does not exist */ michael@0: bRv = FALSE; michael@0: } michael@0: michael@0: return bRv; michael@0: } michael@0: michael@0: // Will deep copy ver2 into ver1 michael@0: static void michael@0: CopyVersion(verBlock *ver1, verBlock *ver2) michael@0: { michael@0: ver1->wMajor = ver2->wMajor; michael@0: ver1->wMinor = ver2->wMinor; michael@0: ver1->wRelease = ver2->wRelease; michael@0: ver1->wBuild = ver2->wBuild; michael@0: } michael@0: michael@0: // Convert a string version to a version struct michael@0: static void michael@0: TranslateVersionStr(const WCHAR* szVersion, verBlock *vbVersion) michael@0: { michael@0: WCHAR* szNum1 = nullptr; michael@0: WCHAR* szNum2 = nullptr; michael@0: WCHAR* szNum3 = nullptr; michael@0: WCHAR* szNum4 = nullptr; michael@0: WCHAR* szJavaBuild = nullptr; michael@0: michael@0: WCHAR *strVer = nullptr; michael@0: if (szVersion) { michael@0: strVer = wcsdup(szVersion); michael@0: } michael@0: michael@0: if (!strVer) { michael@0: // Out of memory michael@0: ClearVersion(vbVersion); michael@0: return; michael@0: } michael@0: michael@0: // Java may be using an underscore instead of a dot for the build ID michael@0: szJavaBuild = wcschr(strVer, '_'); michael@0: if (szJavaBuild) { michael@0: szJavaBuild[0] = '.'; michael@0: } michael@0: michael@0: szNum1 = wcstok(strVer, L"."); michael@0: szNum2 = wcstok(nullptr, L"."); michael@0: szNum3 = wcstok(nullptr, L"."); michael@0: szNum4 = wcstok(nullptr, L"."); michael@0: michael@0: vbVersion->wMajor = szNum1 ? (WORD) _wtoi(szNum1) : 0; michael@0: vbVersion->wMinor = szNum2 ? (WORD) _wtoi(szNum2) : 0; michael@0: vbVersion->wRelease = szNum3 ? (WORD) _wtoi(szNum3) : 0; michael@0: vbVersion->wBuild = szNum4 ? (WORD) _wtoi(szNum4) : 0; michael@0: michael@0: free(strVer); michael@0: } michael@0: michael@0: // Compare two version struct, return zero if the same michael@0: static int michael@0: CompareVersion(verBlock vbVersionOld, verBlock vbVersionNew) michael@0: { michael@0: if (vbVersionOld.wMajor > vbVersionNew.wMajor) { michael@0: return 4; michael@0: } else if (vbVersionOld.wMajor < vbVersionNew.wMajor) { michael@0: return -4; michael@0: } michael@0: michael@0: if (vbVersionOld.wMinor > vbVersionNew.wMinor) { michael@0: return 3; michael@0: } else if (vbVersionOld.wMinor < vbVersionNew.wMinor) { michael@0: return -3; michael@0: } michael@0: michael@0: if (vbVersionOld.wRelease > vbVersionNew.wRelease) { michael@0: return 2; michael@0: } else if (vbVersionOld.wRelease < vbVersionNew.wRelease) { michael@0: return -2; michael@0: } michael@0: michael@0: if (vbVersionOld.wBuild > vbVersionNew.wBuild) { michael@0: return 1; michael@0: } else if (vbVersionOld.wBuild < vbVersionNew.wBuild) { michael@0: return -1; michael@0: } michael@0: michael@0: /* the versions are all the same */ michael@0: return 0; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsPluginDirServiceProvider::Constructor/Destructor michael@0: //***************************************************************************** michael@0: michael@0: nsPluginDirServiceProvider::nsPluginDirServiceProvider() michael@0: { michael@0: } michael@0: michael@0: nsPluginDirServiceProvider::~nsPluginDirServiceProvider() michael@0: { michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsPluginDirServiceProvider::nsISupports michael@0: //***************************************************************************** michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPluginDirServiceProvider, michael@0: nsIDirectoryServiceProvider) michael@0: michael@0: //***************************************************************************** michael@0: // nsPluginDirServiceProvider::nsIDirectoryServiceProvider michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP michael@0: nsPluginDirServiceProvider::GetFile(const char *charProp, bool *persistant, michael@0: nsIFile **_retval) michael@0: { michael@0: nsCOMPtr localFile; michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: NS_ENSURE_ARG(charProp); michael@0: michael@0: *_retval = nullptr; michael@0: *persistant = false; michael@0: michael@0: nsCOMPtr regKey = michael@0: do_CreateInstance("@mozilla.org/windows-registry-key;1"); michael@0: NS_ENSURE_TRUE(regKey, NS_ERROR_FAILURE); michael@0: michael@0: if (nsCRT::strcmp(charProp, NS_WIN_QUICKTIME_SCAN_KEY) == 0) { michael@0: nsAdoptingCString strVer = Preferences::GetCString(charProp); michael@0: if (!strVer) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: verBlock minVer; michael@0: TranslateVersionStr(NS_ConvertASCIItoUTF16(strVer).get(), &minVer); michael@0: michael@0: // Look for the Quicktime system installation plugins directory michael@0: verBlock qtVer; michael@0: ClearVersion(&qtVer); michael@0: michael@0: // First we need to check the version of Quicktime via checking michael@0: // the EXE's version table michael@0: rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, michael@0: NS_LITERAL_STRING("software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\QuickTimePlayer.exe"), michael@0: nsIWindowsRegKey::ACCESS_READ); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsAutoString path; michael@0: rv = regKey->ReadStringValue(NS_LITERAL_STRING(""), path); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: GetFileVersion(path.get(), &qtVer); michael@0: } michael@0: regKey->Close(); michael@0: } michael@0: if (CompareVersion(qtVer, minVer) < 0) michael@0: return rv; michael@0: michael@0: rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, michael@0: NS_LITERAL_STRING("software\\Apple Computer, Inc.\\QuickTime"), michael@0: nsIWindowsRegKey::ACCESS_READ); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsAutoString path; michael@0: rv = regKey->ReadStringValue(NS_LITERAL_STRING("InstallDir"), path); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: path += NS_LITERAL_STRING("\\Plugins"); michael@0: rv = NS_NewLocalFile(path, true, michael@0: getter_AddRefs(localFile)); michael@0: } michael@0: } michael@0: } else if (nsCRT::strcmp(charProp, NS_WIN_WMP_SCAN_KEY) == 0) { michael@0: nsAdoptingCString strVer = Preferences::GetCString(charProp); michael@0: if (!strVer) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: verBlock minVer; michael@0: TranslateVersionStr(NS_ConvertASCIItoUTF16(strVer).get(), &minVer); michael@0: michael@0: // Look for Windows Media Player system installation plugins directory michael@0: verBlock wmpVer; michael@0: ClearVersion(&wmpVer); michael@0: michael@0: // First we need to check the version of WMP michael@0: rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, michael@0: NS_LITERAL_STRING("software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\wmplayer.exe"), michael@0: nsIWindowsRegKey::ACCESS_READ); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsAutoString path; michael@0: rv = regKey->ReadStringValue(NS_LITERAL_STRING(""), path); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: GetFileVersion(path.get(), &wmpVer); michael@0: } michael@0: regKey->Close(); michael@0: } michael@0: if (CompareVersion(wmpVer, minVer) < 0) michael@0: return rv; michael@0: michael@0: rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, michael@0: NS_LITERAL_STRING("software\\Microsoft\\MediaPlayer"), michael@0: nsIWindowsRegKey::ACCESS_READ); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsAutoString path; michael@0: rv = regKey->ReadStringValue(NS_LITERAL_STRING("Installation Directory"), michael@0: path); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = NS_NewLocalFile(path, true, michael@0: getter_AddRefs(localFile)); michael@0: } michael@0: } michael@0: } else if (nsCRT::strcmp(charProp, NS_WIN_ACROBAT_SCAN_KEY) == 0) { michael@0: nsAdoptingCString strVer = Preferences::GetCString(charProp); michael@0: if (!strVer) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: verBlock minVer; michael@0: TranslateVersionStr(NS_ConvertASCIItoUTF16(strVer).get(), &minVer); michael@0: michael@0: // Look for Adobe Acrobat system installation plugins directory michael@0: verBlock maxVer; michael@0: ClearVersion(&maxVer); michael@0: michael@0: nsAutoString newestPath; michael@0: michael@0: rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, michael@0: NS_LITERAL_STRING("software\\Adobe\\Acrobat Reader"), michael@0: nsIWindowsRegKey::ACCESS_READ); michael@0: if (NS_FAILED(rv)) { michael@0: rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, michael@0: NS_LITERAL_STRING("software\\Adobe\\Adobe Acrobat"), michael@0: nsIWindowsRegKey::ACCESS_READ); michael@0: if (NS_FAILED(rv)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: // We must enumerate through the keys because what if there is michael@0: // more than one version? michael@0: uint32_t childCount = 0; michael@0: regKey->GetChildCount(&childCount); michael@0: michael@0: for (uint32_t index = 0; index < childCount; ++index) { michael@0: nsAutoString childName; michael@0: rv = regKey->GetChildName(index, childName); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: verBlock curVer; michael@0: TranslateVersionStr(childName.get(), &curVer); michael@0: michael@0: childName += NS_LITERAL_STRING("\\InstallPath"); michael@0: michael@0: nsCOMPtr childKey; michael@0: rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE, michael@0: getter_AddRefs(childKey)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // We have a sub key michael@0: nsAutoString path; michael@0: rv = childKey->ReadStringValue(NS_LITERAL_STRING(""), path); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (CompareVersion(curVer, maxVer) >= 0 && michael@0: CompareVersion(curVer, minVer) >= 0) { michael@0: newestPath = path; michael@0: CopyVersion(&maxVer, &curVer); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!newestPath.IsEmpty()) { michael@0: newestPath += NS_LITERAL_STRING("\\browser"); michael@0: rv = NS_NewLocalFile(newestPath, true, michael@0: getter_AddRefs(localFile)); michael@0: } michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: localFile.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsPluginDirServiceProvider::GetPLIDDirectories(nsISimpleEnumerator **aEnumerator) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEnumerator); michael@0: *aEnumerator = nullptr; michael@0: michael@0: nsCOMArray dirs; michael@0: michael@0: GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, dirs); michael@0: GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, dirs); michael@0: michael@0: return NS_NewArrayEnumerator(aEnumerator, dirs); michael@0: } michael@0: michael@0: nsresult michael@0: nsPluginDirServiceProvider::GetPLIDDirectoriesWithRootKey(uint32_t aKey, nsCOMArray &aDirs) michael@0: { michael@0: nsCOMPtr regKey = michael@0: do_CreateInstance("@mozilla.org/windows-registry-key;1"); michael@0: NS_ENSURE_TRUE(regKey, NS_ERROR_FAILURE); michael@0: michael@0: nsresult rv = regKey->Open(aKey, michael@0: NS_LITERAL_STRING("Software\\MozillaPlugins"), michael@0: nsIWindowsRegKey::ACCESS_READ); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: uint32_t childCount = 0; michael@0: regKey->GetChildCount(&childCount); michael@0: michael@0: for (uint32_t index = 0; index < childCount; ++index) { michael@0: nsAutoString childName; michael@0: rv = regKey->GetChildName(index, childName); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsCOMPtr childKey; michael@0: rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE, michael@0: getter_AddRefs(childKey)); michael@0: if (NS_SUCCEEDED(rv) && childKey) { michael@0: nsAutoString path; michael@0: rv = childKey->ReadStringValue(NS_LITERAL_STRING("Path"), path); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsCOMPtr localFile; michael@0: if (NS_SUCCEEDED(NS_NewLocalFile(path, true, michael@0: getter_AddRefs(localFile))) && michael@0: localFile) { michael@0: // Some vendors use a path directly to the DLL so chop off michael@0: // the filename michael@0: bool isDir = false; michael@0: if (NS_SUCCEEDED(localFile->IsDirectory(&isDir)) && !isDir) { michael@0: nsCOMPtr temp; michael@0: localFile->GetParent(getter_AddRefs(temp)); michael@0: if (temp) michael@0: localFile = temp; michael@0: } michael@0: michael@0: // Now we check to make sure it's actually on disk and michael@0: // To see if we already have this directory in the array michael@0: bool isFileThere = false; michael@0: bool isDupEntry = false; michael@0: if (NS_SUCCEEDED(localFile->Exists(&isFileThere)) && isFileThere) { michael@0: int32_t c = aDirs.Count(); michael@0: for (int32_t i = 0; i < c; i++) { michael@0: nsIFile *dup = static_cast(aDirs[i]); michael@0: if (dup && michael@0: NS_SUCCEEDED(dup->Equals(localFile, &isDupEntry)) && michael@0: isDupEntry) { michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (!isDupEntry) { michael@0: aDirs.AppendObject(localFile); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: