42 static String __resolveChunkPath(Chunk* pCk) {
44 for (Chunk* pChunk = pCk; pChunk; pChunk = pChunk->GetParent()) {
46 List* pList = (List*) pChunk;
47 sPath =
"->'" + pList->GetListTypeString() +
"'" + sPath;
49 sPath =
"->'" + pChunk->GetChunkIDString() +
"'" + sPath;
62 std::cout <<
"Chunk::Chunk(File* pFile)" << std::endl;
76 std::cout <<
"Chunk::Chunk(File*,ulong,bool,List*),StartPos=" << StartPos << std::endl;
108 std::cout <<
"Chunk::Readheader(" << fPos <<
") ";
117 if (SetFilePointer(
pFile->
hFileRead, fPos, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) {
130 #else // little endian 135 #endif // WORDS_BIGENDIAN 150 uint32_t uiNewChunkID =
ChunkID;
154 #else // little endian 156 #endif // WORDS_BIGENDIAN 170 if (SetFilePointer(
pFile->
hFileWrite, fPos, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) {
171 DWORD dwBytesWritten;
173 WriteFile(
pFile->
hFileWrite, &uiNewChunkSize, 4, &dwBytesWritten, NULL);
205 std::cout <<
"Chunk::SetPos(ulong)" << std::endl;
255 std::cout <<
"Chunk::GetState()" << std::endl;
259 #elif defined (WIN32) 284 unsigned long Chunk::Read(
void* pData,
unsigned long WordCount,
unsigned long WordSize) {
286 std::cout <<
"Chunk::Read(void*,ulong,ulong)" << std::endl;
293 unsigned long readWords = read(
pFile->
hFileRead, pData, WordCount * WordSize);
294 if (readWords < 1)
return 0;
295 readWords /= WordSize;
299 ReadFile(
pFile->
hFileRead, pData, WordCount * WordSize, &readWords, NULL);
300 if (readWords < 1)
return 0;
301 readWords /= WordSize;
302 #else // standard C functions 304 unsigned long readWords = fread(pData, WordSize, WordCount,
pFile->
hFileRead);
309 for (
unsigned long iWord = 0; iWord < readWords; iWord++)
313 for (
unsigned long iWord = 0; iWord < readWords; iWord++)
317 for (
unsigned long iWord = 0; iWord < readWords; iWord++)
318 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
342 unsigned long Chunk::Write(
void* pData,
unsigned long WordCount,
unsigned long WordSize) {
344 throw Exception(
"Cannot write data to chunk, file has to be opened in read+write mode first");
346 throw Exception(
"End of chunk reached while trying to write data");
350 for (
unsigned long iWord = 0; iWord < WordCount; iWord++)
354 for (
unsigned long iWord = 0; iWord < WordCount; iWord++)
358 for (
unsigned long iWord = 0; iWord < WordCount; iWord++)
359 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
368 unsigned long writtenWords = write(
pFile->
hFileWrite, pData, WordCount * WordSize);
369 if (writtenWords < 1)
throw Exception(
"POSIX IO Error while trying to write chunk data");
370 writtenWords /= WordSize;
377 WriteFile(
pFile->
hFileWrite, pData, WordCount * WordSize, &writtenWords, NULL);
378 if (writtenWords < 1)
throw Exception(
"Windows IO Error while trying to write chunk data");
379 writtenWords /= WordSize;
380 #else // standard C functions 385 unsigned long writtenWords = fwrite(pData, WordSize, WordCount,
pFile->
hFileWrite);
393 unsigned long readWords =
Read(pData, WordCount, WordSize);
394 if (readWords != WordCount)
throw RIFF::Exception(
"End of chunk data reached.");
411 std::cout <<
"Chunk::ReadInt8(int8_t*,ulong)" << std::endl;
431 return Write(pData, WordCount, 1);
448 std::cout <<
"Chunk::ReadUint8(uint8_t*,ulong)" << std::endl;
468 return Write(pData, WordCount, 1);
485 std::cout <<
"Chunk::ReadInt16(int16_t*,ulong)" << std::endl;
505 return Write(pData, WordCount, 2);
522 std::cout <<
"Chunk::ReadUint16(uint16_t*,ulong)" << std::endl;
542 return Write(pData, WordCount, 2);
559 std::cout <<
"Chunk::ReadInt32(int32_t*,ulong)" << std::endl;
579 return Write(pData, WordCount, 4);
596 std::cout <<
"Chunk::ReadUint32(uint32_t*,ulong)" << std::endl;
612 char* buf =
new char[size];
614 s.assign(buf, std::find(buf, buf + size,
'\0'));
633 return Write(pData, WordCount, 4);
645 std::cout <<
"Chunk::ReadInt8()" << std::endl;
661 std::cout <<
"Chunk::ReadUint8()" << std::endl;
678 std::cout <<
"Chunk::ReadInt16()" << std::endl;
695 std::cout <<
"Chunk::ReadUint16()" << std::endl;
712 std::cout <<
"Chunk::ReadInt32()" << std::endl;
729 std::cout <<
"Chunk::ReadUint32()" << std::endl;
785 if (!pNewBuffer)
throw Exception(
"Could not enlarge chunk data buffer to " + ToString(
NewChunkSize) +
" bytes");
828 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(
this));
847 const unsigned long ulOriginalPos = ulWritePos;
851 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
861 throw Exception(
"Writing Chunk data (from RAM) failed");
865 DWORD dwBytesWritten;
868 throw Exception(
"Writing Chunk data (from RAM) failed");
873 throw Exception(
"Writing Chunk data (from RAM) failed");
878 int8_t* pCopyBuffer =
new int8_t[4096];
881 DWORD iBytesMoved = 1;
885 for (
unsigned long ulOffset = 0; ulToMove > 0 && iBytesMoved > 0; ulOffset += iBytesMoved, ulToMove -= iBytesMoved) {
886 iBytesMoved = (ulToMove < 4096) ? ulToMove : 4096;
894 ReadFile(
pFile->
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
895 SetFilePointer(
pFile->
hFileWrite, ulWritePos + ulOffset, NULL, FILE_BEGIN);
896 WriteFile(
pFile->
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
899 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
pFile->
hFileRead);
904 delete[] pCopyBuffer;
905 if (iBytesMoved < 0)
throw Exception(
"Writing Chunk data (from file) failed");
918 const char cPadByte = 0;
924 DWORD dwBytesWritten;
947 std::cout <<
"List::List(File* pFile)" << std::endl;
954 :
Chunk(pFile, StartPos, Parent) {
956 std::cout <<
"List::List(File*,ulong,bool,List*)" << std::endl;
973 std::cout <<
"List::~List()" << std::endl;
980 ChunkList::iterator iter =
pSubChunks->begin();
982 while (iter != end) {
1008 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1027 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1030 ChunkList::iterator iter =
pSubChunks->begin();
1032 while (iter != end) {
1052 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1068 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1086 std::cout <<
"List::GetFirstSubList()" << std::endl;
1108 std::cout <<
"List::GetNextSubList()" << std::endl;
1134 unsigned int result = 0;
1136 ChunkList::iterator iter =
pSubChunks->begin();
1138 while (iter != end) {
1139 if ((*iter)->GetChunkID() ==
ChunkID) {
1159 unsigned int result = 0;
1161 ChunkList::iterator iter =
pSubChunks->begin();
1163 while (iter != end) {
1187 if (uiBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1191 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1192 pNewChunk->
Resize(uiBodySize);
1225 if (pNewParent ==
this || !pNewParent)
return;
1234 ChunkList::iterator iter =
pSubChunks->begin();
1236 for (; iter != end; ++iter) {
1237 if ((*iter)->GetChunkID() == pSrc->
GetChunkID()) {
1238 (*pSubChunksMap)[pSrc->
GetChunkID()] = *iter;
1264 return pNewListChunk;
1283 ChunkList::iterator iter =
pSubChunks->begin();
1285 for (; iter != end; ++iter) {
1286 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1287 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1297 std::cout <<
"List::Readheader(ulong) ";
1305 #elif defined(WIN32) 1329 #elif defined(WIN32) 1331 DWORD dwBytesWritten;
1341 std::cout <<
"List::LoadSubChunks()";
1351 unsigned long uiOriginalPos =
GetPos();
1369 (*pSubChunksMap)[ckid] = ck;
1378 pList->LoadSubChunksRecursively();
1396 const unsigned long ulOriginalPos = ulWritePos;
1400 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1404 for (ChunkList::iterator iter =
pSubChunks->begin(), end =
pSubChunks->end(); iter != end; ++iter) {
1405 ulWritePos = (*iter)->WriteChunk(ulWritePos, ulCurrentDataOffset);
1422 for (ChunkList::iterator iter =
pSubChunks->begin(), end =
pSubChunks->end(); iter != end; ++iter) {
1423 (*iter)->__resetPos();
1441 #define _GET_RESIZED_CHUNKS() \ 1442 (reinterpret_cast<std::set<Chunk*>*>(ResizedChunks.front())) 1462 ResizedChunks.push_back(reinterpret_cast<Chunk*>(
new std::set<Chunk*>));
1486 std::cout <<
"File::File("<<path<<
")" << std::endl;
1490 __openExistingFile(path);
1531 __openExistingFile(path, &FileType);
1549 void File::__openExistingFile(
const String& path, uint32_t* FileType) {
1551 ResizedChunks.push_back(reinterpret_cast<Chunk*>(
new std::set<Chunk*>));
1556 String sError = strerror(errno);
1559 #elif defined(WIN32) 1561 path.c_str(), GENERIC_READ,
1562 FILE_SHARE_READ | FILE_SHARE_WRITE,
1563 NULL, OPEN_EXISTING,
1564 FILE_ATTRIBUTE_NORMAL |
1565 FILE_FLAG_RANDOM_ACCESS, NULL
1567 if (
hFileRead == INVALID_HANDLE_VALUE) {
1580 if (FileType &&
ChunkID != *FileType)
1588 if (
Read(&ckid, 4, 1) != 4) {
1589 throw RIFF::Exception(
"Invalid file header ID (premature end of header)");
1590 }
else if (ckid != *FileType) {
1628 if (NewMode != Mode) {
1636 String sError = strerror(errno);
1637 throw Exception(
"Could not (re)open file \"" +
Filename +
"\" in read mode: " + sError);
1639 #elif defined(WIN32) 1643 FILE_SHARE_READ | FILE_SHARE_WRITE,
1644 NULL, OPEN_EXISTING,
1645 FILE_ATTRIBUTE_NORMAL |
1646 FILE_FLAG_RANDOM_ACCESS,
1649 if (
hFileRead == INVALID_HANDLE_VALUE) {
1666 String sError = strerror(errno);
1667 throw Exception(
"Could not open file \"" +
Filename +
"\" in read+write mode: " + sError);
1669 #elif defined(WIN32) 1673 GENERIC_READ | GENERIC_WRITE,
1676 FILE_ATTRIBUTE_NORMAL |
1677 FILE_FLAG_RANDOM_ACCESS,
1680 if (
hFileRead == INVALID_HANDLE_VALUE) {
1683 FILE_SHARE_READ | FILE_SHARE_WRITE,
1684 NULL, OPEN_EXISTING,
1685 FILE_ATTRIBUTE_NORMAL |
1686 FILE_FLAG_RANDOM_ACCESS,
1689 throw Exception(
"Could not (re)open file \"" +
Filename +
"\" in read+write mode");
1705 #elif defined(WIN32) 1715 throw Exception(
"Unknown file access mode");
1753 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
1769 unsigned long ulPositiveSizeDiff = 0;
1771 for (std::set<Chunk*>::const_iterator iter = resizedChunks->begin(), end = resizedChunks->end(); iter != end; ++iter) {
1772 if ((*iter)->GetNewSize() == 0) {
1773 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(*iter));
1775 unsigned long newSizePadded = (*iter)->GetNewSize() + (*iter)->GetNewSize() % 2;
1776 unsigned long oldSizePadded = (*iter)->GetSize() + (*iter)->GetSize() % 2;
1777 if (newSizePadded > oldSizePadded) ulPositiveSizeDiff += newSizePadded - oldSizePadded;
1780 unsigned long ulWorkingFileSize = GetFileSize();
1783 if (ulPositiveSizeDiff > 0) {
1785 ulWorkingFileSize += ulPositiveSizeDiff;
1786 ResizeFile(ulWorkingFileSize);
1788 int8_t* pCopyBuffer =
new int8_t[4096];
1791 DWORD iBytesMoved = 1;
1793 int iBytesMoved = 1;
1795 for (
unsigned long ulPos = ulFileSize; iBytesMoved > 0; ) {
1797 ulPos -= iBytesMoved;
1800 iBytesMoved = read(
hFileRead, pCopyBuffer, iBytesMoved);
1802 iBytesMoved = write(
hFileWrite, pCopyBuffer, iBytesMoved);
1803 #elif defined(WIN32) 1805 ReadFile(
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1806 SetFilePointer(
hFileWrite,
ulPos + ulPositiveSizeDiff, NULL, FILE_BEGIN);
1807 WriteFile(
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1810 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
hFileRead);
1812 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved,
hFileWrite);
1815 delete[] pCopyBuffer;
1816 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
1820 unsigned long ulTotalSize =
WriteChunk(0, ulPositiveSizeDiff);
1821 unsigned long ulActualSize = __GetFileSize(
hFileWrite);
1824 if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1827 resizedChunks->clear();
1848 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
1856 hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
1859 String sError = strerror(errno);
1860 throw Exception(
"Could not open file \"" + path +
"\" for writing: " + sError);
1862 #elif defined(WIN32) 1864 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
1865 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
1866 FILE_FLAG_RANDOM_ACCESS, NULL
1870 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1876 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1882 unsigned long ulTotalSize =
WriteChunk(0, 0);
1883 unsigned long ulActualSize = __GetFileSize(
hFileWrite);
1886 if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1893 #elif defined(WIN32) 1907 void File::ResizeFile(
unsigned long ulNewSize) {
1911 #elif defined(WIN32) 1913 SetFilePointer(
hFileWrite, ulNewSize, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
1917 # error Sorry, this version of libgig only supports POSIX and Windows systems yet. 1918 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)! 1924 std::cout <<
"File::~File()" << std::endl;
1937 void File::Cleanup() {
1940 #elif defined(WIN32) 1959 unsigned long File::GetFileSize() {
1964 unsigned long File::__GetFileSize(
int hFile) {
1965 struct stat filestat;
1966 fstat(hFile, &filestat);
1967 long size = filestat.st_size;
1970 #elif defined(WIN32) 1971 unsigned long File::__GetFileSize(HANDLE hFile) {
1972 DWORD dwSize = ::GetFileSize(hFile, NULL );
1973 if (dwSize == INVALID_FILE_SIZE)
1974 throw Exception(
"Windows FS error: could not determine file size");
1977 #else // standard C functions 1978 unsigned long File::__GetFileSize(FILE* hFile) {
1979 long curpos = ftell(hFile);
1980 fseek(hFile, 0, SEEK_END);
1981 long size = ftell(hFile);
1982 fseek(hFile, curpos, SEEK_SET);
1992 std::cout <<
"RIFF::Exception: " << Message << std::endl;
virtual unsigned long WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset)
Write chunk persistently e.g.
unsigned long WriteUint32(uint32_t *pData, unsigned long WordCount=1)
Writes WordCount number of 32 Bit unsigned integer words from the buffer pointed by pData to the chun...
#define _GET_RESIZED_CHUNKS()
int16_t ReadInt16()
Reads one 16 Bit signed integer word and increments the position within the chunk.
void UnlogResized(Chunk *pResizedChunk)
void swapBytes_16(void *Word)
stream_whence_t
File stream position dependent to these relations.
unsigned long Read(void *pData, unsigned long WordCount, unsigned long WordSize)
Reads WordCount number of data words with given WordSize and copies it into a buffer pointed by pData...
Chunk * GetFirstSubChunk()
Returns the first subchunk within the list.
String libraryName()
Returns the name of this C++ library.
File(uint32_t FileType)
Create new RIFF file.
unsigned long WriteUint16(uint16_t *pData, unsigned long WordCount=1)
Writes WordCount number of 16 Bit unsigned integer words from the buffer pointed by pData to the chun...
uint32_t GetChunkID()
Chunk ID in unsigned integer representation.
layout_t Layout
An ordinary RIFF file is always set to layout_standard.
layout_t GetLayout() const
void ReadHeader(unsigned long fPos)
void swapBytes(void *Word, unsigned long WordSize)
stream_state_t
Current state of the file stream.
unsigned long SetPos(unsigned long Where, stream_whence_t Whence=stream_start)
Sets the position within the chunk body, thus within the data portion of the chunk (in bytes)...
void ReadString(String &s, int size)
Reads a null-padded string of size characters and copies it into the string s.
void WriteHeader(unsigned long fPos)
String libraryVersion()
Returns version of this C++ library.
List * GetSubList(uint32_t ListType)
Returns sublist chunk with list type ListType within this chunk list.
void DeleteSubChunk(Chunk *pSubChunk)
Removes a sub chunk.
unsigned long WriteInt16(int16_t *pData, unsigned long WordCount=1)
Writes WordCount number of 16 Bit signed integer words from the buffer pointed by pData to the chunk'...
#define CHUNK_HEADER_SIZE
int hFileWrite
handle / descriptor for writing to (some) file
unsigned long RemainingBytes()
Returns the number of bytes left to read in the chunk body.
List * GetFirstSubList()
Returns the first sublist within the list (that is a subchunk with chunk ID "LIST").
stream_mode_t
Whether file stream is open in read or in read/write mode.
std::list< Chunk * > ChunkList
unsigned long GetPos()
Position within the chunk data body.
void SetByteOrder(endian_t Endian)
Set the byte order to be used when saving.
int8_t ReadInt8()
Reads one 8 Bit signed integer word and increments the position within the chunk. ...
void ReadHeader(unsigned long fPos)
String GetListTypeString()
Returns string representation of the lists's id.
ChunkList::iterator ListIterator
unsigned long WriteInt32(int32_t *pData, unsigned long WordCount=1)
Writes WordCount number of 32 Bit signed integer words from the buffer pointed by pData to the chunk'...
Chunk * GetSubChunk(uint32_t ChunkID)
Returns subchunk with chunk ID ChunkID within this chunk list.
Chunk * GetNextSubChunk()
Returns the next subchunk within the list.
unsigned long ReadSceptical(void *pData, unsigned long WordCount, unsigned long WordSize)
Just an internal wrapper for the main Read() method with additional Exception throwing on errors...
int32_t ReadInt32()
Reads one 32 Bit signed integer word and increments the position within the chunk.
layout_t
General chunk structure of a file.
stream_state_t GetState()
Returns the current state of the chunk object.
uint32_t GetListType()
Returns unsigned integer representation of the list's ID.
uint32_t ReadUint32()
Reads one 32 Bit unsigned integer word and increments the position within the chunk.
ChunkList::iterator ChunksIterator
unsigned long Write(void *pData, unsigned long WordCount, unsigned long WordSize)
Writes WordCount number of data words with given WordSize from the buffer pointed by pData...
void swapBytes_32(void *Word)
Chunk * AddSubChunk(uint32_t uiChunkID, uint uiBodySize)
Creates a new sub chunk.
int hFileRead
handle / descriptor for reading from file
Not a "real" RIFF file: First chunk in file is an ordinary data chunk, not a List chunk...
void LogAsResized(Chunk *pResizedChunk)
virtual void __resetPos()
Sets Chunk's read/write position to zero.
uint16_t ReadUint16()
Reads one 16 Bit unsigned integer word and increments the position within the chunk.
virtual void __resetPos()
Sets List Chunk's read/write position to zero and causes all sub chunks to do the same...
uint32_t CurrentChunkSize
endian_t
Alignment of data bytes in memory (system dependant).
void SetFileName(const String &path)
void * LoadChunkData()
Load chunk body into RAM.
unsigned long WriteInt8(int8_t *pData, unsigned long WordCount=1)
Writes WordCount number of 8 Bit signed integer words from the buffer pointed by pData to the chunk's...
Standard RIFF file layout: First chunk in file is a List chunk which contains all other chunks and th...
unsigned long GetSize() const
Chunk size in bytes (without header, thus the chunk data body)
unsigned long ulChunkDataSize
List * AddSubList(uint32_t uiListType)
Creates a new list sub chunk.
void LoadSubChunksRecursively()
RIFF specific classes and definitions.
bool IsNew() const
Returns true if this file has been created new from scratch and has not been stored to disk yet...
List(File *pFile, unsigned long StartPos, List *Parent)
virtual unsigned long WriteChunk(unsigned long ulWritePos, unsigned long ulCurrentDataOffset)
Write list chunk persistently e.g.
void MoveSubChunk(Chunk *pSrc, Chunk *pDst)
Moves a sub chunk witin this list.
unsigned int CountSubChunks()
Returns number of subchunks within the list.
String convertToString(uint32_t word)
bool SetMode(stream_mode_t NewMode)
Change file access mode.
virtual void Save()
Save changes to same file.
Will be thrown whenever an error occurs while handling a RIFF file.
unsigned long WriteUint8(uint8_t *pData, unsigned long WordCount=1)
Writes WordCount number of 8 Bit unsigned integer words from the buffer pointed by pData to the chunk...
void ReleaseChunkData()
Free loaded chunk body from RAM.
unsigned int CountSubLists()
Returns number of sublists within the list.
String GetChunkIDString()
Returns the String representation of the chunk's ID (e.g.
void WriteHeader(unsigned long fPos)
std::map< uint32_t, RIFF::Chunk * > ChunkMap
void Resize(int iNewSize)
Resize chunk.
List * GetNextSubList()
Returns the next sublist (that is a subchunk with chunk ID "LIST") within the list.
Chunk(File *pFile, unsigned long StartPos, List *Parent)
uint8_t ReadUint8()
Reads one 8 Bit unsigned integer word and increments the position within the chunk.