42 static String __resolveChunkPath(Chunk* pCk) {
44 for (Chunk* pChunk = pCk; pChunk; pChunk = pChunk->GetParent()) {
45 if (pChunk->GetChunkID() == CHUNK_ID_LIST) {
46 List* pList = (List*) pChunk;
47 sPath =
"->'" + pList->GetListTypeString() +
"'" + sPath;
49 sPath =
"->'" + pChunk->GetChunkIDString() +
"'" + sPath;
60 progress_t::progress_t() {
72 Chunk::Chunk(File* pFile) {
74 std::cout <<
"Chunk::Chunk(File* pFile)" << std::endl;
79 ullCurrentChunkSize = 0;
82 ChunkID = CHUNK_ID_RIFF;
86 Chunk::Chunk(File* pFile,
file_offset_t StartPos, List* Parent) {
88 std::cout <<
"Chunk::Chunk(File*,file_offset_t,List*),StartPos=" << StartPos << std::endl;
91 ullStartPos = StartPos + CHUNK_HEADER_SIZE(pFile->FileOffsetSize);
95 ullCurrentChunkSize = 0;
101 Chunk::Chunk(File* pFile, List* pParent, uint32_t uiChunkID,
file_offset_t ullBodySize) {
104 this->pParent = pParent;
108 ullChunkDataSize = 0;
109 ullCurrentChunkSize = 0;
110 ullNewChunkSize = ullBodySize;
114 if (pChunkData)
delete[] pChunkData;
119 std::cout <<
"Chunk::Readheader(" << filePos <<
") ";
122 ullNewChunkSize = ullCurrentChunkSize = 0;
124 if (lseek(pFile->
hFileRead, filePos, SEEK_SET) != -1) {
128 LARGE_INTEGER liFilePos;
129 liFilePos.QuadPart = filePos;
130 if (SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN)) {
132 ReadFile(pFile->
hFileRead, &ChunkID, 4, &dwBytesRead, NULL);
135 if (!fseeko(pFile->
hFileRead, filePos, SEEK_SET)) {
140 if (ChunkID == CHUNK_ID_RIFF) {
141 pFile->bEndianNative =
false;
143 #else // little endian 144 if (ChunkID == CHUNK_ID_RIFX) {
145 pFile->bEndianNative =
false;
146 ChunkID = CHUNK_ID_RIFF;
148 #endif // WORDS_BIGENDIAN 149 if (!pFile->bEndianNative) {
152 swapBytes_32(&ullCurrentChunkSize);
154 swapBytes_64(&ullCurrentChunkSize);
157 std::cout <<
"ckID=" << convertToString(ChunkID) <<
" ";
158 std::cout <<
"ckSize=" << ullCurrentChunkSize <<
" ";
159 std::cout <<
"bEndianNative=" << pFile->bEndianNative << std::endl;
161 ullNewChunkSize = ullCurrentChunkSize;
166 uint32_t uiNewChunkID = ChunkID;
167 if (ChunkID == CHUNK_ID_RIFF) {
169 if (pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
170 #else // little endian 171 if (!pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
172 #endif // WORDS_BIGENDIAN 175 uint64_t ullNewChunkSize = this->ullNewChunkSize;
176 if (!pFile->bEndianNative) {
178 swapBytes_32(&ullNewChunkSize);
180 swapBytes_64(&ullNewChunkSize);
184 if (lseek(pFile->
hFileWrite, filePos, SEEK_SET) != -1) {
189 LARGE_INTEGER liFilePos;
190 liFilePos.QuadPart = filePos;
191 if (SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN)) {
192 DWORD dwBytesWritten;
193 WriteFile(pFile->
hFileWrite, &uiNewChunkID, 4, &dwBytesWritten, NULL);
197 if (!fseeko(pFile->
hFileWrite, filePos, SEEK_SET)) {
198 fwrite(&uiNewChunkID, 4, 1, pFile->
hFileWrite);
209 return convertToString(ChunkID);
226 std::cout <<
"Chunk::SetPos(file_offset_t,stream_whence_t)" << std::endl;
233 ullPos = ullCurrentChunkSize - 1 - Where;
235 case stream_backward:
238 case stream_start:
default:
242 if (ullPos > ullCurrentChunkSize) ullPos = ullCurrentChunkSize;
258 std::cout <<
"Chunk::Remainingbytes()=" << ullCurrentChunkSize - ullPos << std::endl;
260 return (ullCurrentChunkSize > ullPos) ? ullCurrentChunkSize - ullPos : 0;
271 return CHUNK_HEADER_SIZE(fileOffsetSize) +
289 std::cout <<
"Chunk::GetState()" << std::endl;
292 if (pFile->
hFileRead == 0)
return stream_closed;
293 #elif defined (WIN32) 294 if (pFile->
hFileRead == INVALID_HANDLE_VALUE)
295 return stream_closed;
297 if (pFile->
hFileRead == NULL)
return stream_closed;
299 if (ullPos < ullCurrentChunkSize)
return stream_ready;
300 else return stream_end_reached;
320 std::cout <<
"Chunk::Read(void*,file_offset_t,file_offset_t)" << std::endl;
323 if (ullPos >= ullCurrentChunkSize)
return 0;
324 if (ullPos + WordCount * WordSize >= ullCurrentChunkSize) WordCount = (ullCurrentChunkSize - ullPos) / WordSize;
326 if (lseek(pFile->
hFileRead, ullStartPos + ullPos, SEEK_SET) < 0)
return 0;
327 ssize_t readWords = read(pFile->
hFileRead, pData, WordCount * WordSize);
330 std::cerr <<
"POSIX read() failed: " << strerror(errno) << std::endl << std::flush;
334 readWords /= WordSize;
336 LARGE_INTEGER liFilePos;
337 liFilePos.QuadPart = ullStartPos + ullPos;
338 if (!SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN))
341 ReadFile(pFile->
hFileRead, pData, WordCount * WordSize, &readWords, NULL);
342 if (readWords < 1)
return 0;
343 readWords /= WordSize;
344 #else // standard C functions 345 if (fseeko(pFile->
hFileRead, ullStartPos + ullPos, SEEK_SET))
return 0;
348 if (!pFile->bEndianNative && WordSize != 1) {
352 swapBytes_16((uint16_t*) pData + iWord);
356 swapBytes_32((uint32_t*) pData + iWord);
360 swapBytes_64((uint64_t*) pData + iWord);
364 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
368 SetPos(readWords * WordSize, stream_curpos);
389 if (pFile->Mode != stream_mode_read_write)
390 throw Exception(
"Cannot write data to chunk, file has to be opened in read+write mode first");
391 if (ullPos >= ullCurrentChunkSize || ullPos + WordCount * WordSize > ullCurrentChunkSize)
392 throw Exception(
"End of chunk reached while trying to write data");
393 if (!pFile->bEndianNative && WordSize != 1) {
397 swapBytes_16((uint16_t*) pData + iWord);
401 swapBytes_32((uint32_t*) pData + iWord);
405 swapBytes_64((uint64_t*) pData + iWord);
409 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
414 if (lseek(pFile->
hFileWrite, ullStartPos + ullPos, SEEK_SET) < 0) {
415 throw Exception(
"Could not seek to position " + ToString(ullPos) +
416 " in chunk (" + ToString(ullStartPos + ullPos) +
" in file)");
418 ssize_t writtenWords = write(pFile->
hFileWrite, pData, WordCount * WordSize);
419 if (writtenWords < 1)
throw Exception(
"POSIX IO Error while trying to write chunk data");
420 writtenWords /= WordSize;
422 LARGE_INTEGER liFilePos;
423 liFilePos.QuadPart = ullStartPos + ullPos;
424 if (!SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN)) {
425 throw Exception(
"Could not seek to position " + ToString(ullPos) +
426 " in chunk (" + ToString(ullStartPos + ullPos) +
" in file)");
429 WriteFile(pFile->
hFileWrite, pData, WordCount * WordSize, &writtenWords, NULL);
430 if (writtenWords < 1)
throw Exception(
"Windows IO Error while trying to write chunk data");
431 writtenWords /= WordSize;
432 #else // standard C functions 433 if (fseeko(pFile->
hFileWrite, ullStartPos + ullPos, SEEK_SET)) {
434 throw Exception(
"Could not seek to position " + ToString(ullPos) +
435 " in chunk (" + ToString(ullStartPos + ullPos) +
" in file)");
439 SetPos(writtenWords * WordSize, stream_curpos);
446 if (readWords != WordCount)
throw RIFF::Exception(
"End of chunk data reached.");
463 std::cout <<
"Chunk::ReadInt8(int8_t*,file_offset_t)" << std::endl;
483 return Write(pData, WordCount, 1);
500 std::cout <<
"Chunk::ReadUint8(uint8_t*,file_offset_t)" << std::endl;
520 return Write(pData, WordCount, 1);
537 std::cout <<
"Chunk::ReadInt16(int16_t*,file_offset_t)" << std::endl;
557 return Write(pData, WordCount, 2);
574 std::cout <<
"Chunk::ReadUint16(uint16_t*,file_offset_t)" << std::endl;
594 return Write(pData, WordCount, 2);
611 std::cout <<
"Chunk::ReadInt32(int32_t*,file_offset_t)" << std::endl;
631 return Write(pData, WordCount, 4);
648 std::cout <<
"Chunk::ReadUint32(uint32_t*,file_offset_t)" << std::endl;
664 char* buf =
new char[size];
666 s.assign(buf, std::find(buf, buf + size,
'\0'));
685 return Write(pData, WordCount, 4);
697 std::cout <<
"Chunk::ReadInt8()" << std::endl;
713 std::cout <<
"Chunk::ReadUint8()" << std::endl;
730 std::cout <<
"Chunk::ReadInt16()" << std::endl;
747 std::cout <<
"Chunk::ReadUint16()" << std::endl;
764 std::cout <<
"Chunk::ReadInt32()" << std::endl;
781 std::cout <<
"Chunk::ReadUint32()" << std::endl;
810 if (!pChunkData && pFile->Filename !=
"" ) {
812 if (lseek(pFile->
hFileRead, ullStartPos, SEEK_SET) == -1)
return NULL;
814 LARGE_INTEGER liFilePos;
815 liFilePos.QuadPart = ullStartPos;
816 if (!SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN))
return NULL;
818 if (fseeko(pFile->
hFileRead, ullStartPos, SEEK_SET))
return NULL;
820 file_offset_t ullBufferSize = (ullCurrentChunkSize > ullNewChunkSize) ? ullCurrentChunkSize : ullNewChunkSize;
821 pChunkData =
new uint8_t[ullBufferSize];
822 if (!pChunkData)
return NULL;
823 memset(pChunkData, 0, ullBufferSize);
834 return (pChunkData = NULL);
836 ullChunkDataSize = ullBufferSize;
837 }
else if (ullNewChunkSize > ullChunkDataSize) {
838 uint8_t* pNewBuffer =
new uint8_t[ullNewChunkSize];
839 if (!pNewBuffer)
throw Exception(
"Could not enlarge chunk data buffer to " + ToString(ullNewChunkSize) +
" bytes");
840 memset(pNewBuffer, 0 , ullNewChunkSize);
841 memcpy(pNewBuffer, pChunkData, ullChunkDataSize);
843 pChunkData = pNewBuffer;
844 ullChunkDataSize = ullNewChunkSize;
882 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(
this));
883 if ((NewSize >> 48) != 0)
884 throw Exception(
"Unrealistic high chunk size detected: " + __resolveChunkPath(
this));
885 if (ullNewChunkSize == NewSize)
return;
886 ullNewChunkSize = NewSize;
906 if (pFile->Mode != stream_mode_read_write)
907 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
915 lseek(pFile->
hFileWrite, ullWritePos, SEEK_SET);
916 if (write(pFile->
hFileWrite, pChunkData, ullNewChunkSize) != ullNewChunkSize) {
917 throw Exception(
"Writing Chunk data (from RAM) failed");
920 LARGE_INTEGER liFilePos;
921 liFilePos.QuadPart = ullWritePos;
922 SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN);
923 DWORD dwBytesWritten;
924 WriteFile(pFile->
hFileWrite, pChunkData, ullNewChunkSize, &dwBytesWritten, NULL);
925 if (dwBytesWritten != ullNewChunkSize) {
926 throw Exception(
"Writing Chunk data (from RAM) failed");
929 fseeko(pFile->
hFileWrite, ullWritePos, SEEK_SET);
930 if (fwrite(pChunkData, 1, ullNewChunkSize, pFile->
hFileWrite) != ullNewChunkSize) {
931 throw Exception(
"Writing Chunk data (from RAM) failed");
936 int8_t* pCopyBuffer =
new int8_t[4096];
937 file_offset_t ullToMove = (ullNewChunkSize < ullCurrentChunkSize) ? ullNewChunkSize : ullCurrentChunkSize;
939 DWORD iBytesMoved = 1;
943 for (
file_offset_t ullOffset = 0; ullToMove > 0 && iBytesMoved > 0; ullOffset += iBytesMoved, ullToMove -= iBytesMoved) {
944 iBytesMoved = (ullToMove < 4096) ?
int(ullToMove) : 4096;
946 lseek(pFile->
hFileRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
947 iBytesMoved = (int) read(pFile->
hFileRead, pCopyBuffer, (
size_t) iBytesMoved);
948 lseek(pFile->
hFileWrite, ullWritePos + ullOffset, SEEK_SET);
949 iBytesMoved = (int) write(pFile->
hFileWrite, pCopyBuffer, (
size_t) iBytesMoved);
951 LARGE_INTEGER liFilePos;
952 liFilePos.QuadPart = ullStartPos + ullCurrentDataOffset + ullOffset;
953 SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN);
954 ReadFile(pFile->
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
955 liFilePos.QuadPart = ullWritePos + ullOffset;
956 SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN);
957 WriteFile(pFile->
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
959 fseeko(pFile->
hFileRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
960 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, pFile->
hFileRead);
961 fseeko(pFile->
hFileWrite, ullWritePos + ullOffset, SEEK_SET);
962 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, pFile->
hFileWrite);
965 delete[] pCopyBuffer;
966 if (iBytesMoved < 0)
throw Exception(
"Writing Chunk data (from file) failed");
970 ullCurrentChunkSize = ullNewChunkSize;
971 WriteHeader(ullOriginalPos);
973 __notify_progress(pProgress, 1.0);
976 ullStartPos = ullOriginalPos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
980 if ((ullStartPos + ullNewChunkSize) % 2 != 0) {
981 const char cPadByte = 0;
983 lseek(pFile->
hFileWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
986 LARGE_INTEGER liFilePos;
987 liFilePos.QuadPart = ullStartPos + ullNewChunkSize;
988 SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN);
989 DWORD dwBytesWritten;
990 WriteFile(pFile->
hFileWrite, &cPadByte, 1, &dwBytesWritten, NULL);
992 fseeko(pFile->
hFileWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
995 return ullStartPos + ullNewChunkSize + 1;
998 return ullStartPos + ullNewChunkSize;
1010 List::List(
File* pFile) :
Chunk(pFile) {
1012 std::cout <<
"List::List(File* pFile)" << std::endl;
1013 #endif // DEBUG_RIFF 1015 pSubChunksMap = NULL;
1018 List::List(File* pFile,
file_offset_t StartPos, List* Parent)
1019 : Chunk(pFile, StartPos, Parent) {
1021 std::cout <<
"List::List(File*,file_offset_t,List*)" << std::endl;
1022 #endif // DEBUG_RIFF 1024 pSubChunksMap = NULL;
1025 ReadHeader(StartPos);
1026 ullStartPos = StartPos + LIST_HEADER_SIZE(pFile->FileOffsetSize);
1029 List::List(File* pFile, List* pParent, uint32_t uiListID)
1030 : Chunk(pFile, pParent, CHUNK_ID_LIST, 0) {
1032 pSubChunksMap = NULL;
1033 ListType = uiListID;
1038 std::cout <<
"List::~List()" << std::endl;
1039 #endif // DEBUG_RIFF 1043 void List::DeleteChunkList() {
1045 ChunkList::iterator iter = pSubChunks->begin();
1046 ChunkList::iterator end = pSubChunks->end();
1047 while (iter != end) {
1054 if (pSubChunksMap) {
1055 delete pSubChunksMap;
1056 pSubChunksMap = NULL;
1073 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1074 #endif // DEBUG_RIFF 1075 if (!pSubChunksMap) LoadSubChunks();
1076 return (*pSubChunksMap)[ChunkID];
1092 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1093 #endif // DEBUG_RIFF 1094 if (!pSubChunks) LoadSubChunks();
1095 ChunkList::iterator iter = pSubChunks->begin();
1096 ChunkList::iterator end = pSubChunks->end();
1097 while (iter != end) {
1098 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1118 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1119 #endif // DEBUG_RIFF 1120 if (!pSubChunks) LoadSubChunks();
1121 ChunksIterator = pSubChunks->begin();
1122 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1135 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1136 #endif // DEBUG_RIFF 1137 if (!pSubChunks)
return NULL;
1139 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1153 std::cout <<
"List::GetFirstSubList()" << std::endl;
1154 #endif // DEBUG_RIFF 1155 if (!pSubChunks) LoadSubChunks();
1156 ListIterator = pSubChunks->begin();
1157 ChunkList::iterator end = pSubChunks->end();
1158 while (ListIterator != end) {
1159 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1175 std::cout <<
"List::GetNextSubList()" << std::endl;
1176 #endif // DEBUG_RIFF 1177 if (!pSubChunks)
return NULL;
1178 if (ListIterator == pSubChunks->end())
return NULL;
1180 ChunkList::iterator end = pSubChunks->end();
1181 while (ListIterator != end) {
1182 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1192 if (!pSubChunks) LoadSubChunks();
1193 return pSubChunks->size();
1202 if (!pSubChunks) LoadSubChunks();
1203 ChunkList::iterator iter = pSubChunks->begin();
1204 ChunkList::iterator end = pSubChunks->end();
1205 while (iter != end) {
1206 if ((*iter)->GetChunkID() == ChunkID) {
1227 if (!pSubChunks) LoadSubChunks();
1228 ChunkList::iterator iter = pSubChunks->begin();
1229 ChunkList::iterator end = pSubChunks->end();
1230 while (iter != end) {
1231 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1254 if (ullBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1255 if (!pSubChunks) LoadSubChunks();
1256 Chunk* pNewChunk =
new Chunk(pFile,
this, uiChunkID, 0);
1257 pSubChunks->push_back(pNewChunk);
1258 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1259 pNewChunk->
Resize(ullBodySize);
1276 if (!pSubChunks) LoadSubChunks();
1277 pSubChunks->remove(pSrc);
1278 ChunkList::iterator iter = find(pSubChunks->begin(), pSubChunks->end(), pDst);
1279 pSubChunks->insert(iter, pSrc);
1291 if (pNewParent ==
this || !pNewParent)
return;
1292 if (!pSubChunks) LoadSubChunks();
1293 if (!pNewParent->pSubChunks) pNewParent->LoadSubChunks();
1294 pSubChunks->remove(pSrc);
1295 pNewParent->pSubChunks->push_back(pSrc);
1297 if ((*pSubChunksMap)[pSrc->
GetChunkID()] == pSrc) {
1300 ChunkList::iterator iter = pSubChunks->begin();
1301 ChunkList::iterator end = pSubChunks->end();
1302 for (; iter != end; ++iter) {
1303 if ((*iter)->GetChunkID() == pSrc->
GetChunkID()) {
1304 (*pSubChunksMap)[pSrc->
GetChunkID()] = *iter;
1310 if (!(*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()])
1311 (*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()] = pSrc;
1324 if (!pSubChunks) LoadSubChunks();
1325 List* pNewListChunk =
new List(pFile,
this, uiListType);
1326 pSubChunks->push_back(pNewListChunk);
1327 (*pSubChunksMap)[CHUNK_ID_LIST] = pNewListChunk;
1329 return pNewListChunk;
1343 if (!pSubChunks) LoadSubChunks();
1344 pSubChunks->remove(pSubChunk);
1345 if ((*pSubChunksMap)[pSubChunk->
GetChunkID()] == pSubChunk) {
1346 pSubChunksMap->erase(pSubChunk->
GetChunkID());
1348 ChunkList::iterator iter = pSubChunks->begin();
1349 ChunkList::iterator end = pSubChunks->end();
1350 for (; iter != end; ++iter) {
1351 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1352 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1368 if (!pSubChunks) LoadSubChunks();
1370 ChunkList::iterator iter = pSubChunks->begin();
1371 ChunkList::iterator end = pSubChunks->end();
1372 for (; iter != end; ++iter)
1373 size += (*iter)->RequiredPhysicalSize(fileOffsetSize);
1379 std::cout <<
"List::Readheader(file_offset_t) ";
1380 #endif // DEBUG_RIFF 1381 Chunk::ReadHeader(filePos);
1382 if (ullCurrentChunkSize < 4)
return;
1383 ullNewChunkSize = ullCurrentChunkSize -= 4;
1387 #elif defined(WIN32) 1388 LARGE_INTEGER liFilePos;
1389 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1390 SetFilePointerEx(pFile->
hFileRead, liFilePos, NULL, FILE_BEGIN);
1392 ReadFile(pFile->
hFileRead, &ListType, 4, &dwBytesRead, NULL);
1395 fread(&ListType, 4, 1, pFile->
hFileRead);
1398 std::cout <<
"listType=" << convertToString(ListType) << std::endl;
1399 #endif // DEBUG_RIFF 1400 if (!pFile->bEndianNative) {
1407 ullNewChunkSize += 4;
1408 Chunk::WriteHeader(filePos);
1409 ullNewChunkSize -= 4;
1413 #elif defined(WIN32) 1414 LARGE_INTEGER liFilePos;
1415 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1416 SetFilePointerEx(pFile->
hFileWrite, liFilePos, NULL, FILE_BEGIN);
1417 DWORD dwBytesWritten;
1418 WriteFile(pFile->
hFileWrite, &ListType, 4, &dwBytesWritten, NULL);
1425 void List::LoadSubChunks(progress_t* pProgress) {
1427 std::cout <<
"List::LoadSubChunks()";
1428 #endif // DEBUG_RIFF 1430 pSubChunks =
new ChunkList();
1431 pSubChunksMap =
new ChunkMap();
1433 if (pFile->
hFileRead == INVALID_HANDLE_VALUE)
return;
1444 std::cout <<
" ckid=" << convertToString(ckid) << std::endl;
1445 #endif // DEBUG_RIFF 1446 if (ckid == CHUNK_ID_LIST) {
1447 ck =
new RIFF::List(pFile, ullStartPos + ullPos - 4,
this);
1451 ck =
new RIFF::Chunk(pFile, ullStartPos + ullPos - 4,
this);
1454 pSubChunks->push_back(ck);
1455 (*pSubChunksMap)[ckid] = ck;
1460 __notify_progress(pProgress, 1.0);
1463 void List::LoadSubChunksRecursively(progress_t* pProgress) {
1468 progress_t subprogress;
1469 __divide_progress(pProgress, &subprogress, n, i);
1471 pList->LoadSubChunksRecursively(&subprogress);
1473 __notify_progress(pProgress, 1.0);
1495 if (pFile->Mode != stream_mode_read_write)
1496 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1501 const size_t n = pSubChunks->size();
1502 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter, ++i) {
1505 __divide_progress(pProgress, &subprogress, n, i);
1507 ullWritePos = (*iter)->WriteChunk(ullWritePos, ullCurrentDataOffset, &subprogress);
1512 ullCurrentChunkSize = ullNewChunkSize = ullWritePos - ullOriginalPos - LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1513 WriteHeader(ullOriginalPos);
1516 ullStartPos = ullOriginalPos + LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1518 __notify_progress(pProgress, 1.0);
1526 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
1527 (*iter)->__resetPos();
1536 return convertToString(ListType);
1567 Mode = stream_mode_closed;
1568 bEndianNative =
true;
1569 ListType = FileType;
1587 std::cout <<
"File::File("<<path<<
")" << std::endl;
1588 #endif // DEBUG_RIFF 1589 bEndianNative =
true;
1592 __openExistingFile(path);
1593 if (ChunkID != CHUNK_ID_RIFF && ChunkID != CHUNK_ID_RIFX) {
1630 :
List(this), Filename(path), bIsNewFile(false), Layout(layout),
1631 FileOffsetPreference(fileOffsetSize)
1635 throw Exception(
"Invalid RIFF::offset_size_t");
1638 __openExistingFile(path, &FileType);
1656 void File::__openExistingFile(
const String& path, uint32_t* FileType) {
1661 String sError = strerror(errno);
1664 #elif defined(WIN32) 1666 path.c_str(), GENERIC_READ,
1667 FILE_SHARE_READ | FILE_SHARE_WRITE,
1668 NULL, OPEN_EXISTING,
1669 FILE_ATTRIBUTE_NORMAL |
1670 FILE_FLAG_RANDOM_ACCESS, NULL
1672 if (
hFileRead == INVALID_HANDLE_VALUE) {
1680 Mode = stream_mode_read;
1690 if (FileType && ChunkID != *FileType)
1698 if (
Read(&ckid, 4, 1) != 4) {
1699 throw RIFF::Exception(
"Invalid file header ID (premature end of header)");
1700 }
else if (ckid != *FileType) {
1701 String s =
" (expected '" + convertToString(*FileType) +
"' but got '" + convertToString(ckid) +
"')";
1711 String File::GetFileName()
const {
1715 void File::SetFileName(
const String& path) {
1738 if (NewMode != Mode) {
1740 case stream_mode_read:
1746 String sError = strerror(errno);
1747 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode: " + sError);
1749 #elif defined(WIN32) 1752 Filename.c_str(), GENERIC_READ,
1753 FILE_SHARE_READ | FILE_SHARE_WRITE,
1754 NULL, OPEN_EXISTING,
1755 FILE_ATTRIBUTE_NORMAL |
1756 FILE_FLAG_RANDOM_ACCESS,
1759 if (
hFileRead == INVALID_HANDLE_VALUE) {
1761 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
1766 if (!
hFileRead)
throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
1770 case stream_mode_read_write:
1776 String sError = strerror(errno);
1777 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode: " + sError);
1779 #elif defined(WIN32) 1783 GENERIC_READ | GENERIC_WRITE,
1786 FILE_ATTRIBUTE_NORMAL |
1787 FILE_FLAG_RANDOM_ACCESS,
1790 if (
hFileRead == INVALID_HANDLE_VALUE) {
1792 Filename.c_str(), GENERIC_READ,
1793 FILE_SHARE_READ | FILE_SHARE_WRITE,
1794 NULL, OPEN_EXISTING,
1795 FILE_ATTRIBUTE_NORMAL |
1796 FILE_FLAG_RANDOM_ACCESS,
1799 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read+write mode");
1806 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode");
1811 case stream_mode_closed:
1815 #elif defined(WIN32) 1825 throw Exception(
"Unknown file access mode");
1844 bEndianNative = Endian != endian_little;
1846 bEndianNative = Endian != endian_big;
1862 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
1868 __divide_progress(pProgress, &subprogress, 3.f, 0.f);
1870 LoadSubChunksRecursively(&subprogress);
1872 __notify_progress(&subprogress, 1.f);
1876 SetMode(stream_mode_read_write);
1898 if (newFileSize > workingFileSize) {
1899 positiveSizeDiff = newFileSize - workingFileSize;
1903 __divide_progress(pProgress, &subprogress, 3.f, 1.f);
1906 ResizeFile(newFileSize);
1909 int8_t* pCopyBuffer =
new int8_t[4096];
1911 DWORD iBytesMoved = 1;
1913 ssize_t iBytesMoved = 1;
1915 for (
file_offset_t ullPos = workingFileSize, iNotif = 0; iBytesMoved > 0; ++iNotif) {
1916 iBytesMoved = (ullPos < 4096) ? ullPos : 4096;
1917 ullPos -= iBytesMoved;
1920 iBytesMoved = read(
hFileRead, pCopyBuffer, iBytesMoved);
1921 lseek(
hFileWrite, ullPos + positiveSizeDiff, SEEK_SET);
1922 iBytesMoved = write(
hFileWrite, pCopyBuffer, iBytesMoved);
1923 #elif defined(WIN32) 1924 LARGE_INTEGER liFilePos;
1925 liFilePos.QuadPart = ullPos;
1926 SetFilePointerEx(
hFileRead, liFilePos, NULL, FILE_BEGIN);
1927 ReadFile(
hFileRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1928 liFilePos.QuadPart = ullPos + positiveSizeDiff;
1929 SetFilePointerEx(
hFileWrite, liFilePos, NULL, FILE_BEGIN);
1930 WriteFile(
hFileWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1933 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved,
hFileRead);
1934 fseeko(
hFileWrite, ullPos + positiveSizeDiff, SEEK_SET);
1935 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved,
hFileWrite);
1937 if (!(iNotif % 8) && iBytesMoved > 0)
1938 __notify_progress(&subprogress,
float(workingFileSize - ullPos) /
float(workingFileSize));
1940 delete[] pCopyBuffer;
1941 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
1943 __notify_progress(&subprogress, 1.f);
1950 __divide_progress(pProgress, &subprogress, 3.f, 2.f);
1955 __notify_progress(&subprogress, 1.f);
1958 if (finalSize < finalActualSize) ResizeFile(finalSize);
1960 __notify_progress(pProgress, 1.0);
1982 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
1988 __divide_progress(pProgress, &subprogress, 2.f, 0.f);
1990 LoadSubChunksRecursively(&subprogress);
1992 __notify_progress(&subprogress, 1.f);
1995 if (!bIsNewFile)
SetMode(stream_mode_read);
1998 hFileWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
2001 String sError = strerror(errno);
2002 throw Exception(
"Could not open file \"" + path +
"\" for writing: " + sError);
2004 #elif defined(WIN32) 2006 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
2007 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
2008 FILE_FLAG_RANDOM_ACCESS, NULL
2012 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2018 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2021 Mode = stream_mode_read_write;
2035 __divide_progress(pProgress, &subprogress, 2.f, 1.f);
2037 ullTotalSize =
WriteChunk(0, 0, &subprogress);
2039 __notify_progress(&subprogress, 1.f);
2044 if (ullActualSize > ullTotalSize) ResizeFile(ullTotalSize);
2048 #elif defined(WIN32) 2059 SetMode(stream_mode_read_write);
2061 __notify_progress(pProgress, 1.0);
2067 throw Exception(
"Could not resize file \"" + Filename +
"\"");
2068 #elif defined(WIN32) 2069 LARGE_INTEGER liFilePos;
2070 liFilePos.QuadPart = ullNewSize;
2072 !SetFilePointerEx(
hFileWrite, liFilePos, NULL, FILE_BEGIN) ||
2074 )
throw Exception(
"Could not resize file \"" + Filename +
"\"");
2076 # error Sorry, this version of libgig only supports POSIX and Windows systems yet. 2077 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)! 2083 std::cout <<
"File::~File()" << std::endl;
2084 #endif // DEBUG_RIFF 2096 void File::Cleanup() {
2099 #elif defined(WIN32) 2159 switch (fileOffsetSize) {
2169 default:
throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2175 switch (FileOffsetPreference) {
2177 return (fileSize >> 32) ? 8 : 4;
2183 throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2227 struct stat filestat;
2228 if (fstat(hFile, &filestat) == -1)
2229 throw Exception(
"POSIX FS error: could not determine file size");
2230 return filestat.st_size;
2232 #elif defined(WIN32) 2235 if (!GetFileSizeEx(hFile, &size))
2236 throw Exception(
"Windows FS error: could not determine file size");
2237 return size.QuadPart;
2239 #else // standard C functions 2241 off_t curpos = ftello(hFile);
2242 if (fseeko(hFile, 0, SEEK_END) == -1)
2243 throw Exception(
"FS error: could not determine file size");
2244 off_t size = ftello(hFile);
2245 fseeko(hFile, curpos, SEEK_SET);
2254 Exception::Exception() {
2257 Exception::Exception(String format, ...) {
2259 va_start(arg, format);
2260 Message = assemble(format, arg);
2264 Exception::Exception(String format, va_list arg) {
2265 Message = assemble(format, arg);
2268 void Exception::PrintMessage() {
2269 std::cout <<
"RIFF::Exception: " << Message << std::endl;
2272 String Exception::assemble(String format, va_list arg) {
2274 vasprintf(&buf, format.c_str(), arg);
file_offset_t WriteUint32(uint32_t *pData, file_offset_t WordCount=1)
Writes WordCount number of 32 Bit unsigned integer words from the buffer pointed by pData to the chun...
bool IsNew() const
Returns true if this file has been created new from scratch and has not been stored to disk yet...
int16_t ReadInt16()
Reads one 16 Bit signed integer word and increments the position within the chunk.
virtual file_offset_t RequiredPhysicalSize(int fileOffsetSize)
Returns the actual total size in bytes (including List chunk header and all subchunks) of this List C...
int FileOffsetSize
Size of file offsets (in bytes) when this file was opened (or saved the last time).
file_offset_t WriteUint16(uint16_t *pData, file_offset_t WordCount=1)
Writes WordCount number of 16 Bit unsigned integer words from the buffer pointed by pData to the chun...
size_t CountSubLists()
Returns number of sublists within the list.
stream_whence_t
File stream position dependent to these relations.
Chunk * GetFirstSubChunk()
Returns the first subchunk within the list (which may be an ordinary chunk as well as a list chunk)...
String libraryName()
Returns the name of this C++ library.
File(uint32_t FileType)
Create new RIFF file.
file_offset_t WriteInt32(int32_t *pData, file_offset_t WordCount=1)
Writes WordCount number of 32 Bit signed integer words from the buffer pointed by pData to the chunk'...
file_offset_t GetSize() const
Chunk size in bytes (without header, thus the chunk data body)
layout_t Layout
An ordinary RIFF file is always set to layout_standard.
void(* callback)(progress_t *)
Callback function pointer which has to be assigned to a function for progress notification.
stream_state_t
Current state of the file stream.
void ReadString(String &s, int size)
Reads a null-padded string of size characters and copies it into the string s.
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.
Use 32 bit offsets for files smaller than 4 GB, use 64 bit offsets for files equal or larger than 4 G...
int hFileWrite
handle / descriptor for writing to (some) file
List * GetFirstSubList()
Returns the first sublist within the list (that is a subchunk with chunk ID "LIST").
virtual file_offset_t WriteChunk(file_offset_t ullWritePos, file_offset_t ullCurrentDataOffset, progress_t *pProgress=NULL)
Write chunk persistently e.g.
stream_mode_t
Whether file stream is open in read or in read/write mode.
String GetListTypeString() const
Returns string representation of the lists's id.
void SetByteOrder(endian_t Endian)
Set the byte order to be used when saving.
file_offset_t WriteInt16(int16_t *pData, file_offset_t WordCount=1)
Writes WordCount number of 16 Bit signed integer words from the buffer pointed by pData to the chunk'...
file_offset_t ReadSceptical(void *pData, file_offset_t WordCount, file_offset_t WordSize)
Just an internal wrapper for the main Read() method with additional Exception throwing on errors...
file_offset_t Read(void *pData, file_offset_t WordCount, file_offset_t WordSize)
Reads WordCount number of data words with given WordSize and copies it into a buffer pointed by pData...
file_offset_t WriteInt8(int8_t *pData, file_offset_t WordCount=1)
Writes WordCount number of 8 Bit signed integer words from the buffer pointed by pData to the chunk's...
file_offset_t SetPos(file_offset_t Where, stream_whence_t Whence=stream_start)
Sets the position within the chunk body, thus within the data portion of the chunk (in bytes)...
int8_t ReadInt8()
Reads one 8 Bit signed integer word and increments the position within the chunk. ...
virtual file_offset_t WriteChunk(file_offset_t ullWritePos, file_offset_t ullCurrentDataOffset, progress_t *pProgress=NULL)
Write list chunk persistently e.g.
offset_size_t
Size of RIFF file offsets used in all RIFF chunks' headers.
uint64_t file_offset_t
Type used by libgig for handling file positioning during file I/O tasks.
float __range_min
Only for internal usage, do not modify!
Chunk * GetSubChunk(uint32_t ChunkID)
Returns subchunk with chunk ID ChunkID within this chunk list.
Chunk * GetNextSubChunk()
Returns the next subchunk within the list (which may be an ordinary chunk as well as a list chunk)...
int32_t ReadInt32()
Reads one 32 Bit signed integer word and increments the position within the chunk.
virtual void Save(progress_t *pProgress=NULL)
Save changes to same file.
layout_t
General RIFF chunk structure of a RIFF file.
virtual file_offset_t RequiredPhysicalSize(int fileOffsetSize)
Returns the actual total size in bytes (including header) of this Chunk if being stored to a file...
file_offset_t GetRequiredFileSize()
Returns the required size (in bytes) for this RIFF File to be saved to disk.
uint32_t ReadUint32()
Reads one 32 Bit unsigned integer word and increments the position within the chunk.
int GetFileOffsetSize() const
Returns the current size (in bytes) of file offsets stored in the headers of all chunks of this file...
uint32_t GetChunkID() const
Chunk ID in unsigned integer representation.
void * custom
This pointer can be used for arbitrary data.
file_offset_t RemainingBytes() const
Returns the number of bytes left to read in the chunk body.
Used for indicating the progress of a certain task.
file_offset_t Write(void *pData, file_offset_t WordCount, file_offset_t WordSize)
Writes WordCount number of data words with given WordSize from the buffer pointed by pData...
int hFileRead
handle / descriptor for reading from file
uint32_t GetListType() const
Returns unsigned integer representation of the list's ID.
Not a "real" RIFF file: First chunk in file is an ordinary data chunk, not a List chunk...
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...
endian_t
Alignment of data bytes in memory (system dependant).
void * LoadChunkData()
Load chunk body into RAM.
file_offset_t WriteUint8(uint8_t *pData, file_offset_t WordCount=1)
Writes WordCount number of 8 Bit unsigned integer words from the buffer pointed by pData to the chunk...
Standard RIFF file layout: First chunk in file is a List chunk which contains all other chunks and th...
void Resize(file_offset_t NewSize)
Resize chunk.
List * AddSubList(uint32_t uiListType)
Creates a new list sub chunk.
RIFF specific classes and definitions.
void MoveSubChunk(Chunk *pSrc, Chunk *pDst)
Moves a sub chunk witin this list.
Always use 32 bit offsets (even for files larger than 4 GB).
size_t CountSubChunks()
Returns number of subchunks within the list (including list chunks).
stream_state_t GetState() const
Returns the current state of the chunk object.
bool SetMode(stream_mode_t NewMode)
Change file access mode.
float __range_max
Only for internal usage, do not modify!
String GetChunkIDString() const
Returns the String representation of the chunk's ID (e.g.
int GetRequiredFileOffsetSize()
Returns the required size (in bytes) of file offsets stored in the headers of all chunks of this file...
Will be thrown whenever an error occurs while handling a RIFF file.
Always use 64 bit offsets (even for files smaller than 4 GB).
void ReleaseChunkData()
Free loaded chunk body from RAM.
file_offset_t GetCurrentFileSize() const
Returns the current size of this file (in bytes) as it is currently yet stored on disk...
file_offset_t GetPos() const
Position within the chunk data body (starting with 0).
List * GetNextSubList()
Returns the next sublist (that is a subchunk with chunk ID "LIST") within the list.
Chunk * AddSubChunk(uint32_t uiChunkID, file_offset_t ullBodySize)
Creates a new sub chunk.
uint8_t ReadUint8()
Reads one 8 Bit unsigned integer word and increments the position within the chunk.