diff --git a/bson/_cbson.h b/bson/_cbson.h index 31055e7e4..c2b78ad5e 100644 --- a/bson/_cbson.h +++ b/bson/_cbson.h @@ -14,33 +14,22 @@ * limitations under the License. */ +#ifndef _CBSON_H +#define _CBSON_H + #include +#include "buffer.h" -/* A buffer representing some data being encoded to BSON. */ -typedef struct { - char* buffer; - int size; - int position; -} bson_buffer; - -bson_buffer* buffer_new(void); - -int buffer_save_bytes(bson_buffer* buffer, int size); - -int buffer_write_bytes(bson_buffer* buffer, const char* bytes, int size); - -void buffer_free(bson_buffer* buffer); - -int write_dict(bson_buffer* buffer, PyObject* dict, +int write_dict(buffer_t buffer, PyObject* dict, unsigned char check_keys, unsigned char top_level); -PyObject* elements_to_dict(const char* string, int max, - PyObject* as_class, unsigned char tz_aware); +PyObject* elements_to_dict(const char* string, int max, PyObject* as_class, + unsigned char tz_aware); -int write_pair(bson_buffer* buffer, const char* name, - Py_ssize_t name_length, PyObject* value, - unsigned char check_keys, unsigned char allow_id); +int write_pair(buffer_t buffer, const char* name, Py_ssize_t name_length, + PyObject* value, unsigned char check_keys, unsigned char allow_id); -int decode_and_write_pair(bson_buffer* buffer, - PyObject* key, PyObject* value, +int decode_and_write_pair(buffer_t buffer, PyObject* key, PyObject* value, unsigned char check_keys, unsigned char top_level); + +#endif diff --git a/bson/_cbsonmodule.c b/bson/_cbsonmodule.c index f0a66f965..85f972679 100644 --- a/bson/_cbsonmodule.c +++ b/bson/_cbsonmodule.c @@ -26,6 +26,7 @@ #include #include "_cbson.h" +#include "buffer.h" #include "time64.h" #include "encoding_helpers.h" @@ -55,8 +56,6 @@ typedef int Py_ssize_t; PyErr_WarnEx((category), (message), 1) #endif -#define INITIAL_BUFFER_SIZE 256 - /* Maximum number of regex flags */ #define FLAGS_SIZE 7 @@ -127,81 +126,17 @@ static long long millis_from_datetime(PyObject* datetime) { return millis; } -bson_buffer* buffer_new(void) { - bson_buffer* buffer; - buffer = (bson_buffer*)malloc(sizeof(bson_buffer)); - if (!buffer) { - PyErr_NoMemory(); - return NULL; - } - buffer->size = INITIAL_BUFFER_SIZE; - buffer->position = 0; - buffer->buffer = (char*)malloc(INITIAL_BUFFER_SIZE); - if (!buffer->buffer) { - PyErr_NoMemory(); - return NULL; - } - return buffer; -} - -void buffer_free(bson_buffer* buffer) { - if (buffer == NULL) { - return; - } - free(buffer->buffer); - free(buffer); -} - -/* returns zero on failure */ -static int buffer_resize(bson_buffer* buffer, int min_length) { - int size = buffer->size; - if (size >= min_length) { - return 1; - } - while (size < min_length) { - size *= 2; - } - buffer->buffer = (char*)realloc(buffer->buffer, size); - if (!buffer->buffer) { +/* Just make this compatible w/ the old API. */ +static inline int buffer_write_bytes(buffer_t buffer, const char* data, int size) { + if (buffer_write(buffer, data, size)) { PyErr_NoMemory(); return 0; } - buffer->size = size; - return 1; -} - -/* returns zero on failure */ -static int buffer_assure_space(bson_buffer* buffer, int size) { - if (buffer->position + size <= buffer->size) { - return 1; - } - return buffer_resize(buffer, buffer->position + size); -} - -/* returns offset for writing, or -1 on failure */ -int buffer_save_bytes(bson_buffer* buffer, int size) { - int position; - - if (!buffer_assure_space(buffer, size)) { - return -1; - } - position = buffer->position; - buffer->position += size; - return position; -} - -/* returns zero on failure */ -int buffer_write_bytes(bson_buffer* buffer, const char* bytes, int size) { - if (!buffer_assure_space(buffer, size)) { - return 0; - } - memcpy(buffer->buffer + buffer->position, bytes, size); - buffer->position += size; return 1; } /* returns 0 on failure */ -static int write_string(bson_buffer* buffer, PyObject* py_string) { +static int write_string(buffer_t buffer, PyObject* py_string) { Py_ssize_t string_length; const char* string = PyString_AsString(py_string); if (!string) { @@ -280,11 +215,11 @@ static int _reload_python_objects(void) { * space has already been reserved. * * returns 0 on failure */ -static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* value, unsigned char check_keys, unsigned char first_attempt) { +static int write_element_to_buffer(buffer_t buffer, int type_byte, PyObject* value, unsigned char check_keys, unsigned char first_attempt) { if (PyBool_Check(value)) { const long bool = PyInt_AsLong(value); const char c = bool ? 0x01 : 0x00; - *(buffer->buffer + type_byte) = 0x08; + *(buffer_get_buffer(buffer) + type_byte) = 0x08; return buffer_write_bytes(buffer, &c, 1); } else if (PyInt_Check(value) || PyLong_Check(value)) { @@ -299,20 +234,20 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* "MongoDB can only handle up to 8-byte ints"); return 0; } - *(buffer->buffer + type_byte) = 0x12; + *(buffer_get_buffer(buffer) + type_byte) = 0x12; return buffer_write_bytes(buffer, (const char*)&long_long_value, 8); } - *(buffer->buffer + type_byte) = 0x10; + *(buffer_get_buffer(buffer) + type_byte) = 0x10; return buffer_write_bytes(buffer, (const char*)&int_value, 4); } else if (PyFloat_Check(value)) { const double d = PyFloat_AsDouble(value); - *(buffer->buffer + type_byte) = 0x01; + *(buffer_get_buffer(buffer) + type_byte) = 0x01; return buffer_write_bytes(buffer, (const char*)&d, 8); } else if (value == Py_None) { - *(buffer->buffer + type_byte) = 0x0A; + *(buffer_get_buffer(buffer) + type_byte) = 0x0A; return 1; } else if (PyDict_Check(value)) { - *(buffer->buffer + type_byte) = 0x03; + *(buffer_get_buffer(buffer) + type_byte) = 0x03; return write_dict(buffer, value, check_keys, 0); } else if (PyList_Check(value) || PyTuple_Check(value)) { int start_position, @@ -322,22 +257,24 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* i; char zero = 0; - *(buffer->buffer + type_byte) = 0x04; - start_position = buffer->position; + *(buffer_get_buffer(buffer) + type_byte) = 0x04; + start_position = buffer_get_position(buffer); /* save space for length */ - length_location = buffer_save_bytes(buffer, 4); + length_location = buffer_save_space(buffer, 4); if (length_location == -1) { + PyErr_NoMemory(); return 0; } items = PySequence_Size(value); for(i = 0; i < items; i++) { - int list_type_byte = buffer_save_bytes(buffer, 1); + int list_type_byte = buffer_save_space(buffer, 1); char* name; PyObject* item_value; - if (type_byte == -1) { + if (list_type_byte == -1) { + PyErr_NoMemory(); return 0; } if (INT2STRING(&name, i) < 0 || !name) { @@ -362,13 +299,13 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* if (!buffer_write_bytes(buffer, &zero, 1)) { return 0; } - length = buffer->position - start_position; - memcpy(buffer->buffer + length_location, &length, 4); + length = buffer_get_position(buffer) - start_position; + memcpy(buffer_get_buffer(buffer) + length_location, &length, 4); return 1; } else if (PyObject_IsInstance(value, Binary)) { PyObject* subtype_object; - *(buffer->buffer + type_byte) = 0x05; + *(buffer_get_buffer(buffer) + type_byte) = 0x05; subtype_object = PyObject_GetAttrString(value, "subtype"); if (!subtype_object) { return 0; @@ -416,7 +353,7 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* PyObject* bytes; - *(buffer->buffer + type_byte) = 0x05; + *(buffer_get_buffer(buffer) + type_byte) = 0x05; if (!buffer_write_bytes(buffer, (const char*)&length, 4)) { return 0; } @@ -440,12 +377,13 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* length; PyObject* scope; - *(buffer->buffer + type_byte) = 0x0F; + *(buffer_get_buffer(buffer) + type_byte) = 0x0F; - start_position = buffer->position; + start_position = buffer_get_position(buffer); /* save space for length */ - length_location = buffer_save_bytes(buffer, 4); + length_location = buffer_save_space(buffer, 4); if (length_location == -1) { + PyErr_NoMemory(); return 0; } @@ -463,14 +401,14 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* } Py_DECREF(scope); - length = buffer->position - start_position; - memcpy(buffer->buffer + length_location, &length, 4); + length = buffer_get_position(buffer) - start_position; + memcpy(buffer_get_buffer(buffer) + length_location, &length, 4); return 1; } else if (PyString_Check(value)) { int result; result_t status; - *(buffer->buffer + type_byte) = 0x02; + *(buffer_get_buffer(buffer) + type_byte) = 0x02; status = check_string((const unsigned char*)PyString_AsString(value), PyString_Size(value), 1, 0); if (status == NOT_UTF_8) { @@ -486,7 +424,7 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* PyObject* encoded; int result; - *(buffer->buffer + type_byte) = 0x02; + *(buffer_get_buffer(buffer) + type_byte) = 0x02; encoded = PyUnicode_AsUTF8String(value); if (!encoded) { return 0; @@ -508,7 +446,7 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* } else { millis = millis_from_datetime(value); } - *(buffer->buffer + type_byte) = 0x09; + *(buffer_get_buffer(buffer) + type_byte) = 0x09; return buffer_write_bytes(buffer, (const char*)&millis, 8); } else if (PyObject_IsInstance(value, ObjectId)) { PyObject* pystring = PyObject_GetAttrString(value, "_ObjectId__id"); @@ -526,7 +464,7 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* return 0; } Py_DECREF(pystring); - *(buffer->buffer + type_byte) = 0x07; + *(buffer_get_buffer(buffer) + type_byte) = 0x07; } return 1; } else if (PyObject_IsInstance(value, DBRef)) { @@ -539,7 +477,7 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* return 0; } Py_DECREF(as_doc); - *(buffer->buffer + type_byte) = 0x03; + *(buffer_get_buffer(buffer) + type_byte) = 0x03; return 1; } else if (PyObject_IsInstance(value, Timestamp)) { PyObject* obj; @@ -565,7 +503,7 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* return 0; } - *(buffer->buffer + type_byte) = 0x11; + *(buffer_get_buffer(buffer) + type_byte) = 0x11; return 1; } else if (PyObject_TypeCheck(value, REType)) { @@ -651,13 +589,13 @@ static int write_element_to_buffer(bson_buffer* buffer, int type_byte, PyObject* if (!buffer_write_bytes(buffer, flags, flags_length)) { return 0; } - *(buffer->buffer + type_byte) = 0x0B; + *(buffer_get_buffer(buffer) + type_byte) = 0x0B; return 1; } else if (PyObject_IsInstance(value, MinKey)) { - *(buffer->buffer + type_byte) = 0xFF; + *(buffer_get_buffer(buffer) + type_byte) = 0xFF; return 1; } else if (PyObject_IsInstance(value, MaxKey)) { - *(buffer->buffer + type_byte) = 0x7F; + *(buffer_get_buffer(buffer) + type_byte) = 0x7F; return 1; } else if (first_attempt) { /* Try reloading the modules and having one more go at it. */ @@ -712,7 +650,7 @@ static int check_key_name(const char* name, /* Write a (key, value) pair to the buffer. * * Returns 0 on failure */ -int write_pair(bson_buffer* buffer, const char* name, Py_ssize_t name_length, PyObject* value, unsigned char check_keys, unsigned char allow_id) { +int write_pair(buffer_t buffer, const char* name, Py_ssize_t name_length, PyObject* value, unsigned char check_keys, unsigned char allow_id) { int type_byte; /* Don't write any _id elements unless we're explicitly told to - @@ -722,8 +660,9 @@ int write_pair(bson_buffer* buffer, const char* name, Py_ssize_t name_length, Py return 1; } - type_byte = buffer_save_bytes(buffer, 1); + type_byte = buffer_save_space(buffer, 1); if (type_byte == -1) { + PyErr_NoMemory(); return 0; } if (check_keys && !check_key_name(name, name_length)) { @@ -738,7 +677,7 @@ int write_pair(bson_buffer* buffer, const char* name, Py_ssize_t name_length, Py return 1; } -int decode_and_write_pair(bson_buffer* buffer, +int decode_and_write_pair(buffer_t buffer, PyObject* key, PyObject* value, unsigned char check_keys, unsigned char top_level) { PyObject* encoded; @@ -802,7 +741,7 @@ int decode_and_write_pair(bson_buffer* buffer, } /* returns 0 on failure */ -int write_dict(bson_buffer* buffer, PyObject* dict, unsigned char check_keys, unsigned char top_level) { +int write_dict(buffer_t buffer, PyObject* dict, unsigned char check_keys, unsigned char top_level) { PyObject* key; PyObject* iter; char zero = 0; @@ -818,8 +757,9 @@ int write_dict(bson_buffer* buffer, PyObject* dict, unsigned char check_keys, un return 0; } - length_location = buffer_save_bytes(buffer, 4); + length_location = buffer_save_space(buffer, 4); if (length_location == -1) { + PyErr_NoMemory(); return 0; } @@ -854,7 +794,7 @@ int write_dict(bson_buffer* buffer, PyObject* dict, unsigned char check_keys, un if (!buffer_write_bytes(buffer, &zero, 1)) { return 0; } - length = buffer->position - length_location; + length = buffer_get_position(buffer) - length_location; if (length > 4 * 1024 * 1024) { PyObject* InvalidDocument = _error("InvalidDocument"); PyErr_SetString(InvalidDocument, "document too large - " @@ -862,7 +802,7 @@ int write_dict(bson_buffer* buffer, PyObject* dict, unsigned char check_keys, un Py_DECREF(InvalidDocument); return 0; } - memcpy(buffer->buffer + length_location, &length, 4); + memcpy(buffer_get_buffer(buffer) + length_location, &length, 4); return 1; } @@ -870,7 +810,7 @@ static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) { PyObject* dict; PyObject* result; unsigned char check_keys; - bson_buffer* buffer; + buffer_t buffer; if (!PyArg_ParseTuple(args, "Ob", &dict, &check_keys)) { return NULL; @@ -878,6 +818,7 @@ static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) { buffer = buffer_new(); if (!buffer) { + PyErr_NoMemory(); return NULL; } @@ -887,7 +828,8 @@ static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) { } /* objectify buffer */ - result = Py_BuildValue("s#", buffer->buffer, buffer->position); + result = Py_BuildValue("s#", buffer_get_buffer(buffer), + buffer_get_position(buffer)); buffer_free(buffer); return result; } diff --git a/bson/buffer.c b/bson/buffer.c new file mode 100644 index 000000000..957ebdc0a --- /dev/null +++ b/bson/buffer.c @@ -0,0 +1,135 @@ +/* + * Copyright 2009-2010 10gen, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "buffer.h" + +#define INITIAL_BUFFER_SIZE 256 + +struct buffer { + char* buffer; + int size; + int position; +}; + +/* Allocate and return a new buffer. + * Return NULL on allocation failure. */ +buffer_t buffer_new(void) { + buffer_t buffer; + buffer = (buffer_t)malloc(sizeof(struct buffer)); + if (buffer == NULL) { + return NULL; + } + + buffer->size = INITIAL_BUFFER_SIZE; + buffer->position = 0; + buffer->buffer = (char*)malloc(sizeof(char) * INITIAL_BUFFER_SIZE); + if (buffer->buffer == NULL) { + free(buffer); + return NULL; + } + + return buffer; +} + +/* Free the memory allocated for `buffer`. + * Return non-zero on failure. */ +int buffer_free(buffer_t buffer) { + if (buffer == NULL) { + return 1; + } + free(buffer->buffer); + free(buffer); + return 0; +} + +/* Grow `buffer` to at least `min_length`. + * Return non-zero on allocation failure. */ +static int buffer_grow(buffer_t buffer, int min_length) { + int size = buffer->size; + char* old_buffer = buffer->buffer; + if (size >= min_length) { + return 0; + } + while (size < min_length) { + size *= 2; + } + buffer->buffer = (char*)realloc(buffer->buffer, sizeof(char) * size); + if (buffer->buffer == NULL) { + free(old_buffer); + free(buffer); + return 1; + } + buffer->size = size; + return 0; +} + +/* Assure that `buffer` has at least `size` free bytes (and grow if needed). + * Return non-zero on allocation failure. */ +static int buffer_assure_space(buffer_t buffer, int size) { + if (buffer->position + size <= buffer->size) { + return 0; + } + return buffer_grow(buffer, buffer->position + size); +} + +/* Save `size` bytes from the current position in `buffer` (and grow if needed). + * Return offset for writing, or -1 on allocation failure. */ +buffer_position buffer_save_space(buffer_t buffer, int size) { + int position = buffer->position; + if (buffer_assure_space(buffer, size) != 0) { + return -1; + } + buffer->position += size; + return position; +} + +/* Write `size` bytes from `data` to `buffer` (and grow if needed). + * Return non-zero on allocation failure. */ +int buffer_write(buffer_t buffer, const char* data, int size) { + if (buffer_assure_space(buffer, size) != 0) { + return 1; + } + + memcpy(buffer->buffer + buffer->position, data, size); + buffer->position += size; + return 0; +} + +/* Write `size` bytes from `data` to `buffer` at position `position`. + * Does not change the internal position of `buffer`. + * Return non-zero if buffer isn't large enough for write. */ +int buffer_write_at_position(buffer_t buffer, buffer_position position, + const char* data, int size) { + if (position + size > buffer->size) { + buffer_free(buffer); + return 1; + } + + memcpy(buffer->buffer + position, data, size); + return 0; +} + + +int buffer_get_position(buffer_t buffer) { + return buffer->position; +} + +char* buffer_get_buffer(buffer_t buffer) { + return buffer->buffer; +} diff --git a/bson/buffer.h b/bson/buffer.h new file mode 100644 index 000000000..8141357d7 --- /dev/null +++ b/bson/buffer.h @@ -0,0 +1,55 @@ +/* + * Copyright 2009-2010 10gen, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BUFFER_H +#define BUFFER_H + +/* Note: if any of these functions return a failure condition then the buffer + * has already been freed. */ + +/* A buffer */ +typedef struct buffer* buffer_t; +/* A position in the buffer */ +typedef int buffer_position; + +/* Allocate and return a new buffer. + * Return NULL on allocation failure. */ +buffer_t buffer_new(void); + +/* Free the memory allocated for `buffer`. + * Return non-zero on failure. */ +int buffer_free(buffer_t buffer); + +/* Save `size` bytes from the current position in `buffer` (and grow if needed). + * Return offset for writing, or -1 on allocation failure. */ +buffer_position buffer_save_space(buffer_t buffer, int size); + +/* Write `size` bytes from `data` to `buffer` (and grow if needed). + * Return non-zero on allocation failure. */ +int buffer_write(buffer_t buffer, const char* data, int size); + +/* Write `size` bytes from `data` to `buffer` at position `position`. + * Does not change the internal position of `buffer`. + * Return non-zero if buffer isn't large enough for write. */ +int buffer_write_at_position(buffer_t buffer, buffer_position position, const char* data, int size); + +/* Getters for the internals of a buffer_t. + * Should try to avoid using these as much as possible + * since they break the abstraction. */ +buffer_position buffer_get_position(buffer_t buffer); +char* buffer_get_buffer(buffer_t buffer); + +#endif diff --git a/pymongo/_cmessagemodule.c b/pymongo/_cmessagemodule.c index 4880cf569..a57e4c515 100644 --- a/pymongo/_cmessagemodule.c +++ b/pymongo/_cmessagemodule.c @@ -23,6 +23,7 @@ #include #include "_cbson.h" +#include "buffer.h" /*#include #include @@ -30,6 +31,15 @@ #include "time64.h" #include "encoding_helpers.h"*/ +/* Just make this compatible w/ the old API. */ +static inline int buffer_write_bytes(buffer_t buffer, const char* data, int size) { + if (buffer_write(buffer, data, size)) { + PyErr_NoMemory(); + return 0; + } + return 1; +} + /* Get an error class from the pymongo.errors module. * * Returns a new ref */ @@ -46,7 +56,7 @@ static PyObject* _error(char* name) { /* add a lastError message on the end of the buffer. * returns 0 on failure */ -static int add_last_error(bson_buffer* buffer, int request_id, PyObject* args) { +static int add_last_error(buffer_t buffer, int request_id, PyObject* args) { int message_start; int document_start; int message_length; @@ -56,8 +66,9 @@ static int add_last_error(bson_buffer* buffer, int request_id, PyObject* args) { Py_ssize_t pos = 0; PyObject* one; - message_start = buffer_save_bytes(buffer, 4); + message_start = buffer_save_space(buffer, 4); if (message_start == -1) { + PyErr_NoMemory(); return 0; } if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) || @@ -73,8 +84,9 @@ static int add_last_error(bson_buffer* buffer, int request_id, PyObject* args) { } /* save space for length */ - document_start = buffer_save_bytes(buffer, 4); + document_start = buffer_save_space(buffer, 4); if (document_start == -1) { + PyErr_NoMemory(); return 0; } @@ -98,8 +110,8 @@ static int add_last_error(bson_buffer* buffer, int request_id, PyObject* args) { return 0; } - message_length = buffer->position - message_start; - document_length = buffer->position - document_start; + message_length = buffer_get_position(buffer) - message_start; + document_length = buffer_get_position(buffer) - document_start; if (document_length > 4 * 1024 * 1024) { PyObject* InvalidDocument = _error("InvalidDocument"); PyErr_SetString(InvalidDocument, "document too large - " @@ -107,8 +119,8 @@ static int add_last_error(bson_buffer* buffer, int request_id, PyObject* args) { Py_DECREF(InvalidDocument); return 0; } - memcpy(buffer->buffer + message_start, &message_length, 4); - memcpy(buffer->buffer + document_start, &document_length, 4); + memcpy(buffer_get_buffer(buffer) + message_start, &message_length, 4); + memcpy(buffer_get_buffer(buffer) + document_start, &document_length, 4); return 1; } @@ -123,7 +135,7 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) { unsigned char check_keys; unsigned char safe; PyObject* last_error_args; - bson_buffer* buffer; + buffer_t buffer; int length_location; PyObject* result; @@ -137,14 +149,19 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) { buffer = buffer_new(); if (!buffer) { + PyErr_NoMemory(); PyMem_Free(collection_name); return NULL; } // save space for message length - length_location = buffer_save_bytes(buffer, 4); - if (length_location == -1 || - !buffer_write_bytes(buffer, (const char*)&request_id, 4) || + length_location = buffer_save_space(buffer, 4); + if (length_location == -1) { + PyMem_Free(collection_name); + PyErr_NoMemory(); + return NULL; + } + if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) || !buffer_write_bytes(buffer, "\x00\x00\x00\x00" "\xd2\x07\x00\x00" @@ -176,7 +193,8 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) { } } - memcpy(buffer->buffer + length_location, &buffer->position, 4); + memcpy(buffer_get_buffer(buffer) + length_location, + buffer_get_buffer(buffer) + buffer_get_position(buffer), 4); if (safe) { if (!add_last_error(buffer, request_id, last_error_args)) { @@ -187,7 +205,8 @@ static PyObject* _cbson_insert_message(PyObject* self, PyObject* args) { /* objectify buffer */ result = Py_BuildValue("is#", request_id, - buffer->buffer, buffer->position); + buffer_get_buffer(buffer), + buffer_get_position(buffer)); buffer_free(buffer); return result; } @@ -204,7 +223,7 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) { unsigned char safe; PyObject* last_error_args; int options; - bson_buffer* buffer; + buffer_t buffer; int length_location; PyObject* result; @@ -226,14 +245,19 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) { } buffer = buffer_new(); if (!buffer) { + PyErr_NoMemory(); PyMem_Free(collection_name); return NULL; } // save space for message length - length_location = buffer_save_bytes(buffer, 4); - if (length_location == -1 || - !buffer_write_bytes(buffer, (const char*)&request_id, 4) || + length_location = buffer_save_space(buffer, 4); + if (length_location == -1) { + PyMem_Free(collection_name); + PyErr_NoMemory(); + return NULL; + } + if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) || !buffer_write_bytes(buffer, "\x00\x00\x00\x00" "\xd1\x07\x00\x00" @@ -252,7 +276,8 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) { PyMem_Free(collection_name); - memcpy(buffer->buffer + length_location, &buffer->position, 4); + memcpy(buffer_get_buffer(buffer) + length_location, + buffer_get_buffer(buffer) + buffer_get_position(buffer), 4); if (safe) { if (!add_last_error(buffer, request_id, last_error_args)) { @@ -263,7 +288,8 @@ static PyObject* _cbson_update_message(PyObject* self, PyObject* args) { /* objectify buffer */ result = Py_BuildValue("is#", request_id, - buffer->buffer, buffer->position); + buffer_get_buffer(buffer), + buffer_get_position(buffer)); buffer_free(buffer); return result; } @@ -278,7 +304,7 @@ static PyObject* _cbson_query_message(PyObject* self, PyObject* args) { int num_to_return; PyObject* query; PyObject* field_selector = Py_None; - bson_buffer* buffer; + buffer_t buffer; int length_location; PyObject* result; @@ -293,20 +319,22 @@ static PyObject* _cbson_query_message(PyObject* self, PyObject* args) { } buffer = buffer_new(); if (!buffer) { + PyErr_NoMemory(); PyMem_Free(collection_name); return NULL; } // save space for message length - length_location = buffer_save_bytes(buffer, 4); - if (length_location == -1 || - !buffer_write_bytes(buffer, (const char*)&request_id, 4) || - !buffer_write_bytes(buffer, - "\x00\x00\x00\x00" - "\xd4\x07\x00\x00", 8) || + length_location = buffer_save_space(buffer, 4); + if (length_location == -1) { + PyMem_Free(collection_name); + PyErr_NoMemory(); + return NULL; + } + if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) || + !buffer_write_bytes(buffer, "\x00\x00\x00\x00\xd4\x07\x00\x00", 8) || !buffer_write_bytes(buffer, (const char*)&options, 4) || - !buffer_write_bytes(buffer, - collection_name, + !buffer_write_bytes(buffer, collection_name, collection_name_length + 1) || !buffer_write_bytes(buffer, (const char*)&num_to_skip, 4) || !buffer_write_bytes(buffer, (const char*)&num_to_return, 4) || @@ -320,11 +348,13 @@ static PyObject* _cbson_query_message(PyObject* self, PyObject* args) { PyMem_Free(collection_name); - memcpy(buffer->buffer + length_location, &buffer->position, 4); + memcpy(buffer_get_buffer(buffer) + length_location, + buffer_get_buffer(buffer) + buffer_get_position(buffer), 4); /* objectify buffer */ result = Py_BuildValue("is#", request_id, - buffer->buffer, buffer->position); + buffer_get_buffer(buffer), + buffer_get_position(buffer)); buffer_free(buffer); return result; } @@ -336,7 +366,7 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) { int collection_name_length; int num_to_return; long long cursor_id; - bson_buffer* buffer; + buffer_t buffer; int length_location; PyObject* result; @@ -350,14 +380,19 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) { } buffer = buffer_new(); if (!buffer) { + PyErr_NoMemory(); PyMem_Free(collection_name); return NULL; } // save space for message length - length_location = buffer_save_bytes(buffer, 4); - if (length_location == -1 || - !buffer_write_bytes(buffer, (const char*)&request_id, 4) || + length_location = buffer_save_space(buffer, 4); + if (length_location == -1) { + PyMem_Free(collection_name); + PyErr_NoMemory(); + return NULL; + } + if (!buffer_write_bytes(buffer, (const char*)&request_id, 4) || !buffer_write_bytes(buffer, "\x00\x00\x00\x00" "\xd5\x07\x00\x00" @@ -374,11 +409,13 @@ static PyObject* _cbson_get_more_message(PyObject* self, PyObject* args) { PyMem_Free(collection_name); - memcpy(buffer->buffer + length_location, &buffer->position, 4); + memcpy(buffer_get_buffer(buffer) + length_location, + buffer_get_buffer(buffer) + buffer_get_position(buffer), 4); /* objectify buffer */ result = Py_BuildValue("is#", request_id, - buffer->buffer, buffer->position); + buffer_get_buffer(buffer), + buffer_get_position(buffer)); buffer_free(buffer); return result; } diff --git a/setup.py b/setup.py index 2f38abb0c..649883fe2 100755 --- a/setup.py +++ b/setup.py @@ -132,6 +132,7 @@ c_ext = Feature( include_dirs=['bson'], sources=['bson/_cbsonmodule.c', 'bson/time64.c', + 'bson/buffer.c', 'bson/encoding_helpers.c']), Extension('pymongo._cmessage', include_dirs=['bson', 'pymongo'], @@ -142,11 +143,11 @@ if "--no_ext" in sys.argv: features = {} elif sys.byteorder == "big": print """ -*************************************************** -The optional C extension is currently not supported +***************************************************** +The optional C extensions are currently not supported on big endian platforms and will not be built. Performance may be degraded. -*************************************************** +***************************************************** """ features = {} else: