15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/version.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <stddef.h> 858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace base { 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parses the |numbers| vector representing the different numbers 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// inside the version string and constructs a vector of valid integers. It stops 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// when it reaches an invalid item (including the wildcard character). |parsed| 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is the resulting integer vector. Function returns true if all numbers were 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// parsed successfully, false otherwise. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParseVersionNumbers(const std::string& version_str, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<uint16>* parsed) { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> numbers; 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SplitString(version_str, '.', &numbers); 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (numbers.empty()) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<std::string>::const_iterator it = numbers.begin(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != numbers.end(); ++it) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num; 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!StringToInt(*it, &num)) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num < 0) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint16 max = 0xFFFF; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (num > max) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This throws out things like +3, or 032. 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (IntToString(num) != *it) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parsed->push_back(static_cast<uint16>(num)); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Compares version components in |components1| with components in 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// |components2|. Returns -1, 0 or 1 if |components1| is less than, equal to, 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// or greater than |components2|, respectively. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CompareVersionComponents(const std::vector<uint16>& components1, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<uint16>& components2) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t count = std::min(components1.size(), components2.size()); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < count; ++i) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (components1[i] > components2[i]) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (components1[i] < components2[i]) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (components1.size() > components2.size()) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = count; i < components1.size(); ++i) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (components1[i] > 0) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (components1.size() < components2.size()) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = count; i < components2.size(); ++i) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (components2[i] > 0) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Version::Version() { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Version::~Version() { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Version::Version(const std::string& version_str) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<uint16> parsed; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ParseVersionNumbers(version_str, &parsed)) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) components_.swap(parsed); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Version::IsValid() const { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (!components_.empty()); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Version::IsValidWildcardString(const std::string& wildcard_string) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string version_string = wildcard_string; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (EndsWith(wildcard_string.c_str(), ".*", false)) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) version_string = wildcard_string.substr(0, wildcard_string.size() - 2); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Version version(version_string); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return version.IsValid(); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Version::IsOlderThan(const std::string& version_str) const { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Version proposed_ver(version_str); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!proposed_ver.IsValid()) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (CompareTo(proposed_ver) < 0); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Version::CompareToWildcardString(const std::string& wildcard_string) const { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsValid()); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(Version::IsValidWildcardString(wildcard_string)); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Default behavior if the string doesn't end with a wildcard. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!EndsWith(wildcard_string.c_str(), ".*", false)) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Version version(wildcard_string); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(version.IsValid()); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CompareTo(version); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<uint16> parsed; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool success = ParseVersionNumbers( 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wildcard_string.substr(0, wildcard_string.length() - 2), &parsed); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(success); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int comparison = CompareVersionComponents(components_, parsed); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the version is smaller than the wildcard version's |parsed| vector, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then the wildcard has no effect (e.g. comparing 1.2.3 and 1.3.*) and the 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // version is still smaller. Same logic for equality (e.g. comparing 1.2.2 to 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1.2.2.* is 0 regardless of the wildcard). Under this logic, 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1.2.0.0.0.0 compared to 1.2.* is 0. 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (comparison == -1 || comparison == 0) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return comparison; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Catch the case where the digits of |parsed| are found in |components_|, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which means that the two are equal since |parsed| has a trailing "*". 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (e.g. 1.2.3 vs. 1.2.* will return 0). All other cases return 1 since 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // components is greater (e.g. 3.2.3 vs 1.*). 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(parsed.size(), 0UL); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t min_num_comp = std::min(components_.size(), parsed.size()); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < min_num_comp; ++i) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (components_[i] != parsed[i]) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Version::Equals(const Version& that) const { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsValid()); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(that.IsValid()); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (CompareTo(that) == 0); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Version::CompareTo(const Version& other) const { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsValid()); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(other.IsValid()); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CompareVersionComponents(components_, other.components_); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const std::string Version::GetString() const { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsValid()); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string version_str; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t count = components_.size(); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < count - 1; ++i) { 171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) version_str.append(IntToString(components_[i])); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) version_str.append("."); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) version_str.append(IntToString(components_[count - 1])); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return version_str; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace base 179