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 |