int main(int argc, char*const* argv) { int opt, has_consumed_fmt_input; unsigned i; co_this = argv[0]; while (-1 != (opt = #ifdef HAVE_GETOPT_LONG getopt_long(argc, argv, short_options, long_options, NULL) #else getopt(argc, argv, short_options) #endif )) { switch (opt) { case '?': case ':': case 'h': fputs(usage_statement, opt == 'h'? stdout : stderr); return (opt == 'h'? 0 : 255); case 'V': puts("drachencode (" PACKAGE_STRING ")"); return 0; case 'b': uint_arg_or_die(&co_block_size, "block-size"); break; case 'd': co_is_decoding = 1; break; case 'D': co_dryrun = 1; break; case 'e': co_is_encoding = 1; break; case 'f': co_force = 1; break; case 'H': uint_arg_or_die(&co_image_bh, "img-block-height"); break; case 'W': uint_arg_or_die(&co_image_bw, "img-block-width"); break; case 'O': uint_arg_or_die(&co_image_off, "img-offset"); break; case 'C': uint_arg_or_die(&co_image_nc, "img-num-cols"); break; case 'X': uint_arg_or_die(&co_image_comps, "img-num-components"); break; case 'R': uint_arg_or_die(&co_image_nr, "img-num-rows"); break; case 'w': co_nowarn = 1; break; case 'N': co_base_son_on_output = 1; break; case 'n': co_sequential_output_name = strdup(optarg); break; case 'u': co_allow_unsafe_names = 1; break; case 'o': co_primary_filename = strdup(optarg); break; case 't': co_timing_statistics = 1; break; case 'v': ++co_verbosity; break; case 'Z': co_zero_frames = 1; break; case 'a': uint_arg_or_die(&co_begin, "begin"); break; case 'z': uint_arg_or_die(&co_end, "end"); break; case 's': uint_arg_or_die(&co_stride, "stride"); break; default: fprintf(stderr, "%s: FATAL: Unknown \"known\" option: %c\n", co_this, (char)opt); exit(255); } } /* Validate options */ if (!(co_is_decoding ^ co_is_encoding)) { l_error("Exactly one of --encode or --decode must be specified."); return 255; } if (co_is_encoding && (co_image_nc || co_image_nr || co_image_bw || co_image_bh || co_image_off || co_image_comps) && !(co_image_nc && co_image_nr && co_image_bw && co_image_bh)) { l_error("Either no image options, or at least --img-num-cols,\n" "--img-num-rows, --img-block-width, and --img-block-height\n" "must be specified."); return 255; } if (co_image_nc && !co_image_comps) co_image_comps = 1; /* Validate the format string, if given */ if (co_sequential_output_name) { has_consumed_fmt_input = 0; for (i = 0; co_sequential_output_name[i]; ++i) { if (co_sequential_output_name[i] == '%') { ++i; if (co_sequential_output_name[i] == '%') /* Simple escaped percent sign */ continue; if (has_consumed_fmt_input) { l_error("Format string has more than one consuming formatting."); return 255; } has_consumed_fmt_input = 1; /* Flags */ while (co_sequential_output_name[i] == '#' || co_sequential_output_name[i] == '0' || co_sequential_output_name[i] == '-' || co_sequential_output_name[i] == ' ' || co_sequential_output_name[i] == '+') ++i; /* Width */ while (co_sequential_output_name[i] >= '0' && co_sequential_output_name[i] <= '9') ++i; /* Type */ if (co_sequential_output_name[i] != 'd' && co_sequential_output_name[i] != 'i' && co_sequential_output_name[i] != 'o' && co_sequential_output_name[i] != 'u' && co_sequential_output_name[i] != 'x' && co_sequential_output_name[i] != 'X') { l_error("Invalid format string type."); return 255; } } } if (!has_consumed_fmt_input) { l_error("Format string is not variant."); return 255; } } if (co_is_encoding && !co_force && !co_primary_filename) { l_error("Not implicitly encoding to standard output without --force"); return 255; } if (co_image_bh && co_image_nr && co_image_nr % co_image_bh) { l_warn("img-block-height does not divide evenly into img-num-rows."); l_warn("Actual block height will differ from what you specfied."); } if (co_image_bw && co_image_nc && co_image_nc % co_image_bw) { l_warn("img-block-width does not divide evenly into img-num-cols."); l_warn("Actual block height will differ from what you specified."); } if (co_dryrun && co_is_encoding) { l_report("Changing output file to /dev/null to perform dry-run."); co_primary_filename = "/dev/null"; } if (co_is_encoding) { co_num_encoding_input_files = optind <= argc? argc - optind : 0; /* Cast is safe, we won't be modifying anything. * (char*const* -> const char*const* is technically "incompatible") */ co_encoding_input_files = (const char*const*)argv+optind; if (!co_num_encoding_input_files) { l_error("No encoding input files given."); return 255; } return do_encode(); } else { if (optind >= argc) { co_primary_filename = "-"; if (!co_force) l_warn("Decoding from standard input."); } else if (argc - optind == 1) { co_primary_filename = argv[optind]; } else { l_error("Too many input files."); return 255; } return do_decode(); } }
static int do_encode(void) { FILE* file = 0, *infile = 0; drachen_encoder* enc = NULL; struct stat statbuf; uint32_t frame_size, amt_read; uint32_t* custom_xform = NULL; unsigned char* buffer = NULL; int status = 0; unsigned i; clock_t enc_start, enc_end, total_time = 0; unsigned long long total_data; unsigned data_suffix = 0; drachen_block_spec custom_blocks[2]; if (!co_primary_filename || !strcmp(co_primary_filename, "-")) file = stdin; else file = fopen(co_primary_filename, /* Only allow overwriting if forced, or if writing to the * bitbucket. */ co_force || !strcmp(co_primary_filename, "/dev/null")? "wb" : "wbx"); if (!file) { l_sysferr("Could not open output file", co_primary_filename); if (errno == EEXIST) fprintf(stderr, "Use --force to overwrite it anyway.\n"); status = 254; goto finish; } /* Get the frame size from the first file */ if (stat(co_encoding_input_files[0], &statbuf)) { l_sysferr("Could not stat first input file", co_encoding_input_files[0]); status = 254; goto finish; } if (!statbuf.st_size) { l_error("First file appears to be empty (size==0), giving up."); status = 254; goto finish; } frame_size = statbuf.st_size; l_reportf("Using frame size of %u bytes.\n", (unsigned)frame_size); if (co_image_bw) { if (frame_size < co_image_off + co_image_comps*co_image_nr*co_image_nc) { l_error("Frames are too small for the image parameters you specified."); status = 255; goto finish; } if (frame_size > co_image_nc + co_image_comps*co_image_nr*co_image_nc) l_warn("Frame size is larger than the space used by the image parms."); custom_xform = malloc(sizeof(uint32_t)*frame_size); if (!custom_xform) { l_syserr("Could not allocate image transform buffer"); status = 254; goto finish; } /* Initialise the whole thing first in case the image doesn't cover the * whole thing. */ for (i = 0; i < frame_size; ++i) custom_xform[i] = i; drachen_make_image_xform_matrix(custom_xform, co_image_off, co_image_nc, co_image_nr, co_image_comps, co_image_bw, co_image_bh); } buffer = malloc(frame_size); if (!buffer) { l_syserr("Could not allocate input buffer"); status = 254; goto finish; } enc = drachen_create_encoder(file, frame_size, custom_xform); if (!enc) { l_syserr("Could not allocate encoder"); status = 254; goto finish; } if (co_block_size) { custom_blocks[0].segment_end = 0xFFFFFFFFu; custom_blocks[0].block_size = co_block_size; drachen_set_block_size(enc, custom_blocks); } else if (co_image_bh) { if (co_image_off) { custom_blocks[0].segment_end = co_image_off; custom_blocks[0].block_size = co_image_off; custom_blocks[1].segment_end = 0xFFFFFFFFu; custom_blocks[1].block_size = co_image_bw/4; if (custom_blocks[1].block_size < 16) custom_blocks[1].block_size = co_image_bw; } else { custom_blocks[0].segment_end = 0xFFFFFFFFu; custom_blocks[0].block_size = co_image_bw/4; if (custom_blocks[0].block_size < 16) custom_blocks[0].block_size = co_image_bw; } drachen_set_block_size(enc, custom_blocks); } for (i = 0; i < co_num_encoding_input_files; ++i) { l_report(co_encoding_input_files[i]); infile = fopen(co_encoding_input_files[i], "rb"); if (!infile) { l_sysferr("Could not open input file", co_encoding_input_files[i]); status = 254; goto finish; } amt_read = fread(buffer, 1, frame_size, infile); if (ferror(infile)) { l_sysferr("Could not read from input file", co_encoding_input_files[i]); status = 254; goto finish; } if (EOF != fgetc(infile)) { l_warns("File is longer than frame size; it will be truncated", co_encoding_input_files[i]); } fclose(infile); infile = NULL; if (amt_read < frame_size) { l_warns("File is shorter than frame size; other bytes assumed zero.", co_encoding_input_files[i]); memset(buffer+amt_read, 0, frame_size-amt_read); } enc_start = clock(); status = drachen_encode(enc, buffer, co_encoding_input_files[i]); enc_end = clock(); if (status) { l_errore(co_encoding_input_files[i], enc); goto finish; } total_time += enc_end - enc_start; if (co_timing_statistics) l_report_extraf("File %s encoded in %u ms\n", co_encoding_input_files[i], (unsigned)((enc_end-enc_start)*1000/CLOCKS_PER_SEC)); } /* If timing statistics were requested, print them */ if (co_timing_statistics) { if (total_time == 0) total_time = 1; fprintf(stderr, "Encoding rate:\n"); fprintf(stderr, " Frames/ms: %u\n", (unsigned)(((unsigned long long)co_num_encoding_input_files) * CLOCKS_PER_SEC / 1000 / total_time)); fprintf(stderr, " Frames/sec: %u\n", (unsigned)(((unsigned long long)co_num_encoding_input_files) * CLOCKS_PER_SEC / total_time)); fprintf(stderr, " Frames/min: %u\n", (unsigned)(((unsigned long long)co_num_encoding_input_files) * 60 * CLOCKS_PER_SEC / total_time)); total_data = co_num_encoding_input_files; total_data *= frame_size; total_data *= CLOCKS_PER_SEC; total_data /= total_time; while (total_data > 1024*1024) { total_data /= 1024; ++data_suffix; } fprintf(stderr, " Data rate: %u %s/sec\n", (unsigned)total_data, data_suffices[data_suffix]); } finish: if (infile) fclose(infile); if (buffer) free(buffer); if (custom_xform) free(custom_xform); if (enc) { drachen_free(enc); file = NULL; } if (file) fclose(file); return status; }
// Find the matching plugin structure for the section name `section`. If no // such section exists, a new one is allocated and returned. If the section // name matches the special name "Global", it is added to the appropriate list. // // Returns true on success, false on failure. static bool find_plugin_section(struct registry *registry, const char *section, struct plugin **plugin) { struct plugin *current; // Check if this is the special "Global" section used to specify default // parameters and other special values. if (strcmp(section, "Global") == 0) { // If this is the first value from the Global section, we need to // create it. if (registry->global == NULL) { // Allocate a new structure. if ((*plugin = calloc(1, sizeof(**plugin))) == NULL) { l_error("memory allocation failure"); return false; } // Install as the global plugin. registry->global = *plugin; registry->global->section = strdup(section); } // Return pointer to parent. *plugin = registry->global; // Success. return !! registry->global->section; } else { // This is not the Global section, a regular plugin section. current = registry->plugins; for (current = registry->plugins; current; current = current->next) { // Search to see if we already recognise this section. if (strcmp(current->section, section) == 0) { // Match found. *plugin = current; return true; } } } // This is the first time we've seen this section, we have to set it up. l_debug("new plugin section %s discovered", section); // Allocate a new structure. if ((*plugin = calloc(1, sizeof(**plugin))) == NULL) { l_error("memory allocation failure"); return false; } // Check if we have any other plugins registered. if (registry->plugins != NULL) { // Find the tail of the plugin registry. for (current = registry->plugins; current->next; current = current->next) ; // Add to the list. current->next = *plugin; current = current->next; current->section = strdup(section); } else { // This is the first plugin structure we've seen, create the list head. registry->plugins = *plugin; registry->plugins->section = strdup(section); current = registry->plugins; } // Success. return !! current->section; }