Home | History | Annotate | Download | only in util
      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.
      4 
      5 #include "chrome/installer/util/channel_info.h"
      6 
      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"
     11 
     12 using base::win::RegKey;
     13 
     14 namespace {
     15 
     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";
     27 
     28 const wchar_t* const kChannels[] = {
     29   installer::kChromeChannelBeta,
     30   installer::kChromeChannelDev,
     31   installer::kChromeChannelStableExplicit
     32 };
     33 
     34 const wchar_t* const kModifiers[] = {
     35   kModStage,
     36   kModMultiInstall,
     37   kModChrome,
     38   kModChromeFrame,
     39   kModAppHostDeprecated,  // TODO(huangs): Remove by M27.
     40   kModAppLauncher,
     41   kModReadyMode,
     42   kSfxMultiFail,
     43   kSfxMigrating,
     44   kSfxFull,
     45 };
     46 
     47 enum ModifierIndex {
     48   MOD_STAGE,
     49   MOD_MULTI_INSTALL,
     50   MOD_CHROME,
     51   MOD_CHROME_FRAME,
     52   MOD_APP_HOST_DEPRECATED,  // TODO(huangs): Remove by M27.
     53   MOD_APP_LAUNCHER,
     54   MOD_READY_MODE,
     55   SFX_MULTI_FAIL,
     56   SFX_MIGRATING,
     57   SFX_FULL,
     58   NUM_MODIFIERS
     59 };
     60 
     61 COMPILE_ASSERT(NUM_MODIFIERS == arraysize(kModifiers),
     62     kModifiers_disagrees_with_ModifierIndex_comma_they_must_match_bang);
     63 
     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;
     77   do {
     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
     83     // end.
     84     if (mod_takes_arg) {
     85       pos = ap_value.find(L'-', pos);
     86       if (pos == std::wstring::npos)
     87         pos = ap_value.size();
     88       break;
     89     }
     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;
     94   if (length != NULL)
     95     *length = pos - mod_position;
     96   return true;
     97 }
     98 
     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);
    103 }
    104 
    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;
    109 
    110   for (int scan = index + 1; scan < NUM_MODIFIERS; ++scan) {
    111     if (FindModifier(static_cast<ModifierIndex>(scan), ap_value, &result, NULL))
    112       return result;
    113   }
    114 
    115   return ap_value.size();
    116 }
    117 
    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);
    121   DCHECK(ap_value);
    122   std::wstring::size_type position;
    123   std::wstring::size_type length;
    124   bool have_modifier = FindModifier(index, *ap_value, &position, &length);
    125   if (set) {
    126     if (!have_modifier) {
    127       ap_value->insert(FindInsertionPoint(index, *ap_value), kModifiers[index]);
    128       return true;
    129     }
    130   } else {
    131     if (have_modifier) {
    132       ap_value->erase(position, length);
    133       return true;
    134     }
    135   }
    136   return false;
    137 }
    138 
    139 }  // namespace
    140 
    141 namespace installer {
    142 
    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;
    147 }
    148 
    149 bool ChannelInfo::Write(RegKey* key) const {
    150   DCHECK(key);
    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;
    157     return false;
    158   }
    159   return true;
    160 }
    161 
    162 bool ChannelInfo::GetChannelName(std::wstring* channel_name) const {
    163   DCHECK(channel_name);
    164   if (value_.empty()) {
    165     channel_name->erase();
    166     return true;
    167   } else {
    168     for (const wchar_t* const* scan = &kChannels[0],
    169              *const* end = &kChannels[arraysize(kChannels)]; scan != end;
    170          ++scan) {
    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();
    175         else
    176           channel_name->assign(*scan);
    177         return true;
    178       }
    179     }
    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);
    185     }
    186     if (tmp_value.empty()) {
    187       channel_name->erase();
    188       return true;
    189     }
    190   }
    191 
    192   return false;
    193 }
    194 
    195 bool ChannelInfo::IsChrome() const {
    196   return HasModifier(MOD_CHROME, value_);
    197 }
    198 
    199 bool ChannelInfo::SetChrome(bool value) {
    200   return SetModifier(MOD_CHROME, value, &value_);
    201 }
    202 
    203 bool ChannelInfo::IsChromeFrame() const {
    204   return HasModifier(MOD_CHROME_FRAME, value_);
    205 }
    206 
    207 bool ChannelInfo::SetChromeFrame(bool value) {
    208   return SetModifier(MOD_CHROME_FRAME, value, &value_);
    209 }
    210 
    211 bool ChannelInfo::IsAppLauncher() const {
    212   return HasModifier(MOD_APP_LAUNCHER, value_);
    213 }
    214 
    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;
    220 }
    221 
    222 bool ChannelInfo::IsMultiInstall() const {
    223   return HasModifier(MOD_MULTI_INSTALL, value_);
    224 }
    225 
    226 bool ChannelInfo::SetMultiInstall(bool value) {
    227   return SetModifier(MOD_MULTI_INSTALL, value, &value_);
    228 }
    229 
    230 bool ChannelInfo::IsReadyMode() const {
    231   return HasModifier(MOD_READY_MODE, value_);
    232 }
    233 
    234 bool ChannelInfo::SetReadyMode(bool value) {
    235   return SetModifier(MOD_READY_MODE, value, &value_);
    236 }
    237 
    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);
    247       return true;
    248     }
    249     if (value_.compare(position, length, stage_str) != 0) {
    250       value_.replace(position, length, stage_str);
    251       return true;
    252     }
    253   } else {
    254     if (have_modifier) {
    255       value_.erase(position, length);
    256       return true;
    257     }
    258   }
    259   return false;
    260 }
    261 
    262 std::wstring ChannelInfo::GetStage() const {
    263   std::wstring::size_type position;
    264   std::wstring::size_type length;
    265 
    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);
    272   }
    273   return std::wstring();
    274 }
    275 
    276 bool ChannelInfo::HasFullSuffix() const {
    277   return HasModifier(SFX_FULL, value_);
    278 }
    279 
    280 bool ChannelInfo::SetFullSuffix(bool value) {
    281   return SetModifier(SFX_FULL, value, &value_);
    282 }
    283 
    284 bool ChannelInfo::HasMultiFailSuffix() const {
    285   return HasModifier(SFX_MULTI_FAIL, value_);
    286 }
    287 
    288 bool ChannelInfo::SetMultiFailSuffix(bool value) {
    289   return SetModifier(SFX_MULTI_FAIL, value, &value_);
    290 }
    291 
    292 bool ChannelInfo::SetMigratingSuffix(bool value) {
    293   return SetModifier(SFX_MIGRATING, value, &value_);
    294 }
    295 
    296 bool ChannelInfo::HasMigratingSuffix() const {
    297   return HasModifier(SFX_MIGRATING, value_);
    298 }
    299 
    300 bool ChannelInfo::RemoveAllModifiersAndSuffixes() {
    301   bool modified = false;
    302 
    303   for (int scan = 0; scan < NUM_MODIFIERS; ++scan) {
    304     ModifierIndex index = static_cast<ModifierIndex>(scan);
    305     modified = SetModifier(index, false, &value_) || modified;
    306   }
    307 
    308   return modified;
    309 }
    310 
    311 }  // namespace installer
    312