@@ -170,20 +170,16 @@ public final JrtPath toAbsolutePath() {
170170
171171 @ Override
172172 public final URI toUri () {
173- try {
174- String p = toAbsolutePath ().path ;
175- if (!p .startsWith ("/modules" ) || p .contains (".." )) {
176- throw new IOError (new RuntimeException (p + " cannot be represented as URI" ));
177- }
173+ String p = toAbsolutePath ().path ;
174+ if (!p .startsWith ("/modules" ) || p .contains (".." )) {
175+ throw new IOError (new RuntimeException (p + " cannot be represented as URI" ));
176+ }
178177
179- p = p .substring ("/modules" .length ());
180- if (p .isEmpty ()) {
181- p = "/" ;
182- }
183- return new URI ("jrt" , p , null );
184- } catch (URISyntaxException ex ) {
185- throw new AssertionError (ex );
178+ p = p .substring ("/modules" .length ());
179+ if (p .isEmpty ()) {
180+ p = "/" ;
186181 }
182+ return toUri (p );
187183 }
188184
189185 private boolean equalsNameAt (JrtPath other , int index ) {
@@ -825,4 +821,135 @@ private void copyToTarget(JrtPath target, CopyOption... options)
825821 }
826822 }
827823 }
824+
825+ // adopted from sun.nio.fs.UnixUriUtils
826+ private static URI toUri (String str ) {
827+ char [] path = str .toCharArray ();
828+ assert path [0 ] == '/' ;
829+ StringBuilder sb = new StringBuilder ();
830+ sb .append (path [0 ]);
831+ for (int i = 1 ; i < path .length ; i ++) {
832+ char c = (char )(path [i ] & 0xff );
833+ if (match (c , L_PATH , H_PATH )) {
834+ sb .append (c );
835+ } else {
836+ sb .append ('%' );
837+ sb .append (hexDigits [(c >> 4 ) & 0x0f ]);
838+ sb .append (hexDigits [(c ) & 0x0f ]);
839+ }
840+ }
841+
842+ try {
843+ return new URI ("jrt:" + sb .toString ());
844+ } catch (URISyntaxException x ) {
845+ throw new AssertionError (x ); // should not happen
846+ }
847+ }
848+
849+ // The following is copied from java.net.URI
850+
851+ // Compute the low-order mask for the characters in the given string
852+ private static long lowMask (String chars ) {
853+ int n = chars .length ();
854+ long m = 0 ;
855+ for (int i = 0 ; i < n ; i ++) {
856+ char c = chars .charAt (i );
857+ if (c < 64 )
858+ m |= (1L << c );
859+ }
860+ return m ;
861+ }
862+
863+ // Compute the high-order mask for the characters in the given string
864+ private static long highMask (String chars ) {
865+ int n = chars .length ();
866+ long m = 0 ;
867+ for (int i = 0 ; i < n ; i ++) {
868+ char c = chars .charAt (i );
869+ if ((c >= 64 ) && (c < 128 ))
870+ m |= (1L << (c - 64 ));
871+ }
872+ return m ;
873+ }
874+
875+ // Compute a low-order mask for the characters
876+ // between first and last, inclusive
877+ private static long lowMask (char first , char last ) {
878+ long m = 0 ;
879+ int f = Math .max (Math .min (first , 63 ), 0 );
880+ int l = Math .max (Math .min (last , 63 ), 0 );
881+ for (int i = f ; i <= l ; i ++)
882+ m |= 1L << i ;
883+ return m ;
884+ }
885+
886+ // Compute a high-order mask for the characters
887+ // between first and last, inclusive
888+ private static long highMask (char first , char last ) {
889+ long m = 0 ;
890+ int f = Math .max (Math .min (first , 127 ), 64 ) - 64 ;
891+ int l = Math .max (Math .min (last , 127 ), 64 ) - 64 ;
892+ for (int i = f ; i <= l ; i ++)
893+ m |= 1L << i ;
894+ return m ;
895+ }
896+
897+ // Tell whether the given character is permitted by the given mask pair
898+ private static boolean match (char c , long lowMask , long highMask ) {
899+ if (c < 64 )
900+ return ((1L << c ) & lowMask ) != 0 ;
901+ if (c < 128 )
902+ return ((1L << (c - 64 )) & highMask ) != 0 ;
903+ return false ;
904+ }
905+
906+ // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
907+ // "8" | "9"
908+ private static final long L_DIGIT = lowMask ('0' , '9' );
909+ private static final long H_DIGIT = 0L ;
910+
911+ // upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
912+ // "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
913+ // "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
914+ private static final long L_UPALPHA = 0L ;
915+ private static final long H_UPALPHA = highMask ('A' , 'Z' );
916+
917+ // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
918+ // "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
919+ // "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
920+ private static final long L_LOWALPHA = 0L ;
921+ private static final long H_LOWALPHA = highMask ('a' , 'z' );
922+
923+ // alpha = lowalpha | upalpha
924+ private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA ;
925+ private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA ;
926+
927+ // alphanum = alpha | digit
928+ private static final long L_ALPHANUM = L_DIGIT | L_ALPHA ;
929+ private static final long H_ALPHANUM = H_DIGIT | H_ALPHA ;
930+
931+ // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
932+ // "(" | ")"
933+ private static final long L_MARK = lowMask ("-_.!~*'()" );
934+ private static final long H_MARK = highMask ("-_.!~*'()" );
935+
936+ // unreserved = alphanum | mark
937+ private static final long L_UNRESERVED = L_ALPHANUM | L_MARK ;
938+ private static final long H_UNRESERVED = H_ALPHANUM | H_MARK ;
939+
940+ // pchar = unreserved | escaped |
941+ // ":" | "@" | "&" | "=" | "+" | "$" | ","
942+ private static final long L_PCHAR
943+ = L_UNRESERVED | lowMask (":@&=+$," );
944+ private static final long H_PCHAR
945+ = H_UNRESERVED | highMask (":@&=+$," );
946+
947+ // All valid path characters
948+ private static final long L_PATH = L_PCHAR | lowMask (";/" );
949+ private static final long H_PATH = H_PCHAR | highMask (";/" );
950+
951+ private static final char [] hexDigits = {
952+ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
953+ '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F'
954+ };
828955}
0 commit comments