2121 */
2222package com .github .packageurl ;
2323
24+ import java .io .ByteArrayOutputStream ;
2425import java .io .Serializable ;
2526import java .net .URI ;
2627import java .net .URISyntaxException ;
@@ -441,22 +442,25 @@ private String percentEncode(final String input) {
441442 }
442443
443444 private static String uriEncode (String source , Charset charset ) {
444- if (source == null || source .length () == 0 ) {
445+ if (source == null || source .isEmpty () ) {
445446 return source ;
446447 }
447448
448- StringBuilder builder = new StringBuilder ();
449- for (byte b : source .getBytes (charset )) {
449+ boolean changed = false ;
450+ StringBuilder builder = new StringBuilder (source .length ());
451+ byte [] bytes = source .getBytes (charset );
452+
453+ for (byte b : bytes ) {
450454 if (isUnreserved (b )) {
451455 builder .append ((char ) b );
452- }
453- else {
454- // Substitution: A '%' followed by the hexadecimal representation of the ASCII value of the replaced character
456+ } else {
455457 builder .append ('%' );
456- builder .append (Integer .toHexString (b ).toUpperCase ());
458+ builder .append (Character .toUpperCase (Character .forDigit ((b >> 4 ) & 0xF , 16 )));
459+ builder .append (Character .toUpperCase (Character .forDigit (b & 0xF , 16 )));
460+ changed = true ;
457461 }
458462 }
459- return builder .toString ();
463+ return changed ? builder .toString () : source ;
460464 }
461465
462466 private static boolean isUnreserved (int c ) {
@@ -479,34 +483,37 @@ private static boolean isDigit(int c) {
479483 * @return a decoded String
480484 */
481485 private String percentDecode (final String input ) {
482- if (input == null ) {
483- return null ;
484- }
485- final String decoded = uriDecode (input );
486- if (!decoded .equals (input )) {
487- return decoded ;
488- }
489- return input ;
486+ return uriDecode (input );
490487 }
491488
492489 public static String uriDecode (String source ) {
493- if (source == null ) {
490+ if (source == null || source . isEmpty () ) {
494491 return source ;
495492 }
496- int length = source .length ();
497- StringBuilder builder = new StringBuilder ();
493+
494+ boolean changed = false ;
495+ byte [] bytes = source .getBytes (StandardCharsets .UTF_8 );
496+ int length = bytes .length ;
497+ ByteArrayOutputStream buffer = new ByteArrayOutputStream (length );
498+
498499 for (int i = 0 ; i < length ; i ++) {
499- if (source .charAt (i ) == '%' ) {
500- String str = source .substring (i + 1 , i + 3 );
501- char c = (char ) Integer .parseInt (str , 16 );
502- builder .append (c );
503- i += 2 ;
504- }
505- else {
506- builder .append (source .charAt (i ));
500+ int b = bytes [i ];
501+
502+ if (b == '%' ) {
503+ if (i + 2 >= length ) {
504+ return null ;
505+ }
506+
507+ int b1 = Character .digit (bytes [++i ], 16 );
508+ int b2 = Character .digit (bytes [++i ], 16 );
509+ buffer .write ((char ) ((b1 << 4 ) + b2 ));
510+ changed = true ;
511+ } else {
512+ buffer .write (b );
507513 }
508514 }
509- return builder .toString ();
515+
516+ return changed ? new String (buffer .toByteArray (), StandardCharsets .UTF_8 ) : source ;
510517 }
511518
512519 /**
0 commit comments