38 static String __resolveChunkPath(Chunk* pCk) {
40 for (Chunk* pChunk = pCk; pChunk; pChunk = pChunk->GetParent()) {
42 List* pList = (List*) pChunk;
43 sPath =
"->'" + pList->GetListTypeString() +
"'" + sPath;
45 sPath =
"->'" + pChunk->GetChunkIDString() +
"'" + sPath;
58 std::cout <<
"Chunk::Chunk(File* pFile)" << std::endl;
72 std::cout <<
"Chunk::Chunk(File*,ulong,bool,List*),StartPos=" << StartPos << std::endl;
104 std::cout <<
"Chunk::Readheader(" << fPos <<
") ";
113 if (SetFilePointer(
pFile->
hFileRead, fPos, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) {
126 #else // little endian
131 #endif // WORDS_BIGENDIAN
146 uint32_t uiNewChunkID =
ChunkID;
150 #else // little endian
152 #endif // WORDS_BIGENDIAN
166 if (SetFilePointer(
pFile->
hFileWrite, fPos, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) {
167 DWORD dwBytesWritten;
169 WriteFile(
pFile->
hFileWrite, &uiNewChunkSize, 4, &dwBytesWritten, NULL);
201 std::cout <<
"Chunk::SetPos(ulong)" << std::endl;
251 std::cout <<
"Chunk::GetState()" << std::endl;
255 #elif defined (WIN32)
280 unsigned long Chunk::Read(
void* pData,
unsigned long WordCount,
unsigned long WordSize) {
282 std::cout <<
"Chunk::Read(void*,ulong,ulong)" << std::endl;
289 unsigned long readWords = read(
pFile->
hFileRead, pData, WordCount * WordSize);
290 if (readWords < 1)
return 0;
291 readWords /= WordSize;
295 ReadFile(
pFile->
hFileRead, pData, WordCount * WordSize, &readWords, NULL);
296 if (readWords < 1)
return 0;
297 readWords /= WordSize;
298 #else // standard C functions
300 unsigned long readWords = fread(pData, WordSize, WordCount,
pFile->
hFileRead);
305 for (
unsigned long iWord = 0; iWord < readWords; iWord++)
309 for (
unsigned long iWord = 0; iWord < readWords; iWord++)
313 for (
unsigned long iWord = 0; iWord < readWords; iWord++)
314 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
338 unsigned long Chunk::Write(
void* pData,
unsigned long WordCount,
unsigned long WordSize) {
340 throw Exception(
"Cannot write data to chunk, file has to be opened in read+write mode first");
342 throw Exception(
"End of chunk reached while trying to write data");
346 for (
unsigned long iWord = 0; iWord < WordCount; iWord++)
350 for (
unsigned long iWord = 0; iWord < WordCount; iWord++)
354 for (
unsigned long iWord = 0; iWord < WordCount; iWord++)
355 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
364 unsigned long writtenWords = write(
pFile->
hFileWrite, pData, WordCount * WordSize);
365 if (writtenWords < 1)
throw Exception(
"POSIX IO Error while trying to write chunk data");
366 writtenWords /= WordSize;
373 WriteFile(
pFile->
hFileWrite, pData, WordCount * WordSize, &writtenWords, NULL);
374 if (writtenWords < 1)
throw Exception(
"Windows IO Error while trying to write chunk data");
375 writtenWords /= WordSize;
376 #else // standard C functions
381 unsigned long writtenWords = fwrite(pData, WordSize, WordCount,
pFile->
hFileWrite);
389 unsigned long readWords =
Read(pData, WordCount, WordSize);
390 if (readWords != WordCount)
throw RIFF::Exception(
"End of chunk data reached.");
407 std::cout <<
"Chunk::ReadInt8(int8_t*,ulong)" << std::endl;
427 return Write(pData, WordCount, 1);
444 std::cout <<
"Chunk::ReadUint8(uint8_t*,ulong)" << std::endl;
464 return Write(pData, WordCount, 1);
481 std::cout <<
"Chunk::ReadInt16(int16_t*,ulong)" << std::endl;
501 return Write(pData, WordCount, 2);
518 std::cout <<
"Chunk::ReadUint16(uint16_t*,ulong)" << std::endl;
538 return Write(pData, WordCount, 2);
555 std::cout <<
"Chunk::ReadInt32(int32_t*,ulong)" << std::endl;
575 return Write(pData, WordCount, 4);
592 std::cout <<
"Chunk::ReadUint32(uint32_t*,ulong)" << std::endl;
608 char* buf =
new char[size];
610 s.assign(buf, std::find(buf, buf + size,
'\0'));
629 return Write(pData, WordCount, 4);
641 std::cout <<
"Chunk::ReadInt8()" << std::endl;
657 std::cout <<
"Chunk::ReadUint8()" << std::endl;
674 std::cout <<
"Chunk::ReadInt16()" << std::endl;
691 std::cout <<
"Chunk::ReadUint16()" << std::endl;
708 std::cout <<
"Chunk::ReadInt32()" << std::endl;
725 std::cout <<
"Chunk::ReadUint32()" << std::endl;
781 if (!pNewBuffer)
throw Exception(
"Could not enlarge chunk data buffer to " + ToString(
NewChunkSize) +
" bytes");
824 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(
this));
843 const unsigned long ulOriginalPos = ulWritePos;
847 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
857 throw Exception(
"Writing Chunk data (from RAM) failed");
861 DWORD dwBytesWritten;
864 throw Exception(
"Writing Chunk data (from RAM) failed");
869 throw Exception(
"Writing Chunk data (from RAM) failed");
874 int8_t* pCopyBuffer =
new int8_t[4096];
877 DWORD iBytesMoved = 1;
881 for (
unsigned long ulOffset = 0; ulToMove > 0 && iBytesMoved > 0; ulOffset += iBytesMoved, ulToMove -= iBytesMoved) {
882 iBytesMoved = (ulToMove < 4096) ? ulToMove : 4096;
890 ReadFile(
pFile->
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
891 SetFilePointer(
pFile->
hFileWrite, ulWritePos + ulOffset, NULL, FILE_BEGIN);
892 WriteFile(
pFile->
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
895 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
pFile->
hFileRead);
900 delete[] pCopyBuffer;
901 if (iBytesMoved < 0)
throw Exception(
"Writing Chunk data (from file) failed");
914 const char cPadByte = 0;
920 DWORD dwBytesWritten;
943 std::cout <<
"List::List(File* pFile)" << std::endl;
950 :
Chunk(pFile, StartPos, Parent) {
952 std::cout <<
"List::List(File*,ulong,bool,List*)" << std::endl;
969 std::cout <<
"List::~List()" << std::endl;
976 ChunkList::iterator iter =
pSubChunks->begin();
978 while (iter != end) {
1004 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1023 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1026 ChunkList::iterator iter =
pSubChunks->begin();
1028 while (iter != end) {
1048 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1064 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1082 std::cout <<
"List::GetFirstSubList()" << std::endl;
1104 std::cout <<
"List::GetNextSubList()" << std::endl;
1130 unsigned int result = 0;
1132 ChunkList::iterator iter =
pSubChunks->begin();
1134 while (iter != end) {
1135 if ((*iter)->GetChunkID() ==
ChunkID) {
1155 unsigned int result = 0;
1157 ChunkList::iterator iter =
pSubChunks->begin();
1159 while (iter != end) {
1183 if (uiBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1187 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1188 pNewChunk->
Resize(uiBodySize);
1221 if (pNewParent ==
this || !pNewParent)
return;
1230 ChunkList::iterator iter =
pSubChunks->begin();
1232 for (; iter != end; ++iter) {
1233 if ((*iter)->GetChunkID() == pSrc->
GetChunkID()) {
1234 (*pSubChunksMap)[pSrc->
GetChunkID()] = *iter;
1260 return pNewListChunk;
1279 ChunkList::iterator iter =
pSubChunks->begin();
1281 for (; iter != end; ++iter) {
1282 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1283 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1293 std::cout <<
"List::Readheader(ulong) ";
1301 #elif defined(WIN32)
1325 #elif defined(WIN32)
1327 DWORD dwBytesWritten;
1337 std::cout <<
"List::LoadSubChunks()";
1347 unsigned long uiOriginalPos =
GetPos();
1365 (*pSubChunksMap)[ckid] = ck;
1374 pList->LoadSubChunksRecursively();
1392 const unsigned long ulOriginalPos = ulWritePos;
1396 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1400 for (ChunkList::iterator iter =
pSubChunks->begin(), end =
pSubChunks->end(); iter != end; ++iter) {
1401 ulWritePos = (*iter)->WriteChunk(ulWritePos, ulCurrentDataOffset);
1418 for (ChunkList::iterator iter =
pSubChunks->begin(), end =
pSubChunks->end(); iter != end; ++iter) {
1419 (*iter)->__resetPos();
1437 #define _GET_RESIZED_CHUNKS() \
1438 (reinterpret_cast<std::set<Chunk*>*>(ResizedChunks.front()))
1458 ResizedChunks.push_back(reinterpret_cast<Chunk*>(
new std::set<Chunk*>));
1482 std::cout <<
"File::File("<<path<<
")" << std::endl;
1486 __openExistingFile(path);
1523 :
List(this), Filename(path), bIsNewFile(false), Layout(layout)
1527 __openExistingFile(path, &FileType);
1545 void File::__openExistingFile(
const String& path, uint32_t* FileType) {
1547 ResizedChunks.push_back(reinterpret_cast<Chunk*>(
new std::set<Chunk*>));
1554 #elif defined(WIN32)
1556 path.c_str(), GENERIC_READ,
1557 FILE_SHARE_READ | FILE_SHARE_WRITE,
1558 NULL, OPEN_EXISTING,
1559 FILE_ATTRIBUTE_NORMAL |
1560 FILE_FLAG_RANDOM_ACCESS, NULL
1562 if (
hFileRead == INVALID_HANDLE_VALUE) {
1575 if (FileType &&
ChunkID != *FileType)
1583 if (
Read(&ckid, 4, 1) != 4) {
1584 throw RIFF::Exception(
"Invalid file header ID (premature end of header)");
1585 }
else if (ckid != *FileType) {
1623 if (NewMode != Mode) {
1633 #elif defined(WIN32)
1637 FILE_SHARE_READ | FILE_SHARE_WRITE,
1638 NULL, OPEN_EXISTING,
1639 FILE_ATTRIBUTE_NORMAL |
1640 FILE_FLAG_RANDOM_ACCESS,
1643 if (
hFileRead == INVALID_HANDLE_VALUE) {
1662 #elif defined(WIN32)
1666 GENERIC_READ | GENERIC_WRITE,
1669 FILE_ATTRIBUTE_NORMAL |
1670 FILE_FLAG_RANDOM_ACCESS,
1673 if (
hFileRead == INVALID_HANDLE_VALUE) {
1676 FILE_SHARE_READ | FILE_SHARE_WRITE,
1677 NULL, OPEN_EXISTING,
1678 FILE_ATTRIBUTE_NORMAL |
1679 FILE_FLAG_RANDOM_ACCESS,
1682 throw Exception(
"Could not (re)open file \"" +
Filename +
"\" in read+write mode");
1698 #elif defined(WIN32)
1708 throw Exception(
"Unknown file access mode");
1746 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
1762 unsigned long ulPositiveSizeDiff = 0;
1764 for (std::set<Chunk*>::const_iterator iter = resizedChunks->begin(), end = resizedChunks->end(); iter != end; ++iter) {
1765 if ((*iter)->GetNewSize() == 0) {
1766 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(*iter));
1768 unsigned long newSizePadded = (*iter)->GetNewSize() + (*iter)->GetNewSize() % 2;
1769 unsigned long oldSizePadded = (*iter)->GetSize() + (*iter)->GetSize() % 2;
1770 if (newSizePadded > oldSizePadded) ulPositiveSizeDiff += newSizePadded - oldSizePadded;
1773 unsigned long ulWorkingFileSize = GetFileSize();
1776 if (ulPositiveSizeDiff > 0) {
1778 ulWorkingFileSize += ulPositiveSizeDiff;
1779 ResizeFile(ulWorkingFileSize);
1781 int8_t* pCopyBuffer =
new int8_t[4096];
1784 DWORD iBytesMoved = 1;
1786 int iBytesMoved = 1;
1788 for (
unsigned long ulPos = ulFileSize; iBytesMoved > 0; ) {
1790 ulPos -= iBytesMoved;
1793 iBytesMoved = read(
hFileRead, pCopyBuffer, iBytesMoved);
1795 iBytesMoved = write(
hFileWrite, pCopyBuffer, iBytesMoved);
1796 #elif defined(WIN32)
1798 ReadFile(
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1799 SetFilePointer(
hFileWrite,
ulPos + ulPositiveSizeDiff, NULL, FILE_BEGIN);
1800 WriteFile(
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1803 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
hFileRead);
1805 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved,
hFileWrite);
1808 delete[] pCopyBuffer;
1809 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
1813 unsigned long ulTotalSize =
WriteChunk(0, ulPositiveSizeDiff);
1814 unsigned long ulActualSize = __GetFileSize(
hFileWrite);
1817 if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1820 resizedChunks->clear();
1841 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
1849 hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
1852 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1854 #elif defined(WIN32)
1856 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
1857 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
1858 FILE_FLAG_RANDOM_ACCESS, NULL
1862 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1868 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1874 unsigned long ulTotalSize =
WriteChunk(0, 0);
1875 unsigned long ulActualSize = __GetFileSize(
hFileWrite);
1878 if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1885 #elif defined(WIN32)
1899 void File::ResizeFile(
unsigned long ulNewSize) {
1903 #elif defined(WIN32)
1905 SetFilePointer(
hFileWrite, ulNewSize, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
1909 # error Sorry, this version of libgig only supports POSIX and Windows systems yet.
1910 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)!
1916 std::cout <<
"File::~File()" << std::endl;
1929 void File::Cleanup() {
1932 #elif defined(WIN32)
1951 unsigned long File::GetFileSize() {
1956 unsigned long File::__GetFileSize(
int hFile) {
1957 struct stat filestat;
1958 fstat(hFile, &filestat);
1959 long size = filestat.st_size;
1962 #elif defined(WIN32)
1963 unsigned long File::__GetFileSize(HANDLE hFile) {
1964 DWORD dwSize = ::GetFileSize(hFile, NULL );
1965 if (dwSize == INVALID_FILE_SIZE)
1966 throw Exception(
"Windows FS error: could not determine file size");
1969 #else // standard C functions
1970 unsigned long File::__GetFileSize(FILE* hFile) {
1971 long curpos = ftell(hFile);
1972 fseek(hFile, 0, SEEK_END);
1973 long size = ftell(hFile);
1974 fseek(hFile, curpos, SEEK_SET);
1984 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()
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.