blob: f4219dde826f56b93836545b40cd86a00b326b8a [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
[email protected]19b8d82f2009-01-29 19:18:572// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]19b8d82f2009-01-29 19:18:575#include "base/version.h"
6
[email protected]c014f2b32013-09-03 23:29:127#include <stddef.h>
8
[email protected]b566c112010-12-21 08:27:259#include <algorithm>
Hans Wennborge93e9b22021-07-12 16:58:2910#include <ostream>
Helmut Januschka6bfb01f52024-05-28 15:47:4511#include <string_view>
[email protected]b566c112010-12-21 08:27:2512
Hans Wennborgc3cffa62020-04-27 10:09:1213#include "base/check_op.h"
[email protected]dfa049e2013-02-07 02:57:2214#include "base/strings/string_number_conversions.h"
[email protected]5ae0b763e2013-02-07 23:01:3915#include "base/strings/string_split.h"
[email protected]c851cfd2013-06-10 20:11:1416#include "base/strings/string_util.h"
[email protected]26931bc2010-03-25 22:19:0417
[email protected]1f04ef42013-04-22 07:35:5018namespace base {
19
[email protected]810b25082012-07-04 16:22:4820namespace {
21
22// Parses the |numbers| vector representing the different numbers
23// inside the version string and constructs a vector of valid integers. It stops
24// when it reaches an invalid item (including the wildcard character). |parsed|
25// is the resulting integer vector. Function returns true if all numbers were
26// parsed successfully, false otherwise.
Helmut Januschka6bfb01f52024-05-28 15:47:4527bool ParseVersionNumbers(std::string_view version_str,
wfhbf68f4d5b2015-03-10 01:32:5928 std::vector<uint32_t>* parsed) {
Helmut Januschka6bfb01f52024-05-28 15:47:4529 std::vector<std::string_view> numbers =
brettw89365dc2015-06-16 05:52:4730 SplitStringPiece(version_str, ".", KEEP_WHITESPACE, SPLIT_WANT_ALL);
Peter Kasting134ef9af2024-12-28 02:30:0931 if (numbers.empty()) {
[email protected]810b25082012-07-04 16:22:4832 return false;
Peter Kasting134ef9af2024-12-28 02:30:0933 }
[email protected]810b25082012-07-04 16:22:4834
brettw89365dc2015-06-16 05:52:4735 for (auto it = numbers.begin(); it != numbers.end(); ++it) {
Peter Kasting134ef9af2024-12-28 02:30:0936 if (StartsWith(*it, "+", CompareCase::SENSITIVE)) {
wfhf1512492015-02-22 05:41:3937 return false;
Peter Kasting134ef9af2024-12-28 02:30:0938 }
brettw89365dc2015-06-16 05:52:4739
wfhbf68f4d5b2015-03-10 01:32:5940 unsigned int num;
Peter Kasting134ef9af2024-12-28 02:30:0941 if (!StringToUint(*it, &num)) {
[email protected]810b25082012-07-04 16:22:4842 return false;
Peter Kasting134ef9af2024-12-28 02:30:0943 }
[email protected]810b25082012-07-04 16:22:4844
wfhf1512492015-02-22 05:41:3945 // This throws out leading zeros for the first item only.
Peter Kasting134ef9af2024-12-28 02:30:0946 if (it == numbers.begin() && NumberToString(num) != *it) {
[email protected]810b25082012-07-04 16:22:4847 return false;
Peter Kasting134ef9af2024-12-28 02:30:0948 }
[email protected]810b25082012-07-04 16:22:4849
wfhbf68f4d5b2015-03-10 01:32:5950 // StringToUint returns unsigned int but Version fields are uint32_t.
Peter Kasting134ef9af2024-12-28 02:30:0951 static_assert(sizeof(uint32_t) == sizeof(unsigned int),
52 "uint32_t must be same as unsigned int");
wfhbf68f4d5b2015-03-10 01:32:5953 parsed->push_back(num);
[email protected]810b25082012-07-04 16:22:4854 }
55 return true;
56}
57
58// Compares version components in |components1| with components in
[email protected]8c71390f2013-06-21 05:00:3059// |components2|. Returns -1, 0 or 1 if |components1| is less than, equal to,
60// or greater than |components2|, respectively.
wfhbf68f4d5b2015-03-10 01:32:5961int CompareVersionComponents(const std::vector<uint32_t>& components1,
62 const std::vector<uint32_t>& components2) {
[email protected]810b25082012-07-04 16:22:4863 const size_t count = std::min(components1.size(), components2.size());
64 for (size_t i = 0; i < count; ++i) {
Peter Kasting134ef9af2024-12-28 02:30:0965 if (components1[i] > components2[i]) {
[email protected]810b25082012-07-04 16:22:4866 return 1;
Peter Kasting134ef9af2024-12-28 02:30:0967 }
68 if (components1[i] < components2[i]) {
[email protected]810b25082012-07-04 16:22:4869 return -1;
Peter Kasting134ef9af2024-12-28 02:30:0970 }
[email protected]810b25082012-07-04 16:22:4871 }
72 if (components1.size() > components2.size()) {
73 for (size_t i = count; i < components1.size(); ++i) {
Peter Kasting134ef9af2024-12-28 02:30:0974 if (components1[i] > 0) {
[email protected]810b25082012-07-04 16:22:4875 return 1;
Peter Kasting134ef9af2024-12-28 02:30:0976 }
[email protected]810b25082012-07-04 16:22:4877 }
78 } else if (components1.size() < components2.size()) {
79 for (size_t i = count; i < components2.size(); ++i) {
Peter Kasting134ef9af2024-12-28 02:30:0980 if (components2[i] > 0) {
[email protected]810b25082012-07-04 16:22:4881 return -1;
Peter Kasting134ef9af2024-12-28 02:30:0982 }
[email protected]810b25082012-07-04 16:22:4883 }
84 }
85 return 0;
86}
87
88} // namespace
89
Chris Watkinsbb7211c2017-11-29 07:16:3890Version::Version() = default;
[email protected]9989c9bb2011-01-07 20:23:4391
vmpstre65942b2016-02-25 00:50:3192Version::Version(const Version& other) = default;
93
David Bertonid8a8c002024-07-18 19:30:4694Version::Version(Version&& other) = default;
95
Chris Watkinsbb7211c2017-11-29 07:16:3896Version::~Version() = default;
[email protected]1513bf82011-06-07 17:43:2097
Helmut Januschka6bfb01f52024-05-28 15:47:4598Version::Version(std::string_view version_str) {
wfhbf68f4d5b2015-03-10 01:32:5999 std::vector<uint32_t> parsed;
Peter Kasting134ef9af2024-12-28 02:30:09100 if (!ParseVersionNumbers(version_str, &parsed)) {
[email protected]810b25082012-07-04 16:22:48101 return;
Peter Kasting134ef9af2024-12-28 02:30:09102 }
[email protected]810b25082012-07-04 16:22:48103
[email protected]760024782011-06-07 17:21:30104 components_.swap(parsed);
105}
[email protected]9989c9bb2011-01-07 20:23:43106
Daniel Cheng31b35a562018-04-23 10:34:55107Version::Version(std::vector<uint32_t> components)
108 : components_(std::move(components)) {}
staraz8fb38082016-07-25 18:48:21109
[email protected]760024782011-06-07 17:21:30110bool Version::IsValid() const {
111 return (!components_.empty());
112}
113
[email protected]810b25082012-07-04 16:22:48114// static
Helmut Januschka6bfb01f52024-05-28 15:47:45115bool Version::IsValidWildcardString(std::string_view wildcard_string) {
116 std::string_view version_string = wildcard_string;
Peter Kasting134ef9af2024-12-28 02:30:09117 if (EndsWith(version_string, ".*", CompareCase::SENSITIVE)) {
Greg Thompson15a9d172019-08-06 21:13:55118 version_string = version_string.substr(0, version_string.size() - 2);
Peter Kasting134ef9af2024-12-28 02:30:09119 }
[email protected]810b25082012-07-04 16:22:48120
121 Version version(version_string);
122 return version.IsValid();
123}
124
Helmut Januschka6bfb01f52024-05-28 15:47:45125int Version::CompareToWildcardString(std::string_view wildcard_string) const {
[email protected]810b25082012-07-04 16:22:48126 DCHECK(IsValid());
127 DCHECK(Version::IsValidWildcardString(wildcard_string));
128
129 // Default behavior if the string doesn't end with a wildcard.
brettw89365dc2015-06-16 05:52:47130 if (!EndsWith(wildcard_string, ".*", CompareCase::SENSITIVE)) {
[email protected]810b25082012-07-04 16:22:48131 Version version(wildcard_string);
132 DCHECK(version.IsValid());
133 return CompareTo(version);
134 }
135
wfhbf68f4d5b2015-03-10 01:32:59136 std::vector<uint32_t> parsed;
[email protected]810b25082012-07-04 16:22:48137 const bool success = ParseVersionNumbers(
138 wildcard_string.substr(0, wildcard_string.length() - 2), &parsed);
139 DCHECK(success);
140 const int comparison = CompareVersionComponents(components_, parsed);
141 // If the version is smaller than the wildcard version's |parsed| vector,
142 // then the wildcard has no effect (e.g. comparing 1.2.3 and 1.3.*) and the
143 // version is still smaller. Same logic for equality (e.g. comparing 1.2.2 to
144 // 1.2.2.* is 0 regardless of the wildcard). Under this logic,
145 // 1.2.0.0.0.0 compared to 1.2.* is 0.
Peter Kasting134ef9af2024-12-28 02:30:09146 if (comparison == -1 || comparison == 0) {
[email protected]810b25082012-07-04 16:22:48147 return comparison;
Peter Kasting134ef9af2024-12-28 02:30:09148 }
[email protected]810b25082012-07-04 16:22:48149
150 // Catch the case where the digits of |parsed| are found in |components_|,
151 // which means that the two are equal since |parsed| has a trailing "*".
152 // (e.g. 1.2.3 vs. 1.2.* will return 0). All other cases return 1 since
153 // components is greater (e.g. 3.2.3 vs 1.*).
154 DCHECK_GT(parsed.size(), 0UL);
155 const size_t min_num_comp = std::min(components_.size(), parsed.size());
156 for (size_t i = 0; i < min_num_comp; ++i) {
Peter Kasting134ef9af2024-12-28 02:30:09157 if (components_[i] != parsed[i]) {
[email protected]810b25082012-07-04 16:22:48158 return 1;
Peter Kasting134ef9af2024-12-28 02:30:09159 }
[email protected]810b25082012-07-04 16:22:48160 }
161 return 0;
162}
163
[email protected]19b8d82f2009-01-29 19:18:57164int Version::CompareTo(const Version& other) const {
[email protected]760024782011-06-07 17:21:30165 DCHECK(IsValid());
166 DCHECK(other.IsValid());
[email protected]810b25082012-07-04 16:22:48167 return CompareVersionComponents(components_, other.components_);
[email protected]19b8d82f2009-01-29 19:18:57168}
169
Devlin Croninfde745d2019-09-25 22:21:57170std::string Version::GetString() const {
Peter Kasting134ef9af2024-12-28 02:30:09171 if (!IsValid()) {
John Rummell42b76ce42021-10-11 23:44:40172 return "invalid";
Peter Kasting134ef9af2024-12-28 02:30:09173 }
John Rummell42b76ce42021-10-11 23:44:40174
[email protected]19b8d82f2009-01-29 19:18:57175 std::string version_str;
[email protected]6dc910c2010-11-10 17:02:19176 size_t count = components_.size();
177 for (size_t i = 0; i < count - 1; ++i) {
Raul Tambrea9c13642019-03-25 13:34:42178 version_str.append(NumberToString(components_[i]));
[email protected]19b8d82f2009-01-29 19:18:57179 version_str.append(".");
180 }
Raul Tambrea9c13642019-03-25 13:34:42181 version_str.append(NumberToString(components_[count - 1]));
[email protected]19b8d82f2009-01-29 19:18:57182 return version_str;
183}
[email protected]1f04ef42013-04-22 07:35:50184
robpercivaldcd8b102016-01-25 19:39:00185bool operator==(const Version& v1, const Version& v2) {
186 return v1.CompareTo(v2) == 0;
187}
188
robpercivaldcd8b102016-01-25 19:39:00189bool operator<(const Version& v1, const Version& v2) {
190 return v1.CompareTo(v2) < 0;
191}
192
193bool operator<=(const Version& v1, const Version& v2) {
194 return v1.CompareTo(v2) <= 0;
195}
196
197bool operator>(const Version& v1, const Version& v2) {
198 return v1.CompareTo(v2) > 0;
199}
200
201bool operator>=(const Version& v1, const Version& v2) {
202 return v1.CompareTo(v2) >= 0;
203}
204
205std::ostream& operator<<(std::ostream& stream, const Version& v) {
206 return stream << v.GetString();
207}
208
[email protected]1f04ef42013-04-22 07:35:50209} // namespace base