| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "lib/tonic/file_loader/file_loader.h" |
| |
| #include <iostream> |
| #include <memory> |
| #include <utility> |
| |
| #include "lib/ftl/files/directory.h" |
| #include "lib/ftl/files/file.h" |
| #include "lib/ftl/files/path.h" |
| #include "lib/ftl/files/symlink.h" |
| #include "lib/ftl/logging.h" |
| #include "lib/tonic/converter/dart_converter.h" |
| #include "lib/tonic/parsers/packages_map.h" |
| |
| namespace tonic { |
| namespace { |
| |
| constexpr char kPackageScheme[] = "package:"; |
| constexpr size_t kPackageSchemeLength = sizeof(kPackageScheme) - 1; |
| |
| constexpr char kFileScheme[] = "file:"; |
| constexpr size_t kFileSchemeLength = sizeof(kFileScheme) - 1; |
| |
| constexpr char kFileURLPrefix[] = "file://"; |
| constexpr size_t kFileURLPrefixLength = sizeof(kFileURLPrefix) - 1; |
| |
| constexpr char kDartScheme[] = "dart:"; |
| |
| // Extract the scheme prefix ('package:' or 'file:' from ) |
| std::string ExtractSchemePrefix(std::string url) { |
| if (url.find(kPackageScheme) == 0u) |
| return kPackageScheme; |
| if (url.find(kFileScheme) == 0u) |
| return kFileScheme; |
| return std::string(); |
| } |
| |
| // Extract the path from a package: or file: url. |
| std::string ExtractPath(std::string url) { |
| if (url.find(kPackageScheme) == 0u) |
| return url.substr(kPackageSchemeLength); |
| if (url.find(kFileScheme) == 0u) |
| return url.substr(kFileSchemeLength); |
| return url; |
| } |
| |
| } // namespace |
| |
| FileLoader::FileLoader() {} |
| |
| FileLoader::~FileLoader() {} |
| |
| bool FileLoader::LoadPackagesMap(const std::string& packages) { |
| packages_ = packages; |
| dependencies_.insert(packages_); |
| std::string packages_source; |
| if (!files::ReadFileToString(packages_, &packages_source)) { |
| std::cerr << "error: Unable to load .packages file '" << packages_ << "'." |
| << std::endl; |
| return false; |
| } |
| packages_map_.reset(new PackagesMap()); |
| std::string error; |
| if (!packages_map_->Parse(packages_source, &error)) { |
| std::cerr << "error: Unable to parse .packages file '" << packages_ << "'." |
| << std::endl |
| << error << std::endl; |
| return false; |
| } |
| return true; |
| } |
| |
| Dart_Handle FileLoader::HandleLibraryTag(Dart_LibraryTag tag, |
| Dart_Handle library, |
| Dart_Handle url) { |
| FTL_DCHECK(Dart_IsLibrary(library)); |
| FTL_DCHECK(Dart_IsString(url)); |
| if (tag == Dart_kCanonicalizeUrl) |
| return CanonicalizeURL(library, url); |
| if (tag == Dart_kImportTag) |
| return Import(url); |
| if (tag == Dart_kSourceTag) |
| return Source(library, url); |
| if (tag == Dart_kScriptTag) |
| return Script(url); |
| return Dart_NewApiError("Unknown library tag."); |
| } |
| |
| Dart_Handle FileLoader::CanonicalizeURL(Dart_Handle library, Dart_Handle url) { |
| std::string string = StdStringFromDart(url); |
| if (string.find(kDartScheme) == 0u) |
| return url; |
| if (string.find(kPackageScheme) == 0u) |
| return url; |
| if (string.find(kFileScheme) == 0u) |
| return StdStringToDart(string.substr(kFileSchemeLength)); |
| |
| std::string library_url = StdStringFromDart(Dart_LibraryUrl(library)); |
| std::string prefix = ExtractSchemePrefix(library_url); |
| std::string base_path = ExtractPath(library_url); |
| std::string simplified_path = |
| files::SimplifyPath(files::GetDirectoryName(base_path) + "/" + string); |
| return StdStringToDart(prefix + simplified_path); |
| } |
| |
| std::string FileLoader::GetFilePathForURL(std::string url) { |
| if (url.find(kPackageScheme) == 0u) |
| return GetFilePathForPackageURL(std::move(url)); |
| if (url.find(kFileScheme) == 0u) |
| return GetFilePathForFileURL(std::move(url)); |
| return url; |
| } |
| |
| std::string FileLoader::GetFilePathForPackageURL(std::string url) { |
| FTL_DCHECK(url.find(kPackageScheme) == 0u); |
| url = url.substr(kPackageSchemeLength); |
| size_t slash = url.find('/'); |
| if (slash == std::string::npos) |
| return std::string(); |
| std::string package = url.substr(0, slash); |
| std::string library_path = url.substr(slash + 1); |
| std::string package_path = packages_map_->Resolve(package); |
| if (package_path.empty()) |
| return std::string(); |
| if (package_path.find(kFileURLPrefix) == 0u) |
| return package_path.substr(kFileURLPrefixLength) + library_path; |
| return files::GetDirectoryName(packages_) + "/" + package_path + "/" + |
| library_path; |
| } |
| |
| std::string FileLoader::GetFilePathForFileURL(std::string url) { |
| FTL_DCHECK(url.find(kFileURLPrefix) == 0u); |
| return url.substr(kFileURLPrefixLength); |
| } |
| |
| std::string FileLoader::GetFileURLForPath(const std::string& path) { |
| return std::string(kFileURLPrefix) + path; |
| } |
| |
| std::string FileLoader::Fetch(const std::string& url, |
| std::string* resolved_url) { |
| std::string path = GetFilePathForURL(url); |
| if (resolved_url) |
| *resolved_url = GetFileURLForPath(path); |
| std::string source; |
| if (!files::ReadFileToString(files::GetAbsoluteFilePath(path), &source)) { |
| std::cerr << "error: Unable to find Dart library '" << url << "'." |
| << std::endl; |
| exit(1); |
| } |
| url_dependencies_.insert(url); |
| dependencies_.insert(path); |
| return source; |
| } |
| |
| Dart_Handle FileLoader::LoadLibrary(const std::string& url) { |
| std::string resolved_url; |
| Dart_Handle source = ToDart(Fetch(url, &resolved_url)); |
| Dart_Handle result = |
| Dart_LoadLibrary(ToDart(url), ToDart(resolved_url), source, 0, 0); |
| DART_CHECK_VALID(result); |
| return result; |
| } |
| |
| Dart_Handle FileLoader::Import(Dart_Handle url) { |
| return LoadLibrary(StdStringFromDart(url)); |
| } |
| |
| Dart_Handle FileLoader::Source(Dart_Handle library, Dart_Handle url) { |
| std::string resolved_url; |
| Dart_Handle source = ToDart(Fetch(StdStringFromDart(url), &resolved_url)); |
| Dart_Handle result = |
| Dart_LoadSource(library, url, ToDart(resolved_url), source, 0, 0); |
| DART_CHECK_VALID(result); |
| return result; |
| } |
| |
| Dart_Handle FileLoader::Script(Dart_Handle url) { |
| std::string resolved_url; |
| Dart_Handle source = ToDart(Fetch(StdStringFromDart(url), &resolved_url)); |
| Dart_Handle result = Dart_LoadScript(url, ToDart(resolved_url), source, 0, 0); |
| DART_CHECK_VALID(result); |
| return result; |
| } |
| |
| } // namespace tonic |