@@ -2867,9 +2867,6 @@ static int _element_to_dict(PyObject* self, const char* string,
28672867}
28682868
28692869static PyObject * _cbson_element_to_dict (PyObject * self , PyObject * args ) {
2870- /* TODO(PYTHON-6038): buffer-protocol inputs are copied
2871- * upstream in get_data_and_view. Native RawBSONDocument inflation in C
2872- * should accept the buffer directly. */
28732870 char * string ;
28742871 PyObject * bson ;
28752872 PyObject * options_obj = NULL ;
@@ -3094,6 +3091,98 @@ static PyObject* _prepare_input_buffer(PyObject* self, PyObject* bson,
30943091 return PyBytes_FromObject (bson );
30953092}
30963093
3094+ /* Decode all elements of a raw BSON document into `result`. */
3095+ static PyObject * _cbson_raw_to_dict (PyObject * self , PyObject * args ) {
3096+ PyObject * data ;
3097+ unsigned position ;
3098+ unsigned obj_end ;
3099+ PyObject * options_obj ;
3100+ PyObject * result ;
3101+ int raw_array = 0 ;
3102+ codec_options_t options ;
3103+ PyObject * bson = NULL ;
3104+ Py_buffer view = {0 };
3105+ PyObject * ret = NULL ;
3106+ const char * string ;
3107+ unsigned end ;
3108+
3109+ if (!(PyArg_ParseTuple (args , "OIIOOp" , & data , & position , & obj_end ,
3110+ & options_obj , & result , & raw_array ) &&
3111+ convert_codec_options (self , options_obj , & options ))) {
3112+ return NULL ;
3113+ }
3114+
3115+ bson = _prepare_input_buffer (self , data , & options );
3116+ if (!bson ) {
3117+ destroy_codec_options (& options );
3118+ return NULL ;
3119+ }
3120+
3121+ if (!_get_buffer (bson , & view )) {
3122+ Py_DECREF (bson );
3123+ destroy_codec_options (& options );
3124+ return NULL ;
3125+ }
3126+
3127+ string = (char * )view .buf ;
3128+ /* obj_end must be the index of the document's eoo byte. The eoo check
3129+ * also protects against field scans running past the end of the buffer. */
3130+ if (obj_end < 1 || (Py_ssize_t )obj_end >= view .len || position > obj_end ||
3131+ string [obj_end ]) {
3132+ PyObject * InvalidBSON = _error ("InvalidBSON" );
3133+ if (InvalidBSON ) {
3134+ PyErr_SetString (InvalidBSON , "bad object or element length" );
3135+ Py_DECREF (InvalidBSON );
3136+ }
3137+ goto done ;
3138+ }
3139+
3140+ options .buffer_owner = bson ;
3141+
3142+ end = obj_end - 1 ;
3143+ while (position < end ) {
3144+ PyObject * name = NULL ;
3145+ PyObject * value = NULL ;
3146+ int new_position = _element_to_dict (
3147+ self , string , position , obj_end , & options , raw_array , & name , & value );
3148+ if (new_position < 0 ) {
3149+ goto done ;
3150+ }
3151+ position = (unsigned )new_position ;
3152+
3153+ if (PyDict_CheckExact (result )) {
3154+ if (PyDict_SetItem (result , name , value ) < 0 ) {
3155+ Py_DECREF (name );
3156+ Py_DECREF (value );
3157+ goto done ;
3158+ }
3159+ } else {
3160+ if (PyObject_SetItem (result , name , value ) < 0 ) {
3161+ Py_DECREF (name );
3162+ Py_DECREF (value );
3163+ goto done ;
3164+ }
3165+ }
3166+ Py_DECREF (name );
3167+ Py_DECREF (value );
3168+ }
3169+ if (position != obj_end ) {
3170+ PyObject * InvalidBSON = _error ("InvalidBSON" );
3171+ if (InvalidBSON ) {
3172+ PyErr_SetString (InvalidBSON , "bad object or element length" );
3173+ Py_DECREF (InvalidBSON );
3174+ }
3175+ goto done ;
3176+ }
3177+ Py_INCREF (result );
3178+ ret = result ;
3179+ done :
3180+ PyBuffer_Release (& view );
3181+ Py_DECREF (bson );
3182+ destroy_codec_options (& options );
3183+ return ret ;
3184+ }
3185+
30973186static PyObject * _cbson_bson_to_dict (PyObject * self , PyObject * args ) {
30983187 int32_t size ;
30993188 Py_ssize_t total_size ;
@@ -3423,6 +3512,8 @@ static PyMethodDef _CBSONMethods[] = {
34233512 "convert binary data to a sequence of documents." },
34243513 {"_element_to_dict" , _cbson_element_to_dict , METH_VARARGS ,
34253514 "Decode a single key, value pair." },
3515+ {"_raw_to_dict" , _cbson_raw_to_dict , METH_VARARGS ,
3516+ "Decode all elements of a raw BSON document into a result mapping." },
34263517 {"_array_of_documents_to_buffer" , _cbson_array_of_documents_to_buffer , METH_VARARGS , "Convert raw array of documents to a stream of BSON documents" },
34273518 {"_test_long_long_to_str" , _test_long_long_to_str , METH_VARARGS , "Test conversion of extreme and common Py_ssize_t values to str." },
34283519 {NULL , NULL , 0 , NULL }
0 commit comments