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
33 const wchar_t* const kModifiers
[] = {
38 kModAppHostDeprecated
, // TODO(huangs): Remove by M27.
51 MOD_APP_HOST_DEPRECATED
, // TODO(huangs): Remove by M27.
60 COMPILE_ASSERT(NUM_MODIFIERS
== arraysize(kModifiers
),
61 kModifiers_disagrees_with_ModifierIndex_comma_they_must_match_bang
);
63 // Returns true if the modifier is found, in which case |position| holds the
64 // location at which the modifier was found. The number of characters in the
65 // modifier is returned in |length|, if non-NULL.
66 bool FindModifier(ModifierIndex index
,
67 const std::wstring
& ap_value
,
68 std::wstring::size_type
* position
,
69 std::wstring::size_type
* length
) {
70 DCHECK(position
!= NULL
);
71 std::wstring::size_type mod_position
= std::wstring::npos
;
72 std::wstring::size_type mod_length
=
73 std::wstring::traits_type::length(kModifiers
[index
]);
74 const bool mod_takes_arg
= (kModifiers
[index
][mod_length
- 1] == L
':');
75 std::wstring::size_type pos
= 0;
77 mod_position
= ap_value
.find(kModifiers
[index
], pos
, mod_length
);
78 if (mod_position
== std::wstring::npos
)
79 return false; // Modifier not found.
80 pos
= mod_position
+ mod_length
;
81 // Modifiers that take an argument gobble up to the next separator or to the
84 pos
= ap_value
.find(L
'-', pos
);
85 if (pos
== std::wstring::npos
)
86 pos
= ap_value
.size();
89 // Regular modifiers must be followed by '-' or the end of the string.
90 } while (pos
!= ap_value
.size() && ap_value
[pos
] != L
'-');
91 DCHECK_NE(mod_position
, std::wstring::npos
);
92 *position
= mod_position
;
94 *length
= pos
- mod_position
;
98 bool HasModifier(ModifierIndex index
, const std::wstring
& ap_value
) {
99 DCHECK(index
>= 0 && index
< NUM_MODIFIERS
);
100 std::wstring::size_type position
;
101 return FindModifier(index
, ap_value
, &position
, NULL
);
104 std::wstring::size_type
FindInsertionPoint(ModifierIndex index
,
105 const std::wstring
& ap_value
) {
106 // Return the location of the next modifier.
107 std::wstring::size_type result
;
109 for (int scan
= index
+ 1; scan
< NUM_MODIFIERS
; ++scan
) {
110 if (FindModifier(static_cast<ModifierIndex
>(scan
), ap_value
, &result
, NULL
))
114 return ap_value
.size();
117 // Returns true if |ap_value| is modified.
118 bool SetModifier(ModifierIndex index
, bool set
, std::wstring
* ap_value
) {
119 DCHECK(index
>= 0 && index
< NUM_MODIFIERS
);
121 std::wstring::size_type position
;
122 std::wstring::size_type length
;
123 bool have_modifier
= FindModifier(index
, *ap_value
, &position
, &length
);
125 if (!have_modifier
) {
126 ap_value
->insert(FindInsertionPoint(index
, *ap_value
), kModifiers
[index
]);
131 ap_value
->erase(position
, length
);
140 namespace installer
{
142 bool ChannelInfo::Initialize(const RegKey
& key
) {
143 LONG result
= key
.ReadValue(google_update::kRegApField
, &value_
);
144 return result
== ERROR_SUCCESS
|| result
== ERROR_FILE_NOT_FOUND
||
145 result
== ERROR_INVALID_HANDLE
;
148 bool ChannelInfo::Write(RegKey
* key
) const {
150 // Google Update deletes the value when it is empty, so we may as well, too.
151 LONG result
= value_
.empty() ?
152 key
->DeleteValue(google_update::kRegApField
) :
153 key
->WriteValue(google_update::kRegApField
, value_
.c_str());
154 if (result
!= ERROR_SUCCESS
) {
155 LOG(ERROR
) << "Failed writing channel info; result: " << result
;
161 bool ChannelInfo::GetChannelName(std::wstring
* channel_name
) const {
162 DCHECK(channel_name
);
163 if (value_
.empty()) {
164 channel_name
->erase();
167 for (const wchar_t* const* scan
= &kChannels
[0],
168 *const* end
= &kChannels
[arraysize(kChannels
)]; scan
!= end
;
170 if (value_
.find(*scan
) != std::wstring::npos
) {
171 channel_name
->assign(*scan
);
175 // There may be modifiers present. Strip them off and see if we're left
176 // with the empty string (stable channel).
177 std::wstring tmp_value
= value_
;
178 for (int i
= 0; i
!= NUM_MODIFIERS
; ++i
) {
179 SetModifier(static_cast<ModifierIndex
>(i
), false, &tmp_value
);
181 if (tmp_value
.empty()) {
182 channel_name
->erase();
190 bool ChannelInfo::IsChrome() const {
191 return HasModifier(MOD_CHROME
, value_
);
194 bool ChannelInfo::SetChrome(bool value
) {
195 return SetModifier(MOD_CHROME
, value
, &value_
);
198 bool ChannelInfo::IsChromeFrame() const {
199 return HasModifier(MOD_CHROME_FRAME
, value_
);
202 bool ChannelInfo::SetChromeFrame(bool value
) {
203 return SetModifier(MOD_CHROME_FRAME
, value
, &value_
);
206 bool ChannelInfo::IsAppLauncher() const {
207 return HasModifier(MOD_APP_LAUNCHER
, value_
);
210 bool ChannelInfo::SetAppLauncher(bool value
) {
211 // Unconditionally remove -apphost since it has been deprecated.
212 bool changed_app_host
= SetModifier(MOD_APP_HOST_DEPRECATED
, false, &value_
);
213 bool changed_app_launcher
= SetModifier(MOD_APP_LAUNCHER
, value
, &value_
);
214 return changed_app_host
|| changed_app_launcher
;
217 bool ChannelInfo::IsMultiInstall() const {
218 return HasModifier(MOD_MULTI_INSTALL
, value_
);
221 bool ChannelInfo::SetMultiInstall(bool value
) {
222 return SetModifier(MOD_MULTI_INSTALL
, value
, &value_
);
225 bool ChannelInfo::IsReadyMode() const {
226 return HasModifier(MOD_READY_MODE
, value_
);
229 bool ChannelInfo::SetReadyMode(bool value
) {
230 return SetModifier(MOD_READY_MODE
, value
, &value_
);
233 bool ChannelInfo::SetStage(const wchar_t* stage
) {
234 std::wstring::size_type position
;
235 std::wstring::size_type length
;
236 bool have_modifier
= FindModifier(MOD_STAGE
, value_
, &position
, &length
);
237 if (stage
!= NULL
&& *stage
!= L
'\0') {
238 std::wstring
stage_str(kModStage
);
239 stage_str
.append(stage
);
240 if (!have_modifier
) {
241 value_
.insert(FindInsertionPoint(MOD_STAGE
, value_
), stage_str
);
244 if (value_
.compare(position
, length
, stage_str
) != 0) {
245 value_
.replace(position
, length
, stage_str
);
250 value_
.erase(position
, length
);
257 std::wstring
ChannelInfo::GetStage() const {
258 std::wstring::size_type position
;
259 std::wstring::size_type length
;
261 if (FindModifier(MOD_STAGE
, value_
, &position
, &length
)) {
262 // Return the portion after the prefix.
263 std::wstring::size_type pfx_length
=
264 std::wstring::traits_type::length(kModStage
);
265 DCHECK_LE(pfx_length
, length
);
266 return value_
.substr(position
+ pfx_length
, length
- pfx_length
);
268 return std::wstring();
271 bool ChannelInfo::HasFullSuffix() const {
272 return HasModifier(SFX_FULL
, value_
);
275 bool ChannelInfo::SetFullSuffix(bool value
) {
276 return SetModifier(SFX_FULL
, value
, &value_
);
279 bool ChannelInfo::HasMultiFailSuffix() const {
280 return HasModifier(SFX_MULTI_FAIL
, value_
);
283 bool ChannelInfo::SetMultiFailSuffix(bool value
) {
284 return SetModifier(SFX_MULTI_FAIL
, value
, &value_
);
287 bool ChannelInfo::SetMigratingSuffix(bool value
) {
288 return SetModifier(SFX_MIGRATING
, value
, &value_
);
291 bool ChannelInfo::HasMigratingSuffix() const {
292 return HasModifier(SFX_MIGRATING
, value_
);
295 bool ChannelInfo::RemoveAllModifiersAndSuffixes() {
296 bool modified
= false;
298 for (int scan
= 0; scan
< NUM_MODIFIERS
; ++scan
) {
299 ModifierIndex index
= static_cast<ModifierIndex
>(scan
);
300 modified
= SetModifier(index
, false, &value_
) || modified
;
306 } // namespace installer