in src/constbuffer_array_splitter.c [17:210]
CONSTBUFFER_ARRAY_HANDLE constbuffer_array_splitter_split(CONSTBUFFER_ARRAY_HANDLE buffers, uint32_t max_buffer_size)
{
CONSTBUFFER_ARRAY_HANDLE result;
if (
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_001: [ If buffers is NULL then constbuffer_array_splitter_split shall fail and return NULL. ]*/
buffers == NULL ||
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_002: [ If max_buffer_size is 0 then constbuffer_array_splitter_split shall fail and return NULL. ]*/
max_buffer_size == 0
)
{
LogError("Invalid args : CONSTBUFFER_ARRAY_HANDLE buffers=%p, size_t max_buffer_size=%" PRIu32,
buffers, max_buffer_size);
result = NULL;
}
else
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_018: [ constbuffer_array_splitter_split shall call constbuffer_array_get_buffer_count. ]*/
uint32_t buffer_count;
(void)constbuffer_array_get_buffer_count(buffers, &buffer_count);
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_019: [ If the buffer count is 0 then constbuffer_array_splitter_split shall call constbuffer_array_create_empty and return the result. ]*/
if (buffer_count == 0)
{
result = constbuffer_array_create_empty();
if (result == NULL)
{
LogError("constbuffer_array_create_empty failed");
}
// return as-is
}
else
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_004: [ constbuffer_array_splitter_split shall call constbuffer_array_get_all_buffers_size for buffers and store the result as remaining_buffer_size. ]*/
uint32_t remaining_buffer_size;
// NOTE: the total block size is limited to UINT32_MAX
// If we need to evict blocks with more than 4GB of data (including all headers) then this needs to be updated to get a 64-bit size
int temp_result = constbuffer_array_get_all_buffers_size(buffers, &remaining_buffer_size);
if (temp_result != 0)
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_017: [ If there are any other failures then constbuffer_array_splitter_split shall fail and return NULL. ]*/
LogError("constbuffer_array_get_all_buffers_size failed");
result = NULL;
}
else
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_020: [ If the remaining_buffer_size is 0 (all buffers are empty) then constbuffer_array_splitter_split shall call constbuffer_array_create_empty and return the result. ]*/
if (remaining_buffer_size == 0)
{
result = constbuffer_array_create_empty();
if (result == NULL)
{
LogError("constbuffer_array_create_empty failed");
}
// return as-is
}
else
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_005: [ constbuffer_array_splitter_split shall allocate an array of CONSTBUFFER_HANDLE of size remaining_buffer_size / max_buffer_size (rounded up). ]*/
uint32_t split_buffer_count = (remaining_buffer_size + max_buffer_size - 1) / max_buffer_size;
CONSTBUFFER_HANDLE* split_buffers = malloc_2(split_buffer_count, sizeof(CONSTBUFFER_HANDLE));
if (split_buffers == NULL)
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_017: [ If there are any other failures then constbuffer_array_splitter_split shall fail and return NULL. ]*/
LogError("Failed to allocate %" PRIu32 " buffer handle array", split_buffer_count);
result = NULL;
}
else
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_006: [ constbuffer_array_splitter_split shall initialize the current buffer index to 0 and the current buffer offset to 0. ]*/
uint32_t current_buffer_index = 0;
uint32_t current_buffer_offset = 0;
uint32_t current_split_buffer_index = 0;
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_007: [ constbuffer_array_splitter_split shall get the first buffer in buffers that is not empty. ]*/
const CONSTBUFFER* current_buffer = constbuffer_array_get_buffer_content(buffers, current_buffer_index);
while (current_buffer->size == 0)
{
++current_buffer_index;
current_buffer = constbuffer_array_get_buffer_content(buffers, current_buffer_index);
}
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_008: [ While the remaining_buffer_size is greater than 0: ]*/
while (remaining_buffer_size > 0)
{
bool failed = false;
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_009: [ constbuffer_array_splitter_split shall allocate memory of size min(max_buffer_size, remaining_buffer_size). ]*/
uint32_t next_split_buffer_size = MIN(max_buffer_size, remaining_buffer_size);
unsigned char* split_buffer_memory = malloc(next_split_buffer_size);
if (split_buffer_memory == NULL)
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_017: [ If there are any other failures then constbuffer_array_splitter_split shall fail and return NULL. ]*/
LogError("Failed to allocate memory (%" PRIu32 " bytes) for buffer copy", next_split_buffer_size);
failed = true;
}
else
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_010: [ constbuffer_array_splitter_split shall copy data from the buffers starting at the current buffer index and buffer offset until it has filled the allocated memory. ]*/
for (uint32_t i = 0; i < next_split_buffer_size; ++i)
{
split_buffer_memory[i] = current_buffer->buffer[current_buffer_offset];
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_011: [ constbuffer_array_splitter_split shall update the current buffer offset as it copies the memory. ]*/
++current_buffer_offset;
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_012: [ If the end of the current buffer in buffers is reached then constbuffer_array_splitter_split shall increment the buffer index and reset the buffer offset to 0, to read the next buffer in the original array (skipping over empty buffers). ]*/
while (current_buffer != NULL &&
current_buffer_offset >= current_buffer->size)
{
current_buffer_offset = 0;
++current_buffer_index;
if (remaining_buffer_size - (i + 1) > 0)
{
current_buffer = constbuffer_array_get_buffer_content(buffers, current_buffer_index);
}
else
{
// This should be the end of the copy
current_buffer = NULL;
}
}
}
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_014: [ constbuffer_array_splitter_split shall call CONSTBUFFER_CreateWithMoveMemory for the allocated memory and store it in the allocated array. ]*/
split_buffers[current_split_buffer_index] = CONSTBUFFER_CreateWithMoveMemory(split_buffer_memory, next_split_buffer_size);
if (split_buffers[current_split_buffer_index] == NULL)
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_017: [ If there are any other failures then constbuffer_array_splitter_split shall fail and return NULL. ]*/
LogError("CONSTBUFFER_CreateWithMoveMemory failed for buffer %" PRIu32, current_split_buffer_index);
failed = true;
}
else
{
split_buffer_memory = NULL;
++current_split_buffer_index;
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_013: [ constbuffer_array_splitter_split shall decrement the remaining_buffer_size by the amount of data copied. ]*/
remaining_buffer_size -= next_split_buffer_size;
}
if (split_buffer_memory != NULL)
{
free(split_buffer_memory);
}
}
if (failed)
{
break;
}
}
if (remaining_buffer_size > 0)
{
result = NULL;
}
else
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_015: [ constbuffer_array_splitter_split shall call constbuffer_array_create with the allocated array of buffer handles as split_buffers. ]*/
result = constbuffer_array_create(split_buffers, split_buffer_count);
if (result == NULL)
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_017: [ If there are any other failures then constbuffer_array_splitter_split shall fail and return NULL. ]*/
LogError("constbuffer_array_create failed");
// return as-is
}
else
{
/*Codes_SRS_CONSTBUFFER_ARRAY_SPLITTER_42_016: [ constbuffer_array_splitter_split shall succeed and return the split_buffers. ]*/
}
}
for (uint32_t i = 0; i < current_split_buffer_index; ++i)
{
CONSTBUFFER_DecRef(split_buffers[i]);
}
free(split_buffers);
}
}
}
}
}
return result;
}