| Index: ppapi/native_client/src/trusted/plugin/pnacl_resources.cc | 
| diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc | 
| index af2944fa78fd1522b61aa4696375372ca06147d6..119d53acd94ebaa154bf329bf325d4a63a774bb2 100644 | 
| --- a/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc | 
| +++ b/ppapi/native_client/src/trusted/plugin/pnacl_resources.cc | 
| @@ -7,22 +7,29 @@ | 
| #include "native_client/src/include/portability_io.h" | 
| #include "native_client/src/shared/platform/nacl_check.h" | 
| #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" | 
| +#include "native_client/src/trusted/plugin/file_utils.h" | 
| #include "native_client/src/trusted/plugin/manifest.h" | 
| #include "native_client/src/trusted/plugin/plugin.h" | 
| #include "native_client/src/trusted/plugin/pnacl_coordinator.h" | 
| #include "native_client/src/trusted/plugin/utility.h" | 
| - | 
| #include "ppapi/c/pp_errors.h" | 
| +#include "third_party/jsoncpp/source/include/json/reader.h" | 
| +#include "third_party/jsoncpp/source/include/json/value.h" | 
|  | 
| namespace plugin { | 
|  | 
| -static const char kPnaclComponentScheme[] = | 
| -    "pnacl-component://"; | 
| -const char PnaclUrls::kLlcUrl[] = "llc.nexe"; | 
| -const char PnaclUrls::kLdUrl[] = "ld.nexe"; | 
| +static const char kPnaclComponentScheme[] = "pnacl-component://"; | 
| +const char PnaclUrls::kResourceInfoUrl[] = "pnacl.json"; | 
| + | 
| +const char PnaclResources::kDefaultLlcName[] = "llc.nexe"; | 
| +const char PnaclResources::kDefaultLdName[] = "ld.nexe"; | 
|  | 
| nacl::string PnaclUrls::GetBaseUrl() { | 
| -  return nacl::string(kPnaclComponentScheme) + GetSandboxISA() + "/"; | 
| +  return nacl::string(kPnaclComponentScheme); | 
| +} | 
| + | 
| +nacl::string PnaclUrls::PrependPlatformPrefix(const nacl::string& url) { | 
| +  return nacl::string(GetSandboxISA()) + "/" + url; | 
| } | 
|  | 
| // Determine if a URL is for a pnacl-component file, or if it is some other | 
| @@ -92,22 +99,118 @@ nacl::DescWrapper* PnaclResources::WrapperForUrl(const nacl::string& url) { | 
| return resource_wrappers_[url]; | 
| } | 
|  | 
| -void PnaclResources::StartLoad() { | 
| +void PnaclResources::ReadResourceInfo( | 
| +    const nacl::string& resource_info_url, | 
| +    const pp::CompletionCallback& resource_info_read_cb) { | 
| +  PLUGIN_PRINTF(("PnaclResources::ReadResourceInfo\n")); | 
| + | 
| +  nacl::string full_url; | 
| +  ErrorInfo error_info; | 
| +  if (!manifest_->ResolveURL(resource_info_url, &full_url, &error_info)) { | 
| +    ReadResourceInfoError(nacl::string("failed to resolve ") + | 
| +                          resource_info_url + ": " + | 
| +                          error_info.message() + "."); | 
| +    return; | 
| +  } | 
| +  PLUGIN_PRINTF(("Resolved resources info url: %s\n", full_url.c_str())); | 
| +  nacl::string resource_info_filename = | 
| +    PnaclUrls::PnaclComponentURLToFilename(full_url); | 
| + | 
| +  PLUGIN_PRINTF(("Pnacl-converted resources info url: %s\n", | 
| +                 resource_info_filename.c_str())); | 
| + | 
| +  int32_t fd = GetPnaclFD(plugin_, resource_info_filename.c_str()); | 
| +  if (fd < 0) { | 
| +    ReadResourceInfoError( | 
| +        nacl::string("PnaclResources::ReadResourceInfo failed for: ") + | 
| +        resource_info_filename); | 
| +    return; | 
| +  } | 
| + | 
| +  nacl::string json_buffer; | 
| +  file_utils::StatusCode status = file_utils::SlurpFile(fd, json_buffer); | 
| +  if (status != file_utils::PLUGIN_FILE_SUCCESS) { | 
| +    ReadResourceInfoError( | 
| +        nacl::string("PnaclResources::ReadResourceInfo reading " | 
| +                     "failed for: ") + resource_info_filename); | 
| +    return; | 
| +  } | 
| + | 
| +  // Finally, we have the resource info JSON data in json_buffer. | 
| +  PLUGIN_PRINTF(("Resource info JSON data:\n%s\n", json_buffer.c_str())); | 
| +  nacl::string error_message; | 
| +  if (!ParseResourceInfo(json_buffer, error_message)) { | 
| +    ReadResourceInfoError(nacl::string("Parsing resource info failed: ") + | 
| +                          error_message + "\n"); | 
| +    return; | 
| +  } | 
| + | 
| +  // Done. Queue the completion callback. | 
| +  pp::Core* core = pp::Module::Get()->core(); | 
| +  core->CallOnMainThread(0, resource_info_read_cb, PP_OK); | 
| +} | 
| + | 
| +void PnaclResources::ReadResourceInfoError(const nacl::string& msg) { | 
| +  coordinator_->ReportNonPpapiError(ERROR_PNACL_RESOURCE_FETCH, msg); | 
| +} | 
| + | 
| +bool PnaclResources::ParseResourceInfo(const nacl::string& buf, | 
| +                                       nacl::string& errmsg) { | 
| +  // Expect the JSON file to contain a top-level object (dictionary). | 
| +  Json::Reader json_reader; | 
| +  Json::Value json_data; | 
| +  if (!json_reader.parse(buf, json_data)) { | 
| +    errmsg = nacl::string("JSON parse error: ") + | 
| +             json_reader.getFormatedErrorMessages(); | 
| +    return false; | 
| +  } | 
| + | 
| +  if (!json_data.isObject()) { | 
| +    errmsg = nacl::string("Malformed JSON dictionary"); | 
| +    return false; | 
| +  } | 
| + | 
| +  if (json_data.isMember("pnacl-llc-name")) { | 
| +    Json::Value json_name = json_data["pnacl-llc-name"]; | 
| +    if (json_name.isString()) { | 
| +      llc_tool_name = json_name.asString(); | 
| +      PLUGIN_PRINTF(("Set llc_tool_name=%s\n", llc_tool_name.c_str())); | 
| +    } | 
| +  } | 
| + | 
| +  if (json_data.isMember("pnacl-ld-name")) { | 
| +    Json::Value json_name = json_data["pnacl-ld-name"]; | 
| +    if (json_name.isString()) { | 
| +      ld_tool_name = json_name.asString(); | 
| +      PLUGIN_PRINTF(("Set ld_tool_name=%s\n", ld_tool_name.c_str())); | 
| +    } | 
| +  } | 
| + | 
| +  return true; | 
| +} | 
| + | 
| +void PnaclResources::StartLoad( | 
| +    const pp::CompletionCallback& all_loaded_callback) { | 
| PLUGIN_PRINTF(("PnaclResources::StartLoad\n")); | 
|  | 
| -  CHECK(resource_urls_.size() > 0); | 
| +  std::vector<nacl::string> resource_urls; | 
| +  resource_urls.push_back(GetLlcUrl()); | 
| +  resource_urls.push_back(GetLdUrl()); | 
| + | 
| PLUGIN_PRINTF(("PnaclResources::StartLoad -- local install of PNaCl.\n")); | 
| // Do a blocking load of each of the resources. | 
| int32_t result = PP_OK; | 
| -  for (size_t i = 0; i < resource_urls_.size(); ++i) { | 
| -    const nacl::string& url = resource_urls_[i]; | 
| +  for (size_t i = 0; i < resource_urls.size(); ++i) { | 
| +    const nacl::string& url_with_platform_prefix = | 
| +      PnaclUrls::PrependPlatformPrefix(resource_urls[i]); | 
| nacl::string full_url; | 
| ErrorInfo error_info; | 
| -    if (!manifest_->ResolveURL(resource_urls_[i], &full_url, &error_info)) { | 
| +    if (!manifest_->ResolveURL(url_with_platform_prefix, &full_url, | 
| +                               &error_info)) { | 
| coordinator_->ReportNonPpapiError( | 
| ERROR_PNACL_RESOURCE_FETCH, | 
| nacl::string("failed to resolve ") + | 
| -          url + ": " + | 
| +          url_with_platform_prefix + ": " + | 
| error_info.message() + "."); | 
| break; | 
| } | 
| @@ -117,18 +220,18 @@ void PnaclResources::StartLoad() { | 
| if (fd < 0) { | 
| coordinator_->ReportNonPpapiError( | 
| ERROR_PNACL_RESOURCE_FETCH, | 
| -          nacl::string("PnaclLocalResources::StartLoad failed for: ") + | 
| +          nacl::string("PnaclResources::StartLoad failed for: ") + | 
| filename + " (PNaCl not installed?  Check chrome://nacl)"); | 
| result = PP_ERROR_FILENOTFOUND; | 
| break; | 
| } else { | 
| -      resource_wrappers_[url] = | 
| +      resource_wrappers_[resource_urls[i]] = | 
| plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY); | 
| } | 
| } | 
| // We're done!  Queue the callback. | 
| pp::Core* core = pp::Module::Get()->core(); | 
| -  core->CallOnMainThread(0, all_loaded_callback_, result); | 
| +  core->CallOnMainThread(0, all_loaded_callback, result); | 
| } | 
|  | 
| }  // namespace plugin | 
|  |