Index: pkg/path/lib/src/style/windows.dart |
diff --git a/pkg/path/lib/src/style/windows.dart b/pkg/path/lib/src/style/windows.dart |
index be9f45fdfabc8ed88f0f5eea7ccd9eab686f7555..2965f1eee9230ae930e02acd11f42f36b2f82b02 100644 |
--- a/pkg/path/lib/src/style/windows.dart |
+++ b/pkg/path/lib/src/style/windows.dart |
@@ -4,8 +4,10 @@ |
library path.style.windows; |
-import '../parsed_path.dart'; |
+import '../characters.dart' as chars; |
import '../internal_style.dart'; |
+import '../parsed_path.dart'; |
+import '../utils.dart'; |
/// The style for Windows paths. |
class WindowsStyle extends InternalStyle { |
@@ -13,11 +15,37 @@ class WindowsStyle extends InternalStyle { |
final name = 'windows'; |
final separator = '\\'; |
+ final separators = const ['/', '\\']; |
+ |
+ // Deprecated properties. |
+ |
final separatorPattern = new RegExp(r'[/\\]'); |
final needsSeparatorPattern = new RegExp(r'[^/\\]$'); |
final rootPattern = new RegExp(r'^(\\\\[^\\]+\\[^\\/]+|[a-zA-Z]:[/\\])'); |
final relativeRootPattern = new RegExp(r"^[/\\](?![/\\])"); |
+ bool containsSeparator(String path) => path.contains('/'); |
+ |
+ bool isSeparator(int codeUnit) => |
+ codeUnit == chars.SLASH || codeUnit == chars.BACKSLASH; |
+ |
+ bool needsSeparator(String path) { |
+ if (path.isEmpty) return false; |
+ return !isSeparator(path.codeUnitAt(path.length - 1)); |
+ } |
+ |
+ String getRoot(String path) { |
+ var root = _getRoot(path); |
+ return root == null ? getRelativeRoot(path) : root; |
+ } |
+ |
+ String getRelativeRoot(String path) { |
+ if (path.isEmpty) return null; |
+ if (!isSeparator(path.codeUnitAt(0))) return null; |
+ if (path.length > 1 && isSeparator(path.codeUnitAt(1))) return null; |
+ return path[0]; |
+ } |
+ |
String pathFromUri(Uri uri) { |
if (uri.scheme != '' && uri.scheme != 'file') { |
throw new ArgumentError("Uri $uri must have scheme 'file:'."); |
@@ -66,9 +94,45 @@ class WindowsStyle extends InternalStyle { |
// Get rid of the trailing "\" in "C:\" because the URI constructor will |
// add a separator on its own. |
- parsed.parts.insert(0, parsed.root.replaceAll(separatorPattern, "")); |
+ parsed.parts.insert(0, |
+ parsed.root.replaceAll("/", "").replaceAll("\\", "")); |
return new Uri(scheme: 'file', pathSegments: parsed.parts); |
} |
} |
+ |
+ // A helper method for [getRoot] that doesn't handle relative roots. |
+ String _getRoot(String path) { |
+ if (path.length < 3) return null; |
+ |
+ // We aren't using a RegExp for this because they're slow (issue 19090). If |
+ // we could, we'd match against r'^(\\\\[^\\]+\\[^\\/]+|[a-zA-Z]:[/\\])'. |
+ |
+ // Try roots like "C:\". |
+ if (isAlphabetic(path.codeUnitAt(0))) { |
+ if (path.codeUnitAt(1) != chars.COLON) return null; |
+ if (!isSeparator(path.codeUnitAt(2))) return null; |
+ return path.substring(0, 3); |
+ } |
+ |
+ // Try roots like "\\server\share". |
+ if (!path.startsWith('\\\\')) return null; |
+ |
+ var start = 2; |
+ // The server is one or more non-"\" characters. |
+ while (start < path.length && path.codeUnitAt(start) != chars.BACKSLASH) { |
+ start++; |
+ } |
+ if (start == 2 || start == path.length) return null; |
+ |
+ // The share is one or more non-"\" characters. |
+ start += 1; |
+ if (path.codeUnitAt(start) == chars.BACKSLASH) return null; |
+ start += 1; |
+ while (start < path.length && path.codeUnitAt(start) != chars.BACKSLASH) { |
+ start++; |
+ } |
+ |
+ return path.substring(0, start); |
+ } |
} |