| Index: trunk/src/ppapi/native_client/src/trusted/plugin/json_manifest.cc
|
| ===================================================================
|
| --- trunk/src/ppapi/native_client/src/trusted/plugin/json_manifest.cc (revision 205338)
|
| +++ trunk/src/ppapi/native_client/src/trusted/plugin/json_manifest.cc (working copy)
|
| @@ -45,12 +45,19 @@
|
| const char* const kOptLevelKey = "-O";
|
| const char* const kPnaclExperimentalFlags = "experimental_flags";
|
|
|
| -// Sample NaCL manifest file:
|
| +// Sample manifest file:
|
| // {
|
| // "program": {
|
| // "x86-32": {"url": "myprogram_x86-32.nexe"},
|
| // "x86-64": {"url": "myprogram_x86-64.nexe"},
|
| -// "arm": {"url": "myprogram_arm.nexe"}
|
| +// "arm": {"url": "myprogram_arm.nexe"},
|
| +// "portable": {
|
| +// "pnacl-translate": {
|
| +// "url": "myprogram.pexe",
|
| +// "sha256": "...",
|
| +// "-O": 0
|
| +// }
|
| +// }
|
| // },
|
| // "interpreter": {
|
| // "x86-32": {"url": "interpreter_x86-32.nexe"},
|
| @@ -66,32 +73,14 @@
|
| // "portable": {"url": "bar.txt"}
|
| // },
|
| // "libfoo.so": {
|
| -// "x86-64" : { "url": "..." }
|
| +// "x86-64-ivybridge-foo": { "url": "..."},
|
| +// "x86-64-ivybridge" : { "pnacl-translate": { "url": "..."}},
|
| +// "x86-64" : { "url": "..." },
|
| +// "portable": {"pnacl-translate": {"url": "..."}}
|
| // }
|
| // }
|
| // }
|
|
|
| -// Sample PNaCl manifest file:
|
| -// {
|
| -// "program": {
|
| -// "portable": {
|
| -// "pnacl-translate": {
|
| -// "url": "myprogram.pexe",
|
| -// "sha256": "...",
|
| -// "-O": 0
|
| -// }
|
| -// }
|
| -// },
|
| -// "files": {
|
| -// "foo.txt": {
|
| -// "portable": {"url": "foo.txt"}
|
| -// },
|
| -// "bar.txt": {
|
| -// "portable": {"url": "bar.txt"}
|
| -// }
|
| -// }
|
| -// }
|
| -
|
| // Looks up |property_name| in the vector |valid_names| with length
|
| // |valid_name_count|. Returns true if |property_name| is found.
|
| bool FindMatchingProperty(const nacl::string& property_name,
|
| @@ -133,8 +122,7 @@
|
| if (!FindMatchingProperty(property_name,
|
| valid_keys,
|
| valid_key_count)) {
|
| - // For forward compatibility, we do not prohibit other keys being in
|
| - // the dictionary.
|
| + // TODO(jvoung): Should this set error_string and return false?
|
| PLUGIN_PRINTF(("WARNING: '%s' property '%s' has unknown key '%s'.\n",
|
| parent_key.c_str(),
|
| container_key.c_str(), property_name.c_str()));
|
| @@ -159,44 +147,22 @@
|
| bool IsValidUrlSpec(const Json::Value& url_spec,
|
| const nacl::string& container_key,
|
| const nacl::string& parent_key,
|
| - const nacl::string& sandbox_isa,
|
| nacl::string* error_string) {
|
| static const char* kManifestUrlSpecRequired[] = {
|
| kUrlKey
|
| };
|
| - const char** urlSpecPlusOptional;
|
| - size_t urlSpecPlusOptionalLength;
|
| - if (sandbox_isa == kPortableKey) {
|
| - static const char* kPnaclUrlSpecPlusOptional[] = {
|
| - kUrlKey,
|
| - kCacheIdentityKey,
|
| - kOptLevelKey,
|
| - };
|
| - urlSpecPlusOptional = kPnaclUrlSpecPlusOptional;
|
| - urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kPnaclUrlSpecPlusOptional);
|
| - } else {
|
| - urlSpecPlusOptional = kManifestUrlSpecRequired;
|
| - urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kManifestUrlSpecRequired);
|
| - }
|
| + static const char* kManifestUrlSpecPlusOptional[] = {
|
| + kUrlKey,
|
| + kCacheIdentityKey
|
| + };
|
| if (!IsValidDictionary(url_spec, container_key, parent_key,
|
| - urlSpecPlusOptional,
|
| - urlSpecPlusOptionalLength,
|
| + kManifestUrlSpecPlusOptional,
|
| + NACL_ARRAY_SIZE(kManifestUrlSpecPlusOptional),
|
| kManifestUrlSpecRequired,
|
| NACL_ARRAY_SIZE(kManifestUrlSpecRequired),
|
| error_string)) {
|
| return false;
|
| }
|
| - // URL specifications must not contain "pnacl-translate" keys.
|
| - // This prohibits NaCl clients from invoking PNaCl.
|
| - Json::Value translate = url_spec[kPnaclTranslateKey];
|
| - if (!translate.empty()) {
|
| - nacl::stringstream error_stream;
|
| - error_stream << parent_key << " property '" << container_key <<
|
| - "' has '" << kPnaclTranslateKey << "' inside URL spec.";
|
| - *error_string = error_stream.str();
|
| - return false;
|
| - }
|
| - // Verify the correct types of the fields if they exist.
|
| Json::Value url = url_spec[kUrlKey];
|
| if (!url.isString()) {
|
| nacl::stringstream error_stream;
|
| @@ -206,24 +172,6 @@
|
| *error_string = error_stream.str();
|
| return false;
|
| }
|
| - Json::Value cache_identity = url_spec[kCacheIdentityKey];
|
| - if (!cache_identity.empty() && !cache_identity.isString()) {
|
| - nacl::stringstream error_stream;
|
| - error_stream << parent_key << " property '" << container_key <<
|
| - "' has non-string value '" << cache_identity.toStyledString() <<
|
| - "' for key '" << kCacheIdentityKey << "'.";
|
| - *error_string = error_stream.str();
|
| - return false;
|
| - }
|
| - Json::Value opt_level = url_spec[kOptLevelKey];
|
| - if (!opt_level.empty() && !opt_level.isNumeric()) {
|
| - nacl::stringstream error_stream;
|
| - error_stream << parent_key << " property '" << container_key <<
|
| - "' has non-numeric value '" << opt_level.toStyledString() <<
|
| - "' for key '" << kOptLevelKey << "'.";
|
| - *error_string = error_stream.str();
|
| - return false;
|
| - }
|
| return true;
|
| }
|
|
|
| @@ -232,7 +180,6 @@
|
| bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec,
|
| const nacl::string& container_key,
|
| const nacl::string& parent_key,
|
| - const nacl::string& sandbox_isa,
|
| nacl::string* error_string) {
|
| static const char* kManifestPnaclSpecProperties[] = {
|
| kPnaclTranslateKey
|
| @@ -247,7 +194,7 @@
|
| }
|
| Json::Value url_spec = pnacl_spec[kPnaclTranslateKey];
|
| if (!IsValidUrlSpec(url_spec, kPnaclTranslateKey,
|
| - container_key, sandbox_isa, error_string)) {
|
| + container_key, error_string)) {
|
| return false;
|
| }
|
| return true;
|
| @@ -263,7 +210,6 @@
|
| bool IsValidISADictionary(const Json::Value& dictionary,
|
| const nacl::string& parent_key,
|
| const nacl::string& sandbox_isa,
|
| - bool must_find_matching_entry,
|
| ErrorInfo* error_info) {
|
| if (error_info == NULL) return false;
|
|
|
| @@ -274,86 +220,39 @@
|
| " property is not an ISA to URL dictionary");
|
| return false;
|
| }
|
| - // Build the set of reserved ISA dictionary keys.
|
| - const char** isaProperties;
|
| - size_t isaPropertiesLength;
|
| - if (sandbox_isa == kPortableKey) {
|
| - // The known values for PNaCl ISA dictionaries in the manifest.
|
| - static const char* kPnaclManifestISAProperties[] = {
|
| - kPortableKey
|
| - };
|
| - isaProperties = kPnaclManifestISAProperties;
|
| - isaPropertiesLength = NACL_ARRAY_SIZE(kPnaclManifestISAProperties);
|
| - } else {
|
| - // The known values for NaCl ISA dictionaries in the manifest.
|
| - static const char* kNaClManifestISAProperties[] = {
|
| + // The keys to the dictionary have to be valid ISA names.
|
| + Json::Value::Members members = dictionary.getMemberNames();
|
| + for (size_t i = 0; i < members.size(); ++i) {
|
| + // The known ISA values for ISA dictionaries in the manifest.
|
| + static const char* kManifestISAProperties[] = {
|
| kX8632Key,
|
| kX8664Key,
|
| kArmKey,
|
| - // "portable" is here to allow checking that, if present, it can
|
| - // only refer to an URL, such as for a data file, and not to
|
| - // "pnacl-translate", which would cause the creation of a nexe.
|
| kPortableKey
|
| };
|
| - isaProperties = kNaClManifestISAProperties;
|
| - isaPropertiesLength = NACL_ARRAY_SIZE(kNaClManifestISAProperties);
|
| - }
|
| - // Check that entries in the dictionary are structurally correct.
|
| - Json::Value::Members members = dictionary.getMemberNames();
|
| - for (size_t i = 0; i < members.size(); ++i) {
|
| nacl::string property_name = members[i];
|
| + if (!FindMatchingProperty(property_name,
|
| + kManifestISAProperties,
|
| + NACL_ARRAY_SIZE(kManifestISAProperties))) {
|
| + PLUGIN_PRINTF(("IsValidISADictionary: unrecognized ISA '%s'.\n",
|
| + property_name.c_str()));
|
| + }
|
| + // Could be "arch/portable" : URLSpec, or
|
| + // it could be "arch/portable" : { "pnacl-translate": URLSpec }
|
| + // for executables that need to be translated.
|
| Json::Value property_value = dictionary[property_name];
|
| nacl::string error_string;
|
| - if (FindMatchingProperty(property_name,
|
| - isaProperties,
|
| - isaPropertiesLength)) {
|
| - // For NaCl, arch entries can only be
|
| - // "arch/portable" : URLSpec
|
| - // For PNaCl arch in "program" dictionary entries can only be
|
| - // "portable" : { "pnacl-translate": URLSpec }
|
| - // For PNaCl arch elsewhere, dictionary entries can only be
|
| - // "portable" : URLSpec
|
| - if ((sandbox_isa != kPortableKey &&
|
| - !IsValidUrlSpec(property_value, property_name, parent_key,
|
| - sandbox_isa, &error_string)) ||
|
| - (sandbox_isa == kPortableKey &&
|
| - parent_key == kProgramKey &&
|
| - !IsValidPnaclTranslateSpec(property_value, property_name, parent_key,
|
| - sandbox_isa, &error_string)) ||
|
| - (sandbox_isa == kPortableKey &&
|
| - parent_key != kProgramKey &&
|
| - !IsValidUrlSpec(property_value, property_name, parent_key,
|
| - sandbox_isa, &error_string))) {
|
| - error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| - nacl::string("manifest: ") + error_string);
|
| - return false;
|
| - }
|
| - } else {
|
| - // For forward compatibility, we do not prohibit other keys being in
|
| - // the dictionary, as they may be architectures supported in later
|
| - // versions. However, the value of these entries must be an URLSpec.
|
| - PLUGIN_PRINTF(("IsValidISADictionary: unrecognized key '%s'.\n",
|
| - property_name.c_str()));
|
| - if (!IsValidUrlSpec(property_value, property_name, parent_key,
|
| - sandbox_isa, &error_string)) {
|
| - error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| - nacl::string("manifest: ") + error_string);
|
| - return false;
|
| - }
|
| + if (!IsValidUrlSpec(property_value, property_name, parent_key,
|
| + &error_string) &&
|
| + !IsValidPnaclTranslateSpec(property_value, property_name,
|
| + parent_key, &error_string)) {
|
| + error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
|
| + nacl::string("manifest: ") + error_string);
|
| + return false;
|
| }
|
| }
|
|
|
| - if (sandbox_isa == kPortableKey) {
|
| - bool has_portable = dictionary.isMember(kPortableKey);
|
| -
|
| - if (!has_portable) {
|
| - error_info->SetReport(
|
| - ERROR_MANIFEST_PROGRAM_MISSING_ARCH,
|
| - nacl::string("manifest: no version of ") + parent_key +
|
| - " given for portable.");
|
| - return false;
|
| - }
|
| - } else if (must_find_matching_entry) {
|
| + if (!sandbox_isa.empty()) {
|
| // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include
|
| // micro-architectures that can resolve to multiple valid sandboxes.
|
| bool has_isa = dictionary.isMember(sandbox_isa);
|
| @@ -394,16 +293,14 @@
|
| bool GetURLFromISADictionary(const Json::Value& dictionary,
|
| const nacl::string& parent_key,
|
| const nacl::string& sandbox_isa,
|
| + bool prefer_portable,
|
| nacl::string* url,
|
| PnaclOptions* pnacl_options,
|
| ErrorInfo* error_info) {
|
| if (url == NULL || pnacl_options == NULL || error_info == NULL)
|
| return false;
|
|
|
| - // When the application actually requests a resolved URL, we must have
|
| - // a matching entry (sandbox_isa or portable) for NaCl.
|
| - if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, true,
|
| - error_info)) {
|
| + if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, error_info)) {
|
| error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
|
| "architecture " + sandbox_isa +
|
| " is not found for file " + parent_key);
|
| @@ -417,7 +314,7 @@
|
| bool has_portable = dictionary.isMember(kPortableKey);
|
| bool has_isa = dictionary.isMember(sandbox_isa);
|
| nacl::string chosen_isa;
|
| - if ((sandbox_isa == kPortableKey) || (has_portable && !has_isa)) {
|
| + if ((has_portable && prefer_portable) || !has_isa) {
|
| chosen_isa = kPortableKey;
|
| } else {
|
| chosen_isa = sandbox_isa;
|
| @@ -426,11 +323,9 @@
|
| // Check if this requires a pnacl-translate, otherwise just grab the URL.
|
| // We may have pnacl-translate for isa-specific bitcode for CPU tuning.
|
| if (isa_spec.isMember(kPnaclTranslateKey)) {
|
| - // PNaCl
|
| GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options);
|
| pnacl_options->set_translate(true);
|
| } else {
|
| - // NaCl
|
| *url = isa_spec[kUrlKey].asString();
|
| pnacl_options->set_translate(false);
|
| }
|
| @@ -442,6 +337,7 @@
|
| const nacl::string& key,
|
| const nacl::string& sandbox_isa,
|
| const Manifest* manifest,
|
| + bool prefer_portable,
|
| nacl::string* full_url,
|
| PnaclOptions* pnacl_options,
|
| ErrorInfo* error_info) {
|
| @@ -453,8 +349,8 @@
|
| }
|
| const Json::Value& isa_dict = dictionary[key];
|
| nacl::string relative_url;
|
| - if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, &relative_url,
|
| - pnacl_options, error_info)) {
|
| + if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, prefer_portable,
|
| + &relative_url, pnacl_options, error_info)) {
|
| return false;
|
| }
|
| return manifest->ResolveURL(relative_url, full_url, error_info);
|
| @@ -514,33 +410,24 @@
|
| }
|
|
|
| // Validate the program section.
|
| - // There must be a matching (portable or sandbox_isa_) entry for program for
|
| - // NaCl.
|
| if (!IsValidISADictionary(dictionary_[kProgramKey],
|
| kProgramKey,
|
| sandbox_isa_,
|
| - true,
|
| error_info)) {
|
| return false;
|
| }
|
|
|
| // Validate the interpreter section (if given).
|
| - // There must be a matching (portable or sandbox_isa_) entry for interpreter
|
| - // for NaCl.
|
| if (dictionary_.isMember(kInterpreterKey)) {
|
| if (!IsValidISADictionary(dictionary_[kInterpreterKey],
|
| kInterpreterKey,
|
| sandbox_isa_,
|
| - true,
|
| error_info)) {
|
| return false;
|
| }
|
| }
|
|
|
| // Validate the file dictionary (if given).
|
| - // The "files" key does not require a matching (portable or sandbox_isa_)
|
| - // entry at schema validation time for NaCl. This allows manifests to specify
|
| - // resources that are only loaded for a particular sandbox_isa.
|
| if (dictionary_.isMember(kFilesKey)) {
|
| const Json::Value& files = dictionary_[kFilesKey];
|
| if (!files.isObject()) {
|
| @@ -553,8 +440,7 @@
|
| nacl::string file_name = members[i];
|
| if (!IsValidISADictionary(files[file_name],
|
| file_name,
|
| - sandbox_isa_,
|
| - false,
|
| + nacl::string(),
|
| error_info)) {
|
| return false;
|
| }
|
| @@ -598,6 +484,7 @@
|
| if (!GetURLFromISADictionary(program,
|
| kProgramKey,
|
| sandbox_isa_,
|
| + prefer_portable_,
|
| &nexe_url,
|
| pnacl_options,
|
| error_info)) {
|
| @@ -632,8 +519,8 @@
|
| return false;
|
|
|
| if (key == kProgramKey) {
|
| - return GetKeyUrl(dictionary_, key, sandbox_isa_, this, full_url,
|
| - pnacl_options, error_info);
|
| + return GetKeyUrl(dictionary_, key, sandbox_isa_, this, prefer_portable_,
|
| + full_url, pnacl_options, error_info);
|
| }
|
| nacl::string::const_iterator p = find(key.begin(), key.end(), '/');
|
| if (p == key.end()) {
|
| @@ -667,8 +554,8 @@
|
| nacl::string("ResolveKey: no such \"files\" entry: ") + key);
|
| return false;
|
| }
|
| - return GetKeyUrl(files, rest, sandbox_isa_, this, full_url, pnacl_options,
|
| - error_info);
|
| + return GetKeyUrl(files, rest, sandbox_isa_, this, prefer_portable_,
|
| + full_url, pnacl_options, error_info);
|
| }
|
|
|
| } // namespace plugin
|
|
|