} Argument_VcFieldName;
typedef struct {
+ char *field; /* the whole field as passed on the command line, i.e. "NAME=VALUE" */
char *field_name;
/* according to the vorbis spec, field values can contain \0 so simple C strings are not enough here */
unsigned field_value_length;
static int short_usage(const char *message, ...);
static int long_usage(const char *message, ...);
static char *local_strdup(const char *source);
-static FLAC__bool parse_vorbis_comment_field(const char *field, char **name, char **value, unsigned *length);
+static FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length);
static FLAC__bool parse_add_padding(const char *in, unsigned *out);
static FLAC__bool parse_block_number(const char *in, Argument_BlockNumber *out);
static FLAC__bool parse_block_type(const char *in, Argument_BlockType *out);
static FLAC__bool remove_vc_field(FLAC__StreamMetaData *block, const char *field_name, FLAC__bool *needs_write);
static FLAC__bool remove_vc_firstfield(FLAC__StreamMetaData *block, const char *field_name, FLAC__bool *needs_write);
static FLAC__bool set_vc_field(FLAC__StreamMetaData *block, const Argument_VcField *field, FLAC__bool *needs_write);
+static FLAC__bool field_name_matches_entry(const char *field_name, unsigned field_name_length, const FLAC__StreamMetaData_VorbisComment_Entry *entry);
static void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent);
int main(int argc, char *argv[])
else if(0 == strcmp(opt, "set-vc-field")) {
op = append_shorthand_operation(options, OP__SET_VC_FIELD);
FLAC__ASSERT(0 != option_argument);
- 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))) {
+ if(!parse_vorbis_comment_field(option_argument, &(op->argument.set_vc_field.field), &(op->argument.set_vc_field.field_name), &(op->argument.set_vc_field.field_value), &(op->argument.set_vc_field.field_value_length))) {
fprintf(stderr, "ERROR: malformed vorbis comment field \"%s\"\n", option_argument);
ok = false;
}
free(op->argument.show_vc_field.field_name);
break;
case OP__SET_VC_FIELD:
+ if(0 != op->argument.set_vc_field.field)
+ free(op->argument.set_vc_field.field);
if(0 != op->argument.set_vc_field.field_name)
free(op->argument.set_vc_field.field_name);
if(0 != op->argument.set_vc_field.field_value)
return ret;
}
-FLAC__bool parse_vorbis_comment_field(const char *field, char **name, char **value, unsigned *length)
+FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length)
{
- char *p, *s = local_strdup(field);
+ char *p, *s;
+
+ if(0 != field)
+ *field = local_strdup(field_ref);
+
+ s = local_strdup(field_ref);
if(0 == (p = strchr(s, '='))) {
free(s);
{
unsigned i;
+/*@@@ yuck, should do this with a varargs function or something: */
#define PPR if(filename)printf("%s:",filename);
PPR; printf("METADATA block #%u\n", block_number);
PPR; printf(" type: %u (%s)\n", (unsigned)block->type, block->type<=FLAC__METADATA_TYPE_VORBIS_COMMENT? FLAC__MetaDataTypeString[block->type] : "UNKNOWN");
const unsigned field_name_length = strlen(field_name);
for(i = 0; i < num_entries; i++) {
- if(0 != memchr(entry[i].entry, '=', entry[i].length) && 0 == strncmp(field_name, entry[i].entry, field_name_length))
+ if(field_name_matches_entry(field_name, field_name_length, entry + i))
write_vc_field(filename, entry + i);
}
}
if(0 != block->data.vorbis_comment.comments) {
FLAC__ASSERT(block->data.vorbis_comment.num_comments == 0);
- if(!FLAC__metadata_object_vorbiscomment_entry_array_resize(&block->data.vorbis_comment.comments, block->data.vorbis_comment.num_comments, 0))
+ if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, 0))
return false;
*needs_write = true;
}
FLAC__bool remove_vc_field(FLAC__StreamMetaData *block, const char *field_name, FLAC__bool *needs_write)
{
FLAC__bool ok = true;
+ const unsigned field_name_length = strlen(field_name);
+ int i;
+
+ FLAC__ASSERT(0 != block);
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
FLAC__ASSERT(0 != needs_write);
+ /* must delete from end to start otherwise it will interfere with our iteration */
+ for(i = (int)block->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
+ if(field_name_matches_entry(field_name, field_name_length, block->data.vorbis_comment.comments + i)) {
+ ok &= FLAC__metadata_object_vorbiscomment_delete_comment(block, (unsigned)i);
+ if(ok)
+ *needs_write = true;
+ }
+ }
+
return ok;
}
FLAC__bool remove_vc_firstfield(FLAC__StreamMetaData *block, const char *field_name, FLAC__bool *needs_write)
{
- FLAC__bool ok = true;
+ const unsigned field_name_length = strlen(field_name);
+ unsigned i;
+
+ FLAC__ASSERT(0 != block);
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
FLAC__ASSERT(0 != needs_write);
- return ok;
+ for(i = 0; i < block->data.vorbis_comment.num_comments; i++) {
+ if(field_name_matches_entry(field_name, field_name_length, block->data.vorbis_comment.comments + i)) {
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, (unsigned)i))
+ return false;
+ else
+ *needs_write = true;
+ break;
+ }
+ }
+
+ return true;
}
FLAC__bool set_vc_field(FLAC__StreamMetaData *block, const Argument_VcField *field, FLAC__bool *needs_write)
{
+ FLAC__StreamMetaData_VorbisComment_Entry entry;
FLAC__ASSERT(0 != block);
FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
FLAC__ASSERT(0 != field);
FLAC__ASSERT(0 != needs_write);
- if(!FLAC__metadata_object_vorbiscomment_entry_array_resize(&block->data.vorbis_comment.comments, block->data.vorbis_comment.num_comments, block->data.vorbis_comment.num_comments + 1))
- return false;
+ entry.length = strlen(field->field);
+ entry.entry = field->field;
- block->data.vorbis_comment.num_comments++;
+ if(!FLAC__metadata_object_vorbiscomment_set_comment(block, block->data.vorbis_comment.num_comments, &entry, /*copy=*/true)) {
+ return false;
+ }
+ else {
+ *needs_write = true;
+ return true;
+ }
+}
- *needs_write = true;
- return true;
+FLAC__bool field_name_matches_entry(const char *field_name, unsigned field_name_length, const FLAC__StreamMetaData_VorbisComment_Entry *entry)
+{
+ return (0 != memchr(entry->entry, '=', entry->length) && 0 == strncmp(field_name, entry->entry, field_name_length));
}
void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent)