diff options
Diffstat (limited to 'src/3rd_party/bson_c_lib/src/bson_array.c')
-rw-r--r-- | src/3rd_party/bson_c_lib/src/bson_array.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/src/3rd_party/bson_c_lib/src/bson_array.c b/src/3rd_party/bson_c_lib/src/bson_array.c new file mode 100644 index 0000000000..edac6a1f02 --- /dev/null +++ b/src/3rd_party/bson_c_lib/src/bson_array.c @@ -0,0 +1,391 @@ +#include "bson_array.h" + +bool bson_array_initialize(BsonArray *array, size_t initialCapacity) { + array->count = 0; + array->maxCount = initialCapacity; + array->elements = malloc(sizeof(BsonElement *) * initialCapacity); + return true; +} + +void bson_array_deinitialize(BsonArray *array) { + size_t i = 0; + for (i = 0; i < array->count; i++) { + BsonElement *element = array->elements[i]; + if (element->type == TYPE_DOCUMENT) { + bson_object_deinitialize((BsonObject *)element->value); + } + else if (element->type == TYPE_ARRAY) { + bson_array_deinitialize((BsonArray *)element->value); + } + free(element->value); + free(element); + } + + free(array->elements); +} + +size_t bson_array_size(BsonArray *array) { + size_t arraySize = ARRAY_OVERHEAD_BYTES; + size_t i = 0; + for (i = 0; i < array->count; i++) { + BsonElement *element = array->elements[i]; + arraySize += array_key_size(i) + ELEMENT_OVERHEAD_BYTES; + if (element->type == TYPE_DOCUMENT) { + arraySize += bson_object_size((BsonObject *)element->value); + } + else if (element->type == TYPE_ARRAY) { + arraySize += bson_array_size((BsonArray *)element->value); + } + else { + arraySize += element->size; + } + } + return arraySize; +} + +uint8_t *bson_array_to_bytes(BsonArray *array) { + size_t arraySize = bson_array_size(array); + uint8_t *bytes = malloc(arraySize); + size_t position = 0; + write_int32_le(bytes, (int32_t)arraySize, &position); + size_t i = 0; + for (i = 0; i < array->count; i++) { + BsonElement *element = array->elements[i]; + + bytes[position++] = element->type; + + uint8_t *keyBytes = index_to_key(i); + memcpy(&bytes[position], keyBytes, digits(i)); + free(keyBytes); + position += digits(i); + + //Null-terminate + bytes[position++] = 0x00; + + switch (element->type) { + case TYPE_DOCUMENT: { + BsonObject *obj = (BsonObject *)element->value; + uint8_t *objBytes = bson_object_to_bytes(obj); + if (objBytes == NULL) { + printf("An error occured while parsing the object with index \"%i\"\n", (int)i); + free(bytes); + return NULL; + } + size_t objSize = bson_object_size(obj); + memcpy(&bytes[position], objBytes, objSize); + free(objBytes); + position += objSize; + break; + } + case TYPE_ARRAY: { + BsonArray *subArray = (BsonArray *)element->value; + uint8_t *subArrayBytes = bson_array_to_bytes(subArray); + if (subArrayBytes == NULL) { + printf("An error occured while parsing the object with index \"%i\"\n", (int)i); + free(bytes); + return NULL; + } + size_t subArraySize = bson_array_size(subArray); + memset(&bytes[position], 0, subArraySize); + memcpy(&bytes[position], subArrayBytes, subArraySize); + free(subArrayBytes); + position += subArraySize; + break; + } + case TYPE_INT32: { + write_int32_le(bytes, *(int32_t *)element->value, &position); + break; + } + case TYPE_INT64: { + write_int64_le(bytes, *(int64_t *)element->value, &position); + break; + } + case TYPE_STRING: { + char *stringVal = (char *)element->value; + //String length is written first + write_int32_le(bytes, (int32_t)(strlen(stringVal) + 1), &position); + + uint8_t *stringBytes = string_to_byte_array(stringVal); + memcpy(&bytes[position], stringBytes, strlen(stringVal)); + free(stringBytes); + position += strlen(stringVal); + + //Null-terminate + bytes[position++] = 0x00; + break; + } + case TYPE_DOUBLE: { + write_double_le(bytes, *(double *)element->value, &position); + break; + } + case TYPE_BOOLEAN: { + bytes[position++] = (uint8_t)(*(bson_boolean *)element->value); + break; + } + default: { + printf("Unrecognized BSON type: %i\n", element->type); + position += sizeof(*element->value); + } + } + } + + bytes[position++] = DOCUMENT_END; + if (position != arraySize) { + printf("Something went horribly wrong. Unexpected size of array in bytes: %i, expected size: %i\n", (int)position, (int)arraySize); + free(bytes); + return NULL; + } + return bytes; +} + +BsonArray bson_array_from_bytes(uint8_t *data) { + uint8_t *current = data; + int32_t size = read_int32_le(¤t); + BsonArray array; + bson_array_initialize(&array, 10); + uint8_t type = *current; + current++; + while (type != DOCUMENT_END) { + char *key = byte_array_to_string(current); + current += strlen(key) + 1; + + switch ((element_type)type) { + case TYPE_DOCUMENT: { + BsonObject obj = bson_object_from_bytes(current); + bson_array_add_object(&array, &obj); + current += bson_object_size(&obj); + break; + } + case TYPE_ARRAY: { + BsonArray subArray = bson_array_from_bytes(current); + bson_array_add_array(&array, &subArray); + current += bson_array_size(&subArray); + break; + } + case TYPE_INT32: { + int32_t value = read_int32_le(¤t); + bson_array_add_int32(&array, value); + break; + } + case TYPE_INT64: { + int64_t value = read_int64_le(¤t); + bson_array_add_int64(&array, value); + break; + } + case TYPE_STRING: { + //String length is read first + int32_t stringLength = read_int32_le(¤t) - 1; + + char *stringVal = byte_array_to_bson_string(current, stringLength); + bson_array_add_string(&array, stringVal); + free(stringVal); + current += stringLength + 1; + break; + } + case TYPE_DOUBLE: { + double value = read_double_le(¤t); + bson_array_add_double(&array, value); + break; + } + case TYPE_BOOLEAN: { + bson_array_add_bool(&array, *current); + current++; + break; + } + default: { + printf("Unrecognized BSON type: %i\n", type); + } + } + free(key); + type = *current; + current++; + } + + if (data + size != current) { + printf("Unexpected parsed array size. Expected %i, got %i\n", (int) size, (int)(current - data)); + } + return array; +} + +char *bson_array_to_string(BsonArray *array, char *out) { + //TODO just move the pointer rather than keep a position variable + int position = 0; + position += sprintf(out, "[ "); + size_t i = 0; + for (i = 0; i < array->count; i++) { + BsonElement *element = array->elements[i]; + switch (element->type) { + case TYPE_DOCUMENT: { + char docString[512]; + position += sprintf(&out[position], "%s", bson_object_to_string(bson_array_get_object(array, i), docString)); + break; + } + case TYPE_ARRAY: { + char docString[512]; + position += sprintf(&out[position], "%s", bson_array_to_string(bson_array_get_array(array, i), docString)); + break; + } + case TYPE_INT32: { + position += sprintf(&out[position], "%i", (int)bson_array_get_int32(array, i)); + break; + } + case TYPE_INT64: { + position += sprintf(&out[position], "%li", (long)bson_array_get_int64(array, i)); + break; + } + case TYPE_STRING: { + position += sprintf(&out[position], "\"%s\"", bson_array_get_string(array, i)); + break; + } + case TYPE_DOUBLE: { + position += sprintf(&out[position], "%f", bson_array_get_double(array, i)); + break; + } + case TYPE_BOOLEAN: { + position += sprintf(&out[position], "%s", (bson_array_get_bool(array, i) == BOOLEAN_TRUE) ? "true" : "false"); + break; + } + default: { + printf("Unrecognized BSON type: %i\n", element->type); + position += sprintf(&out[position], "UNKNOWN_TYPE"); + } + } + if (i != (array->count - 1)) { + position += sprintf(&out[position], ", "); + } + } + sprintf(&out[position], " ]"); + + return out; +} + +bool bson_array_resize(BsonArray *array, size_t newSize) { + if (array->count > newSize) { + printf("Attempted to resize an array smaller than the number of elements it contains\n"); + return false; + } + int i = 0; + BsonElement **newArray = malloc(sizeof(BsonElement *) * newSize); + BsonElement **oldArray = array->elements; + for (i = 0; i < array->maxCount; i++) { + newArray[i] = oldArray[i]; + } + free(oldArray); + array->elements = newArray; + array->maxCount = newSize; + return true; +} + +bool bson_array_add_element(BsonArray *array, BsonElement *element, size_t allocSize) { + if (array->count == array->maxCount) { + if (!bson_array_resize(array, array->maxCount * 2)) { + return false; + } + } + BsonElement *allocElement = malloc(sizeof(BsonElement)); + allocElement->type = element->type; + allocElement->size = element->size; + allocElement->value = malloc(allocSize); + memcpy(allocElement->value, element->value, allocSize); + array->elements[array->count] = allocElement; + array->count++; + return true; +} + +/* + @brief Add a new element to the end of a given array + + @param array - The array to be modified + @param type - The type of the element to be added + @param value - The value of the element to be added + @param allocSize - The size, in bytes, to be allocated for the element + @param elementSize - The size, in bytes, of the element when converted to BSON format + + @return - true if the addition was successful, false if not +*/ +bool bson_array_add(BsonArray *array, element_type type, void *value, size_t allocSize, size_t elementSize) { + BsonElement element; + element.type = type; + element.value = value; + element.size = elementSize; + return bson_array_add_element(array, &element, allocSize); +} + +bool bson_array_add_object(BsonArray *array, BsonObject *value) { + return bson_array_add(array, TYPE_DOCUMENT, value, sizeof(BsonObject), 0); +} + +bool bson_array_add_array(BsonArray *array, BsonArray *value) { + return bson_array_add(array, TYPE_ARRAY, value, sizeof(BsonArray), 0); +} + +bool bson_array_add_int32(BsonArray *array, int32_t value) { + return bson_array_add(array, TYPE_INT32, &value, sizeof(int32_t), + SIZE_INT32); +} + +bool bson_array_add_int64(BsonArray *array, int64_t value) { + return bson_array_add(array, TYPE_INT64, &value, sizeof(int64_t), + SIZE_INT64); +} + +bool bson_array_add_string(BsonArray *array, char *value) { + return bson_array_add(array, TYPE_STRING, value, (strlen(value) + 1) * sizeof(char), + strlen(value) + STRING_OVERHEAD_BYTES); +} + +bool bson_array_add_bool(BsonArray *array, bson_boolean value) { + return bson_array_add(array, TYPE_BOOLEAN, &value, sizeof(bson_boolean), + SIZE_BOOLEAN); +} + +bool bson_array_add_double(BsonArray *array, double value) { + return bson_array_add(array, TYPE_DOUBLE, &value, sizeof(double), + SIZE_DOUBLE); +} + +BsonElement *bson_array_get(BsonArray *array, size_t index) { + return (index >= array->count) ? NULL : array->elements[index]; +} + +BsonObject *bson_array_get_object(BsonArray *array, size_t index) { + BsonElement *element = bson_array_get(array, index); + return (element == NULL || element->type != TYPE_DOCUMENT) ? + NULL : (BsonObject *)element->value; +} + +BsonArray *bson_array_get_array(BsonArray *array, size_t index) { + BsonElement *element = bson_array_get(array, index); + return (element == NULL || element->type != TYPE_ARRAY) ? + NULL : (BsonArray *)element->value; +} + +int32_t bson_array_get_int32(BsonArray *array, size_t index) { + BsonElement *element = bson_array_get(array, index); + return (element == NULL || element->type != TYPE_INT32) ? + -1 : *(int32_t *)element->value; +} + +int64_t bson_array_get_int64(BsonArray *array, size_t index) { + BsonElement *element = bson_array_get(array, index); + return (element == NULL || element->type != TYPE_INT64) ? + -1 : *(int64_t *)element->value; +} + +char *bson_array_get_string(BsonArray *array, size_t index) { + BsonElement *element = bson_array_get(array, index); + return (element == NULL || element->type != TYPE_STRING) ? + NULL : (char *)element->value; +} + +bson_boolean bson_array_get_bool(BsonArray *array, size_t index) { + BsonElement *element = bson_array_get(array, index); + return (element == NULL || element->type != TYPE_BOOLEAN) ? + BOOLEAN_INVALID : *(bson_boolean *)element->value; +} + +double bson_array_get_double(BsonArray *array, size_t index) { + BsonElement *element = bson_array_get(array, index); + return (element == NULL || element->type != TYPE_DOUBLE) ? + -1 : *(double *)element->value; +} |