2020 * BSON encoding and decoding.
2121 */
2222
23+
24+ #define _GNU_SOURCE
25+ #include <stdio.h>
26+ #include <time.h>
27+ #undef _GNU_SOURCE // avoid multiple define from Python.h
28+
2329#include <Python.h>
2430#include <datetime.h>
25- #include <time.h>
2631
2732static PyObject * CBSONError ;
2833static PyObject * InvalidName ;
@@ -34,6 +39,7 @@ static PyObject* Code;
3439static PyObject * ObjectId ;
3540static PyObject * DBRef ;
3641static PyObject * RECompile ;
42+ static PyObject * UUID ;
3743
3844#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN )
3945typedef int Py_ssize_t ;
@@ -473,6 +479,33 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject*
473479 }
474480 }
475481 return 1 ;
482+ } else if (UUID && PyObject_IsInstance (value , UUID )) {
483+ // Just a special case of Binary above, but simpler to do as a separate case
484+
485+ // UUID is always 16 bytes, subtype 3
486+ int length = 16 ;
487+ const char subtype = 3 ;
488+
489+ PyObject * bytes ;
490+
491+ * (buffer -> buffer + type_byte ) = 0x05 ;
492+ if (!buffer_write_bytes (buffer , (const char * )& length , 4 )) {
493+ return 0 ;
494+ }
495+ if (!buffer_write_bytes (buffer , & subtype , 1 )) {
496+ return 0 ;
497+ }
498+
499+ bytes = PyObject_GetAttrString (value , "bytes" );
500+ if (!bytes ) {
501+ return 0 ;
502+ }
503+ if (!buffer_write_bytes (buffer , PyString_AsString (bytes ), length )) {
504+ Py_DECREF (bytes );
505+ return 0 ;
506+ }
507+ Py_DECREF (bytes );
508+ return 1 ;
476509 } else if (PyObject_IsInstance (value , Code )) {
477510 int start_position ,
478511 length_location ,
@@ -1072,6 +1105,7 @@ static PyObject* get_value(const char* buffer, int* position, int type) {
10721105
10731106 memcpy (& length , buffer + * position , 4 );
10741107 subtype = (unsigned char )buffer [* position + 4 ];
1108+
10751109 if (subtype == 2 ) {
10761110 data = PyString_FromStringAndSize (buffer + * position + 9 , length - 4 );
10771111 } else {
@@ -1080,6 +1114,35 @@ static PyObject* get_value(const char* buffer, int* position, int type) {
10801114 if (!data ) {
10811115 return NULL ;
10821116 }
1117+
1118+ if (subtype == 3 && UUID ) { // Encode as UUID, not Binary
1119+ PyObject * kwargs ;
1120+ PyObject * args = PyTuple_New (0 );
1121+ if (!args ) {
1122+ return NULL ;
1123+ }
1124+ kwargs = PyDict_New ();
1125+ if (!kwargs ) {
1126+ Py_DECREF (args );
1127+ return NULL ;
1128+ }
1129+
1130+ assert (length == 16 ); // UUID should always be 16 bytes
1131+
1132+ PyDict_SetItemString (kwargs , "bytes" , data );
1133+ value = PyObject_Call (UUID , args , kwargs );
1134+
1135+ Py_DECREF (args );
1136+ Py_DECREF (kwargs );
1137+ Py_DECREF (data );
1138+ if (!value ) {
1139+ return NULL ;
1140+ }
1141+
1142+ * position += length + 5 ;
1143+ break ;
1144+ }
1145+
10831146 st = PyInt_FromLong (subtype );
10841147 if (!st ) {
10851148 Py_DECREF (data );
@@ -1433,4 +1496,13 @@ PyMODINIT_FUNC init_cbson(void) {
14331496 }
14341497 RECompile = PyObject_GetAttrString (module , "compile" );
14351498 Py_DECREF (module );
1499+
1500+ module = PyImport_ImportModule ("uuid" );
1501+ if (!module ) {
1502+ UUID = NULL ;
1503+ PyErr_Clear ();
1504+ } else {
1505+ UUID = PyObject_GetAttrString (module , "UUID" );
1506+ Py_DECREF (module );
1507+ }
14361508}
0 commit comments