shithub: mpl

Download patch

ref: 80067ce095cccd88ab3212819445a930355cd4bb
parent: d4c4de32ca051a3ccfbeebc07de8f6aba27af960
author: Moody <[email protected]>
date: Sat Jun 6 14:05:04 EDT 2020

Add very limited ID3v2 support
This makes mpl capable of reading from ytfs
Currently only utf-8 is supported for text tag encoding
Likewise only TALB and TIT2 tabgs are supported

--- a/dir.c
+++ b/dir.c
@@ -44,7 +44,9 @@
 		s->fmeta = readflacmeta(fd, needpic);
 		break;
 	case MP3:
-		s->idmeta = readid3(fd);
+		s->idmeta = readid3v2(fd);
+		if(s->idmeta == nil)
+			s->idmeta = readid3(fd);
 		break;
 	case VORBIS:
 		/* TODO parse raw ogg file */
--- a/fncs.h
+++ b/fncs.h
@@ -13,6 +13,7 @@
 
 /* id3.c */
 ID3v1*	readid3(int);
+ID3v1*	readid3v2(int);
 void	destroyid3(ID3v1 *id);
 
 /* vorbis.c */
--- a/id3.c
+++ b/id3.c
@@ -19,6 +19,92 @@
 	id->title = runesmprint("%s", slash+1);
 }
 
+/* The following function is stolen from https://git.sr.ht/~ft/libtags/ */
+#define synchsafe(d) (uint)(((d)[0]&127)<<21 | ((d)[1]&127)<<14 | ((d)[2]&127)<<7 | ((d)[3]&127)<<0)
+#define beuint(d) (uint)((d)[0]<<24 | (d)[1]<<16 | (d)[2]<<8 | (d)[3]<<0)
+
+ID3v1*
+readid3v2(int fd)
+{
+	int sz, framesz;
+	int ver;
+	char nu[8];
+	uchar d[10];
+	uchar buf[256];
+	ID3v1 *id;
+
+	read(fd, d, sizeof d);
+
+	ver = d[3];
+	sz = synchsafe(&d[6]);
+
+	if(ver == 2 && (d[5] & (1<<6)) != 0) /* compression */
+		return nil;
+
+	if(ver > 2){
+		if((d[5] & (1<<4)) != 0) /* footer */
+			sz -= 10;
+		if((d[5] & (1<<6)) != 0){ /* we don't do extended header */
+			return nil;
+		}
+	}
+
+	framesz = (ver >= 3) ? 10 : 6;
+
+	id = emalloc(sizeof(ID3v1));
+	id->title = id->album = nil;
+	for(; sz > framesz;){
+		int tsz;
+
+		read(fd, d, framesz);
+		sz -= framesz;
+
+		if(memcmp(d, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", framesz) == 0)
+			break;
+
+		if(ver >= 3){
+			tsz = (ver == 3) ? beuint(&d[4]) : synchsafe(&d[4]);
+			if(tsz < 0 || tsz > sz)
+				break;
+
+			d[4] = 0;
+
+			if((d[9] & 0x0c) != 0){ /* compression & encryption */
+				return nil;
+			}
+		}else{
+			tsz = beuint(&d[3]) >> 8;
+			if(tsz > sz)
+				return nil;
+			d[3] = 0;
+		}
+		sz -= tsz;
+
+		if(memcmp(d, "TIT2", 4) == 0){
+			read(fd, nu, 1);
+			switch(nu[0]){
+			case 3:
+				id->title = emalloc(sizeof(Rune)*tsz);
+				read(fd, buf, tsz-1);
+				runesprint(id->title, "%s", (char*)buf);
+			}
+		}else if(memcmp(d, "TALB", 4) == 0){
+			read(fd, nu, 1);
+			switch(nu[0]){
+			case 3:
+				id->album = emalloc(sizeof(Rune)*tsz);
+				read(fd, buf, tsz-1);
+				runesprint(id->album, "%s", (char*)buf);
+			}
+		}
+	}
+
+	if(id->title == nil || id->album == nil)
+		return nil;
+
+	return id;
+}
+
 ID3v1*
 readid3(int fd)
 {