@@ -11,7 +11,7 @@ static PyObject *MaxMindDB_error;
1111
1212typedef struct {
1313 PyObject_HEAD /* no semicolon */
14- MMDB_s * mmdb ;
14+ MMDB_s * mmdb ;
1515} Reader_obj ;
1616
1717typedef struct {
@@ -27,17 +27,10 @@ typedef struct {
2727 PyObject * record_size ;
2828} Metadata_obj ;
2929
30- static const MMDB_entry_data_list_s * handle_entry_data_list (
31- const MMDB_entry_data_list_s * entry_data_list ,
32- PyObject * * py_obj );
33- static const MMDB_entry_data_list_s * handle_map (
34- const MMDB_entry_data_list_s * entry_data_list ,
35- PyObject * * py_obj );
36- static const MMDB_entry_data_list_s * handle_array (
37- const MMDB_entry_data_list_s * entry_data_list ,
38- PyObject * * py_obj );
39- static void handle_uint128 (const MMDB_entry_data_list_s * entry_data_list ,
40- PyObject * * py_obj );
30+ static PyObject * from_entry_data_list (MMDB_entry_data_list_s * * entry_data_list );
31+ static PyObject * from_map (MMDB_entry_data_list_s * * entry_data_list );
32+ static PyObject * from_array (MMDB_entry_data_list_s * * entry_data_list );
33+ static PyObject * from_uint128 (const MMDB_entry_data_list_s * entry_data_list );
4134
4235#if PY_MAJOR_VERSION >= 3
4336 #define MOD_INIT (name ) PyMODINIT_FUNC PyInit_ ## name(void)
@@ -54,7 +47,7 @@ static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
5447 # define UNUSED (x ) UNUSED_ ## x
5548#endif
5649
57- static PyObject * Reader_constructor (PyObject * UNUSED (self ), PyObject * args )
50+ static PyObject * Reader_constructor (PyObject * UNUSED (self ), PyObject * args )
5851{
5952 char * filename ;
6053
@@ -77,13 +70,15 @@ static PyObject *Reader_constructor(PyObject *UNUSED(self), PyObject * args)
7770
7871 Reader_obj * obj = PyObject_New (Reader_obj , & Reader_Type );
7972 if (!obj ) {
73+ PyErr_NoMemory ();
8074 return NULL ;
8175 }
8276
8377 uint16_t status = MMDB_open (filename , MMDB_MODE_MMAP , mmdb );
8478
8579 if (MMDB_SUCCESS != status ) {
8680 free (mmdb );
81+ PyObject_Del (obj );
8782 return PyErr_Format (
8883 MaxMindDB_error ,
8984 "Error opening database file (%s). Is this a valid MaxMind DB file?" ,
@@ -95,7 +90,7 @@ static PyObject *Reader_constructor(PyObject *UNUSED(self), PyObject * args)
9590 return (PyObject * )obj ;
9691}
9792
98- static PyObject * Reader_get (PyObject * self , PyObject * args )
93+ static PyObject * Reader_get (PyObject * self , PyObject * args )
9994{
10095 char * ip_address = NULL ;
10196
@@ -131,14 +126,11 @@ static PyObject *Reader_get(PyObject * self, PyObject * args)
131126 return NULL ;
132127 }
133128
134- MMDB_entry_data_list_s * entry_data_list = NULL ;
135-
136129 if (!result .found_entry ) {
137130 Py_RETURN_NONE ;
138131 }
139132
140- PyObject * py_obj = NULL ;
141-
133+ MMDB_entry_data_list_s * entry_data_list = NULL ;
142134 int status = MMDB_get_entry_data_list (& result .entry , & entry_data_list );
143135 if (MMDB_SUCCESS != status ) {
144136 PyErr_Format (MaxMindDB_error ,
@@ -154,8 +146,9 @@ static PyObject *Reader_get(PyObject * self, PyObject * args)
154146 return NULL ;
155147 }
156148
157- handle_entry_data_list (entry_data_list , & py_obj );
158- MMDB_free_entry_data_list (entry_data_list );
149+ MMDB_entry_data_list_s * original_entry_data_list = entry_data_list ;
150+ PyObject * py_obj = from_entry_data_list (& entry_data_list );
151+ MMDB_free_entry_data_list (original_entry_data_list );
159152 return py_obj ;
160153}
161154
@@ -174,13 +167,18 @@ static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args))
174167 return NULL ;
175168 }
176169
177- PyObject * metadata_dict ;
178-
179170 MMDB_entry_data_list_s * entry_data_list ;
180171 MMDB_get_metadata_as_entry_data_list (mmdb_obj -> mmdb , & entry_data_list );
181-
182- handle_entry_data_list (entry_data_list , & metadata_dict );
183- MMDB_free_entry_data_list (entry_data_list );
172+ MMDB_entry_data_list_s * original_entry_data_list = entry_data_list ;
173+
174+ PyObject * metadata_dict = from_entry_data_list (& entry_data_list );
175+ MMDB_free_entry_data_list (original_entry_data_list );
176+ if (NULL == metadata_dict || !PyDict_Check (metadata_dict )) {
177+ PyErr_SetString (MaxMindDB_error ,
178+ "Error decoding metadata." );
179+ PyObject_Del (obj );
180+ return NULL ;
181+ }
184182
185183 obj -> binary_format_major_version = PyDict_GetItemString (
186184 metadata_dict , "binary_format_major_version" );
@@ -194,6 +192,21 @@ static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args))
194192 obj -> node_count = PyDict_GetItemString (metadata_dict , "node_count" );
195193 obj -> record_size = PyDict_GetItemString (metadata_dict , "record_size" );
196194
195+ if (NULL == obj -> binary_format_major_version ||
196+ NULL == obj -> binary_format_minor_version ||
197+ NULL == obj -> build_epoch ||
198+ NULL == obj -> database_type ||
199+ NULL == obj -> description ||
200+ NULL == obj -> ip_version ||
201+ NULL == obj -> languages ||
202+ NULL == obj -> node_count ||
203+ NULL == obj -> record_size ) {
204+ PyErr_SetString (MaxMindDB_error ,
205+ "Error decoding metadata." );
206+ PyObject_Del (obj );
207+ return NULL ;
208+ }
209+
197210 Py_INCREF (obj -> binary_format_major_version );
198211 Py_INCREF (obj -> binary_format_minor_version );
199212 Py_INCREF (obj -> build_epoch );
@@ -203,11 +216,13 @@ static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args))
203216 Py_INCREF (obj -> languages );
204217 Py_INCREF (obj -> node_count );
205218 Py_INCREF (obj -> record_size );
219+
206220 Py_DECREF (metadata_dict );
221+
207222 return (PyObject * )obj ;
208223}
209224
210- static PyObject * Reader_close (PyObject * self , PyObject * UNUSED (args ))
225+ static PyObject * Reader_close (PyObject * self , PyObject * UNUSED (args ))
211226{
212227 Reader_obj * mmdb_obj = (Reader_obj * )self ;
213228
@@ -223,7 +238,7 @@ static PyObject *Reader_close(PyObject * self, PyObject *UNUSED(args))
223238 Py_RETURN_NONE ;
224239}
225240
226- static void Reader_dealloc (PyObject * self )
241+ static void Reader_dealloc (PyObject * self )
227242{
228243 Reader_obj * obj = (Reader_obj * )self ;
229244 if (NULL != obj -> mmdb ) {
@@ -233,7 +248,7 @@ static void Reader_dealloc(PyObject * self)
233248 PyObject_Del (self );
234249}
235250
236- static void Metadata_dealloc (PyObject * self )
251+ static void Metadata_dealloc (PyObject * self )
237252{
238253 Metadata_obj * obj = (Metadata_obj * )self ;
239254 Py_DECREF (obj -> binary_format_major_version );
@@ -248,118 +263,108 @@ static void Metadata_dealloc(PyObject * self)
248263 PyObject_Del (self );
249264}
250265
251- static const MMDB_entry_data_list_s * handle_entry_data_list (
252- const MMDB_entry_data_list_s * entry_data_list ,
253- PyObject * * py_obj )
266+ static PyObject * from_entry_data_list (MMDB_entry_data_list_s * * entry_data_list )
254267{
255- switch (entry_data_list -> entry_data .type ) {
268+ switch (( * entry_data_list ) -> entry_data .type ) {
256269 case MMDB_DATA_TYPE_MAP :
257- return handle_map (entry_data_list , py_obj );
270+ return from_map (entry_data_list );
258271 case MMDB_DATA_TYPE_ARRAY :
259- return handle_array (entry_data_list , py_obj );
272+ return from_array (entry_data_list );
260273 case MMDB_DATA_TYPE_UTF8_STRING :
261- * py_obj = PyUnicode_FromStringAndSize (
262- entry_data_list -> entry_data .utf8_string ,
263- entry_data_list -> entry_data .data_size
264- );
265- break ;
274+ return PyUnicode_FromStringAndSize (
275+ (* entry_data_list )-> entry_data .utf8_string ,
276+ (* entry_data_list )-> entry_data .data_size
277+ );
266278 case MMDB_DATA_TYPE_BYTES :
267- * py_obj = PyByteArray_FromStringAndSize (
268- (const char * )entry_data_list -> entry_data .bytes ,
269- (Py_ssize_t )entry_data_list -> entry_data .data_size );
270- break ;
279+ return PyByteArray_FromStringAndSize (
280+ (const char * )(* entry_data_list )-> entry_data .bytes ,
281+ (Py_ssize_t )(* entry_data_list )-> entry_data .data_size );
271282 case MMDB_DATA_TYPE_DOUBLE :
272- * py_obj = PyFloat_FromDouble (entry_data_list -> entry_data .double_value );
273- break ;
283+ return PyFloat_FromDouble ((* entry_data_list )-> entry_data .double_value );
274284 case MMDB_DATA_TYPE_FLOAT :
275- * py_obj = PyFloat_FromDouble (entry_data_list -> entry_data .float_value );
276- break ;
285+ return PyFloat_FromDouble ((* entry_data_list )-> entry_data .float_value );
277286 case MMDB_DATA_TYPE_UINT16 :
278- * py_obj = PyLong_FromLong ( entry_data_list -> entry_data .uint16 );
279- break ;
287+ return PyLong_FromLong ( (* entry_data_list )-> entry_data .uint16 );
280288 case MMDB_DATA_TYPE_UINT32 :
281- * py_obj = PyLong_FromLong (entry_data_list -> entry_data .uint32 );
282- break ;
289+ return PyLong_FromLong ((* entry_data_list )-> entry_data .uint32 );
283290 case MMDB_DATA_TYPE_BOOLEAN :
284- * py_obj = PyBool_FromLong (entry_data_list -> entry_data .boolean );
285- break ;
291+ return PyBool_FromLong ((* entry_data_list )-> entry_data .boolean );
286292 case MMDB_DATA_TYPE_UINT64 :
287- * py_obj = PyLong_FromUnsignedLongLong (
288- entry_data_list -> entry_data .uint64 );
289- break ;
293+ return PyLong_FromUnsignedLongLong (
294+ (* entry_data_list )-> entry_data .uint64 );
290295 case MMDB_DATA_TYPE_UINT128 :
291- handle_uint128 (entry_data_list , py_obj );
292- break ;
296+ return from_uint128 (* entry_data_list );
293297 case MMDB_DATA_TYPE_INT32 :
294- * py_obj = PyLong_FromLong (entry_data_list -> entry_data .int32 );
295- break ;
298+ return PyLong_FromLong ((* entry_data_list )-> entry_data .int32 );
296299 default :
297300 PyErr_Format (MaxMindDB_error ,
298301 "Invalid data type arguments: %d" ,
299- entry_data_list -> entry_data .type );
302+ ( * entry_data_list ) -> entry_data .type );
300303 return NULL ;
301304 }
302- return entry_data_list -> next ;
305+ return NULL ;
303306}
304307
305- static const MMDB_entry_data_list_s * handle_map (
306- const MMDB_entry_data_list_s * entry_data_list ,
307- PyObject * * py_obj )
308+ static PyObject * from_map (MMDB_entry_data_list_s * * entry_data_list )
308309{
309- * py_obj = PyDict_New ();
310- if (* py_obj == NULL ) {
310+ PyObject * py_obj = PyDict_New ();
311+ if (NULL == py_obj ) {
311312 PyErr_NoMemory ();
312313 return NULL ;
313314 }
314315
315- const uint32_t map_size = entry_data_list -> entry_data .data_size ;
316- entry_data_list = entry_data_list -> next ;
316+ const uint32_t map_size = (* entry_data_list )-> entry_data .data_size ;
317317
318318 uint i ;
319319 for (i = 0 ; i < map_size && entry_data_list ; i ++ ) {
320- PyObject * key , * value ;
320+ * entry_data_list = ( * entry_data_list ) -> next ;
321321
322- key = PyUnicode_FromStringAndSize (
323- (char * )entry_data_list -> entry_data .utf8_string ,
324- entry_data_list -> entry_data .data_size
322+ PyObject * key = PyUnicode_FromStringAndSize (
323+ (char * )( * entry_data_list ) -> entry_data .utf8_string ,
324+ ( * entry_data_list ) -> entry_data .data_size
325325 );
326326
327- entry_data_list = entry_data_list -> next ;
327+ * entry_data_list = ( * entry_data_list ) -> next ;
328328
329- entry_data_list = handle_entry_data_list (entry_data_list ,
330- & value );
331- PyDict_SetItem (* py_obj , key , value );
329+ PyObject * value = from_entry_data_list (entry_data_list );
330+ if (NULL == value ) {
331+ Py_DECREF (key );
332+ Py_DECREF (py_obj );
333+ return NULL ;
334+ }
335+ PyDict_SetItem (py_obj , key , value );
332336 Py_DECREF (value );
333337 Py_DECREF (key );
334338 }
335- return entry_data_list ;
339+
340+ return py_obj ;
336341}
337342
338- static const MMDB_entry_data_list_s * handle_array (
339- const MMDB_entry_data_list_s * entry_data_list ,
340- PyObject * * py_obj )
343+ static PyObject * from_array (MMDB_entry_data_list_s * * entry_data_list )
341344{
342- const uint32_t size = entry_data_list -> entry_data .data_size ;
345+ const uint32_t size = ( * entry_data_list ) -> entry_data .data_size ;
343346
344- * py_obj = PyList_New (size );
345- if (* py_obj == NULL ) {
347+ PyObject * py_obj = PyList_New (size );
348+ if (NULL == py_obj ) {
346349 PyErr_NoMemory ();
347350 return NULL ;
348351 }
349- entry_data_list = entry_data_list -> next ;
350352
351353 uint i ;
352354 for (i = 0 ; i < size && entry_data_list ; i ++ ) {
353- PyObject * new_value ;
354- entry_data_list = handle_entry_data_list (entry_data_list ,
355- & new_value );
356- PyList_SET_ITEM (* py_obj , i , new_value );
355+ * entry_data_list = (* entry_data_list )-> next ;
356+ PyObject * value = from_entry_data_list (entry_data_list );
357+ if (NULL == value ) {
358+ Py_DECREF (py_obj );
359+ return NULL ;
360+ }
361+ // PyList_SetItem 'steals' the reference
362+ PyList_SetItem (py_obj , i , value );
357363 }
358- return entry_data_list ;
364+ return py_obj ;
359365}
360366
361- static void handle_uint128 (const MMDB_entry_data_list_s * entry_data_list ,
362- PyObject * * py_obj )
367+ static PyObject * from_uint128 (const MMDB_entry_data_list_s * entry_data_list )
363368{
364369 uint64_t high = 0 ;
365370 uint64_t low = 0 ;
@@ -377,18 +382,18 @@ static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
377382 low = (uint64_t )entry_data_list -> entry_data .uint128 ;
378383#endif
379384
380- char * num_str ;
381- int status = asprintf (& num_str , "%016" PRIX64 "%016" PRIX64 , high , low );
382-
383- if (status == -1 ) {
385+ char * num_str = malloc (33 );
386+ if (NULL == num_str ) {
384387 PyErr_NoMemory ();
385- * py_obj = NULL ;
386- return ;
388+ return NULL ;
387389 }
388390
389- * py_obj = PyLong_FromString (num_str , NULL , 16 );
391+ snprintf (num_str , 33 , "%016" PRIX64 "%016" PRIX64 , high , low );
392+
393+ PyObject * py_obj = PyLong_FromString (num_str , NULL , 16 );
390394
391395 free (num_str );
396+ return py_obj ;
392397}
393398
394399static PyMethodDef Reader_methods [] = {
0 commit comments