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 const wchar_t kModAppHostDeprecated
[] = L
"-apphost";
19 const wchar_t kModAppLauncherDeprecated
[] = L
"-applauncher";
20 const wchar_t kModMultiInstall
[] = L
"-multi";
21 const wchar_t kModReadyMode
[] = L
"-readymode";
22 const wchar_t kModStage
[] = L
"-stage:";
23 const wchar_t kSfxFull
[] = L
"-full";
24 const wchar_t kSfxMigrating
[] = L
"-migrating";
25 const wchar_t kSfxMultiFail
[] = L
"-multifail";
27 const wchar_t* const kChannels
[] = {
28 installer::kChromeChannelBeta
,
29 installer::kChromeChannelDev
,
30 installer::kChromeChannelStableExplicit
33 const wchar_t* const kModifiers
[] = {
38 kModAppHostDeprecated
,
39 kModAppLauncherDeprecated
,
51 MOD_APP_HOST_DEPRECATED
,
52 MOD_APP_LAUNCHER_DEPRECATED
,
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 base::string16
& ap_value
,
68 base::string16::size_type
* position
,
69 base::string16::size_type
* length
) {
70 DCHECK(position
!= NULL
);
71 base::string16::size_type mod_position
= base::string16::npos
;
72 base::string16::size_type mod_length
=
73 base::string16::traits_type::length(kModifiers
[index
]);
74 const bool mod_takes_arg
= (kModifiers
[index
][mod_length
- 1] == L
':');
75 base::string16::size_type pos
= 0;
77 mod_position
= ap_value
.find(kModifiers
[index
], pos
, mod_length
);
78 if (mod_position
== base::string16::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
== base::string16::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
, base::string16::npos
);
92 *position
= mod_position
;
94 *length
= pos
- mod_position
;
98 bool HasModifier(ModifierIndex index
, const base::string16
& ap_value
) {
99 DCHECK(index
>= 0 && index
< NUM_MODIFIERS
);
100 base::string16::size_type position
;
101 return FindModifier(index
, ap_value
, &position
, NULL
);
104 base::string16::size_type
FindInsertionPoint(ModifierIndex index
,
105 const base::string16
& ap_value
) {
106 // Return the location of the next modifier.
107 base::string16::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
, base::string16
* ap_value
) {
119 DCHECK(index
>= 0 && index
< NUM_MODIFIERS
);
121 base::string16::size_type position
;
122 base::string16::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(base::string16
* 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
) != base::string16::npos
) {
171 // Report channels with "stable" in them as stable (empty string).
172 if (*scan
== installer::kChromeChannelStableExplicit
)
173 channel_name
->erase();
175 channel_name
->assign(*scan
);
179 // There may be modifiers present. Strip them off and see if we're left
180 // with the empty string (stable channel).
181 base::string16 tmp_value
= value_
;
182 for (int i
= 0; i
!= NUM_MODIFIERS
; ++i
) {
183 SetModifier(static_cast<ModifierIndex
>(i
), false, &tmp_value
);
185 if (tmp_value
.empty()) {
186 channel_name
->erase();
194 bool ChannelInfo::IsChrome() const {
195 return HasModifier(MOD_CHROME
, value_
);
198 bool ChannelInfo::SetChrome(bool value
) {
199 return SetModifier(MOD_CHROME
, value
, &value_
);
202 bool ChannelInfo::IsChromeFrame() const {
203 return HasModifier(MOD_CHROME_FRAME
, value_
);
206 bool ChannelInfo::SetChromeFrame(bool value
) {
207 return SetModifier(MOD_CHROME_FRAME
, value
, &value_
);
210 bool ChannelInfo::IsAppLauncher() const {
211 return HasModifier(MOD_APP_LAUNCHER_DEPRECATED
, value_
);
214 bool ChannelInfo::SetAppLauncher(bool value
) {
215 // Unconditionally remove -apphost since it has been long deprecated.
216 bool changed_app_host
= SetModifier(MOD_APP_HOST_DEPRECATED
, false, &value_
);
217 // Set value for -applauncher, relying on caller for policy.
218 bool changed_app_launcher
=
219 SetModifier(MOD_APP_LAUNCHER_DEPRECATED
, value
, &value_
);
220 return changed_app_host
|| changed_app_launcher
;
223 bool ChannelInfo::IsMultiInstall() const {
224 return HasModifier(MOD_MULTI_INSTALL
, value_
);
227 bool ChannelInfo::SetMultiInstall(bool value
) {
228 return SetModifier(MOD_MULTI_INSTALL
, value
, &value_
);
231 bool ChannelInfo::IsReadyMode() const {
232 return HasModifier(MOD_READY_MODE
, value_
);
235 bool ChannelInfo::SetReadyMode(bool value
) {
236 return SetModifier(MOD_READY_MODE
, value
, &value_
);
239 bool ChannelInfo::SetStage(const wchar_t* stage
) {
240 base::string16::size_type position
;
241 base::string16::size_type length
;
242 bool have_modifier
= FindModifier(MOD_STAGE
, value_
, &position
, &length
);
243 if (stage
!= NULL
&& *stage
!= L
'\0') {
244 base::string16
stage_str(kModStage
);
245 stage_str
.append(stage
);
246 if (!have_modifier
) {
247 value_
.insert(FindInsertionPoint(MOD_STAGE
, value_
), stage_str
);
250 if (value_
.compare(position
, length
, stage_str
) != 0) {
251 value_
.replace(position
, length
, stage_str
);
256 value_
.erase(position
, length
);
263 base::string16
ChannelInfo::GetStage() const {
264 base::string16::size_type position
;
265 base::string16::size_type length
;
267 if (FindModifier(MOD_STAGE
, value_
, &position
, &length
)) {
268 // Return the portion after the prefix.
269 base::string16::size_type pfx_length
=
270 base::string16::traits_type::length(kModStage
);
271 DCHECK_LE(pfx_length
, length
);
272 return value_
.substr(position
+ pfx_length
, length
- pfx_length
);
274 return base::string16();
277 bool ChannelInfo::HasFullSuffix() const {
278 return HasModifier(SFX_FULL
, value_
);
281 bool ChannelInfo::SetFullSuffix(bool value
) {
282 return SetModifier(SFX_FULL
, value
, &value_
);
285 bool ChannelInfo::HasMultiFailSuffix() const {
286 return HasModifier(SFX_MULTI_FAIL
, value_
);
289 bool ChannelInfo::SetMultiFailSuffix(bool value
) {
290 return SetModifier(SFX_MULTI_FAIL
, value
, &value_
);
293 bool ChannelInfo::SetMigratingSuffix(bool value
) {
294 return SetModifier(SFX_MIGRATING
, value
, &value_
);
297 bool ChannelInfo::HasMigratingSuffix() const {
298 return HasModifier(SFX_MIGRATING
, value_
);
301 bool ChannelInfo::RemoveAllModifiersAndSuffixes() {
302 bool modified
= false;
304 for (int scan
= 0; scan
< NUM_MODIFIERS
; ++scan
) {
305 ModifierIndex index
= static_cast<ModifierIndex
>(scan
);
306 modified
= SetModifier(index
, false, &value_
) || modified
;
312 } // namespace installer