blob: c6d3acf83ffcae71315b619c062fa3103ba0d800 [file] [log] [blame]
/*
* Original code from https://github.com/renenglish/pb2json
*/
#include "pb2json.h"
#include <google/protobuf/message.h>
#include <jansson.h>
std::string Pb2Json::hex_encode(const std::string& input)
{
static const char* const lut = "0123456789abcdef";
size_t len = input.length();
std::string output;
output.reserve(2 * len);
for (size_t i = 0; i < len; ++i)
{
const unsigned char c = input[i];
output.push_back(lut[c >> 4]);
output.push_back(lut[c & 15]);
}
return output;
}
char * Pb2Json::pb2json(const google::protobuf::Message &msg)
{
json_t *root = parse_msg(&msg);
char *json = json_dumps(root,0);
json_decref(root);
return json; // should be freed by caller
}
char * Pb2Json::pb2json( google::protobuf::Message *msg,const char *buf ,int len)
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
std::string s (buf,len);
msg->ParseFromString(s);
json_t *root = parse_msg(msg);
char *json = json_dumps(root,0);
json_decref(root);
google::protobuf::ShutdownProtobufLibrary();
return json; // should be freed by caller
}
json_t *Pb2Json::parse_repeated_field(const google::protobuf::Message *msg,
const google::protobuf::Reflection * ref,
const google::protobuf::FieldDescriptor *field)
{
size_t count = ref->FieldSize(*msg,field);
json_t *arr = json_array();
if(!arr)return NULL;
switch(field->cpp_type())
{
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
for(size_t i = 0 ; i != count ; ++i)
{
double value1 = ref->GetRepeatedDouble(*msg,field,i);
json_array_append_new(arr,json_real(value1));
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
for(size_t i = 0 ; i != count ; ++i)
{
float value2 = ref->GetRepeatedFloat(*msg,field,i);
json_array_append_new(arr,json_real(value2));
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
for(size_t i = 0 ; i != count ; ++i)
{
int64_t value3 = ref->GetRepeatedInt64(*msg,field,i);
json_array_append_new(arr,json_integer(value3)) ;
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
for(size_t i = 0 ; i != count ; ++i)
{
uint64_t value4 = ref->GetRepeatedUInt64(*msg,field,i);
json_array_append_new(arr,json_integer(value4));
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
for(size_t i = 0 ; i != count ; ++i)
{
int32_t value5 = ref->GetRepeatedInt32(*msg,field,i);
json_array_append_new(arr,json_integer(value5));
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
for(size_t i = 0 ; i != count ; ++i)
{
uint32_t value6 = ref->GetRepeatedUInt32(*msg,field,i);
json_array_append_new(arr,json_integer(value6));
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
for(size_t i = 0 ; i != count ; ++i)
{
bool value7 = ref->GetRepeatedBool(*msg,field,i);
json_array_append_new(arr,value7?json_true():json_false()) ;
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
for(size_t i = 0 ; i != count ; ++i)
{
std::string value8 = ref->GetRepeatedString(*msg,field,i);
json_array_append_new(arr,json_string(value8.c_str()));
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
for(size_t i = 0 ; i != count ; ++i)
{
const google::protobuf::Message *value9 = &(ref->GetRepeatedMessage(*msg,field,i));
json_array_append_new(arr,parse_msg(value9));
}
break;
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
for(size_t i = 0 ; i != count ; ++i)
{
const google::protobuf::EnumValueDescriptor* value10 =
ref->GetRepeatedEnum(*msg,field,i);
json_array_append_new(arr,json_integer(value10->number()));
}
break;
default:
break;
}
return arr;
}
json_t *Pb2Json::parse_msg(const google::protobuf::Message *msg)
{
const google::protobuf::Descriptor *d = msg->GetDescriptor();
if(!d)return NULL;
size_t count = d->field_count();
json_t *root = json_object();
if(!root)return NULL;
for (size_t i = 0; i != count ; ++i)
{
const google::protobuf::FieldDescriptor *field = d->field(i);
if(!field)return NULL;
const google::protobuf::Reflection *ref = msg->GetReflection();
if(!ref)return NULL;
const char *name = field->name().c_str();
if(field->is_repeated())
json_object_set_new(root,name,parse_repeated_field(msg,ref,field));
if(!field->is_repeated() && ref->HasField(*msg,field))
{
double value1;
float value2;
int64_t value3;
uint64_t value4;
int32_t value5;
uint32_t value6;
bool value7;
std::string value8;
const google::protobuf::Message *value9;
const google::protobuf::EnumValueDescriptor *value10;
switch (field->cpp_type())
{
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
value1 = ref->GetDouble(*msg,field);
json_object_set_new(root,name,json_real(value1));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
value2 = ref->GetFloat(*msg,field);
json_object_set_new(root,name,json_real(value2));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
value3 = ref->GetInt64(*msg,field);
json_object_set_new(root,name,json_integer(value3)) ;
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
value4 = ref->GetUInt64(*msg,field);
json_object_set_new(root,name,json_integer(value4));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
value5 = ref->GetInt32(*msg,field);
json_object_set_new(root,name,json_integer(value5));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
value6 = ref->GetUInt32(*msg,field);
json_object_set_new(root,name,json_integer(value6));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
value7 = ref->GetBool(*msg,field);
json_object_set_new(root,name,value7?json_true():json_false()) ;
break;
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
if (field->type() == google::protobuf::FieldDescriptor::TYPE_BYTES) {
value8 = hex_encode(ref->GetString(*msg,field));
} else {
value8 = ref->GetString(*msg,field);
}
json_object_set_new(root,name,json_string(value8.c_str()));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
value9 = &(ref->GetMessage(*msg,field));
json_object_set_new(root,name,parse_msg(value9));
break;
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
value10 = ref->GetEnum(*msg,field);
json_object_set_new(root,name,json_integer(value10->number()));
break;
default:
break;
}
}
}
return root;
}