$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
