2779f7628bac01a6930d6e6484ae350b83ba86c3
[vuplus_xbmc] / xbmc / addons / AddonVersion.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25
26 #include "AddonVersion.h"
27 #include "guilib/LocalizeStrings.h"
28
29 namespace ADDON
30 {
31   AddonVersion::AddonVersion(const CStdString& version)
32   {
33     m_originalVersion = version;
34     if (m_originalVersion.IsEmpty())
35       m_originalVersion = "0.0.0";
36     const char *epoch_end = strchr(m_originalVersion.c_str(), ':');
37     if (epoch_end != NULL)
38       mEpoch = atoi(m_originalVersion.c_str());
39     else
40       mEpoch = 0;
41
42     const char *upstream_start;
43     if (epoch_end)
44       upstream_start = epoch_end + 1;
45     else
46       upstream_start = m_originalVersion.c_str();
47
48     const char *upstream_end = strrchr(upstream_start, '-');
49     size_t upstream_size;
50     if (upstream_end == NULL)
51       upstream_size = strlen(upstream_start);
52     else
53       upstream_size = upstream_end - upstream_start;
54
55     mUpstream = (char*) malloc(upstream_size + 1);
56     strncpy(mUpstream, upstream_start, upstream_size);
57     mUpstream[upstream_size] = '\0';
58
59     if (upstream_end == NULL)
60       mRevision = strdup("0");
61     else
62       mRevision = strdup(upstream_end + 1);
63   }
64
65   /**Compare two components of a Debian-style version.  Return -1, 0, or 1
66    * if a is less than, equal to, or greater than b, respectively.
67    */
68   int AddonVersion::CompareComponent(const char *a, const char *b)
69   {
70     while (*a && *b)
71     {
72       while (*a && *b && !isdigit(*a) && !isdigit(*b))
73       {
74         if (*a != *b)
75         {
76           if (*a == '~') return -1;
77           if (*b == '~') return 1;
78           return *a < *b ? -1 : 1;
79         }
80         a++;
81         b++;
82       }
83       if (*a && *b && (!isdigit(*a) || !isdigit(*b)))
84       {
85         if (*a == '~') return -1;
86         if (*b == '~') return 1;
87         return isdigit(*a) ? -1 : 1;
88       }
89
90       char *next_a, *next_b;
91       long int num_a = strtol(a, &next_a, 10);
92       long int num_b = strtol(b, &next_b, 10);
93       if (num_a != num_b)
94         return num_a < num_b ? -1 : 1;
95
96       a = next_a;
97       b = next_b;
98     }
99     if (!*a && !*b)
100       return 0;
101     if (*a)
102       return *a == '~' ? -1 : 1;
103     else
104       return *b == '~' ? 1 : -1;
105   }
106
107   bool AddonVersion::operator<(const AddonVersion& other) const
108   {
109     if (Epoch() != other.Epoch())
110       return Epoch() < other.Epoch();
111
112     int result = CompareComponent(Upstream(), other.Upstream());
113     if (result)
114       return (result < 0);
115
116     return (CompareComponent(Revision(), other.Revision()) < 0);
117   }
118
119   bool AddonVersion::operator==(const AddonVersion& other) const
120   {
121     return Epoch() == other.Epoch()
122       && CompareComponent(Upstream(), other.Upstream()) == 0
123       && CompareComponent(Revision(), other.Revision()) == 0;
124   }
125
126   CStdString AddonVersion::Print() const
127   {
128     CStdString out;
129     out.Format("%s %s", g_localizeStrings.Get(24051), m_originalVersion); // "Version <str>"
130     return CStdString(out);
131   }
132
133   bool AddonVersion::SplitFileName(CStdString& ID, CStdString& version,
134                                    const CStdString& filename)
135   {
136     int dpos = filename.rfind("-");
137     if (dpos < 0)
138       return false;
139     ID = filename.Mid(0,dpos);
140     version = filename.Mid(dpos+1);
141     version = version.Mid(0,version.size()-4);
142
143     return true;
144   }
145
146   bool AddonVersion::Test()
147   {
148     AddonVersion v1_0("1.0");
149     AddonVersion v1_00("1.00");
150     AddonVersion v1_0_0("1.0.0");
151     AddonVersion v1_1("1.1");
152     AddonVersion v1_01("1.01");
153     AddonVersion v1_0_1("1.0.1");
154
155     bool ret = false;
156
157     // These are totally sane
158     ret = (v1_0 < v1_1) && (v1_0 < v1_01) && (v1_0 < v1_0_1) &&
159           (v1_1 > v1_0_1) && (v1_01 > v1_0_1);
160
161     // These are rather sane
162     ret &= (v1_0 != v1_0_0) && (v1_0 < v1_0_0) && (v1_0_0 > v1_0) &&
163            (v1_00 != v1_0_0) && (v1_00 < v1_0_0) && (v1_0_0 > v1_00);
164
165     ret &= (v1_0 == v1_00) && !(v1_0 < v1_00) && !(v1_0 > v1_00);
166     ret &= (v1_1 == v1_01) && !(v1_1 < v1_01) && !(v1_1 > v1_01);
167
168     return ret;
169   }
170 }