shithub: cuefs

Download patch

ref: adb84ba1604eca9fbacc16b1eede182a107562ca
parent: 448e84898530e6f597db845c72ea66e372374558
author: Tevo <estevan.cps@gmail.com>
date: Wed Dec 23 19:04:34 EST 2020

Fix timestamps, don't allow reads after the end of the song

--- /dev/null
+++ b/BUGS
@@ -1,0 +1,4 @@
+• unsure if seeking on a file works correctly
+• crashes on unmount (buffer overflow caught by free())
+• current treatment of lossy sources is less than ideal
+• can only serve .wav and raw pcm files (no flac encoder)
--- a/cue.c
+++ b/cue.c
@@ -48,7 +48,11 @@
 	if(cur == nil)
 		return;
 	recfreeentries(s, cur->next);
-	maybefree(nil, cur->starts);
+	for(Start *s = cur->starts; s != nil; s = cur->starts)
+	{
+		cur->starts = s->next;
+		free(s);
+	}
 	/* file should get freed by the cuesheet */
 	maybefree(nil, cur->title);
 	maybefree(s->performer, cur->performer);
@@ -103,15 +107,6 @@
 }
 
 void
-atleast(Timestamps *ts, int val)
-{
-	if(ts->maxindex > val)
-		return;
-	ts->starts = erealloc(ts->starts, (val+1) * sizeof(*ts->starts));
-	ts->maxindex = val;
-}
-
-void
 setperformer(Cuesheet *c, char *artist)
 {
 	artist = strdup(artist);
@@ -175,12 +170,28 @@
 void
 settimestamp(Cuesheet *c, int i, Timestamp t)
 {
+	Start *entry, *before;
+
 	if(c->curentry == nil)
 		parserfatal("timestamp outside of track");
 
-	atleast(c->curentry, i);
 	debug("setting timestamp[%d] for %d as %ud frames\n", i, c->curentry->index, t.frames);
-	c->curentry->starts[i] = t;
+
+	entry = emallocz(sizeof(*entry), 1);
+	entry->Timestamp = t;
+	entry->index = i;
+
+	before = nil;
+
+	if(c->curentry->starts == nil)
+		c->curentry->starts = entry;
+	else
+	{
+		for(Start *s = c->curentry->starts; s != nil && s->index < i; s++)
+			before = s;
+		entry->next = before->next;
+		before->next = entry;
+	}
 }
 
 char*
--- a/cuefs.h
+++ b/cuefs.h
@@ -47,15 +47,16 @@
 	char *name;
 } AFile;
 
-typedef struct
+typedef struct Start
 {
-	Timestamp *starts;
-	u8int maxindex;
-} Timestamps;
+	Timestamp;
+	u8int index;
+	struct Start *next;
+} Start;
 
 typedef struct Entry
 {
-	Timestamps;
+	Start *starts;
 	AFile *file;
 	int index;
 	char *title, *performer;
--- a/fs.c
+++ b/fs.c
@@ -15,7 +15,7 @@
 typedef struct
 {
 	int fd, pid;
-	vlong curoff;
+	vlong curoff, end;
 } Decoder;
 
 void pcmserve(Entry*, Req*);
@@ -35,8 +35,12 @@
 	[WAVE]	= "audio/wavdec"
 };
 
+/* 
+ * FIXME find a better way to signal decoder failure,
+ * one that we can answer the Tread with
+ */
 Decoder*
-pipedec(AFile *f, double sec, vlong off)
+pipedec(AFile *f, double sec, vlong off, vlong end)
 {
 	Decoder *ret;
 	int fd[2], afd;
@@ -52,6 +56,7 @@
 	ret = emalloc(sizeof(*ret));
 	ret->fd = fd[0];
 	ret->curoff = off;
+	ret->end = end;
 
 	switch(ret->pid = rfork(RFPROC|RFFDG|RFREND|RFNOTEG))
 	{
@@ -110,8 +115,17 @@
 long
 readdec(Decoder *dec, void *buf, long count)
 {
-	long ret;
+	long ret, n;
 
+	debug("readdec: decoder offset = %lld, decoder end = %lld, count = %ld\n",
+		dec->curoff, dec->end, count);
+
+	n = dec->end - dec->curoff + count;
+	if(n < 0)
+		count += n;
+
+	debug("reading %ld bytes from pid %d\n", count, dec->pid);
+
 	ret = read(dec->fd, buf, count);
 	dec->curoff += ret;
 
@@ -123,13 +137,22 @@
 {
 	Decoder *dec;
 	double sec;
+	long end;
 
 	sec = t2sec(e->starts[0]) + of2sec(44100, 16, 2, r->ifcall.offset);
 
+	/*
+	 * wouldn't be that bad to just read and throw away a little of the
+	 * decoded pcm if r->ifcall.offset isn't that far from dec->curoff
+	 */
 	if((dec = r->fid->aux) == nil || dec->curoff != r->ifcall.offset)
 	{
+		/* amount of samples between songs... */
+		end = (e->next->starts->frames - e->starts->frames) * (44100/75);
+		/* ...*2 channels, 2 bytes per sample */
+		end *= 2*2;
 		closedec(dec);
-		dec = r->fid->aux = pipedec(e->file, sec, r->ifcall.offset);
+		dec = r->fid->aux = pipedec(e->file, sec, r->ifcall.offset, end);
 	}
 
 	r->ofcall.count = readdec(dec, r->ofcall.data, r->ifcall.count);