From 281d0fd48965b973ca69a432b2a9bf0152ae9023 Mon Sep 17 00:00:00 2001 Message-Id: <281d0fd48965b973ca69a432b2a9bf0152ae9023.1714622750.git.mdw@distorted.org.uk> From: Mark Wooding Date: Mon, 7 Jun 2010 20:40:46 +0100 Subject: [PATCH] WAV hands-off reading. Hands-off readering code built into tracklength plugin. Organization: Straylight/Edgeware From: Richard Kettlewell --- lib/hreader.c | 56 ++++++++++++++++++++++++++------------------- lib/hreader.h | 24 ++++++++----------- lib/wav.c | 21 ++++++----------- lib/wav.h | 6 +++-- plugins/Makefile.am | 2 +- 5 files changed, 54 insertions(+), 55 deletions(-) diff --git a/lib/hreader.c b/lib/hreader.c index 5973375..9bcc808 100644 --- a/lib/hreader.c +++ b/lib/hreader.c @@ -23,6 +23,8 @@ #include #include +static int hreader_fill(struct hreader *h, off_t offset); + void hreader_init(const char *path, struct hreader *h) { memset(h, 0, sizeof *h); h->path = xstrdup(path); @@ -31,43 +33,51 @@ void hreader_init(const char *path, struct hreader *h) { } int hreader_read(struct hreader *h, void *buffer, size_t n) { - if(h->consumed == h->bytes) { - int r; + int r = hreader_pread(h, buffer, n, h->read_offset); + if(r > 0) + h->read_offset += r; + return r; +} - if((r = hreader_fill(h)) <= 0) - return r; +int hreader_pread(struct hreader *h, void *buffer, size_t n, off_t offset) { + size_t bytes_read = 0; + + while(bytes_read < n) { + // If the desired byte range is outside the file, fetch new contents + if(offset < h->buf_offset || offset >= h->buf_offset + (off_t)h->bytes) { + int r = hreader_fill(h, offset); + if(r < 0) + return -1; /* disaster! */ + else if(r == 0) + break; /* end of file */ + } + // Figure out how much we can read this time round + size_t left = h->bytes - (offset - h->buf_offset); + // Truncate the read if we don't want that much + if(left > (n - bytes_read)) + left = n - bytes_read; + memcpy((char *)buffer + bytes_read, + h->buffer + (offset - h->buf_offset), + left); + offset += left; + bytes_read += left; } - if(n > h->bytes - h->consumed) - n = h->bytes - h->consumed; - memcpy(buffer, h->buffer + h->consumed, n); - h->consumed += n; - return n; + return bytes_read; } -int hreader_fill(struct hreader *h) { - if(h->consumed < h->bytes) - return h->bytes - h->consumed; - h->bytes = h->consumed = 0; +static int hreader_fill(struct hreader *h, off_t offset) { int fd = open(h->path, O_RDONLY); if(fd < 0) return -1; - if(lseek(fd, h->offset, SEEK_SET) < 0) { - close(fd); - return -1; - } - int n = read(fd, h->buffer, h->bufsize); + int n = pread(fd, h->buffer, h->bufsize, offset); close(fd); if(n < 0) return -1; + h->buf_offset = offset; h->bytes = n; - h->offset += n; return n; } -void hreader_consume(struct hreader *h, size_t n) { - h->consumed += n; -} - /* Local Variables: c-basic-offset:2 diff --git a/lib/hreader.h b/lib/hreader.h index 1eadc55..8ef3a40 100644 --- a/lib/hreader.h +++ b/lib/hreader.h @@ -29,11 +29,11 @@ */ struct hreader { const char *path; /* file to read */ - off_t offset; /* how far we've read so far */ + off_t read_offset; /* for next hreader_read() */ + off_t buf_offset; /* offset of start of buffer */ char *buffer; /* input buffer */ size_t bufsize; /* buffer size */ size_t bytes; /* size of last read */ - size_t consumed; /* bytes consumed by caller from last read */ }; /** @brief Initialize a hands-off reader @@ -50,20 +50,14 @@ void hreader_init(const char *path, struct hreader *h); */ int hreader_read(struct hreader *h, void *buffer, size_t n); -/** @brief Read more bytes - * @param h Reader to update - * @return Bytes available to read - * - * If not all bytes were consumed so far then just returns the number - * of bytes left to consume. - */ -int hreader_fill(struct hreader *h); - -/** @brief Consume some bytes - * @param h Reader to update - * @param n Bytes to consume +/** @brief Read some bytes at a given offset + * @param h Reader to read from + * @param offset Offset to read at + * @param buffer Where to store bytes + * @param n Maximum bytes to read + * @return Bytes read, or 0 at EOF, or -1 on error */ -void hreader_consume(struct hreader *h, size_t n); +int hreader_pread(struct hreader *h, void *buffer, size_t n, off_t offset); #endif /* HREADER_H */ diff --git a/lib/wav.c b/lib/wav.c index 455bb72..8b2d640 100644 --- a/lib/wav.c +++ b/lib/wav.c @@ -128,9 +128,8 @@ int wav_init(struct wavfile *f, const char *path) { off_t where; memset(f, 0, sizeof *f); - f->fd = -1; f->data = -1; - if((f->fd = open(path, O_RDONLY)) < 0) goto error_errno; + hreader_init(path, f->input); /* Read the file header * * offset size meaning @@ -138,7 +137,7 @@ int wav_init(struct wavfile *f, const char *path) { * 04 4 length of rest of file * 08 4 'WAVE' * */ - if((n = pread(f->fd, header, 12, 0)) < 0) goto error_errno; + if((n = hreader_pread(f->input, header, 12, 0)) < 0) goto error_errno; else if(n < 12) goto einval; if(strncmp(header, "RIFF", 4) || strncmp(header + 8, "WAVE", 4)) goto einval; @@ -151,7 +150,7 @@ int wav_init(struct wavfile *f, const char *path) { * 00 4 chunk ID * 04 4 length of rest of chunk */ - if((n = pread(f->fd, header, 8, where)) < 0) goto error_errno; + if((n = hreader_pread(f->input, header, 8, where)) < 0) goto error_errno; else if(n < 8) goto einval; if(!strncmp(header,"fmt ", 4)) { /* This is the format chunk @@ -168,7 +167,8 @@ int wav_init(struct wavfile *f, const char *path) { * 18 ? extra undocumented rubbish */ if(get32(header + 4) < 16) goto einval; - if((n = pread(f->fd, header + 8, 16, where + 8)) < 0) goto error_errno; + if((n = hreader_pread(f->input, header + 8, 16, where + 8)) < 0) + goto error_errno; else if(n < 16) goto einval; f->channels = get16(header + 0x0A); f->rate = get32(header + 0x0C); @@ -196,14 +196,7 @@ error: } /** @brief Close a WAV file */ -void wav_destroy(struct wavfile *f) { - if(f) { - const int save_errno = errno; - - if(f->fd >= 0) - close(f->fd); - errno = save_errno; - } +void wav_destroy(struct wavfile attribute((unused)) *f) { } /** @brief Visit all the data in a WAV file @@ -227,7 +220,7 @@ int wav_data(struct wavfile *f, size_t want = (off_t)sizeof buffer > left ? (size_t)left : sizeof buffer; want -= want % bytes_per_frame; - if((n = pread(f->fd, buffer, want, where)) < 0) return errno; + if((n = hreader_pread(f->input, buffer, want, where)) < 0) return errno; if((size_t)n < want) return EINVAL; if((err = callback(f, buffer, n, u))) return err; where += n; diff --git a/lib/wav.h b/lib/wav.h index d2de912..3c9c477 100644 --- a/lib/wav.h +++ b/lib/wav.h @@ -22,10 +22,12 @@ #ifndef WAV_H #define WAV_H +#include "hreader.h" + /** @brief WAV file access structure */ struct wavfile { - /** @brief File descriptor onto file */ - int fd; + /** @brief File read handle */ + struct hreader input[1]; /** @brief File length */ off_t length; diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 7852152..410f5ae 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -23,7 +23,7 @@ AM_CPPFLAGS=-I${top_srcdir}/lib notify_la_SOURCES=notify.c notify_la_LDFLAGS=-module -disorder_tracklength_la_SOURCES=tracklength.c mad.c madshim.h ../lib/wav.h ../lib/wav.c +disorder_tracklength_la_SOURCES=tracklength.c mad.c madshim.h ../lib/wav.h ../lib/wav.c ../lib/hreader.h ../lib/hreader.c disorder_tracklength_la_LDFLAGS=-module disorder_tracklength_la_LIBADD=$(LIBVORBISFILE) $(LIBMAD) $(LIBFLAC) -lm -- [mdw]