blob: a86ccb39abd7d53bcfb87eb6ec9c4a0f9460e546 [file] [log] [blame]
/**
* Copyright © 2020 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "user_data_json.hpp"
#include "pel_types.hpp"
#include "user_data_formats.hpp"
#include <fifo_map.hpp>
#include <iomanip>
#include <nlohmann/json.hpp>
#include <phosphor-logging/log.hpp>
#include <sstream>
namespace openpower::pels::user_data
{
using namespace phosphor::logging;
// Use fifo_map as nlohmann::json's map. We are just ignoring the 'less'
// compare. With this map the keys are kept in FIFO order.
template <class K, class V, class dummy_compare, class A>
using fifoMap = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
using fifoJSON = nlohmann::basic_json<fifoMap>;
/**
* @brief Returns a JSON string for use by PEL::printSectionInJSON().
*
* The returning string will contain a JSON object, but without
* the outer {}. If the input JSON isn't a JSON object (dict), then
* one will be created with the input added to a 'Data' key.
*
* @param[in] json - The JSON to convert to a string
*
* @return std::string - The JSON string
*/
std::string prettyJSON(uint16_t componentID, uint8_t subType, uint8_t version,
const fifoJSON& json)
{
fifoJSON output;
output["Section Version"] = std::to_string(version);
output["Sub-section type"] = std::to_string(subType);
char value[10];
sprintf(value, "0x%04X", componentID);
output["Created by"] = std::string{value};
if (!json.is_object())
{
output["Data"] = json;
}
else
{
for (const auto& [key, value] : json.items())
{
output[key] = value;
}
}
// Let nlohmann do the pretty printing.
std::stringstream stream;
stream << std::setw(4) << output;
auto jsonString = stream.str();
// Now it looks like:
// {
// "Section Version": ...
// ...
// }
// Since PEL::printSectionInJSON() will supply the outer { }s,
// remove the existing ones.
// Replace the { and the following newline, and the } and its
// preceeding newline.
jsonString.erase(0, 2);
auto pos = jsonString.find_last_of('}');
jsonString.erase(pos - 1);
return jsonString;
}
/**
* @brief Convert to an appropriate JSON string as the data is one of
* the formats that we natively support.
*
* @param[in] componentID - The comp ID from the UserData section header
* @param[in] subType - The subtype from the UserData section header
* @param[in] version - The version from the UserData section header
* @param[in] data - The data itself
*
* @return std::optional<std::string> - The JSON string if it could be created,
* else std::nullopt.
*/
std::optional<std::string>
getBuiltinFormatJSON(uint16_t componentID, uint8_t subType, uint8_t version,
const std::vector<uint8_t>& data)
{
switch (subType)
{
case static_cast<uint8_t>(UserDataFormat::json):
{
std::string jsonString{data.begin(), data.begin() + data.size()};
fifoJSON json = nlohmann::json::parse(jsonString);
return prettyJSON(componentID, subType, version, json);
}
default:
break;
}
return std::nullopt;
}
std::optional<std::string> getJSON(uint16_t componentID, uint8_t subType,
uint8_t version,
const std::vector<uint8_t>& data)
{
try
{
switch (componentID)
{
case static_cast<uint16_t>(ComponentID::phosphorLogging):
return getBuiltinFormatJSON(componentID, subType, version,
data);
default:
break;
}
}
catch (std::exception& e)
{
log<level::ERR>("Failed parsing UserData", entry("ERROR=%s", e.what()));
}
return std::nullopt;
}
} // namespace openpower::pels::user_data