shithub: sox

Download patch

ref: 2c68f3826ca8b0bb84c28abc13e8decc1e1f273f
parent: 0fc1ff31d5dafcdc0c580d43c4d275c976f469a0
author: Chris Bagwell <chris@cnpbagwell.com>
date: Sun Oct 26 17:30:46 EDT 2014

Work around for libsndfile size bug on RF64

--- a/ChangeLog
+++ b/ChangeLog
@@ -25,6 +25,8 @@
   o Add optional support for reading Ogg Opus files. (John Stumpo)
   o Fix for max size text chunks in aiff files. (cbagwell)
   o Add reading support for RF64 WAV files. (Dave Lambley)
+  o Work around for libsndfile created RF64 files with invalid
+    sizes. (Dave Lambley)
 
 Effects:
 
--- a/src/wav.c
+++ b/src/wav.c
@@ -372,6 +372,44 @@
 /****************************************************************************/
 /* General Sox WAV file code                                                */
 /****************************************************************************/
+
+static int sndfile_workaround(uint64_t *len, sox_format_t *ft) {
+    char magic[5];
+    off_t here;
+
+    here = lsx_tell(ft);
+
+    lsx_debug("Attempting work around for bad ds64 length bug");
+
+    /* Seek to last four bytes of chunk, assuming size is correct. */
+    if (lsx_seeki(ft, (off_t)(*len)-4, SEEK_CUR) != SOX_SUCCESS)
+    {
+        lsx_fail_errno(ft, SOX_EHDR, "WAV chunk appears to have invalid size %ld.", *len);
+        return SOX_EOF;
+    }
+
+    /* Get the last four bytes to see if it is an "fmt " chunk */
+    if (lsx_reads(ft, magic, (size_t)4) == SOX_EOF)
+    {
+        lsx_fail_errno(ft,SOX_EHDR, "WAV chunk appears to have invalid size %ld.", *len);
+        return SOX_EOF;
+    }
+
+    /* Seek back to where we were, which won't work if you're piping */
+    if (lsx_seeki(ft, here, SEEK_SET)!=SOX_SUCCESS)
+    {
+        lsx_fail_errno(ft,SOX_EHDR, "Cannot seek backwards to work around possible broken header.");
+        return SOX_EOF;
+    }
+    if (memcmp(magic, "fmt ", (size_t)4)==0)
+    {
+        /* If the last four bytes were "fmt ", len is almost certainly four bytes too big. */
+        lsx_debug("File had libsndfile bug, working around tell=%ld", lsx_tell(ft));
+        *len -= 4;
+    }
+    return SOX_SUCCESS;
+}
+
 static int findChunk(sox_format_t * ft, const char *Label, uint64_t *len)
 {
     char magic[5];
@@ -410,6 +448,18 @@
         }
         else {
             *len = len_tmp;
+        }
+
+        /* Work around for a bug in libsndfile
+         * https://github.com/erikd/libsndfile/commit/7fa1c57c37844a9d44642ea35e6638238b8af19e#src/rf64.c
+           The ds64 chunk should be 0x1c bytes, not 0x20.
+         */
+        if ((*len) == 0x20 && memcmp(Label, "ds64", (size_t)4)==0)
+        {
+            int fail;
+            if ((fail = sndfile_workaround(len, ft)) != SOX_SUCCESS) {
+                return fail;
+            }
         }
 
         if (memcmp(Label, magic, (size_t)4) == 0)