Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(892)

Side by Side Diff: sdk/lib/io/path_impl.dart

Issue 23054008: Remove the Path class from dart:io (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Minor fixes Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 part of dart.io; 5 part of dart.io;
6 6
7 class _Path implements Path { 7 class __Path implements _Path {
8 final String _path; 8 final String _path;
9 final bool isWindowsShare; 9 final bool isWindowsShare;
10 10
11 _Path(String source) 11 __Path(String source)
12 : _path = _clean(source), isWindowsShare = _isWindowsShare(source); 12 : _path = _clean(source), isWindowsShare = _isWindowsShare(source);
13 13
14 _Path.raw(String source) : _path = source, isWindowsShare = false; 14 __Path.raw(String source) : _path = source, isWindowsShare = false;
15 15
16 _Path._internal(String this._path, bool this.isWindowsShare); 16 __Path._internal(String this._path, bool this.isWindowsShare);
17 17
18 static String _clean(String source) { 18 static String _clean(String source) {
19 if (Platform.operatingSystem == 'windows') return _cleanWindows(source); 19 if (Platform.operatingSystem == 'windows') return _cleanWindows(source);
20 return source; 20 return source;
21 } 21 }
22 22
23 static String _cleanWindows(String source) { 23 static String _cleanWindows(String source) {
24 // Change \ to /. 24 // Change \ to /.
25 var clean = source.replaceAll('\\', '/'); 25 var clean = source.replaceAll('\\', '/');
26 // Add / before intial [Drive letter]: 26 // Add / before intial [Drive letter]:
(...skipping 10 matching lines...) Expand all
37 return Platform.operatingSystem == 'windows' && source.startsWith('\\\\'); 37 return Platform.operatingSystem == 'windows' && source.startsWith('\\\\');
38 } 38 }
39 39
40 int get hashCode => _path.hashCode; 40 int get hashCode => _path.hashCode;
41 bool get isEmpty => _path.isEmpty; 41 bool get isEmpty => _path.isEmpty;
42 bool get isAbsolute => _path.startsWith('/'); 42 bool get isAbsolute => _path.startsWith('/');
43 bool get hasTrailingSeparator => _path.endsWith('/'); 43 bool get hasTrailingSeparator => _path.endsWith('/');
44 44
45 String toString() => _path; 45 String toString() => _path;
46 46
47 Path relativeTo(Path base) { 47 _Path relativeTo(_Path base) {
48 // Returns a path "relative" such that 48 // Returns a path "relative" such that
49 // base.join(relative) == this.canonicalize. 49 // base.join(relative) == this.canonicalize.
50 // Throws exception if an impossible case is reached. 50 // Throws exception if an impossible case is reached.
51 if (base.isAbsolute != isAbsolute || 51 if (base.isAbsolute != isAbsolute ||
52 base.isWindowsShare != isWindowsShare) { 52 base.isWindowsShare != isWindowsShare) {
53 throw new ArgumentError( 53 throw new ArgumentError(
54 "Invalid case of Path.relativeTo(base):\n" 54 "Invalid case of _Path.relativeTo(base):\n"
55 " Path and base must both be relative, or both absolute.\n" 55 " Path and base must both be relative, or both absolute.\n"
56 " Arguments: $_path.relativeTo($base)"); 56 " Arguments: $_path.relativeTo($base)");
57 } 57 }
58 58
59 var basePath = base.toString(); 59 var basePath = base.toString();
60 // Handle drive letters specially on Windows. 60 // Handle drive letters specially on Windows.
61 if (base.isAbsolute && Platform.operatingSystem == 'windows') { 61 if (base.isAbsolute && Platform.operatingSystem == 'windows') {
62 bool baseHasDrive = 62 bool baseHasDrive =
63 basePath.length >= 4 && basePath[2] == ':' && basePath[3] == '/'; 63 basePath.length >= 4 && basePath[2] == ':' && basePath[3] == '/';
64 bool pathHasDrive = 64 bool pathHasDrive =
65 _path.length >= 4 && _path[2] == ':' && _path[3] == '/'; 65 _path.length >= 4 && _path[2] == ':' && _path[3] == '/';
66 if (baseHasDrive && pathHasDrive) { 66 if (baseHasDrive && pathHasDrive) {
67 int baseDrive = basePath.codeUnitAt(1) | 32; // Convert to uppercase. 67 int baseDrive = basePath.codeUnitAt(1) | 32; // Convert to uppercase.
68 if (baseDrive >= 'a'.codeUnitAt(0) && 68 if (baseDrive >= 'a'.codeUnitAt(0) &&
69 baseDrive <= 'z'.codeUnitAt(0) && 69 baseDrive <= 'z'.codeUnitAt(0) &&
70 baseDrive == (_path.codeUnitAt(1) | 32)) { 70 baseDrive == (_path.codeUnitAt(1) | 32)) {
71 if(basePath[1] != _path[1]) { 71 if(basePath[1] != _path[1]) {
72 // Replace the drive letter in basePath with that from _path. 72 // Replace the drive letter in basePath with that from _path.
73 basePath = '/${_path[1]}:/${basePath.substring(4)}'; 73 basePath = '/${_path[1]}:/${basePath.substring(4)}';
74 base = new Path(basePath); 74 base = new _Path(basePath);
75 } 75 }
76 } else { 76 } else {
77 throw new ArgumentError( 77 throw new ArgumentError(
78 "Invalid case of Path.relativeTo(base):\n" 78 "Invalid case of _Path.relativeTo(base):\n"
79 " Base path and target path are on different Windows drives.\n" 79 " Base path and target path are on different Windows drives.\n"
80 " Arguments: $_path.relativeTo($base)"); 80 " Arguments: $_path.relativeTo($base)");
81 } 81 }
82 } else if (baseHasDrive != pathHasDrive) { 82 } else if (baseHasDrive != pathHasDrive) {
83 throw new ArgumentError( 83 throw new ArgumentError(
84 "Invalid case of Path.relativeTo(base):\n" 84 "Invalid case of _Path.relativeTo(base):\n"
85 " Base path must start with a drive letter if and " 85 " Base path must start with a drive letter if and "
86 "only if target path does.\n" 86 "only if target path does.\n"
87 " Arguments: $_path.relativeTo($base)"); 87 " Arguments: $_path.relativeTo($base)");
88 } 88 }
89 89
90 } 90 }
91 if (_path.startsWith(basePath)) { 91 if (_path.startsWith(basePath)) {
92 if (_path == basePath) return new Path('.'); 92 if (_path == basePath) return new _Path('.');
93 // There must be a '/' at the end of the match, or immediately after. 93 // There must be a '/' at the end of the match, or immediately after.
94 int matchEnd = basePath.length; 94 int matchEnd = basePath.length;
95 if (_path[matchEnd - 1] == '/' || _path[matchEnd] == '/') { 95 if (_path[matchEnd - 1] == '/' || _path[matchEnd] == '/') {
96 // Drop any extra '/' characters at matchEnd 96 // Drop any extra '/' characters at matchEnd
97 while (matchEnd < _path.length && _path[matchEnd] == '/') { 97 while (matchEnd < _path.length && _path[matchEnd] == '/') {
98 matchEnd++; 98 matchEnd++;
99 } 99 }
100 return new Path(_path.substring(matchEnd)).canonicalize(); 100 return new _Path(_path.substring(matchEnd)).canonicalize();
101 } 101 }
102 } 102 }
103 103
104 List<String> baseSegments = base.canonicalize().segments(); 104 List<String> baseSegments = base.canonicalize().segments();
105 List<String> pathSegments = canonicalize().segments(); 105 List<String> pathSegments = canonicalize().segments();
106 if (baseSegments.length == 1 && baseSegments[0] == '.') { 106 if (baseSegments.length == 1 && baseSegments[0] == '.') {
107 baseSegments = []; 107 baseSegments = [];
108 } 108 }
109 if (pathSegments.length == 1 && pathSegments[0] == '.') { 109 if (pathSegments.length == 1 && pathSegments[0] == '.') {
110 pathSegments = []; 110 pathSegments = [];
111 } 111 }
112 int common = 0; 112 int common = 0;
113 int length = min(pathSegments.length, baseSegments.length); 113 int length = min(pathSegments.length, baseSegments.length);
114 while (common < length && pathSegments[common] == baseSegments[common]) { 114 while (common < length && pathSegments[common] == baseSegments[common]) {
115 common++; 115 common++;
116 } 116 }
117 final segments = new List<String>(); 117 final segments = new List<String>();
118 118
119 if (common < baseSegments.length && baseSegments[common] == '..') { 119 if (common < baseSegments.length && baseSegments[common] == '..') {
120 throw new ArgumentError( 120 throw new ArgumentError(
121 "Invalid case of Path.relativeTo(base):\n" 121 "Invalid case of _Path.relativeTo(base):\n"
122 " Base path has more '..'s than path does.\n" 122 " Base path has more '..'s than path does.\n"
123 " Arguments: $_path.relativeTo($base)"); 123 " Arguments: $_path.relativeTo($base)");
124 } 124 }
125 for (int i = common; i < baseSegments.length; i++) { 125 for (int i = common; i < baseSegments.length; i++) {
126 segments.add('..'); 126 segments.add('..');
127 } 127 }
128 for (int i = common; i < pathSegments.length; i++) { 128 for (int i = common; i < pathSegments.length; i++) {
129 segments.add('${pathSegments[i]}'); 129 segments.add('${pathSegments[i]}');
130 } 130 }
131 if (segments.isEmpty) { 131 if (segments.isEmpty) {
132 segments.add('.'); 132 segments.add('.');
133 } 133 }
134 if (hasTrailingSeparator) { 134 if (hasTrailingSeparator) {
135 segments.add(''); 135 segments.add('');
136 } 136 }
137 return new Path(segments.join('/')); 137 return new _Path(segments.join('/'));
138 } 138 }
139 139
140 140
141 Path join(Path further) { 141 _Path join(_Path further) {
142 if (further.isAbsolute) { 142 if (further.isAbsolute) {
143 throw new ArgumentError( 143 throw new ArgumentError(
144 "Path.join called with absolute Path as argument."); 144 "Path.join called with absolute Path as argument.");
145 } 145 }
146 if (isEmpty) { 146 if (isEmpty) {
147 return further.canonicalize(); 147 return further.canonicalize();
148 } 148 }
149 if (hasTrailingSeparator) { 149 if (hasTrailingSeparator) {
150 var joined = new _Path._internal('$_path${further}', isWindowsShare); 150 var joined = new __Path._internal('$_path${further}', isWindowsShare);
151 return joined.canonicalize(); 151 return joined.canonicalize();
152 } 152 }
153 var joined = new _Path._internal('$_path/${further}', isWindowsShare); 153 var joined = new __Path._internal('$_path/${further}', isWindowsShare);
154 return joined.canonicalize(); 154 return joined.canonicalize();
155 } 155 }
156 156
157 // Note: The URI RFC names for canonicalize, join, and relativeTo 157 // Note: The URI RFC names for canonicalize, join, and relativeTo
158 // are normalize, resolve, and relativize. But resolve and relativize 158 // are normalize, resolve, and relativize. But resolve and relativize
159 // drop the last segment of the base path (the filename), on URIs. 159 // drop the last segment of the base path (the filename), on URIs.
160 Path canonicalize() { 160 _Path canonicalize() {
161 if (isCanonical) return this; 161 if (isCanonical) return this;
162 return makeCanonical(); 162 return makeCanonical();
163 } 163 }
164 164
165 bool get isCanonical { 165 bool get isCanonical {
166 // Contains no consecutive path separators. 166 // Contains no consecutive path separators.
167 // Contains no segments that are '.'. 167 // Contains no segments that are '.'.
168 // Absolute paths have no segments that are '..'. 168 // Absolute paths have no segments that are '..'.
169 // All '..' segments of a relative path are at the beginning. 169 // All '..' segments of a relative path are at the beginning.
170 if (isEmpty) return false; // The canonical form of '' is '.'. 170 if (isEmpty) return false; // The canonical form of '' is '.'.
171 if (_path == '.') return true; 171 if (_path == '.') return true;
172 List segs = _path.split('/'); // Don't mask the getter 'segments'. 172 List segs = _path.split('/'); // Don't mask the getter 'segments'.
173 if (segs[0] == '') { // Absolute path 173 if (segs[0] == '') { // Absolute path
174 segs[0] = null; // Faster than removeRange(). 174 segs[0] = null; // Faster than removeRange().
175 } else { // A canonical relative path may start with .. segments. 175 } else { // A canonical relative path may start with .. segments.
176 for (int pos = 0; 176 for (int pos = 0;
177 pos < segs.length && segs[pos] == '..'; 177 pos < segs.length && segs[pos] == '..';
178 ++pos) { 178 ++pos) {
179 segs[pos] = null; 179 segs[pos] = null;
180 } 180 }
181 } 181 }
182 if (segs.last == '') segs.removeLast(); // Path ends with /. 182 if (segs.last == '') segs.removeLast(); // Path ends with /.
183 // No remaining segments can be ., .., or empty. 183 // No remaining segments can be ., .., or empty.
184 return !segs.any((s) => s == '' || s == '.' || s == '..'); 184 return !segs.any((s) => s == '' || s == '.' || s == '..');
185 } 185 }
186 186
187 Path makeCanonical() { 187 _Path makeCanonical() {
188 bool isAbs = isAbsolute; 188 bool isAbs = isAbsolute;
189 List segs = segments(); 189 List segs = segments();
190 String drive; 190 String drive;
191 if (isAbs && 191 if (isAbs &&
192 !segs.isEmpty && 192 !segs.isEmpty &&
193 segs[0].length == 2 && 193 segs[0].length == 2 &&
194 segs[0][1] == ':') { 194 segs[0][1] == ':') {
195 drive = segs[0]; 195 drive = segs[0];
196 segs.removeRange(0, 1); 196 segs.removeRange(0, 1);
197 } 197 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 segmentsToJoin.add(''); 235 segmentsToJoin.add('');
236 } else { 236 } else {
237 segmentsToJoin.add('.'); 237 segmentsToJoin.add('.');
238 } 238 }
239 } else { 239 } else {
240 segmentsToJoin.addAll(newSegs); 240 segmentsToJoin.addAll(newSegs);
241 if (hasTrailingSeparator) { 241 if (hasTrailingSeparator) {
242 segmentsToJoin.add(''); 242 segmentsToJoin.add('');
243 } 243 }
244 } 244 }
245 return new _Path._internal(segmentsToJoin.join('/'), isWindowsShare); 245 return new __Path._internal(segmentsToJoin.join('/'), isWindowsShare);
246 } 246 }
247 247
248 String toNativePath() { 248 String toNativePath() {
249 if (isEmpty) return '.'; 249 if (isEmpty) return '.';
250 if (Platform.operatingSystem == 'windows') { 250 if (Platform.operatingSystem == 'windows') {
251 String nativePath = _path; 251 String nativePath = _path;
252 // Drop '/' before a drive letter. 252 // Drop '/' before a drive letter.
253 if (nativePath.length >= 3 && 253 if (nativePath.length >= 3 &&
254 nativePath.startsWith('/') && 254 nativePath.startsWith('/') &&
255 nativePath[2] == ':') { 255 nativePath[2] == ':') {
256 nativePath = nativePath.substring(1); 256 nativePath = nativePath.substring(1);
257 } 257 }
258 nativePath = nativePath.replaceAll('/', '\\'); 258 nativePath = nativePath.replaceAll('/', '\\');
259 if (isWindowsShare) { 259 if (isWindowsShare) {
260 return '\\$nativePath'; 260 return '\\$nativePath';
261 } 261 }
262 return nativePath; 262 return nativePath;
263 } 263 }
264 return _path; 264 return _path;
265 } 265 }
266 266
267 List<String> segments() { 267 List<String> segments() {
268 List result = _path.split('/'); 268 List result = _path.split('/');
269 if (isAbsolute) result.removeRange(0, 1); 269 if (isAbsolute) result.removeRange(0, 1);
270 if (hasTrailingSeparator) result.removeLast(); 270 if (hasTrailingSeparator) result.removeLast();
271 return result; 271 return result;
272 } 272 }
273 273
274 Path append(String finalSegment) { 274 _Path append(String finalSegment) {
275 if (isEmpty) { 275 if (isEmpty) {
276 return new _Path._internal(finalSegment, isWindowsShare); 276 return new __Path._internal(finalSegment, isWindowsShare);
277 } else if (hasTrailingSeparator) { 277 } else if (hasTrailingSeparator) {
278 return new _Path._internal('$_path$finalSegment', isWindowsShare); 278 return new __Path._internal('$_path$finalSegment', isWindowsShare);
279 } else { 279 } else {
280 return new _Path._internal('$_path/$finalSegment', isWindowsShare); 280 return new __Path._internal('$_path/$finalSegment', isWindowsShare);
281 } 281 }
282 } 282 }
283 283
284 String get filenameWithoutExtension { 284 String get filenameWithoutExtension {
285 var name = filename; 285 var name = filename;
286 if (name == '.' || name == '..') return name; 286 if (name == '.' || name == '..') return name;
287 int pos = name.lastIndexOf('.'); 287 int pos = name.lastIndexOf('.');
288 return (pos < 0) ? name : name.substring(0, pos); 288 return (pos < 0) ? name : name.substring(0, pos);
289 } 289 }
290 290
291 String get extension { 291 String get extension {
292 var name = filename; 292 var name = filename;
293 int pos = name.lastIndexOf('.'); 293 int pos = name.lastIndexOf('.');
294 return (pos < 0) ? '' : name.substring(pos + 1); 294 return (pos < 0) ? '' : name.substring(pos + 1);
295 } 295 }
296 296
297 Path get directoryPath { 297 _Path get directoryPath {
298 int pos = _path.lastIndexOf('/'); 298 int pos = _path.lastIndexOf('/');
299 if (pos < 0) return new Path(''); 299 if (pos < 0) return new _Path('');
300 while (pos > 0 && _path[pos - 1] == '/') --pos; 300 while (pos > 0 && _path[pos - 1] == '/') --pos;
301 var dirPath = (pos > 0) ? _path.substring(0, pos) : '/'; 301 var dirPath = (pos > 0) ? _path.substring(0, pos) : '/';
302 return new _Path._internal(dirPath, isWindowsShare); 302 return new __Path._internal(dirPath, isWindowsShare);
303 } 303 }
304 304
305 String get filename { 305 String get filename {
306 int pos = _path.lastIndexOf('/'); 306 int pos = _path.lastIndexOf('/');
307 return _path.substring(pos + 1); 307 return _path.substring(pos + 1);
308 } 308 }
309 } 309 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698