FLAC__bool flac__vorbiscomment_add(FLAC__StreamMetadata *block, const char *comment, FLAC__bool value_from_file, const char **violation)
{
	Argument_VcField parsed;
	FLAC__bool dummy;

	FLAC__ASSERT(0 != block);
	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
	FLAC__ASSERT(0 != comment);

	memset(&parsed, 0, sizeof(parsed));

	parsed.field_value_from_file = value_from_file;
	if(!parse_vorbis_comment_field(comment, &(parsed.field), &(parsed.field_name), &(parsed.field_value), &(parsed.field_value_length), violation)) {
		free_field(&parsed);
		return false;
	}

	if(!set_vc_field(block, &parsed, &dummy, /*raw=*/false, violation)) {
		free_field(&parsed);
		return false;
	}
	else {
		free_field(&parsed);
		return true;
	}
}
FLAC__bool import_vc_from(const char *filename, FLAC__StreamMetadata *block, const Argument_String *vc_filename, FLAC__bool *needs_write, FLAC__bool raw)
{
	FILE *f;
	char line[65536];
	FLAC__bool ret;

	if(0 == vc_filename->value || strlen(vc_filename->value) == 0) {
		fprintf(stderr, "%s: ERROR: empty import file name\n", filename);
		return false;
	}
	if(0 == strcmp(vc_filename->value, "-"))
		f = stdin;
	else
		f = fopen(vc_filename->value, "r");

	if(0 == f) {
		fprintf(stderr, "%s: ERROR: can't open import file %s: %s\n", filename, vc_filename->value, strerror(errno));
		return false;
	}

	ret = true;
	while(ret && !feof(f)) {
		fgets(line, sizeof(line), f);
		if(!feof(f)) {
			char *p = strchr(line, '\n');
			if(0 == p) {
				fprintf(stderr, "%s: ERROR: line too long, aborting\n", vc_filename->value);
				ret = false;
			}
			else {
				const char *violation;
				Argument_VcField field;
				*p = '\0';
				memset(&field, 0, sizeof(Argument_VcField));
				field.field_value_from_file = false;
				if(!parse_vorbis_comment_field(line, &field.field, &field.field_name, &field.field_value, &field.field_value_length, &violation)) {
					FLAC__ASSERT(0 != violation);
					fprintf(stderr, "%s: ERROR: malformed vorbis comment field \"%s\",\n       %s\n", vc_filename->value, line, violation);
					ret = false;
				}
				else {
					ret = set_vc_field(filename, block, &field, needs_write, raw);
				}
				if(0 != field.field)
					free(field.field);
				if(0 != field.field_name)
					free(field.field_name);
				if(0 != field.field_value)
					free(field.field_value);
			}
		}
	};

	if(f != stdin)
		fclose(f);
	return ret;
}
Beispiel #3
0
FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options)
{
	const char *opt = long_options_[option_index].name;
	Operation *op;
	Argument *arg;
	FLAC__bool ok = true;

	if(0 == strcmp(opt, "preserve-modtime")) {
		options->preserve_modtime = true;
	}
	else if(0 == strcmp(opt, "with-filename")) {
		options->prefix_with_filename = true;
	}
	else if(0 == strcmp(opt, "no-filename")) {
		options->prefix_with_filename = false;
	}
	else if(0 == strcmp(opt, "no-utf8-convert")) {
		options->utf8_convert = false;
	}
	else if(0 == strcmp(opt, "dont-use-padding")) {
		options->use_padding = false;
	}
	else if(0 == strcmp(opt, "no-cued-seekpoints")) {
		options->cued_seekpoints = false;
	}
	else if(0 == strcmp(opt, "show-md5sum")) {
		(void) append_shorthand_operation(options, OP__SHOW_MD5SUM);
	}
	else if(0 == strcmp(opt, "show-min-blocksize")) {
		(void) append_shorthand_operation(options, OP__SHOW_MIN_BLOCKSIZE);
	}
	else if(0 == strcmp(opt, "show-max-blocksize")) {
		(void) append_shorthand_operation(options, OP__SHOW_MAX_BLOCKSIZE);
	}
	else if(0 == strcmp(opt, "show-min-framesize")) {
		(void) append_shorthand_operation(options, OP__SHOW_MIN_FRAMESIZE);
	}
	else if(0 == strcmp(opt, "show-max-framesize")) {
		(void) append_shorthand_operation(options, OP__SHOW_MAX_FRAMESIZE);
	}
	else if(0 == strcmp(opt, "show-sample-rate")) {
		(void) append_shorthand_operation(options, OP__SHOW_SAMPLE_RATE);
	}
	else if(0 == strcmp(opt, "show-channels")) {
		(void) append_shorthand_operation(options, OP__SHOW_CHANNELS);
	}
	else if(0 == strcmp(opt, "show-bps")) {
		(void) append_shorthand_operation(options, OP__SHOW_BPS);
	}
	else if(0 == strcmp(opt, "show-total-samples")) {
		(void) append_shorthand_operation(options, OP__SHOW_TOTAL_SAMPLES);
	}
	else if(0 == strcmp(opt, "set-md5sum")) {
		op = append_shorthand_operation(options, OP__SET_MD5SUM);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_md5(option_argument, op->argument.streaminfo_md5.value)) {
			flac_fprintf(stderr, "ERROR (--%s): bad MD5 sum\n", opt);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "set-min-blocksize")) {
		op = append_shorthand_operation(options, OP__SET_MIN_BLOCKSIZE);
		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BLOCK_SIZE || op->argument.streaminfo_uint32.value > FLAC__MAX_BLOCK_SIZE) {
			flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "set-max-blocksize")) {
		op = append_shorthand_operation(options, OP__SET_MAX_BLOCKSIZE);
		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BLOCK_SIZE || op->argument.streaminfo_uint32.value > FLAC__MAX_BLOCK_SIZE) {
			flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "set-min-framesize")) {
		op = append_shorthand_operation(options, OP__SET_MIN_FRAMESIZE);
		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value >= (1u<<FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) {
			flac_fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "set-max-framesize")) {
		op = append_shorthand_operation(options, OP__SET_MAX_FRAMESIZE);
		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value >= (1u<<FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) {
			flac_fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "set-sample-rate")) {
		op = append_shorthand_operation(options, OP__SET_SAMPLE_RATE);
		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || !FLAC__format_sample_rate_is_valid(op->argument.streaminfo_uint32.value)) {
			flac_fprintf(stderr, "ERROR (--%s): invalid sample rate\n", opt);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "set-channels")) {
		op = append_shorthand_operation(options, OP__SET_CHANNELS);
		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value > FLAC__MAX_CHANNELS) {
			flac_fprintf(stderr, "ERROR (--%s): value must be > 0 and <= %u\n", opt, FLAC__MAX_CHANNELS);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "set-bps")) {
		op = append_shorthand_operation(options, OP__SET_BPS);
		if(!parse_uint32(option_argument, &(op->argument.streaminfo_uint32.value)) || op->argument.streaminfo_uint32.value < FLAC__MIN_BITS_PER_SAMPLE || op->argument.streaminfo_uint32.value > FLAC__MAX_BITS_PER_SAMPLE) {
			flac_fprintf(stderr, "ERROR (--%s): value must be >= %u and <= %u\n", opt, FLAC__MIN_BITS_PER_SAMPLE, FLAC__MAX_BITS_PER_SAMPLE);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "set-total-samples")) {
		op = append_shorthand_operation(options, OP__SET_TOTAL_SAMPLES);
		if(!parse_uint64(option_argument, &(op->argument.streaminfo_uint64.value)) || op->argument.streaminfo_uint64.value >= (((FLAC__uint64)1)<<FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) {
			flac_fprintf(stderr, "ERROR (--%s): value must be a %u-bit unsigned integer\n", opt, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN);
			ok = false;
		}
		else
			undocumented_warning(opt);
	}
	else if(0 == strcmp(opt, "show-vendor-tag")) {
		(void) append_shorthand_operation(options, OP__SHOW_VC_VENDOR);
	}
	else if(0 == strcmp(opt, "show-tag")) {
		const char *violation;
		op = append_shorthand_operation(options, OP__SHOW_VC_FIELD);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
			FLAC__ASSERT(0 != violation);
			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "remove-all-tags")) {
		(void) append_shorthand_operation(options, OP__REMOVE_VC_ALL);
	}
	else if(0 == strcmp(opt, "remove-tag")) {
		const char *violation;
		op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
			FLAC__ASSERT(0 != violation);
			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "remove-first-tag")) {
		const char *violation;
		op = append_shorthand_operation(options, OP__REMOVE_VC_FIRSTFIELD);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_vorbis_comment_field_name(option_argument, &(op->argument.vc_field_name.value), &violation)) {
			FLAC__ASSERT(0 != violation);
			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field name \"%s\",\n       %s\n", opt, option_argument, violation);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "set-tag")) {
		const char *violation;
		op = append_shorthand_operation(options, OP__SET_VC_FIELD);
		FLAC__ASSERT(0 != option_argument);
		op->argument.vc_field.field_value_from_file = false;
		if(!parse_vorbis_comment_field(option_argument, &(op->argument.vc_field.field), &(op->argument.vc_field.field_name), &(op->argument.vc_field.field_value), &(op->argument.vc_field.field_value_length), &violation)) {
			FLAC__ASSERT(0 != violation);
			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field \"%s\",\n       %s\n", opt, option_argument, violation);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "set-tag-from-file")) {
		const char *violation;
		op = append_shorthand_operation(options, OP__SET_VC_FIELD);
		FLAC__ASSERT(0 != option_argument);
		op->argument.vc_field.field_value_from_file = true;
		if(!parse_vorbis_comment_field(option_argument, &(op->argument.vc_field.field), &(op->argument.vc_field.field_name), &(op->argument.vc_field.field_value), &(op->argument.vc_field.field_value_length), &violation)) {
			FLAC__ASSERT(0 != violation);
			flac_fprintf(stderr, "ERROR (--%s): malformed vorbis comment field \"%s\",\n       %s\n", opt, option_argument, violation);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "import-tags-from")) {
		op = append_shorthand_operation(options, OP__IMPORT_VC_FROM);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_string(option_argument, &(op->argument.filename.value))) {
			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "export-tags-to")) {
		op = append_shorthand_operation(options, OP__EXPORT_VC_TO);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_string(option_argument, &(op->argument.filename.value))) {
			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "import-cuesheet-from")) {
		if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) {
			flac_fprintf(stderr, "ERROR (--%s): may be specified only once\n", opt);
			ok = false;
		}
		op = append_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_string(option_argument, &(op->argument.import_cuesheet_from.filename))) {
			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "export-cuesheet-to")) {
		op = append_shorthand_operation(options, OP__EXPORT_CUESHEET_TO);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_string(option_argument, &(op->argument.filename.value))) {
			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "import-picture-from")) {
		op = append_shorthand_operation(options, OP__IMPORT_PICTURE_FROM);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_string(option_argument, &(op->argument.specification.value))) {
			flac_fprintf(stderr, "ERROR (--%s): missing specification\n", opt);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "export-picture-to")) {
		arg = find_argument(options, ARG__BLOCK_NUMBER);
		op = append_shorthand_operation(options, OP__EXPORT_PICTURE_TO);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_string(option_argument, &(op->argument.export_picture_to.filename))) {
			flac_fprintf(stderr, "ERROR (--%s): missing filename\n", opt);
			ok = false;
		}
		op->argument.export_picture_to.block_number_link = arg? &(arg->value.block_number) : 0;
	}
	else if(0 == strcmp(opt, "add-seekpoint")) {
		const char *violation;
		char *spec;
		FLAC__ASSERT(0 != option_argument);
		if(!parse_add_seekpoint(option_argument, &spec, &violation)) {
			FLAC__ASSERT(0 != violation);
			flac_fprintf(stderr, "ERROR (--%s): malformed seekpoint specification \"%s\",\n       %s\n", opt, option_argument, violation);
			ok = false;
		}
		else {
			op = find_shorthand_operation(options, OP__ADD_SEEKPOINT);
			if(0 == op)
				op = append_shorthand_operation(options, OP__ADD_SEEKPOINT);
			local_strcat(&(op->argument.add_seekpoint.specification), spec);
			local_strcat(&(op->argument.add_seekpoint.specification), ";");
			free(spec);
		}
	}
	else if(0 == strcmp(opt, "add-replay-gain")) {
		(void) append_shorthand_operation(options, OP__ADD_REPLAY_GAIN);
	}
	else if(0 == strcmp(opt, "remove-replay-gain")) {
		const FLAC__byte * const tags[5] = {
			GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS,
			GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN,
			GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK,
			GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN,
			GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK
		};
		size_t i;
		for(i = 0; i < sizeof(tags)/sizeof(tags[0]); i++) {
			op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD);
			op->argument.vc_field_name.value = local_strdup((const char *)tags[i]);
		}
	}
	else if(0 == strcmp(opt, "add-padding")) {
		op = append_shorthand_operation(options, OP__ADD_PADDING);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_add_padding(option_argument, &(op->argument.add_padding.length))) {
			flac_fprintf(stderr, "ERROR (--%s): illegal length \"%s\", length must be >= 0 and < 2^%u\n", opt, option_argument, FLAC__STREAM_METADATA_LENGTH_LEN);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "help")) {
		options->show_long_help = true;
	}
	else if(0 == strcmp(opt, "version")) {
		options->show_version = true;
	}
	else if(0 == strcmp(opt, "list")) {
		(void) append_major_operation(options, OP__LIST);
	}
	else if(0 == strcmp(opt, "append")) {
		(void) append_major_operation(options, OP__APPEND);
	}
	else if(0 == strcmp(opt, "remove")) {
		(void) append_major_operation(options, OP__REMOVE);
	}
	else if(0 == strcmp(opt, "remove-all")) {
		(void) append_major_operation(options, OP__REMOVE_ALL);
	}
	else if(0 == strcmp(opt, "merge-padding")) {
		(void) append_major_operation(options, OP__MERGE_PADDING);
	}
	else if(0 == strcmp(opt, "sort-padding")) {
		(void) append_major_operation(options, OP__SORT_PADDING);
	}
	else if(0 == strcmp(opt, "block-number")) {
		arg = append_argument(options, ARG__BLOCK_NUMBER);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_block_number(option_argument, &(arg->value.block_number))) {
			flac_fprintf(stderr, "ERROR: malformed block number specification \"%s\"\n", option_argument);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "block-type")) {
		arg = append_argument(options, ARG__BLOCK_TYPE);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_block_type(option_argument, &(arg->value.block_type))) {
			flac_fprintf(stderr, "ERROR (--%s): malformed block type specification \"%s\"\n", opt, option_argument);
			ok = false;
		}
		options->args.checks.has_block_type = true;
	}
	else if(0 == strcmp(opt, "except-block-type")) {
		arg = append_argument(options, ARG__EXCEPT_BLOCK_TYPE);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_block_type(option_argument, &(arg->value.block_type))) {
			flac_fprintf(stderr, "ERROR (--%s): malformed block type specification \"%s\"\n", opt, option_argument);
			ok = false;
		}
		options->args.checks.has_except_block_type = true;
	}
	else if(0 == strcmp(opt, "data-format")) {
		arg = append_argument(options, ARG__DATA_FORMAT);
		FLAC__ASSERT(0 != option_argument);
		if(!parse_data_format(option_argument, &(arg->value.data_format))) {
			flac_fprintf(stderr, "ERROR (--%s): illegal data format \"%s\"\n", opt, option_argument);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "application-data-format")) {
		FLAC__ASSERT(0 != option_argument);
		if(!parse_application_data_format(option_argument, &(options->application_data_format_is_hexdump))) {
			flac_fprintf(stderr, "ERROR (--%s): illegal application data format \"%s\"\n", opt, option_argument);
			ok = false;
		}
	}
	else if(0 == strcmp(opt, "from-file")) {
		arg = append_argument(options, ARG__FROM_FILE);
		FLAC__ASSERT(0 != option_argument);
		arg->value.from_file.file_name = local_strdup(option_argument);
	}
	else {
		FLAC__ASSERT(0);
	}

	return ok;
}