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 (at) 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 41 namespace google { 42 namespace protobuf { 43 namespace python { 44 45 46 static void CFieldDescriptorDealloc(CFieldDescriptor* self); 47 48 static google::protobuf::DescriptorPool* g_descriptor_pool = NULL; 49 50 static PyObject* CFieldDescriptor_GetFullName( 51 CFieldDescriptor* self, void *closure) { 52 Py_XINCREF(self->full_name); 53 return self->full_name; 54 } 55 56 static PyObject* CFieldDescriptor_GetName( 57 CFieldDescriptor *self, void *closure) { 58 Py_XINCREF(self->name); 59 return self->name; 60 } 61 62 static PyObject* CFieldDescriptor_GetCppType( 63 CFieldDescriptor *self, void *closure) { 64 Py_XINCREF(self->cpp_type); 65 return self->cpp_type; 66 } 67 68 static PyObject* CFieldDescriptor_GetLabel( 69 CFieldDescriptor *self, void *closure) { 70 Py_XINCREF(self->label); 71 return self->label; 72 } 73 74 static PyObject* CFieldDescriptor_GetID( 75 CFieldDescriptor *self, void *closure) { 76 Py_XINCREF(self->id); 77 return self->id; 78 } 79 80 81 static 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 95 PyTypeObject 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 140 static 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 149 typedef struct { 150 PyObject_HEAD 151 152 const google::protobuf::DescriptorPool* pool; 153 } CDescriptorPool; 154 155 static void CDescriptorPoolDealloc(CDescriptorPool* self); 156 157 static 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 176 static 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 197 static 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 215 static 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 227 PyTypeObject 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 272 static void CDescriptorPoolDealloc(CDescriptorPool* self) { 273 self->ob_type->tp_free(reinterpret_cast<PyObject*>(self)); 274 } 275 276 google::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 284 PyObject* 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 294 PyObject* 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 324 bool 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