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 library builtin; | 5 library builtin; |
6 // NOTE: Do not import 'dart:io' in builtin. | 6 // NOTE: Do not import 'dart:io' in builtin. |
7 import 'dart:async'; | |
8 import 'dart:convert'; | |
9 import 'dart:isolate'; | 7 import 'dart:isolate'; |
10 | 8 import 'dart:typed_data'; |
11 | |
12 /* See Dart_LibraryTag in dart_api.h */ | |
13 const Dart_kScriptTag = null; | |
14 const Dart_kImportTag = 0; | |
15 const Dart_kSourceTag = 1; | |
16 const Dart_kCanonicalizeUrl = 2; | |
17 | |
18 // Dart native extension scheme. | |
19 const _DART_EXT = 'dart-ext:'; | |
20 | 9 |
21 // import 'root_library'; happens here from C Code | 10 // import 'root_library'; happens here from C Code |
22 | 11 |
| 12 // Build time flag to enable debug logging of loading code. |
| 13 const _logLoading = false; |
| 14 |
| 15 |
23 // The root library (aka the script) is imported into this library. The | 16 // The root library (aka the script) is imported into this library. The |
24 // standalone embedder uses this to lookup the main entrypoint in the | 17 // standalone embedder uses this to lookup the main entrypoint in the |
25 // root library's namespace. | 18 // root library's namespace. |
26 Function _getMainClosure() => main; | 19 Function _getMainClosure() => main; |
27 | 20 |
28 // A port for communicating with the service isolate for I/O. | |
29 SendPort _loadPort; | |
30 | 21 |
31 const _logBuiltin = false; | 22 // 'print' implementation. |
| 23 // The standalone embedder registers the closurized _print function with the |
| 24 // dart:core library. |
| 25 void _printString(String s) native "Builtin_PrintString"; |
32 | 26 |
33 // Corelib 'print' implementation. | 27 |
34 void _print(arg) { | 28 void _print(arg) { |
35 _Logger._printString(arg.toString()); | 29 _printString(arg.toString()); |
36 } | 30 } |
37 | 31 |
38 class _Logger { | |
39 static void _printString(String s) native "Logger_PrintString"; | |
40 } | |
41 | 32 |
42 _getPrintClosure() => _print; | 33 _getPrintClosure() => _print; |
43 | 34 |
| 35 |
| 36 // Corelib 'Uri.base' implementation. |
| 37 // Uri.base is susceptible to changes in the current working directory. |
44 _getCurrentDirectoryPath() native "Builtin_GetCurrentDirectory"; | 38 _getCurrentDirectoryPath() native "Builtin_GetCurrentDirectory"; |
45 | 39 |
46 // Corelib 'Uri.base' implementation. | 40 |
47 Uri _uriBase() { | 41 Uri _uriBase() { |
48 // We are not using Dircetory.current here to limit the dependency | 42 // We are not using Dircetory.current here to limit the dependency |
49 // on dart:io. This code is the same as: | 43 // on dart:io. This code is the same as: |
50 // return new Uri.file(Directory.current.path + "/"); | 44 // return new Uri.file(Directory.current.path + "/"); |
51 var result = _getCurrentDirectoryPath(); | 45 var result = _getCurrentDirectoryPath(); |
52 return new Uri.file(result + "/"); | 46 return new Uri.file("$result/"); |
53 } | 47 } |
54 | 48 |
| 49 |
55 _getUriBaseClosure() => _uriBase; | 50 _getUriBaseClosure() => _uriBase; |
56 | 51 |
57 | 52 |
58 // Are we running on Windows? | 53 // Asynchronous loading of resources. |
59 var _isWindows; | 54 // The embedder forwards most loading requests to this library. |
60 var _workingWindowsDrivePrefix; | 55 |
61 // The current working directory | 56 // See Dart_LibraryTag in dart_api.h |
| 57 const Dart_kScriptTag = null; |
| 58 const Dart_kImportTag = 0; |
| 59 const Dart_kSourceTag = 1; |
| 60 const Dart_kCanonicalizeUrl = 2; |
| 61 |
| 62 // A port for communicating with the service isolate for I/O. |
| 63 SendPort _loadPort; |
| 64 // Maintain a number of outstanding load requests. Current loading request is |
| 65 // finished once there are no outstanding requests. |
| 66 int _numOutstandingLoadRequests = 0; |
| 67 |
| 68 // The current working directory when the embedder was launched. |
62 var _workingDirectoryUri; | 69 var _workingDirectoryUri; |
63 // The URI that the entry point script was loaded from. Remembered so that | 70 // The URI that the entry point script was loaded from. Remembered so that |
64 // package imports can be resolved relative to it. | 71 // package imports can be resolved relative to it. |
65 var _entryPointScript; | 72 var _entryPointScript; |
66 // The directory to look in to resolve "package:" scheme URIs. | 73 // The directory to look in to resolve "package:" scheme URIs. By detault it is |
67 var _packageRoot; | 74 // the 'packages' directory right next to the script. |
| 75 var _packageRoot = _entryPointScript.resolve('packages/'); |
| 76 |
| 77 // Special handling for Windows paths so that they are compatible with URI |
| 78 // handling. |
| 79 // Embedder sets whether we are running on Windows. |
| 80 var _isWindows; |
| 81 |
| 82 |
| 83 // A class wrapping the load error message in an Error object. |
| 84 class LoadError extends Error { |
| 85 final String message; |
| 86 LoadError(this.message); |
| 87 |
| 88 String toString() => 'Load Error: $message'; |
| 89 } |
| 90 |
| 91 |
| 92 // Native calls provided by the embedder. |
| 93 void _signalDoneLoading() native "Builtin_DoneLoading"; |
| 94 void _loadScriptCallback(int tag, String uri, String libraryUri, Uint8List data) |
| 95 native "Builtin_LoadSource"; |
| 96 void _asyncLoadErrorCallback(uri, libraryUri, error) |
| 97 native "Builtin_AsyncLoadError"; |
| 98 |
68 | 99 |
69 _sanitizeWindowsPath(path) { | 100 _sanitizeWindowsPath(path) { |
70 // For Windows we need to massage the paths a bit according to | 101 // For Windows we need to massage the paths a bit according to |
71 // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx | 102 // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx |
72 // | 103 // |
73 // Convert | 104 // Convert |
74 // C:\one\two\three | 105 // C:\one\two\three |
75 // to | 106 // to |
76 // /C:/one/two/three | 107 // /C:/one/two/three |
77 | 108 |
78 if (_isWindows == false) { | 109 if (_isWindows == false) { |
79 // Do nothing when not running Windows. | 110 // Do nothing when not running Windows. |
80 return path; | 111 return path; |
81 } | 112 } |
82 | 113 |
83 var fixedPath = "${path.replaceAll('\\', '/')}"; | 114 var fixedPath = "${path.replaceAll('\\', '/')}"; |
84 | 115 |
85 if ((path.length > 2) && (path[1] == ':')) { | 116 if ((path.length > 2) && (path[1] == ':')) { |
86 // Path begins with a drive letter. | 117 // Path begins with a drive letter. |
87 return '/$fixedPath'; | 118 return '/$fixedPath'; |
88 } | 119 } |
89 | 120 |
90 return fixedPath; | 121 return fixedPath; |
91 } | 122 } |
92 | 123 |
| 124 |
93 _trimWindowsPath(path) { | 125 _trimWindowsPath(path) { |
94 // Convert /X:/ to X:/. | 126 // Convert /X:/ to X:/. |
95 if (_isWindows == false) { | 127 if (_isWindows == false) { |
96 // Do nothing when not running Windows. | 128 // Do nothing when not running Windows. |
97 return path; | 129 return path; |
98 } | 130 } |
99 if (!path.startsWith('/') || (path.length < 3)) { | 131 if (!path.startsWith('/') || (path.length < 3)) { |
100 return path; | 132 return path; |
101 } | 133 } |
102 // Match '/?:'. | 134 // Match '/?:'. |
103 if ((path[0] == '/') && (path[2] == ':')) { | 135 if ((path[0] == '/') && (path[2] == ':')) { |
104 // Remove leading '/'. | 136 // Remove leading '/'. |
105 return path.substring(1); | 137 return path.substring(1); |
106 } | 138 } |
107 return path; | 139 return path; |
108 } | 140 } |
109 | 141 |
| 142 |
| 143 // Ensure we have a trailing slash character. |
110 _enforceTrailingSlash(uri) { | 144 _enforceTrailingSlash(uri) { |
111 // Ensure we have a trailing slash character. | |
112 if (!uri.endsWith('/')) { | 145 if (!uri.endsWith('/')) { |
113 return '$uri/'; | 146 return '$uri/'; |
114 } | 147 } |
115 return uri; | 148 return uri; |
116 } | 149 } |
117 | 150 |
118 | 151 |
119 _extractDriveLetterPrefix(cwd) { | 152 // Embedder Entrypoint: |
120 if (!_isWindows) { | 153 // The embedder calls this method with the current working directory. |
121 return null; | 154 void _setWorkingDirectory(cwd) { |
| 155 if (_logLoading) { |
| 156 _print('# Setting working directory: $cwd'); |
122 } | 157 } |
123 if (cwd.length > 1 && cwd[1] == ':') { | 158 _workingDirectoryUri = new Uri.directory(cwd); |
124 return '/${cwd[0]}:'; | 159 if (_logLoading) { |
125 } | 160 _print('# Working directory URI: $_workingDirectoryUri'); |
126 return null; | |
127 } | |
128 | |
129 | |
130 void _setWorkingDirectory(cwd) { | |
131 _workingWindowsDrivePrefix = _extractDriveLetterPrefix(cwd); | |
132 cwd = _sanitizeWindowsPath(cwd); | |
133 cwd = _enforceTrailingSlash(cwd); | |
134 _workingDirectoryUri = new Uri(scheme: 'file', path: cwd); | |
135 if (_logBuiltin) { | |
136 _print('# Working Directory: $cwd'); | |
137 } | 161 } |
138 } | 162 } |
139 | 163 |
140 | 164 |
| 165 // Embedder Entrypoint: |
| 166 // The embedder calls this method with a custom package root. |
141 _setPackageRoot(String packageRoot) { | 167 _setPackageRoot(String packageRoot) { |
142 packageRoot = _enforceTrailingSlash(packageRoot); | 168 packageRoot = _enforceTrailingSlash(packageRoot); |
143 if (packageRoot.startsWith('file:') || | 169 if (packageRoot.startsWith('file:') || |
144 packageRoot.startsWith('http:') || | 170 packageRoot.startsWith('http:') || |
145 packageRoot.startsWith('https:')) { | 171 packageRoot.startsWith('https:')) { |
146 _packageRoot = _workingDirectoryUri.resolve(packageRoot); | 172 _packageRoot = _workingDirectoryUri.resolve(packageRoot); |
147 } else { | 173 } else { |
148 packageRoot = _sanitizeWindowsPath(packageRoot); | 174 packageRoot = _sanitizeWindowsPath(packageRoot); |
149 packageRoot = _trimWindowsPath(packageRoot); | 175 packageRoot = _trimWindowsPath(packageRoot); |
150 _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot)); | 176 _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot)); |
151 } | 177 } |
152 if (_logBuiltin) { | 178 if (_logLoading) { |
153 _print('# Package root: $packageRoot -> $_packageRoot'); | 179 _print('# Package root: $packageRoot -> $_packageRoot'); |
154 } | 180 } |
155 } | 181 } |
156 | 182 |
157 | 183 |
158 // Given a uri with a 'package' scheme, return a Uri that is prefixed with | 184 // Given a uri with a 'package' scheme, return a Uri that is prefixed with |
159 // the package root. | 185 // the package root. |
160 Uri _resolvePackageUri(Uri uri) { | 186 Uri _resolvePackageUri(Uri uri) { |
161 if (!uri.host.isEmpty) { | 187 if (!uri.host.isEmpty) { |
162 var path = '${uri.host}${uri.path}'; | 188 var path = '${uri.host}${uri.path}'; |
163 var right = 'package:$path'; | 189 var right = 'package:$path'; |
164 var wrong = 'package://$path'; | 190 var wrong = 'package://$path'; |
165 | 191 |
166 throw "URIs using the 'package:' scheme should look like " | 192 throw "URIs using the 'package:' scheme should look like " |
167 "'$right', not '$wrong'."; | 193 "'$right', not '$wrong'."; |
168 } | 194 } |
169 | 195 |
170 var packageRoot = _packageRoot == null ? | 196 if (_logLoading) { |
171 _entryPointScript.resolve('packages/') : | 197 _print('# Package root: $_packageRoot'); |
172 _packageRoot; | 198 _print('# uri path: ${uri.path}'); |
173 return packageRoot.resolve(uri.path); | 199 } |
| 200 return _packageRoot.resolve(uri.path); |
174 } | 201 } |
175 | 202 |
176 | 203 |
177 | 204 // Resolves the script uri in the current working directory iff the given uri |
178 String _resolveScriptUri(String scriptName) { | 205 // did not specify a scheme (e.g. a path to a script file on the command line). |
| 206 Uri _resolveScriptUri(String scriptName) { |
179 if (_workingDirectoryUri == null) { | 207 if (_workingDirectoryUri == null) { |
180 throw 'No current working directory set.'; | 208 throw 'No current working directory set.'; |
181 } | 209 } |
182 scriptName = _sanitizeWindowsPath(scriptName); | 210 scriptName = _sanitizeWindowsPath(scriptName); |
183 | 211 |
184 var scriptUri = Uri.parse(scriptName); | 212 var scriptUri = Uri.parse(scriptName); |
185 if (scriptUri.scheme != '') { | 213 if (scriptUri.scheme == '') { |
186 // Script has a scheme, assume that it is fully formed. | |
187 _entryPointScript = scriptUri; | |
188 } else { | |
189 // Script does not have a scheme, assume that it is a path, | 214 // Script does not have a scheme, assume that it is a path, |
190 // resolve it against the working directory. | 215 // resolve it against the working directory. |
191 _entryPointScript = _workingDirectoryUri.resolve(scriptName); | 216 scriptUri = _workingDirectoryUri.resolveUri(scriptUri); |
192 } | 217 } |
193 if (_logBuiltin) { | 218 |
| 219 // Remember the entry point script URI so that we can resolve packages |
| 220 // based on this location. |
| 221 _entryPointScript = scriptUri; |
| 222 |
| 223 if (_logLoading) { |
194 _print('# Resolved entry point to: $_entryPointScript'); | 224 _print('# Resolved entry point to: $_entryPointScript'); |
195 } | 225 } |
196 return _entryPointScript.toString(); | 226 return scriptUri; |
197 } | 227 } |
198 | 228 |
199 | 229 |
200 // Function called by standalone embedder to resolve uris. | 230 void _finishLoadRequest(String uri) { |
201 String _resolveUri(String base, String userString) { | |
202 if (_logBuiltin) { | |
203 _print('# Resolving: $userString from $base'); | |
204 } | |
205 var baseUri = Uri.parse(base); | |
206 if (userString.startsWith(_DART_EXT)) { | |
207 var uri = userString.substring(_DART_EXT.length); | |
208 return '$_DART_EXT${baseUri.resolve(uri)}'; | |
209 } else { | |
210 return baseUri.resolve(userString).toString(); | |
211 } | |
212 } | |
213 | |
214 Uri _createUri(String userUri) { | |
215 var uri = Uri.parse(userUri); | |
216 switch (uri.scheme) { | |
217 case '': | |
218 case 'data': | |
219 case 'file': | |
220 case 'http': | |
221 case 'https': | |
222 return uri; | |
223 case 'package': | |
224 return _resolvePackageUri(uri); | |
225 default: | |
226 // Only handling file, http[s], and package URIs | |
227 // in standalone binary. | |
228 if (_logBuiltin) { | |
229 _print('# Unknown scheme (${uri.scheme}) in $uri.'); | |
230 } | |
231 throw 'Not a known scheme: $uri'; | |
232 } | |
233 } | |
234 | |
235 int _numOutstandingLoadRequests = 0; | |
236 void _finishedOneLoadRequest(String uri) { | |
237 assert(_numOutstandingLoadRequests > 0); | 231 assert(_numOutstandingLoadRequests > 0); |
238 _numOutstandingLoadRequests--; | 232 _numOutstandingLoadRequests--; |
239 if (_logBuiltin) { | 233 if (_logLoading) { |
240 _print("Loading of $uri finished, " | 234 _print("Loading of $uri finished, " |
241 "${_numOutstandingLoadRequests} requests remaining"); | 235 "${_numOutstandingLoadRequests} requests remaining"); |
242 } | 236 } |
243 if (_numOutstandingLoadRequests == 0) { | 237 if (_numOutstandingLoadRequests == 0) { |
244 _signalDoneLoading(); | 238 _signalDoneLoading(); |
245 } | 239 } |
246 } | 240 } |
247 | 241 |
248 void _startingOneLoadRequest(String uri) { | 242 |
| 243 void _startLoadRequest(String uri, Uri resourceUri) { |
249 assert(_numOutstandingLoadRequests >= 0); | 244 assert(_numOutstandingLoadRequests >= 0); |
250 _numOutstandingLoadRequests++; | 245 _numOutstandingLoadRequests++; |
251 if (_logBuiltin) { | 246 if (_logLoading) { |
252 _print("Loading of $uri started, " | 247 _print("Loading of $resourceUri for $uri started, " |
253 "${_numOutstandingLoadRequests} requests outstanding"); | 248 "${_numOutstandingLoadRequests} requests outstanding"); |
254 } | 249 } |
255 } | 250 } |
256 | 251 |
257 class LoadError extends Error { | |
258 final String message; | |
259 LoadError(this.message); | |
260 | 252 |
261 String toString() => 'Load Error: $message'; | 253 void _loadScript(int tag, String uri, String libraryUri, Uint8List data) { |
262 } | |
263 | |
264 void _signalDoneLoading() native "Builtin_DoneLoading"; | |
265 void _loadScriptCallback(int tag, String uri, String libraryUri, List<int> data) | |
266 native "Builtin_LoadScript"; | |
267 void _asyncLoadErrorCallback(uri, libraryUri, error) | |
268 native "Builtin_AsyncLoadError"; | |
269 | |
270 void _loadScript(int tag, String uri, String libraryUri, List<int> data) { | |
271 // TODO: Currently a compilation error while loading the script is | 254 // TODO: Currently a compilation error while loading the script is |
272 // fatal for the isolate. _loadScriptCallback() does not return and | 255 // fatal for the isolate. _loadScriptCallback() does not return and |
273 // the _numOutstandingLoadRequests counter remains out of sync. | 256 // the _numOutstandingLoadRequests counter remains out of sync. |
274 _loadScriptCallback(tag, uri, libraryUri, data); | 257 _loadScriptCallback(tag, uri, libraryUri, data); |
275 _finishedOneLoadRequest(uri); | 258 _finishLoadRequest(uri); |
276 } | 259 } |
277 | 260 |
| 261 |
278 void _asyncLoadError(int tag, String uri, String libraryUri, LoadError error) { | 262 void _asyncLoadError(int tag, String uri, String libraryUri, LoadError error) { |
279 if (_logBuiltin) { | 263 if (_logLoading) { |
280 _print("_asyncLoadError($uri), error: $error"); | 264 _print("_asyncLoadError($uri), error: $error"); |
281 } | 265 } |
282 if (tag == Dart_kImportTag) { | 266 if (tag == Dart_kImportTag) { |
283 // When importing a library, the libraryUri is the imported | 267 // When importing a library, the libraryUri is the imported |
284 // uri. | 268 // uri. |
285 libraryUri = uri; | 269 libraryUri = uri; |
286 } | 270 } |
287 _asyncLoadErrorCallback(uri, libraryUri, error); | 271 _asyncLoadErrorCallback(uri, libraryUri, error); |
288 _finishedOneLoadRequest(uri); | 272 _finishLoadRequest(uri); |
289 } | 273 } |
290 | 274 |
291 | 275 |
292 _loadDataAsyncLoadPort(int tag, | 276 _loadDataFromLoadPort(int tag, |
293 String uri, | 277 String uri, |
294 String libraryUri, | 278 String libraryUri, |
295 Uri resourceUri) { | 279 Uri resourceUri) { |
296 var receivePort = new ReceivePort(); | 280 var receivePort = new ReceivePort(); |
297 receivePort.first.then((dataOrError) { | 281 receivePort.first.then((dataOrError) { |
298 receivePort.close(); | 282 receivePort.close(); |
299 if (dataOrError is List<int>) { | 283 if (dataOrError is Uint8List) { |
300 _loadScript(tag, uri, libraryUri, dataOrError); | 284 _loadScript(tag, uri, libraryUri, dataOrError); |
301 } else { | 285 } else { |
302 assert(dataOrError is String); | 286 assert(dataOrError is String); |
303 var error = new LoadError(dataOrError.toString()); | 287 var error = new LoadError(dataOrError.toString()); |
304 _asyncLoadError(tag, uri, libraryUri, error); | 288 _asyncLoadError(tag, uri, libraryUri, error); |
305 } | 289 } |
306 }).catchError((e) { | 290 }).catchError((e) { |
307 receivePort.close(); | 291 receivePort.close(); |
308 // Wrap inside a LoadError unless we are already propagating a previously | 292 // Wrap inside a LoadError unless we are already propagating a previously |
309 // seen LoadError. | 293 // seen LoadError. |
310 var error = (e is LoadError) ? e : new LoadError(e.toString); | 294 var error = (e is LoadError) ? e : new LoadError(e.toString); |
311 _asyncLoadError(tag, uri, libraryUri, error); | 295 _asyncLoadError(tag, uri, libraryUri, error); |
312 }); | 296 }); |
313 | 297 |
314 try { | 298 try { |
315 var msg = [receivePort.sendPort, resourceUri.toString()]; | 299 var msg = [receivePort.sendPort, resourceUri.toString()]; |
316 _loadPort.send(msg); | 300 _loadPort.send(msg); |
317 _startingOneLoadRequest(uri); | 301 _startLoadRequest(uri, resourceUri); |
318 } catch (e) { | 302 } catch (e) { |
319 if (_logBuiltin) { | 303 if (_logLoading) { |
320 _print("Exception when communicating with service isolate: $e"); | 304 _print("Exception when communicating with service isolate: $e"); |
321 } | 305 } |
322 // Wrap inside a LoadError unless we are already propagating a previously | 306 // Wrap inside a LoadError unless we are already propagating a previously |
323 // seen LoadError. | 307 // seen LoadError. |
324 var error = (e is LoadError) ? e : new LoadError(e.toString); | 308 var error = (e is LoadError) ? e : new LoadError(e.toString); |
325 _asyncLoadError(tag, uri, libraryUri, error); | 309 _asyncLoadError(tag, uri, libraryUri, error); |
326 receivePort.close(); | 310 receivePort.close(); |
327 } | 311 } |
328 } | 312 } |
329 | 313 |
| 314 |
| 315 // Embedder Entrypoint: |
330 // Asynchronously loads script data through a http[s] or file uri. | 316 // Asynchronously loads script data through a http[s] or file uri. |
331 _loadDataAsync(int tag, String uri, String libraryUri) { | 317 _loadDataAsync(int tag, String uri, String libraryUri) { |
| 318 var resourceUri; |
332 if (tag == Dart_kScriptTag) { | 319 if (tag == Dart_kScriptTag) { |
333 uri = _resolveScriptUri(uri); | 320 resourceUri = _resolveScriptUri(uri); |
| 321 uri = resourceUri.toString(); |
| 322 } else { |
| 323 resourceUri = Uri.parse(uri); |
334 } | 324 } |
335 | 325 |
336 Uri resourceUri = _createUri(uri); | 326 // package based uris need to be resolved to the correct loadable location. |
| 327 if (resourceUri.scheme == 'package') { |
| 328 resourceUri = _resolvePackageUri(resourceUri); |
| 329 } |
337 | 330 |
338 _loadDataAsyncLoadPort(tag, uri, libraryUri, resourceUri); | 331 _loadDataFromLoadPort(tag, uri, libraryUri, resourceUri); |
339 } | 332 } |
340 | 333 |
| 334 |
| 335 // Embedder Entrypoint: |
| 336 // Function called by standalone embedder to resolve uris when the VM requests |
| 337 // Dart_kCanonicalizeUrl from the tag handler. |
| 338 String _resolveUri(String base, String userString) { |
| 339 if (_logLoading) { |
| 340 _print('# Resolving: $userString from $base'); |
| 341 } |
| 342 var baseUri = Uri.parse(base); |
| 343 var result; |
| 344 if (userString.startsWith(_DART_EXT)) { |
| 345 var uri = userString.substring(_DART_EXT.length); |
| 346 result = '$_DART_EXT${baseUri.resolve(uri)}'; |
| 347 } else { |
| 348 result = baseUri.resolve(userString).toString(); |
| 349 } |
| 350 if (_logLoading) { |
| 351 _print('Resolved $userString in $base to $result'); |
| 352 } |
| 353 return result; |
| 354 } |
| 355 |
| 356 |
| 357 // Embedder Entrypoint (gen_snapshot): |
| 358 // Resolve relative paths relative to working directory. |
| 359 String _resolveInWorkingDirectory(String fileName) { |
| 360 if (_workingDirectoryUri == null) { |
| 361 throw 'No current working directory set.'; |
| 362 } |
| 363 var name = _sanitizeWindowsPath(fileName); |
| 364 |
| 365 var uri = Uri.parse(name); |
| 366 if (uri.scheme != '') { |
| 367 throw 'Schemes are not supported when resolving filenames.'; |
| 368 } |
| 369 uri = _workingDirectoryUri.resolveUri(uri); |
| 370 |
| 371 if (_logLoading) { |
| 372 _print('# Resolved in working directory: $fileName -> $uri'); |
| 373 } |
| 374 return uri.toString(); |
| 375 } |
| 376 |
| 377 |
| 378 // Handling of dart-ext loading. |
| 379 // Dart native extension scheme. |
| 380 const _DART_EXT = 'dart-ext:'; |
| 381 |
| 382 String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension"; |
| 383 |
| 384 |
| 385 String _platformExtensionFileName(String name) { |
| 386 var extension = _nativeLibraryExtension(); |
| 387 |
| 388 if (_isWindows) { |
| 389 return '$name.$extension'; |
| 390 } else { |
| 391 return 'lib$name.$extension'; |
| 392 } |
| 393 } |
| 394 |
| 395 |
341 // Returns either a file path or a URI starting with http[s]:, as a String. | 396 // Returns either a file path or a URI starting with http[s]:, as a String. |
342 String _filePathFromUri(String userUri) { | 397 String _filePathFromUri(String userUri) { |
343 var uri = Uri.parse(userUri); | 398 var uri = Uri.parse(userUri); |
344 if (_logBuiltin) { | 399 if (_logLoading) { |
345 _print('# Getting file path from: $uri'); | 400 _print('# Getting file path from: $uri'); |
346 } | 401 } |
347 | 402 |
348 var path; | 403 var path; |
349 switch (uri.scheme) { | 404 switch (uri.scheme) { |
350 case '': | 405 case '': |
351 case 'file': | 406 case 'file': |
352 return uri.toFilePath(); | 407 return uri.toFilePath(); |
353 case 'package': | 408 case 'package': |
354 return _filePathFromUri(_resolvePackageUri(uri).toString()); | 409 return _filePathFromUri(_resolvePackageUri(uri).toString()); |
355 case 'data': | 410 case 'data': |
356 case 'http': | 411 case 'http': |
357 case 'https': | 412 case 'https': |
358 return uri.toString(); | 413 return uri.toString(); |
359 default: | 414 default: |
360 // Only handling file, http, and package URIs | 415 // Only handling file, http, and package URIs |
361 // in standalone binary. | 416 // in standalone binary. |
362 if (_logBuiltin) { | 417 if (_logLoading) { |
363 _print('# Unknown scheme (${uri.scheme}) in $uri.'); | 418 _print('# Unknown scheme (${uri.scheme}) in $uri.'); |
364 } | 419 } |
365 throw 'Not a known scheme: $uri'; | 420 throw 'Not a known scheme: $uri'; |
366 } | 421 } |
367 } | 422 } |
368 | 423 |
369 String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension"; | |
370 | 424 |
371 String _platformExtensionFileName(String name) { | 425 // Embedder Entrypoint: |
372 var extension = _nativeLibraryExtension(); | 426 // When loading an extension the embedder calls this method to get the |
373 | 427 // different components. |
374 if (_isWindows) { | |
375 return '$name.$extension'; | |
376 } else { | |
377 return 'lib$name.$extension'; | |
378 } | |
379 } | |
380 | |
381 // Returns the directory part, the filename part, and the name | 428 // Returns the directory part, the filename part, and the name |
382 // of a native extension URL as a list [directory, filename, name]. | 429 // of a native extension URL as a list [directory, filename, name]. |
383 // The directory part is either a file system path or an HTTP(S) URL. | 430 // The directory part is either a file system path or an HTTP(S) URL. |
384 // The filename part is the extension name, with the platform-dependent | 431 // The filename part is the extension name, with the platform-dependent |
385 // prefixes and extensions added. | 432 // prefixes and extensions added. |
386 _extensionPathFromUri(String userUri) { | 433 _extensionPathFromUri(String userUri) { |
387 if (!userUri.startsWith(_DART_EXT)) { | 434 if (!userUri.startsWith(_DART_EXT)) { |
388 throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:'; | 435 throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:'; |
389 } | 436 } |
390 userUri = userUri.substring(_DART_EXT.length); | 437 userUri = userUri.substring(_DART_EXT.length); |
391 | 438 |
392 if (userUri.contains('\\')) { | 439 if (userUri.contains('\\')) { |
393 throw 'Unexpected internal error: Extension URI $userUri contains \\'; | 440 throw 'Unexpected internal error: Extension URI $userUri contains \\'; |
394 } | 441 } |
395 | 442 |
396 | |
397 String name; | 443 String name; |
398 String path; // Will end in '/'. | 444 String path; // Will end in '/'. |
399 int index = userUri.lastIndexOf('/'); | 445 int index = userUri.lastIndexOf('/'); |
400 if (index == -1) { | 446 if (index == -1) { |
401 name = userUri; | 447 name = userUri; |
402 path = './'; | 448 path = './'; |
403 } else if (index == userUri.length - 1) { | 449 } else if (index == userUri.length - 1) { |
404 throw 'Extension name missing in $extensionUri'; | 450 throw 'Extension name missing in $extensionUri'; |
405 } else { | 451 } else { |
406 name = userUri.substring(index + 1); | 452 name = userUri.substring(index + 1); |
407 path = userUri.substring(0, index + 1); | 453 path = userUri.substring(0, index + 1); |
408 } | 454 } |
409 | 455 |
410 path = _filePathFromUri(path); | 456 path = _filePathFromUri(path); |
411 var filename = _platformExtensionFileName(name); | 457 var filename = _platformExtensionFileName(name); |
412 | 458 |
413 return [path, filename, name]; | 459 return [path, filename, name]; |
414 } | 460 } |
OLD | NEW |