1 /*
2 * This file is part of dependency-check-core.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Copyright (c) 2013 Jeremy Long. All Rights Reserved.
17 */
18 package org.owasp.dependencycheck.utils;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 /**
26 * <p>
27 * A utility class to extract version numbers from file names (or other strings
28 * containing version numbers.</p>
29 *
30 * @author Jeremy Long
31 */
32 public final class DependencyVersionUtil {
33
34 /**
35 * Regular expression to extract version numbers from file names.
36 */
37 private static final Pattern RX_VERSION = Pattern.compile("\\d+(\\.\\d{1,6})+(\\.?([_-](release|beta|alpha|\\d+)|[a-zA-Z_-]{1,3}\\d{0,8}))?");
38 /**
39 * Regular expression to extract a single version number without periods.
40 * This is a last ditch effort just to check in case we are missing a
41 * version number using the previous regex.
42 */
43 private static final Pattern RX_SINGLE_VERSION = Pattern.compile("\\d+(\\.?([_-](release|beta|alpha)|[a-zA-Z_-]{1,3}\\d{1,8}))?");
44
45 /**
46 * Regular expression to extract the part before the version numbers if
47 * there are any based on RX_VERSION. In most cases, this part represents a
48 * more accurate name.
49 */
50 private static final Pattern RX_PRE_VERSION = Pattern.compile("^(.+)[_-](\\d+\\.\\d{1,6})+");
51
52 /**
53 * Private constructor for utility class.
54 */
55 private DependencyVersionUtil() {
56 }
57
58 /**
59 * <p>
60 * A utility class to extract version numbers from file names (or other
61 * strings containing version numbers.</p>
62 * <pre>
63 * Example:
64 * Give the file name: library-name-1.4.1r2-release.jar
65 * This function would return: 1.4.1.r2</pre>
66 *
67 * @param text the text being analyzed
68 * @return a DependencyVersion containing the version
69 */
70 public static DependencyVersion parseVersion(String text) {
71 if (text == null) {
72 return null;
73 }
74 //'-' is a special case used within the CVE entries, just include it as the version.
75 if ("-".equals(text)) {
76 final DependencyVersion dv = new DependencyVersion();
77 final List<String> list = new ArrayList<String>();
78 list.add(text);
79 dv.setVersionParts(list);
80 return dv;
81 }
82 String version = null;
83 Matcher matcher = RX_VERSION.matcher(text);
84 if (matcher.find()) {
85 version = matcher.group();
86 }
87 //throw away the results if there are two things that look like version numbers
88 if (matcher.find()) {
89 return null;
90 }
91 if (version == null) {
92 matcher = RX_SINGLE_VERSION.matcher(text);
93 if (matcher.find()) {
94 version = matcher.group();
95 } else {
96 return null;
97 }
98 //throw away the results if there are two things that look like version numbers
99 if (matcher.find()) {
100 return null;
101 }
102 }
103 if (version != null && version.endsWith("-py2") && version.length() > 4) {
104 version = version.substring(0, version.length() - 4);
105 }
106 return new DependencyVersion(version);
107 }
108
109 /**
110 * <p>
111 * A utility class to extract the part before version numbers from file
112 * names (or other strings containing version numbers. In most cases, this
113 * part represents a more accurate name than the full file name.</p>
114 * <pre>
115 * Example:
116 * Give the file name: library-name-1.4.1r2-release.jar
117 * This function would return: library-name</pre>
118 *
119 * @param text the text being analyzed
120 * @return the part before the version numbers if any, otherwise return the
121 * text itself.
122 */
123 public static String parsePreVersion(String text) {
124 if (parseVersion(text) == null) {
125 return text;
126 }
127
128 final Matcher matcher = RX_PRE_VERSION.matcher(text);
129 if (matcher.find()) {
130 return matcher.group(1);
131 }
132 return text;
133 }
134 }