cscg22-gearboy

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

main.c (7713B)


      1// This is free and unencumbered software released into the public domain.
      2// For more information, please refer to <https://unlicense.org>
      3// bbbbbr 2020
      4
      5#include <stdio.h>
      6#include <string.h>
      7#include <stdlib.h>
      8#include <stdbool.h>
      9#include <stdint.h>
     10
     11#include "gbcompress.h"
     12#include "rlecompress.h"
     13#include "files.h"
     14#include "files_c_source.h"
     15
     16#define MAX_STR_LEN     4096
     17
     18#define COMPRESSION_TYPE_GB        0
     19#define COMPRESSION_TYPE_RLE_BLOCK 1
     20#define COMPRESSION_TYPE_DEFAULT   COMPRESSION_TYPE_GB
     21
     22char filename_in[MAX_STR_LEN] = {'\0'};
     23char filename_out[MAX_STR_LEN] = {'\0'};
     24
     25uint8_t * p_buf_in  = NULL;
     26uint8_t * p_buf_out = NULL;
     27
     28bool opt_mode_compress    = true;
     29bool opt_verbose          = false;
     30bool opt_compression_type = COMPRESSION_TYPE_DEFAULT;
     31bool opt_c_source_input   = false;
     32bool opt_c_source_output  = false;
     33char opt_c_source_output_varname[MAX_STR_LEN] = "var_name";
     34
     35static void display_help(void);
     36static int handle_args(int argc, char * argv[]);
     37static int compress(void);
     38static int decompress(void);
     39void cleanup(void);
     40
     41
     42static void display_help(void) {
     43    fprintf(stdout,
     44       "gbcompress [options] infile outfile\n"
     45       "Use: compress a binary file and write it out.\n"
     46       "\n"
     47       "Options\n"
     48       "-h    : Show this help screen\n"
     49       "-d    : Decompress (default is compress)\n"
     50       "-v    : Verbose output\n"
     51       "--cin  : Read input as .c source format (8 bit char ONLY, uses first array found)\n"
     52       "--cout : Write output in .c / .h source format (8 bit char ONLY) \n"
     53       "--varname=<NAME> : specify variable name for c source output\n"
     54       "--alg=<type>     : specify compression type: 'rle', 'gb' (default)\n"
     55       "Example: \"gbcompress binaryfile.bin compressed.bin\"\n"
     56       "Example: \"gbcompress -d compressedfile.bin decompressed.bin\"\n"
     57       "Example: \"gbcompress --alg=rle binaryfile.bin compressed.bin\"\n"
     58       "\n"
     59       "The default compression (gb) is the type used by gbtd/gbmb\n"
     60       "The rle compression is Amiga IFF style\n"
     61       );
     62}
     63
     64
     65int handle_args(int argc, char * argv[]) {
     66
     67    int i = 1; // start at first arg
     68
     69    if( argc < 3 ) {
     70        display_help();
     71        return false;
     72    }
     73
     74    // Start at first optional argument
     75    // Last two arguments *must* be input/output files
     76    for (i = 1; i < (argc - 2); i++ ) {
     77
     78        if (argv[i][0] == '-') {
     79            if (strstr(argv[i], "-h") == argv[i]) {
     80                display_help();
     81                return false;  // Don't parse input when -h is used
     82            } else if (strstr(argv[i], "-v") == argv[i]) {
     83                opt_verbose = true;
     84            } else if (strstr(argv[i], "--cin") == argv[i]) {
     85                opt_c_source_input = true;
     86            } else if (strstr(argv[i], "--cout") == argv[i]) {
     87                opt_c_source_output = true;
     88            } else if (strstr(argv[i], "--varname=") == argv[i]) {
     89                snprintf(opt_c_source_output_varname, sizeof(opt_c_source_output_varname), "%s", argv[i] + 10);
     90            } else if (strstr(argv[i], "--alg=gb") == argv[i]) {
     91                opt_compression_type = COMPRESSION_TYPE_GB;
     92            } else if (strstr(argv[i], "--alg=rle") == argv[i]) {
     93                opt_compression_type = COMPRESSION_TYPE_RLE_BLOCK;
     94            } else if (strstr(argv[i], "-d") == argv[i]) {
     95                opt_mode_compress = false;
     96            } else
     97                printf("gbcompress: Warning: Ignoring unknown option %s\n", argv[i]);
     98        }
     99    }
    100
    101    // Copy input and output filenames from last two arguments
    102    // if not preceded with option dash
    103    if (argv[i][0] != '-') {
    104        snprintf(filename_in, sizeof(filename_in), "%s", argv[i++]);
    105
    106        if (argv[i][0] != '-') {
    107            snprintf(filename_out, sizeof(filename_out), "%s", argv[i++]);
    108            return true;
    109        }
    110    }
    111
    112
    113    return false;
    114}
    115
    116
    117void cleanup(void) {
    118    if (p_buf_in != NULL) {
    119        free(p_buf_in);
    120        p_buf_in = NULL;
    121    }
    122    if (p_buf_out != NULL) {
    123        free(p_buf_out);
    124        p_buf_out = NULL;
    125    }
    126}
    127
    128
    129static int compress() {
    130
    131    uint32_t  buf_size_in = 0;
    132    uint32_t  buf_size_out = 0;
    133    uint32_t  out_len = 0;
    134    bool      result = false;
    135
    136    if (opt_c_source_input)
    137        p_buf_in =  file_read_c_input_into_buffer(filename_in, &buf_size_in);
    138    else
    139        p_buf_in =  file_read_into_buffer(filename_in, &buf_size_in);
    140
    141    // Allocate buffer output buffer same size as input
    142    // It can grow more in gbdecompress_buf()
    143    buf_size_out = buf_size_in;
    144    p_buf_out = malloc(buf_size_out);
    145
    146    if ((p_buf_in) && (p_buf_out) && (buf_size_in > 0)) {
    147
    148        if (opt_compression_type == COMPRESSION_TYPE_GB)
    149            out_len = gbcompress_buf(p_buf_in, buf_size_in, &p_buf_out, buf_size_out);
    150        else if (opt_compression_type == COMPRESSION_TYPE_RLE_BLOCK)
    151            out_len = rlecompress_buf(p_buf_in, buf_size_in, &p_buf_out, buf_size_out);
    152        else
    153            return EXIT_FAILURE;
    154
    155        if (out_len > 0) {
    156
    157            if (opt_c_source_output) {
    158                c_source_set_sizes(out_len, buf_size_in); // compressed, decompressed
    159                result = file_write_c_output_from_buffer(filename_out, p_buf_out, out_len, opt_c_source_output_varname, true);
    160            }
    161            else
    162                result = file_write_from_buffer(filename_out, p_buf_out, out_len);
    163
    164            if (result) {
    165                if (opt_verbose)
    166                    printf("Compressed: %d bytes -> %d bytes (%%%.2f)\n", buf_size_in, out_len, ((double)out_len / (double)buf_size_in) * 100);
    167                return EXIT_SUCCESS;
    168            }
    169        }
    170    }
    171
    172    return EXIT_FAILURE;
    173}
    174
    175
    176static int decompress() {
    177
    178    uint32_t  buf_size_in = 0;
    179    uint32_t  buf_size_out = 0;
    180    uint32_t  out_len = 0;
    181    bool      result = false;
    182
    183    if (opt_c_source_input)
    184        p_buf_in =  file_read_c_input_into_buffer(filename_in, &buf_size_in);
    185    else
    186        p_buf_in =  file_read_into_buffer(filename_in, &buf_size_in);
    187
    188    // Allocate buffer output buffer 3x size of input
    189    // It can grow more in gbdecompress_buf()
    190    buf_size_out = buf_size_in * 3;
    191    p_buf_out = malloc(buf_size_out);
    192
    193    if ((p_buf_in) && (p_buf_out) && (buf_size_in > 0)) {
    194
    195        if (opt_compression_type == COMPRESSION_TYPE_GB)
    196            out_len = gbdecompress_buf(p_buf_in, buf_size_in, &p_buf_out, buf_size_out);
    197        else if (opt_compression_type == COMPRESSION_TYPE_RLE_BLOCK)
    198            out_len = rledecompress_buf(p_buf_in, buf_size_in, &p_buf_out, buf_size_out);
    199        else
    200            return EXIT_FAILURE;
    201
    202        if (out_len > 0) {
    203
    204            if (opt_c_source_output) {
    205                c_source_set_sizes(buf_size_in, out_len); // compressed, decompressed
    206                result = file_write_c_output_from_buffer(filename_out, p_buf_out, out_len, opt_c_source_output_varname, true);
    207            }
    208            else {
    209                result = file_write_from_buffer(filename_out, p_buf_out, out_len);
    210            }
    211
    212            if (result) {
    213                if (opt_verbose)
    214                    printf("Decompressed: %d bytes -> %d bytes (compression was %%%.2f)\n", buf_size_in, out_len, ((double)buf_size_in / (double)out_len) * 100);
    215                return EXIT_SUCCESS;
    216            }
    217        }
    218    }
    219
    220    return EXIT_FAILURE;
    221}
    222
    223
    224int main( int argc, char *argv[] )  {
    225
    226    // Exit with failure by default
    227    int ret = EXIT_FAILURE;
    228
    229    // Register cleanup with exit handler
    230    atexit(cleanup);
    231
    232    if (handle_args(argc, argv)) {
    233
    234        if (opt_mode_compress)
    235            ret = compress();
    236        else
    237            ret = decompress();
    238    }
    239    cleanup();
    240
    241    return ret; // Exit with failure by default
    242}