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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 515 - (show annotations) (download)
Sat May 7 20:19:10 2005 UTC (18 years, 10 months ago) by schoenebeck
File size: 29482 byte(s)
* src/gig.h, src/gig.cpp: implemented progress indicator callback mechanism
  for loading instruments and samples
* src/DLS.cpp: fixed File constructor which caused variable
  File::Instruments always to be zero
* src/RIFF.cpp: fixed method List::LoadSubChunks() which did not restore
  the original position within the body of the given list chunk

1 /***************************************************************************
2 * *
3 * libgig - C++ cross-platform Gigasampler format file loader library *
4 * *
5 * Copyright (C) 2003-2005 by Christian Schoenebeck *
6 * <cuse@users.sourceforge.net> *
7 * *
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 //swapBytes_32(&ChunkID);
86 swapBytes_32(&ChunkSize);
87 }
88 #if DEBUG
89 std::cout << "ckID=" << convertToString(ChunkID) << " ";
90 std::cout << "ckSize=" << ChunkSize << " ";
91 std::cout << "bEndianNative=" << bEndianNative << std::endl;
92 #endif // DEBUG
93 }
94 }
95
96 /**
97 * Returns the String representation of the chunk's ID (e.g. "RIFF",
98 * "LIST").
99 */
100 String Chunk::GetChunkIDString() {
101 return convertToString(ChunkID);
102 }
103
104 /**
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 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 /**
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 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 /**
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 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 if (ulPos >= ChunkSize) return 0;
196 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 /**
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 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 /**
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 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 /**
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 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 /**
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 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 /**
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 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 /**
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 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 /**
645 * Returns number of subchunks within the list.
646 */
647 unsigned int List::CountSubChunks() {
648 if (!pSubChunks) LoadSubChunks();
649 return pSubChunks->size();
650 }
651
652 /**
653 * Returns number of subchunks within the list with chunk ID
654 * <i>\a ChunkId</i>.
655 */
656 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 /**
671 * Returns number of sublists within the list.
672 */
673 unsigned int List::CountSubLists() {
674 return CountSubChunks(CHUNK_ID_LIST);
675 }
676
677 /**
678 * Returns number of sublists within the list with list type
679 * <i>\a ListType</i>
680 */
681 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 //swapBytes_32(&ListType);
714 }
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 unsigned long uiOriginalPos = GetPos();
725 SetPos(0); // jump to beginning of list chunk body
726 while (RemainingBytes() >= CHUNK_HEADER_SIZE) {
727 Chunk* ck;
728 uint32_t ckid;
729 Read(&ckid, 4, 1);
730 #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 SetPos(uiOriginalPos); // restore position before this call
746 }
747 }
748
749 /**
750 * Returns string representation of the lists's id
751 */
752 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 } // namespace RIFF
818 #endif

  ViewVC Help
Powered by ViewVC