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;
57 return handle != INVALID_HANDLE_VALUE;
64 if (!_isValidHandle(handle))
return;
79 progress_t::progress_t() {
94 std::vector<progress_t> v;
95 for (
int i = 0; i < iSubtasks; ++i) {
97 __divide_progress(
this, &p, iSubtasks, i);
127 for (
int i = 0; i < vSubTaskPortions.size(); ++i)
128 fTotal += vSubTaskPortions[i];
130 float fLow = 0.f, fHigh = 0.f;
131 std::vector<progress_t> v;
132 for (
int i = 0; i < vSubTaskPortions.size(); ++i) {
134 fHigh = vSubTaskPortions[i];
136 __divide_progress(
this, &p, fTotal, fLow, fHigh);
147 Chunk::Chunk(
File* pFile) {
149 std::cout <<
"Chunk::Chunk(File* pFile)" << std::endl;
154 ullCurrentChunkSize = 0;
156 ullChunkDataSize = 0;
157 ChunkID = CHUNK_ID_RIFF;
163 std::cout <<
"Chunk::Chunk(File*,file_offset_t,List*),StartPos=" << StartPos << std::endl;
166 ullStartPos = StartPos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
170 ullCurrentChunkSize = 0;
172 ullChunkDataSize = 0;
173 ReadHeader(StartPos);
179 this->pParent = pParent;
183 ullChunkDataSize = 0;
184 ullCurrentChunkSize = 0;
185 ullNewChunkSize = ullBodySize;
189 if (pChunkData)
delete[] pChunkData;
194 std::cout <<
"Chunk::Readheader(" << filePos <<
") ";
197 ullNewChunkSize = ullCurrentChunkSize = 0;
202 if (lseek(hRead, filePos, SEEK_SET) != -1) {
203 read(hRead, &ChunkID, 4);
206 LARGE_INTEGER liFilePos;
207 liFilePos.QuadPart = filePos;
208 if (SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN)) {
210 ReadFile(hRead, &ChunkID, 4, &dwBytesRead, NULL);
211 ReadFile(hRead, &ullCurrentChunkSize, pFile->
FileOffsetSize, &dwBytesRead, NULL);
213 if (!fseeko(hRead, filePos, SEEK_SET)) {
214 fread(&ChunkID, 4, 1, hRead);
218 if (ChunkID == CHUNK_ID_RIFF) {
219 pFile->bEndianNative =
false;
221 #else // little endian 222 if (ChunkID == CHUNK_ID_RIFX) {
223 pFile->bEndianNative =
false;
224 ChunkID = CHUNK_ID_RIFF;
226 #endif // WORDS_BIGENDIAN 227 if (!pFile->bEndianNative) {
230 swapBytes_32(&ullCurrentChunkSize);
232 swapBytes_64(&ullCurrentChunkSize);
235 std::cout <<
"ckID=" << convertToString(ChunkID) <<
" ";
236 std::cout <<
"ckSize=" << ullCurrentChunkSize <<
" ";
237 std::cout <<
"bEndianNative=" << pFile->bEndianNative << std::endl;
239 ullNewChunkSize = ullCurrentChunkSize;
244 uint32_t uiNewChunkID = ChunkID;
245 if (ChunkID == CHUNK_ID_RIFF) {
247 if (pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
248 #else // little endian 249 if (!pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
250 #endif // WORDS_BIGENDIAN 253 uint64_t ullNewChunkSize = this->ullNewChunkSize;
254 if (!pFile->bEndianNative) {
256 swapBytes_32(&ullNewChunkSize);
258 swapBytes_64(&ullNewChunkSize);
264 if (lseek(hWrite, filePos, SEEK_SET) != -1) {
265 write(hWrite, &uiNewChunkID, 4);
269 LARGE_INTEGER liFilePos;
270 liFilePos.QuadPart = filePos;
271 if (SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN)) {
272 DWORD dwBytesWritten;
273 WriteFile(hWrite, &uiNewChunkID, 4, &dwBytesWritten, NULL);
274 WriteFile(hWrite, &ullNewChunkSize, pFile->
FileOffsetSize, &dwBytesWritten, NULL);
277 if (!fseeko(hWrite, filePos, SEEK_SET)) {
278 fwrite(&uiNewChunkID, 4, 1, hWrite);
289 return convertToString(ChunkID);
302 const std::thread::id tid = std::this_thread::get_id();
303 return chunkPos.byThread[tid];
313 const std::thread::id tid = std::this_thread::get_id();
314 std::lock_guard<std::mutex> lock(chunkPos.mutex);
315 return chunkPos.byThread[tid];
325 return ullStartPos + GetPos();
343 std::cout <<
"Chunk::SetPos(file_offset_t,stream_whence_t)" << std::endl;
345 std::lock_guard<std::mutex> lock(chunkPos.mutex);
352 pos = ullCurrentChunkSize - 1 - Where;
354 case stream_backward:
357 case stream_start:
default:
361 if (pos > ullCurrentChunkSize) pos = ullCurrentChunkSize;
378 std::cout <<
"Chunk::Remainingbytes()=" << ullCurrentChunkSize - ullPos << std::endl;
381 return (ullCurrentChunkSize > pos) ? ullCurrentChunkSize - pos : 0;
392 return CHUNK_HEADER_SIZE(fileOffsetSize) +
412 std::cout <<
"Chunk::GetState()" << std::endl;
417 if (!_isValidHandle(hRead))
418 return stream_closed;
421 if (pos < ullCurrentChunkSize)
return stream_ready;
422 else return stream_end_reached;
443 std::cout <<
"Chunk::Read(void*,file_offset_t,file_offset_t)" << std::endl;
447 if (pos >= ullCurrentChunkSize)
return 0;
448 if (pos + WordCount * WordSize >= ullCurrentChunkSize)
449 WordCount = (ullCurrentChunkSize - pos) / WordSize;
454 if (lseek(hRead, ullStartPos + pos, SEEK_SET) < 0)
return 0;
455 ssize_t readWords = read(hRead, pData, WordCount * WordSize);
458 std::cerr <<
"POSIX read() failed: " << strerror(errno) << std::endl << std::flush;
462 readWords /= WordSize;
464 LARGE_INTEGER liFilePos;
465 liFilePos.QuadPart = ullStartPos + pos;
466 if (!SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN))
469 ReadFile(hRead, pData, WordCount * WordSize, &readWords, NULL);
470 if (readWords < 1)
return 0;
471 readWords /= WordSize;
472 #else // standard C functions 473 if (fseeko(hRead, ullStartPos + pos, SEEK_SET))
return 0;
474 file_offset_t readWords = fread(pData, WordSize, WordCount, hRead);
476 if (!pFile->bEndianNative && WordSize != 1) {
480 swapBytes_16((uint16_t*) pData + iWord);
484 swapBytes_32((uint32_t*) pData + iWord);
488 swapBytes_64((uint64_t*) pData + iWord);
492 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
496 SetPos(readWords * WordSize, stream_curpos);
519 if (io.Mode != stream_mode_read_write)
520 throw Exception(
"Cannot write data to chunk, file has to be opened in read+write mode first");
522 if (pos >= ullCurrentChunkSize || pos + WordCount * WordSize > ullCurrentChunkSize)
523 throw Exception(
"End of chunk reached while trying to write data");
524 if (!pFile->bEndianNative && WordSize != 1) {
528 swapBytes_16((uint16_t*) pData + iWord);
532 swapBytes_32((uint32_t*) pData + iWord);
536 swapBytes_64((uint64_t*) pData + iWord);
540 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
545 if (lseek(io.hWrite, ullStartPos + pos, SEEK_SET) < 0) {
546 throw Exception(
"Could not seek to position " + ToString(pos) +
547 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
549 ssize_t writtenWords = write(io.hWrite, pData, WordCount * WordSize);
550 if (writtenWords < 1)
throw Exception(
"POSIX IO Error while trying to write chunk data");
551 writtenWords /= WordSize;
553 LARGE_INTEGER liFilePos;
554 liFilePos.QuadPart = ullStartPos + pos;
555 if (!SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN)) {
556 throw Exception(
"Could not seek to position " + ToString(pos) +
557 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
560 WriteFile(io.hWrite, pData, WordCount * WordSize, &writtenWords, NULL);
561 if (writtenWords < 1)
throw Exception(
"Windows IO Error while trying to write chunk data");
562 writtenWords /= WordSize;
563 #else // standard C functions 564 if (fseeko(io.hWrite, ullStartPos + pos, SEEK_SET)) {
565 throw Exception(
"Could not seek to position " + ToString(pos) +
566 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
568 file_offset_t writtenWords = fwrite(pData, WordSize, WordCount, io.hWrite);
570 SetPos(writtenWords * WordSize, stream_curpos);
577 if (readWords != WordCount)
throw RIFF::Exception(
"End of chunk data reached.");
595 std::cout <<
"Chunk::ReadInt8(int8_t*,file_offset_t)" << std::endl;
597 return ReadSceptical(pData, WordCount, 1);
616 return Write(pData, WordCount, 1);
634 std::cout <<
"Chunk::ReadUint8(uint8_t*,file_offset_t)" << std::endl;
636 return ReadSceptical(pData, WordCount, 1);
655 return Write(pData, WordCount, 1);
673 std::cout <<
"Chunk::ReadInt16(int16_t*,file_offset_t)" << std::endl;
675 return ReadSceptical(pData, WordCount, 2);
694 return Write(pData, WordCount, 2);
712 std::cout <<
"Chunk::ReadUint16(uint16_t*,file_offset_t)" << std::endl;
714 return ReadSceptical(pData, WordCount, 2);
733 return Write(pData, WordCount, 2);
751 std::cout <<
"Chunk::ReadInt32(int32_t*,file_offset_t)" << std::endl;
753 return ReadSceptical(pData, WordCount, 4);
772 return Write(pData, WordCount, 4);
790 std::cout <<
"Chunk::ReadUint32(uint32_t*,file_offset_t)" << std::endl;
792 return ReadSceptical(pData, WordCount, 4);
807 char* buf =
new char[size];
808 ReadSceptical(buf, 1, size);
809 s.assign(buf, std::find(buf, buf + size,
'\0'));
829 return Write(pData, WordCount, 4);
842 std::cout <<
"Chunk::ReadInt8()" << std::endl;
845 ReadSceptical(&word,1,1);
859 std::cout <<
"Chunk::ReadUint8()" << std::endl;
862 ReadSceptical(&word,1,1);
877 std::cout <<
"Chunk::ReadInt16()" << std::endl;
880 ReadSceptical(&word,1,2);
895 std::cout <<
"Chunk::ReadUint16()" << std::endl;
898 ReadSceptical(&word,1,2);
913 std::cout <<
"Chunk::ReadInt32()" << std::endl;
916 ReadSceptical(&word,1,4);
931 std::cout <<
"Chunk::ReadUint32()" << std::endl;
934 ReadSceptical(&word,1,4);
961 if (!pChunkData && pFile->Filename !=
"" ) {
964 if (lseek(hRead, ullStartPos, SEEK_SET) == -1)
return NULL;
966 LARGE_INTEGER liFilePos;
967 liFilePos.QuadPart = ullStartPos;
968 if (!SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN))
return NULL;
970 if (fseeko(hRead, ullStartPos, SEEK_SET))
return NULL;
972 file_offset_t ullBufferSize = (ullCurrentChunkSize > ullNewChunkSize) ? ullCurrentChunkSize : ullNewChunkSize;
973 pChunkData =
new uint8_t[ullBufferSize];
974 if (!pChunkData)
return NULL;
975 memset(pChunkData, 0, ullBufferSize);
977 file_offset_t readWords = read(hRead, pChunkData, GetSize());
980 ReadFile(hRead, pChunkData, GetSize(), &readWords, NULL);
982 file_offset_t readWords = fread(pChunkData, 1, GetSize(), hRead);
984 if (readWords != GetSize()) {
986 return (pChunkData = NULL);
988 ullChunkDataSize = ullBufferSize;
989 }
else if (ullNewChunkSize > ullChunkDataSize) {
990 uint8_t* pNewBuffer =
new uint8_t[ullNewChunkSize];
991 if (!pNewBuffer)
throw Exception(
"Could not enlarge chunk data buffer to " + ToString(ullNewChunkSize) +
" bytes");
992 memset(pNewBuffer, 0 , ullNewChunkSize);
994 memcpy(pNewBuffer, pChunkData, ullChunkDataSize);
997 pChunkData = pNewBuffer;
998 ullChunkDataSize = ullNewChunkSize;
1011 delete[] pChunkData;
1036 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(
this));
1037 if ((NewSize >> 48) != 0)
1038 throw Exception(
"Unrealistic high chunk size detected: " + __resolveChunkPath(
this));
1039 if (ullNewChunkSize == NewSize)
return;
1040 ullNewChunkSize = NewSize;
1063 if (io.Mode != stream_mode_read_write)
1064 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1072 lseek(io.hWrite, ullWritePos, SEEK_SET);
1073 if (write(io.hWrite, pChunkData, ullNewChunkSize) != ullNewChunkSize) {
1074 throw Exception(
"Writing Chunk data (from RAM) failed");
1076 #elif defined(WIN32) 1077 LARGE_INTEGER liFilePos;
1078 liFilePos.QuadPart = ullWritePos;
1079 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1080 DWORD dwBytesWritten;
1081 WriteFile(io.hWrite, pChunkData, ullNewChunkSize, &dwBytesWritten, NULL);
1082 if (dwBytesWritten != ullNewChunkSize) {
1083 throw Exception(
"Writing Chunk data (from RAM) failed");
1086 fseeko(io.hWrite, ullWritePos, SEEK_SET);
1087 if (fwrite(pChunkData, 1, ullNewChunkSize, io.hWrite) != ullNewChunkSize) {
1088 throw Exception(
"Writing Chunk data (from RAM) failed");
1093 int8_t* pCopyBuffer =
new int8_t[4096];
1094 file_offset_t ullToMove = (ullNewChunkSize < ullCurrentChunkSize) ? ullNewChunkSize : ullCurrentChunkSize;
1096 DWORD iBytesMoved = 1;
1098 int iBytesMoved = 1;
1100 for (
file_offset_t ullOffset = 0; ullToMove > 0 && iBytesMoved > 0; ullOffset += iBytesMoved, ullToMove -= iBytesMoved) {
1101 iBytesMoved = (ullToMove < 4096) ?
int(ullToMove) : 4096;
1103 lseek(io.hRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
1104 iBytesMoved = (int) read(io.hRead, pCopyBuffer, (
size_t) iBytesMoved);
1105 lseek(io.hWrite, ullWritePos + ullOffset, SEEK_SET);
1106 iBytesMoved = (int) write(io.hWrite, pCopyBuffer, (
size_t) iBytesMoved);
1107 #elif defined(WIN32) 1108 LARGE_INTEGER liFilePos;
1109 liFilePos.QuadPart = ullStartPos + ullCurrentDataOffset + ullOffset;
1110 SetFilePointerEx(io.hRead, liFilePos, NULL, FILE_BEGIN);
1111 ReadFile(io.hRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1112 liFilePos.QuadPart = ullWritePos + ullOffset;
1113 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1114 WriteFile(io.hWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1116 fseeko(io.hRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
1117 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, io.hRead);
1118 fseeko(io.hWrite, ullWritePos + ullOffset, SEEK_SET);
1119 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, io.hWrite);
1122 delete[] pCopyBuffer;
1123 if (iBytesMoved < 0)
throw Exception(
"Writing Chunk data (from file) failed");
1127 ullCurrentChunkSize = ullNewChunkSize;
1128 WriteHeader(ullOriginalPos);
1131 __notify_progress(pProgress, 1.0);
1134 ullStartPos = ullOriginalPos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1138 if ((ullStartPos + ullNewChunkSize) % 2 != 0) {
1139 const char cPadByte = 0;
1141 lseek(io.hWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
1142 write(io.hWrite, &cPadByte, 1);
1143 #elif defined(WIN32) 1144 LARGE_INTEGER liFilePos;
1145 liFilePos.QuadPart = ullStartPos + ullNewChunkSize;
1146 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1147 DWORD dwBytesWritten;
1148 WriteFile(io.hWrite, &cPadByte, 1, &dwBytesWritten, NULL);
1150 fseeko(io.hWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
1151 fwrite(&cPadByte, 1, 1, io.hWrite);
1153 return ullStartPos + ullNewChunkSize + 1;
1156 return ullStartPos + ullNewChunkSize;
1160 std::lock_guard<std::mutex> lock(chunkPos.mutex);
1161 chunkPos.ullPos = 0;
1162 chunkPos.byThread.clear();
1170 List::List(
File* pFile) :
Chunk(pFile) {
1172 std::cout <<
"List::List(File* pFile)" << std::endl;
1173 #endif // DEBUG_RIFF 1175 pSubChunksMap = NULL;
1179 :
Chunk(pFile, StartPos, Parent) {
1181 std::cout <<
"List::List(File*,file_offset_t,List*)" << std::endl;
1182 #endif // DEBUG_RIFF 1184 pSubChunksMap = NULL;
1185 ReadHeader(StartPos);
1186 ullStartPos = StartPos + LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1189 List::List(
File* pFile,
List* pParent, uint32_t uiListID)
1190 :
Chunk(pFile, pParent, CHUNK_ID_LIST, 0) {
1192 pSubChunksMap = NULL;
1193 ListType = uiListID;
1198 std::cout <<
"List::~List()" << std::endl;
1199 #endif // DEBUG_RIFF 1203 void List::DeleteChunkList() {
1205 ChunkList::iterator iter = pSubChunks->begin();
1206 ChunkList::iterator end = pSubChunks->end();
1207 while (iter != end) {
1214 if (pSubChunksMap) {
1215 delete pSubChunksMap;
1216 pSubChunksMap = NULL;
1230 if (!pSubChunks) LoadSubChunks();
1231 if (pos >= pSubChunks->size())
return NULL;
1232 return (*pSubChunks)[pos];
1248 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1249 #endif // DEBUG_RIFF 1250 if (!pSubChunksMap) LoadSubChunks();
1251 return (*pSubChunksMap)[ChunkID];
1265 if (!pSubChunks) LoadSubChunks();
1266 if (pos >= pSubChunks->size())
return NULL;
1267 for (
size_t iCk = 0, iLst = 0; iCk < pSubChunks->size(); ++iCk) {
1268 Chunk* pChunk = (*pSubChunks)[iCk];
1269 if (pChunk->
GetChunkID() != CHUNK_ID_LIST)
continue;
1270 if (iLst == pos)
return (
List*) pChunk;
1289 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1290 #endif // DEBUG_RIFF 1291 if (!pSubChunks) LoadSubChunks();
1292 ChunkList::iterator iter = pSubChunks->begin();
1293 ChunkList::iterator end = pSubChunks->end();
1294 while (iter != end) {
1295 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1317 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1318 #endif // DEBUG_RIFF 1319 if (!pSubChunks) LoadSubChunks();
1320 ChunksIterator = pSubChunks->begin();
1321 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1336 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1337 #endif // DEBUG_RIFF 1338 if (!pSubChunks)
return NULL;
1340 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1356 std::cout <<
"List::GetFirstSubList()" << std::endl;
1357 #endif // DEBUG_RIFF 1358 if (!pSubChunks) LoadSubChunks();
1359 ListIterator = pSubChunks->begin();
1360 ChunkList::iterator end = pSubChunks->end();
1361 while (ListIterator != end) {
1362 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1380 std::cout <<
"List::GetNextSubList()" << std::endl;
1381 #endif // DEBUG_RIFF 1382 if (!pSubChunks)
return NULL;
1383 if (ListIterator == pSubChunks->end())
return NULL;
1385 ChunkList::iterator end = pSubChunks->end();
1386 while (ListIterator != end) {
1387 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1397 if (!pSubChunks) LoadSubChunks();
1398 return pSubChunks->size();
1407 if (!pSubChunks) LoadSubChunks();
1408 ChunkList::iterator iter = pSubChunks->begin();
1409 ChunkList::iterator end = pSubChunks->end();
1410 while (iter != end) {
1411 if ((*iter)->GetChunkID() == ChunkID) {
1423 return CountSubChunks(CHUNK_ID_LIST);
1432 if (!pSubChunks) LoadSubChunks();
1433 ChunkList::iterator iter = pSubChunks->begin();
1434 ChunkList::iterator end = pSubChunks->end();
1435 while (iter != end) {
1436 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1459 if (ullBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1460 if (!pSubChunks) LoadSubChunks();
1461 Chunk* pNewChunk =
new Chunk(pFile,
this, uiChunkID, 0);
1462 pSubChunks->push_back(pNewChunk);
1463 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1464 pNewChunk->
Resize(ullBodySize);
1481 if (!pSubChunks) LoadSubChunks();
1482 for (
size_t i = 0; i < pSubChunks->size(); ++i) {
1483 if ((*pSubChunks)[i] == pSrc) {
1484 pSubChunks->erase(pSubChunks->begin() + i);
1485 ChunkList::iterator iter =
1486 find(pSubChunks->begin(), pSubChunks->end(), pDst);
1487 pSubChunks->insert(iter, pSrc);
1502 if (pNewParent ==
this || !pNewParent)
return;
1503 if (!pSubChunks) LoadSubChunks();
1504 if (!pNewParent->pSubChunks) pNewParent->LoadSubChunks();
1505 ChunkList::iterator iter =
1506 find(pSubChunks->begin(), pSubChunks->end(), pSrc);
1507 if (iter == pSubChunks->end())
return;
1508 pSubChunks->erase(iter);
1509 pNewParent->pSubChunks->push_back(pSrc);
1511 if ((*pSubChunksMap)[pSrc->
GetChunkID()] == pSrc) {
1514 ChunkList::iterator iter = pSubChunks->begin();
1515 ChunkList::iterator end = pSubChunks->end();
1516 for (; iter != end; ++iter) {
1517 if ((*iter)->GetChunkID() == pSrc->
GetChunkID()) {
1518 (*pSubChunksMap)[pSrc->
GetChunkID()] = *iter;
1524 if (!(*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()])
1525 (*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()] = pSrc;
1538 if (!pSubChunks) LoadSubChunks();
1539 List* pNewListChunk =
new List(pFile,
this, uiListType);
1540 pSubChunks->push_back(pNewListChunk);
1541 (*pSubChunksMap)[CHUNK_ID_LIST] = pNewListChunk;
1543 return pNewListChunk;
1557 if (!pSubChunks) LoadSubChunks();
1558 ChunkList::iterator iter =
1559 find(pSubChunks->begin(), pSubChunks->end(), pSubChunk);
1560 if (iter == pSubChunks->end())
return;
1561 pSubChunks->erase(iter);
1562 if ((*pSubChunksMap)[pSubChunk->
GetChunkID()] == pSubChunk) {
1563 pSubChunksMap->erase(pSubChunk->
GetChunkID());
1565 ChunkList::iterator iter = pSubChunks->begin();
1566 ChunkList::iterator end = pSubChunks->end();
1567 for (; iter != end; ++iter) {
1568 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1569 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1585 if (!pSubChunks) LoadSubChunks();
1587 ChunkList::iterator iter = pSubChunks->begin();
1588 ChunkList::iterator end = pSubChunks->end();
1589 for (; iter != end; ++iter)
1590 size += (*iter)->RequiredPhysicalSize(fileOffsetSize);
1596 std::cout <<
"List::Readheader(file_offset_t) ";
1597 #endif // DEBUG_RIFF 1598 Chunk::ReadHeader(filePos);
1599 if (ullCurrentChunkSize < 4)
return;
1600 ullNewChunkSize = ullCurrentChunkSize -= 4;
1605 lseek(hRead, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1606 read(hRead, &ListType, 4);
1607 #elif defined(WIN32) 1608 LARGE_INTEGER liFilePos;
1609 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1610 SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN);
1612 ReadFile(hRead, &ListType, 4, &dwBytesRead, NULL);
1614 fseeko(hRead, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1615 fread(&ListType, 4, 1, hRead);
1618 std::cout <<
"listType=" << convertToString(ListType) << std::endl;
1619 #endif // DEBUG_RIFF 1620 if (!pFile->bEndianNative) {
1627 ullNewChunkSize += 4;
1628 Chunk::WriteHeader(filePos);
1629 ullNewChunkSize -= 4;
1634 lseek(hWrite, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1635 write(hWrite, &ListType, 4);
1636 #elif defined(WIN32) 1637 LARGE_INTEGER liFilePos;
1638 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1639 SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN);
1640 DWORD dwBytesWritten;
1641 WriteFile(hWrite, &ListType, 4, &dwBytesWritten, NULL);
1643 fseeko(hWrite, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1644 fwrite(&ListType, 4, 1, hWrite);
1648 void List::LoadSubChunks(
progress_t* pProgress) {
1650 std::cout <<
"List::LoadSubChunks()";
1651 #endif // DEBUG_RIFF 1653 pSubChunks =
new ChunkList();
1654 pSubChunksMap =
new ChunkMap();
1657 if (!_isValidHandle(hRead))
return;
1661 while (RemainingBytes() >= CHUNK_HEADER_SIZE(pFile->
FileOffsetSize)) {
1666 if (Read(&ckid, 4, 1) != 4)
1667 throw Exception(
"LoadSubChunks(): Failed reading RIFF chunk ID");
1669 std::cout <<
" ckid=" << convertToString(ckid) << std::endl;
1670 #endif // DEBUG_RIFF 1672 if (ckid == CHUNK_ID_LIST) {
1673 ck =
new RIFF::List(pFile, ullStartPos + pos - 4,
this);
1677 ck =
new RIFF::Chunk(pFile, ullStartPos + pos - 4,
this);
1680 pSubChunks->push_back(ck);
1681 (*pSubChunksMap)[ckid] = ck;
1682 if (GetPos() % 2 != 0) SetPos(1, RIFF::stream_curpos);
1684 SetPos(ullOriginalPos);
1687 __notify_progress(pProgress, 1.0);
1690 void List::LoadSubChunksRecursively(
progress_t* pProgress) {
1691 const int n = (int) CountSubLists();
1693 for (
List* pList = GetSubListAt(i); pList; pList = GetSubListAt(++i)) {
1697 __divide_progress(pProgress, &subprogress, n, i);
1699 pList->LoadSubChunksRecursively(&subprogress);
1701 pList->LoadSubChunksRecursively(NULL);
1704 __notify_progress(pProgress, 1.0);
1726 if (pFile->
GetMode() != stream_mode_read_write)
1727 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1732 const size_t n = pSubChunks->size();
1733 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter, ++i) {
1737 __divide_progress(pProgress, &subprogress, n, i);
1739 ullWritePos = (*iter)->WriteChunk(ullWritePos, ullCurrentDataOffset, &subprogress);
1741 ullWritePos = (*iter)->WriteChunk(ullWritePos, ullCurrentDataOffset, NULL);
1746 ullCurrentChunkSize = ullNewChunkSize = ullWritePos - ullOriginalPos - LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1747 WriteHeader(ullOriginalPos);
1750 ullStartPos = ullOriginalPos + LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1753 __notify_progress(pProgress, 1.0);
1761 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
1762 (*iter)->__resetPos();
1771 return convertToString(ListType);
1797 io.isPerThread =
false;
1799 io.hRead = io.hWrite = INVALID_HANDLE_VALUE;
1801 io.hRead = io.hWrite = 0;
1803 io.Mode = stream_mode_closed;
1804 bEndianNative =
true;
1805 ListType = FileType;
1823 std::cout <<
"File::File("<<path<<
")" << std::endl;
1824 #endif // DEBUG_RIFF 1825 bEndianNative =
true;
1828 __openExistingFile(path);
1829 if (ChunkID != CHUNK_ID_RIFF && ChunkID != CHUNK_ID_RIFX) {
1866 :
List(this), Filename(path), bIsNewFile(false),
Layout(layout),
1867 FileOffsetPreference(fileOffsetSize)
1871 throw Exception(
"Invalid RIFF::offset_size_t");
1874 __openExistingFile(path, &FileType);
1892 void File::__openExistingFile(
const String& path, uint32_t* FileType) {
1893 io.isPerThread =
false;
1895 io.hRead = io.hWrite = open(path.c_str(), O_RDONLY | O_NONBLOCK);
1896 if (io.hRead == -1) {
1897 io.hRead = io.hWrite = 0;
1898 String sError = strerror(errno);
1901 #elif defined(WIN32) 1902 io.hRead = io.hWrite = CreateFile(
1903 path.c_str(), GENERIC_READ,
1904 FILE_SHARE_READ | FILE_SHARE_WRITE,
1905 NULL, OPEN_EXISTING,
1906 FILE_ATTRIBUTE_NORMAL |
1907 FILE_FLAG_RANDOM_ACCESS, NULL
1909 if (io.hRead == INVALID_HANDLE_VALUE) {
1910 io.hRead = io.hWrite = INVALID_HANDLE_VALUE;
1914 io.hRead = io.hWrite = fopen(path.c_str(),
"rb");
1917 io.Mode = stream_mode_read;
1927 if (FileType && ChunkID != *FileType)
1935 if (
Read(&ckid, 4, 1) != 4) {
1936 throw RIFF::Exception(
"Invalid file header ID (premature end of header)");
1937 }
else if (ckid != *FileType) {
1938 String s =
" (expected '" + convertToString(*FileType) +
"' but got '" + convertToString(ckid) +
"')";
1948 String File::GetFileName()
const {
1952 void File::SetFileName(
const String& path) {
1964 File::HandlePair& File::FileHandlePairUnsafeRef() {
1965 if (io.byThread.empty())
return io;
1966 const std::thread::id tid = std::this_thread::get_id();
1967 const auto it = io.byThread.find(tid);
1968 return (it != io.byThread.end()) ?
1970 io.byThread[tid] = {
1973 INVALID_HANDLE_VALUE,
1974 INVALID_HANDLE_VALUE,
1990 std::lock_guard<std::mutex> lock(io.mutex);
1991 if (io.byThread.empty())
return io;
1992 const std::thread::id tid = std::this_thread::get_id();
1993 const auto it = io.byThread.find(tid);
1994 return (it != io.byThread.end()) ?
1996 io.byThread[tid] = {
1999 INVALID_HANDLE_VALUE,
2000 INVALID_HANDLE_VALUE,
2056 bool bResetPos =
false;
2057 bool res = SetModeInternal(NewMode, &bResetPos);
2066 bool File::SetModeInternal(
stream_mode_t NewMode,
bool* pResetPos) {
2067 std::lock_guard<std::mutex> lock(io.mutex);
2068 HandlePair& io = FileHandlePairUnsafeRef();
2069 if (NewMode != io.Mode) {
2071 case stream_mode_read:
2072 if (_isValidHandle(io.hRead)) _close(io.hRead);
2074 io.hRead = io.hWrite = open(Filename.c_str(), O_RDONLY | O_NONBLOCK);
2075 if (io.hRead == -1) {
2076 io.hRead = io.hWrite = 0;
2077 String sError = strerror(errno);
2078 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode: " + sError);
2080 #elif defined(WIN32) 2081 io.hRead = io.hWrite = CreateFile(
2082 Filename.c_str(), GENERIC_READ,
2083 FILE_SHARE_READ | FILE_SHARE_WRITE,
2084 NULL, OPEN_EXISTING,
2085 FILE_ATTRIBUTE_NORMAL |
2086 FILE_FLAG_RANDOM_ACCESS,
2089 if (io.hRead == INVALID_HANDLE_VALUE) {
2090 io.hRead = io.hWrite = INVALID_HANDLE_VALUE;
2091 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
2094 io.hRead = io.hWrite = fopen(Filename.c_str(),
"rb");
2095 if (!io.hRead)
throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
2099 case stream_mode_read_write:
2100 if (_isValidHandle(io.hRead)) _close(io.hRead);
2102 io.hRead = io.hWrite = open(Filename.c_str(), O_RDWR | O_NONBLOCK);
2103 if (io.hRead == -1) {
2104 io.hRead = io.hWrite = open(Filename.c_str(), O_RDONLY | O_NONBLOCK);
2105 String sError = strerror(errno);
2106 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode: " + sError);
2108 #elif defined(WIN32) 2109 io.hRead = io.hWrite = CreateFile(
2111 GENERIC_READ | GENERIC_WRITE,
2114 FILE_ATTRIBUTE_NORMAL |
2115 FILE_FLAG_RANDOM_ACCESS,
2118 if (io.hRead == INVALID_HANDLE_VALUE) {
2119 io.hRead = io.hWrite = CreateFile(
2120 Filename.c_str(), GENERIC_READ,
2121 FILE_SHARE_READ | FILE_SHARE_WRITE,
2122 NULL, OPEN_EXISTING,
2123 FILE_ATTRIBUTE_NORMAL |
2124 FILE_FLAG_RANDOM_ACCESS,
2127 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read+write mode");
2130 io.hRead = io.hWrite = fopen(Filename.c_str(),
"r+b");
2132 io.hRead = io.hWrite = fopen(Filename.c_str(),
"rb");
2133 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode");
2138 case stream_mode_closed:
2139 if (_isValidHandle(io.hRead)) _close(io.hRead);
2140 if (_isValidHandle(io.hWrite)) _close(io.hWrite);
2142 io.hRead = io.hWrite = 0;
2143 #elif defined(WIN32) 2144 io.hRead = io.hWrite = INVALID_HANDLE_VALUE;
2146 io.hRead = io.hWrite = NULL;
2150 throw Exception(
"Unknown file access mode");
2169 bEndianNative = Endian != endian_little;
2171 bEndianNative = Endian != endian_big;
2188 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
2194 __divide_progress(pProgress, &subprogress, 3.f, 0.f);
2196 LoadSubChunksRecursively(&subprogress);
2198 __notify_progress(&subprogress, 1.f);
2200 LoadSubChunksRecursively(NULL);
2203 SetMode(stream_mode_read_write);
2216 const Handle hRead = io.hRead;
2217 const Handle hWrite = io.hWrite;
2229 if (newFileSize > workingFileSize) {
2230 positiveSizeDiff = newFileSize - workingFileSize;
2235 __divide_progress(pProgress, &subprogress, 3.f, 1.f);
2238 ResizeFile(newFileSize);
2241 int8_t* pCopyBuffer =
new int8_t[4096];
2243 DWORD iBytesMoved = 1;
2245 ssize_t iBytesMoved = 1;
2247 for (
file_offset_t ullPos = workingFileSize, iNotif = 0; iBytesMoved > 0; ++iNotif) {
2248 iBytesMoved = (ullPos < 4096) ? ullPos : 4096;
2249 ullPos -= iBytesMoved;
2251 lseek(hRead, ullPos, SEEK_SET);
2252 iBytesMoved = read(hRead, pCopyBuffer, iBytesMoved);
2253 lseek(hWrite, ullPos + positiveSizeDiff, SEEK_SET);
2254 iBytesMoved = write(hWrite, pCopyBuffer, iBytesMoved);
2255 #elif defined(WIN32) 2256 LARGE_INTEGER liFilePos;
2257 liFilePos.QuadPart = ullPos;
2258 SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN);
2259 ReadFile(hRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
2260 liFilePos.QuadPart = ullPos + positiveSizeDiff;
2261 SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN);
2262 WriteFile(hWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
2264 fseeko(hRead, ullPos, SEEK_SET);
2265 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, hRead);
2266 fseeko(hWrite, ullPos + positiveSizeDiff, SEEK_SET);
2267 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, hWrite);
2269 if (pProgress && !(iNotif % 8) && iBytesMoved > 0)
2270 __notify_progress(&subprogress,
float(workingFileSize - ullPos) /
float(workingFileSize));
2272 delete[] pCopyBuffer;
2273 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
2276 __notify_progress(&subprogress, 1.f);
2284 __divide_progress(pProgress, &subprogress, 3.f, 2.f);
2287 const file_offset_t finalActualSize = __GetFileSize(hWrite);
2290 __notify_progress(&subprogress, 1.f);
2293 if (finalSize < finalActualSize) ResizeFile(finalSize);
2296 __notify_progress(pProgress, 1.0);
2319 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
2325 __divide_progress(pProgress, &subprogress, 2.f, 0.f);
2327 LoadSubChunksRecursively(&subprogress);
2329 __notify_progress(&subprogress, 1.f);
2331 LoadSubChunksRecursively(NULL);
2333 if (!bIsNewFile)
SetMode(stream_mode_read);
2336 std::lock_guard<std::mutex> lock(io.mutex);
2337 HandlePair& io = FileHandlePairUnsafeRef();
2341 io.hWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
2342 if (io.hWrite == -1) {
2343 io.hWrite = io.hRead;
2344 String sError = strerror(errno);
2345 throw Exception(
"Could not open file \"" + path +
"\" for writing: " + sError);
2347 #elif defined(WIN32) 2348 io.hWrite = CreateFile(
2349 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
2350 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
2351 FILE_FLAG_RANDOM_ACCESS, NULL
2353 if (io.hWrite == INVALID_HANDLE_VALUE) {
2354 io.hWrite = io.hRead;
2355 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2358 io.hWrite = fopen(path.c_str(),
"w+b");
2360 io.hWrite = io.hRead;
2361 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2364 io.Mode = stream_mode_read_write;
2379 __divide_progress(pProgress, &subprogress, 2.f, 1.f);
2381 ullTotalSize =
WriteChunk(0, 0, &subprogress);
2383 __notify_progress(&subprogress, 1.f);
2390 if (ullActualSize > ullTotalSize) ResizeFile(ullTotalSize);
2393 std::lock_guard<std::mutex> lock(io.mutex);
2394 HandlePair& io = FileHandlePairUnsafeRef();
2396 if (_isValidHandle(io.hWrite)) _close(io.hWrite);
2397 io.hWrite = io.hRead;
2404 SetMode(stream_mode_read_write);
2407 __notify_progress(pProgress, 1.0);
2413 if (ftruncate(hWrite, ullNewSize) < 0)
2414 throw Exception(
"Could not resize file \"" + Filename +
"\"");
2415 #elif defined(WIN32) 2416 LARGE_INTEGER liFilePos;
2417 liFilePos.QuadPart = ullNewSize;
2419 !SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN) ||
2420 !SetEndOfFile(hWrite)
2421 )
throw Exception(
"Could not resize file \"" + Filename +
"\"");
2423 # error Sorry, this version of libgig only supports POSIX and Windows systems yet. 2424 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)! 2430 std::cout <<
"File::~File()" << std::endl;
2431 #endif // DEBUG_RIFF 2443 void File::Cleanup() {
2445 for (
auto it = io.byThread.begin(); it != io.byThread.end(); ++it) {
2446 _close(it->second.hRead);
2465 size = __GetFileSize(hRead);
2507 switch (fileOffsetSize) {
2517 default:
throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2523 switch (FileOffsetPreference) {
2525 return (fileSize >> 32) ? 8 : 4;
2531 throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2610 return io.isPerThread;
2629 std::lock_guard<std::mutex> lock(io.mutex);
2630 if (!io.byThread.empty() == enable)
return;
2631 io.isPerThread = enable;
2633 const std::thread::id tid = std::this_thread::get_id();
2634 io.byThread[tid] = io;
2637 for (
auto it = io.byThread.begin(); it != io.byThread.end(); ++it) {
2638 if (it == io.byThread.begin()) {
2639 io.hRead = it->second.hRead;
2640 io.hWrite = it->second.hWrite;
2642 _close(it->second.hRead);
2643 _close(it->second.hWrite);
2646 io.byThread.clear();
2652 struct stat filestat;
2653 if (fstat(hFile, &filestat) == -1)
2654 throw Exception(
"POSIX FS error: could not determine file size");
2655 return filestat.st_size;
2657 #elif defined(WIN32) 2660 if (!GetFileSizeEx(hFile, &size))
2661 throw Exception(
"Windows FS error: could not determine file size");
2662 return size.QuadPart;
2664 #else // standard C functions 2666 off_t curpos = ftello(hFile);
2667 if (fseeko(hFile, 0, SEEK_END) == -1)
2668 throw Exception(
"FS error: could not determine file size");
2669 off_t size = ftello(hFile);
2670 fseeko(hFile, curpos, SEEK_SET);
2679 Exception::Exception() {
2682 Exception::Exception(String format, ...) {
2684 va_start(arg, format);
2685 Message = assemble(format, arg);
2689 Exception::Exception(String format, va_list arg) {
2690 Message = assemble(format, arg);
2693 void Exception::PrintMessage() {
2694 std::cout <<
"RIFF::Exception: " << Message << std::endl;
2697 String Exception::assemble(String format, va_list arg) {
2699 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)
List * GetSubListAt(size_t pos)
Returns sublist chunk with list type ListType at supplied pos position among all subchunks of type Li...
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.
std::vector< progress_t > subdivide(int iSubtasks)
Divides this progress task into the requested amount of equal weighted sub-progress tasks and returns...
List * GetSubList(uint32_t ListType)
Returns sublist chunk with list type ListType within this chunk list.
void DeleteSubChunk(Chunk *pSubChunk)
Removes a sub chunk.
Handle FileHandle() const
Returns the OS dependent file I/O read handle intended to be used by the calling thread.
Use 32 bit offsets for files smaller than 4 GB, use 64 bit offsets for files equal or larger than 4 G...
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.
HandlePair FileHandlePair() const
Returns the OS dependent file I/O read and write handles intended to be used by the calling thread...
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'...
Handle FileWriteHandle() const
Returns the OS dependent file I/O write handle intended to be used by the calling thread...
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...
int Handle
OS dependent type serving as file handle / descriptor for OS dependent file I/O operations.
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...
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...
bool IsIOPerThread() const
Whether file streams are independent for each thread.
Chunk * GetSubChunkAt(size_t pos)
Returns subchunk at supplied pos position within this chunk list.
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.
file_offset_t GetFilePos() const
Current, actual offset in file of current chunk data body read/write position.
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
Current read/write position within the chunk data body (starting with 0).
void SetIOPerThread(bool enable)
Enable/disable file streams being independent for each thread.
stream_mode_t GetMode() const
Returns the file I/O mode currently being available for the calling thread for this RIFF file (either...
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.