How to use DescriptorPool and extensions correctly?

1,329 views
Skip to first unread message

Gabriel Gambetta

unread,
Jan 19, 2017, 5:46:57 AM1/19/17
to Protocol Buffers
I'm trying to write a C++ program that reads a gzipped binary proto from a file. The outer type of this proto is known at compile time, but it contains extensions that aren't. The extensions are described in a FileDescriptorSet stored into a different file I also have. I want to be able to use TextFormat to dumpl these extensions correctly.

What I've done is load the FileDescriptorSet from the file, create a new DescriptorPool, call BuildFile() on each file in the FileDescriptorSet, create a DynamicMessageFactory, set that in the CodedInputStream, and try to parse the proto. Something like this (error checking removed for readability, but it's there in the actual code, and there are no errors):

google::protobuf::FileDescriptorSet descriptors;
descriptors
.ParseFromCodedStream(&descriptors_input)

google
::protobuf::DescriptorPool descriptor_pool;
for (auto i = 0; i < descriptors.file_size(); ++i) {
  descriptor_pool
.BuildFile(descriptors.file(i));
}

google::protobuf::DynamicMessageFactory factory(&descriptor_pool);
factory.SetDelegateToGeneratedFactory(true);
input.SetExtensionRegistry(&descriptor_pool, &factory);

generated::OuterType entry;
entry.ParseFromCodedStream(input);

This roughly works, but the extensions aren't recognised when I use TextFormat to print the proto.

I've debugged this deep into the proto code, and tracked it down to FindPtrOrNull() in map_util.h, called by DescriptorPool::Tables::FindExtension(). The collection has the entry I'm looking for, but using an identical but not-the-same Descriptor. So I think I've run into the warnings explained here.

I believe this may be because OuterType is part of the FileDescriptorSet I'm loading, so maybe the two descriptors come from 1) generated code, 2) loading the FileDescriptorSet. I've tried to avoid this by not loading the file that describes OuterType, but then I get loading errors complaining that OuterType hasn't been loaded [in the descriptor_pool I'm creating].

I have the feeling this has something to do with using this descriptor pool as an underlay for the built-in pool, but I haven't find anything in the documentation, or any example, that explains how to do this; all the methods I can find are private and/or have warnings of the type "THIS MUST NEVER BE CALLED FROM USER CODE" :(

Any suggestions extremely welcome!

Thanks,

--Gabriel

Gabriel Gambetta

unread,
Jan 19, 2017, 9:14:03 AM1/19/17
to Protocol Buffers
Managed to make it work by doing

descriptor_pool.internal_set_underlay(google::protobuf::DescriptorPool::generated_pool());

before loading the FileDescriptorSet, and avoiding loading the definition for OuterType again, but it's a very fragile solution that uses an internal method which the docs explicitly ask not to. Is there a better way to do this?

Thanks,

--Gabriel

Reply all
Reply to author
Forward
0 new messages