Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

RIFF.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                                                         *
00003  *   libgig - C++ cross-platform Gigasampler format file loader library    *
00004  *                                                                         *
00005  *   Copyright (C) 2003-2005 by Christian Schoenebeck                      *
00006  *                              <cuse@users.sourceforge.net>               *
00007  *                                                                         *
00008  *   This library is free software; you can redistribute it and/or modify  *
00009  *   it under the terms of the GNU General Public License as published by  *
00010  *   the Free Software Foundation; either version 2 of the License, or     *
00011  *   (at your option) any later version.                                   *
00012  *                                                                         *
00013  *   This library is distributed in the hope that it will be useful,       *
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00016  *   GNU General Public License for more details.                          *
00017  *                                                                         *
00018  *   You should have received a copy of the GNU General Public License     *
00019  *   along with this library; if not, write to the Free Software           *
00020  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00021  *   MA  02111-1307  USA                                                   *
00022  ***************************************************************************/
00023 #if 1
00024 #include "RIFF.h"
00025 
00026 namespace RIFF {
00027 
00028 // *************** Chunk **************
00029 // *
00030 
00031     Chunk::Chunk() {
00032         #if DEBUG
00033         std::cout << "Chunk::Chunk()" << std::endl;
00034         #endif // DEBUG
00035         ulPos      = 0;
00036         pParent    = NULL;
00037         pChunkData = NULL;
00038     }
00039 
00040     #if POSIX
00041     Chunk::Chunk(int hFile, unsigned long StartPos, bool EndianNative, List* Parent) {
00042     #else
00043     Chunk::Chunk(FILE* hFile, unsigned long StartPos, bool EndianNative, List* Parent) {
00044     #endif // POSIX
00045         #if DEBUG
00046         std::cout << "Chunk::Chunk(FILE,ulong,bool,List*),StartPos=" << StartPos << std::endl;
00047         #endif // DEBUG
00048         Chunk::hFile  = hFile;
00049         ulStartPos    = StartPos + CHUNK_HEADER_SIZE;
00050         bEndianNative = EndianNative;
00051         pParent       = Parent;
00052         ulPos         = 0;
00053         pChunkData    = NULL;
00054         ReadHeader(StartPos);
00055     }
00056 
00057     Chunk::~Chunk() {
00058         if (pChunkData) delete[] pChunkData;
00059     }
00060 
00061     void Chunk::ReadHeader(unsigned long fPos) {
00062         #if DEBUG
00063         std::cout << "Chunk::Readheader(" << fPos << ") ";
00064         #endif // DEBUG
00065         #if POSIX
00066         if (lseek(hFile, fPos, SEEK_SET) != -1) {
00067             read(hFile, &ChunkID, 4);
00068             read(hFile, &ChunkSize, 4);
00069         #else
00070         if (!fseek(hFile, fPos, SEEK_SET)) {
00071             fread(&ChunkID, 4, 1, hFile);
00072             fread(&ChunkSize, 4, 1, hFile);
00073         #endif // POSIX
00074             #if WORDS_BIGENDIAN
00075             if (ChunkID == CHUNK_ID_RIFF) {
00076                 bEndianNative = false;
00077             }
00078             #else // little endian
00079             if (ChunkID == CHUNK_ID_RIFX) {
00080                 bEndianNative = false;
00081                 ChunkID = CHUNK_ID_RIFF;
00082             }
00083             #endif // WORDS_BIGENDIAN
00084             if (!bEndianNative) {
00085                 //swapBytes_32(&ChunkID);
00086                 swapBytes_32(&ChunkSize);
00087             }
00088             #if DEBUG
00089             std::cout << "ckID=" << convertToString(ChunkID) << " ";
00090             std::cout << "ckSize=" << ChunkSize << " ";
00091             std::cout << "bEndianNative=" << bEndianNative << std::endl;
00092             #endif // DEBUG
00093         }
00094     }
00095 
00100     String Chunk::GetChunkIDString() {
00101         return convertToString(ChunkID);
00102     }
00103 
00113     unsigned long Chunk::SetPos(unsigned long Where, stream_whence_t Whence) {
00114      #if DEBUG
00115      std::cout << "Chunk::SetPos(ulong)" << std::endl;
00116      #endif // DEBUG
00117         switch (Whence) {
00118             case stream_curpos:
00119                 ulPos += Where;
00120                 break;
00121             case stream_end:
00122                 ulPos = ChunkSize - 1 - Where;
00123                 break;
00124             case stream_backward:
00125                 ulPos -= Where;
00126                 break;
00127             case stream_start: default:
00128                 ulPos = Where;
00129                 break;
00130         }
00131         if (ulPos > ChunkSize) ulPos = ChunkSize;
00132         return ulPos;
00133     }
00134 
00145     unsigned long Chunk::RemainingBytes() {
00146        #if DEBUG
00147        std::cout << "Chunk::Remainingbytes()=" << ChunkSize - ulPos << std::endl;
00148        #endif // DEBUG
00149         return ChunkSize - ulPos;
00150     }
00151 
00163     stream_state_t Chunk::GetState() {
00164       #if DEBUG
00165       std::cout << "Chunk::GetState()" << std::endl;
00166       #endif // DEBUG
00167         #if POSIX
00168         if (hFile == 0)        return stream_closed;
00169         #else
00170         if (hFile == NULL)     return stream_closed;
00171         #endif // POSIX
00172         if (ulPos < ChunkSize) return stream_ready;
00173         else                   return stream_end_reached;
00174     }
00175 
00191     unsigned long Chunk::Read(void* pData, unsigned long WordCount, unsigned long WordSize) {
00192        #if DEBUG
00193        std::cout << "Chunk::Read(void*,ulong,ulong)" << std::endl;
00194        #endif // DEBUG
00195         if (ulPos >= ChunkSize) return 0;
00196         if (ulPos + WordCount * WordSize >= ChunkSize) WordCount = (ChunkSize - ulPos) / WordSize;
00197         #if POSIX
00198         if (lseek(hFile, ulStartPos + ulPos, SEEK_SET) < 0) return 0;
00199         unsigned long readWords = read(hFile, pData, WordCount * WordSize);
00200         if (readWords < 1) return 0;
00201         readWords /= WordSize;
00202         #else // standard C functions
00203         if (fseek(hFile, ulStartPos + ulPos, SEEK_SET)) return 0;
00204         unsigned long readWords = fread(pData, WordSize, WordCount, hFile);
00205         #endif // POSIX
00206         if (!bEndianNative && WordSize != 1) {
00207             switch (WordSize) {
00208                 case 2:
00209                     for (unsigned long iWord = 0; iWord < readWords; iWord++)
00210                         swapBytes_16((uint16_t*) pData + iWord);
00211                     break;
00212                 case 4:
00213                     for (unsigned long iWord = 0; iWord < readWords; iWord++)
00214                         swapBytes_32((uint32_t*) pData + iWord);
00215                     break;
00216                 default:
00217                     for (unsigned long iWord = 0; iWord < readWords; iWord++)
00218                         swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
00219                     break;
00220             }
00221         }
00222         SetPos(readWords * WordSize, stream_curpos);
00223         return readWords;
00224     }
00225 
00227     unsigned long Chunk::ReadSceptical(void* pData, unsigned long WordCount, unsigned long WordSize) {
00228         unsigned long readWords = Read(pData, WordCount, WordSize);
00229         if (readWords != WordCount) throw RIFF::Exception("End of chunk data reached.");
00230         return readWords;
00231     }
00232 
00244     unsigned long Chunk::ReadInt8(int8_t* pData, unsigned long WordCount) {
00245        #if DEBUG
00246        std::cout << "Chunk::ReadInt8(int8_t*,ulong)" << std::endl;
00247        #endif // DEBUG
00248         return ReadSceptical(pData, WordCount, 1);
00249     }
00250 
00263     unsigned long Chunk::ReadUint8(uint8_t* pData, unsigned long WordCount) {
00264        #if DEBUG
00265        std::cout << "Chunk::ReadUint8(uint8_t*,ulong)" << std::endl;
00266        #endif // DEBUG
00267         return ReadSceptical(pData, WordCount, 1);
00268     }
00269 
00282     unsigned long Chunk::ReadInt16(int16_t* pData, unsigned long WordCount) {
00283       #if DEBUG
00284       std::cout << "Chunk::ReadInt16(int16_t*,ulong)" << std::endl;
00285       #endif // DEBUG
00286         return ReadSceptical(pData, WordCount, 2);
00287     }
00288 
00301     unsigned long Chunk::ReadUint16(uint16_t* pData, unsigned long WordCount) {
00302       #if DEBUG
00303       std::cout << "Chunk::ReadUint16(uint16_t*,ulong)" << std::endl;
00304       #endif // DEBUG
00305         return ReadSceptical(pData, WordCount, 2);
00306     }
00307 
00320     unsigned long Chunk::ReadInt32(int32_t* pData, unsigned long WordCount) {
00321        #if DEBUG
00322        std::cout << "Chunk::ReadInt32(int32_t*,ulong)" << std::endl;
00323        #endif // DEBUG
00324         return ReadSceptical(pData, WordCount, 4);
00325     }
00326 
00339     unsigned long Chunk::ReadUint32(uint32_t* pData, unsigned long WordCount) {
00340        #if DEBUG
00341        std::cout << "Chunk::ReadUint32(uint32_t*,ulong)" << std::endl;
00342        #endif // DEBUG
00343         return ReadSceptical(pData, WordCount, 4);
00344     }
00345 
00353     int8_t Chunk::ReadInt8() {
00354       #if DEBUG
00355       std::cout << "Chunk::ReadInt8()" << std::endl;
00356       #endif // DEBUG
00357         int8_t word;
00358         ReadSceptical(&word,1,1);
00359         return word;
00360     }
00361 
00369     uint8_t Chunk::ReadUint8() {
00370       #if DEBUG
00371       std::cout << "Chunk::ReadUint8()" << std::endl;
00372       #endif // DEBUG
00373         uint8_t word;
00374         ReadSceptical(&word,1,1);
00375         return word;
00376     }
00377 
00386     int16_t Chunk::ReadInt16() {
00387       #if DEBUG
00388       std::cout << "Chunk::ReadInt16()" << std::endl;
00389       #endif // DEBUG
00390         int16_t word;
00391         ReadSceptical(&word,1,2);
00392         return word;
00393     }
00394 
00403     uint16_t Chunk::ReadUint16() {
00404       #if DEBUG
00405       std::cout << "Chunk::ReadUint16()" << std::endl;
00406       #endif // DEBUG
00407         uint16_t word;
00408         ReadSceptical(&word,1,2);
00409         return word;
00410     }
00411 
00420     int32_t Chunk::ReadInt32() {
00421       #if DEBUG
00422       std::cout << "Chunk::ReadInt32()" << std::endl;
00423       #endif // DEBUG
00424         int32_t word;
00425         ReadSceptical(&word,1,4);
00426         return word;
00427     }
00428 
00437     uint32_t Chunk::ReadUint32() {
00438       #if DEBUG
00439       std::cout << "Chunk::ReadUint32()" << std::endl;
00440       #endif // DEBUG
00441         uint32_t word;
00442         ReadSceptical(&word,1,4);
00443         return word;
00444     }
00445 
00446     void* Chunk::LoadChunkData() {
00447         if (!pChunkData) {
00448             #if POSIX
00449             if (lseek(hFile, ulStartPos, SEEK_SET) == -1) return NULL;
00450             pChunkData = new uint8_t[GetSize()];
00451             if (!pChunkData) return NULL;
00452             unsigned long readWords = read(hFile, pChunkData, GetSize());
00453             #else
00454             if (fseek(hFile, ulStartPos, SEEK_SET)) return NULL;
00455             pChunkData = new uint8_t[GetSize()];
00456             if (!pChunkData) return NULL;
00457             unsigned long readWords = fread(pChunkData, 1, GetSize(), hFile);
00458             #endif // POSIX
00459             if (readWords != GetSize()) {
00460                 delete[] pChunkData;
00461                 return (pChunkData = NULL);
00462             }
00463         }
00464         return pChunkData;
00465     }
00466 
00467     void Chunk::ReleaseChunkData() {
00468         if (pChunkData) {
00469             delete[] pChunkData;
00470             pChunkData = NULL;
00471         }
00472     }
00473 
00474 
00475 
00476 // *************** List ***************
00477 // *
00478 
00479     List::List() : Chunk() {
00480       #if DEBUG
00481       std::cout << "List::List()" << std::endl;
00482       #endif // DEBUG
00483         pSubChunks    = NULL;
00484         pSubChunksMap = NULL;
00485     }
00486 
00487     #if POSIX
00488     List::List(int hFile, unsigned long StartPos, bool EndianNative, List* Parent)
00489     #else
00490     List::List(FILE* hFile, unsigned long StartPos, bool EndianNative, List* Parent)
00491     #endif // POSIX
00492       : Chunk(hFile, StartPos, EndianNative, Parent) {
00493         #if DEBUG
00494         std::cout << "List::List(FILE*,ulong,bool,List*)" << std::endl;
00495         #endif // DEBUG
00496         pSubChunks    = NULL;
00497         pSubChunksMap = NULL;
00498         ReadHeader(StartPos);
00499         ulStartPos    = StartPos + LIST_HEADER_SIZE;
00500     }
00501 
00502     List::~List() {
00503       #if DEBUG
00504       std::cout << "List::~List()" << std::endl;
00505       #endif // DEBUG
00506         if (pSubChunks) {
00507             ChunkList::iterator iter = pSubChunks->begin();
00508             ChunkList::iterator end  = pSubChunks->end();
00509             while (iter != end) {
00510                 delete *iter;
00511                 iter++;
00512             }
00513             delete pSubChunks;
00514         }
00515         if (pSubChunksMap) delete pSubChunksMap;
00516     }
00517 
00529     Chunk* List::GetSubChunk(uint32_t ChunkID) {
00530       #if DEBUG
00531       std::cout << "List::GetSubChunk(uint32_t)" << std::endl;
00532       #endif // DEBUG
00533         if (!pSubChunksMap) LoadSubChunks();
00534         return (*pSubChunksMap)[ChunkID];
00535     }
00536 
00548     List* List::GetSubList(uint32_t ListType) {
00549         #if DEBUG
00550         std::cout << "List::GetSubList(uint32_t)" << std::endl;
00551         #endif // DEBUG
00552         if (!pSubChunks) LoadSubChunks();
00553         ChunkList::iterator iter = pSubChunks->begin();
00554         ChunkList::iterator end  = pSubChunks->end();
00555         while (iter != end) {
00556             if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
00557                 List* l = (List*) *iter;
00558                 if (l->GetListType() == ListType) return l;
00559             }
00560             iter++;
00561         }
00562         return NULL;
00563     }
00564 
00573     Chunk* List::GetFirstSubChunk() {
00574         #if DEBUG
00575         std::cout << "List::GetFirstSubChunk()" << std::endl;
00576         #endif // DEBUG
00577         if (!pSubChunks) LoadSubChunks();
00578         ChunksIterator = pSubChunks->begin();
00579         return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
00580     }
00581 
00589     Chunk* List::GetNextSubChunk() {
00590         #if DEBUG
00591         std::cout << "List::GetNextSubChunk()" << std::endl;
00592         #endif // DEBUG
00593         if (!pSubChunks) return NULL;
00594         ChunksIterator++;
00595         return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
00596     }
00597 
00607     List* List::GetFirstSubList() {
00608         #if DEBUG
00609         std::cout << "List::GetFirstSubList()" << std::endl;
00610         #endif // DEBUG
00611         if (!pSubChunks) LoadSubChunks();
00612         ListIterator            = pSubChunks->begin();
00613         ChunkList::iterator end = pSubChunks->end();
00614         while (ListIterator != end) {
00615             if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST) return (List*) *ListIterator;
00616             ListIterator++;
00617         }
00618         return NULL;
00619     }
00620 
00629     List* List::GetNextSubList() {
00630         #if DEBUG
00631         std::cout << "List::GetNextSubList()" << std::endl;
00632         #endif // DEBUG
00633         if (!pSubChunks) return NULL;
00634         if (ListIterator == pSubChunks->end()) return NULL;
00635         ListIterator++;
00636         ChunkList::iterator end = pSubChunks->end();
00637         while (ListIterator != end) {
00638             if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST) return (List*) *ListIterator;
00639             ListIterator++;
00640         }
00641         return NULL;
00642     }
00643 
00647     unsigned int List::CountSubChunks() {
00648         if (!pSubChunks) LoadSubChunks();
00649         return pSubChunks->size();
00650     }
00651 
00656     unsigned int List::CountSubChunks(uint32_t ChunkID) {
00657         unsigned int result = 0;
00658         if (!pSubChunks) LoadSubChunks();
00659         ChunkList::iterator iter = pSubChunks->begin();
00660         ChunkList::iterator end  = pSubChunks->end();
00661         while (iter != end) {
00662             if ((*iter)->GetChunkID() == ChunkID) {
00663                 result++;
00664             }
00665             iter++;
00666         }
00667         return result;
00668     }
00669 
00673     unsigned int List::CountSubLists() {
00674         return CountSubChunks(CHUNK_ID_LIST);
00675     }
00676 
00681     unsigned int List::CountSubLists(uint32_t ListType) {
00682         unsigned int result = 0;
00683         if (!pSubChunks) LoadSubChunks();
00684         ChunkList::iterator iter = pSubChunks->begin();
00685         ChunkList::iterator end  = pSubChunks->end();
00686         while (iter != end) {
00687             if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
00688                 List* l = (List*) *iter;
00689                 if (l->GetListType() == ListType) result++;
00690             }
00691             iter++;
00692         }
00693         return result;
00694     }
00695 
00696     void List::ReadHeader(unsigned long fPos) {
00697       #if DEBUG
00698       std::cout << "List::Readheader(ulong) ";
00699       #endif // DEBUG
00700         Chunk::ReadHeader(fPos);
00701         ChunkSize -= 4;
00702         #if POSIX
00703         lseek(hFile, fPos + CHUNK_HEADER_SIZE, SEEK_SET);
00704         read(hFile, &ListType, 4);
00705         #else
00706         fseek(hFile, fPos + CHUNK_HEADER_SIZE, SEEK_SET);
00707         fread(&ListType, 4, 1, hFile);
00708         #endif // POSIX
00709       #if DEBUG
00710       std::cout << "listType=" << convertToString(ListType) << std::endl;
00711       #endif // DEBUG
00712         if (!bEndianNative) {
00713             //swapBytes_32(&ListType);
00714         }
00715     }
00716 
00717     void List::LoadSubChunks() {
00718        #if DEBUG
00719        std::cout << "List::LoadSubChunks()";
00720        #endif // DEBUG
00721         if (!pSubChunks) {
00722             pSubChunks    = new ChunkList();
00723             pSubChunksMap = new ChunkMap();
00724             unsigned long uiOriginalPos = GetPos();
00725             SetPos(0); // jump to beginning of list chunk body
00726             while (RemainingBytes() >= CHUNK_HEADER_SIZE) {
00727                 Chunk* ck;
00728                 uint32_t ckid;
00729                 Read(&ckid, 4, 1);
00730        #if DEBUG
00731        std::cout << " ckid=" << convertToString(ckid) << std::endl;
00732        #endif // DEBUG
00733                 if (ckid == CHUNK_ID_LIST) {
00734                     ck = new RIFF::List(hFile, ulStartPos + ulPos - 4, bEndianNative, this);
00735                     SetPos(ck->GetSize() + LIST_HEADER_SIZE - 4, RIFF::stream_curpos);
00736                 }
00737                 else { // simple chunk
00738                     ck = new RIFF::Chunk(hFile, ulStartPos + ulPos - 4, bEndianNative, this);
00739                     SetPos(ck->GetSize() + CHUNK_HEADER_SIZE - 4, RIFF::stream_curpos);
00740                 }
00741                 pSubChunks->push_back(ck);
00742                 (*pSubChunksMap)[ckid] = ck;
00743                 if (GetPos() % 2 != 0) SetPos(1, RIFF::stream_curpos); // jump over pad byte
00744             }
00745             SetPos(uiOriginalPos); // restore position before this call
00746         }
00747     }
00748 
00752     String List::GetListTypeString() {
00753         return convertToString(ListType);
00754     }
00755 
00756 
00757 
00758 // *************** File ***************
00759 // *
00760 
00761     File::File(const String& path) : List() {
00762       #if DEBUG
00763       std::cout << "File::File("<<path<<")" << std::endl;
00764       #endif // DEBUG
00765         bEndianNative = true;
00766         #if POSIX
00767         hFile = open(path.c_str(), O_RDONLY | O_NONBLOCK);
00768         if (hFile <= 0) {
00769             hFile = 0;
00770             throw RIFF::Exception("Can't open \"" + path + "\"");
00771         }
00772         #else
00773         hFile = fopen(path.c_str(), "rb");
00774         if (!hFile) throw RIFF::Exception("Can't open \"" + path + "\"");
00775         #endif // POSIX
00776         ulStartPos = RIFF_HEADER_SIZE;
00777         ReadHeader(0);
00778         if (ChunkID != CHUNK_ID_RIFF) {
00779             throw RIFF::Exception("Not a RIFF file");
00780         }
00781     }
00782 
00783     File::~File() {
00784        #if DEBUG
00785        std::cout << "File::~File()" << std::endl;
00786        #endif // DEBUG
00787         #if POSIX
00788         if (hFile) close(hFile);
00789         #else
00790         if (hFile) fclose(hFile);
00791         #endif // POSIX
00792     }
00793 
00794     unsigned long File::GetFileSize() {
00795         #if POSIX
00796         struct stat filestat;
00797         fstat(hFile, &filestat);
00798         long size = filestat.st_size;
00799         #else // standard C functions
00800         long curpos = ftell(hFile);
00801         fseek(hFile, 0, SEEK_END);
00802         long size = ftell(hFile);
00803         fseek(hFile, curpos, SEEK_SET);
00804         #endif // POSIX
00805         return size;
00806     }
00807 
00808 
00809 
00810 // *************** Exception ***************
00811 // *
00812 
00813     void Exception::PrintMessage() {
00814         std::cout << "RIFF::Exception: " << Message << std::endl;
00815     }
00816 
00817 
00818 // *************** functions ***************
00819 // *
00820 
00826     String libraryName() {
00827         return PACKAGE;
00828     }
00829 
00834     String libraryVersion() {
00835         return VERSION;
00836     }
00837 
00838 } // namespace RIFF
00839 #endif

Generated on Wed May 25 23:48:22 2005 for libgig by  doxygen 1.4.2