blob: 26af2a901f8233f0a8b46fd9e1fd601c72148af8 [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#include "utils.h"
2#include <rawrtc/utils.h>
3#include <rawrtcc/code.h>
4#include <re.h>
5#include <stdarg.h> // va_*
6#include <stdio.h> // sprintf
7#include <string.h> // strlen
8
9/*
10 * Convert binary to hex string where each value is separated by a
11 * colon.
12 */
13enum rawrtc_code rawrtc_bin_to_colon_hex(
14 char** const destinationp, // de-referenced
15 uint8_t* const source,
16 size_t const length) {
17 char* hex_str;
18 char* hex_ptr;
19 size_t i;
20 int ret;
21 enum rawrtc_code error = RAWRTC_CODE_SUCCESS;
22
23 // Check arguments
24 if (!destinationp || !source) {
25 return RAWRTC_CODE_INVALID_ARGUMENT;
26 }
27
28 // Allocate hex string
29 hex_str = mem_zalloc(length > 0 ? (length * 3) : 1, NULL);
30 if (!hex_str) {
31 return RAWRTC_CODE_NO_MEMORY;
32 }
33
34 // Bin to hex
35 hex_ptr = hex_str;
36 for (i = 0; i < length; ++i) {
37 if (i > 0) {
38 *hex_ptr = ':';
39 ++hex_ptr;
40 }
41 ret = sprintf(hex_ptr, "%02X", source[i]);
42 if (ret != 2) {
43 error = RAWRTC_CODE_UNKNOWN_ERROR;
44 goto out;
45 } else {
46 hex_ptr += ret;
47 }
48 }
49
50out:
51 if (error) {
52 mem_deref(hex_str);
53 } else {
54 // Set pointer
55 *destinationp = hex_str;
56 }
57 return error;
58}
59
60/*
61 * Convert hex string with colon-separated hex values to binary.
62 */
63enum rawrtc_code rawrtc_colon_hex_to_bin(
64 size_t* const bytes_written, // de-referenced
65 uint8_t* const buffer, // written into
66 size_t const buffer_size,
67 char* source) {
68 size_t hex_length;
69 size_t bin_length;
70 size_t i;
71
72 // Check arguments
73 if (!bytes_written || !buffer || !source) {
74 return RAWRTC_CODE_INVALID_ARGUMENT;
75 }
76
77 // Validate length
78 hex_length = strlen(source);
79 if (hex_length > 0 && hex_length % 3 != 2) {
80 return RAWRTC_CODE_INVALID_ARGUMENT;
81 }
82
83 // Determine size
84 bin_length = hex_length > 0 ? (size_t)((hex_length + 1) / 3) : 0;
85 if (bin_length > buffer_size) {
86 return RAWRTC_CODE_INSUFFICIENT_SPACE;
87 }
88
89 // Hex to bin
90 for (i = 0; i < bin_length; ++i) {
91 if (i > 0) {
92 // Skip colon
93 ++source;
94 }
95 buffer[i] = ch_hex(*source) << 4;
96 ++source;
97 buffer[i] += ch_hex(*source);
98 ++source;
99 }
100
101 // Done
102 *bytes_written = bin_length;
103 return RAWRTC_CODE_SUCCESS;
104}
105
106/*
107 * Destructor for an existing array container that did reference each
108 * item.
109 */
110static void rawrtc_array_container_destroy(void* arg) {
111 struct rawrtc_array_container* const container = arg;
112 size_t i;
113
114 // Un-reference each item
115 for (i = 0; i < container->n_items; ++i) {
116 mem_deref(container->items[i]);
117 }
118}
119
120/*
121 * Convert a list to a dynamically allocated array container.
122 *
123 * If `reference` is set to `true`, each item in the list will be
124 * referenced and a destructor will be added that unreferences each
125 * item when unreferencing the array.
126 */
127enum rawrtc_code rawrtc_list_to_array(
128 struct rawrtc_array_container** containerp, // de-referenced
129 struct list const* const list,
130 bool reference) {
131 size_t n;
132 struct rawrtc_array_container* container;
133 struct le* le;
134 size_t i;
135
136 // Check arguments
137 if (!containerp || !list) {
138 return RAWRTC_CODE_INVALID_ARGUMENT;
139 }
140
141 // Get list length
142 n = list_count(list);
143
144 // Allocate array & set length immediately
145 container = mem_zalloc(
146 sizeof(*container) + sizeof(void*) * n, reference ? rawrtc_array_container_destroy : NULL);
147 if (!container) {
148 return RAWRTC_CODE_NO_MEMORY;
149 }
150 container->n_items = n;
151
152 // Copy pointer to each item
153 for (le = list_head(list), i = 0; le != NULL; le = le->next, ++i) {
154 if (reference) {
155 mem_ref(le->data);
156 }
157 container->items[i] = le->data;
158 }
159
160 // Set pointer & done
161 *containerp = container;
162 return RAWRTC_CODE_SUCCESS;
163}