FLAC__bool export_pic_to(const char *filename, const FLAC__StreamMetadata *picture, const char *pic_filename)
{
	FILE *f;
	const FLAC__uint32 len = picture->data.picture.data_length;

	if(0 == pic_filename || strlen(pic_filename) == 0) {
		flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
		return false;
	}
	if(0 == strcmp(pic_filename, "-"))
		f = grabbag__file_get_binary_stdout();
	else
		f = flac_fopen(pic_filename, "wb");

	if(0 == f) {
		flac_fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, pic_filename, strerror(errno));
		return false;
	}

	if(fwrite(picture->data.picture.data, 1, len, f) != len) {
		flac_fprintf(stderr, "%s: ERROR: writing PICTURE data to file\n", filename);
		if(f != stdout)
			fclose(f);
		return false;
	}

	if(f != stdout)
		fclose(f);

	return true;
}
Esempio n. 2
0
FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
{
	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
	FLAC__StreamMetadata *block;
	FLAC__bool ok = true;
	unsigned block_number;

	if(0 == iterator)
		die("out of memory allocating iterator");

	FLAC__metadata_iterator_init(iterator, chain);

	block_number = 0;
	do {
		block = FLAC__metadata_iterator_get_block(iterator);
		ok &= (0 != block);
		if(!ok)
			flac_fprintf(stderr, "%s: ERROR: couldn't get block from chain\n", filename);
		else if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number))
			write_metadata(filename, block, block_number, !options->utf8_convert, options->application_data_format_is_hexdump);
		block_number++;
	} while(ok && FLAC__metadata_iterator_next(iterator));

	FLAC__metadata_iterator_delete(iterator);

	return ok;
}
Esempio n. 3
0
void print_error_with_chain_status(FLAC__Metadata_Chain *chain, const char *format, ...)
{
	const FLAC__Metadata_ChainStatus status = FLAC__metadata_chain_status(chain);
	va_list args;

	FLAC__ASSERT(0 != format);

	va_start(args, format);

	(void) flac_vfprintf(stderr, format, args);

	va_end(args);

	flac_fprintf(stderr, ", status = \"%s\"\n", FLAC__Metadata_ChainStatusString[status]);

	if(status == FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE) {
		flac_fprintf(stderr, "\n"
			"The FLAC file could not be opened.  Most likely the file does not exist\n"
			"or is not readable.\n"
		);
	}
	else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE) {
		flac_fprintf(stderr, "\n"
			"The file does not appear to be a FLAC file.\n"
		);
	}
	else if(status == FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE) {
		flac_fprintf(stderr, "\n"
			"The FLAC file does not have write permissions.\n"
		);
	}
	else if(status == FLAC__METADATA_CHAIN_STATUS_BAD_METADATA) {
		flac_fprintf(stderr, "\n"
			"The metadata to be written does not conform to the FLAC metadata\n"
			"specifications.\n"
		);
	}
	else if(status == FLAC__METADATA_CHAIN_STATUS_READ_ERROR) {
		flac_fprintf(stderr, "\n"
			"There was an error while reading the FLAC file.\n"
		);
	}
	else if(status == FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR) {
		flac_fprintf(stderr, "\n"
			"There was an error while writing FLAC file; most probably the disk is\n"
			"full.\n"
		);
	}
	else if(status == FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR) {
		flac_fprintf(stderr, "\n"
			"There was an error removing the temporary FLAC file.\n"
		);
	}
}
Esempio n. 4
0
int short_usage(const char *message, ...)
{
	va_list args;

	if(message) {
		va_start(args, message);

		(void) vfprintf(stderr, message, args);

		va_end(args);

	}
	usage_header(stderr);
	flac_fprintf(stderr, "\n");
	flac_fprintf(stderr, "This is the short help; for full help use 'metaflac --help'\n");
	flac_fprintf(stderr, "\n");
	usage_summary(stderr);

	return message? 1 : 0;
}
FLAC__bool export_cs_to(const char *filename, const FLAC__StreamMetadata *cuesheet, const char *cs_filename)
{
	FILE *f;
	char *ref = 0;
	size_t reflen;

	if(0 == cs_filename || strlen(cs_filename) == 0) {
		flac_fprintf(stderr, "%s: ERROR: empty export file name\n", filename);
		return false;
	}
	if(0 == strcmp(cs_filename, "-"))
		f = stdout;
	else
		f = flac_fopen(cs_filename, "w");

	if(0 == f) {
		flac_fprintf(stderr, "%s: ERROR: can't open export file %s: %s\n", filename, cs_filename, strerror(errno));
		return false;
	}

	reflen = strlen(filename) + 7 + 1;
	if(0 == (ref = malloc(reflen))) {
		flac_fprintf(stderr, "%s: ERROR: allocating memory\n", filename);
		if(f != stdout)
			fclose(f);
		return false;
	}

	flac_snprintf(ref, reflen, "\"%s\" FLAC", filename);

	grabbag__cuesheet_emit(f, cuesheet, ref);

	free(ref);

	if(f != stdout)
		fclose(f);

	return true;
}
Esempio n. 6
0
void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__bool raw, FILE *f)
{
	if(0 != entry->entry) {
		if(filename)
			flac_fprintf(f, "%s:", filename);

		if(!raw) {
			/*
			 * WATCHOUT: comments that contain an embedded null will
			 * be truncated by utf_decode().
			 */
#ifdef _WIN32 /* if we are outputting to console, we need to use proper print functions to show unicode characters */
			if (f == stdout || f == stderr) {
				flac_fprintf(f, "%s", entry->entry);
			} else {
#endif
			char *converted;

			if(utf8_decode((const char *)entry->entry, &converted) >= 0) {
				(void) local_fwrite(converted, 1, strlen(converted), f);
				free(converted);
			}
			else {
				(void) local_fwrite(entry->entry, 1, entry->length, f);
			}
#ifdef _WIN32
			}
#endif
		}
		else {
			(void) local_fwrite(entry->entry, 1, entry->length, f);
		}
	}

	putc('\n', f);
}
FLAC__bool import_pic_from(const char *filename, FLAC__StreamMetadata **picture, const char *specification, FLAC__bool *needs_write)
{
	const char *error_message;

	if(0 == specification || strlen(specification) == 0) {
		flac_fprintf(stderr, "%s: ERROR: empty picture specification\n", filename);
		return false;
	}

	*picture = grabbag__picture_parse_specification(specification, &error_message);

	if(0 == *picture) {
		flac_fprintf(stderr, "%s: ERROR: while parsing picture specification \"%s\": %s\n", filename, specification, error_message);
		return false;
	}

	if(!FLAC__format_picture_is_legal(&(*picture)->data.picture, &error_message)) {
		flac_fprintf(stderr, "%s: ERROR: new PICTURE block for \"%s\" is illegal: %s\n", filename, specification, error_message);
		return false;
	}

	*needs_write = true;
	return true;
}
Esempio n. 8
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;
}
Esempio n. 9
0
FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options)
{
	int ret;
	int option_index = 1;
	FLAC__bool had_error = false;

	while ((ret = share__getopt_long(argc, argv, "", long_options_, &option_index)) != -1) {
		switch (ret) {
			case 0:
				had_error |= !parse_option(option_index, share__optarg, options);
				break;
			case '?':
			case ':':
				had_error = true;
				break;
			default:
				FLAC__ASSERT(0);
				break;
		}
	}

	if(options->prefix_with_filename == 2)
		options->prefix_with_filename = (argc - share__optind > 1);

	if(share__optind >= argc && !options->show_long_help && !options->show_version) {
		flac_fprintf(stderr,"ERROR: you must specify at least one FLAC file;\n");
		flac_fprintf(stderr,"       metaflac cannot be used as a pipe\n");
		had_error = true;
	}

	options->num_files = argc - share__optind;

	if(options->num_files > 0) {
		unsigned i = 0;
		if(0 == (options->filenames = safe_malloc_mul_2op_(sizeof(char*), /*times*/options->num_files)))
			die("out of memory allocating space for file names list");
		while(share__optind < argc)
			options->filenames[i++] = local_strdup(argv[share__optind++]);
	}

	if(options->args.checks.num_major_ops > 0) {
		if(options->args.checks.num_major_ops > 1) {
			flac_fprintf(stderr, "ERROR: you may only specify one major operation at a time\n");
			had_error = true;
		}
		else if(options->args.checks.num_shorthand_ops > 0) {
			flac_fprintf(stderr, "ERROR: you may not mix shorthand and major operations\n");
			had_error = true;
		}
	}

	/* check for only one FLAC file used with certain options */
	if(options->num_files > 1) {
		if(0 != find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM)) {
			flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--import-cuesheet-from'\n");
			had_error = true;
		}
		if(0 != find_shorthand_operation(options, OP__EXPORT_CUESHEET_TO)) {
			flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--export-cuesheet-to'\n");
			had_error = true;
		}
		if(0 != find_shorthand_operation(options, OP__EXPORT_PICTURE_TO)) {
			flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--export-picture-to'\n");
			had_error = true;
		}
		if(
			0 != find_shorthand_operation(options, OP__IMPORT_VC_FROM) &&
			0 == strcmp(find_shorthand_operation(options, OP__IMPORT_VC_FROM)->argument.filename.value, "-")
		) {
			flac_fprintf(stderr, "ERROR: you may only specify one FLAC file when using '--import-tags-from=-'\n");
			had_error = true;
		}
	}

	if(options->args.checks.has_block_type && options->args.checks.has_except_block_type) {
		flac_fprintf(stderr, "ERROR: you may not specify both '--block-type' and '--except-block-type'\n");
		had_error = true;
	}

	if(had_error)
		short_usage(0);

	/*
	 * We need to create an OP__ADD_SEEKPOINT operation if there is
	 * not one already, and --import-cuesheet-from was specified but
	 * --no-cued-seekpoints was not:
	 */
	if(options->cued_seekpoints) {
		Operation *op = find_shorthand_operation(options, OP__IMPORT_CUESHEET_FROM);
		if(0 != op) {
			Operation *op2 = find_shorthand_operation(options, OP__ADD_SEEKPOINT);
			if(0 == op2)
				op2 = append_shorthand_operation(options, OP__ADD_SEEKPOINT);
			op->argument.import_cuesheet_from.add_seekpoint_link = &(op2->argument.add_seekpoint);
		}
	}

	return had_error;
}
Esempio n. 10
0
void die(const char *message)
{
	FLAC__ASSERT(0 != message);
	flac_fprintf(stderr, "ERROR: %s\n", message);
	exit(1);
}
FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write)
{
	FLAC__bool ok = true;
	FLAC__StreamMetadata *cuesheet = 0;
	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
	FLAC__uint64 lead_out_offset = 0;
	FLAC__bool is_cdda = false;
	unsigned sample_rate = 0;

	if(0 == iterator)
		die("out of memory allocating iterator");

	FLAC__metadata_iterator_init(iterator, chain);

	do {
		FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
		if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
			lead_out_offset = block->data.stream_info.total_samples;
			if(lead_out_offset == 0) {
				flac_fprintf(stderr, "%s: ERROR: FLAC file must have total_samples set in STREAMINFO in order to import/export cuesheet\n", filename);
				FLAC__metadata_iterator_delete(iterator);
				return false;
			}
			sample_rate = block->data.stream_info.sample_rate;
			is_cdda = (block->data.stream_info.channels == 1 || block->data.stream_info.channels == 2) && (block->data.stream_info.bits_per_sample == 16) && (sample_rate == 44100);
		}
		else if(block->type == FLAC__METADATA_TYPE_CUESHEET)
			cuesheet = block;
	} while(FLAC__metadata_iterator_next(iterator));

	if(lead_out_offset == 0) {
		flac_fprintf(stderr, "%s: ERROR: FLAC stream has no STREAMINFO block\n", filename);
		FLAC__metadata_iterator_delete(iterator);
		return false;
	}

	switch(operation->type) {
		case OP__IMPORT_CUESHEET_FROM:
			if(0 != cuesheet) {
				flac_fprintf(stderr, "%s: ERROR: FLAC file already has CUESHEET block\n", filename);
				ok = false;
			}
			else {
				ok = import_cs_from(filename, &cuesheet, operation->argument.import_cuesheet_from.filename, needs_write, lead_out_offset, sample_rate, is_cdda, operation->argument.import_cuesheet_from.add_seekpoint_link);
				if(ok) {
					/* append CUESHEET block */
					while(FLAC__metadata_iterator_next(iterator))
						;
					if(!FLAC__metadata_iterator_insert_block_after(iterator, cuesheet)) {
						print_error_with_chain_status(chain, "%s: ERROR: adding new CUESHEET block to metadata", filename);
						FLAC__metadata_object_delete(cuesheet);
						ok = false;
					}
				}
			}
			break;
		case OP__EXPORT_CUESHEET_TO:
			if(0 == cuesheet) {
				flac_fprintf(stderr, "%s: ERROR: FLAC file has no CUESHEET block\n", filename);
				ok = false;
			}
			else
				ok = export_cs_to(filename, cuesheet, operation->argument.filename.value);
			break;
		default:
			ok = false;
			FLAC__ASSERT(0);
			break;
	};

	FLAC__metadata_iterator_delete(iterator);
	return ok;
}
FLAC__bool import_cs_from(const char *filename, FLAC__StreamMetadata **cuesheet, const char *cs_filename, FLAC__bool *needs_write, FLAC__uint64 lead_out_offset, unsigned sample_rate, FLAC__bool is_cdda, Argument_AddSeekpoint *add_seekpoint_link)
{
	FILE *f;
	const char *error_message;
	char **seekpoint_specification = add_seekpoint_link? &(add_seekpoint_link->specification) : 0;
	unsigned last_line_read;

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

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

	*cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, sample_rate, is_cdda, lead_out_offset);

	if(f != stdin)
		fclose(f);

	if(0 == *cuesheet) {
		flac_fprintf(stderr, "%s: ERROR: while parsing cuesheet \"%s\" on line %u: %s\n", filename, cs_filename, last_line_read, error_message);
		return false;
	}

	if(!FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/false, &error_message)) {
		flac_fprintf(stderr, "%s: ERROR parsing cuesheet \"%s\": %s\n", filename, cs_filename, error_message);
		return false;
	}

	/* if we're expecting CDDA, warn about non-compliance */
	if(is_cdda && !FLAC__format_cuesheet_is_legal(&(*cuesheet)->data.cue_sheet, /*check_cd_da_subset=*/true, &error_message)) {
		flac_fprintf(stderr, "%s: WARNING cuesheet \"%s\" is not audio CD compliant: %s\n", filename, cs_filename, error_message);
		(*cuesheet)->data.cue_sheet.is_cd = false;
	}

	/* add seekpoints for each index point if required */
	if(0 != seekpoint_specification) {
		char spec[128];
		unsigned track, indx;
		const FLAC__StreamMetadata_CueSheet *cs = &(*cuesheet)->data.cue_sheet;
		if(0 == *seekpoint_specification)
			*seekpoint_specification = local_strdup("");
		for(track = 0; track < cs->num_tracks; track++) {
			const FLAC__StreamMetadata_CueSheet_Track *tr = cs->tracks+track;
			for(indx = 0; indx < tr->num_indices; indx++) {
				flac_snprintf(spec, sizeof (spec), "%" PRIu64 ";", (tr->offset + tr->indices[indx].offset));
				local_strcat(seekpoint_specification, spec);
			}
		}
	}

	*needs_write = true;
	return true;
}
FLAC__bool do_shorthand_operation__picture(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write)
{
	FLAC__bool ok = true, has_type1 = false, has_type2 = false;
	FLAC__StreamMetadata *picture = 0;
	FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();

	if(0 == iterator)
		die("out of memory allocating iterator");

	FLAC__metadata_iterator_init(iterator, chain);

	switch(operation->type) {
		case OP__IMPORT_PICTURE_FROM:
			ok = import_pic_from(filename, &picture, operation->argument.specification.value, needs_write);
			if(ok) {
				/* append PICTURE block */
				while(FLAC__metadata_iterator_next(iterator))
					;
				if(!FLAC__metadata_iterator_insert_block_after(iterator, picture)) {
					print_error_with_chain_status(chain, "%s: ERROR: adding new PICTURE block to metadata", filename);
					FLAC__metadata_object_delete(picture);
					ok = false;
				}
			}
			if(ok) {
				/* check global PICTURE constraints (max 1 block each of type=1 and type=2) */
				while(FLAC__metadata_iterator_prev(iterator))
					;
				do {
					FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
					if(block->type == FLAC__METADATA_TYPE_PICTURE) {
						if(block->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
							if(has_type1) {
								print_error_with_chain_status(chain, "%s: ERROR: FLAC stream can only have one 32x32 standard icon (type=1) PICTURE block", filename);
								ok = false;
							}
							has_type1 = true;
						}
						else if(block->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
							if(has_type2) {
								print_error_with_chain_status(chain, "%s: ERROR: FLAC stream can only have one icon (type=2) PICTURE block", filename);
								ok = false;
							}
							has_type2 = true;
						}
					}
				} while(FLAC__metadata_iterator_next(iterator));
			}
			break;
		case OP__EXPORT_PICTURE_TO:
			{
				const Argument_BlockNumber *a = operation->argument.export_picture_to.block_number_link;
				int block_number = (a && a->num_entries > 0)? (int)a->entries[0] : -1;
				unsigned i = 0;
				do {
					FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iterator);
					if(block->type == FLAC__METADATA_TYPE_PICTURE && (block_number < 0 || i == (unsigned)block_number))
						picture = block;
					i++;
				} while(FLAC__metadata_iterator_next(iterator) && 0 == picture);
				if(0 == picture) {
					if(block_number < 0)
						flac_fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block\n", filename);
					else
						flac_fprintf(stderr, "%s: ERROR: FLAC file has no PICTURE block at block #%d\n", filename, block_number);
					ok = false;
				}
				else
					ok = export_pic_to(filename, picture, operation->argument.filename.value);
			}
			break;
		default:
			ok = false;
			FLAC__ASSERT(0);
			break;
	};

	FLAC__metadata_iterator_delete(iterator);
	return ok;
}
Esempio n. 14
0
FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime, FLAC__bool scan)
{
	FLAC__StreamMetadata streaminfo;
	float *title_gains = 0, *title_peaks = 0;
	float album_gain, album_peak;
	unsigned sample_rate = 0;
	unsigned bits_per_sample = 0;
	unsigned channels = 0;
	unsigned i;
	const char *error;
	FLAC__bool first = true;

	FLAC__ASSERT(num_files > 0);

	for(i = 0; i < num_files; i++) {
		FLAC__ASSERT(0 != filenames[i]);
		if(!FLAC__metadata_get_streaminfo(filenames[i], &streaminfo)) {
			flac_fprintf(stderr, "%s: ERROR: can't open file or get STREAMINFO block\n", filenames[i]);
			return false;
		}
		if(first) {
			first = false;
			sample_rate = streaminfo.data.stream_info.sample_rate;
			bits_per_sample = streaminfo.data.stream_info.bits_per_sample;
			channels = streaminfo.data.stream_info.channels;
		}
		else {
			if(sample_rate != streaminfo.data.stream_info.sample_rate) {
				flac_fprintf(stderr, "%s: ERROR: sample rate of %u Hz does not match previous files' %u Hz\n", filenames[i], streaminfo.data.stream_info.sample_rate, sample_rate);
				return false;
			}
			if(bits_per_sample != streaminfo.data.stream_info.bits_per_sample) {
				flac_fprintf(stderr, "%s: ERROR: resolution of %u bps does not match previous files' %u bps\n", filenames[i], streaminfo.data.stream_info.bits_per_sample, bits_per_sample);
				return false;
			}
			if(channels != streaminfo.data.stream_info.channels) {
				flac_fprintf(stderr, "%s: ERROR: # channels (%u) does not match previous files' (%u)\n", filenames[i], streaminfo.data.stream_info.channels, channels);
				return false;
			}
		}
		if(!grabbag__replaygain_is_valid_sample_frequency(sample_rate)) {
			flac_fprintf(stderr, "%s: ERROR: sample rate of %u Hz is not supported\n", filenames[i], sample_rate);
			return false;
		}
		if(channels != 1 && channels != 2) {
			flac_fprintf(stderr, "%s: ERROR: # of channels (%u) is not supported, must be 1 or 2\n", filenames[i], channels);
			return false;
		}
	}
	FLAC__ASSERT(bits_per_sample >= FLAC__MIN_BITS_PER_SAMPLE && bits_per_sample <= FLAC__MAX_BITS_PER_SAMPLE);

	if(!grabbag__replaygain_init(sample_rate)) {
		FLAC__ASSERT(0);
		/* double protection */
		flac_fprintf(stderr, "internal error\n");
		return false;
	}

	if(
		0 == (title_gains = safe_malloc_mul_2op_(sizeof(float), /*times*/num_files)) ||
		0 == (title_peaks = safe_malloc_mul_2op_(sizeof(float), /*times*/num_files))
	)
		die("out of memory allocating space for title gains/peaks");

	for(i = 0; i < num_files; i++) {
		if(0 != (error = grabbag__replaygain_analyze_file(filenames[i], title_gains+i, title_peaks+i))) {
			flac_fprintf(stderr, "%s: ERROR: during analysis (%s)\n", filenames[i], error);
			free(title_gains);
			free(title_peaks);
			return false;
		}
	}
	grabbag__replaygain_get_album(&album_gain, &album_peak);

	for(i = 0; i < num_files; i++) {
		if(!scan) {
			if(0 != (error = grabbag__replaygain_store_to_file(filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i], preserve_modtime))) {
				flac_fprintf(stderr, "%s: ERROR: writing tags (%s)\n", filenames[i], error);
				free(title_gains);
				free(title_peaks);
				return false;
			}
		} else {
			flac_fprintf(stdout, "%s: %f %f %f %f\n", filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i]);
		}
	}

	free(title_gains);
	free(title_peaks);
	return true;
}
Esempio n. 15
0
FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
{
	(void) chain, (void) options;
	flac_fprintf(stderr, "ERROR: --append not implemented yet\n");
	return false;
}
Esempio n. 16
0
int main(int argc, char *argv[])
{
	FILE *f;
	char buf[36];
	foreign_metadata_t *fm;
	const char *fn, *error;
	size_t i;
	FLAC__uint32 size;

#ifdef _WIN32
	if (get_utf8_argv(&argc, &argv) != 0) {
		fprintf(stderr, "ERROR: failed to convert command line parameters to UTF-8\n");
		return 1;
	}
#endif

	if(argc != 2) {
		flac_fprintf(stderr, "usage: %s { file.wav | file.aif }\n", argv[0]);
		return 1;
	}
	fn = argv[1];
	if(0 == (f = flac_fopen(fn, "rb")) || fread(buf, 1, 4, f) != 4) {
		flac_fprintf(stderr, "ERROR opening %s for reading\n", fn);
		return 1;
	}
	fclose(f);
	if(0 == (fm = flac__foreign_metadata_new(memcmp(buf, "RIFF", 4) && memcmp(buf, "RF64", 4)? FOREIGN_BLOCK_TYPE__AIFF : FOREIGN_BLOCK_TYPE__RIFF))) {
		flac_fprintf(stderr, "ERROR: out of memory\n");
		return 1;
	}
	if(fm->type == FOREIGN_BLOCK_TYPE__AIFF) {
		if(!flac__foreign_metadata_read_from_aiff(fm, fn, &error)) {
			flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error);
			return 1;
		}
	}
	else {
		if(!flac__foreign_metadata_read_from_wave(fm, fn, &error)) {
			flac_fprintf(stderr, "ERROR reading chunks from %s: %s\n", fn, error);
			return 1;
		}
	}
	if(0 == (f = flac_fopen(fn, "rb"))) {
		flac_fprintf(stderr, "ERROR opening %s for reading\n", fn);
		return 1;
	}
	for(i = 0; i < fm->num_blocks; i++) {
		if(fseeko(f, fm->blocks[i].offset, SEEK_SET) < 0) {
			flac_fprintf(stderr, "ERROR seeking in %s\n", fn);
			return 1;
		}
		if(fread(buf, 1, i==0?12:8, f) != (i==0?12:8)) {
			flac_fprintf(stderr, "ERROR reading %s\n", fn);
			return 1;
		}
		size = unpack32_((FLAC__byte*)buf+4, fm->type);
		printf("block:[%c%c%c%c] size=%08x=(%10u)", buf[0], buf[1], buf[2], buf[3], size, size);
		if(i == 0)
			printf(" type:[%c%c%c%c]", buf[8], buf[9], buf[10], buf[11]);
		else if(fm->type == FOREIGN_BLOCK_TYPE__AIFF && i == fm->audio_block)
			printf(" offset size=%08x=(%10u)", fm->ssnd_offset_size, fm->ssnd_offset_size);
		else if(fm->type == FOREIGN_BLOCK_TYPE__RIFF && i == 1 && !memcmp(buf, "ds64", 4)) {
			if(fread(buf+8, 1, 36-8, f) != 36-8) {
				flac_fprintf(stderr, "ERROR reading %s\n", fn);
				return 1;
			}
			printf("\n    RIFF size=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+8), unpack64le_((FLAC__byte*)buf+8));
			printf("\n    data size=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+16), unpack64le_((FLAC__byte*)buf+16));
			printf("\n    sample count=%016" PRIx64 "=(%20" PRIu64 ")", unpack64le_((FLAC__byte*)buf+24), unpack64le_((FLAC__byte*)buf+24));
			printf("\n    table size=%08x=(%10u)", unpack32le_((FLAC__byte*)buf+32), unpack32le_((FLAC__byte*)buf+32));
		}
		printf("\n");
	}
	fclose(f);
	flac__foreign_metadata_delete(fm);
	return 0;
}