/[svn]/libgig/trunk/src/RIFF.cpp
ViewVC logotype

Diff of /libgig/trunk/src/RIFF.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2675 by schoenebeck, Sun Sep 14 16:07:34 2014 UTC revision 2685 by schoenebeck, Sat Jan 3 21:44:42 2015 UTC
# Line 54  namespace RIFF { Line 54  namespace RIFF {
54    
55    
56    
57    // *************** progress_t ***************
58    // *
59    
60        progress_t::progress_t() {
61            callback    = NULL;
62            custom      = NULL;
63            __range_min = 0.0f;
64            __range_max = 1.0f;
65        }
66    
67    
68    
69  // *************** Chunk **************  // *************** Chunk **************
70  // *  // *
71    
# Line 290  namespace RIFF { Line 302  namespace RIFF {
302          if (ulPos + WordCount * WordSize >= CurrentChunkSize) WordCount = (CurrentChunkSize - ulPos) / WordSize;          if (ulPos + WordCount * WordSize >= CurrentChunkSize) WordCount = (CurrentChunkSize - ulPos) / WordSize;
303          #if POSIX          #if POSIX
304          if (lseek(pFile->hFileRead, ulStartPos + ulPos, SEEK_SET) < 0) return 0;          if (lseek(pFile->hFileRead, ulStartPos + ulPos, SEEK_SET) < 0) return 0;
305          unsigned long readWords = read(pFile->hFileRead, pData, WordCount * WordSize);          ssize_t readWords = read(pFile->hFileRead, pData, WordCount * WordSize);
306          if (readWords < 1) return 0;          if (readWords < 1) {
307                #if DEBUG
308                std::cerr << "POSIX read() failed: " << strerror(errno) << std::endl << std::flush;
309                #endif // DEBUG
310                return 0;
311            }
312          readWords /= WordSize;          readWords /= WordSize;
313          #elif defined(WIN32)          #elif defined(WIN32)
314          if (SetFilePointer(pFile->hFileRead, ulStartPos + ulPos, NULL/*32 bit*/, FILE_BEGIN) == INVALID_SET_FILE_POINTER) return 0;          if (SetFilePointer(pFile->hFileRead, ulStartPos + ulPos, NULL/*32 bit*/, FILE_BEGIN) == INVALID_SET_FILE_POINTER) return 0;
# Line 301  namespace RIFF { Line 318  namespace RIFF {
318          readWords /= WordSize;          readWords /= WordSize;
319          #else // standard C functions          #else // standard C functions
320          if (fseek(pFile->hFileRead, ulStartPos + ulPos, SEEK_SET)) return 0;          if (fseek(pFile->hFileRead, ulStartPos + ulPos, SEEK_SET)) return 0;
321          unsigned long readWords = fread(pData, WordSize, WordCount, pFile->hFileRead);          size_t readWords = fread(pData, WordSize, WordCount, pFile->hFileRead);
322          #endif // POSIX          #endif // POSIX
323          if (!pFile->bEndianNative && WordSize != 1) {          if (!pFile->bEndianNative && WordSize != 1) {
324              switch (WordSize) {              switch (WordSize) {
# Line 839  namespace RIFF { Line 856  namespace RIFF {
856       *                     chunk should be written to       *                     chunk should be written to
857       * @param ulCurrentDataOffset - offset of current (old) data within       * @param ulCurrentDataOffset - offset of current (old) data within
858       *                              the file       *                              the file
859         * @param pProgress - optional: callback function for progress notification
860       * @returns new write position in the "physical" file, that is       * @returns new write position in the "physical" file, that is
861       *          \a ulWritePos incremented by this chunk's new size       *          \a ulWritePos incremented by this chunk's new size
862       *          (including its header size of course)       *          (including its header size of course)
863       */       */
864      unsigned long Chunk::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset) {      unsigned long Chunk::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset, progress_t* pProgress) {
865          const unsigned long ulOriginalPos = ulWritePos;          const unsigned long ulOriginalPos = ulWritePos;
866          ulWritePos += CHUNK_HEADER_SIZE;          ulWritePos += CHUNK_HEADER_SIZE;
867    
# Line 909  namespace RIFF { Line 927  namespace RIFF {
927          CurrentChunkSize = NewChunkSize;          CurrentChunkSize = NewChunkSize;
928          WriteHeader(ulOriginalPos);          WriteHeader(ulOriginalPos);
929    
930            __notify_progress(pProgress, 1.0); // notify done
931    
932          // update chunk's position pointers          // update chunk's position pointers
933          ulStartPos = ulOriginalPos + CHUNK_HEADER_SIZE;          ulStartPos = ulOriginalPos + CHUNK_HEADER_SIZE;
934          ulPos      = 0;          ulPos      = 0;
# Line 1336  namespace RIFF { Line 1356  namespace RIFF {
1356          #endif // POSIX          #endif // POSIX
1357      }      }
1358    
1359      void List::LoadSubChunks() {      void List::LoadSubChunks(progress_t* pProgress) {
1360         #if DEBUG         #if DEBUG
1361         std::cout << "List::LoadSubChunks()";         std::cout << "List::LoadSubChunks()";
1362         #endif // DEBUG         #endif // DEBUG
# Line 1371  namespace RIFF { Line 1391  namespace RIFF {
1391              }              }
1392              SetPos(uiOriginalPos); // restore position before this call              SetPos(uiOriginalPos); // restore position before this call
1393          }          }
1394            __notify_progress(pProgress, 1.0); // notify done
1395      }      }
1396    
1397      void List::LoadSubChunksRecursively() {      void List::LoadSubChunksRecursively(progress_t* pProgress) {
1398          for (List* pList = GetFirstSubList(); pList; pList = GetNextSubList())          const int n = CountSubLists();
1399              pList->LoadSubChunksRecursively();          int i = 0;
1400            for (List* pList = GetFirstSubList(); pList; pList = GetNextSubList(), ++i) {
1401                // divide local progress into subprogress
1402                progress_t subprogress;
1403                __divide_progress(pProgress, &subprogress, n, i);
1404                // do the actual work
1405                pList->LoadSubChunksRecursively(&subprogress);
1406            }
1407            __notify_progress(pProgress, 1.0); // notify done
1408      }      }
1409    
1410      /** @brief Write list chunk persistently e.g. to disk.      /** @brief Write list chunk persistently e.g. to disk.
# Line 1388  namespace RIFF { Line 1417  namespace RIFF {
1417       *                     list chunk should be written to       *                     list chunk should be written to
1418       * @param ulCurrentDataOffset - offset of current (old) data within       * @param ulCurrentDataOffset - offset of current (old) data within
1419       *                              the file       *                              the file
1420         * @param pProgress - optional: callback function for progress notification
1421       * @returns new write position in the "physical" file, that is       * @returns new write position in the "physical" file, that is
1422       *          \a ulWritePos incremented by this list chunk's new size       *          \a ulWritePos incremented by this list chunk's new size
1423       *          (including its header size of course)       *          (including its header size of course)
1424       */       */
1425      unsigned long List::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset) {      unsigned long List::WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset, progress_t* pProgress) {
1426          const unsigned long ulOriginalPos = ulWritePos;          const unsigned long ulOriginalPos = ulWritePos;
1427          ulWritePos += LIST_HEADER_SIZE;          ulWritePos += LIST_HEADER_SIZE;
1428    
# Line 1401  namespace RIFF { Line 1431  namespace RIFF {
1431    
1432          // write all subchunks (including sub list chunks) recursively          // write all subchunks (including sub list chunks) recursively
1433          if (pSubChunks) {          if (pSubChunks) {
1434              for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {              int i = 0;
1435                  ulWritePos = (*iter)->WriteChunk(ulWritePos, ulCurrentDataOffset);              const int n = pSubChunks->size();
1436                for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter, ++i) {
1437                    // divide local progress into subprogress for loading current Instrument
1438                    progress_t subprogress;
1439                    __divide_progress(pProgress, &subprogress, n, i);
1440                    // do the actual work
1441                    ulWritePos = (*iter)->WriteChunk(ulWritePos, ulCurrentDataOffset, &subprogress);
1442              }              }
1443          }          }
1444    
# Line 1413  namespace RIFF { Line 1449  namespace RIFF {
1449          // offset of this list chunk in new written file may have changed          // offset of this list chunk in new written file may have changed
1450          ulStartPos = ulOriginalPos + LIST_HEADER_SIZE;          ulStartPos = ulOriginalPos + LIST_HEADER_SIZE;
1451    
1452             __notify_progress(pProgress, 1.0); // notify done
1453    
1454          return ulWritePos;          return ulWritePos;
1455      }      }
1456    
# Line 1744  namespace RIFF { Line 1782  namespace RIFF {
1782       * than it will have at the end of the saving process, in case chunks       * than it will have at the end of the saving process, in case chunks
1783       * were grown.       * were grown.
1784       *       *
1785         * @param pProgress - optional: callback function for progress notification
1786       * @throws RIFF::Exception if there is an empty chunk or empty list       * @throws RIFF::Exception if there is an empty chunk or empty list
1787       *                         chunk or any kind of IO error occured       *                         chunk or any kind of IO error occured
1788       */       */
1789      void File::Save() {      void File::Save(progress_t* pProgress) {
1790          //TODO: implementation for the case where first chunk is not a global container (List chunk) is not implemented yet (i.e. Korg files)          //TODO: implementation for the case where first chunk is not a global container (List chunk) is not implemented yet (i.e. Korg files)
1791          if (Layout == layout_flat)          if (Layout == layout_flat)
1792              throw Exception("Saving a RIFF file with layout_flat is not implemented yet");              throw Exception("Saving a RIFF file with layout_flat is not implemented yet");
1793    
1794          // make sure the RIFF tree is built (from the original file)          // make sure the RIFF tree is built (from the original file)
1795          LoadSubChunksRecursively();          {
1796                // divide progress into subprogress
1797                progress_t subprogress;
1798                __divide_progress(pProgress, &subprogress, 3.f, 0.f); // arbitrarily subdivided into 1/3 of total progress
1799                // do the actual work
1800                LoadSubChunksRecursively(&subprogress);
1801                // notify subprogress done
1802                __notify_progress(&subprogress, 1.f);
1803            }
1804    
1805          // reopen file in write mode          // reopen file in write mode
1806          SetMode(stream_mode_read_write);          SetMode(stream_mode_read_write);
# Line 1781  namespace RIFF { Line 1828  namespace RIFF {
1828    
1829          // if there are positive size changes...          // if there are positive size changes...
1830          if (ulPositiveSizeDiff > 0) {          if (ulPositiveSizeDiff > 0) {
1831                // divide progress into subprogress
1832                progress_t subprogress;
1833                __divide_progress(pProgress, &subprogress, 3.f, 1.f); // arbitrarily subdivided into 1/3 of total progress
1834    
1835              // ... we enlarge this file first ...              // ... we enlarge this file first ...
1836              ulWorkingFileSize += ulPositiveSizeDiff;              ulWorkingFileSize += ulPositiveSizeDiff;
1837              ResizeFile(ulWorkingFileSize);              ResizeFile(ulWorkingFileSize);
# Line 1792  namespace RIFF { Line 1843  namespace RIFF {
1843              #else              #else
1844              int iBytesMoved = 1;              int iBytesMoved = 1;
1845              #endif              #endif
1846              for (unsigned long ulPos = ulFileSize; iBytesMoved > 0; ) {              for (unsigned long ulPos = ulFileSize, iNotif = 0; iBytesMoved > 0; ++iNotif) {
1847                  iBytesMoved = (ulPos < 4096) ? ulPos : 4096;                  iBytesMoved = (ulPos < 4096) ? ulPos : 4096;
1848                  ulPos -= iBytesMoved;                  ulPos -= iBytesMoved;
1849                  #if POSIX                  #if POSIX
# Line 1811  namespace RIFF { Line 1862  namespace RIFF {
1862                  fseek(hFileWrite, ulPos + ulPositiveSizeDiff, SEEK_SET);                  fseek(hFileWrite, ulPos + ulPositiveSizeDiff, SEEK_SET);
1863                  iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, hFileWrite);                  iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, hFileWrite);
1864                  #endif                  #endif
1865                    if (!(iNotif % 8) && iBytesMoved > 0)
1866                        __notify_progress(&subprogress, float(ulFileSize - ulPos) / float(ulFileSize));
1867              }              }
1868              delete[] pCopyBuffer;              delete[] pCopyBuffer;
1869              if (iBytesMoved < 0) throw Exception("Could not modify file while trying to enlarge it");              if (iBytesMoved < 0) throw Exception("Could not modify file while trying to enlarge it");
1870    
1871                __notify_progress(&subprogress, 1.f); // notify subprogress done
1872          }          }
1873    
1874          // rebuild / rewrite complete RIFF tree          // rebuild / rewrite complete RIFF tree ...
1875          unsigned long ulTotalSize  = WriteChunk(0, ulPositiveSizeDiff);  
1876            // divide progress into subprogress
1877            progress_t subprogress;
1878            __divide_progress(pProgress, &subprogress, 3.f, 2.f); // arbitrarily subdivided into 1/3 of total progress
1879            // do the actual work
1880            unsigned long ulTotalSize  = WriteChunk(0, ulPositiveSizeDiff, &subprogress);
1881          unsigned long ulActualSize = __GetFileSize(hFileWrite);          unsigned long ulActualSize = __GetFileSize(hFileWrite);
1882            // notify subprogress done
1883            __notify_progress(&subprogress, 1.f);
1884    
1885          // resize file to the final size          // resize file to the final size
1886          if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);          if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1887    
1888          // forget all resized chunks          // forget all resized chunks
1889          resizedChunks->clear();          resizedChunks->clear();
1890    
1891            __notify_progress(pProgress, 1.0); // notify done
1892      }      }
1893    
1894      /** @brief Save changes to another file.      /** @brief Save changes to another file.
# Line 1839  namespace RIFF { Line 1903  namespace RIFF {
1903       * the new file (given by \a path) afterwards.       * the new file (given by \a path) afterwards.
1904       *       *
1905       * @param path - path and file name where everything should be written to       * @param path - path and file name where everything should be written to
1906         * @param pProgress - optional: callback function for progress notification
1907       */       */
1908      void File::Save(const String& path) {      void File::Save(const String& path, progress_t* pProgress) {
1909          //TODO: we should make a check here if somebody tries to write to the same file and automatically call the other Save() method in that case          //TODO: we should make a check here if somebody tries to write to the same file and automatically call the other Save() method in that case
1910    
1911          //TODO: implementation for the case where first chunk is not a global container (List chunk) is not implemented yet (i.e. Korg files)          //TODO: implementation for the case where first chunk is not a global container (List chunk) is not implemented yet (i.e. Korg files)
# Line 1848  namespace RIFF { Line 1913  namespace RIFF {
1913              throw Exception("Saving a RIFF file with layout_flat is not implemented yet");              throw Exception("Saving a RIFF file with layout_flat is not implemented yet");
1914    
1915          // make sure the RIFF tree is built (from the original file)          // make sure the RIFF tree is built (from the original file)
1916          LoadSubChunksRecursively();          {
1917                // divide progress into subprogress
1918                progress_t subprogress;
1919                __divide_progress(pProgress, &subprogress, 2.f, 0.f); // arbitrarily subdivided into 1/2 of total progress
1920                // do the actual work
1921                LoadSubChunksRecursively(&subprogress);
1922                // notify subprogress done
1923                __notify_progress(&subprogress, 1.f);
1924            }
1925    
1926          if (!bIsNewFile) SetMode(stream_mode_read);          if (!bIsNewFile) SetMode(stream_mode_read);
1927          // open the other (new) file for writing and truncate it to zero size          // open the other (new) file for writing and truncate it to zero size
# Line 1879  namespace RIFF { Line 1952  namespace RIFF {
1952          Mode = stream_mode_read_write;          Mode = stream_mode_read_write;
1953    
1954          // write complete RIFF tree to the other (new) file          // write complete RIFF tree to the other (new) file
1955          unsigned long ulTotalSize  = WriteChunk(0, 0);          unsigned long ulTotalSize;
1956            {
1957                // divide progress into subprogress
1958                progress_t subprogress;
1959                __divide_progress(pProgress, &subprogress, 2.f, 1.f); // arbitrarily subdivided into 1/2 of total progress
1960                // do the actual work
1961                ulTotalSize = WriteChunk(0, 0, &subprogress);
1962                // notify subprogress done
1963                __notify_progress(&subprogress, 1.f);
1964            }
1965          unsigned long ulActualSize = __GetFileSize(hFileWrite);          unsigned long ulActualSize = __GetFileSize(hFileWrite);
1966    
1967          // resize file to the final size (if the file was originally larger)          // resize file to the final size (if the file was originally larger)
# Line 1902  namespace RIFF { Line 1984  namespace RIFF {
1984          bIsNewFile = false;          bIsNewFile = false;
1985          Mode = (stream_mode_t) -1;       // Just set it to an undefined mode ...          Mode = (stream_mode_t) -1;       // Just set it to an undefined mode ...
1986          SetMode(stream_mode_read_write); // ... so SetMode() has to reopen the file handles.          SetMode(stream_mode_read_write); // ... so SetMode() has to reopen the file handles.
1987    
1988            __notify_progress(pProgress, 1.0); // notify done
1989      }      }
1990    
1991      void File::ResizeFile(unsigned long ulNewSize) {      void File::ResizeFile(unsigned long ulNewSize) {

Legend:
Removed from v.2675  
changed lines
  Added in v.2685

  ViewVC Help
Powered by ViewVC