1// Copyright (c) 2010 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 <algorithm>
8
9#include "base/logging.h"
10#include "base/string_number_conversions.h"
11#include "base/string_split.h"
12#include "base/string_util.h"
13#include "base/utf_string_conversions.h"
14
15Version::Version() : is_valid_(false) {}
16
17Version::~Version() {}
18
19// static
20Version* Version::GetVersionFromString(const std::string& version_str) {
21  Version* vers = new Version();
22  if (vers->InitFromString(version_str)) {
23    DCHECK(vers->is_valid_);
24    return vers;
25  }
26  delete vers;
27  return NULL;
28}
29
30Version* Version::Clone() const {
31  DCHECK(is_valid_);
32  Version* copy = new Version();
33  copy->components_ = components_;
34  copy->is_valid_ = true;
35  return copy;
36}
37
38bool Version::Equals(const Version& that) const {
39  DCHECK(is_valid_);
40  DCHECK(that.is_valid_);
41  return CompareTo(that) == 0;
42}
43
44int Version::CompareTo(const Version& other) const {
45  DCHECK(is_valid_);
46  DCHECK(other.is_valid_);
47  size_t count = std::min(components_.size(), other.components_.size());
48  for (size_t i = 0; i < count; ++i) {
49    if (components_[i] > other.components_[i])
50      return 1;
51    if (components_[i] < other.components_[i])
52      return -1;
53  }
54  if (components_.size() > other.components_.size()) {
55    for (size_t i = count; i < components_.size(); ++i)
56      if (components_[i] > 0)
57        return 1;
58  } else if (components_.size() < other.components_.size()) {
59    for (size_t i = count; i < other.components_.size(); ++i)
60      if (other.components_[i] > 0)
61        return -1;
62  }
63  return 0;
64}
65
66const std::string Version::GetString() const {
67  DCHECK(is_valid_);
68  std::string version_str;
69  size_t count = components_.size();
70  for (size_t i = 0; i < count - 1; ++i) {
71    version_str.append(base::IntToString(components_[i]));
72    version_str.append(".");
73  }
74  version_str.append(base::IntToString(components_[count - 1]));
75  return version_str;
76}
77
78bool Version::InitFromString(const std::string& version_str) {
79  DCHECK(!is_valid_);
80  std::vector<std::string> numbers;
81  base::SplitString(version_str, '.', &numbers);
82  if (numbers.empty())
83    return false;
84  for (std::vector<std::string>::iterator i = numbers.begin();
85       i != numbers.end(); ++i) {
86    int num;
87    if (!base::StringToInt(*i, &num))
88      return false;
89    if (num < 0)
90      return false;
91    const uint16 max = 0xFFFF;
92    if (num > max)
93      return false;
94    // This throws out things like +3, or 032.
95    if (base::IntToString(num) != *i)
96      return false;
97    uint16 component = static_cast<uint16>(num);
98    components_.push_back(component);
99  }
100  is_valid_ = true;
101  return true;
102}
103