mxArray* processPbMessage(const ::google::protobuf::Message* inMsg)
{
// Set up a namespace for convenience for protobuf stuff
namespace pb = ::google::protobuf;
// Extract a descriptor and reflection for the incoming message
const pb::Descriptor* descriptor = inMsg->GetDescriptor();
const pb::Reflection* reflection = inMsg->GetReflection();
// Extract the fields from the message
vector<const pb::FieldDescriptor*> fields;
reflection->ListFields(*inMsg, &fields);
const int numFields = fields.size();
const char **field_names = new const char*[numFields];
const pb::FieldDescriptor* iField;
// Put the fields into a C style array
for (int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
{
iField = fields[fieldIndex];
field_names[fieldIndex] = iField->name().c_str();
}
// Create a Matlab structure
mwSize dims[2] = {1, 1};
mxArray *mexMsg = mxCreateStructArray(2, dims, fields.size(), field_names);
delete[] field_names;
// Initialize varaibles to hold the various value types that we might find
// Values that we extract from the protobuf messages
int intValue;
double valueDouble;
float valueFloat;
string valueString;
const pb::EnumValueDescriptor* valueEnum;
bool valueBool;
int count;
// Submessage varaibles
mxArray* mxSubMessage;
mxArray* nextField;
const pb::Descriptor* subDescriptor;
const pb::Reflection* subReflection;
vector<const pb::FieldDescriptor*> subFields;
int subNumFields;
const pb::FieldDescriptor* subIField;
int subFieldIndex;
mxArray *subMexMsg;
// Iterate through each field in the incoming message (note: this will only handle single messages)
for (int i = 0; i < fields.size(); i++)
{
// Extract the descriptor for this field
const pb::FieldDescriptor* thisField = fields[i];
const char **subFieldNames;
// Determine if this field is repeated and, if so, how many fields there are
count = 0;
if (thisField->is_repeated())
{
count = reflection->FieldSize(*inMsg, thisField);
}
else if (reflection->HasField(*inMsg, thisField))
{
count = -1;
}
else
{
mexErrMsgTxt("Field Issue!");
}
// Determine the name of the field
string fieldName = thisField->name();
// Recurse, if necessary
if (thisField->cpp_type() == pb::FieldDescriptor::CPPTYPE_MESSAGE)
{
// If it's greater than 0, we have a repeated field. Otherwise, it's singular
if (count > 0)
{
// Create a struct array for this field
const pb::Message& firstMessage = (reflection->GetRepeatedMessage(*inMsg, thisField, 0));
subDescriptor = firstMessage.GetDescriptor();
subReflection = firstMessage.GetReflection();
subReflection->ListFields(firstMessage, &subFields);
subNumFields = subFields.size();
subFieldNames = new const char*[subNumFields];
for (subFieldIndex = 0; subFieldIndex < subFields.size(); subFieldIndex++)
{
subIField = subFields[subFieldIndex];
subFieldNames[subFieldIndex] = subIField->name().c_str();
}
mwSize dims[2] = {count, 1};
subMexMsg = mxCreateStructArray(2, dims, subFields.size(), subFieldNames);
// Iterate through each repeated message
for (int j = 0; j < count; ++j)
{
// Call this method on the sub message
const pb::Message& recurseMessage = reflection->GetRepeatedMessage(*inMsg, thisField, j);
mxSubMessage = processPbMessage(&recurseMessage);
// Itereate through and set each field
for (int subFieldIndex = 0; subFieldIndex < subFields.size(); subFieldIndex++)
{
nextField = mxGetField(mxSubMessage, 0, subFieldNames[subFieldIndex]);
mxSetField(subMexMsg, j, subFieldNames[subFieldIndex], nextField);
}
delete[] subFieldNames;
mxSetField(mexMsg, 0, fieldName.c_str(), subMexMsg);
}
else
{
// Call this method on the sub-message
const pb::Message& subMessage = reflection->GetMessage(*inMsg, thisField);
mxSubMessage = processPbMessage(&subMessage);
mxSetField(mexMsg, 0, fieldName.c_str(), mxSubMessage);
}
}
else if (count <= 0)
{
// In this case, the field is not repeated and is not a message. Add it to the Matlab structure
switch(thisField->cpp_type())
{
case pb::FieldDescriptor::CPPTYPE_INT32 :
intValue = reflection->GetInt32(*inMsg, thisField);
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateDoubleScalar((double) intValue));
break;
case pb::FieldDescriptor::CPPTYPE_INT64 :
intValue = reflection->GetInt64(*inMsg, thisField);
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateDoubleScalar((double) intValue));
break;
case pb::FieldDescriptor::CPPTYPE_UINT32 :
intValue = reflection->GetUInt32(*inMsg, thisField);
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateDoubleScalar((double) intValue));
break;
case pb::FieldDescriptor::CPPTYPE_UINT64 :
intValue = reflection->GetUInt64(*inMsg, thisField);
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateDoubleScalar((double) intValue));
break;
case pb::FieldDescriptor::CPPTYPE_DOUBLE :
valueDouble = reflection->GetDouble(*inMsg, thisField);
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateDoubleScalar(valueDouble));
break;
case pb::FieldDescriptor::CPPTYPE_FLOAT :
valueFloat = reflection->GetFloat(*inMsg, thisField);
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateDoubleScalar((double) valueFloat));
break;
case pb::FieldDescriptor::CPPTYPE_BOOL :
valueBool = reflection->GetBool(*inMsg, thisField);
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateLogicalScalar(valueBool));
break;
case pb::FieldDescriptor::CPPTYPE_ENUM :
valueEnum = reflection->GetEnum(*inMsg, thisField);
valueString = valueEnum->name();
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateString(valueString.c_str()));
break;
case pb::FieldDescriptor::CPPTYPE_STRING :
valueString = reflection->GetString(*inMsg, thisField);
mxSetField(mexMsg, 0, fieldName.c_str(), mxCreateString(valueString.c_str()));
break;
}
}
else{
// In this case, the field is repeated. Go through each repetition
mxArray *value;
mwSize dims2[2] = {1, count};
double *doubleArray;
mxLogical *boolArray;
mxChar* charArray;
// Initialize matrices to hold the repeated data
switch(thisField->cpp_type())
{
case pb::FieldDescriptor::CPPTYPE_INT32 :
value = mxCreateDoubleMatrix(1, count, mxREAL);
doubleArray = mxGetPr(value);
break;
case pb::FieldDescriptor::CPPTYPE_INT64 :
value = mxCreateDoubleMatrix(1, count, mxREAL);
doubleArray = mxGetPr(value);
break;
case pb::FieldDescriptor::CPPTYPE_UINT32 :
value = mxCreateDoubleMatrix(1, count, mxREAL);
doubleArray = mxGetPr(value);
break;
case pb::FieldDescriptor::CPPTYPE_UINT64 :
value = mxCreateDoubleMatrix(1, count, mxREAL);
doubleArray = mxGetPr(value);
break;
case pb::FieldDescriptor::CPPTYPE_DOUBLE :
value = mxCreateDoubleMatrix(1, count, mxREAL);
doubleArray = mxGetPr(value);
break;
case pb::FieldDescriptor::CPPTYPE_FLOAT :
value = mxCreateDoubleMatrix(1, count, mxREAL);
doubleArray = mxGetPr(value);
break;
case pb::FieldDescriptor::CPPTYPE_BOOL :
value = mxCreateLogicalMatrix(1, count);
boolArray = (mxLogical *) mxGetPr(value);
break;
case pb::FieldDescriptor::CPPTYPE_STRING :
value = mxCreateCharArray(1, dims2);
charArray = (mxChar *) mxGetPr(value);
break;
case pb::FieldDescriptor::CPPTYPE_ENUM :
value = mxCreateCharArray(1, dims2);
charArray = (mxChar *) mxGetPr(value);
break;
}
for (int k = 0; k < count; ++k)
{
switch(thisField->cpp_type())
{
case pb::FieldDescriptor::CPPTYPE_INT32 :
intValue = reflection->GetRepeatedInt32(*inMsg, thisField, k);
doubleArray[k] = (double) intValue;
break;
case pb::FieldDescriptor::CPPTYPE_INT64 :
intValue = reflection->GetRepeatedInt64(*inMsg, thisField, k);
doubleArray[k] = (double) intValue;
break;
case pb::FieldDescriptor::CPPTYPE_UINT32 :
intValue = reflection->GetRepeatedUInt32(*inMsg, thisField, k);
doubleArray[k] = (double) intValue;
break;
case pb::FieldDescriptor::CPPTYPE_UINT64 :
intValue = reflection->GetRepeatedUInt64(*inMsg, thisField, k);
doubleArray[k] = (double) intValue;
break;
case pb::FieldDescriptor::CPPTYPE_DOUBLE :
valueDouble = reflection->GetRepeatedDouble(*inMsg, thisField, k);
doubleArray[k] = valueDouble;
break;
case pb::FieldDescriptor::CPPTYPE_FLOAT :
valueFloat = reflection->GetRepeatedFloat(*inMsg, thisField, k);
doubleArray[k] = (double) valueFloat;
break;
case pb::FieldDescriptor::CPPTYPE_BOOL :
valueBool = reflection->GetRepeatedBool(*inMsg, thisField, k);
boolArray[k] = valueBool;
break;
case pb::FieldDescriptor::CPPTYPE_STRING :
valueString = reflection->GetRepeatedString(*inMsg, thisField, k);
charArray[k] = (mxChar) valueString.c_str();
break;
case pb::FieldDescriptor::CPPTYPE_ENUM :
valueEnum = reflection->GetRepeatedEnum(*inMsg, thisField, k);
valueString = valueEnum->name();
charArray[k] = (mxChar) valueString.c_str();
break;
}
}
mxSetField(mexMsg, 0, fieldName.c_str(), value);
}
}
}
return mexMsg;
}