OLD | NEW |
(Empty) | |
| 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 #include <Python.h> |
| 32 |
| 33 #include <google/protobuf/dynamic_message.h> |
| 34 #include <google/protobuf/pyext/descriptor.h> |
| 35 #include <google/protobuf/pyext/message.h> |
| 36 #include <google/protobuf/pyext/message_factory.h> |
| 37 #include <google/protobuf/pyext/scoped_pyobject_ptr.h> |
| 38 |
| 39 #if PY_MAJOR_VERSION >= 3 |
| 40 #if PY_VERSION_HEX < 0x03030000 |
| 41 #error "Python 3.0 - 3.2 are not supported." |
| 42 #endif |
| 43 #define PyString_AsStringAndSize(ob, charpp, sizep) \ |
| 44 (PyUnicode_Check(ob)? \ |
| 45 ((*(charpp) = PyUnicode_AsUTF8AndSize(ob, (sizep))) == NULL? -1: 0): \ |
| 46 PyBytes_AsStringAndSize(ob, (charpp), (sizep))) |
| 47 #endif |
| 48 |
| 49 namespace google { |
| 50 namespace protobuf { |
| 51 namespace python { |
| 52 |
| 53 namespace message_factory { |
| 54 |
| 55 PyMessageFactory* NewMessageFactory(PyTypeObject* type, PyDescriptorPool* pool)
{ |
| 56 PyMessageFactory* factory = reinterpret_cast<PyMessageFactory*>( |
| 57 PyType_GenericAlloc(type, 0)); |
| 58 if (factory == NULL) { |
| 59 return NULL; |
| 60 } |
| 61 |
| 62 DynamicMessageFactory* message_factory = new DynamicMessageFactory(); |
| 63 // This option might be the default some day. |
| 64 message_factory->SetDelegateToGeneratedFactory(true); |
| 65 factory->message_factory = message_factory; |
| 66 |
| 67 factory->pool = pool; |
| 68 // TODO(amauryfa): When the MessageFactory is not created from the |
| 69 // DescriptorPool this reference should be owned, not borrowed. |
| 70 // Py_INCREF(pool); |
| 71 |
| 72 factory->classes_by_descriptor = new PyMessageFactory::ClassesByMessageMap(); |
| 73 |
| 74 return factory; |
| 75 } |
| 76 |
| 77 PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) { |
| 78 static char* kwlist[] = {"pool", 0}; |
| 79 PyObject* pool = NULL; |
| 80 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &pool)) { |
| 81 return NULL; |
| 82 } |
| 83 ScopedPyObjectPtr owned_pool; |
| 84 if (pool == NULL || pool == Py_None) { |
| 85 owned_pool.reset(PyObject_CallFunction( |
| 86 reinterpret_cast<PyObject*>(&PyDescriptorPool_Type), NULL)); |
| 87 if (owned_pool == NULL) { |
| 88 return NULL; |
| 89 } |
| 90 pool = owned_pool.get(); |
| 91 } else { |
| 92 if (!PyObject_TypeCheck(pool, &PyDescriptorPool_Type)) { |
| 93 PyErr_Format(PyExc_TypeError, "Expected a DescriptorPool, got %s", |
| 94 pool->ob_type->tp_name); |
| 95 return NULL; |
| 96 } |
| 97 } |
| 98 |
| 99 return reinterpret_cast<PyObject*>( |
| 100 NewMessageFactory(type, reinterpret_cast<PyDescriptorPool*>(pool))); |
| 101 } |
| 102 |
| 103 static void Dealloc(PyMessageFactory* self) { |
| 104 // TODO(amauryfa): When the MessageFactory is not created from the |
| 105 // DescriptorPool this reference should be owned, not borrowed. |
| 106 // Py_CLEAR(self->pool); |
| 107 typedef PyMessageFactory::ClassesByMessageMap::iterator iterator; |
| 108 for (iterator it = self->classes_by_descriptor->begin(); |
| 109 it != self->classes_by_descriptor->end(); ++it) { |
| 110 Py_DECREF(it->second); |
| 111 } |
| 112 delete self->classes_by_descriptor; |
| 113 delete self->message_factory; |
| 114 Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); |
| 115 } |
| 116 |
| 117 // Add a message class to our database. |
| 118 int RegisterMessageClass(PyMessageFactory* self, |
| 119 const Descriptor* message_descriptor, |
| 120 CMessageClass* message_class) { |
| 121 Py_INCREF(message_class); |
| 122 typedef PyMessageFactory::ClassesByMessageMap::iterator iterator; |
| 123 std::pair<iterator, bool> ret = self->classes_by_descriptor->insert( |
| 124 std::make_pair(message_descriptor, message_class)); |
| 125 if (!ret.second) { |
| 126 // Update case: DECREF the previous value. |
| 127 Py_DECREF(ret.first->second); |
| 128 ret.first->second = message_class; |
| 129 } |
| 130 return 0; |
| 131 } |
| 132 |
| 133 CMessageClass* GetOrCreateMessageClass(PyMessageFactory* self, |
| 134 const Descriptor* descriptor) { |
| 135 // This is the same implementation as MessageFactory.GetPrototype(). |
| 136 ScopedPyObjectPtr py_descriptor( |
| 137 PyMessageDescriptor_FromDescriptor(descriptor)); |
| 138 if (py_descriptor == NULL) { |
| 139 return NULL; |
| 140 } |
| 141 // Do not create a MessageClass that already exists. |
| 142 hash_map<const Descriptor*, CMessageClass*>::iterator it = |
| 143 self->classes_by_descriptor->find(descriptor); |
| 144 if (it != self->classes_by_descriptor->end()) { |
| 145 Py_INCREF(it->second); |
| 146 return it->second; |
| 147 } |
| 148 // Create a new message class. |
| 149 ScopedPyObjectPtr args(Py_BuildValue( |
| 150 "s(){sOsOsO}", descriptor->name().c_str(), |
| 151 "DESCRIPTOR", py_descriptor.get(), |
| 152 "__module__", Py_None, |
| 153 "message_factory", self)); |
| 154 if (args == NULL) { |
| 155 return NULL; |
| 156 } |
| 157 ScopedPyObjectPtr message_class(PyObject_CallObject( |
| 158 reinterpret_cast<PyObject*>(&CMessageClass_Type), args.get())); |
| 159 if (message_class == NULL) { |
| 160 return NULL; |
| 161 } |
| 162 // Create messages class for the messages used by the fields, and registers |
| 163 // all extensions for these messages during the recursion. |
| 164 for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) { |
| 165 const Descriptor* sub_descriptor = |
| 166 descriptor->field(field_idx)->message_type(); |
| 167 // It is NULL if the field type is not a message. |
| 168 if (sub_descriptor != NULL) { |
| 169 CMessageClass* result = GetOrCreateMessageClass(self, sub_descriptor); |
| 170 if (result == NULL) { |
| 171 return NULL; |
| 172 } |
| 173 Py_DECREF(result); |
| 174 } |
| 175 } |
| 176 |
| 177 // Register extensions defined in this message. |
| 178 for (int ext_idx = 0 ; ext_idx < descriptor->extension_count() ; ext_idx++) { |
| 179 const FieldDescriptor* extension = descriptor->extension(ext_idx); |
| 180 ScopedPyObjectPtr py_extended_class( |
| 181 GetOrCreateMessageClass(self, extension->containing_type()) |
| 182 ->AsPyObject()); |
| 183 if (py_extended_class == NULL) { |
| 184 return NULL; |
| 185 } |
| 186 ScopedPyObjectPtr py_extension(PyFieldDescriptor_FromDescriptor(extension)); |
| 187 if (py_extension == NULL) { |
| 188 return NULL; |
| 189 } |
| 190 ScopedPyObjectPtr result(cmessage::RegisterExtension( |
| 191 py_extended_class.get(), py_extension.get())); |
| 192 if (result == NULL) { |
| 193 return NULL; |
| 194 } |
| 195 } |
| 196 return reinterpret_cast<CMessageClass*>(message_class.release()); |
| 197 } |
| 198 |
| 199 // Retrieve the message class added to our database. |
| 200 CMessageClass* GetMessageClass(PyMessageFactory* self, |
| 201 const Descriptor* message_descriptor) { |
| 202 typedef PyMessageFactory::ClassesByMessageMap::iterator iterator; |
| 203 iterator ret = self->classes_by_descriptor->find(message_descriptor); |
| 204 if (ret == self->classes_by_descriptor->end()) { |
| 205 PyErr_Format(PyExc_TypeError, "No message class registered for '%s'", |
| 206 message_descriptor->full_name().c_str()); |
| 207 return NULL; |
| 208 } else { |
| 209 return ret->second; |
| 210 } |
| 211 } |
| 212 |
| 213 static PyMethodDef Methods[] = { |
| 214 {NULL}}; |
| 215 |
| 216 static PyObject* GetPool(PyMessageFactory* self, void* closure) { |
| 217 Py_INCREF(self->pool); |
| 218 return reinterpret_cast<PyObject*>(self->pool); |
| 219 } |
| 220 |
| 221 static PyGetSetDef Getters[] = { |
| 222 {"pool", (getter)GetPool, NULL, "DescriptorPool"}, |
| 223 {NULL} |
| 224 }; |
| 225 |
| 226 } // namespace message_factory |
| 227 |
| 228 PyTypeObject PyMessageFactory_Type = { |
| 229 PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME |
| 230 ".MessageFactory", // tp_name |
| 231 sizeof(PyMessageFactory), // tp_basicsize |
| 232 0, // tp_itemsize |
| 233 (destructor)message_factory::Dealloc, // tp_dealloc |
| 234 0, // tp_print |
| 235 0, // tp_getattr |
| 236 0, // tp_setattr |
| 237 0, // tp_compare |
| 238 0, // tp_repr |
| 239 0, // tp_as_number |
| 240 0, // tp_as_sequence |
| 241 0, // tp_as_mapping |
| 242 0, // tp_hash |
| 243 0, // tp_call |
| 244 0, // tp_str |
| 245 0, // tp_getattro |
| 246 0, // tp_setattro |
| 247 0, // tp_as_buffer |
| 248 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags |
| 249 "A static Message Factory", // tp_doc |
| 250 0, // tp_traverse |
| 251 0, // tp_clear |
| 252 0, // tp_richcompare |
| 253 0, // tp_weaklistoffset |
| 254 0, // tp_iter |
| 255 0, // tp_iternext |
| 256 message_factory::Methods, // tp_methods |
| 257 0, // tp_members |
| 258 message_factory::Getters, // tp_getset |
| 259 0, // tp_base |
| 260 0, // tp_dict |
| 261 0, // tp_descr_get |
| 262 0, // tp_descr_set |
| 263 0, // tp_dictoffset |
| 264 0, // tp_init |
| 265 0, // tp_alloc |
| 266 message_factory::New, // tp_new |
| 267 PyObject_Del, // tp_free |
| 268 }; |
| 269 |
| 270 bool InitMessageFactory() { |
| 271 if (PyType_Ready(&PyMessageFactory_Type) < 0) { |
| 272 return false; |
| 273 } |
| 274 |
| 275 return true; |
| 276 } |
| 277 |
| 278 } // namespace python |
| 279 } // namespace protobuf |
| 280 } // namespace google |
OLD | NEW |