1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/importers/json/json_utils.h"
18
19 #include "perfetto/base/build_config.h"
20
21 #include <limits>
22
23 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
24 #include <json/reader.h>
25 #include "perfetto/ext/base/string_utils.h"
26 #endif
27
28 namespace perfetto {
29 namespace trace_processor {
30 namespace json {
31
IsJsonSupported()32 bool IsJsonSupported() {
33 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
34 return true;
35 #else
36 return false;
37 #endif
38 }
39
CoerceToTs(const Json::Value & value)40 base::Optional<int64_t> CoerceToTs(const Json::Value& value) {
41 PERFETTO_DCHECK(IsJsonSupported());
42
43 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
44 switch (static_cast<size_t>(value.type())) {
45 case Json::realValue:
46 return static_cast<int64_t>(value.asDouble() * 1000.0);
47 case Json::uintValue:
48 case Json::intValue:
49 return value.asInt64() * 1000;
50 case Json::stringValue:
51 return CoerceToTs(value.asString());
52 default:
53 return base::nullopt;
54 }
55 #else
56 perfetto::base::ignore_result(value);
57 return base::nullopt;
58 #endif
59 }
60
CoerceToTs(const std::string & s)61 base::Optional<int64_t> CoerceToTs(const std::string& s) {
62 PERFETTO_DCHECK(IsJsonSupported());
63
64 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
65 size_t lhs_end = std::min<size_t>(s.find('.'), s.size());
66 size_t rhs_start = std::min<size_t>(lhs_end + 1, s.size());
67 base::Optional<int64_t> lhs = base::StringToInt64(s.substr(0, lhs_end));
68 base::Optional<double> rhs =
69 base::StringToDouble("0." + s.substr(rhs_start, std::string::npos));
70 if ((!lhs.has_value() && lhs_end > 0) ||
71 (!rhs.has_value() && rhs_start < s.size())) {
72 return base::nullopt;
73 }
74 return lhs.value_or(0) * 1000 +
75 static_cast<int64_t>(rhs.value_or(0) * 1000.0);
76 #else
77 perfetto::base::ignore_result(s);
78 return base::nullopt;
79 #endif
80 }
81
CoerceToInt64(const Json::Value & value)82 base::Optional<int64_t> CoerceToInt64(const Json::Value& value) {
83 PERFETTO_DCHECK(IsJsonSupported());
84
85 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
86 switch (static_cast<size_t>(value.type())) {
87 case Json::realValue:
88 case Json::uintValue:
89 return static_cast<int64_t>(value.asUInt64());
90 case Json::intValue:
91 return value.asInt64();
92 case Json::stringValue: {
93 std::string s = value.asString();
94 char* end;
95 int64_t n = strtoll(s.c_str(), &end, 10);
96 if (end != s.data() + s.size())
97 return base::nullopt;
98 return n;
99 }
100 default:
101 return base::nullopt;
102 }
103 #else
104 perfetto::base::ignore_result(value);
105 return base::nullopt;
106 #endif
107 }
108
CoerceToUint32(const Json::Value & value)109 base::Optional<uint32_t> CoerceToUint32(const Json::Value& value) {
110 PERFETTO_DCHECK(IsJsonSupported());
111
112 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
113 base::Optional<int64_t> result = CoerceToInt64(value);
114 if (!result.has_value())
115 return base::nullopt;
116 int64_t n = result.value();
117 if (n < 0 || n > std::numeric_limits<uint32_t>::max())
118 return base::nullopt;
119 return static_cast<uint32_t>(n);
120 #else
121 perfetto::base::ignore_result(value);
122 return base::nullopt;
123 #endif
124 }
125
ParseJsonString(base::StringView raw_string)126 base::Optional<Json::Value> ParseJsonString(base::StringView raw_string) {
127 PERFETTO_DCHECK(IsJsonSupported());
128
129 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
130 Json::CharReaderBuilder b;
131 auto reader = std::unique_ptr<Json::CharReader>(b.newCharReader());
132
133 Json::Value value;
134 const char* begin = raw_string.data();
135 return reader->parse(begin, begin + raw_string.size(), &value, nullptr)
136 ? base::make_optional(std::move(value))
137 : base::nullopt;
138 #else
139 perfetto::base::ignore_result(raw_string);
140 return base::nullopt;
141 #endif
142 }
143
AddJsonValueToArgs(const Json::Value & value,base::StringView flat_key,base::StringView key,TraceStorage * storage,ArgsTracker::BoundInserter * inserter)144 bool AddJsonValueToArgs(const Json::Value& value,
145 base::StringView flat_key,
146 base::StringView key,
147 TraceStorage* storage,
148 ArgsTracker::BoundInserter* inserter) {
149 PERFETTO_DCHECK(IsJsonSupported());
150
151 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
152 if (value.isObject()) {
153 auto it = value.begin();
154 bool inserted = false;
155 for (; it != value.end(); ++it) {
156 std::string child_name = it.name();
157 std::string child_flat_key = flat_key.ToStdString() + "." + child_name;
158 std::string child_key = key.ToStdString() + "." + child_name;
159 inserted |=
160 AddJsonValueToArgs(*it, base::StringView(child_flat_key),
161 base::StringView(child_key), storage, inserter);
162 }
163 return inserted;
164 }
165
166 if (value.isArray()) {
167 auto it = value.begin();
168 bool inserted_any = false;
169 std::string array_key = key.ToStdString();
170 StringId array_key_id = storage->InternString(key);
171 for (; it != value.end(); ++it) {
172 size_t array_index = inserter->GetNextArrayEntryIndex(array_key_id);
173 std::string child_key =
174 array_key + "[" + std::to_string(array_index) + "]";
175 bool inserted = AddJsonValueToArgs(
176 *it, flat_key, base::StringView(child_key), storage, inserter);
177 if (inserted)
178 inserter->IncrementArrayEntryIndex(array_key_id);
179 inserted_any |= inserted;
180 }
181 return inserted_any;
182 }
183
184 // Leaf value.
185 auto flat_key_id = storage->InternString(flat_key);
186 auto key_id = storage->InternString(key);
187
188 switch (value.type()) {
189 case Json::ValueType::nullValue:
190 break;
191 case Json::ValueType::intValue:
192 inserter->AddArg(flat_key_id, key_id, Variadic::Integer(value.asInt64()));
193 return true;
194 case Json::ValueType::uintValue:
195 inserter->AddArg(flat_key_id, key_id,
196 Variadic::UnsignedInteger(value.asUInt64()));
197 return true;
198 case Json::ValueType::realValue:
199 inserter->AddArg(flat_key_id, key_id, Variadic::Real(value.asDouble()));
200 return true;
201 case Json::ValueType::stringValue:
202 inserter->AddArg(flat_key_id, key_id,
203 Variadic::String(storage->InternString(
204 base::StringView(value.asString()))));
205 return true;
206 case Json::ValueType::booleanValue:
207 inserter->AddArg(flat_key_id, key_id, Variadic::Boolean(value.asBool()));
208 return true;
209 case Json::ValueType::objectValue:
210 case Json::ValueType::arrayValue:
211 PERFETTO_FATAL("Non-leaf types handled above");
212 break;
213 }
214 return false;
215 #else
216 perfetto::base::ignore_result(value);
217 perfetto::base::ignore_result(flat_key);
218 perfetto::base::ignore_result(key);
219 perfetto::base::ignore_result(storage);
220 perfetto::base::ignore_result(inserter);
221 return false;
222 #endif
223 }
224
225 } // namespace json
226 } // namespace trace_processor
227 } // namespace perfetto
228