| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 class _Path implements Path { | 5 class _Path implements Path { |
| 6 final String _path; | 6 final String _path; |
| 7 final bool isWindowsShare; |
| 7 | 8 |
| 8 _Path(String source) : _path = source; | 9 _Path(String source) : _path = source, isWindowsShare = false; |
| 9 _Path.fromNative(String source) : _path = _clean(source); | |
| 10 | 10 |
| 11 int get hashCode => _path.hashCode; | 11 _Path.fromNative(String source) |
| 12 : _path = _clean(source), isWindowsShare = _isWindowsShare(source); |
| 13 |
| 14 _Path._internal(String this._path, bool this.isWindowsShare); |
| 12 | 15 |
| 13 static String _clean(String source) { | 16 static String _clean(String source) { |
| 14 switch (Platform.operatingSystem) { | 17 if (Platform.operatingSystem == 'windows') return _cleanWindows(source); |
| 15 case 'windows': | 18 return source; |
| 16 return _cleanWindows(source); | |
| 17 default: | |
| 18 return source; | |
| 19 } | |
| 20 } | 19 } |
| 21 | 20 |
| 22 static String _cleanWindows(source) { | 21 static String _cleanWindows(String source) { |
| 23 // Change \ to /. | 22 // Change \ to /. |
| 24 var clean = source.replaceAll('\\', '/'); | 23 var clean = source.replaceAll('\\', '/'); |
| 25 // Add / before intial [Drive letter]: | 24 // Add / before intial [Drive letter]: |
| 26 if (clean.length >= 2 && clean[1] == ':') { | 25 if (clean.length >= 2 && clean[1] == ':') { |
| 27 clean = '/$clean'; | 26 clean = '/$clean'; |
| 28 } | 27 } |
| 28 if (_isWindowsShare(source)) { |
| 29 return clean.substring(1, clean.length); |
| 30 } |
| 29 return clean; | 31 return clean; |
| 30 } | 32 } |
| 31 | 33 |
| 34 static bool _isWindowsShare(String source) { |
| 35 return Platform.operatingSystem == 'windows' && source.startsWith('\\\\'); |
| 36 } |
| 37 |
| 38 int get hashCode => _path.hashCode; |
| 32 bool get isEmpty => _path.isEmpty; | 39 bool get isEmpty => _path.isEmpty; |
| 33 bool get isAbsolute => _path.startsWith('/'); | 40 bool get isAbsolute => _path.startsWith('/'); |
| 34 bool get hasTrailingSeparator => _path.endsWith('/'); | 41 bool get hasTrailingSeparator => _path.endsWith('/'); |
| 35 | 42 |
| 36 String toString() => _path; | 43 String toString() => _path; |
| 37 | 44 |
| 38 Path relativeTo(Path base) { | 45 Path relativeTo(Path base) { |
| 39 // Throws exception if an unimplemented or impossible case is reached. | 46 // Throws exception if an unimplemented or impossible case is reached. |
| 40 // Returns a path "relative" such that | 47 // Returns a path "relative" such that |
| 41 // base.join(relative) == this.canonicalize. | 48 // base.join(relative) == this.canonicalize. |
| 42 // Throws an exception if no such path exists, or the case is not | 49 // Throws an exception if no such path exists, or the case is not |
| 43 // implemented yet. | 50 // implemented yet. |
| 44 var basePath = base.toString(); | 51 var basePath = base.toString(); |
| 45 if (base.isAbsolute && _path.startsWith(basePath)) { | 52 if (base.isAbsolute && _path.startsWith(basePath) && |
| 53 base.isWindowsShare == isWindowsShare) { |
| 46 if (_path == basePath) return new Path('.'); | 54 if (_path == basePath) return new Path('.'); |
| 47 if (base.hasTrailingSeparator) { | 55 if (base.hasTrailingSeparator) { |
| 48 return new Path(_path.substring(basePath.length)); | 56 return new Path(_path.substring(basePath.length)); |
| 49 } | 57 } |
| 50 if (_path[basePath.length] == '/') { | 58 if (_path[basePath.length] == '/') { |
| 51 return new Path(_path.substring(basePath.length + 1)); | 59 return new Path(_path.substring(basePath.length + 1)); |
| 52 } | 60 } |
| 53 } else if (base.isAbsolute && isAbsolute) { | 61 } else if (base.isAbsolute && isAbsolute && |
| 62 base.isWindowsShare == isWindowsShare) { |
| 54 List<String> baseSegments = base.canonicalize().segments(); | 63 List<String> baseSegments = base.canonicalize().segments(); |
| 55 List<String> pathSegments = canonicalize().segments(); | 64 List<String> pathSegments = canonicalize().segments(); |
| 56 int common = 0; | 65 int common = 0; |
| 57 int length = min(pathSegments.length, baseSegments.length); | 66 int length = min(pathSegments.length, baseSegments.length); |
| 58 while (common < length && pathSegments[common] == baseSegments[common]) { | 67 while (common < length && pathSegments[common] == baseSegments[common]) { |
| 59 common++; | 68 common++; |
| 60 } | 69 } |
| 61 final sb = new StringBuffer(); | 70 final sb = new StringBuffer(); |
| 62 | 71 |
| 63 for (int i = common + 1; i < baseSegments.length; i++) { | 72 for (int i = common + 1; i < baseSegments.length; i++) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 83 | 92 |
| 84 Path join(Path further) { | 93 Path join(Path further) { |
| 85 if (further.isAbsolute) { | 94 if (further.isAbsolute) { |
| 86 throw new ArgumentError( | 95 throw new ArgumentError( |
| 87 "Path.join called with absolute Path as argument."); | 96 "Path.join called with absolute Path as argument."); |
| 88 } | 97 } |
| 89 if (isEmpty) { | 98 if (isEmpty) { |
| 90 return further.canonicalize(); | 99 return further.canonicalize(); |
| 91 } | 100 } |
| 92 if (hasTrailingSeparator) { | 101 if (hasTrailingSeparator) { |
| 93 return new Path('$_path${further}').canonicalize(); | 102 var joined = new _Path._internal('$_path${further}', isWindowsShare); |
| 103 return joined.canonicalize(); |
| 94 } | 104 } |
| 95 return new Path('$_path/${further}').canonicalize(); | 105 var joined = new _Path._internal('$_path/${further}', isWindowsShare); |
| 106 return joined.canonicalize(); |
| 96 } | 107 } |
| 97 | 108 |
| 98 // Note: The URI RFC names for these operations are normalize, resolve, and | 109 // Note: The URI RFC names for these operations are normalize, resolve, and |
| 99 // relativize. | 110 // relativize. |
| 100 Path canonicalize() { | 111 Path canonicalize() { |
| 101 if (isCanonical) return this; | 112 if (isCanonical) return this; |
| 102 return makeCanonical(); | 113 return makeCanonical(); |
| 103 } | 114 } |
| 104 | 115 |
| 105 bool get isCanonical { | 116 bool get isCanonical { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 segmentsToJoin.add(''); | 186 segmentsToJoin.add(''); |
| 176 } else { | 187 } else { |
| 177 segmentsToJoin.add('.'); | 188 segmentsToJoin.add('.'); |
| 178 } | 189 } |
| 179 } else { | 190 } else { |
| 180 segmentsToJoin.addAll(newSegs); | 191 segmentsToJoin.addAll(newSegs); |
| 181 if (hasTrailingSeparator) { | 192 if (hasTrailingSeparator) { |
| 182 segmentsToJoin.add(''); | 193 segmentsToJoin.add(''); |
| 183 } | 194 } |
| 184 } | 195 } |
| 185 return new Path(Strings.join(segmentsToJoin, '/')); | 196 return new _Path._internal(Strings.join(segmentsToJoin, '/'), |
| 197 isWindowsShare); |
| 186 } | 198 } |
| 187 | 199 |
| 188 String toNativePath() { | 200 String toNativePath() { |
| 189 if (Platform.operatingSystem == 'windows') { | 201 if (Platform.operatingSystem == 'windows') { |
| 190 String nativePath = _path; | 202 String nativePath = _path; |
| 191 // Drop '/' before a drive letter. | 203 // Drop '/' before a drive letter. |
| 192 if (nativePath.length >= 3 && | 204 if (nativePath.length >= 3 && |
| 193 nativePath.startsWith('/') && | 205 nativePath.startsWith('/') && |
| 194 nativePath[2] == ':') { | 206 nativePath[2] == ':') { |
| 195 nativePath = nativePath.substring(1); | 207 nativePath = nativePath.substring(1); |
| 196 } | 208 } |
| 197 nativePath = nativePath.replaceAll('/', '\\'); | 209 nativePath = nativePath.replaceAll('/', '\\'); |
| 210 if (isWindowsShare) { |
| 211 return '\\$nativePath'; |
| 212 } |
| 198 return nativePath; | 213 return nativePath; |
| 199 } | 214 } |
| 200 return _path; | 215 return _path; |
| 201 } | 216 } |
| 202 | 217 |
| 203 List<String> segments() { | 218 List<String> segments() { |
| 204 List result = _path.split('/'); | 219 List result = _path.split('/'); |
| 205 if (isAbsolute) result.removeRange(0, 1); | 220 if (isAbsolute) result.removeRange(0, 1); |
| 206 if (hasTrailingSeparator) result.removeLast(); | 221 if (hasTrailingSeparator) result.removeLast(); |
| 207 return result; | 222 return result; |
| 208 } | 223 } |
| 209 | 224 |
| 210 Path append(String finalSegment) { | 225 Path append(String finalSegment) { |
| 211 if (isEmpty) { | 226 if (isEmpty) { |
| 212 return new Path(finalSegment); | 227 return new _Path._internal(finalSegment, isWindowsShare); |
| 213 } else if (hasTrailingSeparator) { | 228 } else if (hasTrailingSeparator) { |
| 214 return new Path('$_path$finalSegment'); | 229 return new _Path._internal('$_path$finalSegment', isWindowsShare); |
| 215 } else { | 230 } else { |
| 216 return new Path('$_path/$finalSegment'); | 231 return new _Path._internal('$_path/$finalSegment', isWindowsShare); |
| 217 } | 232 } |
| 218 } | 233 } |
| 219 | 234 |
| 220 String get filenameWithoutExtension { | 235 String get filenameWithoutExtension { |
| 221 var name = filename; | 236 var name = filename; |
| 222 if (name == '.' || name == '..') return name; | 237 if (name == '.' || name == '..') return name; |
| 223 int pos = name.lastIndexOf('.'); | 238 int pos = name.lastIndexOf('.'); |
| 224 return (pos < 0) ? name : name.substring(0, pos); | 239 return (pos < 0) ? name : name.substring(0, pos); |
| 225 } | 240 } |
| 226 | 241 |
| 227 String get extension { | 242 String get extension { |
| 228 var name = filename; | 243 var name = filename; |
| 229 int pos = name.lastIndexOf('.'); | 244 int pos = name.lastIndexOf('.'); |
| 230 return (pos < 0) ? '' : name.substring(pos + 1); | 245 return (pos < 0) ? '' : name.substring(pos + 1); |
| 231 } | 246 } |
| 232 | 247 |
| 233 Path get directoryPath { | 248 Path get directoryPath { |
| 234 int pos = _path.lastIndexOf('/'); | 249 int pos = _path.lastIndexOf('/'); |
| 235 if (pos < 0) return new Path(''); | 250 if (pos < 0) return new Path(''); |
| 236 while (pos > 0 && _path[pos - 1] == '/') --pos; | 251 while (pos > 0 && _path[pos - 1] == '/') --pos; |
| 237 return new Path((pos > 0) ? _path.substring(0, pos) : '/'); | 252 var dirPath = (pos > 0) ? _path.substring(0, pos) : '/'; |
| 253 return new _Path._internal(dirPath, isWindowsShare); |
| 238 } | 254 } |
| 239 | 255 |
| 240 String get filename { | 256 String get filename { |
| 241 int pos = _path.lastIndexOf('/'); | 257 int pos = _path.lastIndexOf('/'); |
| 242 return _path.substring(pos + 1); | 258 return _path.substring(pos + 1); |
| 243 } | 259 } |
| 244 } | 260 } |
| OLD | NEW |