1
2 #include "dynamicproto.h"
3
4 #include <google/protobuf/dynamic_message.h>
5 #include <google/protobuf/compiler/importer.h>
6
7 #include <iostream>
8 #include <memory>
9 #include <exception>
10
11 using namespace google::protobuf::compiler;
12 using namespace google::protobuf;
13
14 namespace {
15
16 class ErrorCollector : public MultiFileErrorCollector {
17 public:
AddError(const std::string & file_name,int line,int column,const std::string & message)18 void AddError(const std::string& file_name, int line, int column,
19 const std::string& message) override {
20 std::cerr << "Error in: " << file_name << " line: " << line << " column: "
21 << column << " message: " << message << std::endl;
22 }
23 };
24
25 DiskSourceTree source_tree;
26 ErrorCollector error_collector;
27 std::unique_ptr<Importer> importer;
28 DynamicMessageFactory factory; // This needs to be kept around
29
30 } // namespace
31
32 namespace dynamicproto {
33
warnNotInitialized()34 void warnNotInitialized() {
35 std::cerr << "Warning: dynamicproto has not been initalized" << std::endl;
36 }
37
init(const std::vector<std::string> & include_paths)38 void init(const std::vector<std::string>& include_paths) {
39 for (auto& path: include_paths) {
40 source_tree.MapPath("", path);
41 }
42 importer = std::unique_ptr<Importer>(new Importer(&source_tree,
43 &error_collector));
44 }
45
fileDescriptorDependencies(const FileDescriptor * fdesc,std::vector<const FileDescriptor * > & result)46 void fileDescriptorDependencies(const FileDescriptor* fdesc,
47 std::vector<const FileDescriptor*>& result) {
48 if(fdesc) {
49 size_t n = fdesc->dependency_count();
50 for (size_t i=0; i<n; ++i) {
51 fileDescriptorDependencies(fdesc->dependency(i), result);
52 }
53 result.push_back(fdesc);
54 }
55 }
56
57 // Get a FileDescriptor for the file and all its dependencies,
58 // the latter of which appear at the beginning of the vector.
59 std::vector<const FileDescriptor*>
fileDescriptors(const std::string & file_name)60 fileDescriptors(const std::string& file_name) {
61 std::vector<const FileDescriptor*> result;
62 if(importer) {
63 const FileDescriptor* fdesc = importer->Import(file_name);
64 fileDescriptorDependencies(fdesc, result);
65 }
66 else {
67 warnNotInitialized();
68 }
69 return result;
70 }
71
72 // Find extensions of full_name in desc and add them to result.
extensionsOf(const FileDescriptor * desc,const std::string & full_name,std::vector<const FieldDescriptor * > & result)73 void extensionsOf(const FileDescriptor* desc, const std::string& full_name,
74 std::vector<const FieldDescriptor*>& result) {
75 // TODO: look in all messages that may contain inner extensions
76 if(desc) {
77 int n = desc->extension_count();
78 for (int i=0;i<n;++i) {
79 auto e = desc->extension(i);
80 if(e->containing_type()->full_name()==full_name)
81 result.push_back(e);
82 }
83 n = desc->dependency_count();
84 for (int i=0;i<n;++i) {
85 extensionsOf(desc->dependency(i), full_name, result);
86 }
87 }
88 }
89
enums(const FileDescriptor * extDesc)90 std::vector<const EnumDescriptor*> enums(const FileDescriptor* extDesc) {
91 std::vector<const EnumDescriptor*> result;
92 if(extDesc) {
93 int n = extDesc->enum_type_count();
94 for (int i=0;i<n;++i) {
95 auto e = extDesc->enum_type(i);
96 result.push_back(e);
97 }
98 }
99 return result;
100 }
101
print(const EnumDescriptor * e,std::ostream & o)102 void print(const EnumDescriptor* e, std::ostream& o) {
103 o << "enum " << e->name() << " { ";
104 int n = e->value_count();
105 bool first = true;
106 for (int i=0; i<n; ++i) {
107 if(first)
108 first = false;
109 else
110 o << ", ";
111 o << e->value(i)->name() << "=" << (i+1);
112 }
113 o << "}";
114 }
115
newMessage(const FileDescriptor * fdesc,const std::string & name)116 Message* newMessage(const FileDescriptor* fdesc, const std::string& name) {
117 auto desc = fdesc->FindMessageTypeByName(name);
118 if(desc) {
119 auto p = factory.GetPrototype(desc);
120 if(p)
121 return p->New();
122 }
123 size_t n = fdesc->dependency_count();
124 for (size_t i=0; i<n; ++i) {
125 auto m = newMessage(fdesc->dependency(i), name);
126 if(m) return m;
127 }
128 return nullptr;
129 }
130
131 } // namespace dynamicproto
132