1 /* metaflac - Command-line FLAC metadata editor
2 * Copyright (C) 2001,2002 Josh Coalson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 more powerful operations yet to add:
21 add a seektable, using same args as flac
28 #include "FLAC/assert.h"
29 #include "FLAC/metadata.h"
39 # include "share/getopt.h"
43 getopt format struct; note we don't use short options so we just
44 set the 'val' field to 0 everywhere to indicate a valid option.
46 static struct option long_options_[] = {
48 { "preserve-modtime", 0, 0, 0 },
49 { "with-filename", 0, 0, 0 },
50 { "no-filename", 0, 0, 0 },
51 { "dont-use-padding", 0, 0, 0 },
52 /* shorthand operations */
53 { "show-md5sum", 0, 0, 0 },
54 { "show-min-blocksize", 0, 0, 0 },
55 { "show-max-blocksize", 0, 0, 0 },
56 { "show-min-framesize", 0, 0, 0 },
57 { "show-max-framesize", 0, 0, 0 },
58 { "show-sample-rate", 0, 0, 0 },
59 { "show-channels", 0, 0, 0 },
60 { "show-bps", 0, 0, 0 },
61 { "show-total-samples", 0, 0, 0 },
62 { "show-vc-vendor", 0, 0, 0 },
63 { "show-vc-field", 1, 0, 0 },
64 { "remove-vc-all", 0, 0, 0 },
65 { "remove-vc-field", 1, 0, 0 },
66 { "remove-vc-firstfield", 1, 0, 0 },
67 { "set-vc-field", 1, 0, 0 },
68 /* major operations */
71 { "append", 0, 0, 0 },
72 { "remove", 0, 0, 0 },
73 { "remove-all", 0, 0, 0 },
74 { "merge-padding", 0, 0, 0 },
75 { "sort-padding", 0, 0, 0 },
76 { "block-number", 1, 0, 0 },
77 { "block-type", 1, 0, 0 },
78 { "except-block-type", 1, 0, 0 },
79 { "data-format", 1, 0, 0 },
80 { "application-data-format", 1, 0, 0 },
81 { "from-file", 1, 0, 0 },
87 OP__SHOW_MIN_BLOCKSIZE,
88 OP__SHOW_MAX_BLOCKSIZE,
89 OP__SHOW_MIN_FRAMESIZE,
90 OP__SHOW_MAX_FRAMESIZE,
94 OP__SHOW_TOTAL_SAMPLES,
99 OP__REMOVE_VC_FIRSTFIELD,
110 OP__EXCEPT_BLOCK_TYPE,
112 OP__APPLICATION_DATA_FORMAT,
118 } Argument_VcFieldName;
122 /* according to the vorbis spec, field values can contain \0 so simple C strings are not enough here */
123 unsigned field_value_length;
128 unsigned num_entries;
130 } Argument_BlockNumber;
134 } Argument_BlockType;
137 FLAC__bool is_binary;
138 } Argument_DataFormat;
141 FLAC__bool is_hexdump;
142 } Argument_ApplicationDataFormat;
151 Argument_VcFieldName show_vc_field;
152 Argument_VcFieldName remove_vc_field;
153 Argument_VcFieldName remove_vc_firstfield;
154 Argument_VcField set_vc_field;
155 Argument_BlockNumber block_number;
156 Argument_BlockType block_type;
157 Argument_BlockType except_block_type;
158 Argument_DataFormat data_format;
159 Argument_ApplicationDataFormat application_data_format;
160 Argument_FromFile from_file;
165 FLAC__bool preserve_modtime;
166 FLAC__bool prefix_with_filename;
167 FLAC__bool use_padding;
169 unsigned num_shorthand_ops;
170 unsigned num_major_ops;
171 FLAC__bool has_block_type;
172 FLAC__bool has_except_block_type;
175 Operation *operations;
176 unsigned num_operations;
179 } CommandLineOptions;
181 static void init_options(CommandLineOptions *options);
182 static FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options);
183 static FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options);
184 static void free_options(CommandLineOptions *options);
185 static void append_operation(CommandLineOptions *options, Operation operation);
186 static Operation *append_major_operation(CommandLineOptions *options, OperationType type);
187 static Operation *append_shorthand_operation(CommandLineOptions *options, OperationType type);
188 static int short_usage(const char *message, ...);
189 static int long_usage(const char *message, ...);
190 static void hexdump(const FLAC__byte *buf, unsigned bytes, const char *indent);
191 static char *local_strdup(const char *source);
192 static FLAC__bool parse_vorbis_comment_field(const char *field, char **name, char **value, unsigned *length);
193 static FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out);
194 static FLAC__bool parse_block_type(const char *in, Argument_BlockType *out);
195 static FLAC__bool parse_data_format(const char *in, Argument_DataFormat *out);
196 static FLAC__bool parse_application_data_format(const char *in, Argument_ApplicationDataFormat *out);
198 int main(int argc, char *argv[])
200 CommandLineOptions options;
203 init_options(&options);
205 ret = !parse_options(argc, argv, &options);
207 free_options(&options);
212 void init_options(CommandLineOptions *options)
214 options->preserve_modtime = false;
216 /* hack to mean "use default if not forced on command line" */
217 FLAC__ASSERT(true != 2);
218 options->prefix_with_filename = 2;
220 options->use_padding = true;
221 options->checks.num_shorthand_ops = 0;
222 options->checks.num_major_ops = 0;
223 options->checks.has_block_type = false;
224 options->checks.has_except_block_type = false;
226 options->ops.operations = 0;
227 options->ops.num_operations = 0;
228 options->ops.capacity = 0;
231 FLAC__bool parse_options(int argc, char *argv[], CommandLineOptions *options)
234 int option_index = 1;
235 FLAC__bool had_error = false;
237 while ((ret = getopt_long(argc, argv, "", long_options_, &option_index)) != -1) {
240 had_error |= !parse_option(option_index, optarg, options);
252 if(options->prefix_with_filename == 2)
253 options->prefix_with_filename = (argc - optind > 1);
257 printf("%s ", argv[optind++]);
264 FLAC__bool parse_option(int option_index, const char *option_argument, CommandLineOptions *options)
266 const char *opt = long_options_[option_index].name;
268 FLAC__bool ret = true;
270 if(0 == strcmp(opt, "preserve-modtime")) {
271 options->preserve_modtime = true;
273 else if(0 == strcmp(opt, "with-filename")) {
274 options->prefix_with_filename = true;
276 else if(0 == strcmp(opt, "no-filename")) {
277 options->prefix_with_filename = false;
279 else if(0 == strcmp(opt, "dont-use-padding")) {
280 options->use_padding = false;
282 else if(0 == strcmp(opt, "show-md5sum")) {
283 (void) append_shorthand_operation(options, OP__SHOW_MD5SUM);
285 else if(0 == strcmp(opt, "show-min-blocksize")) {
286 (void) append_shorthand_operation(options, OP__SHOW_MIN_BLOCKSIZE);
288 else if(0 == strcmp(opt, "show-max-blocksize")) {
289 (void) append_shorthand_operation(options, OP__SHOW_MAX_BLOCKSIZE);
291 else if(0 == strcmp(opt, "show-min-framesize")) {
292 (void) append_shorthand_operation(options, OP__SHOW_MIN_FRAMESIZE);
294 else if(0 == strcmp(opt, "show-max-framesize")) {
295 (void) append_shorthand_operation(options, OP__SHOW_MAX_FRAMESIZE);
297 else if(0 == strcmp(opt, "show-sample-rate")) {
298 (void) append_shorthand_operation(options, OP__SHOW_SAMPLE_RATE);
300 else if(0 == strcmp(opt, "show-channels")) {
301 (void) append_shorthand_operation(options, OP__SHOW_CHANNELS);
303 else if(0 == strcmp(opt, "show-bps")) {
304 (void) append_shorthand_operation(options, OP__SHOW_BPS);
306 else if(0 == strcmp(opt, "show-total-samples")) {
307 (void) append_shorthand_operation(options, OP__SHOW_TOTAL_SAMPLES);
309 else if(0 == strcmp(opt, "show-vc-vendor")) {
310 (void) append_shorthand_operation(options, OP__SHOW_VC_VENDOR);
312 else if(0 == strcmp(opt, "show-vc-field")) {
313 op = append_shorthand_operation(options, OP__SHOW_VC_FIELD);
314 FLAC__ASSERT(0 != option_argument);
315 op->argument.show_vc_field.field_name = local_strdup(option_argument);
317 else if(0 == strcmp(opt, "remove-vc-all")) {
318 (void) append_shorthand_operation(options, OP__REMOVE_VC_ALL);
320 else if(0 == strcmp(opt, "remove-vc-field")) {
321 op = append_shorthand_operation(options, OP__REMOVE_VC_FIELD);
322 FLAC__ASSERT(0 != option_argument);
323 op->argument.remove_vc_field.field_name = local_strdup(option_argument);
325 else if(0 == strcmp(opt, "remove-vc-firstfield")) {
326 op = append_shorthand_operation(options, OP__REMOVE_VC_FIRSTFIELD);
327 FLAC__ASSERT(0 != option_argument);
328 op->argument.remove_vc_firstfield.field_name = local_strdup(option_argument);
330 else if(0 == strcmp(opt, "set-vc-field")) {
331 op = append_shorthand_operation(options, OP__SET_VC_FIELD);
332 FLAC__ASSERT(0 != option_argument);
333 if(!parse_vorbis_comment_field(option_argument, &(op->argument.set_vc_field.field_name), &(op->argument.set_vc_field.field_value), &(op->argument.set_vc_field.field_value_length))) {
334 fprintf(stderr, "ERROR: malformed vorbis comment field \"%s\"\n", option_argument);
338 else if(0 == strcmp(opt, "help")) {
339 (void) append_major_operation(options, OP__HELP);
341 else if(0 == strcmp(opt, "list")) {
342 (void) append_major_operation(options, OP__LIST);
344 else if(0 == strcmp(opt, "append")) {
345 (void) append_major_operation(options, OP__APPEND);
347 else if(0 == strcmp(opt, "remove")) {
348 (void) append_major_operation(options, OP__REMOVE);
350 else if(0 == strcmp(opt, "remove-all")) {
351 (void) append_major_operation(options, OP__REMOVE_ALL);
353 else if(0 == strcmp(opt, "merge-padding")) {
354 (void) append_major_operation(options, OP__MERGE_PADDING);
356 else if(0 == strcmp(opt, "sort-padding")) {
357 (void) append_major_operation(options, OP__SORT_PADDING);
359 else if(0 == strcmp(opt, "block-number")) {
360 op = append_major_operation(options, OP__BLOCK_NUMBER);
361 FLAC__ASSERT(0 != option_argument);
362 if(!parse_block_number(option_argument, &(op->argument.block_number))) {
363 fprintf(stderr, "ERROR: malformed block number specification \"%s\"\n", option_argument);
367 else if(0 == strcmp(opt, "block-type")) {
368 op = append_major_operation(options, OP__BLOCK_TYPE);
369 FLAC__ASSERT(0 != option_argument);
370 if(!parse_block_type(option_argument, &(op->argument.block_type))) {
371 fprintf(stderr, "ERROR: malformed block type specification \"%s\"\n", option_argument);
375 else if(0 == strcmp(opt, "except-block-type")) {
376 op = append_major_operation(options, OP__EXCEPT_BLOCK_TYPE);
377 FLAC__ASSERT(0 != option_argument);
378 if(!parse_block_type(option_argument, &(op->argument.except_block_type))) {
379 fprintf(stderr, "ERROR: malformed block type specification \"%s\"\n", option_argument);
383 else if(0 == strcmp(opt, "data-format")) {
384 op = append_major_operation(options, OP__DATA_FORMAT);
385 FLAC__ASSERT(0 != option_argument);
386 if(!parse_data_format(option_argument, &(op->argument.data_format))) {
387 fprintf(stderr, "ERROR: illegal data format \"%s\"\n", option_argument);
391 else if(0 == strcmp(opt, "application-data-format")) {
392 op = append_major_operation(options, OP__APPLICATION_DATA_FORMAT);
393 FLAC__ASSERT(0 != option_argument);
394 if(!parse_application_data_format(option_argument, &(op->argument.application_data_format))) {
395 fprintf(stderr, "ERROR: illegal application data format \"%s\"\n", option_argument);
399 else if(0 == strcmp(opt, "from-file")) {
400 op = append_major_operation(options, OP__FROM_FILE);
401 FLAC__ASSERT(0 != option_argument);
402 op->argument.from_file.file_name = local_strdup(option_argument);
411 void free_options(CommandLineOptions *options)
416 FLAC__ASSERT(0 == options->ops.operations || options->ops.num_operations > 0);
418 for(i = 0; i < options->ops.num_operations; i++) {
419 op = options->ops.operations + i;
421 case OP__SHOW_VC_FIELD:
422 case OP__REMOVE_VC_FIELD:
423 case OP__REMOVE_VC_FIRSTFIELD:
424 FLAC__ASSERT(0 != op->argument.show_vc_field.field_name);
425 free(op->argument.show_vc_field.field_name);
427 case OP__SET_VC_FIELD:
428 FLAC__ASSERT(0 != op->argument.set_vc_field.field_name);
429 free(op->argument.set_vc_field.field_name);
430 if(0 != op->argument.set_vc_field.field_value)
431 free(op->argument.set_vc_field.field_value);
433 case OP__BLOCK_NUMBER:
437 case OP__EXCEPT_BLOCK_TYPE:
441 FLAC__ASSERT(0 != op->argument.from_file.file_name);
442 free(op->argument.from_file.file_name);
449 if(0 != options->ops.operations)
450 free(options->ops.operations);
453 void append_operation(CommandLineOptions *options, Operation operation)
455 if(options->ops.capacity == 0) {
456 options->ops.capacity = 50;
457 if(0 == (options->ops.operations = malloc(sizeof(Operation) * options->ops.capacity))) {
458 fprintf(stderr, "ERROR: out of memory allocating space for option list\n");
461 memset(options->ops.operations, 0, sizeof(Operation) * options->ops.capacity);
463 if(options->ops.capacity <= options->ops.num_operations) {
464 unsigned original_capacity = options->ops.capacity;
465 options->ops.capacity *= 4;
466 if(0 == (options->ops.operations = realloc(options->ops.operations, sizeof(Operation) * options->ops.capacity))) {
467 fprintf(stderr, "ERROR: out of memory allocating space for option list\n");
470 memset(options->ops.operations + original_capacity, 0, sizeof(Operation) * (options->ops.capacity - original_capacity));
473 options->ops.operations[options->ops.num_operations++] = operation;
476 Operation *append_major_operation(CommandLineOptions *options, OperationType type)
480 append_operation(options, op);
481 options->checks.num_major_ops++;
482 return options->ops.operations + (options->ops.num_operations - 1);
485 Operation *append_shorthand_operation(CommandLineOptions *options, OperationType type)
489 append_operation(options, op);
490 options->checks.num_shorthand_ops++;
491 return options->ops.operations + (options->ops.num_operations - 1);
494 static void usage_header(FILE *out)
496 fprintf(out, "==============================================================================\n");
497 fprintf(out, "metaflac - Command-line FLAC metadata editor version %s\n", FLAC__VERSION_STRING);
498 fprintf(out, "Copyright (C) 2001,2002 Josh Coalson\n");
500 fprintf(out, "This program is free software; you can redistribute it and/or\n");
501 fprintf(out, "modify it under the terms of the GNU General Public License\n");
502 fprintf(out, "as published by the Free Software Foundation; either version 2\n");
503 fprintf(out, "of the License, or (at your option) any later version.\n");
505 fprintf(out, "This program is distributed in the hope that it will be useful,\n");
506 fprintf(out, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
507 fprintf(out, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
508 fprintf(out, "GNU General Public License for more details.\n");
510 fprintf(out, "You should have received a copy of the GNU General Public License\n");
511 fprintf(out, "along with this program; if not, write to the Free Software\n");
512 fprintf(out, "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n");
513 fprintf(out, "==============================================================================\n");
516 static void usage_summary(FILE *out)
518 fprintf(out, "Usage:\n");
519 fprintf(out, " metaflac [options] [operations] FLACfile [FLACfile ...]\n");
521 fprintf(out, "Use metaflac to list, add, remove, or edit metadata in one or more FLAC files.\n");
522 fprintf(out, "You may perform one major operation, or many shorthand operations at a time.\n");
524 fprintf(out, "Options:\n");
525 fprintf(out, "--preserve-modtime Preserve the original modification time in spite of edits\n");
526 fprintf(out, "--with-filename Prefix each output line with the FLAC file name\n");
527 fprintf(out, " (the default if more than one FLAC file is specified)\n");
528 fprintf(out, "--no-filename Do not prefix each output line with the FLAC file name\n");
529 fprintf(out, " (the default if only one FLAC file is specified)\n");
530 fprintf(out, "--dont-use-padding By default metaflac tries to use padding where possible\n");
531 fprintf(out, " to avoid rewriting the entire file if the metadata size\n");
532 fprintf(out, " changes. Use this option to tell metaflac to not use\n");
533 fprintf(out, " padding at all.\n");
536 int short_usage(const char *message, ...)
541 va_start(args, message);
543 (void) vfprintf(stderr, message, args);
548 usage_header(stderr);
549 fprintf(stderr, "\n");
550 fprintf(stderr, "This is the short help; for full help use 'metaflac --help'\n");
551 fprintf(stderr, "\n");
552 usage_summary(stderr);
554 return message? 1 : 0;
557 int long_usage(const char *message, ...)
559 FILE *out = (message? stderr : stdout);
563 va_start(args, message);
565 (void) vfprintf(stderr, message, args);
574 fprintf(out, "Shorthand operations:\n");
575 fprintf(out, "--show-md5sum Show the MD5 signature from the STREAMINFO block.\n");
576 fprintf(out, "--show-min-blocksize Show the minimum block size from the STREAMINFO block.\n");
577 fprintf(out, "--show-max-blocksize Show the maximum block size from the STREAMINFO block.\n");
578 fprintf(out, "--show-min-framesize Show the minimum frame size from the STREAMINFO block.\n");
579 fprintf(out, "--show-max-framesize Show the maximum frame size from the STREAMINFO block.\n");
580 fprintf(out, "--show-sample-rate Show the sample rate from the STREAMINFO block.\n");
581 fprintf(out, "--show-channels Show the number of channels from the STREAMINFO block.\n");
582 fprintf(out, "--show-bps Show the # of bits per sample from the STREAMINFO block.\n");
583 fprintf(out, "--show-total-samples Show the total # of samples from the STREAMINFO block.\n");
585 fprintf(out, "--show-vc-vendor Show the vendor string from the VORBIS_COMMENT block.\n");
586 fprintf(out, "--show-vc-field=name Show all Vorbis comment fields where the the field name\n");
587 fprintf(out, " matches 'name'.\n");
588 fprintf(out, "--remove-vc-field=name\n");
589 fprintf(out, " Remove all Vorbis comment fields whose field name is\n");
590 fprintf(out, " 'name'.\n");
591 fprintf(out, "--remove-vc-firstfield=name\n");
592 fprintf(out, " Remove first Vorbis comment field whose field name is\n");
593 fprintf(out, " 'name'.\n");
594 fprintf(out, "--remove-vc-all Remove all Vorbis comment fields, leaving only the\n");
595 fprintf(out, " vendor string in the VORBIS_COMMENT block.\n");
596 fprintf(out, "--set-vc-field=field Add a Vorbis comment field. The field must comply with\n");
597 fprintf(out, " the Vorbis comment spec, of the form \"NAME=VALUE\". If\n");
598 fprintf(out, " there is currently no VORBIS_COMMENT block, one will be\n");
599 fprintf(out, " created.\n");
601 fprintf(out, "Major operations:\n");
602 fprintf(out, "--list : List the contents of one or more metadata blocks to stdout. By\n");
603 fprintf(out, " default, all metadata blocks are listed in text format. Use the\n");
604 fprintf(out, " following options to change this behavior:\n");
606 fprintf(out, " --block-number=#[,#[...]]\n");
607 fprintf(out, " An optional comma-separated list of block numbers to display. The first\n");
608 fprintf(out, " block, the STREAMINFO block, is block 0.\n");
610 fprintf(out, " --block-type=type[,type[...]]\n");
611 fprintf(out, " --except-block-type=type[,type[...]]\n");
612 fprintf(out, " An optional comma-separated list of block types to included or ignored\n");
613 fprintf(out, " with this option. Use only one of --block-type or --except-block-type.\n");
614 fprintf(out, " The valid block types are: STREAMINFO, PADDING, APPLICATION, SEEKTABLE,\n");
615 fprintf(out, " VORBIS_COMMENT. You may narrow down the types of APPLICATION blocks\n");
616 fprintf(out, " displayed as follows:\n");
617 fprintf(out, " APPLICATION:abcd The APPLICATION block(s) whose textual repre-\n");
618 fprintf(out, " sentation of the 4-byte ID is \"abcd\"\n");
619 fprintf(out, " APPLICATION:0xXXXXXXXX The APPLICATION block(s) whose hexadecimal big-\n");
620 fprintf(out, " endian representation of the 4-byte ID is\n");
621 fprintf(out, " \"0xXXXXXXXX\". For the example \"abcd\" above the\n");
622 fprintf(out, " hexadecimal equivalalent is 0x61626364\n");
624 fprintf(out, " NOTE: if both --block-number and --[except-]block-type are specified,\n");
625 fprintf(out, " the result is the logical AND of both arguments.\n");
628 /*@@@ not implemented yet */
629 fprintf(out, " --data-format=binary|text\n");
630 fprintf(out, " By default a human-readable text representation of the data is displayed.\n");
631 fprintf(out, " You may specify --data-format=binary to dump the raw binary form of each\n");
632 fprintf(out, " metadata block. The output can be read in using a subsequent call to\n");
633 fprintf(out, " "metaflac --append --from-file=..."\n");
636 fprintf(out, " --application-data-format=hexdump|text\n");
637 fprintf(out, " If the application block you are displaying contains binary data but your\n");
638 fprintf(out, " --data-format=text, you can display a hex dump of the application data\n");
639 fprintf(out, " contents instead using --application-data-format=hexdump\n");
642 /*@@@ not implemented yet */
643 fprintf(out, "--append : Insert a metadata block from a file. The input file must be in the\n");
644 fprintf(out, " same format as generated with --list.\n");
646 fprintf(out, " --block-number=#\n");
647 fprintf(out, " Specify the insertion point (defaults to last block). The new block will\n");
648 fprintf(out, " be added after the given block number. This prevents the illegal insertion\n");
649 fprintf(out, " of a block before the first STREAMINFO block. You may not --append another\n");
650 fprintf(out, " STREAMINFO block.\n");
652 fprintf(out, " --from-file=filename\n");
653 fprintf(out, " Mandatory 'option' to specify the input file containing the block contents.\n");
655 fprintf(out, " --data-format=binary|text\n");
656 fprintf(out, " By default the block contents are assumed to be in binary format. You can\n");
657 fprintf(out, " override this by specifying --data-format=text\n");
660 fprintf(out, "--remove : Remove one or more metadata blocks from the metadata. Unless\n");
661 fprintf(out, " --dont-use-padding is specified, the blocks will be replaced with\n");
662 fprintf(out, " padding. You may not remove the STREAMINFO block.\n");
664 fprintf(out, " --block-number=#[,#[...]]\n");
665 fprintf(out, " --block-type=type[,type[...]]\n");
666 fprintf(out, " --except-block-type=type[,type[...]]\n");
667 fprintf(out, " See --list above for usage.\n");
669 fprintf(out, " NOTE: if both --block-number and --[except-]block-type are specified,\n");
670 fprintf(out, " the result is the logical AND of both arguments.\n");
672 fprintf(out, "--remove-all : Remove all metadata blocks (except the STREAMINFO block) from\n");
673 fprintf(out, " the metadata. Unless --dont-use-padding is specified, the\n");
674 fprintf(out, " blocks will be replaced with padding.\n");
676 fprintf(out, "--merge-padding : Merge adjacent PADDING blocks into single blocks.\n");
678 fprintf(out, "--sort-padding : Move all PADDING blocks to the end of the metadata and merge\n");
679 fprintf(out, " them into a single block.\n");
681 return message? 1 : 0;
684 void hexdump(const FLAC__byte *buf, unsigned bytes, const char *indent)
686 unsigned i, left = bytes;
687 const FLAC__byte *b = buf;
689 for(i = 0; i < bytes; i += 16) {
691 "%02X %02X %02X %02X %02X %02X %02X %02X "
692 "%02X %02X %02X %02X %02X %02X %02X %02X "
693 "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
695 left > 0? (unsigned char)b[ 0] : 0,
696 left > 1? (unsigned char)b[ 1] : 0,
697 left > 2? (unsigned char)b[ 2] : 0,
698 left > 3? (unsigned char)b[ 3] : 0,
699 left > 4? (unsigned char)b[ 4] : 0,
700 left > 5? (unsigned char)b[ 5] : 0,
701 left > 6? (unsigned char)b[ 6] : 0,
702 left > 7? (unsigned char)b[ 7] : 0,
703 left > 8? (unsigned char)b[ 8] : 0,
704 left > 9? (unsigned char)b[ 9] : 0,
705 left > 10? (unsigned char)b[10] : 0,
706 left > 11? (unsigned char)b[11] : 0,
707 left > 12? (unsigned char)b[12] : 0,
708 left > 13? (unsigned char)b[13] : 0,
709 left > 14? (unsigned char)b[14] : 0,
710 left > 15? (unsigned char)b[15] : 0,
711 (left > 0) ? (isprint(b[ 0]) ? b[ 0] : '.') : ' ',
712 (left > 1) ? (isprint(b[ 1]) ? b[ 1] : '.') : ' ',
713 (left > 2) ? (isprint(b[ 2]) ? b[ 2] : '.') : ' ',
714 (left > 3) ? (isprint(b[ 3]) ? b[ 3] : '.') : ' ',
715 (left > 4) ? (isprint(b[ 4]) ? b[ 4] : '.') : ' ',
716 (left > 5) ? (isprint(b[ 5]) ? b[ 5] : '.') : ' ',
717 (left > 6) ? (isprint(b[ 6]) ? b[ 6] : '.') : ' ',
718 (left > 7) ? (isprint(b[ 7]) ? b[ 7] : '.') : ' ',
719 (left > 8) ? (isprint(b[ 8]) ? b[ 8] : '.') : ' ',
720 (left > 9) ? (isprint(b[ 9]) ? b[ 9] : '.') : ' ',
721 (left > 10) ? (isprint(b[10]) ? b[10] : '.') : ' ',
722 (left > 11) ? (isprint(b[11]) ? b[11] : '.') : ' ',
723 (left > 12) ? (isprint(b[12]) ? b[12] : '.') : ' ',
724 (left > 13) ? (isprint(b[13]) ? b[13] : '.') : ' ',
725 (left > 14) ? (isprint(b[14]) ? b[14] : '.') : ' ',
726 (left > 15) ? (isprint(b[15]) ? b[15] : '.') : ' '
733 char *local_strdup(const char *source)
736 FLAC__ASSERT(0 != source);
737 if(0 == (ret = strdup(source))) {
738 fprintf(stderr, "ERROR: out of memory during strdup()\n");
744 FLAC__bool parse_vorbis_comment_field(const char *field, char **name, char **value, unsigned *length)
746 char *p, *s = local_strdup(field);
748 if(0 == (p = strchr(s, '='))) {
753 *name = local_strdup(s);
754 *value = local_strdup(p);
761 FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out)
770 s = local_strdup(in);
772 /* first count the entries */
773 for(out->num_entries = 1, p = strchr(s, ','); p; out->num_entries++, p = strchr(s, ','))
777 FLAC__ASSERT(out->num_entries > 0);
778 if(0 == (out->entries = malloc(sizeof(unsigned) * out->num_entries))) {
779 fprintf(stderr, "ERROR: out of memory allocating space for option list\n");
787 if(0 != (p = strchr(q, ',')))
789 if(!isdigit((int)(*q)) || (i = atoi(q)) < 0) {
793 FLAC__ASSERT(entry < out->num_entries);
794 out->entries[entry++] = (unsigned)i;
797 FLAC__ASSERT(entry == out->num_entries);
803 FLAC__bool parse_block_type(const char *in, Argument_BlockType *out)
808 FLAC__bool parse_data_format(const char *in, Argument_DataFormat *out)
810 if(0 == strcmp(in, "binary"))
811 out->is_binary = true;
812 else if(0 == strcmp(in, "text"))
813 out->is_binary = false;
819 FLAC__bool parse_application_data_format(const char *in, Argument_ApplicationDataFormat *out)
821 if(0 == strcmp(in, "hexdump"))
822 out->is_hexdump = true;
823 else if(0 == strcmp(in, "text"))
824 out->is_hexdump = false;