// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/file_version_info_win.h" #include #include #include "base/files/file_path.h" #include "base/logging.h" #include "base/threading/thread_restrictions.h" #include "base/win/resource_util.h" using base::FilePath; namespace { struct LanguageAndCodePage { WORD language; WORD code_page; }; // Returns the \\VarFileInfo\\Translation value extracted from the // VS_VERSION_INFO resource in |data|. LanguageAndCodePage* GetTranslate(const void* data) { LanguageAndCodePage* translate = nullptr; UINT length; if (::VerQueryValue(data, L"\\VarFileInfo\\Translation", reinterpret_cast(&translate), &length)) { return translate; } return nullptr; } VS_FIXEDFILEINFO* GetVsFixedFileInfo(const void* data) { VS_FIXEDFILEINFO* fixed_file_info = nullptr; UINT length; if (::VerQueryValue(data, L"\\", reinterpret_cast(&fixed_file_info), &length)) { return fixed_file_info; } return nullptr; } } // namespace FileVersionInfoWin::~FileVersionInfoWin() = default; // static FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForModule( HMODULE module) { void* data; size_t version_info_length; const bool has_version_resource = base::win::GetResourceFromModule( module, VS_VERSION_INFO, RT_VERSION, &data, &version_info_length); if (!has_version_resource) return nullptr; const LanguageAndCodePage* translate = GetTranslate(data); if (!translate) return nullptr; return new FileVersionInfoWin(data, translate->language, translate->code_page); } // static FileVersionInfo* FileVersionInfo::CreateFileVersionInfo( const FilePath& file_path) { base::ThreadRestrictions::AssertIOAllowed(); DWORD dummy; const wchar_t* path = file_path.value().c_str(); const DWORD length = ::GetFileVersionInfoSize(path, &dummy); if (length == 0) return nullptr; std::vector data(length, 0); if (!::GetFileVersionInfo(path, dummy, length, data.data())) return nullptr; const LanguageAndCodePage* translate = GetTranslate(data.data()); if (!translate) return nullptr; return new FileVersionInfoWin(std::move(data), translate->language, translate->code_page); } base::string16 FileVersionInfoWin::company_name() { return GetStringValue(L"CompanyName"); } base::string16 FileVersionInfoWin::company_short_name() { return GetStringValue(L"CompanyShortName"); } base::string16 FileVersionInfoWin::internal_name() { return GetStringValue(L"InternalName"); } base::string16 FileVersionInfoWin::product_name() { return GetStringValue(L"ProductName"); } base::string16 FileVersionInfoWin::product_short_name() { return GetStringValue(L"ProductShortName"); } base::string16 FileVersionInfoWin::comments() { return GetStringValue(L"Comments"); } base::string16 FileVersionInfoWin::legal_copyright() { return GetStringValue(L"LegalCopyright"); } base::string16 FileVersionInfoWin::product_version() { return GetStringValue(L"ProductVersion"); } base::string16 FileVersionInfoWin::file_description() { return GetStringValue(L"FileDescription"); } base::string16 FileVersionInfoWin::legal_trademarks() { return GetStringValue(L"LegalTrademarks"); } base::string16 FileVersionInfoWin::private_build() { return GetStringValue(L"PrivateBuild"); } base::string16 FileVersionInfoWin::file_version() { return GetStringValue(L"FileVersion"); } base::string16 FileVersionInfoWin::original_filename() { return GetStringValue(L"OriginalFilename"); } base::string16 FileVersionInfoWin::special_build() { return GetStringValue(L"SpecialBuild"); } base::string16 FileVersionInfoWin::last_change() { return GetStringValue(L"LastChange"); } bool FileVersionInfoWin::is_official_build() { return (GetStringValue(L"Official Build").compare(L"1") == 0); } bool FileVersionInfoWin::GetValue(const wchar_t* name, std::wstring* value_str) { WORD lang_codepage[8]; size_t i = 0; // Use the language and codepage from the DLL. lang_codepage[i++] = language_; lang_codepage[i++] = code_page_; // Use the default language and codepage from the DLL. lang_codepage[i++] = ::GetUserDefaultLangID(); lang_codepage[i++] = code_page_; // Use the language from the DLL and Latin codepage (most common). lang_codepage[i++] = language_; lang_codepage[i++] = 1252; // Use the default language and Latin codepage (most common). lang_codepage[i++] = ::GetUserDefaultLangID(); lang_codepage[i++] = 1252; i = 0; while (i < arraysize(lang_codepage)) { wchar_t sub_block[MAX_PATH]; WORD language = lang_codepage[i++]; WORD code_page = lang_codepage[i++]; _snwprintf_s(sub_block, MAX_PATH, MAX_PATH, L"\\StringFileInfo\\%04x%04x\\%ls", language, code_page, name); LPVOID value = NULL; uint32_t size; BOOL r = ::VerQueryValue(data_, sub_block, &value, &size); if (r && value) { value_str->assign(static_cast(value)); return true; } } return false; } std::wstring FileVersionInfoWin::GetStringValue(const wchar_t* name) { std::wstring str; if (GetValue(name, &str)) return str; else return L""; } FileVersionInfoWin::FileVersionInfoWin(std::vector&& data, WORD language, WORD code_page) : owned_data_(std::move(data)), data_(owned_data_.data()), language_(language), code_page_(code_page), fixed_file_info_(GetVsFixedFileInfo(data_)) { DCHECK(!owned_data_.empty()); } FileVersionInfoWin::FileVersionInfoWin(void* data, WORD language, WORD code_page) : data_(data), language_(language), code_page_(code_page), fixed_file_info_(GetVsFixedFileInfo(data)) { DCHECK(data_); }