blob: 030a509132c91aee41ef50a3c44b314eda58675d [file] [log] [blame]
// Copyright 2017 The Chromium OS 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 <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/json/json_reader.h>
//#include <base/logging.h>
#include <base/values.h>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>
#include "manifest.h"
namespace huddly {
namespace {
const int kAcceptableManifestVersionMin = 2;
const int kAcceptableManifestVersionMax = 2;
const int kManifestVersionUnknown = -1;
} // namespace
bool Manifest::ParseFile() {
std::string content = GetFileContent(path_);
if (content.empty()) {
std::cout << "..Empty content of file: " << path_.value() << "\n";
return false;
}
// Note: |root_dic| is valid only during |root| is alive.
#ifdef __ANDROID__
scoped_ptr<base::Value> root =
base::JSONReader().Read(content, base::JSON_PARSE_RFC);
#else
auto root = base::JSONReader::Read(content, base::JSON_PARSE_RFC);
#endif
if (!root) {
std::cout << "..No root is found in JSON dict in file: " << path_.value()
<< "\n";
return false;
}
if (!root->is_dict()) {
std::cout << "..Failed to read as dictionary from file: " << path_.value()
<< "\n";
return false;
}
manifest_ver_ = ParseManifestVersion(*root);
if (!IsCompatible(manifest_ver_)) {
std::cout << "..ParseManifestDict failed: manifest version "
<< manifest_ver_
<< " is incompatible from file: " << path_.value() << "\n";
return false;
}
// Parse strings: Upon internal failures, empty strings are returned.
ParseHardwareRev(*root, &hw_rev_);
ParseFirmwareFileVersions(*root, &app_ver_, &boot_ver_);
return true;
}
int Manifest::ParseManifestVersion(const base::Value& dic) {
CHECK(dic.is_dict());
// key: manifest_version
auto manifest_version = dic.FindIntKey("manifest_version");
if (!manifest_version.has_value()) {
std::cout << "..failed to parse manifest_version. Default to "
<< kManifestVersionUnknown << "\n";
return kManifestVersionUnknown;
}
return *manifest_version;
}
bool Manifest::IsCompatible(int manifest_ver) {
bool result = (kAcceptableManifestVersionMin <= manifest_ver) &&
(manifest_ver <= kAcceptableManifestVersionMax);
if (!result) {
std::cout << "..Manifest version " << manifest_ver
<< " is outside the supported range: ["
<< kAcceptableManifestVersionMin << ", "
<< kAcceptableManifestVersionMax << "]"
<< "\n";
}
return result;
}
void Manifest::ParseFirmwareFileVersions(const base::Value& dic,
std::string* app_ver,
std::string* boot_ver) {
CHECK(dic.is_dict());
*app_ver = "";
*boot_ver = "";
// key: files
const base::Value* files_list = dic.FindListKey("files");
if (!files_list) {
std::cout << "failed to parse in finding 'files' key"
<< "\n";
return;
}
for (const auto& elem : files_list->GetList()) {
if (!elem.is_dict()) {
std::cout << "failed to parse an files element as dictionary"
<< "\n";
continue;
}
const std::string* type = elem.FindStringKey("type");
if (!type) {
std::cout << "failed to parse type as string";
continue;
}
const base::Value* version_dic = elem.FindDictKey("version");
if (!version_dic) {
std::cout << "failed to parse version as dictionary";
continue;
}
const base::Value* numerical_list = version_dic->FindListKey("numerical");
if (!numerical_list) {
std::cout << "failed to parse numerical as list";
continue;
}
std::string numerical_str = ListToStr(*numerical_list, ".");
if (*type == "mv2_boot") {
*boot_ver = numerical_str;
} else if (*type == "mv2_app") {
*app_ver = numerical_str;
}
}
}
std::string Manifest::ListToStr(const base::Value& list_val,
const std::string& separator) {
CHECK(list_val.is_list());
std::string result = "";
for (const auto& val : list_val.GetList()) {
if (!val.is_int()) {
std::cout << "failed to parse value as integer from list value"
<< "\n";
continue;
}
result.append(std::to_string(val.GetInt()));
result.append(separator);
}
result.pop_back(); // Drop the last separator;
return result;
}
void Manifest::ParseHardwareRev(const base::Value& dic,
std::string* hw_rev) {
*hw_rev = "";
// key: compatible_hw
const base::Value* compatible_hw_list = dic.FindListKey("compatible_hw");
if (!compatible_hw_list) {
std::cout << "failed to parse in finding 'compatible_hw' key'"
<< "\n";
return; // returning empty string |hw_rev|.
}
for (const auto& compatible_hw_dic : compatible_hw_list->GetList()) {
if (!compatible_hw_dic.is_dict()) {
std::cout << "failed to parse 'compatible_hw' element as dictionary"
<< "\n";
continue;
}
const base::Value* rev_list = compatible_hw_dic.FindListKey("hwrevs");
if (!rev_list) {
std::cout << "failed to parse hwrevs as list"
<< "\n";
continue;
}
*hw_rev = ListToStr(*rev_list, ",");
}
}
std::string Manifest::GetFileContent(const base::FilePath& path) {
std::string content;
if (!ReadFileToString(path, &content)) {
return "";
}
return content;
}
void Manifest::Dump() {
std::cout << "Manifest file: " << path_.value() << "\n";
std::cout << "Manifest ver : " << manifest_ver_ << "\n";
std::cout << "App ver : " << app_ver_ << "\n";
std::cout << "Boot ver : " << boot_ver_ << "\n";
std::cout << "Hardware rev : " << hw_rev_ << "\n";
}
} // namespace huddly