blob: 7c25a79408e17f7e167ee0c12920371d71490e8d [file]
/*
* Copyright (C) 2025 The Android Open Source Project
*
* 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 "src/trace_processor/util/json_writer.h"
#include <cmath>
#include <cstdint>
#include <functional>
#include <string>
#include <string_view>
#include <utility>
#include "perfetto/ext/base/dynamic_string_writer.h"
#include "perfetto/ext/base/string_utils.h"
namespace perfetto::trace_processor::json {
namespace {
// Helper function to write an escaped JSON string.
void WriteEscapedJsonString(base::DynamicStringWriter& writer,
std::string_view value) {
writer.AppendChar('"');
for (char c : value) {
unsigned char uc = static_cast<unsigned char>(c);
if (c == '"') {
writer.AppendLiteral("\\\"");
} else if (c == '\\') {
writer.AppendLiteral("\\\\");
} else if (c == '\n') {
writer.AppendLiteral("\\n");
} else if (c == '\r') {
writer.AppendLiteral("\\r");
} else if (c == '\t') {
writer.AppendLiteral("\\t");
} else if (uc < 0x20) {
writer.AppendLiteral("\\u00");
writer.AppendChar("0123456789abcdef"[uc >> 4]);
writer.AppendChar("0123456789abcdef"[uc & 0xf]);
} else {
writer.AppendChar(c);
}
}
writer.AppendChar('"');
}
} // namespace
JsonDictWriter::JsonDictWriter(base::DynamicStringWriter& writer)
: buffer_(writer), first_(true) {}
void JsonDictWriter::AddNull(std::string_view key) {
Add(key, [](JsonValueWriter&& v) { std::move(v).WriteNull(); });
}
void JsonDictWriter::AddBool(std::string_view key, bool value) {
Add(key, [value](JsonValueWriter&& v) { std::move(v).WriteBool(value); });
}
void JsonDictWriter::AddInt(std::string_view key, int64_t value) {
Add(key, [value](JsonValueWriter&& v) { std::move(v).WriteInt(value); });
}
void JsonDictWriter::AddUint(std::string_view key, uint64_t value) {
Add(key, [value](JsonValueWriter&& v) { std::move(v).WriteUint(value); });
}
void JsonDictWriter::AddDouble(std::string_view key, double value) {
Add(key, [value](JsonValueWriter&& v) { std::move(v).WriteDouble(value); });
}
void JsonDictWriter::AddString(std::string_view key, std::string_view value) {
Add(key, [value](JsonValueWriter&& v) { std::move(v).WriteString(value); });
}
void JsonDictWriter::WriteKey(std::string_view key) {
if (!first_) {
buffer_.AppendChar(',');
}
first_ = false;
WriteEscapedJsonString(buffer_, key);
buffer_.AppendChar(':');
}
JsonArrayWriter::JsonArrayWriter(base::DynamicStringWriter& writer)
: buffer_(writer), first_(true) {}
void JsonArrayWriter::AppendNull() {
Append([](JsonValueWriter&& v) { std::move(v).WriteNull(); });
}
void JsonArrayWriter::AppendBool(bool value) {
Append([value](JsonValueWriter&& v) { std::move(v).WriteBool(value); });
}
void JsonArrayWriter::AppendInt(int64_t value) {
Append([value](JsonValueWriter&& v) { std::move(v).WriteInt(value); });
}
void JsonArrayWriter::AppendUint(uint64_t value) {
Append([value](JsonValueWriter&& v) { std::move(v).WriteUint(value); });
}
void JsonArrayWriter::AppendDouble(double value) {
Append([value](JsonValueWriter&& v) { std::move(v).WriteDouble(value); });
}
void JsonArrayWriter::AppendString(std::string_view value) {
Append([value](JsonValueWriter&& v) { std::move(v).WriteString(value); });
}
void JsonArrayWriter::AddSeparator() {
if (!first_) {
buffer_.AppendChar(',');
}
first_ = false;
}
JsonValueWriter::JsonValueWriter(base::DynamicStringWriter& writer)
: buffer_(writer) {}
void JsonValueWriter::WriteNull() && {
buffer_.AppendLiteral("null");
}
void JsonValueWriter::WriteBool(bool value) && {
buffer_.AppendString(value ? "true" : "false");
}
void JsonValueWriter::WriteInt(int64_t value) && {
buffer_.AppendInt(value);
}
void JsonValueWriter::WriteUint(uint64_t value) && {
buffer_.AppendUnsignedInt(value);
}
void JsonValueWriter::WriteDouble(double value) && {
if (std::isnan(value)) {
buffer_.AppendLiteral("\"NaN\"");
} else if (std::isinf(value) && value > 0) {
buffer_.AppendLiteral("\"Infinity\"");
} else if (std::isinf(value) && value < 0) {
buffer_.AppendLiteral("\"-Infinity\"");
} else {
buffer_.AppendDouble(value);
}
}
void JsonValueWriter::WriteString(std::string_view value) && {
WriteEscapedString(value);
}
void JsonValueWriter::WriteEscapedString(std::string_view value) {
buffer_.AppendChar('"');
for (char c : value) {
unsigned char uc = static_cast<unsigned char>(c);
if (c == '"') {
buffer_.AppendLiteral("\\\"");
} else if (c == '\\') {
buffer_.AppendLiteral("\\\\");
} else if (c == '\n') {
buffer_.AppendLiteral("\\n");
} else if (c == '\r') {
buffer_.AppendLiteral("\\r");
} else if (c == '\t') {
buffer_.AppendLiteral("\\t");
} else if (uc < 0x20) {
buffer_.AppendLiteral("\\u00");
buffer_.AppendChar("0123456789abcdef"[uc >> 4]);
buffer_.AppendChar("0123456789abcdef"[uc & 0xf]);
} else {
buffer_.AppendChar(c);
}
}
buffer_.AppendChar('"');
}
void JsonDictWriter::Add(std::string_view key,
std::function<void(JsonValueWriter&&)> writer) {
WriteKey(key);
writer(JsonValueWriter(buffer_));
}
void JsonDictWriter::AddDict(std::string_view key,
std::function<void(JsonDictWriter&)> dict_writer) {
WriteKey(key);
buffer_.AppendChar('{');
JsonDictWriter dict(buffer_);
dict_writer(dict);
buffer_.AppendChar('}');
}
void JsonDictWriter::AddArray(
std::string_view key,
std::function<void(JsonArrayWriter&)> array_writer) {
WriteKey(key);
buffer_.AppendChar('[');
JsonArrayWriter array(buffer_);
array_writer(array);
buffer_.AppendChar(']');
}
void JsonArrayWriter::Append(
std::function<void(JsonValueWriter&&)> value_writer) {
AddSeparator();
JsonValueWriter writer(buffer_);
value_writer(std::move(writer));
}
void JsonArrayWriter::AppendDict(
std::function<void(JsonDictWriter&)> dict_writer) {
AddSeparator();
buffer_.AppendChar('{');
JsonDictWriter dict(buffer_);
dict_writer(dict);
buffer_.AppendChar('}');
}
void JsonArrayWriter::AppendArray(
std::function<void(JsonArrayWriter&)> array_writer) {
AddSeparator();
buffer_.AppendChar('[');
JsonArrayWriter array(buffer_);
array_writer(array);
buffer_.AppendChar(']');
}
void JsonValueWriter::WriteDict(
std::function<void(JsonDictWriter&)> dict_writer) && {
buffer_.AppendChar('{');
JsonDictWriter dict(buffer_);
dict_writer(dict);
buffer_.AppendChar('}');
}
void JsonValueWriter::WriteArray(
std::function<void(JsonArrayWriter&)> array_writer) && {
buffer_.AppendChar('[');
JsonArrayWriter array(buffer_);
array_writer(array);
buffer_.AppendChar(']');
}
std::string Write(std::function<void(JsonValueWriter&&)> value_writer) {
base::DynamicStringWriter writer;
JsonValueWriter json_value_writer(writer);
value_writer(std::move(json_value_writer));
return writer.GetStringView().ToStdString();
}
} // namespace perfetto::trace_processor::json