+#ifdef HAVE_LIBID3TAG
+
+#include <id3tag.h>
+
+static char *get_latin1(id3_ucs4_t const *string)
+{
+ if (!string)
+ return NULL;
+ return (char *)id3_ucs4_latin1duplicate(string);
+}
+
+static char *get_stringlist(union id3_field *field)
+{
+ unsigned int k, nstrings = id3_field_getnstrings(field);
+ char *result = NULL;
+
+ for (k = 0; k < nstrings; k++) {
+ char *tmp = (char *)get_latin1(id3_field_getstrings(field, k));
+ if (result) {
+ char *tmp2 = result;
+ result = make_message("%s %s", tmp2, tmp);
+ free(tmp);
+ free(tmp2);
+ } else
+ result = tmp;
+ }
+ return result;
+}
+
+static char *get_string(union id3_field *field)
+{
+ id3_ucs4_t const *string = id3_field_getfullstring(field);
+
+ return get_latin1(string);
+}
+
+#define FOR_EACH_FIELD(f, j, fr) for (j = 0; j < (fr)->nfields && \
+ (f = id3_frame_field((fr), j)); j++)
+
+static char *get_strings(struct id3_frame *fr)
+{
+ int j;
+ union id3_field *field;
+
+ FOR_EACH_FIELD(field, j, fr) {
+ enum id3_field_type type = id3_field_type(field);
+
+ if (type == ID3_FIELD_TYPE_STRINGLIST)
+ return get_stringlist(field);
+ if (type == ID3_FIELD_TYPE_STRINGFULL)
+ return get_string(field);
+ }
+ return NULL;
+}
+
+static char *mp3_get_id3(__a_unused unsigned char *map,
+ __a_unused size_t numbytes, int fd)
+{
+ int i;
+ struct id3_tag *id3_t;
+ char *title = NULL, *artist = NULL, *album = NULL, *year = NULL,
+ *comment = NULL, *result;
+ struct id3_file *id3_f = id3_file_fdopen(fd, ID3_FILE_MODE_READONLY);
+
+ if (!id3_f)
+ goto no_tag;
+ id3_t = id3_file_tag(id3_f);
+ if (!id3_t)
+ goto no_tag;
+ for (i = 0; i < id3_t->nframes; i++) {
+ struct id3_frame *fr = id3_t->frames[i];
+ if (!strcmp(fr->id, "TIT2")) {
+ if (!title)
+ title = get_strings(fr);
+ continue;
+ }
+ if (!strcmp(fr->id, "TPE1")) {
+ if (!artist)
+ artist = get_strings(fr);
+ continue;
+ }
+ if (!strcmp(fr->id, "TALB")) {
+ if (!album)
+ album = get_strings(fr);
+ continue;
+ }
+ if (!strcmp(fr->id, "TDRC")) {
+ if (!year)
+ year = get_strings(fr);
+ continue;
+ }
+ if (!strcmp(fr->id, "COMM")) {
+ if (!comment)
+ comment = get_strings(fr);
+ continue;
+ }
+ }
+ id3_file_close(id3_f);
+ result = make_taginfo(title, artist, album, year, comment);
+ free(title);
+ free(artist);
+ free(album);
+ free(year);
+ free(comment);
+ return result;
+no_tag:
+ if (id3_f)
+ id3_file_close(id3_f);
+ return make_message("%s: (no id3 v1/v2 tag)\n%s:\n",
+ status_item_list[SI_TAGINFO1],
+ status_item_list[SI_TAGINFO2]);
+}
+
+#else /* HAVE_LIBID3TAG */
+
+/*
+ * Remove trailing whitespace from the end of a string
+ */
+static char *unpad(char *string)
+{
+ char *pos = string + strlen(string) - 1;
+ while (para_isspace(pos[0]))
+ (pos--)[0] = 0;
+ return string;
+}
+
+static char *mp3_get_id3(unsigned char *map, size_t numbytes, __a_unused int fd)
+{
+ char title[31], artist[31], album[31], year[5], comment[31];
+ off_t fpos;
+
+ if (numbytes < 128 || strncmp("TAG", (char *)map + numbytes - 128, 3)) {
+ PARA_DEBUG_LOG("no id3 v1 tag\n");
+ return make_message("%s: (no id3 v1 tag)\n%s:\n",
+ status_item_list[SI_TAGINFO1],
+ status_item_list[SI_TAGINFO2]);
+ }
+ fpos = numbytes - 125;
+ memcpy(title, map + fpos, 30);
+ fpos += 30;
+ title[30] = '\0';
+ memcpy(artist, map + fpos, 30);
+ fpos += 30;
+ artist[30] = '\0';
+ memcpy(album, map + fpos, 30);
+ fpos += 30;
+ album[30] = '\0';
+ memcpy(year, map + fpos, 4);
+ fpos += 4;
+ year[4] = '\0';
+ memcpy(comment, map + fpos, 30);
+ comment[30] = '\0';
+ unpad(title);
+ unpad(artist);
+ unpad(album);
+ unpad(year);
+ unpad(comment);
+ return make_taginfo(title, artist, album, year, comment);
+}
+#endif /* HAVE_LIBID3TAG */