blob: 78e06a380b0b78276e01ea228ede211f887a3e3e [file] [log] [blame]
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "print_tools/ipp_in_json.h"
6
7#include <memory>
8#include <utility>
9
10#include <base/json/json_writer.h>
11#include <base/macros.h>
hscham2e0b8ef2020-11-05 11:45:57 +090012#include <base/optional.h>
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070013#include <base/values.h>
14
15namespace {
16
hscham2e0b8ef2020-11-05 11:45:57 +090017base::Value SaveAsJson(const ipp::Collection* coll);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070018
19// It saves a single value (at given index) from the attribute as JSON
20// structure. The parameter "attr" cannot be nullptr, "index" must be correct.
hscham2e0b8ef2020-11-05 11:45:57 +090021base::Value SaveAsJson(const ipp::Attribute* attr, unsigned index) {
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070022 CHECK(attr != nullptr);
23 CHECK(index < attr->GetSize());
24 using AttrType = ipp::AttrType;
25 switch (attr->GetType()) {
26 case AttrType::integer: {
27 int vi;
28 attr->GetValue(&vi, index);
hscham2e0b8ef2020-11-05 11:45:57 +090029 return base::Value(vi);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070030 }
31 case AttrType::boolean: {
32 int vb;
33 attr->GetValue(&vb, index);
hscham2e0b8ef2020-11-05 11:45:57 +090034 return base::Value(static_cast<bool>(vb));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070035 }
36 case AttrType::enum_: {
37 std::string vs;
38 attr->GetValue(&vs, index);
39 if (vs.empty()) {
40 int vi;
41 attr->GetValue(&vi, index);
hscham2e0b8ef2020-11-05 11:45:57 +090042 return base::Value(vi);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070043 }
hscham2e0b8ef2020-11-05 11:45:57 +090044 return base::Value(vs);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070045 }
46 case AttrType::collection:
47 return SaveAsJson(attr->GetCollection(index));
48 case AttrType::text:
49 case AttrType::name: {
50 ipp::StringWithLanguage vs;
51 attr->GetValue(&vs, index);
52 if (vs.language.empty())
hscham2e0b8ef2020-11-05 11:45:57 +090053 return base::Value(vs.value);
54 base::Value obj(base::Value::Type::DICTIONARY);
55 obj.SetStringKey("value", vs.value);
56 obj.SetStringKey("language", vs.language);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070057 return obj;
58 }
59 case AttrType::dateTime:
60 case AttrType::resolution:
61 case AttrType::rangeOfInteger:
62 case AttrType::octetString:
63 case AttrType::keyword:
64 case AttrType::uri:
65 case AttrType::uriScheme:
66 case AttrType::charset:
67 case AttrType::naturalLanguage:
68 case AttrType::mimeMediaType: {
69 std::string vs;
70 attr->GetValue(&vs, index);
hscham2e0b8ef2020-11-05 11:45:57 +090071 return base::Value(vs);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070072 }
73 }
hscham2e0b8ef2020-11-05 11:45:57 +090074 return base::Value(); // not reachable
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070075}
76
77// It saves all attribute's values as JSON structure.
78// The parameter "attr" cannot be nullptr.
hscham2e0b8ef2020-11-05 11:45:57 +090079base::Value SaveAsJson(const ipp::Attribute* attr) {
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070080 CHECK(attr != nullptr);
81 if (attr->IsASet()) {
hscham2e0b8ef2020-11-05 11:45:57 +090082 base::Value arr(base::Value::Type::LIST);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070083 const unsigned size = attr->GetSize();
84 for (unsigned i = 0; i < size; ++i)
hscham2e0b8ef2020-11-05 11:45:57 +090085 arr.Append(SaveAsJson(attr, i));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070086 return arr;
87 } else {
88 return SaveAsJson(attr, 0);
89 }
90}
91
92// It saves a given Collection as JSON object.
93// The parameter "coll" cannot be nullptr.
hscham2e0b8ef2020-11-05 11:45:57 +090094base::Value SaveAsJson(const ipp::Collection* coll) {
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070095 CHECK(coll != nullptr);
hscham2e0b8ef2020-11-05 11:45:57 +090096 base::Value obj(base::Value::Type::DICTIONARY);
Piotr Pawliczek70ef9a32019-12-03 12:16:16 -080097 std::vector<const ipp::Attribute*> attrs = coll->GetAllAttributes();
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -070098
99 for (auto a : attrs) {
100 auto state = a->GetState();
101 if (state == ipp::AttrState::unset)
102 continue;
103
104 if (state == ipp::AttrState::set) {
hscham2e0b8ef2020-11-05 11:45:57 +0900105 base::Value obj2(base::Value::Type::DICTIONARY);
106 obj2.SetStringKey("type", ToString(a->GetType()));
107 obj2.SetKey("value", SaveAsJson(a));
108 obj.SetKey(a->GetName(), std::move(obj2));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700109 } else {
hscham2e0b8ef2020-11-05 11:45:57 +0900110 obj.SetStringKey(a->GetName(), ToString(state));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700111 }
112 }
113
114 return obj;
115}
116
117// It saves all groups from given Package as JSON object.
118// The parameter "pkg" cannot be nullptr.
hscham2e0b8ef2020-11-05 11:45:57 +0900119base::Value SaveAsJson(const ipp::Package* pkg) {
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700120 CHECK(pkg != nullptr);
hscham2e0b8ef2020-11-05 11:45:57 +0900121 base::Value obj(base::Value::Type::DICTIONARY);
Piotr Pawliczek70ef9a32019-12-03 12:16:16 -0800122 std::vector<const ipp::Group*> groups = pkg->GetAllGroups();
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700123
124 for (auto g : groups) {
Piotr Pawliczek5a6380a2020-02-03 13:04:25 -0800125 const size_t size = g->GetSize();
126 if (size == 0)
127 continue;
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700128 if (g->IsASet()) {
hscham2e0b8ef2020-11-05 11:45:57 +0900129 base::Value arr(base::Value::Type::LIST);
Piotr Pawliczek5a6380a2020-02-03 13:04:25 -0800130 for (size_t i = 0; i < size; ++i)
hscham2e0b8ef2020-11-05 11:45:57 +0900131 arr.Append(SaveAsJson(g->GetCollection(i)));
132 obj.SetKey(ToString(g->GetName()), std::move(arr));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700133 } else {
hscham2e0b8ef2020-11-05 11:45:57 +0900134 obj.SetKey(ToString(g->GetName()), SaveAsJson(g->GetCollection()));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700135 }
136 }
137
138 return obj;
139}
140
141// Saves given logs as JSON array.
hscham2e0b8ef2020-11-05 11:45:57 +0900142base::Value SaveAsJson(const std::vector<ipp::Log>& log) {
143 base::Value arr(base::Value::Type::LIST);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700144 for (const auto& l : log) {
hscham2e0b8ef2020-11-05 11:45:57 +0900145 base::Value obj(base::Value::Type::DICTIONARY);
146 obj.SetStringKey("message", l.message);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700147 if (!l.frame_context.empty())
hscham2e0b8ef2020-11-05 11:45:57 +0900148 obj.SetStringKey("frame_context", l.frame_context);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700149 if (!l.parser_context.empty())
hscham2e0b8ef2020-11-05 11:45:57 +0900150 obj.SetStringKey("parser_context", l.parser_context);
151 arr.Append(std::move(obj));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700152 }
153 return arr;
154}
155
156} // namespace
157
Piotr Pawliczek70ef9a32019-12-03 12:16:16 -0800158bool ConvertToJson(const ipp::Response& response,
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700159 const std::vector<ipp::Log>& log,
160 bool compressed_json,
161 std::string* json) {
162 // Build structure.
hscham2e0b8ef2020-11-05 11:45:57 +0900163 base::Value doc(base::Value::Type::DICTIONARY);
164 doc.SetStringKey("status", ipp::ToString(response.StatusCode()));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700165 if (!log.empty()) {
hscham2e0b8ef2020-11-05 11:45:57 +0900166 doc.SetKey("parsing_logs", SaveAsJson(log));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700167 }
hscham2e0b8ef2020-11-05 11:45:57 +0900168 doc.SetKey("response", SaveAsJson(&response));
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700169 // Convert to JSON.
170 bool result;
171 if (compressed_json) {
hscham2e0b8ef2020-11-05 11:45:57 +0900172 result = base::JSONWriter::Write(doc, json);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700173 } else {
174 const int options = base::JSONWriter::OPTIONS_PRETTY_PRINT;
hscham2e0b8ef2020-11-05 11:45:57 +0900175 result = base::JSONWriter::WriteWithOptions(doc, options, json);
Piotr Pawliczeke8650ea2019-08-10 20:14:07 -0700176 }
177 return result;
178}