in src/json2pb/pb_to_json.cpp [70:177]
bool PbToJsonConverter::Convert(const google::protobuf::Message& message, Handler& handler, bool root_msg) {
const google::protobuf::Reflection* reflection = message.GetReflection();
const google::protobuf::Descriptor* descriptor = message.GetDescriptor();
int ext_range_count = descriptor->extension_range_count();
int field_count = descriptor->field_count();
std::vector<const google::protobuf::FieldDescriptor*> fields;
fields.reserve(64);
for (int i = 0; i < ext_range_count; ++i) {
const google::protobuf::Descriptor::ExtensionRange*
ext_range = descriptor->extension_range(i);
#if GOOGLE_PROTOBUF_VERSION < 4025000
for (int tag_number = ext_range->start; tag_number < ext_range->end; ++tag_number)
#else
for (int tag_number = ext_range->start_number(); tag_number < ext_range->end_number(); ++tag_number)
#endif
{
const google::protobuf::FieldDescriptor* field =
reflection->FindKnownExtensionByNumber(tag_number);
if (field) {
fields.push_back(field);
}
}
}
std::vector<const google::protobuf::FieldDescriptor*> map_fields;
for (int i = 0; i < field_count; ++i) {
const google::protobuf::FieldDescriptor* field = descriptor->field(i);
if (_option.enable_protobuf_map && json2pb::IsProtobufMap(field)) {
map_fields.push_back(field);
} else {
fields.push_back(field);
}
}
if (root_msg && _option.single_repeated_to_array) {
if (map_fields.empty() && fields.size() == 1 && fields.front()->is_repeated()) {
return _PbFieldToJson(message, fields.front(), handler);
}
}
handler.StartObject();
// Fill in non-map fields
std::string field_name_str;
for (size_t i = 0; i < fields.size(); ++i) {
const google::protobuf::FieldDescriptor* field = fields[i];
if (!field->is_repeated() && !reflection->HasField(message, field)) {
// Field that has not been set
if (field->is_required()) {
_error = "Missing required field: " + field->full_name();
return false;
}
// Whether dumps default fields
if (!_option.always_print_primitive_fields) {
continue;
}
} else if (field->is_repeated()
&& reflection->FieldSize(message, field) == 0
&& !_option.jsonify_empty_array) {
// Repeated field that has no entry
continue;
}
const std::string& orig_name = field->name();
bool decoded = decode_name(orig_name, field_name_str);
const std::string& name = decoded ? field_name_str : orig_name;
handler.Key(name.data(), name.size(), false);
if (!_PbFieldToJson(message, field, handler)) {
return false;
}
}
// Fill in map fields
for (size_t i = 0; i < map_fields.size(); ++i) {
const google::protobuf::FieldDescriptor* map_desc = map_fields[i];
const google::protobuf::FieldDescriptor* key_desc =
map_desc->message_type()->field(json2pb::KEY_INDEX);
const google::protobuf::FieldDescriptor* value_desc =
map_desc->message_type()->field(json2pb::VALUE_INDEX);
// Write a json object corresponding to hold protobuf map
// such as {"key": value, ...}
const std::string& orig_name = map_desc->name();
bool decoded = decode_name(orig_name, field_name_str);
const std::string& name = decoded ? field_name_str : orig_name;
handler.Key(name.data(), name.size(), false);
handler.StartObject();
std::string entry_name;
for (int j = 0; j < reflection->FieldSize(message, map_desc); ++j) {
const google::protobuf::Message& entry =
reflection->GetRepeatedMessage(message, map_desc, j);
const google::protobuf::Reflection* entry_reflection = entry.GetReflection();
entry_name = entry_reflection->GetStringReference(
entry, key_desc, &entry_name);
handler.Key(entry_name.data(), entry_name.size(), false);
// Fill in entries into this json object
if (!_PbFieldToJson(entry, value_desc, handler)) {
return false;
}
}
// Hack: Pass 0 as parameter since Writer doesn't care this
handler.EndObject(0);
}
// Hack: Pass 0 as parameter since Writer doesn't care this
handler.EndObject(0);
return true;
}