00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #if 1
00024 #include "RIFF.h"
00025
00026 namespace RIFF {
00027
00028
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
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
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
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
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);
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 {
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);
00744 }
00745 SetPos(uiOriginalPos);
00746 }
00747 }
00748
00752 String List::GetListTypeString() {
00753 return convertToString(ListType);
00754 }
00755
00756
00757
00758
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
00811
00812
00813 void Exception::PrintMessage() {
00814 std::cout << "RIFF::Exception: " << Message << std::endl;
00815 }
00816
00817
00818
00819
00820
00826 String libraryName() {
00827 return PACKAGE;
00828 }
00829
00834 String libraryVersion() {
00835 return VERSION;
00836 }
00837
00838 }
00839 #endif