| OLD | NEW |
| (Empty) |
| 1 part of dart.core; | |
| 2 class Uri {final String _host; | |
| 3 num _port; | |
| 4 String _path; | |
| 5 final String scheme; | |
| 6 String get authority { | |
| 7 if (!hasAuthority) return ""; | |
| 8 var sb = new StringBuffer(); | |
| 9 _writeAuthority(sb); | |
| 10 return sb.toString(); | |
| 11 } | |
| 12 final String _userInfo; | |
| 13 String get userInfo => _userInfo; | |
| 14 String get host { | |
| 15 if (_host == null) return ""; | |
| 16 if (_host.startsWith('[')) { | |
| 17 return _host.substring(1, _host.length - 1); | |
| 18 } | |
| 19 return _host; | |
| 20 } | |
| 21 int get port { | |
| 22 if (_port == null) return _defaultPort(scheme); | |
| 23 return DEVC$RT.cast(_port, num, int, "ImplicitCast", """line 94, column 12 of
dart:core/uri.dart: """, _port is int, true); | |
| 24 } | |
| 25 static int _defaultPort(String scheme) { | |
| 26 if (scheme == "http") return 80; | |
| 27 if (scheme == "https") return 443; | |
| 28 return 0; | |
| 29 } | |
| 30 String get path => _path; | |
| 31 final String _query; | |
| 32 String get query => (_query == null) ? "" : _query; | |
| 33 final String _fragment; | |
| 34 String get fragment => (_fragment == null) ? "" : _fragment; | |
| 35 List<String> _pathSegments; | |
| 36 Map<String, String> _queryParameters; | |
| 37 static Uri parse(String uri) { | |
| 38 bool isRegName(int ch) { | |
| 39 return ch < 128 && ((_regNameTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | |
| 40 } | |
| 41 const int EOI = -1; | |
| 42 String scheme = ""; | |
| 43 String userinfo = ""; | |
| 44 String host = null; | |
| 45 num port = null; | |
| 46 String path = null; | |
| 47 String query = null; | |
| 48 String fragment = null; | |
| 49 int index = 0; | |
| 50 int pathStart = 0; | |
| 51 int char = EOI; | |
| 52 void parseAuth() { | |
| 53 if (index == uri.length) { | |
| 54 char = EOI; | |
| 55 return;} | |
| 56 int authStart = index; | |
| 57 int lastColon = -1; | |
| 58 int lastAt = -1; | |
| 59 char = uri.codeUnitAt(index); | |
| 60 while (index < uri.length) { | |
| 61 char = uri.codeUnitAt(index); | |
| 62 if (char == _SLASH || char == _QUESTION || char == _NUMBER_SIGN) { | |
| 63 break; | |
| 64 } | |
| 65 if (char == _AT_SIGN) { | |
| 66 lastAt = index; | |
| 67 lastColon = -1; | |
| 68 } | |
| 69 else if (char == _COLON) { | |
| 70 lastColon = index; | |
| 71 } | |
| 72 else if (char == _LEFT_BRACKET) { | |
| 73 lastColon = -1; | |
| 74 int endBracket = uri.indexOf(']', index + 1); | |
| 75 if (endBracket == -1) { | |
| 76 index = uri.length; | |
| 77 char = EOI; | |
| 78 break; | |
| 79 } | |
| 80 else { | |
| 81 index = endBracket; | |
| 82 } | |
| 83 } | |
| 84 index++; | |
| 85 char = EOI; | |
| 86 } | |
| 87 int hostStart = authStart; | |
| 88 int hostEnd = index; | |
| 89 if (lastAt >= 0) { | |
| 90 userinfo = _makeUserInfo(uri, authStart, lastAt); | |
| 91 hostStart = lastAt + 1; | |
| 92 } | |
| 93 if (lastColon >= 0) { | |
| 94 int portNumber; | |
| 95 if (lastColon + 1 < index) { | |
| 96 portNumber = 0; | |
| 97 for (int i = lastColon + 1; i < index; i++) { | |
| 98 int digit = uri.codeUnitAt(i); | |
| 99 if (_ZERO > digit || _NINE < digit) { | |
| 100 _fail(uri, i, "Invalid port number"); | |
| 101 } | |
| 102 portNumber = portNumber * 10 + (digit - _ZERO); | |
| 103 } | |
| 104 } | |
| 105 port = _makePort(portNumber, scheme); | |
| 106 hostEnd = lastColon; | |
| 107 } | |
| 108 host = _makeHost(uri, hostStart, hostEnd, true); | |
| 109 if (index < uri.length) { | |
| 110 char = uri.codeUnitAt(index); | |
| 111 } | |
| 112 } | |
| 113 const int NOT_IN_PATH = 0; | |
| 114 const int IN_PATH = 1; | |
| 115 const int ALLOW_AUTH = 2; | |
| 116 int state = NOT_IN_PATH; | |
| 117 int i = index; | |
| 118 while (i < uri.length) { | |
| 119 char = uri.codeUnitAt(i); | |
| 120 if (char == _QUESTION || char == _NUMBER_SIGN) { | |
| 121 state = NOT_IN_PATH; | |
| 122 break; | |
| 123 } | |
| 124 if (char == _SLASH) { | |
| 125 state = (i == 0) ? ALLOW_AUTH : IN_PATH; | |
| 126 break; | |
| 127 } | |
| 128 if (char == _COLON) { | |
| 129 if (i == 0) _fail(uri, 0, "Invalid empty scheme"); | |
| 130 scheme = _makeScheme(uri, i); | |
| 131 i++; | |
| 132 pathStart = i; | |
| 133 if (i == uri.length) { | |
| 134 char = EOI; | |
| 135 state = NOT_IN_PATH; | |
| 136 } | |
| 137 else { | |
| 138 char = uri.codeUnitAt(i); | |
| 139 if (char == _QUESTION || char == _NUMBER_SIGN) { | |
| 140 state = NOT_IN_PATH; | |
| 141 } | |
| 142 else if (char == _SLASH) { | |
| 143 state = ALLOW_AUTH; | |
| 144 } | |
| 145 else { | |
| 146 state = IN_PATH; | |
| 147 } | |
| 148 } | |
| 149 break; | |
| 150 } | |
| 151 i++; | |
| 152 char = EOI; | |
| 153 } | |
| 154 index = i; | |
| 155 if (state == ALLOW_AUTH) { | |
| 156 assert (char == _SLASH); index++; | |
| 157 if (index == uri.length) { | |
| 158 char = EOI; | |
| 159 state = NOT_IN_PATH; | |
| 160 } | |
| 161 else { | |
| 162 char = uri.codeUnitAt(index); | |
| 163 if (char == _SLASH) { | |
| 164 index++; | |
| 165 parseAuth(); | |
| 166 pathStart = index; | |
| 167 } | |
| 168 if (char == _QUESTION || char == _NUMBER_SIGN || char == EOI) { | |
| 169 state = NOT_IN_PATH; | |
| 170 } | |
| 171 else { | |
| 172 state = IN_PATH; | |
| 173 } | |
| 174 } | |
| 175 } | |
| 176 assert (state == IN_PATH || state == NOT_IN_PATH); if (state == IN_PATH) { | |
| 177 while (++index < uri.length) { | |
| 178 char = uri.codeUnitAt(index); | |
| 179 if (char == _QUESTION || char == _NUMBER_SIGN) { | |
| 180 break; | |
| 181 } | |
| 182 char = EOI; | |
| 183 } | |
| 184 state = NOT_IN_PATH; | |
| 185 } | |
| 186 assert (state == NOT_IN_PATH); bool isFile = (scheme == "file"); | |
| 187 bool ensureLeadingSlash = host != null; | |
| 188 path = _makePath(uri, pathStart, index, null, ensureLeadingSlash, isFile); | |
| 189 if (char == _QUESTION) { | |
| 190 int numberSignIndex = uri.indexOf('#', index + 1); | |
| 191 if (numberSignIndex < 0) { | |
| 192 query = _makeQuery(uri, index + 1, uri.length, null); | |
| 193 } | |
| 194 else { | |
| 195 query = _makeQuery(uri, index + 1, numberSignIndex, null); | |
| 196 fragment = _makeFragment(uri, numberSignIndex + 1, uri.length); | |
| 197 } | |
| 198 } | |
| 199 else if (char == _NUMBER_SIGN) { | |
| 200 fragment = _makeFragment(uri, index + 1, uri.length); | |
| 201 } | |
| 202 return new Uri._internal(scheme, userinfo, host, port, path, query, fragment)
; | |
| 203 } | |
| 204 static void _fail(String uri, int index, String message) { | |
| 205 throw new FormatException(message, uri, index); | |
| 206 } | |
| 207 Uri._internal(this.scheme, this._userInfo, this._host, this._port, this._path,
this._query, this._fragment); | |
| 208 factory Uri({ | |
| 209 String scheme : "", String userInfo : "", String host, int port, String path,
Iterable<String> pathSegments, String query, Map<String, String> queryParameters
, String fragment} | |
| 210 ) { | |
| 211 scheme = _makeScheme(scheme, _stringOrNullLength(scheme)); | |
| 212 userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo)); | |
| 213 host = _makeHost(host, 0, _stringOrNullLength(host), false); | |
| 214 if (query == "") query = null; | |
| 215 query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters); | |
| 216 fragment = _makeFragment(fragment, 0, _stringOrNullLength(fragment)); | |
| 217 port = _makePort(port, scheme); | |
| 218 bool isFile = (scheme == "file"); | |
| 219 if (host == null && (userInfo.isNotEmpty || port != null || isFile)) { | |
| 220 host = ""; | |
| 221 } | |
| 222 bool ensureLeadingSlash = host != null; | |
| 223 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, ensureLead
ingSlash, isFile); | |
| 224 return new Uri._internal(scheme, userInfo, host, port, path, query, fragment)
; | |
| 225 } | |
| 226 factory Uri.http(String authority, String unencodedPath, [Map<String, String> q
ueryParameters]) { | |
| 227 return _makeHttpUri("http", authority, unencodedPath, queryParameters); | |
| 228 } | |
| 229 factory Uri.https(String authority, String unencodedPath, [Map<String, String>
queryParameters]) { | |
| 230 return _makeHttpUri("https", authority, unencodedPath, queryParameters); | |
| 231 } | |
| 232 static Uri _makeHttpUri(String scheme, String authority, String unencodedPath,
Map<String, String> queryParameters) { | |
| 233 var userInfo = ""; | |
| 234 var host = null; | |
| 235 var port = null; | |
| 236 if (authority != null && authority.isNotEmpty) { | |
| 237 var hostStart = 0; | |
| 238 bool hasUserInfo = false; | |
| 239 for (int i = 0; i < authority.length; i++) { | |
| 240 if (authority.codeUnitAt(i) == _AT_SIGN) { | |
| 241 hasUserInfo = true; | |
| 242 userInfo = authority.substring(0, i); | |
| 243 hostStart = i + 1; | |
| 244 break; | |
| 245 } | |
| 246 } | |
| 247 var hostEnd = hostStart; | |
| 248 if (hostStart < authority.length && authority.codeUnitAt(hostStart) == _LEF
T_BRACKET) { | |
| 249 for (; hostEnd < authority.length; hostEnd++) { | |
| 250 if (authority.codeUnitAt(hostEnd) == _RIGHT_BRACKET) break; | |
| 251 } | |
| 252 if (hostEnd == authority.length) { | |
| 253 throw new FormatException("Invalid IPv6 host entry.", authority, hostSta
rt); | |
| 254 } | |
| 255 parseIPv6Address(authority, hostStart + 1, hostEnd); | |
| 256 hostEnd++; | |
| 257 if (hostEnd != authority.length && authority.codeUnitAt(hostEnd) != _COLO
N) { | |
| 258 throw new FormatException("Invalid end of authority", authority, hostEnd
); | |
| 259 } | |
| 260 } | |
| 261 bool hasPort = false; | |
| 262 for (; hostEnd < authority.length; hostEnd++) { | |
| 263 if (authority.codeUnitAt(hostEnd) == _COLON) { | |
| 264 var portString = authority.substring(hostEnd + 1); | |
| 265 if (portString.isNotEmpty) port = int.parse(portString); | |
| 266 break; | |
| 267 } | |
| 268 } | |
| 269 host = authority.substring(hostStart, hostEnd); | |
| 270 } | |
| 271 return new Uri(scheme: scheme, userInfo: userInfo, host: DEVC$RT.cast(host, d
ynamic, String, "DynamicCast", """line 609, column 26 of dart:core/uri.dart: """
, host is String, true), port: DEVC$RT.cast(port, dynamic, int, "DynamicCast", "
""line 610, column 26 of dart:core/uri.dart: """, port is int, true), pathSegmen
ts: unencodedPath.split("/"), queryParameters: queryParameters); | |
| 272 } | |
| 273 factory Uri.file(String path, { | |
| 274 bool windows} | |
| 275 ) { | |
| 276 windows = windows == null ? Uri._isWindows : windows; | |
| 277 return windows ? ((__x21) => DEVC$RT.cast(__x21, dynamic, Uri, "DynamicCast",
"""line 698, column 22 of dart:core/uri.dart: """, __x21 is Uri, true))(_makeWi
ndowsFileUrl(path)) : ((__x22) => DEVC$RT.cast(__x22, dynamic, Uri, "DynamicCast
", """line 698, column 50 of dart:core/uri.dart: """, __x22 is Uri, true))(_make
FileUri(path)); | |
| 278 } | |
| 279 external static Uri get base; | |
| 280 external static bool get _isWindows; | |
| 281 static _checkNonWindowsPathReservedCharacters(List<String> segments, bool argum
entError) { | |
| 282 segments.forEach((segment) { | |
| 283 if (segment.contains("/")) { | |
| 284 if (argumentError) { | |
| 285 throw new ArgumentError("Illegal path character $segment"); | |
| 286 } | |
| 287 else { | |
| 288 throw new UnsupportedError("Illegal path character $segment"); | |
| 289 } | |
| 290 } | |
| 291 } | |
| 292 ); | |
| 293 } | |
| 294 static _checkWindowsPathReservedCharacters(List<String> segments, bool argument
Error, [int firstSegment = 0]) { | |
| 295 segments.skip(firstSegment).forEach((segment) { | |
| 296 if (segment.contains(new RegExp(r'["*/:<>?\\|]'))) { | |
| 297 if (argumentError) { | |
| 298 throw new ArgumentError("Illegal character in path"); | |
| 299 } | |
| 300 else { | |
| 301 throw new UnsupportedError("Illegal character in path"); | |
| 302 } | |
| 303 } | |
| 304 } | |
| 305 ); | |
| 306 } | |
| 307 static _checkWindowsDriveLetter(int charCode, bool argumentError) { | |
| 308 if ((_UPPER_CASE_A <= charCode && charCode <= _UPPER_CASE_Z) || (_LOWER_CASE_A
<= charCode && charCode <= _LOWER_CASE_Z)) { | |
| 309 return;} | |
| 310 if (argumentError) { | |
| 311 throw new ArgumentError("Illegal drive letter " + new String.fromCharCode(ch
arCode)); | |
| 312 } | |
| 313 else { | |
| 314 throw new UnsupportedError("Illegal drive letter " + new String.fromCharCode
(charCode)); | |
| 315 } | |
| 316 } | |
| 317 static _makeFileUri(String path) { | |
| 318 String sep = "/"; | |
| 319 if (path.startsWith(sep)) { | |
| 320 return new Uri(scheme: "file", pathSegments: path.split(sep)); | |
| 321 } | |
| 322 else { | |
| 323 return new Uri(pathSegments: path.split(sep)); | |
| 324 } | |
| 325 } | |
| 326 static _makeWindowsFileUrl(String path) { | |
| 327 if (path.startsWith("\\\\?\\")) { | |
| 328 if (path.startsWith("\\\\?\\UNC\\")) { | |
| 329 path = "\\${path.substring(7)}"; | |
| 330 } | |
| 331 else { | |
| 332 path = path.substring(4); | |
| 333 if (path.length < 3 || path.codeUnitAt(1) != _COLON || path.codeUnitAt(2)
!= _BACKSLASH) { | |
| 334 throw new ArgumentError("Windows paths with \\\\?\\ prefix must be absol
ute"); | |
| 335 } | |
| 336 } | |
| 337 } | |
| 338 else { | |
| 339 path = path.replaceAll("/", "\\"); | |
| 340 } | |
| 341 String sep = "\\"; | |
| 342 if (path.length > 1 && path[1] == ":") { | |
| 343 _checkWindowsDriveLetter(path.codeUnitAt(0), true); | |
| 344 if (path.length == 2 || path.codeUnitAt(2) != _BACKSLASH) { | |
| 345 throw new ArgumentError("Windows paths with drive letter must be absolute"
); | |
| 346 } | |
| 347 var pathSegments = path.split(sep); | |
| 348 _checkWindowsPathReservedCharacters(pathSegments, true, 1); | |
| 349 return new Uri(scheme: "file", pathSegments: pathSegments); | |
| 350 } | |
| 351 if (path.length > 0 && path[0] == sep) { | |
| 352 if (path.length > 1 && path[1] == sep) { | |
| 353 int pathStart = path.indexOf("\\", 2); | |
| 354 String hostPart = pathStart == -1 ? path.substring(2) : path.substring(2,
pathStart); | |
| 355 String pathPart = pathStart == -1 ? "" : path.substring(pathStart + 1); | |
| 356 var pathSegments = pathPart.split(sep); | |
| 357 _checkWindowsPathReservedCharacters(pathSegments, true); | |
| 358 return new Uri(scheme: "file", host: hostPart, pathSegments: pathSegments
); | |
| 359 } | |
| 360 else { | |
| 361 var pathSegments = path.split(sep); | |
| 362 _checkWindowsPathReservedCharacters(pathSegments, true); | |
| 363 return new Uri(scheme: "file", pathSegments: pathSegments); | |
| 364 } | |
| 365 } | |
| 366 else { | |
| 367 var pathSegments = path.split(sep); | |
| 368 _checkWindowsPathReservedCharacters(pathSegments, true); | |
| 369 return new Uri(pathSegments: pathSegments); | |
| 370 } | |
| 371 } | |
| 372 Uri replace({ | |
| 373 String scheme, String userInfo, String host, int port, String path, Iterable<S
tring> pathSegments, String query, Map<String, String> queryParameters, String f
ragment} | |
| 374 ) { | |
| 375 bool schemeChanged = false; | |
| 376 if (scheme != null) { | |
| 377 scheme = _makeScheme(scheme, scheme.length); | |
| 378 schemeChanged = true; | |
| 379 } | |
| 380 else { | |
| 381 scheme = this.scheme; | |
| 382 } | |
| 383 bool isFile = (scheme == "file"); | |
| 384 if (userInfo != null) { | |
| 385 userInfo = _makeUserInfo(userInfo, 0, userInfo.length); | |
| 386 } | |
| 387 else { | |
| 388 userInfo = this.userInfo; | |
| 389 } | |
| 390 if (port != null) { | |
| 391 port = _makePort(port, scheme); | |
| 392 } | |
| 393 else { | |
| 394 port = ((__x23) => DEVC$RT.cast(__x23, num, int, "ImplicitCast", """line 889
, column 14 of dart:core/uri.dart: """, __x23 is int, true))(this._port); | |
| 395 if (schemeChanged) { | |
| 396 port = _makePort(port, scheme); | |
| 397 } | |
| 398 } | |
| 399 if (host != null) { | |
| 400 host = _makeHost(host, 0, host.length, false); | |
| 401 } | |
| 402 else if (this.hasAuthority) { | |
| 403 host = this.host; | |
| 404 } | |
| 405 else if (userInfo.isNotEmpty || port != null || isFile) { | |
| 406 host = ""; | |
| 407 } | |
| 408 bool ensureLeadingSlash = (host != null); | |
| 409 if (path != null || pathSegments != null) { | |
| 410 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, ensureLea
dingSlash, isFile); | |
| 411 } | |
| 412 else { | |
| 413 path = this.path; | |
| 414 if ((isFile || (ensureLeadingSlash && !path.isEmpty)) && !path.startsWith('
/')) { | |
| 415 path = "/$path"; | |
| 416 } | |
| 417 } | |
| 418 if (query != null || queryParameters != null) { | |
| 419 query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters); | |
| 420 } | |
| 421 else if (this.hasQuery) { | |
| 422 query = this.query; | |
| 423 } | |
| 424 if (fragment != null) { | |
| 425 fragment = _makeFragment(fragment, 0, fragment.length); | |
| 426 } | |
| 427 else if (this.hasFragment) { | |
| 428 fragment = this.fragment; | |
| 429 } | |
| 430 return new Uri._internal(scheme, userInfo, host, port, path, query, fragment)
; | |
| 431 } | |
| 432 List<String> get pathSegments { | |
| 433 if (_pathSegments == null) { | |
| 434 var pathToSplit = !path.isEmpty && path.codeUnitAt(0) == _SLASH ? path.subst
ring(1) : path; | |
| 435 _pathSegments = new UnmodifiableListView<String>(pathToSplit == "" ? const
<String> [] : new List<String>.from(pathToSplit.split("/").map(Uri.decodeCompone
nt), growable: false)); | |
| 436 } | |
| 437 return _pathSegments; | |
| 438 } | |
| 439 Map<String, String> get queryParameters { | |
| 440 if (_queryParameters == null) { | |
| 441 _queryParameters = new UnmodifiableMapView<String, String>(splitQueryString(
query)); | |
| 442 } | |
| 443 return _queryParameters; | |
| 444 } | |
| 445 static int _makePort(int port, String scheme) { | |
| 446 if (port != null && port == _defaultPort(scheme)) return null; | |
| 447 return port; | |
| 448 } | |
| 449 static String _makeHost(String host, int start, int end, bool strictIPv6) { | |
| 450 if (host == null) return null; | |
| 451 if (start == end) return ""; | |
| 452 if (host.codeUnitAt(start) == _LEFT_BRACKET) { | |
| 453 if (host.codeUnitAt(end - 1) != _RIGHT_BRACKET) { | |
| 454 _fail(host, start, 'Missing end `]` to match `[` in host'); | |
| 455 } | |
| 456 parseIPv6Address(host, start + 1, end - 1); | |
| 457 return host.substring(start, end).toLowerCase(); | |
| 458 } | |
| 459 if (!strictIPv6) { | |
| 460 for (int i = start; i < end; i++) { | |
| 461 if (host.codeUnitAt(i) == _COLON) { | |
| 462 parseIPv6Address(host, start, end); | |
| 463 return '[$host]'; | |
| 464 } | |
| 465 } | |
| 466 } | |
| 467 return _normalizeRegName(host, start, end); | |
| 468 } | |
| 469 static bool _isRegNameChar(int char) { | |
| 470 return char < 127 && (_regNameTable[char >> 4] & (1 << (char & 0xf))) != 0; | |
| 471 } | |
| 472 static String _normalizeRegName(String host, int start, int end) { | |
| 473 StringBuffer buffer; | |
| 474 int sectionStart = start; | |
| 475 int index = start; | |
| 476 bool isNormalized = true; | |
| 477 while (index < end) { | |
| 478 int char = host.codeUnitAt(index); | |
| 479 if (char == _PERCENT) { | |
| 480 String replacement = _normalizeEscape(host, index, true); | |
| 481 if (replacement == null && isNormalized) { | |
| 482 index += 3; | |
| 483 continue; | |
| 484 } | |
| 485 if (buffer == null) buffer = new StringBuffer(); | |
| 486 String slice = host.substring(sectionStart, index); | |
| 487 if (!isNormalized) slice = slice.toLowerCase(); | |
| 488 buffer.write(slice); | |
| 489 int sourceLength = 3; | |
| 490 if (replacement == null) { | |
| 491 replacement = host.substring(index, index + 3); | |
| 492 } | |
| 493 else if (replacement == "%") { | |
| 494 replacement = "%25"; | |
| 495 sourceLength = 1; | |
| 496 } | |
| 497 buffer.write(replacement); | |
| 498 index += sourceLength; | |
| 499 sectionStart = index; | |
| 500 isNormalized = true; | |
| 501 } | |
| 502 else if (_isRegNameChar(char)) { | |
| 503 if (isNormalized && _UPPER_CASE_A <= char && _UPPER_CASE_Z >= char) { | |
| 504 if (buffer == null) buffer = new StringBuffer(); | |
| 505 if (sectionStart < index) { | |
| 506 buffer.write(host.substring(sectionStart, index)); | |
| 507 sectionStart = index; | |
| 508 } | |
| 509 isNormalized = false; | |
| 510 } | |
| 511 index++; | |
| 512 } | |
| 513 else if (_isGeneralDelimiter(char)) { | |
| 514 _fail(host, index, "Invalid character"); | |
| 515 } | |
| 516 else { | |
| 517 int sourceLength = 1; | |
| 518 if ((char & 0xFC00) == 0xD800 && (index + 1) < end) { | |
| 519 int tail = host.codeUnitAt(index + 1); | |
| 520 if ((tail & 0xFC00) == 0xDC00) { | |
| 521 char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff); | |
| 522 sourceLength = 2; | |
| 523 } | |
| 524 } | |
| 525 if (buffer == null) buffer = new StringBuffer(); | |
| 526 String slice = host.substring(sectionStart, index); | |
| 527 if (!isNormalized) slice = slice.toLowerCase(); | |
| 528 buffer.write(slice); | |
| 529 buffer.write(_escapeChar(char)); | |
| 530 index += sourceLength; | |
| 531 sectionStart = index; | |
| 532 } | |
| 533 } | |
| 534 if (buffer == null) return host.substring(start, end); | |
| 535 if (sectionStart < end) { | |
| 536 String slice = host.substring(sectionStart, end); | |
| 537 if (!isNormalized) slice = slice.toLowerCase(); | |
| 538 buffer.write(slice); | |
| 539 } | |
| 540 return buffer.toString(); | |
| 541 } | |
| 542 static String _makeScheme(String scheme, int end) { | |
| 543 if (end == 0) return ""; | |
| 544 final int firstCodeUnit = scheme.codeUnitAt(0); | |
| 545 if (!_isAlphabeticCharacter(firstCodeUnit)) { | |
| 546 _fail(scheme, 0, "Scheme not starting with alphabetic character"); | |
| 547 } | |
| 548 bool allLowercase = firstCodeUnit >= _LOWER_CASE_A; | |
| 549 for (int i = 0; i < end; i++) { | |
| 550 final int codeUnit = scheme.codeUnitAt(i); | |
| 551 if (!_isSchemeCharacter(codeUnit)) { | |
| 552 _fail(scheme, i, "Illegal scheme character"); | |
| 553 } | |
| 554 if (codeUnit < _LOWER_CASE_A || codeUnit > _LOWER_CASE_Z) { | |
| 555 allLowercase = false; | |
| 556 } | |
| 557 } | |
| 558 scheme = scheme.substring(0, end); | |
| 559 if (!allLowercase) scheme = scheme.toLowerCase(); | |
| 560 return scheme; | |
| 561 } | |
| 562 static String _makeUserInfo(String userInfo, int start, int end) { | |
| 563 if (userInfo == null) return ""; | |
| 564 return _normalize(userInfo, start, end, DEVC$RT.cast(_userinfoTable, DEVC$RT.
type((List<dynamic> _) { | |
| 565 } | |
| 566 ), DEVC$RT.type((List<int> _) { | |
| 567 } | |
| 568 ), "CompositeCast", """line 1127, column 45 of dart:core/uri.dart: """, _useri
nfoTable is List<int>, false)); | |
| 569 } | |
| 570 static String _makePath(String path, int start, int end, Iterable<String> pathS
egments, bool ensureLeadingSlash, bool isFile) { | |
| 571 if (path == null && pathSegments == null) return isFile ? "/" : ""; | |
| 572 if (path != null && pathSegments != null) { | |
| 573 throw new ArgumentError('Both path and pathSegments specified'); | |
| 574 } | |
| 575 var result; | |
| 576 if (path != null) { | |
| 577 result = _normalize(path, start, end, DEVC$RT.cast(_pathCharOrSlashTable, DE
VC$RT.type((List<dynamic> _) { | |
| 578 } | |
| 579 ), DEVC$RT.type((List<int> _) { | |
| 580 } | |
| 581 ), "CompositeCast", """line 1140, column 45 of dart:core/uri.dart: """, _pat
hCharOrSlashTable is List<int>, false)); | |
| 582 } | |
| 583 else { | |
| 584 result = pathSegments.map((s) => _uriEncode(DEVC$RT.cast(_pathCharTable, DEV
C$RT.type((List<dynamic> _) { | |
| 585 } | |
| 586 ), DEVC$RT.type((List<int> _) { | |
| 587 } | |
| 588 ), "CompositeCast", """line 1142, column 51 of dart:core/uri.dart: """, _pat
hCharTable is List<int>, false), DEVC$RT.cast(s, dynamic, String, "DynamicCast",
"""line 1142, column 67 of dart:core/uri.dart: """, s is String, true))).join("
/"); | |
| 589 } | |
| 590 if (result.isEmpty) { | |
| 591 if (isFile) return "/"; | |
| 592 } | |
| 593 else if ((isFile || ensureLeadingSlash) && result.codeUnitAt(0) != _SLASH) { | |
| 594 return "/$result"; | |
| 595 } | |
| 596 return DEVC$RT.cast(result, dynamic, String, "DynamicCast", """line 1150, col
umn 12 of dart:core/uri.dart: """, result is String, true); | |
| 597 } | |
| 598 static String _makeQuery(String query, int start, int end, Map<String, String>
queryParameters) { | |
| 599 if (query == null && queryParameters == null) return null; | |
| 600 if (query != null && queryParameters != null) { | |
| 601 throw new ArgumentError('Both query and queryParameters specified'); | |
| 602 } | |
| 603 if (query != null) return _normalize(query, start, end, DEVC$RT.cast(_queryCh
arTable, DEVC$RT.type((List<dynamic> _) { | |
| 604 } | |
| 605 ), DEVC$RT.type((List<int> _) { | |
| 606 } | |
| 607 ), "CompositeCast", """line 1159, column 61 of dart:core/uri.dart: """, _query
CharTable is List<int>, false)); | |
| 608 var result = new StringBuffer(); | |
| 609 var first = true; | |
| 610 queryParameters.forEach((key, value) { | |
| 611 if (!first) { | |
| 612 result.write("&"); | |
| 613 } | |
| 614 first = false; | |
| 615 result.write(Uri.encodeQueryComponent(DEVC$RT.cast(key, dynamic, String, "D
ynamicCast", """line 1168, column 45 of dart:core/uri.dart: """, key is String,
true))); | |
| 616 if (value != null && !value.isEmpty) { | |
| 617 result.write("="); | |
| 618 result.write(Uri.encodeQueryComponent(DEVC$RT.cast(value, dynamic, String
, "DynamicCast", """line 1171, column 47 of dart:core/uri.dart: """, value is St
ring, true))); | |
| 619 } | |
| 620 } | |
| 621 ); | |
| 622 return result.toString(); | |
| 623 } | |
| 624 static String _makeFragment(String fragment, int start, int end) { | |
| 625 if (fragment == null) return null; | |
| 626 return _normalize(fragment, start, end, DEVC$RT.cast(_queryCharTable, DEVC$RT
.type((List<dynamic> _) { | |
| 627 } | |
| 628 ), DEVC$RT.type((List<int> _) { | |
| 629 } | |
| 630 ), "CompositeCast", """line 1179, column 45 of dart:core/uri.dart: """, _query
CharTable is List<int>, false)); | |
| 631 } | |
| 632 static int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; | |
| 633 static bool _isHexDigit(int char) { | |
| 634 if (_NINE >= char) return _ZERO <= char; | |
| 635 char |= 0x20; | |
| 636 return _LOWER_CASE_A <= char && _LOWER_CASE_F >= char; | |
| 637 } | |
| 638 static int _hexValue(int char) { | |
| 639 assert (_isHexDigit(char)); if (_NINE >= char) return char - _ZERO; | |
| 640 char |= 0x20; | |
| 641 return char - (_LOWER_CASE_A - 10); | |
| 642 } | |
| 643 static String _normalizeEscape(String source, int index, bool lowerCase) { | |
| 644 assert (source.codeUnitAt(index) == _PERCENT); if (index + 2 >= source.length)
{ | |
| 645 return "%"; | |
| 646 } | |
| 647 int firstDigit = source.codeUnitAt(index + 1); | |
| 648 int secondDigit = source.codeUnitAt(index + 2); | |
| 649 if (!_isHexDigit(firstDigit) || !_isHexDigit(secondDigit)) { | |
| 650 return "%"; | |
| 651 } | |
| 652 int value = _hexValue(firstDigit) * 16 + _hexValue(secondDigit); | |
| 653 if (_isUnreservedChar(value)) { | |
| 654 if (lowerCase && _UPPER_CASE_A <= value && _UPPER_CASE_Z >= value) { | |
| 655 value |= 0x20; | |
| 656 } | |
| 657 return new String.fromCharCode(value); | |
| 658 } | |
| 659 if (firstDigit >= _LOWER_CASE_A || secondDigit >= _LOWER_CASE_A) { | |
| 660 return source.substring(index, index + 3).toUpperCase(); | |
| 661 } | |
| 662 return null; | |
| 663 } | |
| 664 static bool _isUnreservedChar(int ch) { | |
| 665 return ch < 127 && ((_unreservedTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | |
| 666 } | |
| 667 static String _escapeChar(char) { | |
| 668 assert (char <= 0x10ffff); const hexDigits = "0123456789ABCDEF"; | |
| 669 List codeUnits; | |
| 670 if (char < 0x80) { | |
| 671 codeUnits = new List(3); | |
| 672 codeUnits[0] = _PERCENT; | |
| 673 codeUnits[1] = hexDigits.codeUnitAt(((__x24) => DEVC$RT.cast(__x24, dynamic
, int, "DynamicCast", """line 1249, column 43 of dart:core/uri.dart: """, __x24
is int, true))(char >> 4)); | |
| 674 codeUnits[2] = hexDigits.codeUnitAt(((__x25) => DEVC$RT.cast(__x25, dynamic
, int, "DynamicCast", """line 1250, column 43 of dart:core/uri.dart: """, __x25
is int, true))(char & 0xf)); | |
| 675 } | |
| 676 else { | |
| 677 int flag = 0xc0; | |
| 678 int encodedBytes = 2; | |
| 679 if (char > 0x7ff) { | |
| 680 flag = 0xe0; | |
| 681 encodedBytes = 3; | |
| 682 if (char > 0xffff) { | |
| 683 encodedBytes = 4; | |
| 684 flag = 0xf0; | |
| 685 } | |
| 686 } | |
| 687 codeUnits = new List(3 * encodedBytes); | |
| 688 int index = 0; | |
| 689 while (--encodedBytes >= 0) { | |
| 690 int byte = ((__x26) => DEVC$RT.cast(__x26, dynamic, int, "DynamicCast", ""
"line 1266, column 20 of dart:core/uri.dart: """, __x26 is int, true))(((char >>
(6 * encodedBytes)) & 0x3f) | flag); | |
| 691 codeUnits[index] = _PERCENT; | |
| 692 codeUnits[index + 1] = hexDigits.codeUnitAt(byte >> 4); | |
| 693 codeUnits[index + 2] = hexDigits.codeUnitAt(byte & 0xf); | |
| 694 index += 3; | |
| 695 flag = 0x80; | |
| 696 } | |
| 697 } | |
| 698 return new String.fromCharCodes(DEVC$RT.cast(codeUnits, DEVC$RT.type((List<dy
namic> _) { | |
| 699 } | |
| 700 ), DEVC$RT.type((Iterable<int> _) { | |
| 701 } | |
| 702 ), "CompositeCast", """line 1274, column 37 of dart:core/uri.dart: """, codeUn
its is Iterable<int>, false)); | |
| 703 } | |
| 704 static String _normalize(String component, int start, int end, List<int> charTa
ble) { | |
| 705 StringBuffer buffer; | |
| 706 int sectionStart = start; | |
| 707 int index = start; | |
| 708 while (index < end) { | |
| 709 int char = component.codeUnitAt(index); | |
| 710 if (char < 127 && (charTable[char >> 4] & (1 << (char & 0x0f))) != 0) { | |
| 711 index++; | |
| 712 } | |
| 713 else { | |
| 714 String replacement; | |
| 715 int sourceLength; | |
| 716 if (char == _PERCENT) { | |
| 717 replacement = _normalizeEscape(component, index, false); | |
| 718 if (replacement == null) { | |
| 719 index += 3; | |
| 720 continue; | |
| 721 } | |
| 722 if ("%" == replacement) { | |
| 723 replacement = "%25"; | |
| 724 sourceLength = 1; | |
| 725 } | |
| 726 else { | |
| 727 sourceLength = 3; | |
| 728 } | |
| 729 } | |
| 730 else if (_isGeneralDelimiter(char)) { | |
| 731 _fail(component, index, "Invalid character"); | |
| 732 } | |
| 733 else { | |
| 734 sourceLength = 1; | |
| 735 if ((char & 0xFC00) == 0xD800) { | |
| 736 if (index + 1 < end) { | |
| 737 int tail = component.codeUnitAt(index + 1); | |
| 738 if ((tail & 0xFC00) == 0xDC00) { | |
| 739 sourceLength = 2; | |
| 740 char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff); | |
| 741 } | |
| 742 } | |
| 743 } | |
| 744 replacement = _escapeChar(char); | |
| 745 } | |
| 746 if (buffer == null) buffer = new StringBuffer(); | |
| 747 buffer.write(component.substring(sectionStart, index)); | |
| 748 buffer.write(replacement); | |
| 749 index += sourceLength; | |
| 750 sectionStart = index; | |
| 751 } | |
| 752 } | |
| 753 if (buffer == null) { | |
| 754 return component.substring(start, end); | |
| 755 } | |
| 756 if (sectionStart < end) { | |
| 757 buffer.write(component.substring(sectionStart, end)); | |
| 758 } | |
| 759 return buffer.toString(); | |
| 760 } | |
| 761 static bool _isSchemeCharacter(int ch) { | |
| 762 return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | |
| 763 } | |
| 764 static bool _isGeneralDelimiter(int ch) { | |
| 765 return ch <= _RIGHT_BRACKET && ((_genDelimitersTable[ch >> 4] & (1 << (ch & 0x
0f))) != 0); | |
| 766 } | |
| 767 bool get isAbsolute => scheme != "" && fragment == ""; | |
| 768 String _merge(String base, String reference) { | |
| 769 if (base.isEmpty) return "/$reference"; | |
| 770 int backCount = 0; | |
| 771 int refStart = 0; | |
| 772 while (reference.startsWith("../", refStart)) { | |
| 773 refStart += 3; | |
| 774 backCount++; | |
| 775 } | |
| 776 int baseEnd = base.lastIndexOf('/'); | |
| 777 while (baseEnd > 0 && backCount > 0) { | |
| 778 int newEnd = base.lastIndexOf('/', baseEnd - 1); | |
| 779 if (newEnd < 0) { | |
| 780 break; | |
| 781 } | |
| 782 int delta = baseEnd - newEnd; | |
| 783 if ((delta == 2 || delta == 3) && base.codeUnitAt(newEnd + 1) == _DOT && (d
elta == 2 || base.codeUnitAt(newEnd + 2) == _DOT)) { | |
| 784 break; | |
| 785 } | |
| 786 baseEnd = newEnd; | |
| 787 backCount--; | |
| 788 } | |
| 789 return base.substring(0, baseEnd + 1) + reference.substring(refStart - 3 * ba
ckCount); | |
| 790 } | |
| 791 bool _hasDotSegments(String path) { | |
| 792 if (path.length > 0 && path.codeUnitAt(0) == _DOT) return true; | |
| 793 int index = path.indexOf("/."); | |
| 794 return index != -1; | |
| 795 } | |
| 796 String _removeDotSegments(String path) { | |
| 797 if (!_hasDotSegments(path)) return path; | |
| 798 List<String> output = <String> []; | |
| 799 bool appendSlash = false; | |
| 800 for (String segment in path.split("/")) { | |
| 801 appendSlash = false; | |
| 802 if (segment == "..") { | |
| 803 if (!output.isEmpty && ((output.length != 1) || (output[0] != ""))) output
.removeLast(); | |
| 804 appendSlash = true; | |
| 805 } | |
| 806 else if ("." == segment) { | |
| 807 appendSlash = true; | |
| 808 } | |
| 809 else { | |
| 810 output.add(segment); | |
| 811 } | |
| 812 } | |
| 813 if (appendSlash) output.add(""); | |
| 814 return output.join("/"); | |
| 815 } | |
| 816 Uri resolve(String reference) { | |
| 817 return resolveUri(Uri.parse(reference)); | |
| 818 } | |
| 819 Uri resolveUri(Uri reference) { | |
| 820 String targetScheme; | |
| 821 String targetUserInfo = ""; | |
| 822 String targetHost; | |
| 823 int targetPort; | |
| 824 String targetPath; | |
| 825 String targetQuery; | |
| 826 if (reference.scheme.isNotEmpty) { | |
| 827 targetScheme = reference.scheme; | |
| 828 if (reference.hasAuthority) { | |
| 829 targetUserInfo = reference.userInfo; | |
| 830 targetHost = reference.host; | |
| 831 targetPort = reference.hasPort ? reference.port : null; | |
| 832 } | |
| 833 targetPath = _removeDotSegments(reference.path); | |
| 834 if (reference.hasQuery) { | |
| 835 targetQuery = reference.query; | |
| 836 } | |
| 837 } | |
| 838 else { | |
| 839 targetScheme = this.scheme; | |
| 840 if (reference.hasAuthority) { | |
| 841 targetUserInfo = reference.userInfo; | |
| 842 targetHost = reference.host; | |
| 843 targetPort = _makePort(reference.hasPort ? reference.port : null, targetS
cheme); | |
| 844 targetPath = _removeDotSegments(reference.path); | |
| 845 if (reference.hasQuery) targetQuery = reference.query; | |
| 846 } | |
| 847 else { | |
| 848 if (reference.path == "") { | |
| 849 targetPath = this._path; | |
| 850 if (reference.hasQuery) { | |
| 851 targetQuery = reference.query; | |
| 852 } | |
| 853 else { | |
| 854 targetQuery = this._query; | |
| 855 } | |
| 856 } | |
| 857 else { | |
| 858 if (reference.path.startsWith("/")) { | |
| 859 targetPath = _removeDotSegments(reference.path); | |
| 860 } | |
| 861 else { | |
| 862 targetPath = _removeDotSegments(_merge(this._path, reference.path)); | |
| 863 } | |
| 864 if (reference.hasQuery) targetQuery = reference.query; | |
| 865 } | |
| 866 targetUserInfo = this._userInfo; | |
| 867 targetHost = this._host; | |
| 868 targetPort = ((__x27) => DEVC$RT.cast(__x27, num, int, "ImplicitCast", ""
"line 1490, column 22 of dart:core/uri.dart: """, __x27 is int, true))(this._por
t); | |
| 869 } | |
| 870 } | |
| 871 String fragment = reference.hasFragment ? reference.fragment : null; | |
| 872 return new Uri._internal(targetScheme, targetUserInfo, targetHost, targetPort
, targetPath, targetQuery, fragment); | |
| 873 } | |
| 874 bool get hasAuthority => _host != null; | |
| 875 bool get hasPort => _port != null; | |
| 876 bool get hasQuery => _query != null; | |
| 877 bool get hasFragment => _fragment != null; | |
| 878 String get origin { | |
| 879 if (scheme == "" || _host == null || _host == "") { | |
| 880 throw new StateError("Cannot use origin without a scheme: $this"); | |
| 881 } | |
| 882 if (scheme != "http" && scheme != "https") { | |
| 883 throw new StateError("Origin is only applicable schemes http and https: $thi
s"); | |
| 884 } | |
| 885 if (_port == null) return "$scheme://$_host"; | |
| 886 return "$scheme://$_host:$_port"; | |
| 887 } | |
| 888 String toFilePath({ | |
| 889 bool windows} | |
| 890 ) { | |
| 891 if (scheme != "" && scheme != "file") { | |
| 892 throw new UnsupportedError("Cannot extract a file path from a $scheme URI"); | |
| 893 } | |
| 894 if (query != "") { | |
| 895 throw new UnsupportedError("Cannot extract a file path from a URI with a que
ry component"); | |
| 896 } | |
| 897 if (fragment != "") { | |
| 898 throw new UnsupportedError("Cannot extract a file path from a URI with a fra
gment component"); | |
| 899 } | |
| 900 if (windows == null) windows = _isWindows; | |
| 901 return windows ? _toWindowsFilePath() : _toFilePath(); | |
| 902 } | |
| 903 String _toFilePath() { | |
| 904 if (host != "") { | |
| 905 throw new UnsupportedError("Cannot extract a non-Windows file path from a fi
le URI " "with an authority"); | |
| 906 } | |
| 907 _checkNonWindowsPathReservedCharacters(pathSegments, false); | |
| 908 var result = new StringBuffer(); | |
| 909 if (_isPathAbsolute) result.write("/"); | |
| 910 result.writeAll(pathSegments, "/"); | |
| 911 return result.toString(); | |
| 912 } | |
| 913 String _toWindowsFilePath() { | |
| 914 bool hasDriveLetter = false; | |
| 915 var segments = pathSegments; | |
| 916 if (segments.length > 0 && segments[0].length == 2 && segments[0].codeUnitAt(
1) == _COLON) { | |
| 917 _checkWindowsDriveLetter(segments[0].codeUnitAt(0), false); | |
| 918 _checkWindowsPathReservedCharacters(segments, false, 1); | |
| 919 hasDriveLetter = true; | |
| 920 } | |
| 921 else { | |
| 922 _checkWindowsPathReservedCharacters(segments, false); | |
| 923 } | |
| 924 var result = new StringBuffer(); | |
| 925 if (_isPathAbsolute && !hasDriveLetter) result.write("\\"); | |
| 926 if (host != "") { | |
| 927 result.write("\\"); | |
| 928 result.write(host); | |
| 929 result.write("\\"); | |
| 930 } | |
| 931 result.writeAll(segments, "\\"); | |
| 932 if (hasDriveLetter && segments.length == 1) result.write("\\"); | |
| 933 return result.toString(); | |
| 934 } | |
| 935 bool get _isPathAbsolute { | |
| 936 if (path == null || path.isEmpty) return false; | |
| 937 return path.startsWith('/'); | |
| 938 } | |
| 939 void _writeAuthority(StringSink ss) { | |
| 940 if (_userInfo.isNotEmpty) { | |
| 941 ss.write(_userInfo); | |
| 942 ss.write("@"); | |
| 943 } | |
| 944 if (_host != null) ss.write(_host); | |
| 945 if (_port != null) { | |
| 946 ss.write(":"); | |
| 947 ss.write(_port); | |
| 948 } | |
| 949 } | |
| 950 String toString() { | |
| 951 StringBuffer sb = new StringBuffer(); | |
| 952 _addIfNonEmpty(sb, scheme, scheme, ':'); | |
| 953 if (hasAuthority || path.startsWith("//") || (scheme == "file")) { | |
| 954 sb.write("//"); | |
| 955 _writeAuthority(sb); | |
| 956 } | |
| 957 sb.write(path); | |
| 958 if (_query != null) { | |
| 959 sb..write("?")..write(_query); | |
| 960 } | |
| 961 if (_fragment != null) { | |
| 962 sb..write("#")..write(_fragment); | |
| 963 } | |
| 964 return sb.toString(); | |
| 965 } | |
| 966 bool operator ==(other) { | |
| 967 if (other is! Uri) return false; | |
| 968 Uri uri = DEVC$RT.cast(other, dynamic, Uri, "DynamicCast", """line 1699, colu
mn 15 of dart:core/uri.dart: """, other is Uri, true); | |
| 969 return scheme == uri.scheme && hasAuthority == uri.hasAuthority && userInfo =
= uri.userInfo && host == uri.host && port == uri.port && path == uri.path && ha
sQuery == uri.hasQuery && query == uri.query && hasFragment == uri.hasFragment &
& fragment == uri.fragment; | |
| 970 } | |
| 971 int get hashCode { | |
| 972 int combine(part, current) { | |
| 973 return ((__x28) => DEVC$RT.cast(__x28, dynamic, int, "DynamicCast", """line
1715, column 14 of dart:core/uri.dart: """, __x28 is int, true))((current * 31 +
part.hashCode) & 0x3FFFFFFF); | |
| 974 } | |
| 975 return combine(scheme, combine(userInfo, combine(host, combine(port, combine(
path, combine(query, combine(fragment, 1))))))); | |
| 976 } | |
| 977 static void _addIfNonEmpty(StringBuffer sb, String test, String first, String s
econd) { | |
| 978 if ("" != test) { | |
| 979 sb.write(first); | |
| 980 sb.write(second); | |
| 981 } | |
| 982 } | |
| 983 static String encodeComponent(String component) { | |
| 984 return _uriEncode(DEVC$RT.cast(_unreserved2396Table, DEVC$RT.type((List<dynami
c> _) { | |
| 985 } | |
| 986 ), DEVC$RT.type((List<int> _) { | |
| 987 } | |
| 988 ), "CompositeCast", """line 1750, column 23 of dart:core/uri.dart: """, _unres
erved2396Table is List<int>, false), component); | |
| 989 } | |
| 990 static String encodeQueryComponent(String component, { | |
| 991 Encoding encoding : UTF8} | |
| 992 ) { | |
| 993 return _uriEncode(DEVC$RT.cast(_unreservedTable, DEVC$RT.type((List<dynamic> _
) { | |
| 994 } | |
| 995 ), DEVC$RT.type((List<int> _) { | |
| 996 } | |
| 997 ), "CompositeCast", """line 1789, column 9 of dart:core/uri.dart: """, _unrese
rvedTable is List<int>, false), component, encoding: encoding, spaceToPlus: true
); | |
| 998 } | |
| 999 static String decodeComponent(String encodedComponent) { | |
| 1000 return _uriDecode(encodedComponent); | |
| 1001 } | |
| 1002 static String decodeQueryComponent(String encodedComponent, { | |
| 1003 Encoding encoding : UTF8} | |
| 1004 ) { | |
| 1005 return _uriDecode(encodedComponent, plusToSpace: true, encoding: encoding); | |
| 1006 } | |
| 1007 static String encodeFull(String uri) { | |
| 1008 return _uriEncode(DEVC$RT.cast(_encodeFullTable, DEVC$RT.type((List<dynamic> _
) { | |
| 1009 } | |
| 1010 ), DEVC$RT.type((List<int> _) { | |
| 1011 } | |
| 1012 ), "CompositeCast", """line 1833, column 23 of dart:core/uri.dart: """, _encod
eFullTable is List<int>, false), uri); | |
| 1013 } | |
| 1014 static String decodeFull(String uri) { | |
| 1015 return _uriDecode(uri); | |
| 1016 } | |
| 1017 static Map<String, String> splitQueryString(String query, { | |
| 1018 Encoding encoding : UTF8} | |
| 1019 ) { | |
| 1020 return ((__x29) => DEVC$RT.cast(__x29, dynamic, DEVC$RT.type((Map<String, Stri
ng> _) { | |
| 1021 } | |
| 1022 ), "CompositeCast", """line 1865, column 12 of dart:core/uri.dart: """, __x29
is Map<String, String>, false))(query.split("&").fold({ | |
| 1023 } | |
| 1024 , (map, element) { | |
| 1025 int index = ((__x30) => DEVC$RT.cast(__x30, dynamic, int, "DynamicCast", """
line 1866, column 19 of dart:core/uri.dart: """, __x30 is int, true))(element.in
dexOf("=")); | |
| 1026 if (index == -1) { | |
| 1027 if (element != "") { | |
| 1028 map[decodeQueryComponent(DEVC$RT.cast(element, dynamic, String, "Dynamic
Cast", """line 1869, column 36 of dart:core/uri.dart: """, element is String, tr
ue), encoding: encoding)] = ""; | |
| 1029 } | |
| 1030 } | |
| 1031 else if (index != 0) { | |
| 1032 var key = element.substring(0, index); | |
| 1033 var value = element.substring(index + 1); | |
| 1034 map[Uri.decodeQueryComponent(DEVC$RT.cast(key, dynamic, String, "DynamicC
ast", """line 1874, column 38 of dart:core/uri.dart: """, key is String, true),
encoding: encoding)] = decodeQueryComponent(DEVC$RT.cast(value, dynamic, String,
"DynamicCast", """line 1875, column 34 of dart:core/uri.dart: """, value is Str
ing, true), encoding: encoding); | |
| 1035 } | |
| 1036 return map; | |
| 1037 } | |
| 1038 )); | |
| 1039 } | |
| 1040 static List<int> parseIPv4Address(String host) { | |
| 1041 void error(String msg) { | |
| 1042 throw new FormatException('Illegal IPv4 address, $msg'); | |
| 1043 } | |
| 1044 var bytes = host.split('.'); | |
| 1045 if (bytes.length != 4) { | |
| 1046 error('IPv4 address should contain exactly 4 parts'); | |
| 1047 } | |
| 1048 return ((__x31) => DEVC$RT.cast(__x31, DEVC$RT.type((List<dynamic> _) { | |
| 1049 } | |
| 1050 ), DEVC$RT.type((List<int> _) { | |
| 1051 } | |
| 1052 ), "CompositeCast", """line 1897, column 12 of dart:core/uri.dart: """, __x31
is List<int>, false))(bytes.map((byteString) { | |
| 1053 int byte = int.parse(DEVC$RT.cast(byteString, dynamic, String, "DynamicCast"
, """line 1899, column 32 of dart:core/uri.dart: """, byteString is String, true
)); | |
| 1054 if (byte < 0 || byte > 255) { | |
| 1055 error('each part must be in the range of `0..255`'); | |
| 1056 } | |
| 1057 return byte; | |
| 1058 } | |
| 1059 ).toList()); | |
| 1060 } | |
| 1061 static List<int> parseIPv6Address(String host, [int start = 0, int end]) { | |
| 1062 if (end == null) end = host.length; | |
| 1063 void error(String msg, [position]) { | |
| 1064 throw new FormatException('Illegal IPv6 address, $msg', host, DEVC$RT.cast(p
osition, dynamic, int, "DynamicCast", """line 1934, column 69 of dart:core/uri.d
art: """, position is int, true)); | |
| 1065 } | |
| 1066 int parseHex(int start, int end) { | |
| 1067 if (end - start > 4) { | |
| 1068 error('an IPv6 part can only contain a maximum of 4 hex digits', start); | |
| 1069 } | |
| 1070 int value = int.parse(host.substring(start, end), radix: 16); | |
| 1071 if (value < 0 || value > (1 << 16) - 1) { | |
| 1072 error('each part must be in the range of `0x0..0xFFFF`', start); | |
| 1073 } | |
| 1074 return value; | |
| 1075 } | |
| 1076 if (host.length < 2) error('address is too short'); | |
| 1077 List<int> parts = <int> []; | |
| 1078 bool wildcardSeen = false; | |
| 1079 int partStart = start; | |
| 1080 for (int i = start; i < end; i++) { | |
| 1081 if (host.codeUnitAt(i) == _COLON) { | |
| 1082 if (i == start) { | |
| 1083 i++; | |
| 1084 if (host.codeUnitAt(i) != _COLON) { | |
| 1085 error('invalid start colon.', i); | |
| 1086 } | |
| 1087 partStart = i; | |
| 1088 } | |
| 1089 if (i == partStart) { | |
| 1090 if (wildcardSeen) { | |
| 1091 error('only one wildcard `::` is allowed', i); | |
| 1092 } | |
| 1093 wildcardSeen = true; | |
| 1094 parts.add(-1); | |
| 1095 } | |
| 1096 else { | |
| 1097 parts.add(parseHex(partStart, i)); | |
| 1098 } | |
| 1099 partStart = i + 1; | |
| 1100 } | |
| 1101 } | |
| 1102 if (parts.length == 0) error('too few parts'); | |
| 1103 bool atEnd = (partStart == end); | |
| 1104 bool isLastWildcard = (parts.last == -1); | |
| 1105 if (atEnd && !isLastWildcard) { | |
| 1106 error('expected a part after last `:`', end); | |
| 1107 } | |
| 1108 if (!atEnd) { | |
| 1109 try { | |
| 1110 parts.add(parseHex(partStart, end)); | |
| 1111 } | |
| 1112 catch (e) { | |
| 1113 try { | |
| 1114 List<int> last = parseIPv4Address(host.substring(partStart, end)); | |
| 1115 parts.add(last[0] << 8 | last[1]); | |
| 1116 parts.add(last[2] << 8 | last[3]); | |
| 1117 } | |
| 1118 catch (e) { | |
| 1119 error('invalid end of IPv6 address.', partStart); | |
| 1120 } | |
| 1121 } | |
| 1122 } | |
| 1123 if (wildcardSeen) { | |
| 1124 if (parts.length > 7) { | |
| 1125 error('an address with a wildcard must have less than 7 parts'); | |
| 1126 } | |
| 1127 } | |
| 1128 else if (parts.length != 8) { | |
| 1129 error('an address without a wildcard must contain exactly 8 parts'); | |
| 1130 } | |
| 1131 List bytes = new List<int>(16); | |
| 1132 for (int i = 0, index = 0; i < parts.length; i++) { | |
| 1133 int value = parts[i]; | |
| 1134 if (value == -1) { | |
| 1135 int wildCardLength = 9 - parts.length; | |
| 1136 for (int j = 0; j < wildCardLength; j++) { | |
| 1137 bytes[index] = 0; | |
| 1138 bytes[index + 1] = 0; | |
| 1139 index += 2; | |
| 1140 } | |
| 1141 } | |
| 1142 else { | |
| 1143 bytes[index] = value >> 8; | |
| 1144 bytes[index + 1] = value & 0xff; | |
| 1145 index += 2; | |
| 1146 } | |
| 1147 } | |
| 1148 return DEVC$RT.cast(bytes, DEVC$RT.type((List<dynamic> _) { | |
| 1149 } | |
| 1150 ), DEVC$RT.type((List<int> _) { | |
| 1151 } | |
| 1152 ), "CompositeCast", """line 2019, column 12 of dart:core/uri.dart: """, bytes
is List<int>, false); | |
| 1153 } | |
| 1154 static const int _SPACE = 0x20; | |
| 1155 static const int _DOUBLE_QUOTE = 0x22; | |
| 1156 static const int _NUMBER_SIGN = 0x23; | |
| 1157 static const int _PERCENT = 0x25; | |
| 1158 static const int _ASTERISK = 0x2A; | |
| 1159 static const int _PLUS = 0x2B; | |
| 1160 static const int _DOT = 0x2E; | |
| 1161 static const int _SLASH = 0x2F; | |
| 1162 static const int _ZERO = 0x30; | |
| 1163 static const int _NINE = 0x39; | |
| 1164 static const int _COLON = 0x3A; | |
| 1165 static const int _LESS = 0x3C; | |
| 1166 static const int _GREATER = 0x3E; | |
| 1167 static const int _QUESTION = 0x3F; | |
| 1168 static const int _AT_SIGN = 0x40; | |
| 1169 static const int _UPPER_CASE_A = 0x41; | |
| 1170 static const int _UPPER_CASE_F = 0x46; | |
| 1171 static const int _UPPER_CASE_Z = 0x5A; | |
| 1172 static const int _LEFT_BRACKET = 0x5B; | |
| 1173 static const int _BACKSLASH = 0x5C; | |
| 1174 static const int _RIGHT_BRACKET = 0x5D; | |
| 1175 static const int _LOWER_CASE_A = 0x61; | |
| 1176 static const int _LOWER_CASE_F = 0x66; | |
| 1177 static const int _LOWER_CASE_Z = 0x7A; | |
| 1178 static const int _BAR = 0x7C; | |
| 1179 static String _uriEncode(List<int> canonicalTable, String text, { | |
| 1180 Encoding encoding : UTF8, bool spaceToPlus : false} | |
| 1181 ) { | |
| 1182 byteToHex(byte, buffer) { | |
| 1183 const String hex = '0123456789ABCDEF'; | |
| 1184 buffer.writeCharCode(hex.codeUnitAt(((__x32) => DEVC$RT.cast(__x32, dynamic
, int, "DynamicCast", """line 2060, column 43 of dart:core/uri.dart: """, __x32
is int, true))(byte >> 4))); | |
| 1185 buffer.writeCharCode(hex.codeUnitAt(((__x33) => DEVC$RT.cast(__x33, dynamic
, int, "DynamicCast", """line 2061, column 43 of dart:core/uri.dart: """, __x33
is int, true))(byte & 0x0f))); | |
| 1186 } | |
| 1187 StringBuffer result = new StringBuffer(); | |
| 1188 var bytes = encoding.encode(text); | |
| 1189 for (int i = 0; i < bytes.length; i++) { | |
| 1190 int byte = bytes[i]; | |
| 1191 if (byte < 128 && ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)
) { | |
| 1192 result.writeCharCode(byte); | |
| 1193 } | |
| 1194 else if (spaceToPlus && byte == _SPACE) { | |
| 1195 result.writeCharCode(_PLUS); | |
| 1196 } | |
| 1197 else { | |
| 1198 result.writeCharCode(_PERCENT); | |
| 1199 byteToHex(byte, result); | |
| 1200 } | |
| 1201 } | |
| 1202 return result.toString(); | |
| 1203 } | |
| 1204 static int _hexCharPairToByte(String s, int pos) { | |
| 1205 int byte = 0; | |
| 1206 for (int i = 0; i < 2; i++) { | |
| 1207 var charCode = s.codeUnitAt(pos + i); | |
| 1208 if (0x30 <= charCode && charCode <= 0x39) { | |
| 1209 byte = byte * 16 + charCode - 0x30; | |
| 1210 } | |
| 1211 else { | |
| 1212 charCode |= 0x20; | |
| 1213 if (0x61 <= charCode && charCode <= 0x66) { | |
| 1214 byte = byte * 16 + charCode - 0x57; | |
| 1215 } | |
| 1216 else { | |
| 1217 throw new ArgumentError("Invalid URL encoding"); | |
| 1218 } | |
| 1219 } | |
| 1220 } | |
| 1221 return byte; | |
| 1222 } | |
| 1223 static String _uriDecode(String text, { | |
| 1224 bool plusToSpace : false, Encoding encoding : UTF8} | |
| 1225 ) { | |
| 1226 bool simple = true; | |
| 1227 for (int i = 0; i < text.length && simple; i++) { | |
| 1228 var codeUnit = text.codeUnitAt(i); | |
| 1229 simple = codeUnit != _PERCENT && codeUnit != _PLUS; | |
| 1230 } | |
| 1231 List<int> bytes; | |
| 1232 if (simple) { | |
| 1233 if (encoding == UTF8 || encoding == LATIN1) { | |
| 1234 return text; | |
| 1235 } | |
| 1236 else { | |
| 1237 bytes = text.codeUnits; | |
| 1238 } | |
| 1239 } | |
| 1240 else { | |
| 1241 bytes = new List<int>(); | |
| 1242 for (int i = 0; i < text.length; i++) { | |
| 1243 var codeUnit = text.codeUnitAt(i); | |
| 1244 if (codeUnit > 127) { | |
| 1245 throw new ArgumentError("Illegal percent encoding in URI"); | |
| 1246 } | |
| 1247 if (codeUnit == _PERCENT) { | |
| 1248 if (i + 3 > text.length) { | |
| 1249 throw new ArgumentError('Truncated URI'); | |
| 1250 } | |
| 1251 bytes.add(_hexCharPairToByte(text, i + 1)); | |
| 1252 i += 2; | |
| 1253 } | |
| 1254 else if (plusToSpace && codeUnit == _PLUS) { | |
| 1255 bytes.add(_SPACE); | |
| 1256 } | |
| 1257 else { | |
| 1258 bytes.add(codeUnit); | |
| 1259 } | |
| 1260 } | |
| 1261 } | |
| 1262 return encoding.decode(bytes); | |
| 1263 } | |
| 1264 static bool _isAlphabeticCharacter(int codeUnit) => (codeUnit >= _LOWER_CASE_A
&& codeUnit <= _LOWER_CASE_Z) || (codeUnit >= _UPPER_CASE_A && codeUnit <= _UPPE
R_CASE_Z); | |
| 1265 static const _unreservedTable = const [0x0000, 0x0000, 0x6000, 0x03ff, 0xfffe,
0x87ff, 0xfffe, 0x47ff]; | |
| 1266 static const _unreserved2396Table = const [0x0000, 0x0000, 0x6782, 0x03ff, 0xff
fe, 0x87ff, 0xfffe, 0x47ff]; | |
| 1267 static const _encodeFullTable = const [0x0000, 0x0000, 0xffda, 0xafff, 0xffff,
0x87ff, 0xfffe, 0x47ff]; | |
| 1268 static const _schemeTable = const [0x0000, 0x0000, 0x6800, 0x03ff, 0xfffe, 0x07
ff, 0xfffe, 0x07ff]; | |
| 1269 static const _schemeLowerTable = const [0x0000, 0x0000, 0x6800, 0x03ff, 0x0000,
0x0000, 0xfffe, 0x07ff]; | |
| 1270 static const _subDelimitersTable = const [0x0000, 0x0000, 0x7fd2, 0x2bff, 0xfff
e, 0x87ff, 0xfffe, 0x47ff]; | |
| 1271 static const _genDelimitersTable = const [0x0000, 0x0000, 0x8008, 0x8400, 0x000
1, 0x2800, 0x0000, 0x0000]; | |
| 1272 static const _userinfoTable = const [0x0000, 0x0000, 0x7fd2, 0x2fff, 0xfffe, 0x
87ff, 0xfffe, 0x47ff]; | |
| 1273 static const _regNameTable = const [0x0000, 0x0000, 0x7ff2, 0x2bff, 0xfffe, 0x8
7ff, 0xfffe, 0x47ff]; | |
| 1274 static const _pathCharTable = const [0x0000, 0x0000, 0x7fd2, 0x2fff, 0xffff, 0x
87ff, 0xfffe, 0x47ff]; | |
| 1275 static const _pathCharOrSlashTable = const [0x0000, 0x0000, 0xffd2, 0x2fff, 0xf
fff, 0x87ff, 0xfffe, 0x47ff]; | |
| 1276 static const _queryCharTable = const [0x0000, 0x0000, 0xffd2, 0xafff, 0xffff, 0
x87ff, 0xfffe, 0x47ff]; | |
| 1277 } | |
| OLD | NEW |