Skip to content

Commit a7d1688

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fix-parse-path
2 parents 0eb144d + f16a2eb commit a7d1688

File tree

1 file changed

+69
-74
lines changed

1 file changed

+69
-74
lines changed

src/main/java/com/github/packageurl/PackageURL.java

Lines changed: 69 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,52 @@ public final class PackageURL implements Serializable {
6262

6363
private static final char PERCENT_CHAR = '%';
6464

65+
/**
66+
* The PackageURL scheme constant
67+
*/
68+
public static final String SCHEME = "pkg";
69+
70+
/**
71+
* The PackageURL scheme ({@code "pkg"}) constant followed by a colon ({@code ':'}).
72+
*/
73+
private static final String SCHEME_PART = SCHEME + ':';
74+
75+
/**
76+
* The package "type" or package "protocol" such as maven, npm, nuget, gem, pypi, etc.
77+
* Required.
78+
*/
79+
private String type;
80+
81+
/**
82+
* The name prefix such as a Maven groupid, a Docker image owner, a GitHub user or organization.
83+
* Optional and type-specific.
84+
*/
85+
private @Nullable String namespace;
86+
87+
/**
88+
* The name of the package.
89+
* Required.
90+
*/
91+
private String name;
92+
93+
/**
94+
* The version of the package.
95+
* Optional.
96+
*/
97+
private @Nullable String version;
98+
99+
/**
100+
* Extra qualifying data for a package such as an OS, architecture, a distro, etc.
101+
* Optional and type-specific.
102+
*/
103+
private @Nullable Map<String, String> qualifiers;
104+
105+
/**
106+
* Extra subpath within a package, relative to the package root.
107+
* Optional.
108+
*/
109+
private @Nullable String subpath;
110+
65111
/**
66112
* Constructs a new PackageURL object by parsing the specified string.
67113
*
@@ -111,8 +157,8 @@ public PackageURL(
111157
final @Nullable String subpath)
112158
throws MalformedPackageURLException {
113159
this.type = toLowerCase(validateType(requireNonNull(type, "type")));
114-
this.namespace = validateNamespace(namespace);
115-
this.name = validateName(requireNonNull(name, "name"));
160+
this.namespace = validateNamespace(this.type, namespace);
161+
this.name = validateName(this.type, requireNonNull(name, "name"));
116162
this.version = validateVersion(type, version);
117163
this.qualifiers = parseQualifiers(qualifiers);
118164
this.subpath = validateSubpath(subpath);
@@ -143,52 +189,6 @@ public PackageURL(
143189
this(type, namespace, name, version, (qualifiers != null) ? new TreeMap<>(qualifiers) : null, subpath);
144190
}
145191

146-
/**
147-
* The PackageURL scheme constant
148-
*/
149-
public static final String SCHEME = "pkg";
150-
151-
/**
152-
* The PackageURL scheme ({@code "pkg"}) constant followed by a colon ({@code ':'}).
153-
*/
154-
private static final String SCHEME_PART = SCHEME + ':';
155-
156-
/**
157-
* The package "type" or package "protocol" such as maven, npm, nuget, gem, pypi, etc.
158-
* Required.
159-
*/
160-
private String type;
161-
162-
/**
163-
* The name prefix such as a Maven groupid, a Docker image owner, a GitHub user or organization.
164-
* Optional and type-specific.
165-
*/
166-
private @Nullable String namespace;
167-
168-
/**
169-
* The name of the package.
170-
* Required.
171-
*/
172-
private String name;
173-
174-
/**
175-
* The version of the package.
176-
* Optional.
177-
*/
178-
private @Nullable String version;
179-
180-
/**
181-
* Extra qualifying data for a package such as an OS, architecture, a distro, etc.
182-
* Optional and type-specific.
183-
*/
184-
private @Nullable Map<String, String> qualifiers;
185-
186-
/**
187-
* Extra subpath within a package, relative to the package root.
188-
* Optional.
189-
*/
190-
private @Nullable String subpath;
191-
192192
/**
193193
* Converts this {@link PackageURL} to a {@link PackageURLBuilder}.
194194
*
@@ -276,7 +276,7 @@ public Map<String, String> getQualifiers() {
276276
return subpath;
277277
}
278278

279-
private void validateScheme(final String value) throws MalformedPackageURLException {
279+
private static void validateScheme(final String value) throws MalformedPackageURLException {
280280
if (!SCHEME.equals(value)) {
281281
throw new MalformedPackageURLException(
282282
"The PackageURL scheme '" + value + "' is invalid. It should be '" + SCHEME + "'");
@@ -321,14 +321,16 @@ private static void validateChars(String value, IntPredicate predicate, String c
321321
}
322322
}
323323

324-
private @Nullable String validateNamespace(final @Nullable String value) throws MalformedPackageURLException {
324+
private static @Nullable String validateNamespace(final String type, final @Nullable String value)
325+
throws MalformedPackageURLException {
325326
if (isEmpty(value)) {
326327
return null;
327328
}
328-
return validateNamespace(value.split("/"));
329+
return validateNamespace(type, value.split("/"));
329330
}
330331

331-
private @Nullable String validateNamespace(final String[] values) throws MalformedPackageURLException {
332+
private static @Nullable String validateNamespace(final String type, final String[] values)
333+
throws MalformedPackageURLException {
332334
if (values.length == 0) {
333335
return null;
334336
}
@@ -362,7 +364,7 @@ private static void validateChars(String value, IntPredicate predicate, String c
362364
return retVal;
363365
}
364366

365-
private String validateName(final String value) throws MalformedPackageURLException {
367+
private static String validateName(final String type, final String value) throws MalformedPackageURLException {
366368
if (value.isEmpty()) {
367369
throw new MalformedPackageURLException("The PackageURL name specified is invalid");
368370
}
@@ -393,7 +395,7 @@ private String validateName(final String value) throws MalformedPackageURLExcept
393395
return temp;
394396
}
395397

396-
private @Nullable String validateVersion(final String type, final @Nullable String value) {
398+
private static @Nullable String validateVersion(final String type, final @Nullable String value) {
397399
if (value == null) {
398400
return null;
399401
}
@@ -408,7 +410,7 @@ private String validateName(final String value) throws MalformedPackageURLExcept
408410
}
409411
}
410412

411-
private @Nullable Map<String, String> validateQualifiers(final @Nullable Map<String, String> values)
413+
private static @Nullable Map<String, String> validateQualifiers(final @Nullable Map<String, String> values)
412414
throws MalformedPackageURLException {
413415
if (values == null || values.isEmpty()) {
414416
return null;
@@ -438,7 +440,7 @@ private static void validateValue(final String key, final @Nullable String value
438440
}
439441
}
440442

441-
private @Nullable String validateSubpath(final @Nullable String value) throws MalformedPackageURLException {
443+
private static @Nullable String validateSubpath(final @Nullable String value) throws MalformedPackageURLException {
442444
if (isEmpty(value)) {
443445
return null;
444446
}
@@ -595,20 +597,13 @@ private static String toLowerCase(String s) {
595597
return new String(chars);
596598
}
597599

598-
private static int indexOfPercentChar(final byte[] bytes, final int start) {
599-
return IntStream.range(start, bytes.length)
600+
private static int indexOfFirstPercentChar(final byte[] bytes) {
601+
return IntStream.range(0, bytes.length)
600602
.filter(i -> isPercent(bytes[i]))
601603
.findFirst()
602604
.orElse(-1);
603605
}
604606

605-
private static int indexOfUnsafeChar(final byte[] bytes, final int start) {
606-
return IntStream.range(start, bytes.length)
607-
.filter(i -> shouldEncode(bytes[i]))
608-
.findFirst()
609-
.orElse(-1);
610-
}
611-
612607
private static byte percentDecode(final byte[] bytes, final int start) {
613608
if (start + 2 >= bytes.length) {
614609
throw new ValidationException("Incomplete percent encoding at offset " + start + " with value '"
@@ -642,7 +637,7 @@ private static String percentDecode(final String source) {
642637
}
643638

644639
byte[] bytes = source.getBytes(StandardCharsets.UTF_8);
645-
int i = indexOfPercentChar(bytes, 0);
640+
int i = indexOfFirstPercentChar(bytes);
646641

647642
if (i == -1) {
648643
return source;
@@ -777,11 +772,11 @@ private void parse(final String purl) throws MalformedPackageURLException {
777772
// The 'remainder' should now consist of an optional namespace and the name
778773
index = remainder.lastIndexOf('/');
779774
if (index <= start) {
780-
this.name = validateName(percentDecode(remainder.substring(start)));
775+
this.name = validateName(this.type, percentDecode(remainder.substring(start)));
781776
} else {
782-
this.name = validateName(percentDecode(remainder.substring(index + 1)));
777+
this.name = validateName(this.type, percentDecode(remainder.substring(index + 1)));
783778
remainder = remainder.substring(0, index);
784-
this.namespace = validateNamespace(parsePath(remainder.substring(start), false));
779+
this.namespace = validateNamespace(this.type, parsePath(remainder.substring(start), false));
785780
}
786781
verifyTypeConstraints(this.type, this.namespace, this.name);
787782
} catch (URISyntaxException e) {
@@ -795,7 +790,7 @@ private void parse(final String purl) throws MalformedPackageURLException {
795790
* @param namespace the purl namespace
796791
* @throws MalformedPackageURLException if constraints are not met
797792
*/
798-
private void verifyTypeConstraints(String type, @Nullable String namespace, @Nullable String name)
793+
private static void verifyTypeConstraints(String type, @Nullable String namespace, @Nullable String name)
799794
throws MalformedPackageURLException {
800795
if (StandardTypes.MAVEN.equals(type)) {
801796
if (isEmpty(namespace) || isEmpty(name)) {
@@ -805,7 +800,7 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
805800
}
806801
}
807802

808-
private @Nullable Map<String, String> parseQualifiers(final @Nullable Map<String, String> qualifiers)
803+
private static @Nullable Map<String, String> parseQualifiers(final @Nullable Map<String, String> qualifiers)
809804
throws MalformedPackageURLException {
810805
if (qualifiers == null || qualifiers.isEmpty()) {
811806
return null;
@@ -825,7 +820,7 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
825820
}
826821

827822
@SuppressWarnings("StringSplitter") // reason: surprising behavior is okay in this case
828-
private @Nullable Map<String, String> parseQualifiers(final String encodedString)
823+
private static @Nullable Map<String, String> parseQualifiers(final String encodedString)
829824
throws MalformedPackageURLException {
830825
try {
831826
final TreeMap<String, String> results = Arrays.stream(encodedString.split("&"))
@@ -849,14 +844,14 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
849844
}
850845
}
851846

852-
private String[] parsePath(final String encodedPath, final boolean isSubpath) {
847+
private static String[] parsePath(final String encodedPath, final boolean isSubpath) {
853848
return Arrays.stream(encodedPath.split("/"))
854849
.filter(segment -> !segment.isEmpty() && !(isSubpath && (".".equals(segment) || "..".equals(segment))))
855850
.map(PackageURL::percentDecode)
856851
.toArray(String[]::new);
857852
}
858853

859-
private String encodePath(final String path) {
854+
private static String encodePath(final String path) {
860855
return Arrays.stream(path.split("/")).map(PackageURL::percentEncode).collect(Collectors.joining("/"));
861856
}
862857

0 commit comments

Comments
 (0)