| // Copyright 2021 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 "src/devices/bin/driver_manager/manifest_parser.h" |
| |
| #include <lib/zx/status.h> |
| |
| #include "src/lib/fxl/strings/substitute.h" |
| #include "src/lib/pkg_url/fuchsia_pkg_url.h" |
| |
| namespace { |
| |
| const std::string kFuchsiaPkgPrefix = "fuchsia-pkg://"; |
| const std::string kFuchsiaBootPrefix = "fuchsia-boot://"; |
| const std::string kRelativeUrlPrefix = "#"; |
| |
| bool IsFuchsiaPkgScheme(std::string_view url) { |
| return url.compare(0, kFuchsiaPkgPrefix.length(), kFuchsiaPkgPrefix) == 0; |
| } |
| |
| zx::status<std::string> GetResourcePath(std::string_view url) { |
| size_t seperator = url.find('#'); |
| if (seperator == std::string::npos) { |
| return zx::error(ZX_ERR_NOT_FOUND); |
| } |
| return zx::ok(url.substr(seperator + 1)); |
| } |
| |
| bool IsRelativeUrl(std::string_view url) { |
| return url.compare(0, kRelativeUrlPrefix.length(), kRelativeUrlPrefix) == 0; |
| } |
| |
| } // namespace |
| |
| bool IsFuchsiaBootScheme(std::string_view url) { |
| return url.compare(0, kFuchsiaBootPrefix.length(), kFuchsiaBootPrefix) == 0; |
| } |
| |
| zx::status<std::string> GetBasePathFromUrl(const std::string& url) { |
| if (IsFuchsiaPkgScheme(url)) { |
| component::FuchsiaPkgUrl package_url; |
| if (!package_url.Parse(url)) { |
| LOGF(ERROR, "Failed to parse fuchsia url: %s", url.c_str()); |
| return zx::error(ZX_ERR_INTERNAL); |
| } |
| return zx::ok(fxl::Substitute("/pkgfs/packages/$0/$1", package_url.package_name(), |
| package_url.variant())); |
| } |
| if (IsFuchsiaBootScheme(url)) { |
| auto resource_path = GetResourcePath(url); |
| if (resource_path.is_error()) { |
| LOGF(ERROR, "Failed to parse boot url: %s", url.c_str()); |
| return resource_path; |
| } |
| return zx::ok("/boot"); |
| } |
| if (IsRelativeUrl(url)) { |
| auto resource_path = GetResourcePath(url); |
| if (resource_path.is_error()) { |
| LOGF(ERROR, "Failed to parse test url: %s", url.c_str()); |
| return resource_path; |
| } |
| return zx::ok("/pkg"); |
| } |
| |
| return zx::error(ZX_ERR_NOT_FOUND); |
| } |
| |
| zx::status<std::string> GetPathFromUrl(const std::string& url) { |
| if (IsFuchsiaPkgScheme(url)) { |
| component::FuchsiaPkgUrl package_url; |
| if (!package_url.Parse(url)) { |
| LOGF(ERROR, "Failed to parse fuchsia url: %s", url.c_str()); |
| return zx::error(ZX_ERR_INTERNAL); |
| } |
| return zx::ok(fxl::Substitute("/pkgfs/packages/$0/$1/$2", package_url.package_name(), |
| package_url.variant(), package_url.resource_path())); |
| } |
| if (IsFuchsiaBootScheme(url)) { |
| auto resource_path = GetResourcePath(url); |
| if (resource_path.is_error()) { |
| LOGF(ERROR, "Failed to parse boot url: %s", url.c_str()); |
| return resource_path; |
| } |
| return zx::ok("/boot/" + resource_path.value()); |
| } |
| if (IsRelativeUrl(url)) { |
| auto resource_path = GetResourcePath(url); |
| if (resource_path.is_error()) { |
| LOGF(ERROR, "Failed to parse test url: %s", url.c_str()); |
| return resource_path; |
| } |
| return zx::ok("/pkg/" + resource_path.value()); |
| } |
| |
| return zx::error(ZX_ERR_NOT_FOUND); |
| } |
| |
| zx::status<DriverManifestEntries> ParseDriverManifest(rapidjson::Document manifest) { |
| DriverManifestEntries parsed_drivers; |
| |
| if (!manifest.IsArray()) { |
| LOGF(ERROR, "Driver Manifest's top-level object is not an array"); |
| return zx::error(ZX_ERR_INTERNAL); |
| } |
| |
| for (size_t i = 0; i < manifest.Size(); i++) { |
| const auto& driver = manifest[i]; |
| if (!driver.IsObject()) { |
| continue; |
| } |
| if (manifest[i].HasMember("driver_url")) { |
| const auto& driver_url = manifest[i]["driver_url"]; |
| if (driver_url.IsString()) { |
| DriverManifestEntry entry; |
| entry.driver_url = driver_url.GetString(); |
| parsed_drivers.push_back(std::move(entry)); |
| } |
| } |
| } |
| |
| return zx::ok(std::move(parsed_drivers)); |
| } |
| |
| zx::status<DriverManifestEntries> ParseDriverManifestFromPath(const std::string& path) { |
| json_parser::JSONParser parser; |
| rapidjson::Document manifest = parser.ParseFromFile(path); |
| if (parser.HasError()) { |
| LOGF(ERROR, "DriverManifest JSON failed to parse: %s", parser.error_str().c_str()); |
| return zx::error(ZX_ERR_INTERNAL); |
| } |
| |
| return ParseDriverManifest(std::move(manifest)); |
| } |