files_c_source.c (6743B)
1 2#include <stdio.h> 3#include <stdbool.h> 4#include <stdint.h> 5#include <string.h> 6#include <stdlib.h> 7 8#include "files.h" 9 10#define STR_FFWD_MATCH_ANY NULL 11 12#define BUF_DEFAULT_SIZE 20000 13#define BUF_GROW_SIZE 10000 14 15 16static uint32_t size_compressed = 0; 17static uint32_t size_decompressed = 0; 18 19 20void c_source_set_sizes(uint32_t size_compressed_in, uint32_t size_decompressed_in) { 21 size_compressed = size_compressed_in; 22 size_decompressed = size_decompressed_in; 23} 24 25 26// Search for a character in a string 27// 28// Terminate search if: 29// * any non-allowed character was found (str_chars_allowed, NULL for allow any chars) 30// * end of string is reached (by terminator or length) 31// 32static char * str_ffwd_to(char * str_in, uint32_t * max_len, char char_match, char * str_chars_allowed) { 33 34 char str_cur[2] = " \0"; // current character to test, for strpbrk 35 36 while ((*max_len) && (*str_in != '\0')) { 37 38 str_cur[0] = *str_in; 39 if (*str_in == char_match) 40 return str_in; 41 else if (str_chars_allowed) { 42 if (strpbrk(str_cur, str_chars_allowed) == NULL) { 43 // signal failure if any non-allowed character was found 44 return NULL; 45 } 46 } 47 48 str_in++; 49 (*max_len)--; 50 } 51 52 return NULL; 53} 54 55 56 57// Convert an array of comma delimtied numbers into a buffer 58// 59// If conversion fails: returns NULL, *p_ret_size == 0 60// 61static uint8_t * str_array_to_buf(char * str_in, uint32_t * p_ret_len) { 62 63 uint32_t buf_size = BUF_DEFAULT_SIZE; 64 uint8_t * p_buf = malloc(buf_size); 65 uint8_t * p_buf_last; 66 char * end_ptr; 67 68 // Read value at a time from a string buffer 69 // (strtok will replace the , chars with \0 on each split) 70 char * str_cur = strtok(str_in,","); 71 72 if (p_buf) { 73 74 // Start with size zero 75 *p_ret_len = 0; 76 77 // Loop as long as strtok returns comma separated items 78 while (str_cur != NULL) { 79 80 // Grow buffer if needed 81 if ((*p_ret_len) >= buf_size) { 82 83 buf_size += BUF_GROW_SIZE; 84 p_buf_last = p_buf; 85 p_buf = (uint8_t *)realloc(p_buf, buf_size); 86 87 // Exit if realloc failed 88 if (p_buf == NULL) { 89 *p_ret_len = 0; 90 free(p_buf_last); 91 return NULL; 92 } 93 } 94 95 // Store current value 96 p_buf[ *p_ret_len ] = (uint8_t)strtol(str_cur, &end_ptr, 0); 97 98 // Only advance data buffer if conversion didn't fail 99 if (str_cur != end_ptr) 100 (*p_ret_len)++; 101 102 // Read next value (strtok maintains state of last call) 103 str_cur = strtok(NULL,","); 104 } 105 } 106 107 return p_buf; 108} 109 110 111 112// Read from a file into a buffer, find first C source formatted 113// array and parse it into another buffer (will allocate needed memory) 114// 115// Returns NULL if reading file didn't succeed 116// 117uint8_t * file_read_c_input_into_buffer(char * filename, uint32_t *ret_size) { 118 119 char * filedata = NULL; 120 uint32_t file_size; 121 122 char * str_c_array = NULL; 123 char * str_c_array_start = NULL; 124 uint8_t * p_array_data = NULL; 125 126 filedata = file_read_into_buffer_char(filename, &file_size); 127 128 if (filedata) { 129 str_c_array = filedata; 130 131 // Find array opening bracket `[` 132 str_c_array = str_ffwd_to(str_c_array, &file_size, '[', STR_FFWD_MATCH_ANY); 133 if (str_c_array) { 134 // Find Array closing bracket `]` 135 str_c_array = str_ffwd_to(str_c_array, &file_size, ']', "[xX0123456789ABCDEFabcdef\t\n\r "); 136 if (str_c_array) { 137 // Find Start or array 138 str_c_array = str_ffwd_to(str_c_array, &file_size, '{', "]\t\n\r ="); 139 if (str_c_array) { 140 // Save start of array 141 str_c_array_start = str_c_array + 1; 142 143 // Find end of array 144 str_c_array = str_ffwd_to(str_c_array, &file_size, '}', "{xX0123456789ABCDEFabcdef,\t\n\r "); 145 if (str_c_array) { 146 // Terminate string at end of array 147 *str_c_array = '\0'; 148 149 // If conversion fails: p_array_data == NULL, ret_size == 0 150 p_array_data = str_array_to_buf(str_c_array_start, ret_size); 151 152 // printf("C array length in = %d", *ret_size); 153 } 154 } 155 } 156 } 157 158 // Free file data if allocated 159 free(filedata); 160 filedata = NULL; 161 } 162 163 return p_array_data; 164} 165 166 167 168// Writes a buffer to a file in C source format 169// Adds a matching .h if possible 170// 171bool file_write_c_output_from_buffer(char * filename, uint8_t * p_buf, uint32_t data_len, char * var_name, bool var_is_const) { 172 173 bool status = false; 174 size_t wrote_bytes; 175 FILE * file_out = fopen(filename, "w"); 176 int i; 177 178 if (file_out) { 179 180 // Array entry with variable name 181 fprintf(file_out, "\n\n%s unsigned char %s[] = {", (var_is_const) ? "const" : "", var_name); 182 183 for (i = 0; i < data_len; i++) { 184 185 // Line break every 16 bytes (includes at start. but exclude if on last entry) 186 if ((i != data_len -1 ) && ((i % 16) == 0)) 187 fprintf(file_out, "\n "); 188 189 // Write current byte 190 fprintf(file_out, "0x%.2X", p_buf[i]); 191 192 // Add comma after every entry except last one 193 if (i != data_len -1) 194 fprintf(file_out, ", "); 195 } 196 fprintf(file_out, "\n};\n\n"); 197 status = true; 198 199 fclose(file_out); 200 201 202 // Create matching .h header file output, if file ends in .c or .C 203 if (strlen(filename) >= 2) { 204 if ((strcmp(&filename[strlen(filename) - 2],".c") == 0) || 205 (strcmp(&filename[strlen(filename) - 2],".C") == 0)) { 206 207 // Replace file extension 208 filename[strlen(filename) - 2] = '.'; 209 filename[strlen(filename) - 1] = 'h'; 210 211 FILE * file_out = fopen(filename, "w"); 212 213 if (file_out) { 214 215 fprintf(file_out, "\n\n#define %s_sz_comp %d\n", var_name, size_compressed); 216 fprintf(file_out, "#define %s_sz_decomp %d\n", var_name, size_decompressed); 217 218 // array entry with variable name 219 fprintf(file_out, "\n\nextern %s unsigned char %s[];\n\n", (var_is_const) ? "const" : "", var_name); 220 221 fclose(file_out); 222 } 223 } 224 } 225 } 226 227 return status; 228}