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 kSfxMultiFail[] = L"-multifail";
     26 
     27 const wchar_t* const kChannels[] = {
     28   installer::kChromeChannelBeta,
     29   installer::kChromeChannelDev
     30 };
     31 
     32 const wchar_t* const kModifiers[] = {
     33   kModStage,
     34   kModMultiInstall,
     35   kModChrome,
     36   kModChromeFrame,
     37   kModAppHostDeprecated,  // TODO(huangs): Remove by M27.
     38   kModAppLauncher,
     39   kModReadyMode,
     40   kSfxMultiFail,
     41   kSfxFull
     42 };
     43 
     44 enum ModifierIndex {
     45   MOD_STAGE,
     46   MOD_MULTI_INSTALL,
     47   MOD_CHROME,
     48   MOD_CHROME_FRAME,
     49   MOD_APP_HOST_DEPRECATED,  // TODO(huangs): Remove by M27.
     50   MOD_APP_LAUNCHER,
     51   MOD_READY_MODE,
     52   SFX_MULTI_FAIL,
     53   SFX_FULL,
     54   NUM_MODIFIERS
     55 };
     56 
     57 COMPILE_ASSERT(NUM_MODIFIERS == arraysize(kModifiers),
     58     kModifiers_disagrees_with_ModifierIndex_comma_they_must_match_bang);
     59 
     60 // Returns true if the modifier is found, in which case |position| holds the
     61 // location at which the modifier was found.  The number of characters in the
     62 // modifier is returned in |length|, if non-NULL.
     63 bool FindModifier(ModifierIndex index,
     64                   const std::wstring& ap_value,
     65                   std::wstring::size_type* position,
     66                   std::wstring::size_type* length) {
     67   DCHECK(position != NULL);
     68   std::wstring::size_type mod_position = std::wstring::npos;
     69   std::wstring::size_type mod_length =
     70       std::wstring::traits_type::length(kModifiers[index]);
     71   const bool mod_takes_arg = (kModifiers[index][mod_length - 1] == L':');
     72   std::wstring::size_type pos = 0;
     73   do {
     74     mod_position = ap_value.find(kModifiers[index], pos, mod_length);
     75     if (mod_position == std::wstring::npos)
     76       return false;  // Modifier not found.
     77     pos = mod_position + mod_length;
     78     // Modifiers that take an argument gobble up to the next separator or to the
     79     // end.
     80     if (mod_takes_arg) {
     81       pos = ap_value.find(L'-', pos);
     82       if (pos == std::wstring::npos)
     83         pos = ap_value.size();
     84       break;
     85     }
     86     // Regular modifiers must be followed by '-' or the end of the string.
     87   } while (pos != ap_value.size() && ap_value[pos] != L'-');
     88   DCHECK_NE(mod_position, std::wstring::npos);
     89   *position = mod_position;
     90   if (length != NULL)
     91     *length = pos - mod_position;
     92   return true;
     93 }
     94 
     95 bool HasModifier(ModifierIndex index, const std::wstring& ap_value) {
     96   DCHECK(index >= 0 && index < NUM_MODIFIERS);
     97   std::wstring::size_type position;
     98   return FindModifier(index, ap_value, &position, NULL);
     99 }
    100 
    101 std::wstring::size_type FindInsertionPoint(ModifierIndex index,
    102                                            const std::wstring& ap_value) {
    103   // Return the location of the next modifier.
    104   std::wstring::size_type result;
    105 
    106   for (int scan = index + 1; scan < NUM_MODIFIERS; ++scan) {
    107     if (FindModifier(static_cast<ModifierIndex>(scan), ap_value, &result, NULL))
    108       return result;
    109   }
    110 
    111   return ap_value.size();
    112 }
    113 
    114 // Returns true if |ap_value| is modified.
    115 bool SetModifier(ModifierIndex index, bool set, std::wstring* ap_value) {
    116   DCHECK(index >= 0 && index < NUM_MODIFIERS);
    117   DCHECK(ap_value);
    118   std::wstring::size_type position;
    119   std::wstring::size_type length;
    120   bool have_modifier = FindModifier(index, *ap_value, &position, &length);
    121   if (set) {
    122     if (!have_modifier) {
    123       ap_value->insert(FindInsertionPoint(index, *ap_value), kModifiers[index]);
    124       return true;
    125     }
    126   } else {
    127     if (have_modifier) {
    128       ap_value->erase(position, length);
    129       return true;
    130     }
    131   }
    132   return false;
    133 }
    134 
    135 }  // namespace
    136 
    137 namespace installer {
    138 
    139 bool ChannelInfo::Initialize(const RegKey& key) {
    140   LONG result = key.ReadValue(google_update::kRegApField, &value_);
    141   return result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND ||
    142          result == ERROR_INVALID_HANDLE;
    143 }
    144 
    145 bool ChannelInfo::Write(RegKey* key) const {
    146   DCHECK(key);
    147   // Google Update deletes the value when it is empty, so we may as well, too.
    148   LONG result = value_.empty() ?
    149       key->DeleteValue(google_update::kRegApField) :
    150       key->WriteValue(google_update::kRegApField, value_.c_str());
    151   if (result != ERROR_SUCCESS) {
    152     LOG(ERROR) << "Failed writing channel info; result: " << result;
    153     return false;
    154   }
    155   return true;
    156 }
    157 
    158 bool ChannelInfo::GetChannelName(std::wstring* channel_name) const {
    159   DCHECK(channel_name);
    160   if (value_.empty()) {
    161     channel_name->erase();
    162     return true;
    163   } else {
    164     for (const wchar_t* const* scan = &kChannels[0],
    165              *const* end = &kChannels[arraysize(kChannels)]; scan != end;
    166          ++scan) {
    167       if (value_.find(*scan) != std::wstring::npos) {
    168         channel_name->assign(*scan);
    169         return true;
    170       }
    171     }
    172     // There may be modifiers present.  Strip them off and see if we're left
    173     // with the empty string (stable channel).
    174     std::wstring tmp_value = value_;
    175     for (int i = 0; i != NUM_MODIFIERS; ++i) {
    176       SetModifier(static_cast<ModifierIndex>(i), false, &tmp_value);
    177     }
    178     if (tmp_value.empty()) {
    179       channel_name->erase();
    180       return true;
    181     }
    182   }
    183 
    184   return false;
    185 }
    186 
    187 bool ChannelInfo::IsChrome() const {
    188   return HasModifier(MOD_CHROME, value_);
    189 }
    190 
    191 bool ChannelInfo::SetChrome(bool value) {
    192   return SetModifier(MOD_CHROME, value, &value_);
    193 }
    194 
    195 bool ChannelInfo::IsChromeFrame() const {
    196   return HasModifier(MOD_CHROME_FRAME, value_);
    197 }
    198 
    199 bool ChannelInfo::SetChromeFrame(bool value) {
    200   return SetModifier(MOD_CHROME_FRAME, value, &value_);
    201 }
    202 
    203 bool ChannelInfo::IsAppLauncher() const {
    204   return HasModifier(MOD_APP_LAUNCHER, value_);
    205 }
    206 
    207 bool ChannelInfo::SetAppLauncher(bool value) {
    208   // Unconditionally remove -apphost since it has been deprecated.
    209   bool changed_app_host = SetModifier(MOD_APP_HOST_DEPRECATED, false, &value_);
    210   bool changed_app_launcher = SetModifier(MOD_APP_LAUNCHER, value, &value_);
    211   return changed_app_host || changed_app_launcher;
    212 }
    213 
    214 bool ChannelInfo::IsMultiInstall() const {
    215   return HasModifier(MOD_MULTI_INSTALL, value_);
    216 }
    217 
    218 bool ChannelInfo::SetMultiInstall(bool value) {
    219   return SetModifier(MOD_MULTI_INSTALL, value, &value_);
    220 }
    221 
    222 bool ChannelInfo::IsReadyMode() const {
    223   return HasModifier(MOD_READY_MODE, value_);
    224 }
    225 
    226 bool ChannelInfo::SetReadyMode(bool value) {
    227   return SetModifier(MOD_READY_MODE, value, &value_);
    228 }
    229 
    230 bool ChannelInfo::SetStage(const wchar_t* stage) {
    231   std::wstring::size_type position;
    232   std::wstring::size_type length;
    233   bool have_modifier = FindModifier(MOD_STAGE, value_, &position, &length);
    234   if (stage != NULL && *stage != L'\0') {
    235     std::wstring stage_str(kModStage);
    236     stage_str.append(stage);
    237     if (!have_modifier) {
    238       value_.insert(FindInsertionPoint(MOD_STAGE, value_), stage_str);
    239       return true;
    240     }
    241     if (value_.compare(position, length, stage_str) != 0) {
    242       value_.replace(position, length, stage_str);
    243       return true;
    244     }
    245   } else {
    246     if (have_modifier) {
    247       value_.erase(position, length);
    248       return true;
    249     }
    250   }
    251   return false;
    252 }
    253 
    254 std::wstring ChannelInfo::GetStage() const {
    255   std::wstring::size_type position;
    256   std::wstring::size_type length;
    257 
    258   if (FindModifier(MOD_STAGE, value_, &position, &length)) {
    259     // Return the portion after the prefix.
    260     std::wstring::size_type pfx_length =
    261         std::wstring::traits_type::length(kModStage);
    262     DCHECK_LE(pfx_length, length);
    263     return value_.substr(position + pfx_length, length - pfx_length);
    264   }
    265   return std::wstring();
    266 }
    267 
    268 bool ChannelInfo::HasFullSuffix() const {
    269   return HasModifier(SFX_FULL, value_);
    270 }
    271 
    272 bool ChannelInfo::SetFullSuffix(bool value) {
    273   return SetModifier(SFX_FULL, value, &value_);
    274 }
    275 
    276 bool ChannelInfo::HasMultiFailSuffix() const {
    277   return HasModifier(SFX_MULTI_FAIL, value_);
    278 }
    279 
    280 bool ChannelInfo::SetMultiFailSuffix(bool value) {
    281   return SetModifier(SFX_MULTI_FAIL, value, &value_);
    282 }
    283 
    284 bool ChannelInfo::RemoveAllModifiersAndSuffixes() {
    285   bool modified = false;
    286 
    287   for (int scan = 0; scan < NUM_MODIFIERS; ++scan) {
    288     ModifierIndex index = static_cast<ModifierIndex>(scan);
    289     modified = SetModifier(index, false, &value_) || modified;
    290   }
    291 
    292   return modified;
    293 }
    294 
    295 }  // namespace installer
    296