| // Copyright 2019 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "ipp_in_json.h" | |
| #include <memory> | |
| #include <utility> | |
| #include <base/check.h> | |
| #include <base/json/json_writer.h> | |
| #include <base/values.h> | |
| #include <chromeos/libipp/attribute.h> | |
| #include <chromeos/libipp/frame.h> | |
| #include <chromeos/libipp/ipp_enums.h> | |
| #include <chromeos/libipp/parser.h> | |
| namespace { | |
| base::Value SaveAsJson(const ipp::Collection& coll); | |
| // Converts `value` from the attribute `attr` to base::Value. | |
| template <typename ValueType> | |
| base::Value SaveValueAsJson(const ipp::Attribute& attr, | |
| const ValueType& value) { | |
| return base::Value(ipp::ToString(value)); | |
| } | |
| template <> | |
| base::Value SaveValueAsJson<int32_t>(const ipp::Attribute& attr, | |
| const int32_t& value) { | |
| if (attr.Tag() == ipp::ValueTag::boolean) | |
| return base::Value(static_cast<bool>(value)); | |
| if (attr.Tag() == ipp::ValueTag::enum_) { | |
| ipp::AttrName attrName; | |
| if (ipp::FromString(std::string(attr.Name()), &attrName)) { | |
| return base::Value(ipp::ToString(attrName, value)); | |
| } | |
| } | |
| return base::Value(value); | |
| } | |
| template <> | |
| base::Value SaveValueAsJson<std::string>(const ipp::Attribute& attr, | |
| const std::string& value) { | |
| return base::Value(value); | |
| } | |
| template <> | |
| base::Value SaveValueAsJson<ipp::StringWithLanguage>( | |
| const ipp::Attribute& attr, const ipp::StringWithLanguage& value) { | |
| base::Value::Dict obj; | |
| obj.Set("value", value.value); | |
| obj.Set("language", value.language); | |
| return base::Value(std::move(obj)); | |
| } | |
| // Converts all values from `attr` to base::Value. The type of values must match | |
| // `ValueType`. | |
| template <typename ValueType> | |
| base::Value SaveValuesAsJsonTyped(const ipp::Attribute& attr) { | |
| std::vector<ValueType> values; | |
| attr.GetValues(values); | |
| if (values.size() > 1) { | |
| base::Value::List arr; | |
| for (size_t i = 0; i < values.size(); ++i) | |
| arr.Append(SaveValueAsJson(attr, values[i])); | |
| return base::Value(std::move(arr)); | |
| } else { | |
| return SaveValueAsJson(attr, values.at(0)); | |
| } | |
| } | |
| template <> | |
| base::Value SaveValuesAsJsonTyped<const ipp::Collection&>( | |
| const ipp::Attribute& attr) { | |
| ipp::ConstCollsView colls = attr.Colls(); | |
| if (colls.size() > 1) { | |
| base::Value::List arr; | |
| for (const ipp::Collection& coll : colls) | |
| arr.Append(SaveAsJson(coll)); | |
| return base::Value(std::move(arr)); | |
| } else { | |
| return SaveAsJson(colls[0]); | |
| } | |
| } | |
| // It saves all attribute's values as JSON structure. | |
| base::Value SaveValuesAsJson(const ipp::Attribute& attr) { | |
| switch (attr.Tag()) { | |
| case ipp::ValueTag::textWithLanguage: | |
| case ipp::ValueTag::nameWithLanguage: | |
| return SaveValuesAsJsonTyped<ipp::StringWithLanguage>(attr); | |
| case ipp::ValueTag::dateTime: | |
| return SaveValuesAsJsonTyped<ipp::DateTime>(attr); | |
| case ipp::ValueTag::resolution: | |
| return SaveValuesAsJsonTyped<ipp::Resolution>(attr); | |
| case ipp::ValueTag::rangeOfInteger: | |
| return SaveValuesAsJsonTyped<ipp::RangeOfInteger>(attr); | |
| case ipp::ValueTag::collection: | |
| return SaveValuesAsJsonTyped<const ipp::Collection&>(attr); | |
| default: | |
| if (ipp::IsInteger(attr.Tag())) | |
| return SaveValuesAsJsonTyped<int32_t>(attr); | |
| return SaveValuesAsJsonTyped<std::string>(attr); | |
| } | |
| } | |
| // It saves a given Collection as JSON object. | |
| base::Value SaveAsJson(const ipp::Collection& coll) { | |
| base::Value::Dict obj; | |
| for (const ipp::Attribute& a : coll) { | |
| auto tag = a.Tag(); | |
| if (!ipp::IsOutOfBand(tag)) { | |
| base::Value::Dict obj2; | |
| obj2.Set("type", ipp::ToStrView(tag)); | |
| obj2.Set("value", SaveValuesAsJson(a)); | |
| obj.Set(a.Name(), std::move(obj2)); | |
| } else { | |
| obj.Set(a.Name(), ipp::ToStrView(tag)); | |
| } | |
| } | |
| return base::Value(std::move(obj)); | |
| } | |
| // It saves all groups from given Package as JSON object. | |
| base::Value SaveAsJson(const ipp::Frame& pkg) { | |
| base::Value::Dict obj; | |
| for (ipp::GroupTag gt : ipp::kGroupTags) { | |
| auto groups = pkg.Groups(gt); | |
| if (groups.empty()) | |
| continue; | |
| if (groups.size() > 1) { | |
| base::Value::List arr; | |
| for (const ipp::Collection& g : groups) | |
| arr.Append(SaveAsJson(g)); | |
| obj.Set(ToString(gt), std::move(arr)); | |
| } else { | |
| obj.Set(ToString(gt), SaveAsJson(groups[0])); | |
| } | |
| } | |
| return base::Value(std::move(obj)); | |
| } | |
| // Saves given logs as JSON array. | |
| base::Value SaveAsJson(const ipp::SimpleParserLog& log) { | |
| base::Value::List arr; | |
| for (const auto& l : log.Errors()) { | |
| arr.Append(base::Value(ipp::ToString(l))); | |
| } | |
| return base::Value(std::move(arr)); | |
| } | |
| } // namespace | |
| bool ConvertToJson(const ipp::Frame& response, | |
| const ipp::SimpleParserLog& log, | |
| bool compressed_json, | |
| std::string* json) { | |
| // Build structure. | |
| base::Value::Dict doc; | |
| doc.Set("status", ipp::ToString(response.StatusCode())); | |
| if (!log.Errors().empty()) { | |
| doc.Set("parsing_logs", SaveAsJson(log)); | |
| } | |
| doc.Set("response", SaveAsJson(response)); | |
| // Convert to JSON. | |
| bool result; | |
| if (compressed_json) { | |
| result = base::JSONWriter::Write(doc, json); | |
| } else { | |
| const int options = base::JSONWriter::OPTIONS_PRETTY_PRINT; | |
| result = base::JSONWriter::WriteWithOptions(doc, options, json); | |
| } | |
| return result; | |
| } |