+#include "local_string_utils.h" /* for flac__strlcat() and flac__strlcpy() */
+#include "utils.h"
+#include "vorbiscomment.h"
+
+#if defined _MSC_VER || defined __MINGW32__
+#define FLAC__STRCASECMP stricmp
+#else
+#define FLAC__STRCASECMP strcasecmp
+#endif
+
+#if 0
+/*[JEC] was:#if HAVE_GETOPT_LONG*/
+/*[JEC] see flac/include/share/getopt.h as to why the change */
+# include <getopt.h>
+#else
+# include "share/getopt.h"
+#endif
+
+static int do_it(void);
+
+static FLAC__bool init_options(void);
+static int parse_options(int argc, char *argv[]);
+static int parse_option(int short_option, const char *long_option, const char *option_argument);
+static void free_options(void);
+static void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value);
+static void add_compression_setting_string(compression_setting_type_t type, const char *value);
+static void add_compression_setting_unsigned(compression_setting_type_t type, unsigned value);
+
+static int usage_error(const char *message, ...);
+static void short_usage(void);
+static void show_version(void);
+static void show_help(void);
+static void show_explain(void);
+static void format_mistake(const char *infilename, FileFormat wrong, FileFormat right);
+
+static int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file);
+static int decode_file(const char *infilename);
+
+static const char *get_encoded_outfilename(const char *infilename);
+static const char *get_decoded_outfilename(const char *infilename);
+static const char *get_outfilename(const char *infilename, const char *suffix);
+
+static void die(const char *message);
+static int conditional_fclose(FILE *f);
+static char *local_strdup(const char *source);
+
+/*
+ * share__getopt format struct; note that for long options with no
+ * short option equivalent we just set the 'val' field to 0.
+ */
+static struct share__option long_options_[] = {
+ /*
+ * general options
+ */
+ { "help" , share__no_argument, 0, 'h' },
+ { "explain" , share__no_argument, 0, 'H' },
+ { "version" , share__no_argument, 0, 'v' },
+ { "decode" , share__no_argument, 0, 'd' },
+ { "analyze" , share__no_argument, 0, 'a' },
+ { "test" , share__no_argument, 0, 't' },
+ { "stdout" , share__no_argument, 0, 'c' },
+ { "silent" , share__no_argument, 0, 's' },
+ { "totally-silent" , share__no_argument, 0, 0 },
+ { "warnings-as-errors" , share__no_argument, 0, 'w' },
+ { "force" , share__no_argument, 0, 'f' },
+ { "delete-input-file" , share__no_argument, 0, 0 },
+ { "preserve-modtime" , share__no_argument, 0, 0 },
+ { "keep-foreign-metadata" , share__no_argument, 0, 0 },
+ { "output-prefix" , share__required_argument, 0, 0 },
+ { "output-name" , share__required_argument, 0, 'o' },
+ { "skip" , share__required_argument, 0, 0 },
+ { "until" , share__required_argument, 0, 0 },
+ { "channel-map" , share__required_argument, 0, 0 }, /* undocumented */
+
+ /*
+ * decoding options
+ */
+ { "decode-through-errors", share__no_argument, 0, 'F' },
+ { "cue" , share__required_argument, 0, 0 },
+ { "apply-replaygain-which-is-not-lossless", share__optional_argument, 0, 0 }, /* undocumented */
+
+ /*
+ * encoding options
+ */
+ { "cuesheet" , share__required_argument, 0, 0 },
+ { "no-cued-seekpoints" , share__no_argument, 0, 0 },
+ { "picture" , share__required_argument, 0, 0 },
+ { "tag" , share__required_argument, 0, 'T' },
+ { "tag-from-file" , share__required_argument, 0, 0 },
+ { "compression-level-0" , share__no_argument, 0, '0' },
+ { "compression-level-1" , share__no_argument, 0, '1' },
+ { "compression-level-2" , share__no_argument, 0, '2' },
+ { "compression-level-3" , share__no_argument, 0, '3' },
+ { "compression-level-4" , share__no_argument, 0, '4' },
+ { "compression-level-5" , share__no_argument, 0, '5' },
+ { "compression-level-6" , share__no_argument, 0, '6' },
+ { "compression-level-7" , share__no_argument, 0, '7' },
+ { "compression-level-8" , share__no_argument, 0, '8' },
+ { "compression-level-9" , share__no_argument, 0, '9' },
+ { "best" , share__no_argument, 0, '8' },
+ { "fast" , share__no_argument, 0, '0' },
+ { "verify" , share__no_argument, 0, 'V' },
+ { "force-raw-format" , share__no_argument, 0, 0 },
+ { "force-aiff-format" , share__no_argument, 0, 0 },
+ { "force-rf64-format" , share__no_argument, 0, 0 },
+ { "force-wave64-format" , share__no_argument, 0, 0 },
+ { "lax" , share__no_argument, 0, 0 },
+ { "replay-gain" , share__no_argument, 0, 0 },
+ { "ignore-chunk-sizes" , share__no_argument, 0, 0 },
+ { "sector-align" , share__no_argument, 0, 0 }, /* DEPRECATED */
+ { "seekpoint" , share__required_argument, 0, 'S' },
+ { "padding" , share__required_argument, 0, 'P' },
+#if FLAC__HAS_OGG
+ { "ogg" , share__no_argument, 0, 0 },
+ { "serial-number" , share__required_argument, 0, 0 },
+#endif
+ { "blocksize" , share__required_argument, 0, 'b' },
+ { "exhaustive-model-search" , share__no_argument, 0, 'e' },
+ { "max-lpc-order" , share__required_argument, 0, 'l' },
+ { "apodization" , share__required_argument, 0, 'A' },
+ { "mid-side" , share__no_argument, 0, 'm' },
+ { "adaptive-mid-side" , share__no_argument, 0, 'M' },
+ { "qlp-coeff-precision-search", share__no_argument, 0, 'p' },
+ { "qlp-coeff-precision" , share__required_argument, 0, 'q' },
+ { "rice-partition-order" , share__required_argument, 0, 'r' },
+ { "endian" , share__required_argument, 0, 0 },
+ { "channels" , share__required_argument, 0, 0 },
+ { "bps" , share__required_argument, 0, 0 },
+ { "sample-rate" , share__required_argument, 0, 0 },
+ { "sign" , share__required_argument, 0, 0 },
+ { "input-size" , share__required_argument, 0, 0 },
+
+ /*
+ * analysis options
+ */
+ { "residual-gnuplot", share__no_argument, 0, 0 },
+ { "residual-text", share__no_argument, 0, 0 },
+
+ /*
+ * negatives
+ */
+ { "no-preserve-modtime" , share__no_argument, 0, 0 },
+ { "no-decode-through-errors" , share__no_argument, 0, 0 },
+ { "no-silent" , share__no_argument, 0, 0 },
+ { "no-force" , share__no_argument, 0, 0 },
+ { "no-seektable" , share__no_argument, 0, 0 },
+ { "no-delete-input-file" , share__no_argument, 0, 0 },
+ { "no-keep-foreign-metadata" , share__no_argument, 0, 0 },
+ { "no-replay-gain" , share__no_argument, 0, 0 },
+ { "no-ignore-chunk-sizes" , share__no_argument, 0, 0 },
+ { "no-sector-align" , share__no_argument, 0, 0 }, /* DEPRECATED */
+ { "no-utf8-convert" , share__no_argument, 0, 0 },
+ { "no-lax" , share__no_argument, 0, 0 },
+#if FLAC__HAS_OGG
+ { "no-ogg" , share__no_argument, 0, 0 },
+#endif
+ { "no-exhaustive-model-search", share__no_argument, 0, 0 },
+ { "no-mid-side" , share__no_argument, 0, 0 },
+ { "no-adaptive-mid-side" , share__no_argument, 0, 0 },
+ { "no-qlp-coeff-prec-search" , share__no_argument, 0, 0 },
+ { "no-padding" , share__no_argument, 0, 0 },
+ { "no-verify" , share__no_argument, 0, 0 },
+ { "no-warnings-as-errors" , share__no_argument, 0, 0 },
+ { "no-residual-gnuplot" , share__no_argument, 0, 0 },
+ { "no-residual-text" , share__no_argument, 0, 0 },
+ /*
+ * undocumented debugging options for the test suite
+ */
+ { "disable-constant-subframes", share__no_argument, 0, 0 },
+ { "disable-fixed-subframes" , share__no_argument, 0, 0 },
+ { "disable-verbatim-subframes", share__no_argument, 0, 0 },
+ { "no-md5-sum" , share__no_argument, 0, 0 },
+
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * global to hold command-line option values
+ */
+
+static struct {
+ FLAC__bool show_help;
+ FLAC__bool show_explain;
+ FLAC__bool show_version;
+ FLAC__bool mode_decode;
+ FLAC__bool verify;
+ FLAC__bool treat_warnings_as_errors;
+ FLAC__bool force_file_overwrite;
+ FLAC__bool continue_through_decode_errors;
+ replaygain_synthesis_spec_t replaygain_synthesis_spec;
+ FLAC__bool lax;
+ FLAC__bool test_only;
+ FLAC__bool analyze;
+ FLAC__bool use_ogg;
+ FLAC__bool has_serial_number; /* true iff --serial-number was used */
+ long serial_number; /* this is the Ogg serial number and is unused for native FLAC */
+ FLAC__bool force_to_stdout;
+ FLAC__bool force_raw_format;
+ FLAC__bool force_aiff_format;
+ FLAC__bool force_rf64_format;
+ FLAC__bool force_wave64_format;
+ FLAC__bool delete_input;
+ FLAC__bool preserve_modtime;
+ FLAC__bool keep_foreign_metadata;
+ FLAC__bool replay_gain;
+ FLAC__bool ignore_chunk_sizes;
+ FLAC__bool sector_align;
+ FLAC__bool utf8_convert; /* true by default, to convert tag strings from locale to utf-8, false if --no-utf8-convert used */
+ const char *cmdline_forced_outfilename;
+ const char *output_prefix;
+ analysis_options aopts;
+ int padding; /* -1 => no -P options were given, 0 => -P- was given, else -P value */
+ size_t num_compression_settings;
+ compression_setting_t compression_settings[64]; /* bad MAGIC NUMBER but buffer overflow is checked */
+ const char *skip_specification;
+ const char *until_specification;
+ const char *cue_specification;
+ int format_is_big_endian;
+ int format_is_unsigned_samples;
+ int format_channels;
+ int format_bps;
+ int format_sample_rate;
+ FLAC__off_t format_input_size;
+ char requested_seek_points[5000]; /* bad MAGIC NUMBER but buffer overflow is checked */
+ int num_requested_seek_points; /* -1 => no -S options were given, 0 => -S- was given */
+ const char *cuesheet_filename;
+ FLAC__bool cued_seekpoints;
+ FLAC__bool channel_map_none; /* --channel-map=none specified, eventually will expand to take actual channel map */
+
+ unsigned num_files;
+ char **filenames;
+
+ FLAC__StreamMetadata *vorbis_comment;
+ FLAC__StreamMetadata *pictures[64];
+ unsigned num_pictures;
+
+ struct {
+ FLAC__bool disable_constant_subframes;
+ FLAC__bool disable_fixed_subframes;
+ FLAC__bool disable_verbatim_subframes;
+ FLAC__bool do_md5;
+ } debug;
+} option_values;
+
+
+/*
+ * miscellaneous globals
+ */
+
+static FLAC__int32 align_reservoir_0[588], align_reservoir_1[588]; /* for carrying over samples from --sector-align */ /* DEPRECATED */
+static FLAC__int32 *align_reservoir[2] = { align_reservoir_0, align_reservoir_1 };
+static unsigned align_reservoir_samples = 0; /* 0 .. 587 */
+