file_version_info_win.cc 6.02 KB
Newer Older
1
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
initial.commit's avatar
initial.commit committed
4

5
#include "base/file_version_info_win.h"
initial.commit's avatar
initial.commit committed
6

7
#include <windows.h>
8
#include <stddef.h>
9

10
#include "base/files/file_path.h"
initial.commit's avatar
initial.commit committed
11
#include "base/logging.h"
12
#include "base/threading/thread_restrictions.h"
13
#include "base/win/resource_util.h"
initial.commit's avatar
initial.commit committed
14

15 16
using base::FilePath;

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
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;
initial.commit's avatar
initial.commit committed
34 35
}

36 37 38 39 40 41 42 43
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;
initial.commit's avatar
initial.commit committed
44 45
}

46 47 48
}  // namespace

FileVersionInfoWin::~FileVersionInfoWin() = default;
initial.commit's avatar
initial.commit committed
49 50

// static
51 52
FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForModule(
    HMODULE module) {
53 54 55 56 57 58 59 60 61 62
  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;
initial.commit's avatar
initial.commit committed
63

64 65
  return new FileVersionInfoWin(data, translate->language,
                                translate->code_page);
initial.commit's avatar
initial.commit committed
66 67 68 69
}

// static
FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
70
    const FilePath& file_path) {
71 72
  base::ThreadRestrictions::AssertIOAllowed();

initial.commit's avatar
initial.commit committed
73
  DWORD dummy;
74
  const wchar_t* path = file_path.value().c_str();
75
  const DWORD length = ::GetFileVersionInfoSize(path, &dummy);
initial.commit's avatar
initial.commit committed
76
  if (length == 0)
77
    return nullptr;
initial.commit's avatar
initial.commit committed
78

79
  std::vector<uint8_t> data(length, 0);
initial.commit's avatar
initial.commit committed
80

81 82
  if (!::GetFileVersionInfo(path, dummy, length, data.data()))
    return nullptr;
initial.commit's avatar
initial.commit committed
83

84 85 86
  const LanguageAndCodePage* translate = GetTranslate(data.data());
  if (!translate)
    return nullptr;
initial.commit's avatar
initial.commit committed
87

88 89
  return new FileVersionInfoWin(std::move(data), translate->language,
                                translate->code_page);
initial.commit's avatar
initial.commit committed
90 91
}

92
base::string16 FileVersionInfoWin::company_name() {
initial.commit's avatar
initial.commit committed
93 94 95
  return GetStringValue(L"CompanyName");
}

96
base::string16 FileVersionInfoWin::company_short_name() {
initial.commit's avatar
initial.commit committed
97 98 99
  return GetStringValue(L"CompanyShortName");
}

100
base::string16 FileVersionInfoWin::internal_name() {
initial.commit's avatar
initial.commit committed
101 102 103
  return GetStringValue(L"InternalName");
}

104
base::string16 FileVersionInfoWin::product_name() {
initial.commit's avatar
initial.commit committed
105 106 107
  return GetStringValue(L"ProductName");
}

108
base::string16 FileVersionInfoWin::product_short_name() {
initial.commit's avatar
initial.commit committed
109 110 111
  return GetStringValue(L"ProductShortName");
}

112
base::string16 FileVersionInfoWin::comments() {
initial.commit's avatar
initial.commit committed
113 114 115
  return GetStringValue(L"Comments");
}

116
base::string16 FileVersionInfoWin::legal_copyright() {
initial.commit's avatar
initial.commit committed
117 118 119
  return GetStringValue(L"LegalCopyright");
}

120
base::string16 FileVersionInfoWin::product_version() {
initial.commit's avatar
initial.commit committed
121 122 123
  return GetStringValue(L"ProductVersion");
}

124
base::string16 FileVersionInfoWin::file_description() {
initial.commit's avatar
initial.commit committed
125 126 127
  return GetStringValue(L"FileDescription");
}

128
base::string16 FileVersionInfoWin::legal_trademarks() {
initial.commit's avatar
initial.commit committed
129 130 131
  return GetStringValue(L"LegalTrademarks");
}

132
base::string16 FileVersionInfoWin::private_build() {
initial.commit's avatar
initial.commit committed
133 134 135
  return GetStringValue(L"PrivateBuild");
}

136
base::string16 FileVersionInfoWin::file_version() {
initial.commit's avatar
initial.commit committed
137 138 139
  return GetStringValue(L"FileVersion");
}

140
base::string16 FileVersionInfoWin::original_filename() {
initial.commit's avatar
initial.commit committed
141 142 143
  return GetStringValue(L"OriginalFilename");
}

144
base::string16 FileVersionInfoWin::special_build() {
initial.commit's avatar
initial.commit committed
145 146 147
  return GetStringValue(L"SpecialBuild");
}

148
base::string16 FileVersionInfoWin::last_change() {
initial.commit's avatar
initial.commit committed
149 150 151
  return GetStringValue(L"LastChange");
}

152
bool FileVersionInfoWin::is_official_build() {
initial.commit's avatar
initial.commit committed
153 154 155
  return (GetStringValue(L"Official Build").compare(L"1") == 0);
}

156 157
bool FileVersionInfoWin::GetValue(const wchar_t* name,
                                  std::wstring* value_str) {
initial.commit's avatar
initial.commit committed
158
  WORD lang_codepage[8];
159
  size_t i = 0;
initial.commit's avatar
initial.commit committed
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  // 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,
179
                 L"\\StringFileInfo\\%04x%04x\\%ls", language, code_page, name);
initial.commit's avatar
initial.commit committed
180
    LPVOID value = NULL;
181
    uint32_t size;
182
    BOOL r = ::VerQueryValue(data_, sub_block, &value, &size);
initial.commit's avatar
initial.commit committed
183 184 185 186 187 188 189 190
    if (r && value) {
      value_str->assign(static_cast<wchar_t*>(value));
      return true;
    }
  }
  return false;
}

191
std::wstring FileVersionInfoWin::GetStringValue(const wchar_t* name) {
initial.commit's avatar
initial.commit committed
192 193 194 195 196 197
  std::wstring str;
  if (GetValue(name, &str))
    return str;
  else
    return L"";
}
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218

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_);
}