$NetBSD: patch-ae,v 1.10 2019/05/20 14:47:13 martin Exp $ --- mserv/mp3info.c.orig 2003-07-29 02:17:48.000000000 +0200 +++ mserv/mp3info.c 2019-05-20 16:41:02.827154805 +0200 @@ -26,7 +26,17 @@ #define h_id(val) ((val>>19)&1) #define h_thing(val) ((val>>20)&0xfff) +#ifdef STANDALONE +#define VERBOSE +#endif +#ifdef VERBOSE +#define LOGF(ARG) printf ARG +#else +#define LOGF(ARG) +#endif + #define ID3V2HEADERLEN 10 +#define min(x,y) ((x)<(y)?(x):(y)) /* mp3 bit rate and sampling frequency tables */ @@ -45,12 +55,14 @@ const int sampling_freq_table[2][3] = /* structure of id3 tag in mp3 file */ typedef struct id3tag_disc_str -{ - char title[MP3ID3_TITLELEN]; - char artist[MP3ID3_ARTISTLEN]; - char album[MP3ID3_ALBUMLEN]; - char year[MP3ID3_YEARLEN]; - char comment[MP3ID3_COMMENTLEN]; +{ /* These are all fixed lengths. + * Avoid #define'd lengths that get get redefined for other uses + */ + char title[30]; + char artist[30]; + char album[30]; + char year[4]; + char comment[28]; unsigned char genre; } id3tag_disc; @@ -228,11 +240,28 @@ static int read_id3v2_frame(FILE *f, id3 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; + if (frame->data[0] == 0) { + /* ISO8859-1 */ + frame->data[frame->datalen] = 0; + memmove(frame->data, frame->data + 1, frame->datalen); + } else if (frame->data[0] == 1 && frame->datalen >= 5) { + /* unicode, convert as long as it is 8 bit only */ + int d = 0, i = 1, off0 = 0, off1 = 1; + /* check BOM vs. endianess */ + if ((unsigned char)frame->data[i] == 0xff && (unsigned char)frame->data[i+1] == 0xfe) { + off0 = 1; off1 = 0; + } else if ((unsigned char)frame->data[i] == 0xfe && (unsigned char)frame->data[i+1] == 0xff) { + off1 = 1; off0 = 0; + } else { + return -1; + } + for (i=3; (i+1) < frame->datalen /* && frame->data[i] == 0 */; i+=2) { + frame->data[d++] = frame->data[i+off1]; + if (frame->data[i] == 0 && frame->data[i+1] == 0) + break; + } + frame->data[d] = 0; + } } return 0; } @@ -264,12 +293,12 @@ int mserv_mp3info_readlen(const char *fn { FILE *f; int bitrate, fs, length, headerlen; - long int filelen; + long int filelen, skipped; float mean_frame_size; char tag[3]; unsigned char data[4]; unsigned long int flags; - int errnok; + int errnok, found; char *e; if (id3tag) @@ -281,15 +310,39 @@ int mserv_mp3info_readlen(const char *fn if ((headerlen = mp3_id3v2head(f)) == -1) goto error; - if (fseek(f, headerlen, SEEK_SET) == -1 || fread(&data, 4, 1, f) != 1) + if (fseek(f, headerlen, SEEK_SET) == -1 || fread(&data[0], 1, 1, f) != 1) { + LOGF(("%s: can't read after headerlen %d\n", fname, headerlen)); goto error; + } - /* endian independent to 32-bit flags */ - flags = (data[0]<<24)+(data[1]<<16)+(data[2]<<8)+data[3]; - if (!is_mp3(flags)) { - errno = EDOM; + found = skipped = 0; + for (;;) { + while (data[0] != 0xff) { + /* skip junk at beginning or after header - happens quite often */ + if (fread(&data[0], 1, 1, f) != 1) + goto error; + skipped++; + if (headerlen < 1 && skipped > 4096) + break; /* we are not sure this even is a mp3 file */ + } + if (fread(&data[1], 1, 3, f) != 3) + goto error; + + /* endian independent to 32-bit flags */ + flags = (data[0]<<24)+(data[1]<<16)+(data[2]<<8)+data[3]; + if (is_mp3(flags)) { + found = 1; + break; + } + if (headerlen < 1 && skipped > 4096) + break; /* we are not sure this even is a mp3 file */ + } + if (!found) { + LOGF(("%s: no header found within 4k\n", fname)); goto error; } + if (skipped) + LOGF(("%s: skipped %ld bytes\n", fname, skipped)); bitrate = bitrate_table[h_id(flags)][3-h_layer(flags)] [h_bitrate_index(flags)]; @@ -312,38 +365,44 @@ int mserv_mp3info_readlen(const char *fn if (id3tag) { id3tag_disc tag_disc; + int len; if (fread(&tag_disc, 1, 125, f) != 125) goto error; id3tag->present = 1; - memcpy(id3tag->title, tag_disc.title, MP3ID3_TITLELEN); - id3tag->title[MP3ID3_TITLELEN] = '\0'; + len = min(MP3ID3_TITLELEN, sizeof(tag_disc.title)); + memcpy(id3tag->title, tag_disc.title, len); + id3tag->title[len] = '\0'; e = id3tag->title + strlen(id3tag->title); while (e > id3tag->title && *(e-1) == ' ') *--e = '\0'; - memcpy(id3tag->artist, tag_disc.artist, MP3ID3_ARTISTLEN); - id3tag->artist[MP3ID3_ARTISTLEN] = '\0'; + len = min(MP3ID3_ARTISTLEN, sizeof(tag_disc.artist)); + memcpy(id3tag->artist, tag_disc.artist, len); + id3tag->artist[len] = '\0'; e = id3tag->artist + strlen(id3tag->artist); while (e > id3tag->artist && *(e-1) == ' ') *--e = '\0'; - memcpy(id3tag->album, tag_disc.album, MP3ID3_ALBUMLEN); - id3tag->album[MP3ID3_ALBUMLEN] = '\0'; + len = min(MP3ID3_ALBUMLEN, sizeof(tag_disc.album)); + memcpy(id3tag->album, tag_disc.album, len); + id3tag->album[len] = '\0'; e = id3tag->album + strlen(id3tag->album); while (e > id3tag->album && *(e-1) == ' ') *--e = '\0'; - memcpy(id3tag->year, tag_disc.year, MP3ID3_YEARLEN); - id3tag->year[MP3ID3_YEARLEN] = '\0'; + len = min(MP3ID3_YEARLEN, sizeof(tag_disc.year)); + memcpy(id3tag->year, tag_disc.year, len); + id3tag->year[len] = '\0'; e = id3tag->year + strlen(id3tag->year); while (e > id3tag->year && *(e-1) == ' ') *--e = '\0'; - memcpy(id3tag->comment, tag_disc.comment, MP3ID3_COMMENTLEN); - id3tag->comment[MP3ID3_COMMENTLEN] = '\0'; + len = min(MP3ID3_COMMENTLEN, sizeof(tag_disc.comment)); + memcpy(id3tag->comment, tag_disc.comment, len); + id3tag->comment[len] = '\0'; e = id3tag->comment + strlen(id3tag->comment); while (e > id3tag->comment && *(e-1) == ' ') *--e = '\0'; @@ -395,3 +454,32 @@ int mserv_mp3info_readlen(const char *fn errno = errnok; return -1; } + +#ifdef STANDALONE +int main(int argc, char **argv) +{ + t_id3tag tag; + int bitrate, len; + + if (argc < 2) { + printf("usage: minfo (filename)\n"); + return 1; + } + len = mserv_mp3info_readlen(argv[1], &bitrate, &tag); + if (len < 0) { + printf("no mp3 found\n"); + } else { + if (bitrate) + printf("bitrate %d kbit/s, estimated length " + "%d:%02d.%02d s\n", + bitrate, len/6000, (len%6000)/100, len%100); + if (tag.present) { + printf("title: %s\n", tag.title); + printf("album: %s\n", tag.album); + printf("artist: %s\n", tag.artist); + printf("year: %s\n", tag.year); + } + } + return 0; +} +#endif