1 |
/*************************************************************************** |
2 |
* * |
3 |
* libgig - C++ cross-platform Gigasampler format file loader library * |
4 |
* * |
5 |
* Copyright (C) 2003 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 DEBUG |
75 |
std::cout << "ckID=" << convertToString(ChunkID) << " "; |
76 |
std::cout << "ckSize=" << ChunkSize << std::endl; |
77 |
#endif // DEBUG |
78 |
#if WORDS_BIGENDIAN |
79 |
if (ChunkID == CHUNK_ID_RIFF) { |
80 |
bEndianNative = false; |
81 |
} |
82 |
#else // little endian |
83 |
if (ChunkID == CHUNK_ID_RIFX) { |
84 |
bEndianNative = false; |
85 |
ChunkID = CHUNK_ID_RIFF; |
86 |
} |
87 |
#endif // WORDS_BIGENDIAN |
88 |
if (!bEndianNative) { |
89 |
swapBytes_32(&ChunkID); |
90 |
swapBytes_32(&ChunkSize); |
91 |
} |
92 |
} |
93 |
} |
94 |
|
95 |
String Chunk::GetChunkIDString() { |
96 |
return convertToString(ChunkID); |
97 |
} |
98 |
|
99 |
unsigned long Chunk::SetPos(unsigned long Where, stream_whence_t Whence) { |
100 |
#if DEBUG |
101 |
std::cout << "Chunk::SetPos(ulong)" << std::endl; |
102 |
#endif // DEBUG |
103 |
switch (Whence) { |
104 |
case stream_curpos: |
105 |
ulPos += Where; |
106 |
break; |
107 |
case stream_end: |
108 |
ulPos = ChunkSize - 1 - Where; |
109 |
break; |
110 |
case stream_backward: |
111 |
ulPos -= Where; |
112 |
break; |
113 |
case stream_start: default: |
114 |
ulPos = Where; |
115 |
break; |
116 |
} |
117 |
if (ulPos > ChunkSize) ulPos = ChunkSize; |
118 |
return ulPos; |
119 |
} |
120 |
|
121 |
unsigned long Chunk::RemainingBytes() { |
122 |
#if DEBUG |
123 |
std::cout << "Chunk::Remainingbytes()=" << ChunkSize - ulPos << std::endl; |
124 |
#endif // DEBUG |
125 |
return ChunkSize - ulPos; |
126 |
} |
127 |
|
128 |
stream_state_t Chunk::GetState() { |
129 |
#if DEBUG |
130 |
std::cout << "Chunk::GetState()" << std::endl; |
131 |
#endif // DEBUG |
132 |
#if POSIX |
133 |
if (hFile == 0) return stream_closed; |
134 |
#else |
135 |
if (hFile == NULL) return stream_closed; |
136 |
#endif // POSIX |
137 |
if (ulPos < ChunkSize) return stream_ready; |
138 |
else return stream_end_reached; |
139 |
} |
140 |
|
141 |
/** |
142 |
* Reads \a WordCount number of data words with given \a WordSize and |
143 |
* copies it into a buffer pointed by \a pData. The buffer has to be |
144 |
* allocated and be sure to provide the correct \a WordSize, as this |
145 |
* will be important and taken into account for eventual endian |
146 |
* correction (swapping of bytes due to different native byte order of |
147 |
* a system). The position within the chunk will automatically be |
148 |
* incremented. |
149 |
* |
150 |
* @param pData destination buffer |
151 |
* @param WordCount number of data words to read |
152 |
* @param WordSize size of each data word to read |
153 |
* @returns number of successfully read data words or 0 if end |
154 |
* of file reached or error occured |
155 |
*/ |
156 |
unsigned long Chunk::Read(void* pData, unsigned long WordCount, unsigned long WordSize) { |
157 |
#if DEBUG |
158 |
std::cout << "Chunk::Read(void*,ulong,ulong)" << std::endl; |
159 |
#endif // DEBUG |
160 |
if (ChunkSize - ulPos <= 0) return 0; |
161 |
if (ulPos + WordCount * WordSize >= ChunkSize) WordCount = (ChunkSize - ulPos) / WordSize; |
162 |
#if POSIX |
163 |
if (lseek(hFile, ulStartPos + ulPos, SEEK_SET) < 0) return 0; |
164 |
unsigned long readWords = read(hFile, pData, WordCount * WordSize); |
165 |
if (readWords < 1) return 0; |
166 |
readWords /= WordSize; |
167 |
#else // standard C functions |
168 |
if (fseek(hFile, ulStartPos + ulPos, SEEK_SET)) return 0; |
169 |
unsigned long readWords = fread(pData, WordSize, WordCount, hFile); |
170 |
#endif // POSIX |
171 |
if (!bEndianNative && WordSize != 1) { |
172 |
switch (WordSize) { |
173 |
case 2: |
174 |
for (unsigned long iWord = 0; iWord < readWords; iWord++) |
175 |
swapBytes_16((uint16_t*) pData + iWord); |
176 |
break; |
177 |
case 4: |
178 |
for (unsigned long iWord = 0; iWord < readWords; iWord++) |
179 |
swapBytes_32((uint32_t*) pData + iWord); |
180 |
break; |
181 |
default: |
182 |
for (unsigned long iWord = 0; iWord < readWords; iWord++) |
183 |
swapBytes((uint8_t*) pData + iWord * WordSize, WordSize); |
184 |
break; |
185 |
} |
186 |
} |
187 |
SetPos(readWords * WordSize, stream_curpos); |
188 |
return readWords; |
189 |
} |
190 |
|
191 |
/** Just an internal wrapper for the main <i>Read()</i> method with additional Exception throwing on errors. */ |
192 |
unsigned long Chunk::ReadSceptical(void* pData, unsigned long WordCount, unsigned long WordSize) { |
193 |
unsigned long readWords = Read(pData, WordCount, WordSize); |
194 |
if (readWords != WordCount) throw RIFF::Exception("End of chunk data reached."); |
195 |
return readWords; |
196 |
} |
197 |
|
198 |
/** |
199 |
* Reads \a WordCount number of 8 Bit signed integer words and copies it |
200 |
* into the buffer pointed by \a pData. The buffer has to be allocated. |
201 |
* The position within the chunk will automatically be incremented. |
202 |
* |
203 |
* @param pData destination buffer |
204 |
* @param WordCount number of 8 Bit signed integers to read |
205 |
* @returns number of read integers |
206 |
* @throws RIFF::Exception if an error occured or less than |
207 |
* \a WordCount integers could be read! |
208 |
*/ |
209 |
unsigned long Chunk::ReadInt8(int8_t* pData, unsigned long WordCount) { |
210 |
#if DEBUG |
211 |
std::cout << "Chunk::ReadInt8(int8_t*,ulong)" << std::endl; |
212 |
#endif // DEBUG |
213 |
return ReadSceptical(pData, WordCount, 1); |
214 |
} |
215 |
|
216 |
/** |
217 |
* Reads \a WordCount number of 8 Bit unsigned integer words and copies |
218 |
* it into the buffer pointed by \a pData. The buffer has to be |
219 |
* allocated. The position within the chunk will automatically be |
220 |
* incremented. |
221 |
* |
222 |
* @param pData destination buffer |
223 |
* @param WordCount number of 8 Bit unsigned integers to read |
224 |
* @returns number of read integers |
225 |
* @throws RIFF::Exception if an error occured or less than |
226 |
* \a WordCount integers could be read! |
227 |
*/ |
228 |
unsigned long Chunk::ReadUint8(uint8_t* pData, unsigned long WordCount) { |
229 |
#if DEBUG |
230 |
std::cout << "Chunk::ReadUint8(uint8_t*,ulong)" << std::endl; |
231 |
#endif // DEBUG |
232 |
return ReadSceptical(pData, WordCount, 1); |
233 |
} |
234 |
|
235 |
/** |
236 |
* Reads \a WordCount number of 16 Bit signed integer words and copies |
237 |
* it into the buffer pointed by \a pData. The buffer has to be |
238 |
* allocated. Endian correction will automatically be done if needed. |
239 |
* The position within the chunk will automatically be incremented. |
240 |
* |
241 |
* @param pData destination buffer |
242 |
* @param WordCount number of 16 Bit signed integers to read |
243 |
* @returns number of read integers |
244 |
* @throws RIFF::Exception if an error occured or less than |
245 |
* \a WordCount integers could be read! |
246 |
*/ |
247 |
unsigned long Chunk::ReadInt16(int16_t* pData, unsigned long WordCount) { |
248 |
#if DEBUG |
249 |
std::cout << "Chunk::ReadInt16(int16_t*,ulong)" << std::endl; |
250 |
#endif // DEBUG |
251 |
return ReadSceptical(pData, WordCount, 2); |
252 |
} |
253 |
|
254 |
/** |
255 |
* Reads \a WordCount number of 16 Bit unsigned integer words and copies |
256 |
* it into the buffer pointed by \a pData. The buffer has to be |
257 |
* allocated. Endian correction will automatically be done if needed. |
258 |
* The position within the chunk will automatically be incremented. |
259 |
* |
260 |
* @param pData destination buffer |
261 |
* @param WordCount number of 8 Bit unsigned integers to read |
262 |
* @returns number of read integers |
263 |
* @throws RIFF::Exception if an error occured or less than |
264 |
* \a WordCount integers could be read! |
265 |
*/ |
266 |
unsigned long Chunk::ReadUint16(uint16_t* pData, unsigned long WordCount) { |
267 |
#if DEBUG |
268 |
std::cout << "Chunk::ReadUint16(uint16_t*,ulong)" << std::endl; |
269 |
#endif // DEBUG |
270 |
return ReadSceptical(pData, WordCount, 2); |
271 |
} |
272 |
|
273 |
/** |
274 |
* Reads \a WordCount number of 32 Bit signed integer words and copies |
275 |
* it into the buffer pointed by \a pData. The buffer has to be |
276 |
* allocated. Endian correction will automatically be done if needed. |
277 |
* The position within the chunk will automatically be incremented. |
278 |
* |
279 |
* @param pData destination buffer |
280 |
* @param WordCount number of 32 Bit signed integers to read |
281 |
* @returns number of read integers |
282 |
* @throws RIFF::Exception if an error occured or less than |
283 |
* \a WordCount integers could be read! |
284 |
*/ |
285 |
unsigned long Chunk::ReadInt32(int32_t* pData, unsigned long WordCount) { |
286 |
#if DEBUG |
287 |
std::cout << "Chunk::ReadInt32(int32_t*,ulong)" << std::endl; |
288 |
#endif // DEBUG |
289 |
return ReadSceptical(pData, WordCount, 4); |
290 |
} |
291 |
|
292 |
/** |
293 |
* Reads \a WordCount number of 32 Bit unsigned integer words and copies |
294 |
* it into the buffer pointed by \a pData. The buffer has to be |
295 |
* allocated. Endian correction will automatically be done if needed. |
296 |
* The position within the chunk will automatically be incremented. |
297 |
* |
298 |
* @param pData destination buffer |
299 |
* @param WordCount number of 32 Bit unsigned integers to read |
300 |
* @returns number of read integers |
301 |
* @throws RIFF::Exception if an error occured or less than |
302 |
* \a WordCount integers could be read! |
303 |
*/ |
304 |
unsigned long Chunk::ReadUint32(uint32_t* pData, unsigned long WordCount) { |
305 |
#if DEBUG |
306 |
std::cout << "Chunk::ReadUint32(uint32_t*,ulong)" << std::endl; |
307 |
#endif // DEBUG |
308 |
return ReadSceptical(pData, WordCount, 4); |
309 |
} |
310 |
|
311 |
/** |
312 |
* Reads one 8 Bit signed integer word and increments the position within |
313 |
* the chunk. |
314 |
* |
315 |
* @returns read integer word |
316 |
* @throws RIFF::Exception if an error occured |
317 |
*/ |
318 |
int8_t Chunk::ReadInt8() { |
319 |
#if DEBUG |
320 |
std::cout << "Chunk::ReadInt8()" << std::endl; |
321 |
#endif // DEBUG |
322 |
int8_t word; |
323 |
ReadSceptical(&word,1,1); |
324 |
return word; |
325 |
} |
326 |
|
327 |
/** |
328 |
* Reads one 8 Bit unsigned integer word and increments the position |
329 |
* within the chunk. |
330 |
* |
331 |
* @returns read integer word |
332 |
* @throws RIFF::Exception if an error occured |
333 |
*/ |
334 |
uint8_t Chunk::ReadUint8() { |
335 |
#if DEBUG |
336 |
std::cout << "Chunk::ReadUint8()" << std::endl; |
337 |
#endif // DEBUG |
338 |
uint8_t word; |
339 |
ReadSceptical(&word,1,1); |
340 |
return word; |
341 |
} |
342 |
|
343 |
/** |
344 |
* Reads one 16 Bit signed integer word and increments the position |
345 |
* within the chunk. Endian correction will automatically be done if |
346 |
* needed. |
347 |
* |
348 |
* @returns read integer word |
349 |
* @throws RIFF::Exception if an error occured |
350 |
*/ |
351 |
int16_t Chunk::ReadInt16() { |
352 |
#if DEBUG |
353 |
std::cout << "Chunk::ReadInt16()" << std::endl; |
354 |
#endif // DEBUG |
355 |
int16_t word; |
356 |
ReadSceptical(&word,1,2); |
357 |
return word; |
358 |
} |
359 |
|
360 |
/** |
361 |
* Reads one 16 Bit unsigned integer word and increments the position |
362 |
* within the chunk. Endian correction will automatically be done if |
363 |
* needed. |
364 |
* |
365 |
* @returns read integer word |
366 |
* @throws RIFF::Exception if an error occured |
367 |
*/ |
368 |
uint16_t Chunk::ReadUint16() { |
369 |
#if DEBUG |
370 |
std::cout << "Chunk::ReadUint16()" << std::endl; |
371 |
#endif // DEBUG |
372 |
uint16_t word; |
373 |
ReadSceptical(&word,1,2); |
374 |
return word; |
375 |
} |
376 |
|
377 |
/** |
378 |
* Reads one 32 Bit signed integer word and increments the position |
379 |
* within the chunk. Endian correction will automatically be done if |
380 |
* needed. |
381 |
* |
382 |
* @returns read integer word |
383 |
* @throws RIFF::Exception if an error occured |
384 |
*/ |
385 |
int32_t Chunk::ReadInt32() { |
386 |
#if DEBUG |
387 |
std::cout << "Chunk::ReadInt32()" << std::endl; |
388 |
#endif // DEBUG |
389 |
int32_t word; |
390 |
ReadSceptical(&word,1,4); |
391 |
return word; |
392 |
} |
393 |
|
394 |
/** |
395 |
* Reads one 32 Bit unsigned integer word and increments the position |
396 |
* within the chunk. Endian correction will automatically be done if |
397 |
* needed. |
398 |
* |
399 |
* @returns read integer word |
400 |
* @throws RIFF::Exception if an error occured |
401 |
*/ |
402 |
uint32_t Chunk::ReadUint32() { |
403 |
#if DEBUG |
404 |
std::cout << "Chunk::ReadUint32()" << std::endl; |
405 |
#endif // DEBUG |
406 |
uint32_t word; |
407 |
ReadSceptical(&word,1,4); |
408 |
return word; |
409 |
} |
410 |
|
411 |
void* Chunk::LoadChunkData() { |
412 |
if (!pChunkData) { |
413 |
#if POSIX |
414 |
if (lseek(hFile, ulStartPos, SEEK_SET) == -1) return NULL; |
415 |
pChunkData = new uint8_t[GetSize()]; |
416 |
if (!pChunkData) return NULL; |
417 |
unsigned long readWords = read(hFile, pChunkData, GetSize()); |
418 |
#else |
419 |
if (fseek(hFile, ulStartPos, SEEK_SET)) return NULL; |
420 |
pChunkData = new uint8_t[GetSize()]; |
421 |
if (!pChunkData) return NULL; |
422 |
unsigned long readWords = fread(pChunkData, 1, GetSize(), hFile); |
423 |
#endif // POSIX |
424 |
if (readWords != GetSize()) { |
425 |
delete[] pChunkData; |
426 |
return (pChunkData = NULL); |
427 |
} |
428 |
} |
429 |
return pChunkData; |
430 |
} |
431 |
|
432 |
void Chunk::ReleaseChunkData() { |
433 |
if (pChunkData) { |
434 |
delete[] pChunkData; |
435 |
pChunkData = NULL; |
436 |
} |
437 |
} |
438 |
|
439 |
|
440 |
|
441 |
// *************** List *************** |
442 |
// * |
443 |
|
444 |
List::List() : Chunk() { |
445 |
#if DEBUG |
446 |
std::cout << "List::List()" << std::endl; |
447 |
#endif // DEBUG |
448 |
pSubChunks = NULL; |
449 |
pSubChunksMap = NULL; |
450 |
} |
451 |
|
452 |
#if POSIX |
453 |
List::List(int hFile, unsigned long StartPos, bool EndianNative, List* Parent) |
454 |
#else |
455 |
List::List(FILE* hFile, unsigned long StartPos, bool EndianNative, List* Parent) |
456 |
#endif // POSIX |
457 |
: Chunk(hFile, StartPos, EndianNative, Parent) { |
458 |
#if DEBUG |
459 |
std::cout << "List::List(FILE*,ulong,bool,List*)" << std::endl; |
460 |
#endif // DEBUG |
461 |
pSubChunks = NULL; |
462 |
pSubChunksMap = NULL; |
463 |
ReadHeader(StartPos); |
464 |
ulStartPos = StartPos + LIST_HEADER_SIZE; |
465 |
} |
466 |
|
467 |
List::~List() { |
468 |
#if DEBUG |
469 |
std::cout << "List::~List()" << std::endl; |
470 |
#endif // DEBUG |
471 |
if (pSubChunks) { |
472 |
ChunkList::iterator iter = pSubChunks->begin(); |
473 |
ChunkList::iterator end = pSubChunks->end(); |
474 |
while (iter != end) { |
475 |
delete *iter; |
476 |
iter++; |
477 |
} |
478 |
delete pSubChunks; |
479 |
} |
480 |
if (pSubChunksMap) delete pSubChunksMap; |
481 |
} |
482 |
|
483 |
Chunk* List::GetSubChunk(uint32_t ChunkID) { |
484 |
#if DEBUG |
485 |
std::cout << "List::GetSubChunk(uint32_t)" << std::endl; |
486 |
#endif // DEBUG |
487 |
if (!pSubChunksMap) LoadSubChunks(); |
488 |
return (*pSubChunksMap)[ChunkID]; |
489 |
} |
490 |
|
491 |
List* List::GetSubList(uint32_t ListType) { |
492 |
#if DEBUG |
493 |
std::cout << "List::GetSubList(uint32_t)" << std::endl; |
494 |
#endif // DEBUG |
495 |
if (!pSubChunks) LoadSubChunks(); |
496 |
ChunkList::iterator iter = pSubChunks->begin(); |
497 |
ChunkList::iterator end = pSubChunks->end(); |
498 |
while (iter != end) { |
499 |
if ((*iter)->GetChunkID() == CHUNK_ID_LIST) { |
500 |
List* l = (List*) *iter; |
501 |
if (l->GetListType() == ListType) return l; |
502 |
} |
503 |
iter++; |
504 |
} |
505 |
return NULL; |
506 |
} |
507 |
|
508 |
Chunk* List::GetFirstSubChunk() { |
509 |
#if DEBUG |
510 |
std::cout << "List::GetFirstSubChunk()" << std::endl; |
511 |
#endif // DEBUG |
512 |
if (!pSubChunks) LoadSubChunks(); |
513 |
ChunksIterator = pSubChunks->begin(); |
514 |
return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL; |
515 |
} |
516 |
|
517 |
Chunk* List::GetNextSubChunk() { |
518 |
#if DEBUG |
519 |
std::cout << "List::GetNextSubChunk()" << std::endl; |
520 |
#endif // DEBUG |
521 |
if (!pSubChunks) return NULL; |
522 |
ChunksIterator++; |
523 |
return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL; |
524 |
} |
525 |
|
526 |
List* List::GetFirstSubList() { |
527 |
#if DEBUG |
528 |
std::cout << "List::GetFirstSubList()" << std::endl; |
529 |
#endif // DEBUG |
530 |
if (!pSubChunks) LoadSubChunks(); |
531 |
ListIterator = pSubChunks->begin(); |
532 |
ChunkList::iterator end = pSubChunks->end(); |
533 |
while (ListIterator != end) { |
534 |
if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST) return (List*) *ListIterator; |
535 |
ListIterator++; |
536 |
} |
537 |
return NULL; |
538 |
} |
539 |
|
540 |
List* List::GetNextSubList() { |
541 |
#if DEBUG |
542 |
std::cout << "List::GetNextSubList()" << std::endl; |
543 |
#endif // DEBUG |
544 |
if (!pSubChunks) return NULL; |
545 |
if (ListIterator == pSubChunks->end()) return NULL; |
546 |
ListIterator++; |
547 |
ChunkList::iterator end = pSubChunks->end(); |
548 |
while (ListIterator != end) { |
549 |
if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST) return (List*) *ListIterator; |
550 |
ListIterator++; |
551 |
} |
552 |
return NULL; |
553 |
} |
554 |
|
555 |
unsigned int List::CountSubChunks() { |
556 |
if (!pSubChunks) LoadSubChunks(); |
557 |
return pSubChunks->size(); |
558 |
} |
559 |
|
560 |
unsigned int List::CountSubChunks(uint32_t ChunkID) { |
561 |
unsigned int result = 0; |
562 |
if (!pSubChunks) LoadSubChunks(); |
563 |
ChunkList::iterator iter = pSubChunks->begin(); |
564 |
ChunkList::iterator end = pSubChunks->end(); |
565 |
while (iter != end) { |
566 |
if ((*iter)->GetChunkID() == ChunkID) { |
567 |
result++; |
568 |
} |
569 |
iter++; |
570 |
} |
571 |
return result; |
572 |
} |
573 |
|
574 |
unsigned int List::CountSubLists() { |
575 |
return CountSubChunks(CHUNK_ID_LIST); |
576 |
} |
577 |
|
578 |
unsigned int List::CountSubLists(uint32_t ListType) { |
579 |
unsigned int result = 0; |
580 |
if (!pSubChunks) LoadSubChunks(); |
581 |
ChunkList::iterator iter = pSubChunks->begin(); |
582 |
ChunkList::iterator end = pSubChunks->end(); |
583 |
while (iter != end) { |
584 |
if ((*iter)->GetChunkID() == CHUNK_ID_LIST) { |
585 |
List* l = (List*) *iter; |
586 |
if (l->GetListType() == ListType) result++; |
587 |
} |
588 |
iter++; |
589 |
} |
590 |
return result; |
591 |
} |
592 |
|
593 |
void List::ReadHeader(unsigned long fPos) { |
594 |
#if DEBUG |
595 |
std::cout << "List::Readheader(ulong) "; |
596 |
#endif // DEBUG |
597 |
Chunk::ReadHeader(fPos); |
598 |
ChunkSize -= 4; |
599 |
#if POSIX |
600 |
lseek(hFile, fPos + CHUNK_HEADER_SIZE, SEEK_SET); |
601 |
read(hFile, &ListType, 4); |
602 |
#else |
603 |
fseek(hFile, fPos + CHUNK_HEADER_SIZE, SEEK_SET); |
604 |
fread(&ListType, 4, 1, hFile); |
605 |
#endif // POSIX |
606 |
#if DEBUG |
607 |
std::cout << "listType=" << convertToString(ListType) << std::endl; |
608 |
#endif // DEBUG |
609 |
if (!bEndianNative) { |
610 |
swapBytes_32(&ListType); |
611 |
} |
612 |
} |
613 |
|
614 |
void List::LoadSubChunks() { |
615 |
#if DEBUG |
616 |
std::cout << "List::LoadSubChunks()"; |
617 |
#endif // DEBUG |
618 |
if (!pSubChunks) { |
619 |
pSubChunks = new ChunkList(); |
620 |
pSubChunksMap = new ChunkMap(); |
621 |
while (RemainingBytes() >= CHUNK_HEADER_SIZE) { |
622 |
Chunk* ck; |
623 |
uint32_t ckid = ReadUint32(); |
624 |
#if DEBUG |
625 |
std::cout << " ckid=" << convertToString(ckid) << std::endl; |
626 |
#endif // DEBUG |
627 |
if (ckid == CHUNK_ID_LIST) { |
628 |
ck = new RIFF::List(hFile, ulStartPos + ulPos - 4, bEndianNative, this); |
629 |
SetPos(ck->GetSize() + LIST_HEADER_SIZE - 4, RIFF::stream_curpos); |
630 |
} |
631 |
else { // simple chunk |
632 |
ck = new RIFF::Chunk(hFile, ulStartPos + ulPos - 4, bEndianNative, this); |
633 |
SetPos(ck->GetSize() + CHUNK_HEADER_SIZE - 4, RIFF::stream_curpos); |
634 |
} |
635 |
pSubChunks->push_back(ck); |
636 |
(*pSubChunksMap)[ckid] = ck; |
637 |
if (GetPos() % 2 != 0) SetPos(1, RIFF::stream_curpos); // jump over pad byte |
638 |
} |
639 |
} |
640 |
} |
641 |
|
642 |
String List::GetListTypeString() { |
643 |
return convertToString(ListType); |
644 |
} |
645 |
|
646 |
|
647 |
|
648 |
// *************** File *************** |
649 |
// * |
650 |
|
651 |
File::File(const String& path) : List() { |
652 |
#if DEBUG |
653 |
std::cout << "File::File("<<path<<")" << std::endl; |
654 |
#endif // DEBUG |
655 |
bEndianNative = true; |
656 |
#if POSIX |
657 |
hFile = open(path.c_str(), O_RDONLY | O_NONBLOCK); |
658 |
if (hFile <= 0) { |
659 |
hFile = 0; |
660 |
throw RIFF::Exception("Can't open \"" + path + "\""); |
661 |
} |
662 |
#else |
663 |
hFile = fopen(path.c_str(), "rb"); |
664 |
if (!hFile) throw RIFF::Exception("Can't open \"" + path + "\""); |
665 |
#endif // POSIX |
666 |
ulStartPos = RIFF_HEADER_SIZE; |
667 |
ReadHeader(0); |
668 |
if (ChunkID != CHUNK_ID_RIFF) { |
669 |
throw RIFF::Exception("Not a RIFF file"); |
670 |
} |
671 |
} |
672 |
|
673 |
File::~File() { |
674 |
#if DEBUG |
675 |
std::cout << "File::~File()" << std::endl; |
676 |
#endif // DEBUG |
677 |
#if POSIX |
678 |
if (hFile) close(hFile); |
679 |
#else |
680 |
if (hFile) fclose(hFile); |
681 |
#endif // POSIX |
682 |
} |
683 |
|
684 |
unsigned long File::GetFileSize() { |
685 |
#if POSIX |
686 |
struct stat filestat; |
687 |
fstat(hFile, &filestat); |
688 |
long size = filestat.st_size; |
689 |
#else // standard C functions |
690 |
long curpos = ftell(hFile); |
691 |
fseek(hFile, 0, SEEK_END); |
692 |
long size = ftell(hFile); |
693 |
fseek(hFile, curpos, SEEK_SET); |
694 |
#endif // POSIX |
695 |
return size; |
696 |
} |
697 |
|
698 |
|
699 |
|
700 |
// *************** Exception *************** |
701 |
// * |
702 |
|
703 |
void Exception::PrintMessage() { |
704 |
std::cout << "RIFF::Exception: " << Message << std::endl; |
705 |
} |
706 |
|
707 |
} // namespace RIFF |
708 |
#endif |