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