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)
{