shithub: libtags

ref: f68e997ecefd77b3d1cd33c21264d5ced6e5d021
dir: /wav.c/

View raw version
#include "tagspriv.h"

#define le16u(d) (uint16_t)((d)[0] | (d)[1]<<8)

static const struct {
	char *s;
	int type;
}t[] = {
	{"IART", Tartist},
	{"ICRD", Tdate},
	{"IGNR", Tgenre},
	{"INAM", Ttitle},
	{"IPRD", Talbum},
	{"ITRK", Ttrack},
	{"ICMT", Tcomment},
	{"????", Tunknown},
};

int
tagwav(Tagctx *ctx)
{
	uint8_t *d;
	int i, n, info, csz, x, sz;

	d = (uint8_t*)ctx->buf;

	sz = 1;
	info = 0;
	for(i = 0; sz > 0; i++){
		if(ctx->read(ctx, d, 4+4+(i?0:4)) != 4+4+(i?0:4))
			return -1;
		if(i == 0){
			if(memcmp(d, "RIFF", 4) != 0 || memcmp(d+8, "WAVE", 4) != 0)
				return -1;
			sz = leuint(d+4);
			if(sz < 4)
				return -1;
			sz -= 4;
			continue;
		}else if(memcmp(d, "INFO", 4) == 0){
			info = 1;
			ctx->seek(ctx, -4, 1);
			continue;
		}

		if(sz <= 8)
			break;
		sz -= 4+4;
		csz = leuint(d+4);
		if(sz < csz || csz < 0)
			break;
		sz -= csz;

		if(i == 1){
			if(memcmp(d, "fmt ", 4) != 0 || csz < 16)
				return -1;
			if(ctx->read(ctx, d, 16) != 16)
				return -1;
			csz -= 16;
			ctx->channels = le16u(d+2);
			ctx->samplerate = leuint(d+4);
			x = leuint(d+8);
			if(ctx->channels < 1 || ctx->samplerate < 1 || x < 1)
				return -1;
			ctx->duration = sz*1000 / x;
		}else if(memcmp(d, "LIST", 4) == 0){
			if(csz < 4)
				return -1;
			sz = csz - 4;
			continue;
		}else if(info && csz < ctx->bufsz-5){
			for(n = 0; n < nelem(t); n++){
				if(memcmp(d, t[n].s, 4) == 0 || t[n].type == Tunknown){
					if(ctx->read(ctx, d+5, csz) != csz)
						return -1;
					d[4] = 0;
					d[5+csz] = 0;
					txtcb(ctx, t[n].type, t[n].type == Tunknown ? (char*)d : "", d+5);
					csz = 0;
					break;
				}
			}
			if(n < nelem(t))
				continue;
		}

		if(ctx->seek(ctx, csz, 1) < 0)
			return -1;
	}

	/* some software may append an id3v2 tag */
	if(i > 0 && ctx->read(ctx, d, 8) == 8 && memcmp(d, "id3 ", 4) == 0)
		tagid3v2(ctx);

	return i > 0 ? 0 : -1;
}