James Kuszmaul | 4a42b18 | 2021-01-17 11:32:46 -0800 | [diff] [blame^] | 1 | #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 | */ |
| 13 | enum 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 | |
| 50 | out: |
| 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 | */ |
| 63 | enum 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 | */ |
| 110 | static 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 | */ |
| 127 | enum 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 | } |