• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Implements the DescriptorPool, which collects all descriptors.
32 
33 #include <unordered_map>
34 
35 #include <Python.h>
36 
37 #include <google/protobuf/descriptor.pb.h>
38 #include <google/protobuf/pyext/descriptor.h>
39 #include <google/protobuf/pyext/descriptor_database.h>
40 #include <google/protobuf/pyext/descriptor_pool.h>
41 #include <google/protobuf/pyext/message.h>
42 #include <google/protobuf/pyext/message_factory.h>
43 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
44 #include <google/protobuf/stubs/hash.h>
45 
46 #if PY_MAJOR_VERSION >= 3
47   #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
48   #if PY_VERSION_HEX < 0x03030000
49     #error "Python 3.0 - 3.2 are not supported."
50   #endif
51 #define PyString_AsStringAndSize(ob, charpp, sizep)                           \
52   (PyUnicode_Check(ob) ? ((*(charpp) = const_cast<char*>(                     \
53                                PyUnicode_AsUTF8AndSize(ob, (sizep)))) == NULL \
54                               ? -1                                            \
55                               : 0)                                            \
56                        : PyBytes_AsStringAndSize(ob, (charpp), (sizep)))
57 #endif
58 
59 namespace google {
60 namespace protobuf {
61 namespace python {
62 
63 // A map to cache Python Pools per C++ pointer.
64 // Pointers are not owned here, and belong to the PyDescriptorPool.
65 static std::unordered_map<const DescriptorPool*, PyDescriptorPool*>*
66     descriptor_pool_map;
67 
68 namespace cdescriptor_pool {
69 
70 // Collects errors that occur during proto file building to allow them to be
71 // propagated in the python exception instead of only living in ERROR logs.
72 class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
73  public:
BuildFileErrorCollector()74   BuildFileErrorCollector() : error_message(""), had_errors_(false) {}
75 
AddError(const string & filename,const string & element_name,const Message * descriptor,ErrorLocation location,const string & message)76   void AddError(const string& filename, const string& element_name,
77                 const Message* descriptor, ErrorLocation location,
78                 const string& message) override {
79     // Replicates the logging behavior that happens in the C++ implementation
80     // when an error collector is not passed in.
81     if (!had_errors_) {
82       error_message +=
83           ("Invalid proto descriptor for file \"" + filename + "\":\n");
84       had_errors_ = true;
85     }
86     // As this only happens on failure and will result in the program not
87     // running at all, no effort is made to optimize this string manipulation.
88     error_message += ("  " + element_name + ": " + message + "\n");
89   }
90 
Clear()91   void Clear() {
92     had_errors_ = false;
93     error_message = "";
94   }
95 
96   string error_message;
97 
98  private:
99   bool had_errors_;
100 };
101 
102 // Create a Python DescriptorPool object, but does not fill the "pool"
103 // attribute.
_CreateDescriptorPool()104 static PyDescriptorPool* _CreateDescriptorPool() {
105   PyDescriptorPool* cpool = PyObject_GC_New(
106       PyDescriptorPool, &PyDescriptorPool_Type);
107   if (cpool == NULL) {
108     return NULL;
109   }
110 
111   cpool->error_collector = nullptr;
112   cpool->underlay = NULL;
113   cpool->database = NULL;
114 
115   cpool->descriptor_options = new std::unordered_map<const void*, PyObject*>();
116 
117   cpool->py_message_factory = message_factory::NewMessageFactory(
118       &PyMessageFactory_Type, cpool);
119   if (cpool->py_message_factory == NULL) {
120     Py_DECREF(cpool);
121     return NULL;
122   }
123 
124   PyObject_GC_Track(cpool);
125 
126   return cpool;
127 }
128 
129 // Create a Python DescriptorPool, using the given pool as an underlay:
130 // new messages will be added to a custom pool, not to the underlay.
131 //
132 // Ownership of the underlay is not transferred, its pointer should
133 // stay alive.
PyDescriptorPool_NewWithUnderlay(const DescriptorPool * underlay)134 static PyDescriptorPool* PyDescriptorPool_NewWithUnderlay(
135     const DescriptorPool* underlay) {
136   PyDescriptorPool* cpool = _CreateDescriptorPool();
137   if (cpool == NULL) {
138     return NULL;
139   }
140   cpool->pool = new DescriptorPool(underlay);
141   cpool->underlay = underlay;
142 
143   if (!descriptor_pool_map->insert(
144       std::make_pair(cpool->pool, cpool)).second) {
145     // Should never happen -- would indicate an internal error / bug.
146     PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
147     return NULL;
148   }
149 
150   return cpool;
151 }
152 
PyDescriptorPool_NewWithDatabase(DescriptorDatabase * database)153 static PyDescriptorPool* PyDescriptorPool_NewWithDatabase(
154     DescriptorDatabase* database) {
155   PyDescriptorPool* cpool = _CreateDescriptorPool();
156   if (cpool == NULL) {
157     return NULL;
158   }
159   if (database != NULL) {
160     cpool->error_collector = new BuildFileErrorCollector();
161     cpool->pool = new DescriptorPool(database, cpool->error_collector);
162     cpool->database = database;
163   } else {
164     cpool->pool = new DescriptorPool();
165   }
166 
167   if (!descriptor_pool_map->insert(std::make_pair(cpool->pool, cpool)).second) {
168     // Should never happen -- would indicate an internal error / bug.
169     PyErr_SetString(PyExc_ValueError, "DescriptorPool already registered");
170     return NULL;
171   }
172 
173   return cpool;
174 }
175 
176 // The public DescriptorPool constructor.
New(PyTypeObject * type,PyObject * args,PyObject * kwargs)177 static PyObject* New(PyTypeObject* type,
178                      PyObject* args, PyObject* kwargs) {
179   static char* kwlist[] = {"descriptor_db", 0};
180   PyObject* py_database = NULL;
181   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &py_database)) {
182     return NULL;
183   }
184   DescriptorDatabase* database = NULL;
185   if (py_database && py_database != Py_None) {
186     database = new PyDescriptorDatabase(py_database);
187   }
188   return reinterpret_cast<PyObject*>(
189       PyDescriptorPool_NewWithDatabase(database));
190 }
191 
Dealloc(PyObject * pself)192 static void Dealloc(PyObject* pself) {
193   PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
194   descriptor_pool_map->erase(self->pool);
195   Py_CLEAR(self->py_message_factory);
196   for (std::unordered_map<const void*, PyObject*>::iterator it =
197            self->descriptor_options->begin();
198        it != self->descriptor_options->end(); ++it) {
199     Py_DECREF(it->second);
200   }
201   delete self->descriptor_options;
202   delete self->database;
203   delete self->pool;
204   delete self->error_collector;
205   Py_TYPE(self)->tp_free(pself);
206 }
207 
GcTraverse(PyObject * pself,visitproc visit,void * arg)208 static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
209   PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
210   Py_VISIT(self->py_message_factory);
211   return 0;
212 }
213 
GcClear(PyObject * pself)214 static int GcClear(PyObject* pself) {
215   PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
216   Py_CLEAR(self->py_message_factory);
217   return 0;
218 }
219 
SetErrorFromCollector(DescriptorPool::ErrorCollector * self,char * name,char * error_type)220 PyObject* SetErrorFromCollector(DescriptorPool::ErrorCollector* self,
221                                 char* name, char* error_type) {
222   BuildFileErrorCollector* error_collector =
223       reinterpret_cast<BuildFileErrorCollector*>(self);
224   if (error_collector && !error_collector->error_message.empty()) {
225     PyErr_Format(PyExc_KeyError, "Couldn't build file for %s %.200s\n%s",
226                  error_type, name, error_collector->error_message.c_str());
227     error_collector->Clear();
228     return NULL;
229   }
230   PyErr_Format(PyExc_KeyError, "Couldn't find %s %.200s", error_type, name);
231   return NULL;
232 }
233 
FindMessageByName(PyObject * self,PyObject * arg)234 static PyObject* FindMessageByName(PyObject* self, PyObject* arg) {
235   Py_ssize_t name_size;
236   char* name;
237   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
238     return NULL;
239   }
240 
241   const Descriptor* message_descriptor =
242       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMessageTypeByName(
243           string(name, name_size));
244 
245   if (message_descriptor == NULL) {
246     return SetErrorFromCollector(
247         reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
248         "message");
249   }
250 
251 
252   return PyMessageDescriptor_FromDescriptor(message_descriptor);
253 }
254 
255 
256 
257 
FindFileByName(PyObject * self,PyObject * arg)258 static PyObject* FindFileByName(PyObject* self, PyObject* arg) {
259   Py_ssize_t name_size;
260   char* name;
261   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
262     return NULL;
263   }
264 
265   PyDescriptorPool* py_pool = reinterpret_cast<PyDescriptorPool*>(self);
266   const FileDescriptor* file_descriptor =
267       py_pool->pool->FindFileByName(string(name, name_size));
268 
269   if (file_descriptor == NULL) {
270     return SetErrorFromCollector(py_pool->error_collector, name, "file");
271   }
272   return PyFileDescriptor_FromDescriptor(file_descriptor);
273 }
274 
FindFieldByName(PyDescriptorPool * self,PyObject * arg)275 PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) {
276   Py_ssize_t name_size;
277   char* name;
278   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
279     return NULL;
280   }
281 
282   const FieldDescriptor* field_descriptor =
283       self->pool->FindFieldByName(string(name, name_size));
284   if (field_descriptor == NULL) {
285     return SetErrorFromCollector(self->error_collector, name, "field");
286   }
287 
288 
289   return PyFieldDescriptor_FromDescriptor(field_descriptor);
290 }
291 
FindFieldByNameMethod(PyObject * self,PyObject * arg)292 static PyObject* FindFieldByNameMethod(PyObject* self, PyObject* arg) {
293   return FindFieldByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
294 }
295 
FindExtensionByName(PyDescriptorPool * self,PyObject * arg)296 PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) {
297   Py_ssize_t name_size;
298   char* name;
299   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
300     return NULL;
301   }
302 
303   const FieldDescriptor* field_descriptor =
304       self->pool->FindExtensionByName(string(name, name_size));
305   if (field_descriptor == NULL) {
306     return SetErrorFromCollector(self->error_collector, name,
307                                  "extension field");
308   }
309 
310 
311   return PyFieldDescriptor_FromDescriptor(field_descriptor);
312 }
313 
FindExtensionByNameMethod(PyObject * self,PyObject * arg)314 static PyObject* FindExtensionByNameMethod(PyObject* self, PyObject* arg) {
315   return FindExtensionByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
316 }
317 
FindEnumTypeByName(PyDescriptorPool * self,PyObject * arg)318 PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) {
319   Py_ssize_t name_size;
320   char* name;
321   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
322     return NULL;
323   }
324 
325   const EnumDescriptor* enum_descriptor =
326       self->pool->FindEnumTypeByName(string(name, name_size));
327   if (enum_descriptor == NULL) {
328     return SetErrorFromCollector(self->error_collector, name, "enum");
329   }
330 
331 
332   return PyEnumDescriptor_FromDescriptor(enum_descriptor);
333 }
334 
FindEnumTypeByNameMethod(PyObject * self,PyObject * arg)335 static PyObject* FindEnumTypeByNameMethod(PyObject* self, PyObject* arg) {
336   return FindEnumTypeByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
337 }
338 
FindOneofByName(PyDescriptorPool * self,PyObject * arg)339 PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
340   Py_ssize_t name_size;
341   char* name;
342   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
343     return NULL;
344   }
345 
346   const OneofDescriptor* oneof_descriptor =
347       self->pool->FindOneofByName(string(name, name_size));
348   if (oneof_descriptor == NULL) {
349     return SetErrorFromCollector(self->error_collector, name, "oneof");
350   }
351 
352 
353   return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
354 }
355 
FindOneofByNameMethod(PyObject * self,PyObject * arg)356 static PyObject* FindOneofByNameMethod(PyObject* self, PyObject* arg) {
357   return FindOneofByName(reinterpret_cast<PyDescriptorPool*>(self), arg);
358 }
359 
FindServiceByName(PyObject * self,PyObject * arg)360 static PyObject* FindServiceByName(PyObject* self, PyObject* arg) {
361   Py_ssize_t name_size;
362   char* name;
363   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
364     return NULL;
365   }
366 
367   const ServiceDescriptor* service_descriptor =
368       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
369           string(name, name_size));
370   if (service_descriptor == NULL) {
371     return SetErrorFromCollector(
372         reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
373         "service");
374   }
375 
376 
377   return PyServiceDescriptor_FromDescriptor(service_descriptor);
378 }
379 
FindMethodByName(PyObject * self,PyObject * arg)380 static PyObject* FindMethodByName(PyObject* self, PyObject* arg) {
381   Py_ssize_t name_size;
382   char* name;
383   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
384     return NULL;
385   }
386 
387   const MethodDescriptor* method_descriptor =
388       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMethodByName(
389           string(name, name_size));
390   if (method_descriptor == NULL) {
391     return SetErrorFromCollector(
392         reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
393         "method");
394   }
395 
396 
397   return PyMethodDescriptor_FromDescriptor(method_descriptor);
398 }
399 
FindFileContainingSymbol(PyObject * self,PyObject * arg)400 static PyObject* FindFileContainingSymbol(PyObject* self, PyObject* arg) {
401   Py_ssize_t name_size;
402   char* name;
403   if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
404     return NULL;
405   }
406 
407   const FileDescriptor* file_descriptor =
408       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileContainingSymbol(
409           string(name, name_size));
410   if (file_descriptor == NULL) {
411     return SetErrorFromCollector(
412         reinterpret_cast<PyDescriptorPool*>(self)->error_collector, name,
413         "symbol");
414   }
415 
416 
417   return PyFileDescriptor_FromDescriptor(file_descriptor);
418 }
419 
FindExtensionByNumber(PyObject * self,PyObject * args)420 static PyObject* FindExtensionByNumber(PyObject* self, PyObject* args) {
421   PyObject* message_descriptor;
422   int number;
423   if (!PyArg_ParseTuple(args, "Oi", &message_descriptor, &number)) {
424     return NULL;
425   }
426   const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(
427       message_descriptor);
428   if (descriptor == NULL) {
429     return NULL;
430   }
431 
432   const FieldDescriptor* extension_descriptor =
433       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByNumber(
434           descriptor, number);
435   if (extension_descriptor == NULL) {
436     BuildFileErrorCollector* error_collector =
437         reinterpret_cast<BuildFileErrorCollector*>(
438             reinterpret_cast<PyDescriptorPool*>(self)->error_collector);
439     if (error_collector && !error_collector->error_message.empty()) {
440       PyErr_Format(PyExc_KeyError, "Couldn't build file for Extension %.d\n%s",
441                    number, error_collector->error_message.c_str());
442       error_collector->Clear();
443       return NULL;
444     }
445     PyErr_Format(PyExc_KeyError, "Couldn't find Extension %d", number);
446     return NULL;
447   }
448 
449 
450   return PyFieldDescriptor_FromDescriptor(extension_descriptor);
451 }
452 
FindAllExtensions(PyObject * self,PyObject * arg)453 static PyObject* FindAllExtensions(PyObject* self, PyObject* arg) {
454   const Descriptor* descriptor = PyMessageDescriptor_AsDescriptor(arg);
455   if (descriptor == NULL) {
456     return NULL;
457   }
458 
459   std::vector<const FieldDescriptor*> extensions;
460   reinterpret_cast<PyDescriptorPool*>(self)->pool->FindAllExtensions(
461       descriptor, &extensions);
462 
463   ScopedPyObjectPtr result(PyList_New(extensions.size()));
464   if (result == NULL) {
465     return NULL;
466   }
467   for (int i = 0; i < extensions.size(); i++) {
468     PyObject* extension = PyFieldDescriptor_FromDescriptor(extensions[i]);
469     if (extension == NULL) {
470       return NULL;
471     }
472     PyList_SET_ITEM(result.get(), i, extension);  // Steals the reference.
473   }
474   return result.release();
475 }
476 
477 // These functions should not exist -- the only valid way to create
478 // descriptors is to call Add() or AddSerializedFile().
479 // But these AddDescriptor() functions were created in Python and some people
480 // call them, so we support them for now for compatibility.
481 // However we do check that the existing descriptor already exists in the pool,
482 // which appears to always be true for existing calls -- but then why do people
483 // call a function that will just be a no-op?
484 // TODO(amauryfa): Need to investigate further.
485 
AddFileDescriptor(PyObject * self,PyObject * descriptor)486 static PyObject* AddFileDescriptor(PyObject* self, PyObject* descriptor) {
487   const FileDescriptor* file_descriptor =
488       PyFileDescriptor_AsDescriptor(descriptor);
489   if (!file_descriptor) {
490     return NULL;
491   }
492   if (file_descriptor !=
493       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileByName(
494           file_descriptor->name())) {
495     PyErr_Format(PyExc_ValueError,
496                  "The file descriptor %s does not belong to this pool",
497                  file_descriptor->name().c_str());
498     return NULL;
499   }
500   Py_RETURN_NONE;
501 }
502 
AddDescriptor(PyObject * self,PyObject * descriptor)503 static PyObject* AddDescriptor(PyObject* self, PyObject* descriptor) {
504   const Descriptor* message_descriptor =
505       PyMessageDescriptor_AsDescriptor(descriptor);
506   if (!message_descriptor) {
507     return NULL;
508   }
509   if (message_descriptor !=
510       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMessageTypeByName(
511           message_descriptor->full_name())) {
512     PyErr_Format(PyExc_ValueError,
513                  "The message descriptor %s does not belong to this pool",
514                  message_descriptor->full_name().c_str());
515     return NULL;
516   }
517   Py_RETURN_NONE;
518 }
519 
AddEnumDescriptor(PyObject * self,PyObject * descriptor)520 static PyObject* AddEnumDescriptor(PyObject* self, PyObject* descriptor) {
521   const EnumDescriptor* enum_descriptor =
522       PyEnumDescriptor_AsDescriptor(descriptor);
523   if (!enum_descriptor) {
524     return NULL;
525   }
526   if (enum_descriptor !=
527       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindEnumTypeByName(
528           enum_descriptor->full_name())) {
529     PyErr_Format(PyExc_ValueError,
530                  "The enum descriptor %s does not belong to this pool",
531                  enum_descriptor->full_name().c_str());
532     return NULL;
533   }
534   Py_RETURN_NONE;
535 }
536 
AddExtensionDescriptor(PyObject * self,PyObject * descriptor)537 static PyObject* AddExtensionDescriptor(PyObject* self, PyObject* descriptor) {
538   const FieldDescriptor* extension_descriptor =
539       PyFieldDescriptor_AsDescriptor(descriptor);
540   if (!extension_descriptor) {
541     return NULL;
542   }
543   if (extension_descriptor !=
544       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByName(
545           extension_descriptor->full_name())) {
546     PyErr_Format(PyExc_ValueError,
547                  "The extension descriptor %s does not belong to this pool",
548                  extension_descriptor->full_name().c_str());
549     return NULL;
550   }
551   Py_RETURN_NONE;
552 }
553 
AddServiceDescriptor(PyObject * self,PyObject * descriptor)554 static PyObject* AddServiceDescriptor(PyObject* self, PyObject* descriptor) {
555   const ServiceDescriptor* service_descriptor =
556       PyServiceDescriptor_AsDescriptor(descriptor);
557   if (!service_descriptor) {
558     return NULL;
559   }
560   if (service_descriptor !=
561       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
562           service_descriptor->full_name())) {
563     PyErr_Format(PyExc_ValueError,
564                  "The service descriptor %s does not belong to this pool",
565                  service_descriptor->full_name().c_str());
566     return NULL;
567   }
568   Py_RETURN_NONE;
569 }
570 
571 // The code below loads new Descriptors from a serialized FileDescriptorProto.
AddSerializedFile(PyObject * pself,PyObject * serialized_pb)572 static PyObject* AddSerializedFile(PyObject* pself, PyObject* serialized_pb) {
573   PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
574   char* message_type;
575   Py_ssize_t message_len;
576 
577   if (self->database != NULL) {
578     PyErr_SetString(
579         PyExc_ValueError,
580         "Cannot call Add on a DescriptorPool that uses a DescriptorDatabase. "
581         "Add your file to the underlying database.");
582     return NULL;
583   }
584 
585   if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
586     return NULL;
587   }
588 
589   FileDescriptorProto file_proto;
590   if (!file_proto.ParseFromArray(message_type, message_len)) {
591     PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
592     return NULL;
593   }
594 
595   // If the file was already part of a C++ library, all its descriptors are in
596   // the underlying pool.  No need to do anything else.
597   const FileDescriptor* generated_file = NULL;
598   if (self->underlay) {
599     generated_file = self->underlay->FindFileByName(file_proto.name());
600   }
601   if (generated_file != NULL) {
602     return PyFileDescriptor_FromDescriptorWithSerializedPb(
603         generated_file, serialized_pb);
604   }
605 
606   BuildFileErrorCollector error_collector;
607   const FileDescriptor* descriptor =
608       self->pool->BuildFileCollectingErrors(file_proto,
609                                             &error_collector);
610   if (descriptor == NULL) {
611     PyErr_Format(PyExc_TypeError,
612                  "Couldn't build proto file into descriptor pool!\n%s",
613                  error_collector.error_message.c_str());
614     return NULL;
615   }
616 
617   return PyFileDescriptor_FromDescriptorWithSerializedPb(
618       descriptor, serialized_pb);
619 }
620 
Add(PyObject * self,PyObject * file_descriptor_proto)621 static PyObject* Add(PyObject* self, PyObject* file_descriptor_proto) {
622   ScopedPyObjectPtr serialized_pb(
623       PyObject_CallMethod(file_descriptor_proto, "SerializeToString", NULL));
624   if (serialized_pb == NULL) {
625     return NULL;
626   }
627   return AddSerializedFile(self, serialized_pb.get());
628 }
629 
630 static PyMethodDef Methods[] = {
631   { "Add", Add, METH_O,
632     "Adds the FileDescriptorProto and its types to this pool." },
633   { "AddSerializedFile", AddSerializedFile, METH_O,
634     "Adds a serialized FileDescriptorProto to this pool." },
635 
636   // TODO(amauryfa): Understand why the Python implementation differs from
637   // this one, ask users to use another API and deprecate these functions.
638   { "AddFileDescriptor", AddFileDescriptor, METH_O,
639     "No-op. Add() must have been called before." },
640   { "AddDescriptor", AddDescriptor, METH_O,
641     "No-op. Add() must have been called before." },
642   { "AddEnumDescriptor", AddEnumDescriptor, METH_O,
643     "No-op. Add() must have been called before." },
644   { "AddExtensionDescriptor", AddExtensionDescriptor, METH_O,
645     "No-op. Add() must have been called before." },
646   { "AddServiceDescriptor", AddServiceDescriptor, METH_O,
647     "No-op. Add() must have been called before." },
648 
649   { "FindFileByName", FindFileByName, METH_O,
650     "Searches for a file descriptor by its .proto name." },
651   { "FindMessageTypeByName", FindMessageByName, METH_O,
652     "Searches for a message descriptor by full name." },
653   { "FindFieldByName", FindFieldByNameMethod, METH_O,
654     "Searches for a field descriptor by full name." },
655   { "FindExtensionByName", FindExtensionByNameMethod, METH_O,
656     "Searches for extension descriptor by full name." },
657   { "FindEnumTypeByName", FindEnumTypeByNameMethod, METH_O,
658     "Searches for enum type descriptor by full name." },
659   { "FindOneofByName", FindOneofByNameMethod, METH_O,
660     "Searches for oneof descriptor by full name." },
661   { "FindServiceByName", FindServiceByName, METH_O,
662     "Searches for service descriptor by full name." },
663   { "FindMethodByName", FindMethodByName, METH_O,
664     "Searches for method descriptor by full name." },
665 
666   { "FindFileContainingSymbol", FindFileContainingSymbol, METH_O,
667     "Gets the FileDescriptor containing the specified symbol." },
668   { "FindExtensionByNumber", FindExtensionByNumber, METH_VARARGS,
669     "Gets the extension descriptor for the given number." },
670   { "FindAllExtensions", FindAllExtensions, METH_O,
671     "Gets all known extensions of the given message descriptor." },
672   {NULL}
673 };
674 
675 }  // namespace cdescriptor_pool
676 
677 PyTypeObject PyDescriptorPool_Type = {
678     PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
679     ".DescriptorPool",                        // tp_name
680     sizeof(PyDescriptorPool),                 // tp_basicsize
681     0,                                        // tp_itemsize
682     cdescriptor_pool::Dealloc,                // tp_dealloc
683     0,                                        // tp_print
684     0,                                        // tp_getattr
685     0,                                        // tp_setattr
686     0,                                        // tp_compare
687     0,                                        // tp_repr
688     0,                                        // tp_as_number
689     0,                                        // tp_as_sequence
690     0,                                        // tp_as_mapping
691     0,                                        // tp_hash
692     0,                                        // tp_call
693     0,                                        // tp_str
694     0,                                        // tp_getattro
695     0,                                        // tp_setattro
696     0,                                        // tp_as_buffer
697     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,  // tp_flags
698     "A Descriptor Pool",                      // tp_doc
699     cdescriptor_pool::GcTraverse,             // tp_traverse
700     cdescriptor_pool::GcClear,                // tp_clear
701     0,                                        // tp_richcompare
702     0,                                        // tp_weaklistoffset
703     0,                                        // tp_iter
704     0,                                        // tp_iternext
705     cdescriptor_pool::Methods,                // tp_methods
706     0,                                        // tp_members
707     0,                                        // tp_getset
708     0,                                        // tp_base
709     0,                                        // tp_dict
710     0,                                        // tp_descr_get
711     0,                                        // tp_descr_set
712     0,                                        // tp_dictoffset
713     0,                                        // tp_init
714     0,                                        // tp_alloc
715     cdescriptor_pool::New,                    // tp_new
716     PyObject_GC_Del,                          // tp_free
717 };
718 
719 // This is the DescriptorPool which contains all the definitions from the
720 // generated _pb2.py modules.
721 static PyDescriptorPool* python_generated_pool = NULL;
722 
InitDescriptorPool()723 bool InitDescriptorPool() {
724   if (PyType_Ready(&PyDescriptorPool_Type) < 0)
725     return false;
726 
727   // The Pool of messages declared in Python libraries.
728   // generated_pool() contains all messages already linked in C++ libraries, and
729   // is used as underlay.
730   descriptor_pool_map =
731       new std::unordered_map<const DescriptorPool*, PyDescriptorPool*>;
732   python_generated_pool = cdescriptor_pool::PyDescriptorPool_NewWithUnderlay(
733       DescriptorPool::generated_pool());
734   if (python_generated_pool == NULL) {
735     delete descriptor_pool_map;
736     return false;
737   }
738 
739   // Register this pool to be found for C++-generated descriptors.
740   descriptor_pool_map->insert(
741       std::make_pair(DescriptorPool::generated_pool(),
742                      python_generated_pool));
743 
744   return true;
745 }
746 
747 // The default DescriptorPool used everywhere in this module.
748 // Today it's the python_generated_pool.
749 // TODO(amauryfa): Remove all usages of this function: the pool should be
750 // derived from the context.
GetDefaultDescriptorPool()751 PyDescriptorPool* GetDefaultDescriptorPool() {
752   return python_generated_pool;
753 }
754 
GetDescriptorPool_FromPool(const DescriptorPool * pool)755 PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool) {
756   // Fast path for standard descriptors.
757   if (pool == python_generated_pool->pool ||
758       pool == DescriptorPool::generated_pool()) {
759     return python_generated_pool;
760   }
761   std::unordered_map<const DescriptorPool*, PyDescriptorPool*>::iterator it =
762       descriptor_pool_map->find(pool);
763   if (it == descriptor_pool_map->end()) {
764     PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool");
765     return NULL;
766   }
767   return it->second;
768 }
769 
770 }  // namespace python
771 }  // namespace protobuf
772 }  // namespace google
773