| // 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 <windows.h> |
| #include <stddef.h> |
| |
| #include "base/files/file_path.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_util.h" |
| #include "base/threading/scoped_blocking_call.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<void**>(&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<void**>(&fixed_file_info), |
| &length)) { |
| return fixed_file_info; |
| } |
| return nullptr; |
| } |
| |
| } // namespace |
| |
| FileVersionInfoWin::~FileVersionInfoWin() = default; |
| |
| // static |
| std::unique_ptr<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 base::WrapUnique( |
| new FileVersionInfoWin(data, translate->language, translate->code_page)); |
| } |
| |
| // static |
| std::unique_ptr<FileVersionInfo> FileVersionInfo::CreateFileVersionInfo( |
| const FilePath& file_path) { |
| return FileVersionInfoWin::CreateFileVersionInfoWin(file_path); |
| } |
| |
| // static |
| std::unique_ptr<FileVersionInfoWin> |
| FileVersionInfoWin::CreateFileVersionInfoWin(const FilePath& file_path) { |
| base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); |
| |
| DWORD dummy; |
| const wchar_t* path = base::wdata(file_path.value()); |
| const DWORD length = ::GetFileVersionInfoSize(path, &dummy); |
| if (length == 0) |
| return nullptr; |
| |
| std::vector<uint8_t> data(length, 0); |
| |
| if (!::GetFileVersionInfo(path, dummy, length, data.data())) |
| return nullptr; |
| |
| const LanguageAndCodePage* translate = GetTranslate(data.data()); |
| if (!translate) |
| return nullptr; |
| |
| return base::WrapUnique(new FileVersionInfoWin( |
| std::move(data), translate->language, translate->code_page)); |
| } |
| |
| base::string16 FileVersionInfoWin::company_name() { |
| return GetStringValue(STRING16_LITERAL("CompanyName")); |
| } |
| |
| base::string16 FileVersionInfoWin::company_short_name() { |
| return GetStringValue(STRING16_LITERAL("CompanyShortName")); |
| } |
| |
| base::string16 FileVersionInfoWin::internal_name() { |
| return GetStringValue(STRING16_LITERAL("InternalName")); |
| } |
| |
| base::string16 FileVersionInfoWin::product_name() { |
| return GetStringValue(STRING16_LITERAL("ProductName")); |
| } |
| |
| base::string16 FileVersionInfoWin::product_short_name() { |
| return GetStringValue(STRING16_LITERAL("ProductShortName")); |
| } |
| |
| base::string16 FileVersionInfoWin::comments() { |
| return GetStringValue(STRING16_LITERAL("Comments")); |
| } |
| |
| base::string16 FileVersionInfoWin::legal_copyright() { |
| return GetStringValue(STRING16_LITERAL("LegalCopyright")); |
| } |
| |
| base::string16 FileVersionInfoWin::product_version() { |
| return GetStringValue(STRING16_LITERAL("ProductVersion")); |
| } |
| |
| base::string16 FileVersionInfoWin::file_description() { |
| return GetStringValue(STRING16_LITERAL("FileDescription")); |
| } |
| |
| base::string16 FileVersionInfoWin::legal_trademarks() { |
| return GetStringValue(STRING16_LITERAL("LegalTrademarks")); |
| } |
| |
| base::string16 FileVersionInfoWin::private_build() { |
| return GetStringValue(STRING16_LITERAL("PrivateBuild")); |
| } |
| |
| base::string16 FileVersionInfoWin::file_version() { |
| return GetStringValue(STRING16_LITERAL("FileVersion")); |
| } |
| |
| base::string16 FileVersionInfoWin::original_filename() { |
| return GetStringValue(STRING16_LITERAL("OriginalFilename")); |
| } |
| |
| base::string16 FileVersionInfoWin::special_build() { |
| return GetStringValue(STRING16_LITERAL("SpecialBuild")); |
| } |
| |
| base::string16 FileVersionInfoWin::last_change() { |
| return GetStringValue(STRING16_LITERAL("LastChange")); |
| } |
| |
| bool FileVersionInfoWin::is_official_build() { |
| return GetStringValue(STRING16_LITERAL("Official Build")) == |
| STRING16_LITERAL("1"); |
| } |
| |
| bool FileVersionInfoWin::GetValue(const base::char16* name, |
| base::string16* 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 < base::size(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, |
| base::wdata(name)); |
| LPVOID value = NULL; |
| uint32_t size; |
| BOOL r = ::VerQueryValue(data_, sub_block, &value, &size); |
| if (r && value) { |
| value_str->assign(static_cast<base::char16*>(value)); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| base::string16 FileVersionInfoWin::GetStringValue(const base::char16* name) { |
| base::string16 str; |
| if (GetValue(name, &str)) |
| return str; |
| else |
| return base::string16(); |
| } |
| |
| FileVersionInfoWin::FileVersionInfoWin(std::vector<uint8_t>&& 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_); |
| } |