diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-07-16 22:41:20 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-07-16 22:41:20 +0300 |
commit | 9a2df634f322d174014ac8d5090bfa87a25bb775 (patch) | |
tree | 4346c4b392898c087c55fd20ca998eb39294027b /src/idop.c | |
parent | 8d89ce088cc25786cb9520f67e9fe81c86c70277 (diff) | |
download | idest-9a2df634f322d174014ac8d5090bfa87a25bb775.tar.gz idest-9a2df634f322d174014ac8d5090bfa87a25bb775.tar.bz2 |
Major rewrite.
* src/idest.h (ed_item): Remove union, leave only value instead.
<ref>: New member.
(describe_option,verbose_option,all_frames): New externs.
(set_frame_value): Return int.
(IDEST_OK,IDEST_ERR_*): New constants.
(_idest_errstr, _idest_nerrs): New externs.
(idest_frame_cmp_t,idest_frame_encoder_t)
(idest_frame_decoder_t): New typedefs.
(idest_frametab): New struct.
(idest_frame_lookup)
(find_matching_frame): New protos.
(ed_list_add_item)
(ed_list_print,ed_list_add_assignment)
(ed_list_clear,ed_item_matches_frame)
(ed_item_set_comment_fields): Remove.
(qv_free,input_list_locate)
(parse_ed_items): New protos.
* src/idop.c: Rewrite.
* src/.gitignore: Add src/frametab.c
* src/Makefile.am (idest_SOURCES): Add editem.c and frametab.c
(BUILT_SOURCES): Add frametab.c
(.gperf.c): New rule
(GPERF_FLAGS): New variable.
* src/editem.c: New source.
* src/frametab.gperf: New source.
* src/cmdline.opt: Use input_list_add_assignment in --set handler.
* src/guile.c (frame_to_scm,scm_to_tag): Rewrite using the new
logic.
Diffstat (limited to 'src/idop.c')
-rw-r--r-- | src/idop.c | 567 |
1 files changed, 305 insertions, 262 deletions
@@ -20,59 +20,33 @@ +gl_list_t input_list, output_list; + void -set_frame_value(struct id3_frame *frame, const struct ed_item *item) +input_list_add_assignment(const char *name, const char *value) { - const char *value = item->v.value; - union id3_field *field; - enum id3_field_textencoding encoding = - (latin1_option ? ID3_FIELD_TEXTENCODING_ISO_8859_1 - : ID3_FIELD_TEXTENCODING_UTF_8); - id3_ucs4_t *ucs4; - const char *condesc; + struct ed_item *itm; + + if (!input_list) + input_list = ed_list_create(); + itm = ed_item_from_frame_spec(name, strlen(name)); + itm->value = xstrdup(value); + gl_list_add_last(input_list, itm); +} + +struct ed_item const * +input_list_locate(struct id3_frame *frame, idest_frame_cmp_t cmp) +{ + gl_list_iterator_t itr; + const void *p; + const struct ed_item *item = NULL; - switch (frame_to_item_id(frame->id)) { - default: - field = id3_frame_field(frame, 0); - id3_field_settextencoding(field, encoding); - - if (latin1_option) - ucs4 = id3_latin1_ucs4duplicate( - (const id3_latin1_t *) value); - else - ucs4 = id3_utf8_ucs4duplicate( - (const id3_utf8_t *)value); - - field = id3_frame_field(frame, 1); - id3_field_setstrings(field, 1, &ucs4); - free(ucs4); - break; - - case item_comment: - /* Field 0: Encoding */ - field = id3_frame_field(frame, 0); - id3_field_settextencoding(field, encoding); - /* Field 1: Language */ - field = id3_frame_field(frame, 1); - id3_field_setlanguage(field, item->lang ? item->lang : "eng"); - /* Field 2: Short content descriptor */ - field = id3_frame_field(frame, 2); - condesc = item->condesc ? item->condesc : ""; - if (latin1_option) - ucs4 = id3_latin1_ucs4duplicate( - (const id3_latin1_t *)condesc); - else - ucs4 = id3_utf8_ucs4duplicate( - (const id3_utf8_t *)condesc); - id3_field_setstring(field, ucs4); - /* Field 3: Comment */ - field = id3_frame_field(frame, 3); - if (latin1_option) - ucs4 = id3_latin1_ucs4duplicate( - (const id3_latin1_t *) value); - else - ucs4 = id3_utf8_ucs4duplicate( - (const id3_utf8_t *)value); - id3_field_setfullstring(field, ucs4); - free(ucs4); - break; + itr = gl_list_iterator(input_list); + while (gl_list_iterator_next(&itr, &p, NULL)) { + item = p; + if (memcmp(item->id, frame->id, 4) == 0 && + (!cmp || item->qc == 0 || cmp(frame, item) == 0)) + break; + item = NULL; } + gl_list_iterator_free(&itr); + return item; } @@ -80,64 +54,36 @@ set_frame_value(struct id3_frame *frame, const struct ed_item *item) void -safe_id3_file_update_and_close(struct id3_file *file) +parse_ed_items(const char *arg) { - sigset_t set, oldset; - - sigemptyset(&set); - sigaddset(&set, SIGINT); - sigaddset(&set, SIGTERM); + if (!input_list) + input_list = ed_list_create(); + while (*arg) { + struct ed_item *itm; + size_t len = strcspn(arg, " \t,"); - sigprocmask(SIG_BLOCK, &set, &oldset); - id3_file_update(file); - id3_file_close(file); - sigprocmask(SIG_SETMASK, &oldset, NULL); -} - -static void -update_frame(struct id3_tag *tag, const struct ed_item *item) -{ - struct id3_frame *frame = id3_tag_findframe(tag, item->id, 0); - if (!frame) { - frame = id3_frame_new(item->id); - if (id3_tag_attachframe(tag, frame)) - error(1, 0, "cannot attach new frame"); - } else if (strcmp(item->id, ID3_FRAME_COMMENT) == 0 - && item->condesc) { - /* Special handling for comments */ - int i = 0; - - do { - union id3_field *field = id3_frame_field(frame, 2); - char *s; - - if (field && (s = field_to_string(field, 0)) - && strcmp(s, item->condesc) == 0) - break; - } while (frame = id3_tag_findframe(tag, item->id, ++i)); - if (!frame) { - frame = id3_frame_new(item->id); - if (id3_tag_attachframe(tag, frame)) - error(1, 0, "cannot attach new frame"); - } - } else { - struct id3_frame *fp; - - while (fp = id3_tag_findframe(tag, item->id, 1)) { - id3_tag_detachframe(tag, fp); - id3_frame_delete(fp); - } + itm = ed_item_from_frame_spec(arg, len); + gl_list_add_last(input_list, itm); + arg += len; + if (!*arg) + break; + arg += strspn(arg, " \t,"); } - set_frame_value(frame, item); } -static int -build_tag_options(struct id3_tag *tag, unsigned long location, - id3_length_t length, void *data) +void +input_list_init() { - unsigned int ver = id3_tag_version(tag); - - if (ID3_TAG_VERSION_MAJOR(ver) == 1) - *(unsigned int*)data |= IDEST_ID3V_1; - else - *(unsigned int*)data |= IDEST_ID3V_2; - return 0; + if (all_frames) + input_list = NULL; + else if (!input_list) + parse_ed_items(DEFAULT_ED_LIST); +} + +void +output_list_append(struct ed_item const *item, struct ed_item const *ref) +{ + struct ed_item *elt = ed_item_dup(item); + if (!output_list) + output_list = ed_list_create(); + elt->ref = ref; + gl_list_add_last(output_list, elt); } @@ -145,64 +91,36 @@ build_tag_options(struct id3_tag *tag, unsigned long location, void -set_tags(const char *name) +output_list_print() { - struct id3_file *file; - struct id3_tag *tag; - int modified = 0; - int vopt = version_option; - - file = id3_file_open(name, ID3_FILE_MODE_READWRITE); - if (!file) - error(1, errno, "cannot open file %s", name); - tag = id3_file_tag(file); - if (!tag) - abort(); /* FIXME */ + gl_list_iterator_t itr; + const void *p; - if (ed_list) { - gl_list_iterator_t itr; - const void *p; - - itr = gl_list_iterator(ed_list); + if (all_frames) { + itr = gl_list_iterator(output_list); while (gl_list_iterator_next(&itr, &p, NULL)) { const struct ed_item *item = p; - update_frame(tag, item); - modified |= 1; + ed_item_print(item); } gl_list_iterator_free(&itr); - } - - /* FIXME */ - modified |= guile_transform(name, tag); - - if (convert_version == 0) { - if (modified && !vopt) { - if (id3_file_struct_ntags(file)) { - id3_file_struct_iterate(file, - build_tag_options, - &vopt); - } else - vopt = default_version_option; - } - } else if (id3_file_struct_ntags(file)) { - id3_file_struct_iterate(file, build_tag_options, &vopt); - if (vopt != convert_version) { - vopt = convert_version; - modified |= 1; + } else { + itr = gl_list_iterator(input_list); + while (gl_list_iterator_next(&itr, &p, NULL)) { + int printed = 0; + const struct ed_item *input_item = p; + if (output_list) { + gl_list_iterator_t oitr; + oitr = gl_list_iterator(output_list); + while (gl_list_iterator_next(&oitr, &p, NULL)) { + const struct ed_item *output_item = p; + if (output_item->ref == input_item) { + ed_item_print(output_item); + printed = 1; + } + } + gl_list_iterator_free(&oitr); + } + if (!printed) + ed_item_print(input_item); } + gl_list_iterator_free(&itr); } - - if (modified && vopt) { - int opts = 0; - - if (vopt & IDEST_ID3V_1) - opts |= ID3_TAG_OPTION_ID3V1; - if (!(vopt & IDEST_ID3V_2)) - opts |= ID3_TAG_OPTION_NO_ID3V2; - id3_tag_options(tag, - ID3_TAG_OPTION_ID3V1|ID3_TAG_OPTION_NO_ID3V2, - opts); - } - if (modified) - safe_id3_file_update_and_close(file); - else - id3_file_close(file); } @@ -210,37 +128,24 @@ set_tags(const char *name) void -del_tags(const char *name) +output_list_free() { - struct id3_file *file; - struct id3_tag *tag; - - file = id3_file_open(name, ID3_FILE_MODE_READWRITE); - if (!file) - error(1, errno, "cannot open file %s", name); - tag = id3_file_tag(file); - if (!tag) - abort(); /* FIXME */ - if (ed_list) { - gl_list_iterator_t itr; - const void *p; - - itr = gl_list_iterator(ed_list); - while (gl_list_iterator_next(&itr, &p, NULL)) { - const struct ed_item *item = p; - struct id3_frame *frame; - int i = 0; - - while (frame = id3_tag_findframe(tag, item->id, i)) { - if (ed_item_matches_frame(item, frame)) { - id3_tag_detachframe(tag, frame); - id3_frame_delete(frame); - } else - i++; - } - } - gl_list_iterator_free(&itr); - } else - id3_tag_clearframes(tag); - safe_id3_file_update_and_close(file); + if (output_list) { + gl_list_free(output_list); + output_list = NULL; + } } + +void +safe_id3_file_update_and_close(struct id3_file *file) +{ + sigset_t set, oldset; + + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigprocmask(SIG_BLOCK, &set, &oldset); + id3_file_update(file); + id3_file_close(file); + sigprocmask(SIG_SETMASK, &oldset, NULL); +} @@ -292,3 +197,2 @@ field_to_string(union id3_field *field, int isgenre) case ID3_FIELD_TYPE_INT32: - case ID3_FIELD_TYPE_INT32PLUS: snprintf(buf, sizeof(buf), "%ld", field->number.value); @@ -345,2 +249,6 @@ field_to_string(union id3_field *field, int isgenre) break; + + case ID3_FIELD_TYPE_INT32PLUS: + /* FIXME */ + break; } @@ -348,70 +256,161 @@ field_to_string(union id3_field *field, int isgenre) } + +int +set_frame_value(struct id3_frame *frame, const struct ed_item *item) +{ + const struct idest_frametab *ft = idest_frame_lookup(frame->id); + if (!ft) + return IDEST_ERR_BADTYPE; + return ft->encode(frame, item); +} -static void -add_field(gl_list_t list, struct id3_frame *frame, union id3_field *field) +static int +build_tag_options(struct id3_tag *tag, unsigned long location, + id3_length_t length, void *data) { - id3_ucs4_t const *ucs4; - char *str; - - switch (id3_field_type(field)) { - case ID3_FIELD_TYPE_TEXTENCODING: - break; - case ID3_FIELD_TYPE_LATIN1: - case ID3_FIELD_TYPE_LATIN1FULL: - case ID3_FIELD_TYPE_LATIN1LIST: - break; - case ID3_FIELD_TYPE_STRING: - break; - case ID3_FIELD_TYPE_STRINGFULL: - ucs4 = id3_field_getfullstring(field); - str = idest_ucs4_cvt(ucs4); - gl_list_add_last(list, str); - break; - case ID3_FIELD_TYPE_STRINGLIST: - add_stringlist(list, field, - strcmp(frame->id, ID3_FRAME_GENRE) == 0, - NULL); - break; - case ID3_FIELD_TYPE_LANGUAGE: - case ID3_FIELD_TYPE_FRAMEID: - case ID3_FIELD_TYPE_DATE: - case ID3_FIELD_TYPE_INT8: - case ID3_FIELD_TYPE_INT16: - case ID3_FIELD_TYPE_INT24: - case ID3_FIELD_TYPE_INT32: - case ID3_FIELD_TYPE_INT32PLUS: - case ID3_FIELD_TYPE_BINARYDATA:; - } + unsigned int ver = id3_tag_version(tag); + + if (ID3_TAG_VERSION_MAJOR(ver) == 1) + *(unsigned int*)data |= IDEST_ID3V_1; + else + *(unsigned int*)data |= IDEST_ID3V_2; + return 0; } -void -ed_item_set_comment_fields(struct ed_item *itm, struct id3_frame *frame) +struct id3_frame * +find_matching_frame(struct id3_tag *tag, const struct ed_item *item, + idest_frame_cmp_t cmp) { - union id3_field *field; + struct id3_frame *frame; - if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0) { - field = id3_frame_field(frame, 1); - if (!field) - return; - itm->lang = field_to_string(field, 0); - field = id3_frame_field(frame, 2); - if (!field) - return; - itm->condesc = field_to_string(field, 0); + if (item->qc == 0 || cmp == NULL) + frame = id3_tag_findframe(tag, item->id, 0); + else { + int i; + for (i = 0; frame = id3_tag_findframe(tag, item->id, i); i++) { + if (cmp(frame, item) == 0) + break; + } } + return frame; } -static gl_list_t -frame_to_list(struct id3_frame *frame) + +static int +update_frame(struct id3_tag *tag, const struct ed_item *item) { - gl_list_t list; - unsigned i; - union id3_field *field; + const struct idest_frametab *ft = idest_frame_lookup(item->id); + struct id3_frame *frame; - list = new_string_list(true); - for (i = 0; (field = id3_frame_field(frame, i)); i++) - add_field(list, frame, field); - return list; + if (!ft) + return IDEST_ERR_BADTYPE; + + frame = find_matching_frame(tag, item, ft->cmp); + if (!frame) { + frame = id3_frame_new(item->id); + if (id3_tag_attachframe(tag, frame)) + error(1, 0, "cannot attach new frame"); + } + return ft->encode(frame, item); } +void +set_tags(const char *name) +{ + struct id3_file *file; + struct id3_tag *tag; + int modified = 0; + int vopt = version_option; + + file = id3_file_open(name, ID3_FILE_MODE_READWRITE); + if (!file) + error(1, errno, "cannot open file %s", name); + tag = id3_file_tag(file); + if (!tag) + abort(); /* FIXME */ + + if (input_list) { + gl_list_iterator_t itr; + const void *p; + + itr = gl_list_iterator(input_list); + while (gl_list_iterator_next(&itr, &p, NULL)) { + const struct ed_item *item = p; + int rc = update_frame(tag, item); + if (rc) + error(1, 0, + "cannot set frame %s: %s", + item->id, idest_strerror(rc)); + modified |= 1; + } + gl_list_iterator_free(&itr); + } + + /* FIXME */ + modified |= guile_transform(name, tag); + + if (convert_version == 0) { + if (modified && !vopt) { + if (id3_file_struct_ntags(file)) { + id3_file_struct_iterate(file, + build_tag_options, + &vopt); + } else + vopt = default_version_option; + } + } else if (id3_file_struct_ntags(file)) { + id3_file_struct_iterate(file, build_tag_options, &vopt); + if (vopt != convert_version) { + vopt = convert_version; + modified |= 1; + } + } + + if (modified && vopt) { + int opts = 0; + + if (vopt & IDEST_ID3V_1) + opts |= ID3_TAG_OPTION_ID3V1; + if (!(vopt & IDEST_ID3V_2)) + opts |= ID3_TAG_OPTION_NO_ID3V2; + id3_tag_options(tag, + ID3_TAG_OPTION_ID3V1|ID3_TAG_OPTION_NO_ID3V2, + opts); + } + if (modified) + safe_id3_file_update_and_close(file); + else + id3_file_close(file); +} + +void +del_tags(const char *name) +{ + struct id3_file *file; + struct id3_tag *tag; + + file = id3_file_open(name, ID3_FILE_MODE_READWRITE); + if (!file) + error(1, errno, "cannot open file %s", name); + tag = id3_file_tag(file); + if (!tag) + abort(); /* FIXME */ + if (input_list) { + int i; + struct id3_frame *frame; + + for (i = 0; (frame = id3_tag_findframe(tag, NULL, i)); ) { + const struct idest_frametab *ft = + idest_frame_lookup(frame->id); + if (input_list_locate(frame, ft ? ft->cmp : NULL)) { + id3_tag_detachframe(tag, frame); + id3_frame_delete(frame); + } else + i++; + } + } else + id3_tag_clearframes(tag); + safe_id3_file_update_and_close(file); +} + static void @@ -423,10 +422,49 @@ show_tags(struct id3_tag *tag) for (i = 0; (frame = id3_tag_findframe(tag, NULL, i)); i++) { - gl_list_t list = frame_to_list(frame); - if (gl_list_size(list) > 0) - ed_list_add_item(frame, list); - else - gl_list_free(list); + const struct idest_frametab *ft = + idest_frame_lookup(frame->id); + if (!ft) { + if (verbose_option) + error(0, 0, + "%s: unsupported frame", frame->id); + continue; + } + + if (all_frames) { + struct ed_item outitm; + ed_item_zero(&outitm); + if (describe_option) { + struct id3_frametype const *frametype; + frametype = id3_frametype_lookup(frame->id, + 4); + outitm.name = xstrdup(frametype->description); + } else + outitm.name = xstrdup(frame->id); + memcpy(outitm.id, frame->id, 4); + if (ft->decode(&outitm, frame)) { + error(0, 0, "%s: decoding failed", frame->id); + continue; + } + output_list_append(&outitm, NULL); + ed_item_free_content(&outitm); + } else { + struct ed_item const *ref; + + ref = input_list_locate(frame, ft->cmp); + if (ref) { + struct ed_item outitm; + ed_item_zero(&outitm); + outitm.name = xstrdup(ref->name); + memcpy(outitm.id, ref->id, 4); + if (ft->decode(&outitm, frame)) { + error(0, 0, + "%s: decoding failed", frame->id); + continue; + } + output_list_append(&outitm, ref); + ed_item_free_content(&outitm); + } + } } - ed_list_print(); - ed_list_clear(); + output_list_print(); + output_list_free(); } @@ -439,2 +477,4 @@ query_tags(const char *name) + input_list_init(); + file = id3_file_open(name, ID3_FILE_MODE_READONLY); @@ -451,3 +491,3 @@ query_tags(const char *name) } - + static int @@ -458,5 +498,8 @@ prinfo(struct id3_tag *tag, unsigned long location, unsigned int major = ID3_TAG_VERSION_MAJOR(ver); - printf("version: %u.%u\n", - major > 1 ? 20 + major : major, - ID3_TAG_VERSION_MINOR(ver)); + if (major > 1) + printf("version: 2.%u.%u\n", + major, ID3_TAG_VERSION_MINOR(ver)); + else + printf("version: %u.%u\n", + major, ID3_TAG_VERSION_MINOR(ver)); printf("offset: %lu\n", location); |