blob: 5b07889adef56f7f097a3d4ea26e0a23826e9322 [file] [log] [blame]
/*
* Copyright (C) 2018 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 <google/protobuf/message.h>
#include "perfetto/base/logging.h"
#include "src/trace_processor/proto_to_json.h"
namespace perfetto {
namespace trace_processor {
namespace proto_to_json {
namespace {
std::string EscapeJsonString(const std::string& raw) {
std::string ret;
for (auto it = raw.cbegin(); it != raw.cend(); it++) {
switch (*it) {
case '\\':
ret += "\\\\";
break;
case '"':
ret += "\\\"";
break;
case '/':
ret += "\\/";
break;
case '\b':
ret += "\\b";
break;
case '\f':
ret += "\\f";
break;
case '\n':
ret += "\\n";
break;
case '\r':
ret += "\\r";
break;
case '\t':
ret += "\\t";
break;
default:
ret += *it;
break;
}
}
return '"' + ret + '"';
}
std::string FieldToJson(const google::protobuf::Message& message,
const google::protobuf::FieldDescriptor* field_desc,
int idx,
uint32_t indent) {
using google::protobuf::FieldDescriptor;
const google::protobuf::Reflection* ref = message.GetReflection();
bool is_repeated = field_desc->is_repeated();
switch (field_desc->cpp_type()) {
case FieldDescriptor::CppType::CPPTYPE_BOOL:
return std::to_string(is_repeated
? ref->GetRepeatedBool(message, field_desc, idx)
: ref->GetBool(message, field_desc));
case FieldDescriptor::CppType::CPPTYPE_ENUM:
return EscapeJsonString(
is_repeated ? ref->GetRepeatedEnum(message, field_desc, idx)->name()
: ref->GetEnum(message, field_desc)->name());
case FieldDescriptor::CppType::CPPTYPE_FLOAT:
return std::to_string(
is_repeated
? static_cast<double>(
ref->GetRepeatedFloat(message, field_desc, idx))
: static_cast<double>(ref->GetFloat(message, field_desc)));
case FieldDescriptor::CppType::CPPTYPE_INT32:
return std::to_string(
is_repeated ? ref->GetRepeatedInt32(message, field_desc, idx)
: ref->GetInt32(message, field_desc));
case FieldDescriptor::CppType::CPPTYPE_INT64:
return std::to_string(
is_repeated ? ref->GetRepeatedInt64(message, field_desc, idx)
: ref->GetInt64(message, field_desc));
case FieldDescriptor::CppType::CPPTYPE_DOUBLE:
return std::to_string(
is_repeated ? ref->GetRepeatedDouble(message, field_desc, idx)
: ref->GetDouble(message, field_desc));
case FieldDescriptor::CppType::CPPTYPE_STRING:
return EscapeJsonString(
is_repeated ? ref->GetRepeatedString(message, field_desc, idx)
: ref->GetString(message, field_desc));
case FieldDescriptor::CppType::CPPTYPE_UINT32:
return std::to_string(
is_repeated ? ref->GetRepeatedUInt32(message, field_desc, idx)
: ref->GetUInt32(message, field_desc));
case FieldDescriptor::CppType::CPPTYPE_UINT64:
return std::to_string(
is_repeated ? ref->GetRepeatedInt64(message, field_desc, idx)
: ref->GetInt64(message, field_desc));
case FieldDescriptor::CppType::CPPTYPE_MESSAGE:
return MessageToJson(
is_repeated ? ref->GetRepeatedMessage(message, field_desc, idx)
: ref->GetMessage(message, field_desc),
indent);
}
PERFETTO_FATAL("For GCC");
}
std::string RepeatedFieldValuesToJson(
const google::protobuf::Message& message,
const google::protobuf::FieldDescriptor* field_desc,
uint32_t indent) {
const google::protobuf::Reflection* ref = message.GetReflection();
std::string ret;
for (int i = 0; i < ref->FieldSize(message, field_desc); ++i) {
if (i != 0) {
ret += ",";
}
ret += "\n" + std::string(indent, ' ') +
FieldToJson(message, field_desc, i, indent);
}
return ret;
}
std::string MessageFieldsToJson(const google::protobuf::Message& message,
uint32_t indent) {
const google::protobuf::Reflection* ref = message.GetReflection();
std::vector<const google::protobuf::FieldDescriptor*> field_descs;
ref->ListFields(message, &field_descs);
std::string ret;
uint32_t next_field_idx = 0;
for (const google::protobuf::FieldDescriptor* field_desc : field_descs) {
if (next_field_idx++ != 0) {
ret += ",";
}
std::string value;
if (field_desc->is_repeated()) {
value = "[" + RepeatedFieldValuesToJson(message, field_desc, indent + 2) +
"\n" + std::string(indent, ' ') + "]";
} else {
value = FieldToJson(message, field_desc, 0, indent);
}
const std::string& name = field_desc->is_extension()
? field_desc->full_name()
: field_desc->name();
ret += "\n" + std::string(indent, ' ') + "\"" + name + "\": " + value;
}
return ret;
}
} // namespace
std::string MessageToJson(const google::protobuf::Message& message,
uint32_t indent) {
return "{" + MessageFieldsToJson(message, indent + 2) + "\n" +
std::string(indent, ' ') + "}";
}
} // namespace proto_to_json
} // namespace trace_processor
} // namespace perfetto