cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

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}