blob: 26af2a901f8233f0a8b46fd9e1fd601c72148af8 [file] [log] [blame]
#include "utils.h"
#include <rawrtc/utils.h>
#include <rawrtcc/code.h>
#include <re.h>
#include <stdarg.h> // va_*
#include <stdio.h> // sprintf
#include <string.h> // strlen
/*
* Convert binary to hex string where each value is separated by a
* colon.
*/
enum rawrtc_code rawrtc_bin_to_colon_hex(
char** const destinationp, // de-referenced
uint8_t* const source,
size_t const length) {
char* hex_str;
char* hex_ptr;
size_t i;
int ret;
enum rawrtc_code error = RAWRTC_CODE_SUCCESS;
// Check arguments
if (!destinationp || !source) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Allocate hex string
hex_str = mem_zalloc(length > 0 ? (length * 3) : 1, NULL);
if (!hex_str) {
return RAWRTC_CODE_NO_MEMORY;
}
// Bin to hex
hex_ptr = hex_str;
for (i = 0; i < length; ++i) {
if (i > 0) {
*hex_ptr = ':';
++hex_ptr;
}
ret = sprintf(hex_ptr, "%02X", source[i]);
if (ret != 2) {
error = RAWRTC_CODE_UNKNOWN_ERROR;
goto out;
} else {
hex_ptr += ret;
}
}
out:
if (error) {
mem_deref(hex_str);
} else {
// Set pointer
*destinationp = hex_str;
}
return error;
}
/*
* Convert hex string with colon-separated hex values to binary.
*/
enum rawrtc_code rawrtc_colon_hex_to_bin(
size_t* const bytes_written, // de-referenced
uint8_t* const buffer, // written into
size_t const buffer_size,
char* source) {
size_t hex_length;
size_t bin_length;
size_t i;
// Check arguments
if (!bytes_written || !buffer || !source) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Validate length
hex_length = strlen(source);
if (hex_length > 0 && hex_length % 3 != 2) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Determine size
bin_length = hex_length > 0 ? (size_t)((hex_length + 1) / 3) : 0;
if (bin_length > buffer_size) {
return RAWRTC_CODE_INSUFFICIENT_SPACE;
}
// Hex to bin
for (i = 0; i < bin_length; ++i) {
if (i > 0) {
// Skip colon
++source;
}
buffer[i] = ch_hex(*source) << 4;
++source;
buffer[i] += ch_hex(*source);
++source;
}
// Done
*bytes_written = bin_length;
return RAWRTC_CODE_SUCCESS;
}
/*
* Destructor for an existing array container that did reference each
* item.
*/
static void rawrtc_array_container_destroy(void* arg) {
struct rawrtc_array_container* const container = arg;
size_t i;
// Un-reference each item
for (i = 0; i < container->n_items; ++i) {
mem_deref(container->items[i]);
}
}
/*
* Convert a list to a dynamically allocated array container.
*
* If `reference` is set to `true`, each item in the list will be
* referenced and a destructor will be added that unreferences each
* item when unreferencing the array.
*/
enum rawrtc_code rawrtc_list_to_array(
struct rawrtc_array_container** containerp, // de-referenced
struct list const* const list,
bool reference) {
size_t n;
struct rawrtc_array_container* container;
struct le* le;
size_t i;
// Check arguments
if (!containerp || !list) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Get list length
n = list_count(list);
// Allocate array & set length immediately
container = mem_zalloc(
sizeof(*container) + sizeof(void*) * n, reference ? rawrtc_array_container_destroy : NULL);
if (!container) {
return RAWRTC_CODE_NO_MEMORY;
}
container->n_items = n;
// Copy pointer to each item
for (le = list_head(list), i = 0; le != NULL; le = le->next, ++i) {
if (reference) {
mem_ref(le->data);
}
container->items[i] = le->data;
}
// Set pointer & done
*containerp = container;
return RAWRTC_CODE_SUCCESS;
}