| 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 | 
|---|