/[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 2120 by persson, Sun Aug 29 11:10:36 2010 UTC revision 2584 by schoenebeck, Sat May 31 20:54:39 2014 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   libgig - C++ cross-platform Gigasampler format file access library    *   *   libgig - C++ cross-platform Gigasampler format file access library    *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003-2009 by Christian Schoenebeck                      *   *   Copyright (C) 2003-2014 by Christian Schoenebeck                      *
6   *                              <cuse@users.sourceforge.net>               *   *                              <cuse@users.sourceforge.net>               *
7   *                                                                         *   *                                                                         *
8   *   This library is free software; you can redistribute it and/or modify  *   *   This library is free software; you can redistribute it and/or modify  *
# Line 281  namespace RIFF { Line 281  namespace RIFF {
281         #if DEBUG         #if DEBUG
282         std::cout << "Chunk::Read(void*,ulong,ulong)" << std::endl;         std::cout << "Chunk::Read(void*,ulong,ulong)" << std::endl;
283         #endif // DEBUG         #endif // DEBUG
284          if (ulStartPos == 0) return 0; // is only 0 if this is a new chunk, so nothing to read (yet)          //if (ulStartPos == 0) return 0; // is only 0 if this is a new chunk, so nothing to read (yet)
285          if (ulPos >= CurrentChunkSize) return 0;          if (ulPos >= CurrentChunkSize) return 0;
286          if (ulPos + WordCount * WordSize >= CurrentChunkSize) WordCount = (CurrentChunkSize - ulPos) / WordSize;          if (ulPos + WordCount * WordSize >= CurrentChunkSize) WordCount = (CurrentChunkSize - ulPos) / WordSize;
287          #if POSIX          #if POSIX
# Line 595  namespace RIFF { Line 595  namespace RIFF {
595      }      }
596    
597      /**      /**
598         * Reads a null-padded string of size characters and copies it
599         * into the string \a s. The position within the chunk will
600         * automatically be incremented.
601         *
602         * @param s                 destination string
603         * @param size              number of characters to read
604         * @throws RIFF::Exception  if an error occured or less than
605         *                          \a size characters could be read!
606         */
607        void Chunk::ReadString(String& s, int size) {
608            char* buf = new char[size];
609            ReadSceptical(buf, 1, size);
610            s.assign(buf, std::find(buf, buf + size, '\0'));
611            delete[] buf;
612        }
613    
614        /**
615       * Writes \a WordCount number of 32 Bit unsigned integer words from the       * Writes \a WordCount number of 32 Bit unsigned integer words from the
616       * buffer pointed by \a pData to the chunk's body, directly to the       * buffer pointed by \a pData to the chunk's body, directly to the
617       * actual "physical" file. The position within the chunk will       * actual "physical" file. The position within the chunk will
# Line 734  namespace RIFF { Line 751  namespace RIFF {
751       * @see ReleaseChunkData()       * @see ReleaseChunkData()
752       */       */
753      void* Chunk::LoadChunkData() {      void* Chunk::LoadChunkData() {
754          if (!pChunkData && pFile->Filename != "" && ulStartPos != 0) {          if (!pChunkData && pFile->Filename != "" /*&& ulStartPos != 0*/) {
755              #if POSIX              #if POSIX
756              if (lseek(pFile->hFileRead, ulStartPos, SEEK_SET) == -1) return NULL;              if (lseek(pFile->hFileRead, ulStartPos, SEEK_SET) == -1) return NULL;
757              #elif defined(WIN32)              #elif defined(WIN32)
# Line 1174  namespace RIFF { Line 1191  namespace RIFF {
1191          return pNewChunk;          return pNewChunk;
1192      }      }
1193    
1194      /** @brief Moves a sub chunk.      /** @brief Moves a sub chunk witin this list.
1195       *       *
1196       * Moves a sub chunk from one position in a list to another       * Moves a sub chunk from one position in this list to another
1197       * position in the same list. The pSrc chunk is placed before the       * position in the same list. The pSrc chunk is placed before the
1198       * pDst chunk.       * pDst chunk.
1199       *       *
# Line 1192  namespace RIFF { Line 1209  namespace RIFF {
1209          pSubChunks->insert(iter, pSrc);          pSubChunks->insert(iter, pSrc);
1210      }      }
1211    
1212        /** @brief Moves a sub chunk from this list to another list.
1213         *
1214         * Moves a sub chunk from this list list to the end of another
1215         * list.
1216         *
1217         * @param pSrc - sub chunk to be moved
1218         * @param pDst - destination list where the chunk shall be moved to
1219         */
1220        void List::MoveSubChunk(Chunk* pSrc, List* pNewParent) {
1221            if (pNewParent == this || !pNewParent) return;
1222            if (!pSubChunks) LoadSubChunks();
1223            if (!pNewParent->pSubChunks) pNewParent->LoadSubChunks();
1224            pSubChunks->remove(pSrc);
1225            pNewParent->pSubChunks->push_back(pSrc);
1226            // update chunk id map of this List
1227            if ((*pSubChunksMap)[pSrc->GetChunkID()] == pSrc) {
1228                pSubChunksMap->erase(pSrc->GetChunkID());
1229                // try to find another chunk of the same chunk ID
1230                ChunkList::iterator iter = pSubChunks->begin();
1231                ChunkList::iterator end  = pSubChunks->end();
1232                for (; iter != end; ++iter) {
1233                    if ((*iter)->GetChunkID() == pSrc->GetChunkID()) {
1234                        (*pSubChunksMap)[pSrc->GetChunkID()] = *iter;
1235                        break; // we're done, stop search
1236                    }
1237                }
1238            }
1239            // update chunk id map of other list
1240            if (!(*pNewParent->pSubChunksMap)[pSrc->GetChunkID()])
1241                (*pNewParent->pSubChunksMap)[pSrc->GetChunkID()] = pSrc;
1242        }
1243    
1244      /** @brief Creates a new list sub chunk.      /** @brief Creates a new list sub chunk.
1245       *       *
1246       * Creates and adds a new list sub chunk to this list chunk. Note that       * Creates and adds a new list sub chunk to this list chunk. Note that
# Line 1402  namespace RIFF { Line 1451  namespace RIFF {
1451       * @param FileType - four-byte identifier of the RIFF file type       * @param FileType - four-byte identifier of the RIFF file type
1452       * @see AddSubChunk(), AddSubList(), SetByteOrder()       * @see AddSubChunk(), AddSubList(), SetByteOrder()
1453       */       */
1454      File::File(uint32_t FileType) : List(this) {      File::File(uint32_t FileType)
1455            : List(this), bIsNewFile(true), Layout(layout_standard)
1456        {
1457          //HACK: see _GET_RESIZED_CHUNKS() comment          //HACK: see _GET_RESIZED_CHUNKS() comment
1458          ResizedChunks.push_back(reinterpret_cast<Chunk*>(new std::set<Chunk*>));          ResizedChunks.push_back(reinterpret_cast<Chunk*>(new std::set<Chunk*>));
1459          #if defined(WIN32)          #if defined(WIN32)
# Line 1424  namespace RIFF { Line 1475  namespace RIFF {
1475       * @throws RIFF::Exception if error occured while trying to load the       * @throws RIFF::Exception if error occured while trying to load the
1476       *                         given RIFF file       *                         given RIFF file
1477       */       */
1478      File::File(const String& path) : List(this), Filename(path) {      File::File(const String& path)
1479        #if DEBUG          : List(this), Filename(path), bIsNewFile(false), Layout(layout_standard)
1480        std::cout << "File::File("<<path<<")" << std::endl;      {
1481        #endif // DEBUG         #if DEBUG
1482           std::cout << "File::File("<<path<<")" << std::endl;
1483           #endif // DEBUG
1484          bEndianNative = true;          bEndianNative = true;
1485            try {
1486                __openExistingFile(path);
1487                if (ChunkID != CHUNK_ID_RIFF && ChunkID != CHUNK_ID_RIFX) {
1488                    throw RIFF::Exception("Not a RIFF file");
1489                }
1490            }
1491            catch (...) {
1492                Cleanup();
1493                throw;
1494            }
1495        }
1496    
1497        /** @brief Load existing RIFF-like file.
1498         *
1499         * Loads an existing file, which is not a "real" RIFF file, but similar to
1500         * an ordinary RIFF file.
1501         *
1502         * A "real" RIFF file contains at top level a List chunk either with chunk
1503         * ID "RIFF" or "RIFX". The simple constructor above expects this to be
1504         * case, and if it finds the toplevel List chunk to have another chunk ID
1505         * than one of those two expected ones, it would throw an Exception and
1506         * would refuse to load the file accordingly.
1507         *
1508         * Since there are however a lot of file formats which use the same simple
1509         * principles of the RIFF format, with another toplevel List chunk ID
1510         * though, you can use this alternative constructor here to be able to load
1511         * and handle those files in the same way as you would do with "real" RIFF
1512         * files.
1513         *
1514         * @param path - path and file name of the RIFF-alike file to be opened
1515         * @param FileType - expected toplevel List chunk ID (this is the very
1516         *                   first chunk found in the file)
1517         * @param Endian - whether the file uses little endian or big endian layout
1518         * @param layout - general file structure type
1519         * @throws RIFF::Exception if error occured while trying to load the
1520         *                         given RIFF-alike file
1521         */
1522        File::File(const String& path, uint32_t FileType, endian_t Endian, layout_t layout)
1523            : List(this), Filename(path), bIsNewFile(false), Layout(layout)
1524        {
1525            SetByteOrder(Endian);
1526            try {
1527                __openExistingFile(path, &FileType);
1528            }
1529            catch (...) {
1530                Cleanup();
1531                throw;
1532            }
1533        }
1534    
1535        /**
1536         * Opens an already existing RIFF file or RIFF-alike file. This method
1537         * shall only be called once (in a File class constructor).
1538         *
1539         * @param path - path and file name of the RIFF file or RIFF-alike file to
1540         *               be opened
1541         * @param FileType - (optional) expected chunk ID of first chunk in file
1542         * @throws RIFF::Exception if error occured while trying to load the
1543         *                         given RIFF file or RIFF-alike file
1544         */
1545        void File::__openExistingFile(const String& path, uint32_t* FileType) {
1546          //HACK: see _GET_RESIZED_CHUNKS() comment          //HACK: see _GET_RESIZED_CHUNKS() comment
1547          ResizedChunks.push_back(reinterpret_cast<Chunk*>(new std::set<Chunk*>));          ResizedChunks.push_back(reinterpret_cast<Chunk*>(new std::set<Chunk*>));
1548          #if POSIX          #if POSIX
# Line 1454  namespace RIFF { Line 1568  namespace RIFF {
1568          if (!hFileRead) throw RIFF::Exception("Can't open \"" + path + "\"");          if (!hFileRead) throw RIFF::Exception("Can't open \"" + path + "\"");
1569          #endif // POSIX          #endif // POSIX
1570          Mode = stream_mode_read;          Mode = stream_mode_read;
1571          ulStartPos = RIFF_HEADER_SIZE;          switch (Layout) {
1572          ReadHeader(0);              case layout_standard: // this is a normal RIFF file
1573          if (ChunkID != CHUNK_ID_RIFF && ChunkID != CHUNK_ID_RIFX) {                  ulStartPos = RIFF_HEADER_SIZE;
1574              throw RIFF::Exception("Not a RIFF file");                  ReadHeader(0);
1575                    if (FileType && ChunkID != *FileType)
1576                        throw RIFF::Exception("Invalid file container ID");
1577                    break;
1578                case layout_flat: // non-standard RIFF-alike file
1579                    ulStartPos = 0;
1580                    NewChunkSize = CurrentChunkSize = GetFileSize();
1581                    if (FileType) {
1582                        uint32_t ckid;
1583                        if (Read(&ckid, 4, 1) != 4) {
1584                            throw RIFF::Exception("Invalid file header ID (premature end of header)");
1585                        } else if (ckid != *FileType) {
1586                            String s = " (expected '" + convertToString(*FileType) + "' but got '" + convertToString(ckid) + "')";
1587                            throw RIFF::Exception("Invalid file header ID" + s);
1588                        }
1589                        SetPos(0); // reset to first byte of file
1590                    }
1591                    LoadSubChunks();
1592                    break;
1593          }          }
1594      }      }
1595    
1596      String File::GetFileName() {      String File::GetFileName() {
1597          return Filename;          return Filename;
1598      }      }
1599        
1600        void File::SetFileName(const String& path) {
1601            Filename = path;
1602        }
1603    
1604      stream_mode_t File::GetMode() {      stream_mode_t File::GetMode() {
1605          return Mode;          return Mode;
1606      }      }
1607    
1608        layout_t File::GetLayout() const {
1609            return Layout;
1610        }
1611    
1612      /** @brief Change file access mode.      /** @brief Change file access mode.
1613       *       *
1614       * Changes files access mode either to read-only mode or to read/write       * Changes files access mode either to read-only mode or to read/write
# Line 1601  namespace RIFF { Line 1741  namespace RIFF {
1741       *                         chunk or any kind of IO error occured       *                         chunk or any kind of IO error occured
1742       */       */
1743      void File::Save() {      void File::Save() {
1744            //TODO: implementation for the case where first chunk is not a global container (List chunk) is not implemented yet (i.e. Korg files)
1745            if (Layout == layout_flat)
1746                throw Exception("Saving a RIFF file with layout_flat is not implemented yet");
1747    
1748          // make sure the RIFF tree is built (from the original file)          // make sure the RIFF tree is built (from the original file)
1749          LoadSubChunksRecursively();          LoadSubChunksRecursively();
1750    
# Line 1692  namespace RIFF { Line 1836  namespace RIFF {
1836      void File::Save(const String& path) {      void File::Save(const String& path) {
1837          //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
1838    
1839            //TODO: implementation for the case where first chunk is not a global container (List chunk) is not implemented yet (i.e. Korg files)
1840            if (Layout == layout_flat)
1841                throw Exception("Saving a RIFF file with layout_flat is not implemented yet");
1842    
1843          // make sure the RIFF tree is built (from the original file)          // make sure the RIFF tree is built (from the original file)
1844          LoadSubChunksRecursively();          LoadSubChunksRecursively();
1845    
1846          if (Filename.length() > 0) SetMode(stream_mode_read);          if (!bIsNewFile) SetMode(stream_mode_read);
1847          // 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
1848          #if POSIX          #if POSIX
1849          hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);          hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
# Line 1743  namespace RIFF { Line 1891  namespace RIFF {
1891    
1892          // associate new file with this File object from now on          // associate new file with this File object from now on
1893          Filename = path;          Filename = path;
1894            bIsNewFile = false;
1895          Mode = (stream_mode_t) -1;       // Just set it to an undefined mode ...          Mode = (stream_mode_t) -1;       // Just set it to an undefined mode ...
1896          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.
1897      }      }
# Line 1766  namespace RIFF { Line 1915  namespace RIFF {
1915         #if DEBUG         #if DEBUG
1916         std::cout << "File::~File()" << std::endl;         std::cout << "File::~File()" << std::endl;
1917         #endif // DEBUG         #endif // DEBUG
1918            Cleanup();
1919        }
1920        
1921        /**
1922         * Returns @c true if this file has been created new from scratch and
1923         * has not been stored to disk yet.
1924         */
1925        bool File::IsNew() const {
1926            return bIsNewFile;
1927        }
1928    
1929        void File::Cleanup() {
1930          #if POSIX          #if POSIX
1931          if (hFileRead) close(hFileRead);          if (hFileRead) close(hFileRead);
1932          #elif defined(WIN32)          #elif defined(WIN32)

Legend:
Removed from v.2120  
changed lines
  Added in v.2584

  ViewVC Help
Powered by ViewVC