chiark / gitweb /
WAV hands-off reading.
authorRichard Kettlewell <rjk@greenend.org.uk>
Mon, 7 Jun 2010 19:40:46 +0000 (20:40 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Mon, 7 Jun 2010 19:40:46 +0000 (20:40 +0100)
Hands-off readering code built into tracklength plugin.

lib/hreader.c
lib/hreader.h
lib/wav.c
lib/wav.h
plugins/Makefile.am

index 5973375..9bcc808 100644 (file)
@@ -23,6 +23,8 @@
 #include <string.h>
 #include <fcntl.h>
 
+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
index 1eadc55..8ef3a40 100644 (file)
  */
 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 */
 
index 455bb72..8b2d640 100644 (file)
--- 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;
index d2de912..3c9c477 100644 (file)
--- a/lib/wav.h
+++ b/lib/wav.h
 #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;
index 7852152..410f5ae 100644 (file)
@@ -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