| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library path.style.windows; | |
| 6 | |
| 7 import '../characters.dart' as chars; | 5 import '../characters.dart' as chars; |
| 8 import '../internal_style.dart'; | 6 import '../internal_style.dart'; |
| 9 import '../parsed_path.dart'; | 7 import '../parsed_path.dart'; |
| 10 import '../utils.dart'; | 8 import '../utils.dart'; |
| 11 | 9 |
| 10 // `0b100000` can be bitwise-ORed with uppercase ASCII letters to get their |
| 11 // lowercase equivalents. |
| 12 const _asciiCaseBit = 0x20; |
| 13 |
| 12 /// The style for Windows paths. | 14 /// The style for Windows paths. |
| 13 class WindowsStyle extends InternalStyle { | 15 class WindowsStyle extends InternalStyle { |
| 14 WindowsStyle(); | 16 WindowsStyle(); |
| 15 | 17 |
| 16 final name = 'windows'; | 18 final name = 'windows'; |
| 17 final separator = '\\'; | 19 final separator = '\\'; |
| 18 final separators = const ['/', '\\']; | 20 final separators = const ['/', '\\']; |
| 19 | 21 |
| 20 // Deprecated properties. | 22 // Deprecated properties. |
| 21 | 23 |
| 22 final separatorPattern = new RegExp(r'[/\\]'); | 24 final separatorPattern = new RegExp(r'[/\\]'); |
| 23 final needsSeparatorPattern = new RegExp(r'[^/\\]$'); | 25 final needsSeparatorPattern = new RegExp(r'[^/\\]$'); |
| 24 final rootPattern = new RegExp(r'^(\\\\[^\\]+\\[^\\/]+|[a-zA-Z]:[/\\])'); | 26 final rootPattern = new RegExp(r'^(\\\\[^\\]+\\[^\\/]+|[a-zA-Z]:[/\\])'); |
| 25 final relativeRootPattern = new RegExp(r"^[/\\](?![/\\])"); | 27 final relativeRootPattern = new RegExp(r"^[/\\](?![/\\])"); |
| 26 | 28 |
| 27 bool containsSeparator(String path) => path.contains('/'); | 29 bool containsSeparator(String path) => path.contains('/'); |
| 28 | 30 |
| 29 bool isSeparator(int codeUnit) => | 31 bool isSeparator(int codeUnit) => |
| 30 codeUnit == chars.SLASH || codeUnit == chars.BACKSLASH; | 32 codeUnit == chars.SLASH || codeUnit == chars.BACKSLASH; |
| 31 | 33 |
| 32 bool needsSeparator(String path) { | 34 bool needsSeparator(String path) { |
| 33 if (path.isEmpty) return false; | 35 if (path.isEmpty) return false; |
| 34 return !isSeparator(path.codeUnitAt(path.length - 1)); | 36 return !isSeparator(path.codeUnitAt(path.length - 1)); |
| 35 } | 37 } |
| 36 | 38 |
| 37 int rootLength(String path) { | 39 int rootLength(String path, {bool withDrive: false}) { |
| 38 if (path.isEmpty) return 0; | 40 if (path.isEmpty) return 0; |
| 39 if (path.codeUnitAt(0) == chars.SLASH) return 1; | 41 if (path.codeUnitAt(0) == chars.SLASH) return 1; |
| 40 if (path.codeUnitAt(0) == chars.BACKSLASH) { | 42 if (path.codeUnitAt(0) == chars.BACKSLASH) { |
| 41 if (path.length < 2 || path.codeUnitAt(1) != chars.BACKSLASH) return 1; | 43 if (path.length < 2 || path.codeUnitAt(1) != chars.BACKSLASH) return 1; |
| 42 // The path is a network share. Search for up to two '\'s, as they are | 44 // The path is a network share. Search for up to two '\'s, as they are |
| 43 // the server and share - and part of the root part. | 45 // the server and share - and part of the root part. |
| 44 var index = path.indexOf('\\', 2); | 46 var index = path.indexOf('\\', 2); |
| 45 if (index > 0) { | 47 if (index > 0) { |
| 46 index = path.indexOf('\\', index + 1); | 48 index = path.indexOf('\\', index + 1); |
| 47 if (index > 0) return index; | 49 if (index > 0) return index; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 69 } | 71 } |
| 70 | 72 |
| 71 String pathFromUri(Uri uri) { | 73 String pathFromUri(Uri uri) { |
| 72 if (uri.scheme != '' && uri.scheme != 'file') { | 74 if (uri.scheme != '' && uri.scheme != 'file') { |
| 73 throw new ArgumentError("Uri $uri must have scheme 'file:'."); | 75 throw new ArgumentError("Uri $uri must have scheme 'file:'."); |
| 74 } | 76 } |
| 75 | 77 |
| 76 var path = uri.path; | 78 var path = uri.path; |
| 77 if (uri.host == '') { | 79 if (uri.host == '') { |
| 78 // Drive-letter paths look like "file:///C:/path/to/file". The | 80 // Drive-letter paths look like "file:///C:/path/to/file". The |
| 79 // replaceFirst removes the extra initial slash. | 81 // replaceFirst removes the extra initial slash. Otherwise, leave the |
| 80 if (path.startsWith('/')) path = path.replaceFirst("/", ""); | 82 // slash to match IE's interpretation of "/foo" as a root-relative path. |
| 83 if (path.length >= 3 && |
| 84 path.startsWith('/') && |
| 85 isDriveLetter(path, 1)) { |
| 86 path = path.replaceFirst("/", ""); |
| 87 } |
| 81 } else { | 88 } else { |
| 82 // Network paths look like "file://hostname/path/to/file". | 89 // Network paths look like "file://hostname/path/to/file". |
| 83 path = '\\\\${uri.host}$path'; | 90 path = '\\\\${uri.host}$path'; |
| 84 } | 91 } |
| 85 return Uri.decodeComponent(path.replaceAll("/", "\\")); | 92 return Uri.decodeComponent(path.replaceAll("/", "\\")); |
| 86 } | 93 } |
| 87 | 94 |
| 88 Uri absolutePathToUri(String path) { | 95 Uri absolutePathToUri(String path) { |
| 89 var parsed = new ParsedPath.parse(path, this); | 96 var parsed = new ParsedPath.parse(path, this); |
| 90 if (parsed.root.startsWith(r'\\')) { | 97 if (parsed.root.startsWith(r'\\')) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 115 } | 122 } |
| 116 | 123 |
| 117 // Get rid of the trailing "\" in "C:\" because the URI constructor will | 124 // Get rid of the trailing "\" in "C:\" because the URI constructor will |
| 118 // add a separator on its own. | 125 // add a separator on its own. |
| 119 parsed.parts.insert( | 126 parsed.parts.insert( |
| 120 0, parsed.root.replaceAll("/", "").replaceAll("\\", "")); | 127 0, parsed.root.replaceAll("/", "").replaceAll("\\", "")); |
| 121 | 128 |
| 122 return new Uri(scheme: 'file', pathSegments: parsed.parts); | 129 return new Uri(scheme: 'file', pathSegments: parsed.parts); |
| 123 } | 130 } |
| 124 } | 131 } |
| 132 |
| 133 bool codeUnitsEqual(int codeUnit1, int codeUnit2) { |
| 134 if (codeUnit1 == codeUnit2) return true; |
| 135 |
| 136 /// Forward slashes and backslashes are equivalent on Windows. |
| 137 if (codeUnit1 == chars.SLASH) return codeUnit2 == chars.BACKSLASH; |
| 138 if (codeUnit1 == chars.BACKSLASH) return codeUnit2 == chars.SLASH; |
| 139 |
| 140 // If this check fails, the code units are definitely different. If it |
| 141 // succeeds *and* either codeUnit is an ASCII letter, they're equivalent. |
| 142 if (codeUnit1 ^ codeUnit2 != _asciiCaseBit) return false; |
| 143 |
| 144 // Now we just need to verify that one of the code units is an ASCII letter. |
| 145 var upperCase1 = codeUnit1 | _asciiCaseBit; |
| 146 return upperCase1 >= chars.LOWER_A && upperCase1 <= chars.LOWER_Z; |
| 147 } |
| 148 |
| 149 bool pathsEqual(String path1, String path2) { |
| 150 if (identical(path1, path2)) return true; |
| 151 if (path1.length != path2.length) return false; |
| 152 for (var i = 0; i < path1.length; i++) { |
| 153 if (!codeUnitsEqual(path1.codeUnitAt(i), path2.codeUnitAt(i))) { |
| 154 return false; |
| 155 } |
| 156 } |
| 157 return true; |
| 158 } |
| 159 |
| 160 int canonicalizeCodeUnit(int codeUnit) { |
| 161 if (codeUnit == chars.SLASH) return chars.BACKSLASH; |
| 162 if (codeUnit < chars.UPPER_A) return codeUnit; |
| 163 if (codeUnit > chars.UPPER_Z) return codeUnit; |
| 164 return codeUnit | _asciiCaseBit; |
| 165 } |
| 166 |
| 167 String canonicalizePart(String part) => part.toLowerCase(); |
| 125 } | 168 } |
| OLD | NEW |