$NetBSD: patch-ai,v 1.3 2002/10/03 15:46:58 abs Exp $ --- mserv/mp3info.c.orig Thu Oct 3 16:10:58 2002 +++ mserv/mp3info.c @@ -7,6 +7,7 @@ #include #include #include +#include "mserv.h" #include "mp3info.h" /* mp3 frame header structure */ @@ -25,6 +26,8 @@ #define h_id(val) ((val>>19)&1) #define h_thing(val) ((val>>20)&0xfff) +#define ID3V2HEADERLEN 10 + /* mp3 bit rate and sampling frequency tables */ const int bitrate_table[2][3][16] = @@ -51,6 +54,16 @@ typedef struct id3tag_disc_str unsigned char genre; } id3tag_disc; +/* id3 v2 frame tag data */ + +typedef struct id3v2_frame_str +{ + char frameid[4]; + uint32_t size; + uint16_t flags; + char data[1024]; + size_t datalen; +} id3v2_frame; /* id3 tags genre */ const char *genres_table[] = { @@ -201,20 +214,46 @@ static int is_mp3(unsigned long int flag return 1; } +/* returns 0 if id3v2 frame found, -1 otherwise */ + +static int read_id3v2_frame(FILE *f, id3v2_frame *frame) +{ + if (fread(frame->frameid, 1, 4, f) != 4 || + fread(&frame->size, 1, 4, f) != 4 || fread(&frame->flags, 1, 2, f) != 2) + return -1; + frame->size = ntohl(frame->size); + frame->flags = ntohs(frame->flags); + frame->datalen = (frame->size >= sizeof(frame->data) - 1) + ?(sizeof(frame->data) - 1) :frame->size; + if (fread(frame->data, 1, frame->datalen, f) != frame->datalen) + return -1; + if (frame->frameid[0] == 'T' && memcmp(frame->frameid + 1, "XXX", 3)) { + frame->data[frame->datalen] = 0; + if (frame->data[0] == 0) /* Only handle non unicode */ + strcpy(frame->data, frame->data + 1); + else + frame->data[0] = 0; + } + return 0; +} + /* returns 0 if no id3v2 header, otherwise returns tag length, or -1 and errno set */ static int mp3_id3v2head(FILE *f) { char tag[3]; + char size[4]; if (fseek(f, 0, SEEK_SET) == -1 || fread(tag, 1, 3, f) != 3) return -1; if (strncmp(tag, "ID3", 3)) return 0; /* no header */ + if (fseek(f, 2 + 1, SEEK_CUR) == -1 || fread(size, 1, 4, f) != 4) + return -1; - errno = ENOSYS; - return -1; + return ID3V2HEADERLEN + size[3] + (size[2] << 7) + (size[1] << 14) + + (size[0] << 21); } /* determines length and bitrate of an mp3. returns -1 on failure with errno @@ -321,12 +360,35 @@ int mserv_mp3info_readlen(const char *fn /* No ID3 tag present; last 128 bytes is music. */ filelen += 128; } - fclose(f); /* ignore error */ *bitrate_ret = bitrate; length = ((filelen - headerlen) / mean_frame_size ) * ((115200/2) * (1+h_id(flags)) ) / fs; /* in 1/100 seconds */ + + /* If mp3v2 header present, read its contents */ + if (headerlen && fseek(f, ID3V2HEADERLEN, SEEK_SET) != -1) { + id3v2_frame frame; + while (read_id3v2_frame(f, &frame) != -1) { + if (!memcmp(frame.frameid, "TALB", 4)) { + memcpy(id3tag->album, frame.data, sizeof(id3tag->album) - 1); + id3tag->album[sizeof(id3tag->album) - 1] = 0; + } + else if (!memcmp(frame.frameid, "TPE1", 4)) { + memcpy(id3tag->artist, frame.data, sizeof(id3tag->artist) - 1); + id3tag->artist[sizeof(id3tag->artist) - 1] = 0; + } + else if (!memcmp(frame.frameid, "TIT2", 4)) { + memcpy(id3tag->title, frame.data, sizeof(id3tag->title) - 1); + id3tag->title[sizeof(id3tag->title) - 1] = 0; + } + if (ftell(f) >= headerlen) + break; + } + } + + fclose(f); /* ignore error */ return length; + error: errnok = errno; fclose(f); /* ignore error */