I thought as much, just wanted to make sure I wasn't missing anything :)
So after much playing about, I've managed to get something working, but I
had to use a deprecated function (DynamicMessageFactory(const
DescriptorPool* pool);
)
I also had to pass the fullname() of the message type to be able to know
which descriptor to use in a FileDescriptorProto, am I correct in saying
you can't have two messages with the same fully qualified name? (For
example, "foo.bar.baz" can/should only have one proto?)
Here's my working example, First I have a "MetaMessage" proto which has a
FileDescriptorProto, string for message fullname, and message_data:
import "google/protobuf/descriptor.proto";
message MetaMessage {
required google.protobuf.FileDescriptorProto message_descriptor = 1;
required string message_typename = 2;
required bytes message_data = 3;
}
I then try and find a descriptor for the given message type name first, and
if that fails then I call BuildFile() on my own DescriptorPool to parse the
FileDescriptor into a descriptor, then with custom message factory generate
a DynamicMessageFactory to create DynamicMessages.
void deserializeMessage( const char* filePath )
{
std::ifstream filestr( filePath, std::ifstream::binary );
// Create MetaMessage object and parse from stream
MetaMessage message;
message.ParseFromIstream(&filestr);
// First try and find the descriptor, incase it's a compiled in type
const google::protobuf::Descriptor* descriptor =
google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(
message.message_typename() );
const google::protobuf::Message* prototype = NULL;
// if we have a descriptor, then get the Prototype message
if( descriptor )
{
prototype =
google::protobuf::MessageFactory::generated_factory()->GetPrototype( descriptor
);
}
else
{
// Otherwise, add the descriptor to my Descriptor Pool
static google::protobuf::DescriptorPool myPool;
myPool.BuildFile( message.message_descriptor() );
descriptor = myPool.FindMessageTypeByName( message.message_typename() );
// create a factory from descriptor pool, and get prototype
static google::protobuf::DynamicMessageFactory myFactory(&myPool);
prototype = myFactory.GetPrototype( descriptor );
}
// now we have prototype, can create mutable type and deserialize
if( prototype )
{
google::protobuf::Message* payload = prototype->New();
assert( message.has_message_data() );
payload->ParseFromString( message.message_data() );
std::string msg = payload->GetReflection()->GetString(*payload,
descriptor->FindFieldByName("message"));
std::cout << msg << std::endl;
}
}
int main(int argc, char **argv)
{
if( argc > 1 )
{
deserializeMessage( argv[1] );
}
return 0;
}
Seems to work, but not sure about inter-dependencies within the proto
file...
On Monday, August 19, 2013 9:42:57 PM UTC+1, Oliver wrote:
>
> On Mon, Aug 19, 2013 at 8:37 PM, Tom Ward <[email protected]<javascript:>
> > wrote:
>>
>> Basically I'm trying to work out how to deserialize a protobuf message
>> without using the generated headers, as we're likely to get messages that
>> weren't generated at compile time. I've looked through the documentation,
>> but I only seem to be able to find ones that use generated classes to
>> deserialize, or that use a Descriptor from a generated class to create a
>> DynamicMessage, which I can't seem to work out how to do when we don't have
>> the proto.
>>
>
> The protobuf encoding isn't self-describing; generally you need either a
> compiled message definition or a Descriptor to make sense of an encoded
> message.
> Without one of those, there is not much you can do beyond splitting the
> message into opaque fields that you will have difficulty in interpreting
> further.
>
> As Descriptors can be turned into protobuf messages, one approach is to
> include a serialized Descriptor as part of the standard message framing;
> then you can use DynamicMessage on the receiver side.
> See
> https://developers.google.com/protocol-buffers/docs/techniques#self-description
>
> Oliver
>
>
--
You received this message because you are subscribed to the Google Groups
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/protobuf.
For more options, visit https://groups.google.com/groups/opt_out.