1af616388309 — Chris Cannam 3 months ago
Improve error handling in seek; clear eof bit after eof reached on read, so that subsequent seek doesn't fail (this is C++-standard-dependent, I learn)
1 files changed, 82 insertions(+), 10 deletions(-)

M src/SimpleWavFileReadStream.cpp
M src/SimpleWavFileReadStream.cpp +82 -10
@@ 38,6 38,8 @@ 
 
 #include <iostream>
 
+//#define DEBUG_SIMPLE_WAV_FILE_READ_STREAM 1
+
 namespace breakfastquay
 {
 

          
@@ 222,21 224,80 @@ SimpleWavFileReadStream::readChunkSizeAf
 bool
 SimpleWavFileReadStream::performSeek(size_t frame)
 {
+    if (m_file->fail()) {
+#ifdef DEBUG_SIMPLE_WAV_FILE_READ_STREAM
+        std::cerr << "SimpleWavFileReadStream::performSeek: "
+                  << "file is in failure state! failing the seek"
+                  << std::endl;
+#endif
+        return false;
+    }
+    
     int sampleSize = m_bitDepth / 8;
     int frameSize = sampleSize * m_channelCount;
 
-    size_t target = size_t(m_dataReadStart) + frameSize * frame;
-    if (target > m_dataChunkSize + m_dataReadStart) {
+    std::ifstream::off_type target =
+        std::ifstream::off_type(frame * frameSize + m_dataReadStart);
+
+#ifdef DEBUG_SIMPLE_WAV_FILE_READ_STREAM
+    std::cerr << "SimpleWavFileReadStream[" << this << "]::performSeek: frame "
+              << frame << " with frameSize " << frameSize
+              << " and m_dataReadStart " << m_dataReadStart
+              << " gives target " << target << std::endl;
+#endif
+    
+    if (m_dataChunkSize > 0) {
+        // Known size - m_dataChunkSize *should* be >0 but it isn't
+        // always, e.g. when the file is being written as we read
+        if (target > m_dataChunkSize + m_dataReadStart) {
+#ifdef DEBUG_SIMPLE_WAV_FILE_READ_STREAM
+            std::cerr << "SimpleWavFileReadStream::performSeek: seek to "
+                      << target << " is beyond data end "
+                      << m_dataChunkSize + m_dataReadStart
+                      << ", failing the seek" << std::endl;
+#endif
+            return false;
+        }
+    }
+    
+    m_file->seekg(target, std::ios::beg);
+    if (m_file->fail()) {
+#ifdef DEBUG_SIMPLE_WAV_FILE_READ_STREAM
+        std::cerr << "SimpleWavFileReadStream::performSeek: seek to "
+                  << target << " failed (failbit set), failing the seek"
+                  << std::endl;
+#endif
+        return false;
+    }
+    
+    std::ifstream::pos_type actual = m_file->tellg();
+    // (In fact I think tellg() always reports whatever you passed to seekg())
+    if (actual != std::ifstream::pos_type(target)) {
+#ifdef DEBUG_SIMPLE_WAV_FILE_READ_STREAM
+        std::cerr << "SimpleWavFileReadStream::performSeek: seek to "
+                  << target << " brought us to " << actual
+                  << ", failing the seek" << std::endl;
+#endif
         return false;
     }
 
-    m_file->seekg(target, std::ios::beg);
+    if (actual < std::ifstream::pos_type(m_dataReadStart)) {
+#ifdef DEBUG_SIMPLE_WAV_FILE_READ_STREAM
+        std::cerr << "SimpleWavFileReadStream::performSeek: seek to "
+                  << actual << " lands before data start, failing the seek"
+                  << std::endl;
+#endif
+        return false;
+    }
+        
+    m_dataReadOffset = uint32_t(actual -
+                                std::ifstream::pos_type(m_dataReadStart));
+
+#ifdef DEBUG_SIMPLE_WAV_FILE_READ_STREAM
+    std::cerr << "SimpleWavFileReadStream::performSeek: successful, new offset "
+              << m_dataReadOffset << std::endl;;
+#endif
     
-    size_t actual = m_file->tellg();
-    // (In fact I think tellg() always reports whatever you passed to seekg())
-    if (actual != target) return false;
-
-    m_dataReadOffset = uint32_t(actual - m_dataReadStart);
     return true;
 }
 

          
@@ 248,7 309,7 @@ SimpleWavFileReadStream::getFrames(size_
     
     size_t requested = count * m_channelCount;
     size_t got = 0;
-    
+
     while (got < requested) {
         if (m_dataReadOffset >= m_dataChunkSize) {
             break;

          
@@ 256,7 317,7 @@ SimpleWavFileReadStream::getFrames(size_
         int gotHere = getBytes(sampleSize, buf);
         m_dataReadOffset += gotHere;
         if (gotHere < sampleSize) {
-            return got / m_channelCount;
+            break;
         }
         switch (m_bitDepth) {
         case 8: frames[got] = convertSample8(buf); break;

          
@@ 267,6 328,17 @@ SimpleWavFileReadStream::getFrames(size_
         ++got;
     }
 
+    if (got < requested) {
+#ifdef DEBUG_SIMPLE_WAV_FILE_READ_STREAM
+        std::cerr << "SimpleWavFileReadStream::getFrames: EOF reached after "
+                  << got << " of " << requested << " samples" << std::endl;
+#endif
+    }
+
+    if (m_file->eof() && !m_file->bad()) {
+        m_file->clear();
+    }
+    
     return got / m_channelCount;
 }