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}