diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-05 18:03:32 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-05 18:03:32 +0200 |
commit | 9b5fb2470499d0d054e6dfab55611057d669ad76 (patch) | |
tree | d759a6b838c2f1db0b53c1399b25b45437da2811 | |
parent | a8c4e813eb17fb28adda734c37ee0c4005601936 (diff) | |
download | idest-9b5fb2470499d0d054e6dfab55611057d669ad76.tar.gz idest-9b5fb2470499d0d054e6dfab55611057d669ad76.tar.bz2 |
Switch to using libid3tag
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/cmdline.opt | 28 | ||||
-rw-r--r-- | src/id3ed.h | 20 | ||||
-rw-r--r-- | src/id3v1.c | 133 | ||||
-rw-r--r-- | src/id3v1.h | 20 | ||||
-rw-r--r-- | src/id3v2.c | 33 | ||||
-rw-r--r-- | src/main.c | 134 |
8 files changed, 254 insertions, 120 deletions
diff --git a/configure.ac b/configure.ac index 3b35567..9f5d8fd 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ gl_EARLY # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([stdlib.h]) +AC_CHECK_HEADERS([id3tag.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -25,6 +25,8 @@ AC_TYPE_SIZE_T # Checks for library functions. AC_FUNC_MEMCMP AC_CHECK_FUNCS([memset strcasecmp strerror strncasecmp]) +AC_CHECK_LIB(id3tag, id3_file_tag,, + [AC_MSG_ERROR([Required library libid3tag not found])]) gl_INIT diff --git a/src/Makefile.am b/src/Makefile.am index 9ea4af7..c4205a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ bin_PROGRAMS=id3ed -id3ed_SOURCES=id3ed.h id3v1.c id3v1.h main.c cmdline.h +id3ed_SOURCES=id3ed.h id3v1.c id3v1.h id3v2.c main.c cmdline.h BUILT_SOURCES=cmdline.h EXTRA_DIST=cmdline.opt getopt.m4 INCLUDES=-I$(top_srcdir)/gnu -I$(top_builddir)/gnu diff --git a/src/cmdline.opt b/src/cmdline.opt index b4ba979..27a8298 100644 --- a/src/cmdline.opt +++ b/src/cmdline.opt @@ -5,55 +5,49 @@ OPTIONS_BEGIN(gnu, "id3ed", OPTION(title,t,NUMBER, [<set song title>]) BEGIN - ID3_COPY(id, title, optarg); + title = optarg; mode = MODE_MOD; END OPTION(artist,a,NAME, [<set artist name>]) BEGIN - ID3_COPY(id, artist, optarg); + artist = optarg; mode = MODE_MOD; END OPTION(album,A,NAME, [<set album name>]) BEGIN - ID3_COPY(id, album, optarg); + album = optarg; mode = MODE_MOD; END OPTION(year,y,YEAR, [<set year>]) BEGIN - ID3_COPY(id, year, optarg); + year = optarg; mode = MODE_MOD; END OPTION(comment,c,TEXT, [<set comment>]) BEGIN - ID3_COPY(id, comment, optarg); + comment = optarg; mode = MODE_MOD; END OPTION(track,T,NUMBER, [<set track number>]) BEGIN - id.pad[0] = 0; - id.track[0] = atoi(optarg); + track = atoi(optarg); mode = MODE_MOD; END OPTION(genre,g,NAME, [<set genre>]) BEGIN - int n = id3v1_genre_to_n(optarg); - if (n == -1) - error(1, 0, "%s: unknown genre", optarg); - else if (n == -2) - error(1, 0, "%s: ambiguous genre", optarg); - id.genre[0] = n; + genre = optarg; mode = MODE_MOD; END @@ -63,6 +57,14 @@ BEGIN mode = MODE_QUERY; END +OPTION(id-version,V,VERSION, + [<set ID3 version>]) +BEGIN + version_option = atoi(optarg); + if (version_option > 2) + error(1, 0, "unsupported version"); +END + OPTIONS_END void diff --git a/src/id3ed.h b/src/id3ed.h index e51a55a..52f724d 100644 --- a/src/id3ed.h +++ b/src/id3ed.h @@ -6,9 +6,27 @@ #include <error.h> #include <progname.h> +#include <id3tag.h> + #define _(s) s #define N_(s) s #include "id3v1.h" - +extern struct id3v1_block v1_block; +extern char *title; +extern char *artist; +extern char *album; +extern char *year; +extern char *comment; +extern unsigned track; +extern char *genre; + +void set_id3v1(const char *name); +void query_id3v1(const char *name); +void del_id3v1(const char *name); + +void set_id3v2(const char *name); +void query_id3v2(const char *name); +void del_id3v2(const char *name); + diff --git a/src/id3v1.c b/src/id3v1.c index cd7b7ae..9093eb8 100644 --- a/src/id3v1.c +++ b/src/id3v1.c @@ -192,6 +192,139 @@ id3v1_genre_to_n(const char *genre) return index; } +void +id3v1_copy_string(const char *name, char *ptr, size_t size, const char *arg) +{ + size_t len = strlen(arg); + if (len > size) { + error(0, 0, "%s truncated", name); + len = size; + } + memcpy(ptr, arg, len); +} +int +id3v1_read(FILE *fp, struct id3v1_block *blk) +{ + struct id3v1_block id; + if (fseek(fp, -sizeof(id), SEEK_END)) + return -1; + if (fread(blk, sizeof(id), 1, fp) != 1) + return -1; + if (memcmp(id.header, ID3V1_TAG, ID3V1_HEADER_LEN)) + return 1; + memcpy(blk, &id, sizeof(blk[0])); + return 0; +} +int +id3v1_write(FILE *fp, struct id3v1_block *blk) +{ + struct id3v1_block id; + long offset; + switch (id3v1_read(fp, &id)) { + case 0: + offset = -sizeof(id); + break; + case 1: + offset = 0; + break; + default: + return -1; + } + memcpy(blk, ID3V1_TAG, ID3V1_HEADER_LEN); + if (fseek(fp, offset, SEEK_END)) + return -1; + if (fwrite(&blk, sizeof(blk), 1, fp) != 1) + return -1; + return 0; +} + +#define ID3_MERGE_FIELD(new,old,fld) do { \ + if (new->fld[0] == 0 && old->fld) \ + memcpy(new->fld, old->fld, sizeof(new->fld)); \ + } while (0) + +void +id3v1_merge(struct id3v1_block *id, const struct id3v1_block *old) +{ + ID3_MERGE_FIELD(id,old,title); + ID3_MERGE_FIELD(id,old,artist); + ID3_MERGE_FIELD(id,old,album); + ID3_MERGE_FIELD(id,old,year); + ID3_MERGE_FIELD(id,old,comment); +} + +void +id3v1_init(struct id3v1_block *blk) +{ + memset(blk, 0, sizeof(blk[0])); + memcpy(blk, ID3V1_TAG, ID3V1_HEADER_LEN); +} + + +void +set_id3v1(const char *name) +{ + int rc; + struct id3v1_block old; + FILE *fp = fopen(name, "r+"); + if (!fp) + error(1, errno, "cannot open file %s", name); + + verify_mp3(fp, name); + switch (id3v1_read(fp, &old)) { + case 0: + id3v1_merge(&v1_block, &old); + break; + case 1: + break; + default: + error(1, errno, "%s: read error", name); + } + if (id3v1_write(fp, &v1_block)) + error(1, errno, "%s: write error", name); + + fclose(fp); +} + +void +query_id3v1(const char *name) +{ + struct id3v1_block id; + FILE *fp = fopen(name, "r"); + int rc; + if (!fp) + error(1, errno, "cannot open file %s", name); + + verify_mp3(fp, name); + rc = id3v1_read(fp, &id); + fclose(fp); + + switch (rc) { + case 0: + printf("title: %-.30s\n", id.title); + printf("artist: %-.30s\n", id.artist); + printf("album: %-.30s\n", id.album); + printf("year: %-.4s\n", id.year); + printf("comment: %-.28s\n", id.comment); + printf("genre: %s\n", id3v1_n_to_genre(id.genre[0])); + if (id.pad[0] == 0) + printf("track: %d\n", id.track[0]); + break; + case 1: + break; + case -1: + error(1, errno, "%s: read error", name); + } +} + +void +del_id3v1(const char *name) +{ + error(1, 0, "Delete is not implemented"); +} + + + diff --git a/src/id3v1.h b/src/id3v1.h index 86a2776..6df52ff 100644 --- a/src/id3v1.h +++ b/src/id3v1.h @@ -1,4 +1,4 @@ -struct id3_block { +struct id3v1_block { char header[3]; char title[30]; char artist[30]; @@ -10,8 +10,22 @@ struct id3_block { char genre[1]; }; -#define ID3_TAG "TAG" -#define ID3_HEADER_LEN 3 +#define ID3V1_TAG "TAG" +#define ID3V1_HEADER_LEN 3 +#define ID3V1_SET(blk, name, value) do { \ + if (value) \ + id3v1_copy_string(#name, (blk)->name, \ + sizeof((blk)->name), value); \ + } while(0) + const char *id3v1_n_to_genre(unsigned n); int id3v1_genre_to_n(const char *genre); +void id3v1_init(struct id3v1_block *blk); +void id3v1_copy_string(const char *name, char *ptr, size_t size, + const char *arg); +int id3v1_read(FILE *fp, struct id3v1_block *blk); +int id3v1_write(FILE *fp, struct id3v1_block *blk); +void id3v1_merge(struct id3v1_block *id, const struct id3v1_block *old); + + diff --git a/src/id3v2.c b/src/id3v2.c new file mode 100644 index 0000000..f37606f --- /dev/null +++ b/src/id3v2.c @@ -0,0 +1,33 @@ +#include "id3ed.h" + +void +set_id3v2(const char *name) +{ +} + +static void +show_tag(struct id3_tag *tag) +{ +} + +void +query_id3v2(const char *name) +{ + struct id3_file *file; + struct id3_tag *tag; + + file = id3_file_open(name, ID3_FILE_MODE_READONLY); + if (!file) + error(1, errno, "cannot open file %s", name); + + tag = id3_file_tag(file); + if (tag) + show_tag(tag); + + id3_file_close(file); +} + +void +del_id3v2(const char *name) +{ +} @@ -1,16 +1,15 @@ #include "id3ed.h" -void -copy_string(const char *name, char *ptr, size_t size, const char *arg) -{ - size_t len = strlen(arg); - if (len > size) { - error(0, 0, "%s truncated", name); - len = size; - } - memcpy(ptr, arg, len); -} - +unsigned version_option = 2; +struct id3v1_block v1_block; +char *title; +char *artist; +char *album; +char *year; +char *comment; +unsigned track; +char *genre; + void verify_mp3(FILE *fp, const char *name) @@ -31,7 +30,7 @@ verify_mp3(FILE *fp, const char *name) switch (sig & 0xFFFE) { case 0xFFFA: /* MPEG ADTS, layer III, v1 */ case 0xFFF2: /* MPEG ADTS, layer III, v2 */ - case 0xFFFE: /* MPEG ADTS, layer III, v2.5 */ + case 0xFFFE: /* MPEG ADTS, layer III, v2.5 */ break; default: @@ -39,99 +38,17 @@ verify_mp3(FILE *fp, const char *name) } } -void -read_id3(FILE *fp, const char *name, struct id3_block *blk) -{ - if (fseek(fp, -sizeof(blk[0]), SEEK_END)) - error(1, errno, "%s: seek error", name); - if (fread(blk, sizeof(blk[0]), 1, fp) != 1) - error(1, errno, "%s: read error: %s", name); -} - -#define ID3_MERGE_FIELD(new,old,fld) do { \ - if (new->fld[0] == 0 && old->fld) \ - memcpy(new->fld, old->fld, sizeof(new->fld)); \ - } while (0) - -void -id3_merge(struct id3_block *id, const struct id3_block *old) -{ - ID3_MERGE_FIELD(id,old,title); - ID3_MERGE_FIELD(id,old,artist); - ID3_MERGE_FIELD(id,old,album); - ID3_MERGE_FIELD(id,old,year); - ID3_MERGE_FIELD(id,old,comment); -} - -void -set_id3(const char *name, const struct id3_block *id) -{ - int rc; - struct id3_block old, new; - FILE *fp = fopen(name, "r+"); - if (!fp) - error(1, errno, "cannot open file %s", name); - - verify_mp3(fp, name); - read_id3(fp, name, &old); - - memcpy(&new, id, sizeof(new)); - if (memcmp(old.header, ID3_TAG, ID3_HEADER_LEN) == 0) { - id3_merge(&new, &old); - rc = fseek(fp, -sizeof(id[0]), SEEK_END); - } else - rc = fseek(fp, 0, SEEK_END); - if (rc) - error(1, errno, "%s: seek error", name); - - if (fwrite(&new, sizeof(new), 1, fp) != 1) - error(1, errno, "%s: write error", name); - - fclose(fp); -} - -void -query_id3(const char *name, const struct id3_block *blk_unused) -{ - struct id3_block id; - FILE *fp = fopen(name, "r"); - if (!fp) - error(1, errno, "cannot open file %s", name); - - verify_mp3(fp, name); - read_id3(fp, name, &id); - fclose(fp); - if (memcmp(id.header, ID3_TAG, ID3_HEADER_LEN)) - return; - printf("title: %-.30s\n", id.title); - printf("artist: %-.30s\n", id.artist); - printf("album: %-.30s\n", id.album); - printf("year: %-.4s\n", id.year); - printf("comment: %-.28s\n", id.comment); - printf("genre: %s\n", id3v1_n_to_genre(id.genre[0])); - if (id.pad[0] == 0) - printf("track: %d\n", id.track[0]); -} - -#define ID3_COPY(blk, fld, arg) \ - copy_string(#fld, blk.fld, sizeof(blk.fld), arg) - -void -del_id3(const char *name, const struct id3_block *blk_unused) -{ -} #define MODE_QUERY 0 #define MODE_MOD 1 #define MODE_DELETE 2 -void (*id3_mode[])(const char *, const struct id3_block *) = { - query_id3, - set_id3, - del_id3 +void (*id3_mode[][2])(const char *) = { + { query_id3v1, query_id3v2 }, + { set_id3v1, set_id3v2 }, + { del_id3v1, del_id3v2 } }; -struct id3_block id; int mode = MODE_QUERY; #include "cmdline.h" @@ -142,8 +59,6 @@ main(int argc, char **argv) int c, n; set_program_name(argv[0]); - memset(&id, 0, sizeof(id)); - memcpy(id.header, ID3_TAG, ID3_HEADER_LEN); get_options(argc, argv); @@ -153,8 +68,25 @@ main(int argc, char **argv) if (argc == 0) error(1, 0, "no files"); + if (version_option == 1) { + int n; + + id3v1_init(&v1_block); + ID3V1_SET(&v1_block, title, title); + ID3V1_SET(&v1_block, artist, artist); + ID3V1_SET(&v1_block, album, album); + ID3V1_SET(&v1_block, year, year); + ID3V1_SET(&v1_block, comment, comment); + n = id3v1_genre_to_n(genre); + if (n == -1) + error(1, 0, "%s: unknown genre", genre); + else if (n == -2) + error(1, 0, "%s: ambiguous genre", genre); + v1_block.track[0] = n; + } + while (argc--) - id3_mode[mode](*argv++, &id); + id3_mode[mode][version_option - 1](*argv++); exit(0); } |