1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.utils;
19
20 import java.util.ArrayList;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25 import org.apache.commons.lang3.StringUtils;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public class DependencyVersion implements Iterable<String>, Comparable<DependencyVersion> {
42
43
44
45
46 public DependencyVersion() {
47 }
48
49
50
51
52
53
54
55
56
57 public DependencyVersion(String version) {
58 parseVersion(version);
59 }
60
61
62
63
64
65
66
67
68 public final void parseVersion(String version) {
69 versionParts = new ArrayList<String>();
70 if (version != null) {
71 final Pattern rx = Pattern.compile("(\\d+[a-z]{1,3}$|[a-z]+\\d+|\\d+|(release|beta|alpha)$)");
72 final Matcher matcher = rx.matcher(version.toLowerCase());
73 while (matcher.find()) {
74 versionParts.add(matcher.group());
75 }
76 if (versionParts.isEmpty()) {
77 versionParts.add(version);
78 }
79 }
80 }
81
82
83
84 private List<String> versionParts;
85
86
87
88
89
90
91 public List<String> getVersionParts() {
92 return versionParts;
93 }
94
95
96
97
98
99
100 public void setVersionParts(List<String> versionParts) {
101 this.versionParts = versionParts;
102 }
103
104
105
106
107
108
109 @Override
110 public Iterator<String> iterator() {
111 return versionParts.iterator();
112 }
113
114
115
116
117
118
119 @Override
120 public String toString() {
121 return StringUtils.join(versionParts, '.');
122 }
123
124
125
126
127
128
129
130 @Override
131 public boolean equals(Object obj) {
132 if (obj == null) {
133 return false;
134 }
135 if (getClass() != obj.getClass()) {
136 return false;
137 }
138 final DependencyVersion other = (DependencyVersion) obj;
139 final int minVersionMatchLength = (this.versionParts.size() < other.versionParts.size())
140 ? this.versionParts.size() : other.versionParts.size();
141 final int maxVersionMatchLength = (this.versionParts.size() > other.versionParts.size())
142 ? this.versionParts.size() : other.versionParts.size();
143
144 if (minVersionMatchLength == 1 && maxVersionMatchLength >= 3) {
145 return false;
146 }
147
148
149 for (int i = 0; i < minVersionMatchLength; i++) {
150 final String thisPart = this.versionParts.get(i);
151 final String otherPart = other.versionParts.get(i);
152 if (!thisPart.equals(otherPart)) {
153 return false;
154 }
155 }
156 if (this.versionParts.size() > minVersionMatchLength) {
157 for (int i = minVersionMatchLength; i < this.versionParts.size(); i++) {
158 if (!"0".equals(this.versionParts.get(i))) {
159 return false;
160 }
161 }
162 }
163
164 if (other.versionParts.size() > minVersionMatchLength) {
165 for (int i = minVersionMatchLength; i < other.versionParts.size(); i++) {
166 if (!"0".equals(other.versionParts.get(i))) {
167 return false;
168 }
169 }
170 }
171
172
173
174
175
176
177 return true;
178 }
179
180
181
182
183
184
185 @Override
186 public int hashCode() {
187 int hash = 5;
188 hash = 71 * hash + (this.versionParts != null ? this.versionParts.hashCode() : 0);
189 return hash;
190 }
191
192
193
194
195
196
197
198
199
200 public boolean matchesAtLeastThreeLevels(DependencyVersion version) {
201 if (version == null) {
202 return false;
203 }
204 if (Math.abs(this.versionParts.size() - version.versionParts.size()) >= 3) {
205 return false;
206 }
207
208 final int max = (this.versionParts.size() < version.versionParts.size())
209 ? this.versionParts.size() : version.versionParts.size();
210
211 boolean ret = true;
212 for (int i = 0; i < max; i++) {
213 final String thisVersion = this.versionParts.get(i);
214 final String otherVersion = version.getVersionParts().get(i);
215 if (i >= 3) {
216 if (thisVersion.compareToIgnoreCase(otherVersion) >= 0) {
217 ret = false;
218 break;
219 }
220 } else if (!thisVersion.equals(otherVersion)) {
221 ret = false;
222 break;
223 }
224 }
225
226 return ret;
227 }
228
229 @Override
230 public int compareTo(DependencyVersion version) {
231 if (version == null) {
232 return 1;
233 }
234 final List<String> left = this.getVersionParts();
235 final List<String> right = version.getVersionParts();
236 final int max = left.size() < right.size() ? left.size() : right.size();
237
238 for (int i = 0; i < max; i++) {
239 final String lStr = left.get(i);
240 final String rStr = right.get(i);
241 if (lStr.equals(rStr)) {
242 continue;
243 }
244 try {
245 final int l = Integer.parseInt(lStr);
246 final int r = Integer.parseInt(rStr);
247 if (l < r) {
248 return -1;
249 } else if (l > r) {
250 return 1;
251 }
252 } catch (NumberFormatException ex) {
253 final int comp = left.get(i).compareTo(right.get(i));
254 if (comp < 0) {
255 return -1;
256 } else if (comp > 0) {
257 return 1;
258 }
259 }
260 }
261 if (left.size() < right.size()) {
262 return -1;
263 } else if (left.size() > right.size()) {
264 return 1;
265 } else {
266 return 0;
267 }
268 }
269 }