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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 518 - (hide annotations) (download)
Sun May 8 16:19:34 2005 UTC (18 years, 10 months ago) by schoenebeck
File size: 29977 byte(s)
* added functions libraryName() and libraryVersion() to each of the three
  library units (RIFF,DLS,gig)
* all tools now offer a command line switch -v to show the tools revision
  and the used libgig version
* man pages are now auto generated with the correct libgig version

1 schoenebeck 2 /***************************************************************************
2     * *
3     * libgig - C++ cross-platform Gigasampler format file loader library *
4     * *
5 schoenebeck 384 * Copyright (C) 2003-2005 by Christian Schoenebeck *
6     * <cuse@users.sourceforge.net> *
7 schoenebeck 2 * *
8     * This library is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This library is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this library; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23     #if 1
24     #include "RIFF.h"
25    
26     namespace RIFF {
27    
28     // *************** Chunk **************
29     // *
30    
31     Chunk::Chunk() {
32     #if DEBUG
33     std::cout << "Chunk::Chunk()" << std::endl;
34     #endif // DEBUG
35     ulPos = 0;
36     pParent = NULL;
37     pChunkData = NULL;
38     }
39    
40     #if POSIX
41     Chunk::Chunk(int hFile, unsigned long StartPos, bool EndianNative, List* Parent) {
42     #else
43     Chunk::Chunk(FILE* hFile, unsigned long StartPos, bool EndianNative, List* Parent) {
44     #endif // POSIX
45     #if DEBUG
46     std::cout << "Chunk::Chunk(FILE,ulong,bool,List*),StartPos=" << StartPos << std::endl;
47     #endif // DEBUG
48     Chunk::hFile = hFile;
49     ulStartPos = StartPos + CHUNK_HEADER_SIZE;
50     bEndianNative = EndianNative;
51     pParent = Parent;
52     ulPos = 0;
53     pChunkData = NULL;
54     ReadHeader(StartPos);
55     }
56    
57     Chunk::~Chunk() {
58     if (pChunkData) delete[] pChunkData;
59     }
60    
61     void Chunk::ReadHeader(unsigned long fPos) {
62     #if DEBUG
63     std::cout << "Chunk::Readheader(" << fPos << ") ";
64     #endif // DEBUG
65     #if POSIX
66     if (lseek(hFile, fPos, SEEK_SET) != -1) {
67     read(hFile, &ChunkID, 4);
68     read(hFile, &ChunkSize, 4);
69     #else
70     if (!fseek(hFile, fPos, SEEK_SET)) {
71     fread(&ChunkID, 4, 1, hFile);
72     fread(&ChunkSize, 4, 1, hFile);
73     #endif // POSIX
74     #if WORDS_BIGENDIAN
75     if (ChunkID == CHUNK_ID_RIFF) {
76     bEndianNative = false;
77     }
78     #else // little endian
79     if (ChunkID == CHUNK_ID_RIFX) {
80     bEndianNative = false;
81     ChunkID = CHUNK_ID_RIFF;
82     }
83     #endif // WORDS_BIGENDIAN
84     if (!bEndianNative) {
85 schoenebeck 11 //swapBytes_32(&ChunkID);
86 schoenebeck 2 swapBytes_32(&ChunkSize);
87     }
88 schoenebeck 11 #if DEBUG
89     std::cout << "ckID=" << convertToString(ChunkID) << " ";
90     std::cout << "ckSize=" << ChunkSize << " ";
91     std::cout << "bEndianNative=" << bEndianNative << std::endl;
92     #endif // DEBUG
93 schoenebeck 2 }
94     }
95    
96 schoenebeck 11 /**
97     * Returns the String representation of the chunk's ID (e.g. "RIFF",
98     * "LIST").
99     */
100 schoenebeck 2 String Chunk::GetChunkIDString() {
101     return convertToString(ChunkID);
102     }
103    
104 schoenebeck 11 /**
105     * Sets the position within the chunk body, thus within the data portion
106     * of the chunk (in bytes).
107     *
108     * @param Where - position offset (in bytes)
109     * @param Whence - optional: defines to what <i>\a Where</i> relates to,
110     * if omitted \a Where relates to beginning of the chunk
111     * data
112     */
113 schoenebeck 2 unsigned long Chunk::SetPos(unsigned long Where, stream_whence_t Whence) {
114     #if DEBUG
115     std::cout << "Chunk::SetPos(ulong)" << std::endl;
116     #endif // DEBUG
117     switch (Whence) {
118     case stream_curpos:
119     ulPos += Where;
120     break;
121     case stream_end:
122     ulPos = ChunkSize - 1 - Where;
123     break;
124     case stream_backward:
125     ulPos -= Where;
126     break;
127     case stream_start: default:
128     ulPos = Where;
129     break;
130     }
131     if (ulPos > ChunkSize) ulPos = ChunkSize;
132     return ulPos;
133     }
134    
135 schoenebeck 11 /**
136     * Returns the number of bytes left to read in the chunk body.
137     * When reading data from the chunk using the Read*() Methods, the
138     * position within the chunk data (that is the chunk body) will be
139     * incremented by the number of read bytes and RemainingBytes() returns
140     * how much data is left to read from the current position to the end
141     * of the chunk data.
142     *
143     * @returns number of bytes left to read
144     */
145 schoenebeck 2 unsigned long Chunk::RemainingBytes() {
146     #if DEBUG
147     std::cout << "Chunk::Remainingbytes()=" << ChunkSize - ulPos << std::endl;
148     #endif // DEBUG
149     return ChunkSize - ulPos;
150     }
151    
152 schoenebeck 11 /**
153     * Returns the current state of the chunk object.
154     * Following values are possible:
155     * - RIFF::stream_ready :
156     * chunk data can be read (this is the usual case)
157     * - RIFF::stream_closed :
158     * the data stream was closed somehow, no more reading possible
159     * - RIFF::stream_end_reached :
160     * alreaady reached the end of the chunk data, no more reading
161     * possible without SetPos()
162     */
163 schoenebeck 2 stream_state_t Chunk::GetState() {
164     #if DEBUG
165     std::cout << "Chunk::GetState()" << std::endl;
166     #endif // DEBUG
167     #if POSIX
168     if (hFile == 0) return stream_closed;
169     #else
170     if (hFile == NULL) return stream_closed;
171     #endif // POSIX
172     if (ulPos < ChunkSize) return stream_ready;
173     else return stream_end_reached;
174     }
175    
176     /**
177     * Reads \a WordCount number of data words with given \a WordSize and
178     * copies it into a buffer pointed by \a pData. The buffer has to be
179     * allocated and be sure to provide the correct \a WordSize, as this
180     * will be important and taken into account for eventual endian
181     * correction (swapping of bytes due to different native byte order of
182     * a system). The position within the chunk will automatically be
183     * incremented.
184     *
185     * @param pData destination buffer
186     * @param WordCount number of data words to read
187     * @param WordSize size of each data word to read
188     * @returns number of successfully read data words or 0 if end
189     * of file reached or error occured
190     */
191     unsigned long Chunk::Read(void* pData, unsigned long WordCount, unsigned long WordSize) {
192     #if DEBUG
193     std::cout << "Chunk::Read(void*,ulong,ulong)" << std::endl;
194     #endif // DEBUG
195 schoenebeck 24 if (ulPos >= ChunkSize) return 0;
196 schoenebeck 2 if (ulPos + WordCount * WordSize >= ChunkSize) WordCount = (ChunkSize - ulPos) / WordSize;
197     #if POSIX
198     if (lseek(hFile, ulStartPos + ulPos, SEEK_SET) < 0) return 0;
199     unsigned long readWords = read(hFile, pData, WordCount * WordSize);
200     if (readWords < 1) return 0;
201     readWords /= WordSize;
202     #else // standard C functions
203     if (fseek(hFile, ulStartPos + ulPos, SEEK_SET)) return 0;
204     unsigned long readWords = fread(pData, WordSize, WordCount, hFile);
205     #endif // POSIX
206     if (!bEndianNative && WordSize != 1) {
207     switch (WordSize) {
208     case 2:
209     for (unsigned long iWord = 0; iWord < readWords; iWord++)
210     swapBytes_16((uint16_t*) pData + iWord);
211     break;
212     case 4:
213     for (unsigned long iWord = 0; iWord < readWords; iWord++)
214     swapBytes_32((uint32_t*) pData + iWord);
215     break;
216     default:
217     for (unsigned long iWord = 0; iWord < readWords; iWord++)
218     swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
219     break;
220     }
221     }
222     SetPos(readWords * WordSize, stream_curpos);
223     return readWords;
224     }
225    
226     /** Just an internal wrapper for the main <i>Read()</i> method with additional Exception throwing on errors. */
227     unsigned long Chunk::ReadSceptical(void* pData, unsigned long WordCount, unsigned long WordSize) {
228     unsigned long readWords = Read(pData, WordCount, WordSize);
229     if (readWords != WordCount) throw RIFF::Exception("End of chunk data reached.");
230     return readWords;
231     }
232    
233     /**
234     * Reads \a WordCount number of 8 Bit signed integer words and copies it
235     * into the buffer pointed by \a pData. The buffer has to be allocated.
236     * The position within the chunk will automatically be incremented.
237     *
238     * @param pData destination buffer
239     * @param WordCount number of 8 Bit signed integers to read
240     * @returns number of read integers
241     * @throws RIFF::Exception if an error occured or less than
242     * \a WordCount integers could be read!
243     */
244     unsigned long Chunk::ReadInt8(int8_t* pData, unsigned long WordCount) {
245     #if DEBUG
246     std::cout << "Chunk::ReadInt8(int8_t*,ulong)" << std::endl;
247     #endif // DEBUG
248     return ReadSceptical(pData, WordCount, 1);
249     }
250    
251     /**
252     * Reads \a WordCount number of 8 Bit unsigned integer words and copies
253     * it into the buffer pointed by \a pData. The buffer has to be
254     * allocated. The position within the chunk will automatically be
255     * incremented.
256     *
257     * @param pData destination buffer
258     * @param WordCount number of 8 Bit unsigned integers to read
259     * @returns number of read integers
260     * @throws RIFF::Exception if an error occured or less than
261     * \a WordCount integers could be read!
262     */
263     unsigned long Chunk::ReadUint8(uint8_t* pData, unsigned long WordCount) {
264     #if DEBUG
265     std::cout << "Chunk::ReadUint8(uint8_t*,ulong)" << std::endl;
266     #endif // DEBUG
267     return ReadSceptical(pData, WordCount, 1);
268     }
269    
270     /**
271     * Reads \a WordCount number of 16 Bit signed integer words and copies
272     * it into the buffer pointed by \a pData. The buffer has to be
273     * allocated. Endian correction will automatically be done if needed.
274     * The position within the chunk will automatically be incremented.
275     *
276     * @param pData destination buffer
277     * @param WordCount number of 16 Bit signed integers to read
278     * @returns number of read integers
279     * @throws RIFF::Exception if an error occured or less than
280     * \a WordCount integers could be read!
281     */
282     unsigned long Chunk::ReadInt16(int16_t* pData, unsigned long WordCount) {
283     #if DEBUG
284     std::cout << "Chunk::ReadInt16(int16_t*,ulong)" << std::endl;
285     #endif // DEBUG
286     return ReadSceptical(pData, WordCount, 2);
287     }
288    
289     /**
290     * Reads \a WordCount number of 16 Bit unsigned integer words and copies
291     * it into the buffer pointed by \a pData. The buffer has to be
292     * allocated. Endian correction will automatically be done if needed.
293     * The position within the chunk will automatically be incremented.
294     *
295     * @param pData destination buffer
296     * @param WordCount number of 8 Bit unsigned integers to read
297     * @returns number of read integers
298     * @throws RIFF::Exception if an error occured or less than
299     * \a WordCount integers could be read!
300     */
301     unsigned long Chunk::ReadUint16(uint16_t* pData, unsigned long WordCount) {
302     #if DEBUG
303     std::cout << "Chunk::ReadUint16(uint16_t*,ulong)" << std::endl;
304     #endif // DEBUG
305     return ReadSceptical(pData, WordCount, 2);
306     }
307    
308     /**
309     * Reads \a WordCount number of 32 Bit signed integer words and copies
310     * it into the buffer pointed by \a pData. The buffer has to be
311     * allocated. Endian correction will automatically be done if needed.
312     * The position within the chunk will automatically be incremented.
313     *
314     * @param pData destination buffer
315     * @param WordCount number of 32 Bit signed integers to read
316     * @returns number of read integers
317     * @throws RIFF::Exception if an error occured or less than
318     * \a WordCount integers could be read!
319     */
320     unsigned long Chunk::ReadInt32(int32_t* pData, unsigned long WordCount) {
321     #if DEBUG
322     std::cout << "Chunk::ReadInt32(int32_t*,ulong)" << std::endl;
323     #endif // DEBUG
324     return ReadSceptical(pData, WordCount, 4);
325     }
326    
327     /**
328     * Reads \a WordCount number of 32 Bit unsigned integer words and copies
329     * it into the buffer pointed by \a pData. The buffer has to be
330     * allocated. Endian correction will automatically be done if needed.
331     * The position within the chunk will automatically be incremented.
332     *
333     * @param pData destination buffer
334     * @param WordCount number of 32 Bit unsigned integers to read
335     * @returns number of read integers
336     * @throws RIFF::Exception if an error occured or less than
337     * \a WordCount integers could be read!
338     */
339     unsigned long Chunk::ReadUint32(uint32_t* pData, unsigned long WordCount) {
340     #if DEBUG
341     std::cout << "Chunk::ReadUint32(uint32_t*,ulong)" << std::endl;
342     #endif // DEBUG
343     return ReadSceptical(pData, WordCount, 4);
344     }
345    
346     /**
347     * Reads one 8 Bit signed integer word and increments the position within
348     * the chunk.
349     *
350     * @returns read integer word
351     * @throws RIFF::Exception if an error occured
352     */
353     int8_t Chunk::ReadInt8() {
354     #if DEBUG
355     std::cout << "Chunk::ReadInt8()" << std::endl;
356     #endif // DEBUG
357     int8_t word;
358     ReadSceptical(&word,1,1);
359     return word;
360     }
361    
362     /**
363     * Reads one 8 Bit unsigned integer word and increments the position
364     * within the chunk.
365     *
366     * @returns read integer word
367     * @throws RIFF::Exception if an error occured
368     */
369     uint8_t Chunk::ReadUint8() {
370     #if DEBUG
371     std::cout << "Chunk::ReadUint8()" << std::endl;
372     #endif // DEBUG
373     uint8_t word;
374     ReadSceptical(&word,1,1);
375     return word;
376     }
377    
378     /**
379     * Reads one 16 Bit signed integer word and increments the position
380     * within the chunk. Endian correction will automatically be done if
381     * needed.
382     *
383     * @returns read integer word
384     * @throws RIFF::Exception if an error occured
385     */
386     int16_t Chunk::ReadInt16() {
387     #if DEBUG
388     std::cout << "Chunk::ReadInt16()" << std::endl;
389     #endif // DEBUG
390     int16_t word;
391     ReadSceptical(&word,1,2);
392     return word;
393     }
394    
395     /**
396     * Reads one 16 Bit unsigned integer word and increments the position
397     * within the chunk. Endian correction will automatically be done if
398     * needed.
399     *
400     * @returns read integer word
401     * @throws RIFF::Exception if an error occured
402     */
403     uint16_t Chunk::ReadUint16() {
404     #if DEBUG
405     std::cout << "Chunk::ReadUint16()" << std::endl;
406     #endif // DEBUG
407     uint16_t word;
408     ReadSceptical(&word,1,2);
409     return word;
410     }
411    
412     /**
413     * Reads one 32 Bit signed integer word and increments the position
414     * within the chunk. Endian correction will automatically be done if
415     * needed.
416     *
417     * @returns read integer word
418     * @throws RIFF::Exception if an error occured
419     */
420     int32_t Chunk::ReadInt32() {
421     #if DEBUG
422     std::cout << "Chunk::ReadInt32()" << std::endl;
423     #endif // DEBUG
424     int32_t word;
425     ReadSceptical(&word,1,4);
426     return word;
427     }
428    
429     /**
430     * Reads one 32 Bit unsigned integer word and increments the position
431     * within the chunk. Endian correction will automatically be done if
432     * needed.
433     *
434     * @returns read integer word
435     * @throws RIFF::Exception if an error occured
436     */
437     uint32_t Chunk::ReadUint32() {
438     #if DEBUG
439     std::cout << "Chunk::ReadUint32()" << std::endl;
440     #endif // DEBUG
441     uint32_t word;
442     ReadSceptical(&word,1,4);
443     return word;
444     }
445    
446     void* Chunk::LoadChunkData() {
447     if (!pChunkData) {
448     #if POSIX
449     if (lseek(hFile, ulStartPos, SEEK_SET) == -1) return NULL;
450     pChunkData = new uint8_t[GetSize()];
451     if (!pChunkData) return NULL;
452     unsigned long readWords = read(hFile, pChunkData, GetSize());
453     #else
454     if (fseek(hFile, ulStartPos, SEEK_SET)) return NULL;
455     pChunkData = new uint8_t[GetSize()];
456     if (!pChunkData) return NULL;
457     unsigned long readWords = fread(pChunkData, 1, GetSize(), hFile);
458     #endif // POSIX
459     if (readWords != GetSize()) {
460     delete[] pChunkData;
461     return (pChunkData = NULL);
462     }
463     }
464     return pChunkData;
465     }
466    
467     void Chunk::ReleaseChunkData() {
468     if (pChunkData) {
469     delete[] pChunkData;
470     pChunkData = NULL;
471     }
472     }
473    
474    
475    
476     // *************** List ***************
477     // *
478    
479     List::List() : Chunk() {
480     #if DEBUG
481     std::cout << "List::List()" << std::endl;
482     #endif // DEBUG
483     pSubChunks = NULL;
484     pSubChunksMap = NULL;
485     }
486    
487     #if POSIX
488     List::List(int hFile, unsigned long StartPos, bool EndianNative, List* Parent)
489     #else
490     List::List(FILE* hFile, unsigned long StartPos, bool EndianNative, List* Parent)
491     #endif // POSIX
492     : Chunk(hFile, StartPos, EndianNative, Parent) {
493     #if DEBUG
494     std::cout << "List::List(FILE*,ulong,bool,List*)" << std::endl;
495     #endif // DEBUG
496     pSubChunks = NULL;
497     pSubChunksMap = NULL;
498     ReadHeader(StartPos);
499     ulStartPos = StartPos + LIST_HEADER_SIZE;
500     }
501    
502     List::~List() {
503     #if DEBUG
504     std::cout << "List::~List()" << std::endl;
505     #endif // DEBUG
506     if (pSubChunks) {
507     ChunkList::iterator iter = pSubChunks->begin();
508     ChunkList::iterator end = pSubChunks->end();
509     while (iter != end) {
510     delete *iter;
511     iter++;
512     }
513     delete pSubChunks;
514     }
515     if (pSubChunksMap) delete pSubChunksMap;
516     }
517    
518 schoenebeck 11 /**
519     * Returns subchunk with chunk ID <i>\a ChunkID</i> within this chunk
520     * list. Use this method if you expect only one subchunk of that type in
521     * the list. It there are more than one, it's undetermined which one of
522     * them will be returned! If there are no subchunks with that desired
523     * chunk ID, NULL will be returned.
524     *
525     * @param ChunkID - chunk ID of the sought subchunk
526     * @returns pointer to the subchunk or NULL if there is none of
527     * that ID
528     */
529 schoenebeck 2 Chunk* List::GetSubChunk(uint32_t ChunkID) {
530     #if DEBUG
531     std::cout << "List::GetSubChunk(uint32_t)" << std::endl;
532     #endif // DEBUG
533     if (!pSubChunksMap) LoadSubChunks();
534     return (*pSubChunksMap)[ChunkID];
535     }
536    
537 schoenebeck 11 /**
538     * Returns sublist chunk with list type <i>\a ListType</i> within this
539     * chunk list. Use this method if you expect only one sublist chunk of
540     * that type in the list. It there are more than one, it's undetermined
541     * which one of them will be returned! If there are no sublists with
542     * that desired list type, NULL will be returned.
543     *
544     * @param ListType - list type of the sought sublist
545     * @returns pointer to the sublist or NULL if there is none of
546     * that type
547     */
548 schoenebeck 2 List* List::GetSubList(uint32_t ListType) {
549     #if DEBUG
550     std::cout << "List::GetSubList(uint32_t)" << std::endl;
551     #endif // DEBUG
552     if (!pSubChunks) LoadSubChunks();
553     ChunkList::iterator iter = pSubChunks->begin();
554     ChunkList::iterator end = pSubChunks->end();
555     while (iter != end) {
556     if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
557     List* l = (List*) *iter;
558     if (l->GetListType() == ListType) return l;
559     }
560     iter++;
561     }
562     return NULL;
563     }
564    
565 schoenebeck 11 /**
566     * Returns the first subchunk within the list. You have to call this
567     * method before you can call GetNextSubChunk(). Recall it when you want
568     * to start from the beginning of the list again.
569     *
570     * @returns pointer to the first subchunk within the list, NULL
571     * otherwise
572     */
573 schoenebeck 2 Chunk* List::GetFirstSubChunk() {
574     #if DEBUG
575     std::cout << "List::GetFirstSubChunk()" << std::endl;
576     #endif // DEBUG
577     if (!pSubChunks) LoadSubChunks();
578     ChunksIterator = pSubChunks->begin();
579     return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
580     }
581    
582 schoenebeck 11 /**
583     * Returns the next subchunk within the list. You have to call
584     * GetFirstSubChunk() before you can use this method!
585     *
586     * @returns pointer to the next subchunk within the list or NULL if
587     * end of list is reached
588     */
589 schoenebeck 2 Chunk* List::GetNextSubChunk() {
590     #if DEBUG
591     std::cout << "List::GetNextSubChunk()" << std::endl;
592     #endif // DEBUG
593     if (!pSubChunks) return NULL;
594     ChunksIterator++;
595     return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
596     }
597    
598 schoenebeck 11 /**
599     * Returns the first sublist within the list (that is a subchunk with
600     * chunk ID "LIST"). You have to call this method before you can call
601     * GetNextSubList(). Recall it when you want to start from the beginning
602     * of the list again.
603     *
604     * @returns pointer to the first sublist within the list, NULL
605     * otherwise
606     */
607 schoenebeck 2 List* List::GetFirstSubList() {
608     #if DEBUG
609     std::cout << "List::GetFirstSubList()" << std::endl;
610     #endif // DEBUG
611     if (!pSubChunks) LoadSubChunks();
612     ListIterator = pSubChunks->begin();
613     ChunkList::iterator end = pSubChunks->end();
614     while (ListIterator != end) {
615     if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST) return (List*) *ListIterator;
616     ListIterator++;
617     }
618     return NULL;
619     }
620    
621 schoenebeck 11 /**
622     * Returns the next sublist (that is a subchunk with chunk ID "LIST")
623     * within the list. You have to call GetFirstSubList() before you can
624     * use this method!
625     *
626     * @returns pointer to the next sublist within the list, NULL if
627     * end of list is reached
628     */
629 schoenebeck 2 List* List::GetNextSubList() {
630     #if DEBUG
631     std::cout << "List::GetNextSubList()" << std::endl;
632     #endif // DEBUG
633     if (!pSubChunks) return NULL;
634     if (ListIterator == pSubChunks->end()) return NULL;
635     ListIterator++;
636     ChunkList::iterator end = pSubChunks->end();
637     while (ListIterator != end) {
638     if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST) return (List*) *ListIterator;
639     ListIterator++;
640     }
641     return NULL;
642     }
643    
644 schoenebeck 11 /**
645 schoenebeck 515 * Returns number of subchunks within the list.
646 schoenebeck 11 */
647 schoenebeck 2 unsigned int List::CountSubChunks() {
648     if (!pSubChunks) LoadSubChunks();
649     return pSubChunks->size();
650     }
651    
652 schoenebeck 11 /**
653     * Returns number of subchunks within the list with chunk ID
654     * <i>\a ChunkId</i>.
655     */
656 schoenebeck 2 unsigned int List::CountSubChunks(uint32_t ChunkID) {
657     unsigned int result = 0;
658     if (!pSubChunks) LoadSubChunks();
659     ChunkList::iterator iter = pSubChunks->begin();
660     ChunkList::iterator end = pSubChunks->end();
661     while (iter != end) {
662     if ((*iter)->GetChunkID() == ChunkID) {
663     result++;
664     }
665     iter++;
666     }
667     return result;
668     }
669    
670 schoenebeck 11 /**
671     * Returns number of sublists within the list.
672     */
673 schoenebeck 2 unsigned int List::CountSubLists() {
674     return CountSubChunks(CHUNK_ID_LIST);
675     }
676    
677 schoenebeck 11 /**
678     * Returns number of sublists within the list with list type
679     * <i>\a ListType</i>
680     */
681 schoenebeck 2 unsigned int List::CountSubLists(uint32_t ListType) {
682     unsigned int result = 0;
683     if (!pSubChunks) LoadSubChunks();
684     ChunkList::iterator iter = pSubChunks->begin();
685     ChunkList::iterator end = pSubChunks->end();
686     while (iter != end) {
687     if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
688     List* l = (List*) *iter;
689     if (l->GetListType() == ListType) result++;
690     }
691     iter++;
692     }
693     return result;
694     }
695    
696     void List::ReadHeader(unsigned long fPos) {
697     #if DEBUG
698     std::cout << "List::Readheader(ulong) ";
699     #endif // DEBUG
700     Chunk::ReadHeader(fPos);
701     ChunkSize -= 4;
702     #if POSIX
703     lseek(hFile, fPos + CHUNK_HEADER_SIZE, SEEK_SET);
704     read(hFile, &ListType, 4);
705     #else
706     fseek(hFile, fPos + CHUNK_HEADER_SIZE, SEEK_SET);
707     fread(&ListType, 4, 1, hFile);
708     #endif // POSIX
709     #if DEBUG
710     std::cout << "listType=" << convertToString(ListType) << std::endl;
711     #endif // DEBUG
712     if (!bEndianNative) {
713 schoenebeck 11 //swapBytes_32(&ListType);
714 schoenebeck 2 }
715     }
716    
717     void List::LoadSubChunks() {
718     #if DEBUG
719     std::cout << "List::LoadSubChunks()";
720     #endif // DEBUG
721     if (!pSubChunks) {
722     pSubChunks = new ChunkList();
723     pSubChunksMap = new ChunkMap();
724 schoenebeck 515 unsigned long uiOriginalPos = GetPos();
725     SetPos(0); // jump to beginning of list chunk body
726 schoenebeck 2 while (RemainingBytes() >= CHUNK_HEADER_SIZE) {
727     Chunk* ck;
728 schoenebeck 11 uint32_t ckid;
729     Read(&ckid, 4, 1);
730 schoenebeck 2 #if DEBUG
731     std::cout << " ckid=" << convertToString(ckid) << std::endl;
732     #endif // DEBUG
733     if (ckid == CHUNK_ID_LIST) {
734     ck = new RIFF::List(hFile, ulStartPos + ulPos - 4, bEndianNative, this);
735     SetPos(ck->GetSize() + LIST_HEADER_SIZE - 4, RIFF::stream_curpos);
736     }
737     else { // simple chunk
738     ck = new RIFF::Chunk(hFile, ulStartPos + ulPos - 4, bEndianNative, this);
739     SetPos(ck->GetSize() + CHUNK_HEADER_SIZE - 4, RIFF::stream_curpos);
740     }
741     pSubChunks->push_back(ck);
742     (*pSubChunksMap)[ckid] = ck;
743     if (GetPos() % 2 != 0) SetPos(1, RIFF::stream_curpos); // jump over pad byte
744     }
745 schoenebeck 515 SetPos(uiOriginalPos); // restore position before this call
746 schoenebeck 2 }
747     }
748    
749 schoenebeck 11 /**
750     * Returns string representation of the lists's id
751     */
752 schoenebeck 2 String List::GetListTypeString() {
753     return convertToString(ListType);
754     }
755    
756    
757    
758     // *************** File ***************
759     // *
760    
761     File::File(const String& path) : List() {
762     #if DEBUG
763     std::cout << "File::File("<<path<<")" << std::endl;
764     #endif // DEBUG
765     bEndianNative = true;
766     #if POSIX
767     hFile = open(path.c_str(), O_RDONLY | O_NONBLOCK);
768     if (hFile <= 0) {
769     hFile = 0;
770     throw RIFF::Exception("Can't open \"" + path + "\"");
771     }
772     #else
773     hFile = fopen(path.c_str(), "rb");
774     if (!hFile) throw RIFF::Exception("Can't open \"" + path + "\"");
775     #endif // POSIX
776     ulStartPos = RIFF_HEADER_SIZE;
777     ReadHeader(0);
778     if (ChunkID != CHUNK_ID_RIFF) {
779     throw RIFF::Exception("Not a RIFF file");
780     }
781     }
782    
783     File::~File() {
784     #if DEBUG
785     std::cout << "File::~File()" << std::endl;
786     #endif // DEBUG
787     #if POSIX
788     if (hFile) close(hFile);
789     #else
790     if (hFile) fclose(hFile);
791     #endif // POSIX
792     }
793    
794     unsigned long File::GetFileSize() {
795     #if POSIX
796     struct stat filestat;
797     fstat(hFile, &filestat);
798     long size = filestat.st_size;
799     #else // standard C functions
800     long curpos = ftell(hFile);
801     fseek(hFile, 0, SEEK_END);
802     long size = ftell(hFile);
803     fseek(hFile, curpos, SEEK_SET);
804     #endif // POSIX
805     return size;
806     }
807    
808    
809    
810     // *************** Exception ***************
811     // *
812    
813     void Exception::PrintMessage() {
814     std::cout << "RIFF::Exception: " << Message << std::endl;
815     }
816    
817 schoenebeck 518
818     // *************** functions ***************
819     // *
820    
821     /**
822     * Returns the name of this C++ library. This is usually "libgig" of
823     * course. This call is equivalent to DLS::libraryName() and
824     * gig::libraryName().
825     */
826     String libraryName() {
827     return PACKAGE;
828     }
829    
830     /**
831     * Returns version of this C++ library. This call is equivalent to
832     * DLS::libraryVersion() and gig::libraryVersion().
833     */
834     String libraryVersion() {
835     return VERSION;
836     }
837    
838 schoenebeck 2 } // namespace RIFF
839     #endif

  ViewVC Help
Powered by ViewVC