1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/installer/util/channel_info.h"
7 #include "base/logging.h"
8 #include "base/win/registry.h"
9 #include "chrome/installer/util/google_update_constants.h"
10 #include "chrome/installer/util/util_constants.h"
12 using base::win::RegKey
;
16 const wchar_t kModChrome
[] = L
"-chrome";
17 const wchar_t kModChromeFrame
[] = L
"-chromeframe";
18 // TODO(huangs): Remove by M27.
19 const wchar_t kModAppHostDeprecated
[] = L
"-apphost";
20 const wchar_t kModAppLauncher
[] = L
"-applauncher";
21 const wchar_t kModMultiInstall
[] = L
"-multi";
22 const wchar_t kModReadyMode
[] = L
"-readymode";
23 const wchar_t kModStage
[] = L
"-stage:";
24 const wchar_t kSfxFull
[] = L
"-full";
25 const wchar_t kSfxMigrating
[] = L
"-migrating";
26 const wchar_t kSfxMultiFail
[] = L
"-multifail";
28 const wchar_t* const kChannels
[] = {
29 installer::kChromeChannelBeta
,
30 installer::kChromeChannelDev
,
31 installer::kChromeChannelStableExplicit
34 const wchar_t* const kModifiers
[] = {
39 kModAppHostDeprecated
, // TODO(huangs): Remove by M27.
52 MOD_APP_HOST_DEPRECATED
, // TODO(huangs): Remove by M27.
61 COMPILE_ASSERT(NUM_MODIFIERS
== arraysize(kModifiers
),
62 kModifiers_disagrees_with_ModifierIndex_comma_they_must_match_bang
);
64 // Returns true if the modifier is found, in which case |position| holds the
65 // location at which the modifier was found. The number of characters in the
66 // modifier is returned in |length|, if non-NULL.
67 bool FindModifier(ModifierIndex index
,
68 const std::wstring
& ap_value
,
69 std::wstring::size_type
* position
,
70 std::wstring::size_type
* length
) {
71 DCHECK(position
!= NULL
);
72 std::wstring::size_type mod_position
= std::wstring::npos
;
73 std::wstring::size_type mod_length
=
74 std::wstring::traits_type::length(kModifiers
[index
]);
75 const bool mod_takes_arg
= (kModifiers
[index
][mod_length
- 1] == L
':');
76 std::wstring::size_type pos
= 0;
78 mod_position
= ap_value
.find(kModifiers
[index
], pos
, mod_length
);
79 if (mod_position
== std::wstring::npos
)
80 return false; // Modifier not found.
81 pos
= mod_position
+ mod_length
;
82 // Modifiers that take an argument gobble up to the next separator or to the
85 pos
= ap_value
.find(L
'-', pos
);
86 if (pos
== std::wstring::npos
)
87 pos
= ap_value
.size();
90 // Regular modifiers must be followed by '-' or the end of the string.
91 } while (pos
!= ap_value
.size() && ap_value
[pos
] != L
'-');
92 DCHECK_NE(mod_position
, std::wstring::npos
);
93 *position
= mod_position
;
95 *length
= pos
- mod_position
;
99 bool HasModifier(ModifierIndex index
, const std::wstring
& ap_value
) {
100 DCHECK(index
>= 0 && index
< NUM_MODIFIERS
);
101 std::wstring::size_type position
;
102 return FindModifier(index
, ap_value
, &position
, NULL
);
105 std::wstring::size_type
FindInsertionPoint(ModifierIndex index
,
106 const std::wstring
& ap_value
) {
107 // Return the location of the next modifier.
108 std::wstring::size_type result
;
110 for (int scan
= index
+ 1; scan
< NUM_MODIFIERS
; ++scan
) {
111 if (FindModifier(static_cast<ModifierIndex
>(scan
), ap_value
, &result
, NULL
))
115 return ap_value
.size();
118 // Returns true if |ap_value| is modified.
119 bool SetModifier(ModifierIndex index
, bool set
, std::wstring
* ap_value
) {
120 DCHECK(index
>= 0 && index
< NUM_MODIFIERS
);
122 std::wstring::size_type position
;
123 std::wstring::size_type length
;
124 bool have_modifier
= FindModifier(index
, *ap_value
, &position
, &length
);
126 if (!have_modifier
) {
127 ap_value
->insert(FindInsertionPoint(index
, *ap_value
), kModifiers
[index
]);
132 ap_value
->erase(position
, length
);
141 namespace installer
{
143 bool ChannelInfo::Initialize(const RegKey
& key
) {
144 LONG result
= key
.ReadValue(google_update::kRegApField
, &value_
);
145 return result
== ERROR_SUCCESS
|| result
== ERROR_FILE_NOT_FOUND
||
146 result
== ERROR_INVALID_HANDLE
;
149 bool ChannelInfo::Write(RegKey
* key
) const {
151 // Google Update deletes the value when it is empty, so we may as well, too.
152 LONG result
= value_
.empty() ?
153 key
->DeleteValue(google_update::kRegApField
) :
154 key
->WriteValue(google_update::kRegApField
, value_
.c_str());
155 if (result
!= ERROR_SUCCESS
) {
156 LOG(ERROR
) << "Failed writing channel info; result: " << result
;
162 bool ChannelInfo::GetChannelName(std::wstring
* channel_name
) const {
163 DCHECK(channel_name
);
164 if (value_
.empty()) {
165 channel_name
->erase();
168 for (const wchar_t* const* scan
= &kChannels
[0],
169 *const* end
= &kChannels
[arraysize(kChannels
)]; scan
!= end
;
171 if (value_
.find(*scan
) != std::wstring::npos
) {
172 // Report channels with "stable" in them as stable (empty string).
173 if (*scan
== installer::kChromeChannelStableExplicit
)
174 channel_name
->erase();
176 channel_name
->assign(*scan
);
180 // There may be modifiers present. Strip them off and see if we're left
181 // with the empty string (stable channel).
182 std::wstring tmp_value
= value_
;
183 for (int i
= 0; i
!= NUM_MODIFIERS
; ++i
) {
184 SetModifier(static_cast<ModifierIndex
>(i
), false, &tmp_value
);
186 if (tmp_value
.empty()) {
187 channel_name
->erase();
195 bool ChannelInfo::IsChrome() const {
196 return HasModifier(MOD_CHROME
, value_
);
199 bool ChannelInfo::SetChrome(bool value
) {
200 return SetModifier(MOD_CHROME
, value
, &value_
);
203 bool ChannelInfo::IsChromeFrame() const {
204 return HasModifier(MOD_CHROME_FRAME
, value_
);
207 bool ChannelInfo::SetChromeFrame(bool value
) {
208 return SetModifier(MOD_CHROME_FRAME
, value
, &value_
);
211 bool ChannelInfo::IsAppLauncher() const {
212 return HasModifier(MOD_APP_LAUNCHER
, value_
);
215 bool ChannelInfo::SetAppLauncher(bool value
) {
216 // Unconditionally remove -apphost since it has been deprecated.
217 bool changed_app_host
= SetModifier(MOD_APP_HOST_DEPRECATED
, false, &value_
);
218 bool changed_app_launcher
= SetModifier(MOD_APP_LAUNCHER
, value
, &value_
);
219 return changed_app_host
|| changed_app_launcher
;
222 bool ChannelInfo::IsMultiInstall() const {
223 return HasModifier(MOD_MULTI_INSTALL
, value_
);
226 bool ChannelInfo::SetMultiInstall(bool value
) {
227 return SetModifier(MOD_MULTI_INSTALL
, value
, &value_
);
230 bool ChannelInfo::IsReadyMode() const {
231 return HasModifier(MOD_READY_MODE
, value_
);
234 bool ChannelInfo::SetReadyMode(bool value
) {
235 return SetModifier(MOD_READY_MODE
, value
, &value_
);
238 bool ChannelInfo::SetStage(const wchar_t* stage
) {
239 std::wstring::size_type position
;
240 std::wstring::size_type length
;
241 bool have_modifier
= FindModifier(MOD_STAGE
, value_
, &position
, &length
);
242 if (stage
!= NULL
&& *stage
!= L
'\0') {
243 std::wstring
stage_str(kModStage
);
244 stage_str
.append(stage
);
245 if (!have_modifier
) {
246 value_
.insert(FindInsertionPoint(MOD_STAGE
, value_
), stage_str
);
249 if (value_
.compare(position
, length
, stage_str
) != 0) {
250 value_
.replace(position
, length
, stage_str
);
255 value_
.erase(position
, length
);
262 std::wstring
ChannelInfo::GetStage() const {
263 std::wstring::size_type position
;
264 std::wstring::size_type length
;
266 if (FindModifier(MOD_STAGE
, value_
, &position
, &length
)) {
267 // Return the portion after the prefix.
268 std::wstring::size_type pfx_length
=
269 std::wstring::traits_type::length(kModStage
);
270 DCHECK_LE(pfx_length
, length
);
271 return value_
.substr(position
+ pfx_length
, length
- pfx_length
);
273 return std::wstring();
276 bool ChannelInfo::HasFullSuffix() const {
277 return HasModifier(SFX_FULL
, value_
);
280 bool ChannelInfo::SetFullSuffix(bool value
) {
281 return SetModifier(SFX_FULL
, value
, &value_
);
284 bool ChannelInfo::HasMultiFailSuffix() const {
285 return HasModifier(SFX_MULTI_FAIL
, value_
);
288 bool ChannelInfo::SetMultiFailSuffix(bool value
) {
289 return SetModifier(SFX_MULTI_FAIL
, value
, &value_
);
292 bool ChannelInfo::SetMigratingSuffix(bool value
) {
293 return SetModifier(SFX_MIGRATING
, value
, &value_
);
296 bool ChannelInfo::HasMigratingSuffix() const {
297 return HasModifier(SFX_MIGRATING
, value_
);
300 bool ChannelInfo::RemoveAllModifiersAndSuffixes() {
301 bool modified
= false;
303 for (int scan
= 0; scan
< NUM_MODIFIERS
; ++scan
) {
304 ModifierIndex index
= static_cast<ModifierIndex
>(scan
);
305 modified
= SetModifier(index
, false, &value_
) || modified
;
311 } // namespace installer