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;
959 ChunkList::iterator iter =
pSubChunks->begin();
961 while (iter != end) {
987 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1006 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1009 ChunkList::iterator iter =
pSubChunks->begin();
1011 while (iter != end) {
1031 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1047 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1065 std::cout <<
"List::GetFirstSubList()" << std::endl;
1087 std::cout <<
"List::GetNextSubList()" << std::endl;
1113 unsigned int result = 0;
1115 ChunkList::iterator iter =
pSubChunks->begin();
1117 while (iter != end) {
1118 if ((*iter)->GetChunkID() ==
ChunkID) {
1138 unsigned int result = 0;
1140 ChunkList::iterator iter =
pSubChunks->begin();
1142 while (iter != end) {
1166 if (uiBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1170 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1171 pNewChunk->
Resize(uiBodySize);
1211 return pNewListChunk;
1230 ChunkList::iterator iter =
pSubChunks->begin();
1232 for (; iter != end; ++iter) {
1233 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1234 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1244 std::cout <<
"List::Readheader(ulong) ";
1252 #elif defined(WIN32)
1276 #elif defined(WIN32)
1278 DWORD dwBytesWritten;
1288 std::cout <<
"List::LoadSubChunks()";
1298 unsigned long uiOriginalPos =
GetPos();
1316 (*pSubChunksMap)[ckid] = ck;
1325 pList->LoadSubChunksRecursively();
1343 const unsigned long ulOriginalPos = ulWritePos;
1347 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1351 for (ChunkList::iterator iter =
pSubChunks->begin(), end =
pSubChunks->end(); iter != end; ++iter) {
1352 ulWritePos = (*iter)->WriteChunk(ulWritePos, ulCurrentDataOffset);
1369 for (ChunkList::iterator iter =
pSubChunks->begin(), end =
pSubChunks->end(); iter != end; ++iter) {
1370 (*iter)->__resetPos();
1388 #define _GET_RESIZED_CHUNKS() \
1389 (reinterpret_cast<std::set<Chunk*>*>(ResizedChunks.front()))
1407 ResizedChunks.push_back(reinterpret_cast<Chunk*>(
new std::set<Chunk*>));
1429 std::cout <<
"File::File("<<path<<
")" << std::endl;
1433 ResizedChunks.push_back(reinterpret_cast<Chunk*>(
new std::set<Chunk*>));
1440 #elif defined(WIN32)
1442 path.c_str(), GENERIC_READ,
1443 FILE_SHARE_READ | FILE_SHARE_WRITE,
1444 NULL, OPEN_EXISTING,
1445 FILE_ATTRIBUTE_NORMAL |
1446 FILE_FLAG_RANDOM_ACCESS, NULL
1448 if (
hFileRead == INVALID_HANDLE_VALUE) {
1483 if (NewMode != Mode) {
1493 #elif defined(WIN32)
1497 FILE_SHARE_READ | FILE_SHARE_WRITE,
1498 NULL, OPEN_EXISTING,
1499 FILE_ATTRIBUTE_NORMAL |
1500 FILE_FLAG_RANDOM_ACCESS,
1503 if (
hFileRead == INVALID_HANDLE_VALUE) {
1522 #elif defined(WIN32)
1526 GENERIC_READ | GENERIC_WRITE,
1529 FILE_ATTRIBUTE_NORMAL |
1530 FILE_FLAG_RANDOM_ACCESS,
1533 if (
hFileRead == INVALID_HANDLE_VALUE) {
1536 FILE_SHARE_READ | FILE_SHARE_WRITE,
1537 NULL, OPEN_EXISTING,
1538 FILE_ATTRIBUTE_NORMAL |
1539 FILE_FLAG_RANDOM_ACCESS,
1542 throw Exception(
"Could not (re)open file \"" +
Filename +
"\" in read+write mode");
1558 #elif defined(WIN32)
1568 throw Exception(
"Unknown file access mode");
1618 unsigned long ulPositiveSizeDiff = 0;
1620 for (std::set<Chunk*>::const_iterator iter = resizedChunks->begin(), end = resizedChunks->end(); iter != end; ++iter) {
1621 if ((*iter)->GetNewSize() == 0) {
1622 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(*iter));
1624 unsigned long newSizePadded = (*iter)->GetNewSize() + (*iter)->GetNewSize() % 2;
1625 unsigned long oldSizePadded = (*iter)->GetSize() + (*iter)->GetSize() % 2;
1626 if (newSizePadded > oldSizePadded) ulPositiveSizeDiff += newSizePadded - oldSizePadded;
1629 unsigned long ulWorkingFileSize = GetFileSize();
1632 if (ulPositiveSizeDiff > 0) {
1634 ulWorkingFileSize += ulPositiveSizeDiff;
1635 ResizeFile(ulWorkingFileSize);
1637 int8_t* pCopyBuffer =
new int8_t[4096];
1640 DWORD iBytesMoved = 1;
1642 int iBytesMoved = 1;
1644 for (
unsigned long ulPos = ulFileSize; iBytesMoved > 0; ) {
1646 ulPos -= iBytesMoved;
1649 iBytesMoved = read(
hFileRead, pCopyBuffer, iBytesMoved);
1651 iBytesMoved = write(
hFileWrite, pCopyBuffer, iBytesMoved);
1652 #elif defined(WIN32)
1654 ReadFile(
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1655 SetFilePointer(
hFileWrite,
ulPos + ulPositiveSizeDiff, NULL, FILE_BEGIN);
1656 WriteFile(
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1659 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
hFileRead);
1661 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved,
hFileWrite);
1664 delete[] pCopyBuffer;
1665 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
1669 unsigned long ulTotalSize =
WriteChunk(0, ulPositiveSizeDiff);
1670 unsigned long ulActualSize = __GetFileSize(
hFileWrite);
1673 if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1676 resizedChunks->clear();
1701 hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
1704 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1706 #elif defined(WIN32)
1708 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
1709 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
1710 FILE_FLAG_RANDOM_ACCESS, NULL
1714 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1720 throw Exception(
"Could not open file \"" + path +
"\" for writing");
1726 unsigned long ulTotalSize =
WriteChunk(0, 0);
1727 unsigned long ulActualSize = __GetFileSize(
hFileWrite);
1730 if (ulTotalSize < ulActualSize) ResizeFile(ulTotalSize);
1737 #elif defined(WIN32)
1750 void File::ResizeFile(
unsigned long ulNewSize) {
1754 #elif defined(WIN32)
1756 SetFilePointer(
hFileWrite, ulNewSize, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ||
1760 # error Sorry, this version of libgig only supports POSIX and Windows systems yet.
1761 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)!
1767 std::cout <<
"File::~File()" << std::endl;
1771 #elif defined(WIN32)
1790 unsigned long File::GetFileSize() {
1795 unsigned long File::__GetFileSize(
int hFile) {
1796 struct stat filestat;
1797 fstat(hFile, &filestat);
1798 long size = filestat.st_size;
1801 #elif defined(WIN32)
1802 unsigned long File::__GetFileSize(HANDLE hFile) {
1803 DWORD dwSize = ::GetFileSize(hFile, NULL );
1804 if (dwSize == INVALID_FILE_SIZE)
1805 throw Exception(
"Windows FS error: could not determine file size");
1808 #else // standard C functions
1809 unsigned long File::__GetFileSize(FILE* hFile) {
1810 long curpos = ftell(hFile);
1811 fseek(hFile, 0, SEEK_END);
1812 long size = ftell(hFile);
1813 fseek(hFile, curpos, SEEK_SET);
1823 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()
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.