xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/json/json_utils.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 
CoerceToTs(const Json::Value & value)32 std::optional<int64_t> CoerceToTs(const Json::Value& value) {
33   PERFETTO_DCHECK(IsJsonSupported());
34 
35 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
36   switch (static_cast<size_t>(value.type())) {
37     case Json::realValue:
38       return static_cast<int64_t>(value.asDouble() * 1000.0);
39     case Json::uintValue:
40     case Json::intValue:
41       return value.asInt64() * 1000;
42     case Json::stringValue:
43       return CoerceToTs(value.asString());
44     default:
45       return std::nullopt;
46   }
47 #else
48   perfetto::base::ignore_result(value);
49   return std::nullopt;
50 #endif
51 }
52 
CoerceToTs(const std::string & s)53 std::optional<int64_t> CoerceToTs(const std::string& s) {
54   PERFETTO_DCHECK(IsJsonSupported());
55 
56 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
57   // 's' is formatted as a JSON Number, in microseconds
58   // goal: reformat 's' to be as an int, in nanoseconds
59   std::string s_as_ns = s;
60 
61   // detect and remove scientific notation's exponents
62   int32_t exp_shift = 0;
63   if (size_t exp_start = s.find_first_of("eE");
64       exp_start != std::string::npos) {
65     const std::string exp_s = s.substr(exp_start + 1, s.size());
66     const std::optional<int32_t> exp = base::StringToInt32(exp_s);
67     if (!exp.has_value()) {
68       return std::nullopt;
69     }
70     s_as_ns.erase(exp_start);
71     exp_shift = *exp;
72   }
73 
74   // detect and remove decimal separator
75   size_t int_size = s_as_ns.size();
76   if (size_t frac_start = s.find('.'); frac_start != std::string::npos) {
77     s_as_ns.erase(frac_start, 1);
78     int_size = frac_start;
79   }
80 
81   // expand or shrink to the new size
82   constexpr int us_to_ns_shift = 3;
83   const size_t s_as_ns_size = size_t(
84       std::max<ptrdiff_t>(1, ptrdiff_t(int_size) + exp_shift + us_to_ns_shift));
85   s_as_ns.resize(s_as_ns_size, '0');  // pads or truncates
86 
87   return base::StringToInt64(s_as_ns);
88 #else
89   perfetto::base::ignore_result(s);
90   return std::nullopt;
91 #endif
92 }
93 
CoerceToInt64(const Json::Value & value)94 std::optional<int64_t> CoerceToInt64(const Json::Value& value) {
95   PERFETTO_DCHECK(IsJsonSupported());
96 
97 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
98   switch (static_cast<size_t>(value.type())) {
99     case Json::realValue:
100     case Json::uintValue:
101       return static_cast<int64_t>(value.asUInt64());
102     case Json::intValue:
103       return value.asInt64();
104     case Json::stringValue: {
105       std::string s = value.asString();
106       char* end;
107       int64_t n = strtoll(s.c_str(), &end, 10);
108       if (end != s.data() + s.size())
109         return std::nullopt;
110       return n;
111     }
112     default:
113       return std::nullopt;
114   }
115 #else
116   perfetto::base::ignore_result(value);
117   return std::nullopt;
118 #endif
119 }
120 
CoerceToUint32(const Json::Value & value)121 std::optional<uint32_t> CoerceToUint32(const Json::Value& value) {
122   PERFETTO_DCHECK(IsJsonSupported());
123 
124 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
125   std::optional<int64_t> result = CoerceToInt64(value);
126   if (!result.has_value())
127     return std::nullopt;
128   int64_t n = result.value();
129   if (n < 0 || n > std::numeric_limits<uint32_t>::max())
130     return std::nullopt;
131   return static_cast<uint32_t>(n);
132 #else
133   perfetto::base::ignore_result(value);
134   return std::nullopt;
135 #endif
136 }
137 
ParseJsonString(base::StringView raw_string)138 std::optional<Json::Value> ParseJsonString(base::StringView raw_string) {
139   PERFETTO_DCHECK(IsJsonSupported());
140 
141 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
142   Json::CharReaderBuilder b;
143   auto reader = std::unique_ptr<Json::CharReader>(b.newCharReader());
144 
145   Json::Value value;
146   const char* begin = raw_string.data();
147   return reader->parse(begin, begin + raw_string.size(), &value, nullptr)
148              ? std::make_optional(std::move(value))
149              : std::nullopt;
150 #else
151   perfetto::base::ignore_result(raw_string);
152   return std::nullopt;
153 #endif
154 }
155 
AddJsonValueToArgs(const Json::Value & value,base::StringView flat_key,base::StringView key,TraceStorage * storage,ArgsTracker::BoundInserter * inserter)156 bool AddJsonValueToArgs(const Json::Value& value,
157                         base::StringView flat_key,
158                         base::StringView key,
159                         TraceStorage* storage,
160                         ArgsTracker::BoundInserter* inserter) {
161   PERFETTO_DCHECK(IsJsonSupported());
162 
163 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
164   if (value.isObject()) {
165     auto it = value.begin();
166     bool inserted = false;
167     for (; it != value.end(); ++it) {
168       std::string child_name = it.name();
169       std::string child_flat_key = flat_key.ToStdString() + "." + child_name;
170       std::string child_key = key.ToStdString() + "." + child_name;
171       inserted |=
172           AddJsonValueToArgs(*it, base::StringView(child_flat_key),
173                              base::StringView(child_key), storage, inserter);
174     }
175     return inserted;
176   }
177 
178   if (value.isArray()) {
179     auto it = value.begin();
180     bool inserted_any = false;
181     std::string array_key = key.ToStdString();
182     StringId array_key_id = storage->InternString(key);
183     for (; it != value.end(); ++it) {
184       size_t array_index = inserter->GetNextArrayEntryIndex(array_key_id);
185       std::string child_key =
186           array_key + "[" + std::to_string(array_index) + "]";
187       bool inserted = AddJsonValueToArgs(
188           *it, flat_key, base::StringView(child_key), storage, inserter);
189       if (inserted)
190         inserter->IncrementArrayEntryIndex(array_key_id);
191       inserted_any |= inserted;
192     }
193     return inserted_any;
194   }
195 
196   // Leaf value.
197   auto flat_key_id = storage->InternString(flat_key);
198   auto key_id = storage->InternString(key);
199 
200   switch (value.type()) {
201     case Json::ValueType::nullValue:
202       break;
203     case Json::ValueType::intValue:
204       inserter->AddArg(flat_key_id, key_id, Variadic::Integer(value.asInt64()));
205       return true;
206     case Json::ValueType::uintValue:
207       inserter->AddArg(flat_key_id, key_id,
208                        Variadic::UnsignedInteger(value.asUInt64()));
209       return true;
210     case Json::ValueType::realValue:
211       inserter->AddArg(flat_key_id, key_id, Variadic::Real(value.asDouble()));
212       return true;
213     case Json::ValueType::stringValue:
214       inserter->AddArg(flat_key_id, key_id,
215                        Variadic::String(storage->InternString(
216                            base::StringView(value.asString()))));
217       return true;
218     case Json::ValueType::booleanValue:
219       inserter->AddArg(flat_key_id, key_id, Variadic::Boolean(value.asBool()));
220       return true;
221     case Json::ValueType::objectValue:
222     case Json::ValueType::arrayValue:
223       PERFETTO_FATAL("Non-leaf types handled above");
224       break;
225   }
226   return false;
227 #else
228   perfetto::base::ignore_result(value);
229   perfetto::base::ignore_result(flat_key);
230   perfetto::base::ignore_result(key);
231   perfetto::base::ignore_result(storage);
232   perfetto::base::ignore_result(inserter);
233   return false;
234 #endif
235 }
236 
237 }  // namespace json
238 }  // namespace trace_processor
239 }  // namespace perfetto
240