1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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// Author: petar@google.com (Petar Petrov)
32
33#include <Python.h>
34#include <string>
35
36#include <google/protobuf/pyext/python_descriptor.h>
37#include <google/protobuf/descriptor.pb.h>
38
39#define C(str) const_cast<char*>(str)
40
41namespace google {
42namespace protobuf {
43namespace python {
44
45
46static void CFieldDescriptorDealloc(CFieldDescriptor* self);
47
48static google::protobuf::DescriptorPool* g_descriptor_pool = NULL;
49
50static PyObject* CFieldDescriptor_GetFullName(
51    CFieldDescriptor* self, void *closure) {
52  Py_XINCREF(self->full_name);
53  return self->full_name;
54}
55
56static PyObject* CFieldDescriptor_GetName(
57    CFieldDescriptor *self, void *closure) {
58  Py_XINCREF(self->name);
59  return self->name;
60}
61
62static PyObject* CFieldDescriptor_GetCppType(
63    CFieldDescriptor *self, void *closure) {
64  Py_XINCREF(self->cpp_type);
65  return self->cpp_type;
66}
67
68static PyObject* CFieldDescriptor_GetLabel(
69    CFieldDescriptor *self, void *closure) {
70  Py_XINCREF(self->label);
71  return self->label;
72}
73
74static PyObject* CFieldDescriptor_GetID(
75    CFieldDescriptor *self, void *closure) {
76  Py_XINCREF(self->id);
77  return self->id;
78}
79
80
81static PyGetSetDef CFieldDescriptorGetters[] = {
82  { C("full_name"),
83    (getter)CFieldDescriptor_GetFullName, NULL, "Full name", NULL},
84  { C("name"),
85    (getter)CFieldDescriptor_GetName, NULL, "last name", NULL},
86  { C("cpp_type"),
87    (getter)CFieldDescriptor_GetCppType, NULL, "C++ Type", NULL},
88  { C("label"),
89    (getter)CFieldDescriptor_GetLabel, NULL, "Label", NULL},
90  { C("id"),
91    (getter)CFieldDescriptor_GetID, NULL, "ID", NULL},
92  {NULL}
93};
94
95PyTypeObject CFieldDescriptor_Type = {
96  PyObject_HEAD_INIT(&PyType_Type)
97  0,
98  C("google.protobuf.internal."
99    "_net_proto2___python."
100    "CFieldDescriptor"),                // tp_name
101  sizeof(CFieldDescriptor),             // tp_basicsize
102  0,                                    // tp_itemsize
103  (destructor)CFieldDescriptorDealloc,  // tp_dealloc
104  0,                                    // tp_print
105  0,                                    // tp_getattr
106  0,                                    // tp_setattr
107  0,                                    // tp_compare
108  0,                                    // tp_repr
109  0,                                    // tp_as_number
110  0,                                    // tp_as_sequence
111  0,                                    // tp_as_mapping
112  0,                                    // tp_hash
113  0,                                    // tp_call
114  0,                                    // tp_str
115  0,                                    // tp_getattro
116  0,                                    // tp_setattro
117  0,                                    // tp_as_buffer
118  Py_TPFLAGS_DEFAULT,                   // tp_flags
119  C("A Field Descriptor"),              // tp_doc
120  0,                                    // tp_traverse
121  0,                                    // tp_clear
122  0,                                    // tp_richcompare
123  0,                                    // tp_weaklistoffset
124  0,                                    // tp_iter
125  0,                                    // tp_iternext
126  0,                                    // tp_methods
127  0,                                    // tp_members
128  CFieldDescriptorGetters,              // tp_getset
129  0,                                    // tp_base
130  0,                                    // tp_dict
131  0,                                    // tp_descr_get
132  0,                                    // tp_descr_set
133  0,                                    // tp_dictoffset
134  0,                                    // tp_init
135  PyType_GenericAlloc,                  // tp_alloc
136  PyType_GenericNew,                    // tp_new
137  PyObject_Del,                         // tp_free
138};
139
140static void CFieldDescriptorDealloc(CFieldDescriptor* self) {
141  Py_DECREF(self->full_name);
142  Py_DECREF(self->name);
143  Py_DECREF(self->cpp_type);
144  Py_DECREF(self->label);
145  Py_DECREF(self->id);
146  self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
147}
148
149typedef struct {
150  PyObject_HEAD
151
152  const google::protobuf::DescriptorPool* pool;
153} CDescriptorPool;
154
155static void CDescriptorPoolDealloc(CDescriptorPool* self);
156
157static PyObject* CDescriptorPool_NewCDescriptor(
158    const google::protobuf::FieldDescriptor* field_descriptor) {
159  CFieldDescriptor* cfield_descriptor = PyObject_New(
160      CFieldDescriptor, &CFieldDescriptor_Type);
161  if (cfield_descriptor == NULL) {
162    return NULL;
163  }
164  cfield_descriptor->descriptor = field_descriptor;
165
166  cfield_descriptor->full_name = PyString_FromString(
167      field_descriptor->full_name().c_str());
168  cfield_descriptor->name = PyString_FromString(
169      field_descriptor->name().c_str());
170  cfield_descriptor->cpp_type = PyLong_FromLong(field_descriptor->cpp_type());
171  cfield_descriptor->label = PyLong_FromLong(field_descriptor->label());
172  cfield_descriptor->id = PyLong_FromVoidPtr(cfield_descriptor);
173  return reinterpret_cast<PyObject*>(cfield_descriptor);
174}
175
176static PyObject* CDescriptorPool_FindFieldByName(
177    CDescriptorPool* self, PyObject* arg) {
178  const char* full_field_name = PyString_AsString(arg);
179  if (full_field_name == NULL) {
180    return NULL;
181  }
182
183  const google::protobuf::FieldDescriptor* field_descriptor = NULL;
184
185  field_descriptor = self->pool->FindFieldByName(full_field_name);
186
187
188  if (field_descriptor == NULL) {
189    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
190                 full_field_name);
191    return NULL;
192  }
193
194  return CDescriptorPool_NewCDescriptor(field_descriptor);
195}
196
197static PyObject* CDescriptorPool_FindExtensionByName(
198    CDescriptorPool* self, PyObject* arg) {
199  const char* full_field_name = PyString_AsString(arg);
200  if (full_field_name == NULL) {
201    return NULL;
202  }
203
204  const google::protobuf::FieldDescriptor* field_descriptor =
205      self->pool->FindExtensionByName(full_field_name);
206  if (field_descriptor == NULL) {
207    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
208                 full_field_name);
209    return NULL;
210  }
211
212  return CDescriptorPool_NewCDescriptor(field_descriptor);
213}
214
215static PyMethodDef CDescriptorPoolMethods[] = {
216  { C("FindFieldByName"),
217    (PyCFunction)CDescriptorPool_FindFieldByName,
218    METH_O,
219    C("Searches for a field descriptor by full name.") },
220  { C("FindExtensionByName"),
221    (PyCFunction)CDescriptorPool_FindExtensionByName,
222    METH_O,
223    C("Searches for extension descriptor by full name.") },
224  {NULL}
225};
226
227PyTypeObject CDescriptorPool_Type = {
228  PyObject_HEAD_INIT(&PyType_Type)
229  0,
230  C("google.protobuf.internal."
231    "_net_proto2___python."
232    "CFieldDescriptor"),               // tp_name
233  sizeof(CDescriptorPool),             // tp_basicsize
234  0,                                   // tp_itemsize
235  (destructor)CDescriptorPoolDealloc,  // tp_dealloc
236  0,                                   // tp_print
237  0,                                   // tp_getattr
238  0,                                   // tp_setattr
239  0,                                   // tp_compare
240  0,                                   // tp_repr
241  0,                                   // tp_as_number
242  0,                                   // tp_as_sequence
243  0,                                   // tp_as_mapping
244  0,                                   // tp_hash
245  0,                                   // tp_call
246  0,                                   // tp_str
247  0,                                   // tp_getattro
248  0,                                   // tp_setattro
249  0,                                   // tp_as_buffer
250  Py_TPFLAGS_DEFAULT,                  // tp_flags
251  C("A Descriptor Pool"),              // tp_doc
252  0,                                   // tp_traverse
253  0,                                   // tp_clear
254  0,                                   // tp_richcompare
255  0,                                   // tp_weaklistoffset
256  0,                                   // tp_iter
257  0,                                   // tp_iternext
258  CDescriptorPoolMethods,              // tp_methods
259  0,                                   // tp_members
260  0,                                   // tp_getset
261  0,                                   // tp_base
262  0,                                   // tp_dict
263  0,                                   // tp_descr_get
264  0,                                   // tp_descr_set
265  0,                                   // tp_dictoffset
266  0,                                   // tp_init
267  PyType_GenericAlloc,                 // tp_alloc
268  PyType_GenericNew,                   // tp_new
269  PyObject_Del,                        // tp_free
270};
271
272static void CDescriptorPoolDealloc(CDescriptorPool* self) {
273  self->ob_type->tp_free(reinterpret_cast<PyObject*>(self));
274}
275
276google::protobuf::DescriptorPool* GetDescriptorPool() {
277  if (g_descriptor_pool == NULL) {
278    g_descriptor_pool = new google::protobuf::DescriptorPool(
279        google::protobuf::DescriptorPool::generated_pool());
280  }
281  return g_descriptor_pool;
282}
283
284PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args) {
285  CDescriptorPool* cdescriptor_pool = PyObject_New(
286      CDescriptorPool, &CDescriptorPool_Type);
287  if (cdescriptor_pool == NULL) {
288    return NULL;
289  }
290  cdescriptor_pool->pool = GetDescriptorPool();
291  return reinterpret_cast<PyObject*>(cdescriptor_pool);
292}
293
294PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) {
295  char* message_type;
296  Py_ssize_t message_len;
297
298  if (PyString_AsStringAndSize(arg, &message_type, &message_len) < 0) {
299    return NULL;
300  }
301
302  google::protobuf::FileDescriptorProto file_proto;
303  if (!file_proto.ParseFromArray(message_type, message_len)) {
304    PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
305    return NULL;
306  }
307
308  if (google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
309      file_proto.name()) != NULL) {
310    Py_RETURN_NONE;
311  }
312
313  const google::protobuf::FileDescriptor* descriptor = GetDescriptorPool()->BuildFile(
314      file_proto);
315  if (descriptor == NULL) {
316    PyErr_SetString(PyExc_TypeError,
317                    "Couldn't build proto file into descriptor pool!");
318    return NULL;
319  }
320
321  Py_RETURN_NONE;
322}
323
324bool InitDescriptor() {
325  CFieldDescriptor_Type.tp_new = PyType_GenericNew;
326  if (PyType_Ready(&CFieldDescriptor_Type) < 0)
327    return false;
328
329  CDescriptorPool_Type.tp_new = PyType_GenericNew;
330  if (PyType_Ready(&CDescriptorPool_Type) < 0)
331    return false;
332  return true;
333}
334
335}  // namespace python
336}  // namespace protobuf
337}  // namespace google
338