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;
612 return Write(pData, WordCount, 4);
624 std::cout <<
"Chunk::ReadInt8()" << std::endl;
640 std::cout <<
"Chunk::ReadUint8()" << std::endl;
657 std::cout <<
"Chunk::ReadInt16()" << std::endl;
674 std::cout <<
"Chunk::ReadUint16()" << std::endl;
691 std::cout <<
"Chunk::ReadInt32()" << std::endl;
708 std::cout <<
"Chunk::ReadUint32()" << std::endl;
764 if (!pNewBuffer)
throw Exception(
"Could not enlarge chunk data buffer to " + ToString(
NewChunkSize) +
" bytes");
807 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(
this));
826 const unsigned long ulOriginalPos = ulWritePos;
830 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
840 throw Exception(
"Writing Chunk data (from RAM) failed");
844 DWORD dwBytesWritten;
847 throw Exception(
"Writing Chunk data (from RAM) failed");
852 throw Exception(
"Writing Chunk data (from RAM) failed");
857 int8_t* pCopyBuffer =
new int8_t[4096];
860 DWORD iBytesMoved = 1;
864 for (
unsigned long ulOffset = 0; iBytesMoved > 0; ulOffset += iBytesMoved, ulToMove -= iBytesMoved) {
865 iBytesMoved = (ulToMove < 4096) ? ulToMove : 4096;
873 ReadFile(
pFile->
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
874 SetFilePointer(
pFile->
hFileWrite, ulWritePos + ulOffset, NULL, FILE_BEGIN);
875 WriteFile(
pFile->
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
878 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
pFile->
hFileRead);
883 delete[] pCopyBuffer;
884 if (iBytesMoved < 0)
throw Exception(
"Writing Chunk data (from file) failed");
897 const char cPadByte = 0;
903 DWORD dwBytesWritten;
926 std::cout <<
"List::List(File* pFile)" << std::endl;
933 :
Chunk(pFile, StartPos, Parent) {
935 std::cout <<
"List::List(File*,ulong,bool,List*)" << std::endl;
952 std::cout <<
"List::~List()" << std::endl;
981 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1000 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1003 ChunkList::iterator iter =
pSubChunks->begin();
1005 while (iter != end) {
1025 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1041 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1059 std::cout <<
"List::GetFirstSubList()" << std::endl;
1081 std::cout <<
"List::GetNextSubList()" << std::endl;
1107 unsigned int result = 0;
1109 ChunkList::iterator iter =
pSubChunks->begin();
1111 while (iter != end) {
1112 if ((*iter)->GetChunkID() ==
ChunkID) {
1132 unsigned int result = 0;
1134 ChunkList::iterator iter =
pSubChunks->begin();
1136 while (iter != end) {
1160 if (uiBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1164 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1165 pNewChunk->
Resize(uiBodySize);
1205 return pNewListChunk;
1224 ChunkList::iterator iter =
pSubChunks->begin();
1226 for (; iter != end; ++iter) {
1227 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1228 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1238 std::cout <<
"List::Readheader(ulong) ";
1246 #elif defined(WIN32)
1270 #elif defined(WIN32)
1272 DWORD dwBytesWritten;
1282 std::cout <<
"List::LoadSubChunks()";
1292 unsigned long uiOriginalPos =
GetPos();
1310 (*pSubChunksMap)[ckid] = ck;
1319 pList->LoadSubChunksRecursively();
1337 const unsigned long ulOriginalPos = ulWritePos;
1341 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1345 for (ChunkList::iterator iter =
pSubChunks->begin(), end =
pSubChunks->end(); iter != end; ++iter) {
1346 ulWritePos = (*iter)->WriteChunk(ulWritePos, ulCurrentDataOffset);
1363 for (ChunkList::iterator iter =
pSubChunks->begin(), end =
pSubChunks->end(); iter != end; ++iter) {
1364 (*iter)->__resetPos();
1382 #define _GET_RESIZED_CHUNKS() \
1383 (reinterpret_cast<std::set<Chunk*>*>(ResizedChunks.front()))
1401 ResizedChunks.push_back(reinterpret_cast<Chunk*>(
new std::set<Chunk*>));
1423 std::cout <<
"File::File("<<path<<
")" << std::endl;
1427 ResizedChunks.push_back(reinterpret_cast<Chunk*>(
new std::set<Chunk*>));
1434 #elif defined(WIN32)
1436 path.c_str(), GENERIC_READ,
1437 FILE_SHARE_READ | FILE_SHARE_WRITE,
1438 NULL, OPEN_EXISTING,
1439 FILE_ATTRIBUTE_NORMAL |
1440 FILE_FLAG_RANDOM_ACCESS, NULL
1442 if (
hFileRead == INVALID_HANDLE_VALUE) {
1477 if (NewMode != Mode) {
1487 #elif defined(WIN32)
1491 FILE_SHARE_READ | FILE_SHARE_WRITE,
1492 NULL, OPEN_EXISTING,
1493 FILE_ATTRIBUTE_NORMAL |
1494 FILE_FLAG_RANDOM_ACCESS,
1497 if (
hFileRead == INVALID_HANDLE_VALUE) {
1516 #elif defined(WIN32)
1520 GENERIC_READ | GENERIC_WRITE,
1523 FILE_ATTRIBUTE_NORMAL |
1524 FILE_FLAG_RANDOM_ACCESS,
1527 if (
hFileRead == INVALID_HANDLE_VALUE) {
1530 FILE_SHARE_READ | FILE_SHARE_WRITE,
1531 NULL, OPEN_EXISTING,
1532 FILE_ATTRIBUTE_NORMAL |
1533 FILE_FLAG_RANDOM_ACCESS,
1536 throw Exception(
"Could not (re)open file \"" +
Filename +
"\" in read+write mode");
1552 #elif defined(WIN32)
1562 throw Exception(
"Unknown file access mode");
1612 unsigned long ulPositiveSizeDiff = 0;
1614 for (std::set<Chunk*>::const_iterator iter = resizedChunks->begin(), end = resizedChunks->end(); iter != end; ++iter) {
1615 if ((*iter)->GetNewSize() == 0) {
1616 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(*iter));
1618 unsigned long newSizePadded = (*iter)->GetNewSize() + (*iter)->GetNewSize() % 2;
1619 unsigned long oldSizePadded = (*iter)->GetSize() + (*iter)->GetSize() % 2;
1620 if (newSizePadded > oldSizePadded) ulPositiveSizeDiff += newSizePadded - oldSizePadded;
1623 unsigned long ulWorkingFileSize = GetFileSize();
1626 if (ulPositiveSizeDiff > 0) {
1628 ulWorkingFileSize += ulPositiveSizeDiff;
1629 ResizeFile(ulWorkingFileSize);
1631 int8_t* pCopyBuffer =
new int8_t[4096];
1634 DWORD iBytesMoved = 1;
1636 int iBytesMoved = 1;
1638 for (
unsigned long ulPos = ulFileSize; iBytesMoved > 0; ) {
1640 ulPos -= iBytesMoved;
1643 iBytesMoved = read(
hFileRead, pCopyBuffer, iBytesMoved);
1645 iBytesMoved = write(
hFileWrite, pCopyBuffer, iBytesMoved);
1646 #elif defined(WIN32)
1648 ReadFile(
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1649 SetFilePointer(
hFileWrite,
ulPos + ulPositiveSizeDiff, NULL, FILE_BEGIN);
1650 WriteFile(
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1653 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
hFileRead);
1655 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved,
hFileWrite);
1658 delete[] pCopyBuffer;
1659 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
1663 unsigned long ulTotalSize =
WriteChunk(0, ulPositiveSizeDiff);
1664 unsigned long ulActualSize = __GetFileSize(
hFileWrite);
1667 if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1670 resizedChunks->clear();
1695 hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
1698 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1700 #elif defined(WIN32)
1702 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
1703 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
1704 FILE_FLAG_RANDOM_ACCESS, NULL
1708 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1714 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1720 unsigned long ulTotalSize =
WriteChunk(0, 0);
1721 unsigned long ulActualSize = __GetFileSize(
hFileWrite);
1724 if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1731 #elif defined(WIN32)
1744 void File::ResizeFile(
unsigned long ulNewSize) {
1748 #elif defined(WIN32)
1750 SetFilePointer(
hFileWrite, ulNewSize, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
1754 # error Sorry, this version of libgig only supports POSIX and Windows systems yet.
1755 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)!
1761 std::cout <<
"File::~File()" << std::endl;
1765 #elif defined(WIN32)
1784 unsigned long File::GetFileSize() {
1789 unsigned long File::__GetFileSize(
int hFile) {
1790 struct stat filestat;
1791 fstat(hFile, &filestat);
1792 long size = filestat.st_size;
1795 #elif defined(WIN32)
1796 unsigned long File::__GetFileSize(HANDLE hFile) {
1797 DWORD dwSize = ::GetFileSize(hFile, NULL );
1798 if (dwSize == INVALID_FILE_SIZE)
1799 throw Exception(
"Windows FS error: could not determine file size");
1802 #else // standard C functions
1803 unsigned long File::__GetFileSize(FILE* hFile) {
1804 long curpos = ftell(hFile);
1805 fseek(hFile, 0, SEEK_END);
1806 long size = ftell(hFile);
1807 fseek(hFile, curpos, SEEK_SET);
1817 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.
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 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.
unsigned long GetSize()
Chunk size in bytes (without header, thus the chunk data body)
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.
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
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 * 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...
unsigned long ulChunkDataSize
List * AddSubList(uint32_t uiListType)
Creates a new list sub chunk.
void LoadSubChunksRecursively()
RIFF specific classes and definitions.
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.
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.