~moody/mpl

80067ce095cccd88ab3212819445a930355cd4bb — Moody 1 year, 3 months ago d4c4de3
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
3 files changed, 90 insertions(+), 1 deletions(-)

M dir.c
M fncs.h
M id3.c
M dir.c => dir.c +3 -1
@@ 44,7 44,9 @@ done:
		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 */

M fncs.h => fncs.h +1 -0
@@ 13,6 13,7 @@ int		runecstrcmp(Rune*,Rune*);

/* id3.c */
ID3v1*	readid3(int);
ID3v1*	readid3v2(int);
void	destroyid3(ID3v1 *id);

/* vorbis.c */

M id3.c => id3.c +86 -0
@@ 19,6 19,92 @@ fillnotag(ID3v1 *id, int fd)
	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)
{