1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.river.api.net;
19
20 import java.io.File;
21 import java.io.UnsupportedEncodingException;
22 import java.net.MalformedURLException;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.net.URL;
26 import org.apache.river.impl.Messages;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public final class Uri implements Comparable<Uri> {
49
50
51
52
53 static final String unreserved = "_-!.~\'()*";
54 static final String punct = ",;:$&+=";
55 static final String reserved = punct + "?/[]@";
56
57
58
59
60 static final String someLegal = unreserved + punct;
61
62 static final String queryLegal = unreserved + reserved + "\\\"";
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 private static final char escape = '%';
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 static final String allLegalUnescaped = ":/?#[]@!$&'()*+,;=-._~";
133 static final String allLegal = "%:/?#[]@!$&'()*+,;=-._~";
134
135
136
137
138
139
140
141
142
143
144
145
146 static final String schemeLegal = "+-.";
147
148
149
150
151 static final String userinfoLegal = "-._~!$&'()*+,;=:";
152 static final String authorityLegal = userinfoLegal + "@[]";
153
154
155
156
157 static final String iPvFuture = "-._~!$&'()*+,;=:";
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 static final String hostRegNameLegal = "-._~!$&'()*+,;=";
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 static final String pcharLegal = "-._~!$&'()*+,;=:@";
205 static final String segmentNzNcLegal = "-._~!$&'()*+,;=@";
206 static final String segmentLegal = pcharLegal;
207 static final String pathLegal = segmentLegal + "/";
208
209
210
211
212
213 static final String queryFragLegal = pcharLegal + "/?";
214
215 private final static char a = 'a';
216 private final static char z = 'z';
217 private final static char A = 'A';
218 private final static char Z = 'Z';
219 private final static char upperCaseBitwiseMask = 0xdf;
220 private final static char lowerCaseBitwiseMask = 0x20;
221
222 static String toAsciiUpperCase(String s){
223 return new String(toAsciiUpperCase(s.toCharArray()));
224 }
225
226 static char [] toAsciiUpperCase(char [] array){
227 int length = array.length;
228 for (int i = 0; i < length ; i++){
229 if (array[i] >= a && array[i] <= z) {
230 array[i] = toAsciiUpperCase(array[i]);
231 }
232 }
233 return array;
234 }
235
236 static char toAsciiUpperCase(char c){
237 return (char) (c & upperCaseBitwiseMask);
238 }
239
240 static String toAsciiLowerCase(String s){
241 return new String(toAsciiLowerCase(s.toCharArray()));
242 }
243
244 static char[] toAsciiLowerCase(char [] array){
245 int length = array.length;
246 for (int i = 0; i < length ; i++){
247 if (array[i] >= A && array[i] <= Z) {
248 array[i] = toAsciiLowerCase(array[i]);
249 }
250 }
251 return array;
252 }
253
254 static char toAsciiLowerCase(char c){
255 return (char) (c | lowerCaseBitwiseMask);
256 }
257
258 static boolean charArraysEqual( char [] a , char [] b){
259 int alen = a.length;
260 int blen = b.length;
261 if (alen != blen) return false;
262 for (int i = 0; i < alen; i++){
263 if (a[i] != b[i]) return false;
264 }
265 return true;
266 }
267
268 static boolean asciiStringsUpperCaseEqual(String a, String b){
269 char [] ac = a.toCharArray();
270 toAsciiUpperCase(ac);
271 char [] bc = b.toCharArray();
272 toAsciiUpperCase(bc);
273 return charArraysEqual(ac, bc);
274 }
275
276 static boolean asciiStringsLowerCaseEqual(String a, String b){
277 char [] ac = a.toCharArray();
278 toAsciiLowerCase(ac);
279 char [] bc = b.toCharArray();
280 toAsciiLowerCase(bc);
281 return charArraysEqual(ac, bc);
282 }
283
284
285
286
287
288
289 public static String fixWindowsURI(String uri) {
290 if (uri == null) return null;
291 if (File.separatorChar != '\\') return uri;
292 if ( uri.startsWith("file:") || uri.startsWith("FILE:")){
293 char [] u = uri.toCharArray();
294 int l = u.length;
295 StringBuilder sb = new StringBuilder(uri.length()+1);
296 for (int i=0; i<l; i++){
297
298 if (u[i] == File.separatorChar) {
299 sb.append('/');
300 continue;
301 }
302 if (i == 5 && uri.startsWith(":", 6 )) {
303
304
305 sb.append("/");
306 }
307 sb.append(u[i]);
308 }
309 return sb.toString();
310 }
311 return uri;
312 }
313
314 public static URI uriToURI(Uri uri){
315 return URI.create(uri.toString());
316 }
317
318 public static Uri urlToUri(URL url) throws URISyntaxException{
319 return Uri.parseAndCreate(fixWindowsURI(url.toString()));
320 }
321
322 public static File uriToFile(Uri uri){
323 return new File(uriToURI(uri));
324 }
325
326 public static Uri fileToUri(File file) throws URISyntaxException{
327 String path = file.getAbsolutePath();
328 if (File.separatorChar == '\\') {
329 path = path.replace(File.separatorChar, '/');
330 }
331 path = fixWindowsURI("file:" + path);
332 return Uri.escapeAndCreate(path);
333 }
334
335 public static Uri filePathToUri(String path) throws URISyntaxException{
336 String forwardSlash = "/";
337 if (path == null || path.length() == 0) {
338
339 path = "*";
340 }
341
342
343 boolean directory = false;
344 if (path.endsWith(forwardSlash)) directory = true;
345 path = new File(path).getAbsolutePath();
346 if (directory) {
347 if (!(path.endsWith(File.separator))){
348 path = path + File.separator;
349 }
350 }
351 if (File.separatorChar == '\\') {
352 path = path.replace(File.separatorChar, '/');
353 }
354 path = fixWindowsURI("file:" + path);
355 return Uri.escapeAndCreate(path);
356 }
357
358
359
360 private final String string;
361 private final String scheme;
362 private final String schemespecificpart;
363 private final String authority;
364 private final String userinfo;
365 private final String host;
366 private final int port;
367 private final String path;
368 private final String query;
369 private final String fragment;
370 private final boolean opaque;
371 private final boolean absolute;
372 private final boolean serverAuthority;
373 private final String hashString;
374 private final int hash;
375 private final boolean fileSchemeCaseInsensitiveOS;
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394 private Uri(String string,
395 String scheme,
396 String schemespecificpart,
397 String authority,
398 String userinfo,
399 String host,
400 int port,
401 String path,
402 String query,
403 String fragment,
404 boolean opaque,
405 boolean absolute,
406 boolean serverAuthority,
407 int hash,
408 boolean fileSchemeCaseInsensitiveOS)
409 {
410 super();
411 this.scheme = scheme;
412 this.schemespecificpart = schemespecificpart;
413 this.authority = authority;
414 this.userinfo = userinfo;
415 this.host = host;
416 this.port = port;
417 this.path = path;
418 this.query = query;
419 this.fragment = fragment;
420 this.opaque = opaque;
421 this.absolute = absolute;
422 this.serverAuthority = serverAuthority;
423 if (string == null) {
424 StringBuilder result = new StringBuilder();
425 if (scheme != null) {
426 result.append(scheme);
427 result.append(':');
428 }
429 if (opaque) {
430 result.append(schemespecificpart);
431 } else {
432 if (authority != null) {
433 result.append("//"); //$NON-NLS-1$
434 result.append(authority);
435 }
436
437 if (path != null) {
438 result.append(path);
439 }
440
441 if (query != null) {
442 result.append('?');
443 result.append(query);
444 }
445 }
446
447 if (fragment != null) {
448 result.append('#');
449 result.append(fragment);
450 }
451
452 this.string = result.toString();
453 } else {
454 this.string = string;
455 }
456 this.hashString = getHashString();
457 this.hash = hash == -1 ? hashString.hashCode(): hash;
458 this.fileSchemeCaseInsensitiveOS = fileSchemeCaseInsensitiveOS;
459 }
460
461
462
463
464
465
466
467
468 private Uri(UriParser p){
469 this(p.string,
470 p.scheme,
471 p.schemespecificpart,
472 p.authority,
473 p.userinfo,
474 p.host,
475 p.port,
476 p.path,
477 p.query,
478 p.fragment,
479 p.opaque,
480 p.absolute,
481 p.serverAuthority,
482 p.hash,
483 p.fileSchemeCaseInsensitiveOS);
484 }
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501 public Uri(String uri) throws URISyntaxException {
502 this(constructor1(uri));
503 }
504
505 private static UriParser constructor1(String uri) throws URISyntaxException {
506 uri = URIEncoderDecoder.decodeUnreserved(uri);
507 UriParser p = new UriParser();
508 p.parseURI(uri, false);
509 return p;
510 }
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529 public Uri(String scheme, String ssp, String frag) throws URISyntaxException {
530 this(constructor2(scheme, ssp, frag));
531 }
532
533 private static UriParser constructor2(String scheme, String ssp, String frag) throws URISyntaxException{
534 StringBuilder uri = new StringBuilder();
535 if (scheme != null) {
536 uri.append(scheme);
537 uri.append(':');
538 }
539 if (ssp != null) {
540
541 uri.append(quoteComponent(ssp, allLegalUnescaped));
542 }
543 if (frag != null) {
544 uri.append('#');
545
546 uri.append(quoteComponent(frag, Uri.queryFragLegal));
547 }
548
549 UriParser p = new UriParser();
550 p.parseURI(uri.toString(), false);
551 return p;
552 }
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581 public Uri(String scheme, String userinfo, String host, int port,
582 String path, String query, String fragment)
583 throws URISyntaxException {
584 this(constructor3(scheme, userinfo, host, port, path, query, fragment));
585 }
586
587 private static UriParser constructor3(String scheme, String userinfo, String host, int port,
588 String path, String query, String fragment) throws URISyntaxException {
589 if (scheme == null && userinfo == null && host == null && path == null
590 && query == null && fragment == null) {
591 UriParser p = new UriParser();
592 p.path = "";
593 return p;
594 }
595
596 if (scheme != null && path != null && path.length() > 0
597 && path.charAt(0) != '/') {
598 throw new URISyntaxException(path, Messages.getString("luni.82"));
599 }
600
601 StringBuilder uri = new StringBuilder();
602 if (scheme != null) {
603 uri.append(scheme);
604 uri.append(':');
605 }
606
607 if (userinfo != null || host != null || port != -1) {
608 uri.append("//"); //$NON-NLS-1$
609 }
610
611 if (userinfo != null) {
612
613 uri.append(quoteComponent(userinfo, Uri.userinfoLegal));
614 uri.append('@');
615 }
616
617 if (host != null) {
618
619
620 if (host.indexOf(':') != -1 && host.indexOf(']') == -1
621 && host.indexOf('[') == -1) {
622 host = "[" + host + "]";
623 }
624 uri.append(host);
625 }
626
627 if (port != -1) {
628 uri.append(':');
629 uri.append(port);
630 }
631
632 if (path != null) {
633
634 uri.append(quoteComponent(path, "/@" + Uri.pathLegal));
635 }
636
637 if (query != null) {
638 uri.append('?');
639
640 uri.append(quoteComponent(query, Uri.queryFragLegal));
641 }
642
643 if (fragment != null) {
644
645 uri.append('#');
646 uri.append(quoteComponent(fragment, Uri.queryFragLegal));
647 }
648
649 UriParser p = new UriParser();
650 p.parseURI(uri.toString(), true);
651 return p;
652 }
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673 public Uri(String scheme, String host, String path, String fragment)
674 throws URISyntaxException {
675 this(scheme, null, host, -1, path, null, fragment);
676 }
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700 public Uri(String scheme, String authority, String path, String query,
701 String fragment) throws URISyntaxException {
702 this(constructor4(scheme, authority, path, query, fragment));
703 }
704
705 private static UriParser constructor4(String scheme, String authority, String path, String query,
706 String fragment) throws URISyntaxException {
707 if (scheme != null && path != null && path.length() > 0
708 && path.charAt(0) != '/') {
709 throw new URISyntaxException(path, Messages.getString("luni.82"));
710 }
711
712 StringBuilder uri = new StringBuilder();
713 if (scheme != null) {
714 uri.append(scheme);
715 uri.append(':');
716 }
717 if (authority != null) {
718 uri.append("//"); //$NON-NLS-1$
719
720 uri.append(quoteComponent(authority, "@[]" + Uri.authorityLegal));
721 }
722
723 if (path != null) {
724
725 uri.append(quoteComponent(path, "/@" + Uri.pathLegal));
726 }
727 if (query != null) {
728
729 uri.append('?');
730 uri.append(quoteComponent(query, Uri.queryFragLegal));
731 }
732 if (fragment != null) {
733
734 uri.append('#');
735 uri.append(quoteComponent(fragment, Uri.queryFragLegal));
736 }
737
738 UriParser p = new UriParser();
739 p.parseURI(uri.toString(), false);
740 return p;
741 }
742
743
744
745
746
747
748
749
750 private static String quoteComponent(String component, String legalset) {
751 try {
752
753
754
755
756
757
758 return URIEncoderDecoder.quoteIllegal(component, legalset);
759 } catch (UnsupportedEncodingException e) {
760 throw new RuntimeException(e.toString());
761 }
762 }
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779 @Override
780 public int compareTo(Uri uri) {
781 int ret;
782
783
784 if (scheme == null && uri.scheme != null) {
785 return -1;
786 } else if (scheme != null && uri.scheme == null) {
787 return 1;
788 } else if (scheme != null && uri.scheme != null) {
789 ret = scheme.compareToIgnoreCase(uri.scheme);
790 if (ret != 0) return ret;
791 }
792
793
794 if (!opaque && uri.opaque) {
795 return -1;
796 } else if (opaque && !uri.opaque) {
797 return 1;
798 } else if (opaque && uri.opaque) {
799 ret = schemespecificpart.compareTo(uri.schemespecificpart);
800 if (ret != 0) {
801 return ret;
802 }
803 } else {
804
805
806
807
808 if (authority != null && uri.authority == null) {
809 return 1;
810 } else if (authority == null && uri.authority != null) {
811 return -1;
812 } else if (authority != null && uri.authority != null) {
813 if (host != null && uri.host != null) {
814
815 if (userinfo != null && uri.userinfo == null) {
816 return 1;
817 } else if (userinfo == null && uri.userinfo != null) {
818 return -1;
819 } else if (userinfo != null && uri.userinfo != null) {
820 ret = userinfo.compareTo(uri.userinfo);
821 if (ret != 0) {
822 return ret;
823 }
824 }
825
826
827 ret = host.compareToIgnoreCase(uri.host);
828 if (ret != 0) {
829 return ret;
830 }
831
832
833 if (port != uri.port) {
834 return port - uri.port;
835 }
836 } else {
837
838 ret = authority.compareTo(uri.authority);
839 if (ret != 0) {
840 return ret;
841 }
842 }
843 }
844
845
846
847
848 if (fileSchemeCaseInsensitiveOS){
849 ret = toAsciiUpperCase(path).compareTo(toAsciiUpperCase(uri.path));
850
851 } else {
852 ret = path.compareTo(uri.path);
853 }
854 if (ret != 0) {
855 return ret;
856 }
857
858
859
860 if (query != null && uri.query == null) {
861 return 1;
862 } else if (query == null && uri.query != null) {
863 return -1;
864 } else if (query != null && uri.query != null) {
865 ret = query.compareTo(uri.query);
866 if (ret != 0) {
867 return ret;
868 }
869 }
870 }
871
872
873 if (fragment != null && uri.fragment == null) {
874 return 1;
875 } else if (fragment == null && uri.fragment != null) {
876 return -1;
877 } else if (fragment != null && uri.fragment != null) {
878 ret = fragment.compareTo(uri.fragment);
879 if (ret != 0) {
880 return ret;
881 }
882 }
883
884
885 return 0;
886 }
887
888
889
890
891
892
893
894
895
896
897
898
899 public static Uri create(String rfc3986compliantURI) {
900 Uri result = null;
901 try {
902 result = new Uri(rfc3986compliantURI);
903 } catch (URISyntaxException e) {
904 throw new IllegalArgumentException(e.getMessage());
905 }
906 return result;
907 }
908
909
910
911
912
913
914
915
916
917
918
919
920 public static Uri escapeAndCreate(String unescapedString) throws URISyntaxException{
921 return new Uri(quoteComponent(unescapedString, allLegalUnescaped));
922 }
923
924
925
926
927
928
929
930
931
932
933 public static Uri parseAndCreate(String nonCompliantEscapedString) throws URISyntaxException{
934 return new Uri(quoteComponent(nonCompliantEscapedString, allLegal));
935 }
936
937
938
939
940
941
942 private String convertHexToUpperCase(String s) {
943 StringBuilder result = new StringBuilder("");
944 if (s.indexOf('%') == -1) {
945 return s;
946 }
947
948 int index, previndex = 0;
949 while ((index = s.indexOf('%', previndex)) != -1) {
950 result.append(s.substring(previndex, index + 1));
951
952 result.append(toAsciiUpperCase(s.substring(index + 1, index + 3).toCharArray()));
953 index += 3;
954 previndex = index;
955 }
956 return result.toString();
957 }
958
959
960
961
962
963
964 private boolean equalsHexCaseInsensitive(String first, String second) {
965
966 if (first != null) return first.equals(second);
967 return second == null;
968 }
969
970
971
972
973
974
975
976
977
978
979
980 @Override
981 public boolean equals(Object o) {
982 if (!(o instanceof Uri)) {
983 return false;
984 }
985 if (hash != o.hashCode()) return false;
986 Uri uri = (Uri) o;
987
988 if (uri.fragment == null && fragment != null || uri.fragment != null
989 && fragment == null) {
990 return false;
991 } else if (uri.fragment != null && fragment != null) {
992 if (!equalsHexCaseInsensitive(uri.fragment, fragment)) {
993 return false;
994 }
995 }
996
997 if (uri.scheme == null && scheme != null || uri.scheme != null
998 && scheme == null) {
999 return false;
1000 } else if (uri.scheme != null && scheme != null) {
1001 if (!uri.scheme.equalsIgnoreCase(scheme)) {
1002 return false;
1003 }
1004 }
1005
1006 if (uri.opaque && opaque) {
1007 return equalsHexCaseInsensitive(uri.schemespecificpart,
1008 schemespecificpart);
1009 } else if (!uri.opaque && !opaque) {
1010 if ( !(path != null && (path.equals(uri.path)
1011 || fileSchemeCaseInsensitiveOS
1012
1013 && asciiStringsUpperCaseEqual(path, uri.path)
1014 )))
1015 {
1016 return false;
1017 }
1018
1019 if (uri.query != null && query == null || uri.query == null
1020 && query != null) {
1021 return false;
1022 } else if (uri.query != null && query != null) {
1023 if (!equalsHexCaseInsensitive(uri.query, query)) {
1024 return false;
1025 }
1026 }
1027
1028 if (uri.authority != null && authority == null
1029 || uri.authority == null && authority != null) {
1030 return false;
1031 } else if (uri.authority != null && authority != null) {
1032 if (uri.host != null && host == null || uri.host == null
1033 && host != null) {
1034 return false;
1035 } else if (uri.host == null && host == null) {
1036
1037 return equalsHexCaseInsensitive(uri.authority, authority);
1038 } else {
1039 if (!host.equalsIgnoreCase(uri.host)) {
1040 return false;
1041 }
1042
1043 if (port != uri.port) {
1044 return false;
1045 }
1046
1047 if (uri.userinfo != null && userinfo == null
1048 || uri.userinfo == null && userinfo != null) {
1049 return false;
1050 } else if (uri.userinfo != null && userinfo != null) {
1051 return equalsHexCaseInsensitive(userinfo, uri.userinfo);
1052 } else {
1053 return true;
1054 }
1055 }
1056 } else {
1057
1058 return true;
1059 }
1060
1061 } else {
1062
1063 return false;
1064 }
1065 }
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 public boolean implies(Uri implied) {
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161 if (hash == implied.hash){
1162 if (this.equals(implied)) {
1163 return true;
1164 }
1165 }
1166
1167 if ( scheme != null){
1168 if (!scheme.equalsIgnoreCase(implied.scheme)) {
1169 return false;
1170 }
1171 }
1172
1173 if (host != null) {
1174 if (implied.host == null) {
1175 return false;
1176 }
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194 if (!((host.length() == 0 || "localhost".equals(host)) && (implied.host
1195 .length() == 0 || "localhost".equals(implied.host)))
1196 && !host.equals(implied.host)) {
1197
1198
1199
1200 boolean hostNameMatches = false;
1201 boolean isPartialWild = (host.charAt(0) == '*');
1202 if (isPartialWild) {
1203 boolean isWild = (host.length() == 1);
1204 if (isWild) {
1205 hostNameMatches = true;
1206 } else {
1207
1208 int length = host.length() - 1;
1209 hostNameMatches = implied.host.regionMatches(implied.host.length() - length,
1210 host, 1, length);
1211 }
1212 }
1213 if (!hostNameMatches) return false;
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264 }
1265 }
1266
1267
1268 if (port != -1) {
1269 if (port != implied.port) {
1270 return false;
1271 }
1272 }
1273
1274
1275
1276 String thisFile;
1277 String thatFile;
1278 if (fileSchemeCaseInsensitiveOS){
1279 thisFile = path == null ? null: toAsciiUpperCase(path);
1280 thatFile = implied.path == null ? null: toAsciiUpperCase(implied.path);
1281 } else {
1282 thisFile = path;
1283 thatFile = implied.path;
1284 }
1285 if (thatFile == null || thisFile == null) return false;
1286 if (thisFile.endsWith("/-")) {
1287 if (!thatFile.startsWith(thisFile.substring(0, thisFile
1288 .length() - 2))) {
1289 return false;
1290 }
1291 } else if (thisFile.endsWith("/*")) {
1292 if (!thatFile.startsWith(thisFile.substring(0, thisFile
1293 .length() - 2))) {
1294 return false;
1295 }
1296
1297 if (thatFile.indexOf("/", thisFile.length() - 1) != -1) {
1298 return false;
1299 }
1300 } else {
1301
1302 if (!thisFile.equals(thatFile)) {
1303 if (!thisFile.endsWith("/")) {
1304 if (!thatFile.equals(thisFile + "/")) {
1305 return false;
1306 }
1307 } else {
1308 return false;
1309 }
1310 }
1311 }
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327 return true;
1328 }
1329
1330
1331
1332
1333
1334
1335 public String getAuthority() {
1336 return decode(authority);
1337 }
1338
1339
1340
1341
1342
1343
1344 public String getFragment() {
1345 return decode(fragment);
1346 }
1347
1348
1349
1350
1351
1352
1353 public String getHost() {
1354 return host;
1355 }
1356
1357
1358
1359
1360
1361
1362 public String getPath() {
1363 return decode(path);
1364 }
1365
1366
1367
1368
1369
1370
1371 public int getPort() {
1372 return port;
1373 }
1374
1375
1376
1377
1378
1379
1380 public String getQuery() {
1381 return decode(query);
1382 }
1383
1384
1385
1386
1387
1388
1389 public String getRawAuthority() {
1390 return authority;
1391 }
1392
1393
1394
1395
1396
1397
1398 public String getRawFragment() {
1399 return fragment;
1400 }
1401
1402
1403
1404
1405
1406
1407 public String getRawPath() {
1408 return path;
1409 }
1410
1411
1412
1413
1414
1415
1416 public String getRawQuery() {
1417 return query;
1418 }
1419
1420
1421
1422
1423
1424
1425 public String getRawSchemeSpecificPart() {
1426 return schemespecificpart;
1427 }
1428
1429
1430
1431
1432
1433
1434 public String getRawUserInfo() {
1435 return userinfo;
1436 }
1437
1438
1439
1440
1441
1442
1443 public String getScheme() {
1444 return scheme;
1445 }
1446
1447
1448
1449
1450
1451
1452 public String getSchemeSpecificPart() {
1453 return decode(schemespecificpart);
1454 }
1455
1456
1457
1458
1459
1460
1461 public String getUserInfo() {
1462 return decode(userinfo);
1463 }
1464
1465
1466
1467
1468
1469
1470 @Override
1471 public int hashCode() {
1472 return hash;
1473 }
1474
1475
1476
1477
1478
1479
1480
1481 public boolean isAbsolute() {
1482 return absolute;
1483 }
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493 public boolean isOpaque() {
1494 return opaque;
1495 }
1496
1497
1498
1499
1500
1501
1502
1503 public Uri normalize() {
1504 if (opaque) {
1505 return this;
1506 }
1507 String normalizedPath = normalize(path);
1508
1509 if (path.equals(normalizedPath)) {
1510 return this;
1511 }
1512
1513
1514 return new Uri( null,
1515 scheme,
1516 setSchemeSpecificPart(authority, normalizedPath , query),
1517 authority,
1518 userinfo,
1519 host,
1520 port,
1521 normalizedPath,
1522 query,
1523 fragment,
1524 opaque,
1525 absolute,
1526 serverAuthority,
1527 hash,
1528 fileSchemeCaseInsensitiveOS);
1529 }
1530
1531
1532
1533
1534
1535 private String normalize(String path) {
1536
1537 int index = -1;
1538 int pathlen = path.length();
1539 int size = 0;
1540 if (pathlen > 0 && path.charAt(0) != '/') {
1541 size++;
1542 }
1543 while ((index = path.indexOf('/', index + 1)) != -1) {
1544 if (index + 1 < pathlen && path.charAt(index + 1) != '/') {
1545 size++;
1546 }
1547 }
1548
1549 String[] seglist = new String[size];
1550 boolean[] include = new boolean[size];
1551
1552
1553 int current = 0;
1554 int index2;
1555 index = (pathlen > 0 && path.charAt(0) == '/') ? 1 : 0;
1556 while ((index2 = path.indexOf('/', index + 1)) != -1) {
1557 seglist[current++] = path.substring(index, index2);
1558 index = index2 + 1;
1559 }
1560
1561
1562
1563 if (current < size) {
1564 seglist[current] = path.substring(index);
1565 }
1566
1567
1568 for (int i = 0; i < size; i++) {
1569 include[i] = true;
1570 if (seglist[i].equals("..")) {
1571 int remove = i - 1;
1572
1573 while (remove > -1 && !include[remove]) {
1574 remove--;
1575 }
1576
1577
1578 if (remove > -1 && !seglist[remove].equals("..")) {
1579 include[remove] = false;
1580 include[i] = false;
1581 }
1582 } else if (seglist[i].equals(".")) {
1583 include[i] = false;
1584 }
1585 }
1586
1587
1588 StringBuilder newpath = new StringBuilder();
1589 if (path.startsWith("/")) {
1590 newpath.append('/');
1591 }
1592
1593 for (int i = 0; i < seglist.length; i++) {
1594 if (include[i]) {
1595 newpath.append(seglist[i]);
1596 newpath.append('/');
1597 }
1598 }
1599
1600
1601
1602
1603 if (!path.endsWith("/") && seglist.length > 0
1604 && include[seglist.length - 1]) {
1605 newpath.deleteCharAt(newpath.length() - 1);
1606 }
1607
1608 String result = newpath.toString();
1609
1610
1611
1612 index = result.indexOf(':');
1613 index2 = result.indexOf('/');
1614 if (index != -1 && (index < index2 || index2 == -1)) {
1615 newpath.insert(0, "./");
1616 result = newpath.toString();
1617 }
1618 return result;
1619 }
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631 public Uri parseServerAuthority() throws URISyntaxException {
1632 if (!serverAuthority) {
1633 UriParser p = new UriParser();
1634 p.parseURI(this.toString(), false);
1635 p.parseAuthority(true);
1636 return new Uri(p);
1637 }
1638 return this;
1639 }
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649 public Uri relativize(Uri relative) {
1650 if (relative.opaque || opaque) {
1651 return relative;
1652 }
1653
1654 if (scheme == null ? relative.scheme != null : !scheme
1655 .equals(relative.scheme)) {
1656 return relative;
1657 }
1658
1659 if (authority == null ? relative.authority != null : !authority
1660 .equals(relative.authority)) {
1661 return relative;
1662 }
1663
1664
1665 String thisPath = normalize(path);
1666 String relativePath = normalize(relative.path);
1667
1668
1669
1670
1671
1672 if (!thisPath.equals(relativePath)) {
1673
1674 if (!thisPath.endsWith("/")) {
1675 thisPath = thisPath + '/';
1676 }
1677
1678
1679
1680
1681
1682 if (!relativePath.startsWith(thisPath)) {
1683 return relative;
1684 }
1685 }
1686
1687 String qry = relative.query;
1688
1689 String pth = relativePath.substring(thisPath.length());
1690 return new Uri( null,
1691 null,
1692 setSchemeSpecificPart(null, pth, qry),
1693 null,
1694 null,
1695 null,
1696 -1,
1697 pth,
1698 qry,
1699 relative.fragment,
1700 false,
1701 false,
1702 false,
1703 -1,
1704 fileSchemeCaseInsensitiveOS);
1705 }
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715 public Uri resolve(Uri relative) {
1716 if (relative.absolute || opaque) {
1717 return relative;
1718 }
1719
1720 if (relative.path.equals("") && relative.scheme == null
1721 && relative.authority == null && relative.query == null
1722 && relative.fragment != null) {
1723
1724
1725
1726
1727 return new Uri( null,
1728 scheme,
1729 schemespecificpart,
1730 authority,
1731 userinfo,
1732 host,
1733 port,
1734 path,
1735 query,
1736 relative.fragment,
1737 opaque,
1738 absolute,
1739 serverAuthority,
1740 hash,
1741 fileSchemeCaseInsensitiveOS);
1742
1743
1744
1745 }
1746
1747 if (relative.authority != null) {
1748
1749
1750
1751 return new Uri( null,
1752 scheme,
1753 relative.schemespecificpart,
1754 relative.authority,
1755 relative.userinfo,
1756 relative.host,
1757 relative.port,
1758 relative.path,
1759 relative.query,
1760 relative.fragment,
1761 relative.opaque,
1762 absolute,
1763 relative.serverAuthority,
1764 relative.hash,
1765 fileSchemeCaseInsensitiveOS);
1766 } else {
1767
1768
1769
1770
1771
1772
1773 int endindex = path.lastIndexOf('/') + 1;
1774 String p = relative.path.startsWith("/")? relative.path:
1775 normalize(path.substring(0, endindex) + relative.path);
1776 return new Uri( null,
1777 scheme,
1778 setSchemeSpecificPart(authority, p, relative.query),
1779 authority,
1780 userinfo,
1781 host,
1782 port,
1783 p,
1784 relative.query,
1785 relative.fragment,
1786 opaque,
1787 absolute,
1788 serverAuthority,
1789 hash,
1790 fileSchemeCaseInsensitiveOS);
1791 }
1792 }
1793
1794
1795
1796
1797
1798 private String setSchemeSpecificPart(String authority,
1799 String path,
1800 String query) {
1801
1802 StringBuilder ssp = new StringBuilder();
1803 if (authority != null) {
1804 ssp.append("//"); //$NON-NLS-1$
1805 ssp.append(authority);
1806 }
1807 if (path != null) {
1808 ssp.append(path);
1809 }
1810 if (query != null) {
1811 ssp.append("?");
1812 ssp.append(query);
1813 }
1814
1815 return ssp.toString();
1816 }
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828 public Uri resolve(String relative) {
1829 return resolve(create(relative));
1830 }
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842 private String encodeOthers(String s) {
1843 try {
1844
1845
1846
1847
1848
1849
1850 return URIEncoderDecoder.encodeOthers(s);
1851 } catch (UnsupportedEncodingException e) {
1852 throw new RuntimeException(e.toString());
1853 }
1854 }
1855
1856 private String decode(String s) {
1857 if (s == null) {
1858 return s;
1859 }
1860
1861 try {
1862 return URIEncoderDecoder.decode(s);
1863 } catch (UnsupportedEncodingException e) {
1864 throw new RuntimeException(e.toString());
1865 }
1866 }
1867
1868
1869
1870
1871
1872
1873
1874 public String toASCIIString() {
1875 return encodeOthers(toString());
1876 }
1877
1878
1879
1880
1881
1882
1883 @Override
1884 public String toString() {
1885 return string;
1886 }
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896 private String getHashString() {
1897 StringBuilder result = new StringBuilder();
1898 if (scheme != null) {
1899 result.append(toAsciiLowerCase(scheme));
1900 result.append(':');
1901 }
1902 if (opaque) {
1903 result.append(schemespecificpart);
1904 } else {
1905 if (authority != null) {
1906 result.append("//"); //$NON-NLS-1$
1907 if (host == null) {
1908 result.append(authority);
1909 } else {
1910 if (userinfo != null) {
1911 result.append(userinfo);
1912 result.append("@");
1913 }
1914 result.append(toAsciiLowerCase(host));
1915 if (port != -1) {
1916 result.append(":");
1917 result.append(port);
1918 }
1919 }
1920 }
1921
1922 if (path != null) {
1923 if (fileSchemeCaseInsensitiveOS){
1924 result.append(toAsciiUpperCase(path));
1925 } else {
1926 result.append(path);
1927 }
1928 }
1929
1930 if (query != null) {
1931 result.append('?');
1932 result.append(query);
1933 }
1934 }
1935
1936 if (fragment != null) {
1937 result.append('#');
1938 result.append(fragment);
1939 }
1940
1941 return convertHexToUpperCase(result.toString());
1942 }
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952 public URL toURL() throws MalformedURLException {
1953 if (!absolute) {
1954 throw new IllegalArgumentException(Messages.getString("luni.91") + ": "
1955 + toString());
1956 }
1957 return new URL(toString());
1958 }
1959 }