| OLD | NEW |
| (Empty) |
| 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 "base/version.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "base/strings/string_number_conversions.h" | |
| 13 #include "base/strings/string_split.h" | |
| 14 #include "base/strings/string_util.h" | |
| 15 | |
| 16 namespace base { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Parses the |numbers| vector representing the different numbers | |
| 21 // inside the version string and constructs a vector of valid integers. It stops | |
| 22 // when it reaches an invalid item (including the wildcard character). |parsed| | |
| 23 // is the resulting integer vector. Function returns true if all numbers were | |
| 24 // parsed successfully, false otherwise. | |
| 25 bool ParseVersionNumbers(const std::string& version_str, | |
| 26 std::vector<uint32_t>* parsed) { | |
| 27 std::vector<StringPiece> numbers = | |
| 28 SplitStringPiece(version_str, ".", KEEP_WHITESPACE, SPLIT_WANT_ALL); | |
| 29 if (numbers.empty()) | |
| 30 return false; | |
| 31 | |
| 32 for (auto it = numbers.begin(); it != numbers.end(); ++it) { | |
| 33 if (StartsWith(*it, "+", CompareCase::SENSITIVE)) | |
| 34 return false; | |
| 35 | |
| 36 // TODO(brettw) when we have a StringPiece version of StringToUint, delete | |
| 37 // this string conversion. | |
| 38 unsigned int num; | |
| 39 if (!StringToUint(*it, &num)) | |
| 40 return false; | |
| 41 | |
| 42 // This throws out leading zeros for the first item only. | |
| 43 if (it == numbers.begin() && UintToString(num) != *it) | |
| 44 return false; | |
| 45 | |
| 46 // StringToUint returns unsigned int but Version fields are uint32_t. | |
| 47 static_assert(sizeof (uint32_t) == sizeof (unsigned int), | |
| 48 "uint32_t must be same as unsigned int"); | |
| 49 parsed->push_back(num); | |
| 50 } | |
| 51 return true; | |
| 52 } | |
| 53 | |
| 54 // Compares version components in |components1| with components in | |
| 55 // |components2|. Returns -1, 0 or 1 if |components1| is less than, equal to, | |
| 56 // or greater than |components2|, respectively. | |
| 57 int CompareVersionComponents(const std::vector<uint32_t>& components1, | |
| 58 const std::vector<uint32_t>& components2) { | |
| 59 const size_t count = std::min(components1.size(), components2.size()); | |
| 60 for (size_t i = 0; i < count; ++i) { | |
| 61 if (components1[i] > components2[i]) | |
| 62 return 1; | |
| 63 if (components1[i] < components2[i]) | |
| 64 return -1; | |
| 65 } | |
| 66 if (components1.size() > components2.size()) { | |
| 67 for (size_t i = count; i < components1.size(); ++i) { | |
| 68 if (components1[i] > 0) | |
| 69 return 1; | |
| 70 } | |
| 71 } else if (components1.size() < components2.size()) { | |
| 72 for (size_t i = count; i < components2.size(); ++i) { | |
| 73 if (components2[i] > 0) | |
| 74 return -1; | |
| 75 } | |
| 76 } | |
| 77 return 0; | |
| 78 } | |
| 79 | |
| 80 } // namespace | |
| 81 | |
| 82 Version::Version() { | |
| 83 } | |
| 84 | |
| 85 Version::~Version() { | |
| 86 } | |
| 87 | |
| 88 Version::Version(const std::string& version_str) { | |
| 89 std::vector<uint32_t> parsed; | |
| 90 if (!ParseVersionNumbers(version_str, &parsed)) | |
| 91 return; | |
| 92 | |
| 93 components_.swap(parsed); | |
| 94 } | |
| 95 | |
| 96 bool Version::IsValid() const { | |
| 97 return (!components_.empty()); | |
| 98 } | |
| 99 | |
| 100 // static | |
| 101 bool Version::IsValidWildcardString(const std::string& wildcard_string) { | |
| 102 std::string version_string = wildcard_string; | |
| 103 if (EndsWith(version_string, ".*", CompareCase::SENSITIVE)) | |
| 104 version_string.resize(version_string.size() - 2); | |
| 105 | |
| 106 Version version(version_string); | |
| 107 return version.IsValid(); | |
| 108 } | |
| 109 | |
| 110 bool Version::IsOlderThan(const std::string& version_str) const { | |
| 111 Version proposed_ver(version_str); | |
| 112 if (!proposed_ver.IsValid()) | |
| 113 return false; | |
| 114 return (CompareTo(proposed_ver) < 0); | |
| 115 } | |
| 116 | |
| 117 int Version::CompareToWildcardString(const std::string& wildcard_string) const { | |
| 118 DCHECK(IsValid()); | |
| 119 DCHECK(Version::IsValidWildcardString(wildcard_string)); | |
| 120 | |
| 121 // Default behavior if the string doesn't end with a wildcard. | |
| 122 if (!EndsWith(wildcard_string, ".*", CompareCase::SENSITIVE)) { | |
| 123 Version version(wildcard_string); | |
| 124 DCHECK(version.IsValid()); | |
| 125 return CompareTo(version); | |
| 126 } | |
| 127 | |
| 128 std::vector<uint32_t> parsed; | |
| 129 const bool success = ParseVersionNumbers( | |
| 130 wildcard_string.substr(0, wildcard_string.length() - 2), &parsed); | |
| 131 DCHECK(success); | |
| 132 const int comparison = CompareVersionComponents(components_, parsed); | |
| 133 // If the version is smaller than the wildcard version's |parsed| vector, | |
| 134 // then the wildcard has no effect (e.g. comparing 1.2.3 and 1.3.*) and the | |
| 135 // version is still smaller. Same logic for equality (e.g. comparing 1.2.2 to | |
| 136 // 1.2.2.* is 0 regardless of the wildcard). Under this logic, | |
| 137 // 1.2.0.0.0.0 compared to 1.2.* is 0. | |
| 138 if (comparison == -1 || comparison == 0) | |
| 139 return comparison; | |
| 140 | |
| 141 // Catch the case where the digits of |parsed| are found in |components_|, | |
| 142 // which means that the two are equal since |parsed| has a trailing "*". | |
| 143 // (e.g. 1.2.3 vs. 1.2.* will return 0). All other cases return 1 since | |
| 144 // components is greater (e.g. 3.2.3 vs 1.*). | |
| 145 DCHECK_GT(parsed.size(), 0UL); | |
| 146 const size_t min_num_comp = std::min(components_.size(), parsed.size()); | |
| 147 for (size_t i = 0; i < min_num_comp; ++i) { | |
| 148 if (components_[i] != parsed[i]) | |
| 149 return 1; | |
| 150 } | |
| 151 return 0; | |
| 152 } | |
| 153 | |
| 154 bool Version::Equals(const Version& that) const { | |
| 155 DCHECK(IsValid()); | |
| 156 DCHECK(that.IsValid()); | |
| 157 return (CompareTo(that) == 0); | |
| 158 } | |
| 159 | |
| 160 int Version::CompareTo(const Version& other) const { | |
| 161 DCHECK(IsValid()); | |
| 162 DCHECK(other.IsValid()); | |
| 163 return CompareVersionComponents(components_, other.components_); | |
| 164 } | |
| 165 | |
| 166 const std::string Version::GetString() const { | |
| 167 DCHECK(IsValid()); | |
| 168 std::string version_str; | |
| 169 size_t count = components_.size(); | |
| 170 for (size_t i = 0; i < count - 1; ++i) { | |
| 171 version_str.append(IntToString(components_[i])); | |
| 172 version_str.append("."); | |
| 173 } | |
| 174 version_str.append(IntToString(components_[count - 1])); | |
| 175 return version_str; | |
| 176 } | |
| 177 | |
| 178 } // namespace base | |
| OLD | NEW |