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

Side by Side Diff: pkg/analyzer/lib/src/util/absolute_path.dart

Issue 1511833004: Validate that root paths are absolute and normalized. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 analyzer.src.util.absolute_path; 5 library analyzer.src.util.absolute_path;
6 6
7 /// The class for manipulating absolute paths. 7 /// The class for manipulating absolute, normalized paths.
8 class AbsolutePathContext { 8 class AbsolutePathContext {
9 final String separator; 9 static const int _COLON = 0x3A;
10 static const int _PERIOD = 0x2e;
11 static const int _LOWER_A = 0x61;
12 static const int _LOWER_Z = 0x7A;
13 static const int _UPPER_A = 0x41;
14 static const int _UPPER_Z = 0x5A;
10 15
16 final bool _isWindows;
17 String separator;
11 int _separatorChar; 18 int _separatorChar;
12 19
13 AbsolutePathContext(this.separator) { 20 AbsolutePathContext(this._isWindows) {
14 if (separator.length != 1) { 21 separator = _isWindows ? r'\' : '/';
15 throw new ArgumentError.value(
16 separator, 'separator', 'must be exactly one character long');
17 }
18 _separatorChar = separator.codeUnitAt(0); 22 _separatorChar = separator.codeUnitAt(0);
19 } 23 }
20 24
21 /// Append the given relative [suffix] to the given absolute [parent]. 25 /// Append the given relative [suffix] to the given absolute [parent].
22 /// 26 ///
23 /// context.append('/path/to', 'foo'); // -> '/path/to/foo' 27 /// context.append('/path/to', 'foo'); // -> '/path/to/foo'
24 /// 28 ///
25 /// The given [suffix] cannot be an absolute path or use `..`. 29 /// The given [suffix] cannot be an absolute path or use `..`.
26 String append(String parent, String suffix) { 30 String append(String parent, String suffix) {
27 return '$parent$separator$suffix'; 31 return '$parent$separator$suffix';
(...skipping 20 matching lines...) Expand all
48 /// context.dirname(r'C:\path'); // -> 'C:\' 52 /// context.dirname(r'C:\path'); // -> 'C:\'
49 /// context.dirname(r'C:\'); // -> 'C:\' 53 /// context.dirname(r'C:\'); // -> 'C:\'
50 String dirname(String path) { 54 String dirname(String path) {
51 int firstIndex = path.indexOf(separator); 55 int firstIndex = path.indexOf(separator);
52 int lastIndex = path.lastIndexOf(separator); 56 int lastIndex = path.lastIndexOf(separator);
53 return lastIndex == firstIndex 57 return lastIndex == firstIndex
54 ? path.substring(0, firstIndex + 1) 58 ? path.substring(0, firstIndex + 1)
55 : path.substring(0, lastIndex); 59 : path.substring(0, lastIndex);
56 } 60 }
57 61
62 /// Return `true` if the given [path] is valid.
63 ///
64 /// context.isNormalized('/foo/bar'); // -> true
65 /// context.isNormalized('/foo/bar/../baz'); // -> false
66 bool isValid(String path) {
67 return _isAbsolute(path) && _isNormalized(path);
68 }
69
58 /// Return `true` if [child] is a path beneath [parent], and `false` 70 /// Return `true` if [child] is a path beneath [parent], and `false`
59 /// otherwise. Both the [child] and [parent] paths must be absolute paths. 71 /// otherwise. Both the [child] and [parent] paths must be absolute paths.
60 /// 72 ///
61 /// context.isWithin('/root/path', '/root/path/a'); // -> true 73 /// context.isWithin('/root/path', '/root/path/a'); // -> true
62 /// context.isWithin('/root/path', '/root/other'); // -> false 74 /// context.isWithin('/root/path', '/root/other'); // -> false
63 /// context.isWithin('/root/path', '/root/path'); // -> false 75 /// context.isWithin('/root/path', '/root/path'); // -> false
64 bool isWithin(String parent, String child) { 76 bool isWithin(String parent, String child) {
65 int parentLength = parent.length; 77 int parentLength = parent.length;
66 int childLength = child.length; 78 int childLength = child.length;
67 if (parentLength >= childLength) { 79 if (parentLength >= childLength) {
(...skipping 19 matching lines...) Expand all
87 /// context.relative('/root/path', '/root/path/a/b.dart'); // -> 'a/b.dart ' 99 /// context.relative('/root/path', '/root/path/a/b.dart'); // -> 'a/b.dart '
88 /// context.relative('/root/path', '/root/other.dart'); // -> null 100 /// context.relative('/root/path', '/root/other.dart'); // -> null
89 String suffix(String parent, String child) { 101 String suffix(String parent, String child) {
90 String parentPrefix = parent + separator; 102 String parentPrefix = parent + separator;
91 if (child.startsWith(parentPrefix)) { 103 if (child.startsWith(parentPrefix)) {
92 return child.substring(parentPrefix.length); 104 return child.substring(parentPrefix.length);
93 } 105 }
94 return null; 106 return null;
95 } 107 }
96 108
109 /// Return `true` if the given [path] is absolute.
110 ///
111 /// _isAbsolute('/foo/bar'); // -> true
112 /// _isAbsolute('/'); // -> true
113 /// _isAbsolute('foo/bar'); // -> false
114 /// _isAbsolute('C:\foo\bar'); // -> true
115 /// _isAbsolute('C:\'); // -> true
116 /// _isAbsolute('foo\bar'); // -> false
117 bool _isAbsolute(String path) {
118 if (_isWindows) {
119 return path.length >= 3 &&
120 _isAlphabetic(path.codeUnitAt(0)) &&
121 path.codeUnitAt(1) == _COLON &&
122 path.codeUnitAt(2) == _separatorChar;
123 } else {
124 return path.isNotEmpty && path.codeUnitAt(0) == _separatorChar;
125 }
126 }
127
128
129 /// Return `true` if the given absolute [path] is normalized.
130 ///
131 /// _isAbsolute('/foo/bar'); // -> true
132 /// _isAbsolute('/foo/..bar'); // -> true
133 /// _isAbsolute('/'); // -> true
134 /// _isAbsolute('/foo/bar/../baz'); // -> false
135 /// _isAbsolute('/foo/bar/..'); // -> false
Brian Wilkerson 2015/12/09 22:58:20 Wrong method name in examples.
136 bool _isNormalized(String path) {
137 int periodCount = 0;
138 for (int c in path.codeUnits) {
139 if (c == _PERIOD) {
140 periodCount++;
141 continue;
142 }
143 if (c == _separatorChar) {
144 if (periodCount == 1 || periodCount == 2) {
145 return false;
146 }
147 }
148 periodCount = 0;
149 }
150 return periodCount != 1 && periodCount != 2;
151 }
152
153 /// Returns whether [char] is the code for an ASCII letter (uppercase or
154 /// lowercase).
155 static bool _isAlphabetic(int char) {
156 return char >= _UPPER_A && char <= _UPPER_Z ||
157 char >= _LOWER_A && char <= _LOWER_Z;
158 }
159
97 /// Return `true` if [str] starts with the given [prefix]. 160 /// Return `true` if [str] starts with the given [prefix].
98 /// 161 ///
99 /// The check is done from the end of [prefix], because absolute paths 162 /// The check is done from the end of [prefix], because absolute paths
100 /// usually have the same prefix, e.g. the user's home directory. 163 /// usually have the same prefix, e.g. the user's home directory.
101 static bool _startsWithUnsafe(String str, String prefix) { 164 static bool _startsWithUnsafe(String str, String prefix) {
102 int len = prefix.length; 165 int len = prefix.length;
103 for (int i = len - 1; i >= 0; i--) { 166 for (int i = len - 1; i >= 0; i--) {
104 if (str.codeUnitAt(i) != prefix.codeUnitAt(i)) { 167 if (str.codeUnitAt(i) != prefix.codeUnitAt(i)) {
105 return false; 168 return false;
106 } 169 }
107 } 170 }
108 return true; 171 return true;
109 } 172 }
110 } 173 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/file_system/physical_file_system.dart ('k') | pkg/analyzer/test/src/util/absolute_path_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698