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