37 # define RIFF_INVALID_FILE_HANDLE -1
39 # define RIFF_INVALID_FILE_HANDLE INVALID_HANDLE_VALUE
41 # define RIFF_INVALID_FILE_HANDLE NULL
50 static String __resolveChunkPath(Chunk* pCk) {
52 for (Chunk* pChunk = pCk; pChunk; pChunk = pChunk->GetParent()) {
53 if (pChunk->GetChunkID() == CHUNK_ID_LIST) {
54 List* pList = (List*) pChunk;
55 sPath =
"->'" + pList->GetListTypeString() +
"'" + sPath;
57 sPath =
"->'" + pChunk->GetChunkIDString() +
"'" + sPath;
64 return handle != RIFF_INVALID_FILE_HANDLE;
68 if (!_isValidHandle(handle))
return;
83 progress_t::progress_t() {
92 progress_t::~progress_t() {
103 std::vector<progress_t> v;
104 for (
int i = 0; i < iSubtasks; ++i) {
106 __divide_progress(
this, &p, iSubtasks, i);
136 for (
int i = 0; i < vSubTaskPortions.size(); ++i)
137 fTotal += vSubTaskPortions[i];
139 float fLow = 0.f, fHigh = 0.f;
140 std::vector<progress_t> v;
141 for (
int i = 0; i < vSubTaskPortions.size(); ++i) {
143 fHigh = vSubTaskPortions[i];
145 __divide_progress(
this, &p, fTotal, fLow, fHigh);
156 struct _FileProgress {
162 __notify_progress(progress,
float(current) /
float(total));
171 Chunk::Chunk(File* pFile) {
173 std::cout <<
"Chunk::Chunk(File* pFile)" << std::endl;
178 ullCurrentChunkSize = 0;
180 ullChunkDataSize = 0;
181 ChunkID = CHUNK_ID_RIFF;
185 Chunk::Chunk(File* pFile,
file_offset_t StartPos, List* Parent) {
187 std::cout <<
"Chunk::Chunk(File*,file_offset_t,List*),StartPos=" << StartPos << std::endl;
190 ullStartPos = StartPos + CHUNK_HEADER_SIZE(pFile->FileOffsetSize);
194 ullCurrentChunkSize = 0;
196 ullChunkDataSize = 0;
197 ReadHeader(StartPos);
200 Chunk::Chunk(File* pFile, List* pParent, uint32_t uiChunkID,
file_offset_t ullBodySize) {
203 this->pParent = pParent;
207 ullChunkDataSize = 0;
208 ullCurrentChunkSize = 0;
209 ullNewChunkSize = ullBodySize;
213 if (pChunkData)
delete[] pChunkData;
218 std::cout <<
"Chunk::Readheader(" << filePos <<
") ";
221 ullNewChunkSize = ullCurrentChunkSize = 0;
226 if (lseek(hRead, filePos, SEEK_SET) != -1) {
227 read(hRead, &ChunkID, 4);
230 LARGE_INTEGER liFilePos;
231 liFilePos.QuadPart = filePos;
232 if (SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN)) {
234 ReadFile(hRead, &ChunkID, 4, &dwBytesRead, NULL);
235 ReadFile(hRead, &ullCurrentChunkSize, pFile->
FileOffsetSize, &dwBytesRead, NULL);
237 if (!fseeko(hRead, filePos, SEEK_SET)) {
238 fread(&ChunkID, 4, 1, hRead);
242 if (ChunkID == CHUNK_ID_RIFF) {
243 pFile->bEndianNative =
false;
246 if (ChunkID == CHUNK_ID_RIFX) {
247 pFile->bEndianNative =
false;
248 ChunkID = CHUNK_ID_RIFF;
251 if (!pFile->bEndianNative) {
254 swapBytes_32(&ullCurrentChunkSize);
256 swapBytes_64(&ullCurrentChunkSize);
259 std::cout <<
"ckID=" << convertToString(ChunkID) <<
" ";
260 std::cout <<
"ckSize=" << ullCurrentChunkSize <<
" ";
261 std::cout <<
"bEndianNative=" << pFile->bEndianNative << std::endl;
263 ullNewChunkSize = ullCurrentChunkSize;
268 uint32_t uiNewChunkID = ChunkID;
269 if (ChunkID == CHUNK_ID_RIFF) {
271 if (pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
273 if (!pFile->bEndianNative) uiNewChunkID = CHUNK_ID_RIFX;
277 uint64_t ullNewChunkSize = this->ullNewChunkSize;
278 if (!pFile->bEndianNative) {
280 swapBytes_32(&ullNewChunkSize);
282 swapBytes_64(&ullNewChunkSize);
288 if (lseek(hWrite, filePos, SEEK_SET) != -1) {
289 write(hWrite, &uiNewChunkID, 4);
293 LARGE_INTEGER liFilePos;
294 liFilePos.QuadPart = filePos;
295 if (SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN)) {
296 DWORD dwBytesWritten;
297 WriteFile(hWrite, &uiNewChunkID, 4, &dwBytesWritten, NULL);
298 WriteFile(hWrite, &ullNewChunkSize, pFile->
FileOffsetSize, &dwBytesWritten, NULL);
301 if (!fseeko(hWrite, filePos, SEEK_SET)) {
302 fwrite(&uiNewChunkID, 4, 1, hWrite);
313 return convertToString(ChunkID);
326 const std::thread::id tid = std::this_thread::get_id();
327 return chunkPos.byThread[tid];
337 const std::thread::id tid = std::this_thread::get_id();
338 std::lock_guard<std::mutex> lock(chunkPos.mutex);
339 return chunkPos.byThread[tid];
349 return ullStartPos +
GetPos();
367 std::cout <<
"Chunk::SetPos(file_offset_t,stream_whence_t)" << std::endl;
369 std::lock_guard<std::mutex> lock(chunkPos.mutex);
376 pos = ullCurrentChunkSize - 1 - Where;
378 case stream_backward:
381 case stream_start:
default:
385 if (pos > ullCurrentChunkSize) pos = ullCurrentChunkSize;
402 std::cout <<
"Chunk::Remainingbytes()=" << ullCurrentChunkSize - ullPos << std::endl;
405 return (ullCurrentChunkSize > pos) ? ullCurrentChunkSize - pos : 0;
416 return CHUNK_HEADER_SIZE(fileOffsetSize) +
436 std::cout <<
"Chunk::GetState()" << std::endl;
441 if (!_isValidHandle(hRead))
442 return stream_closed;
445 if (pos < ullCurrentChunkSize)
return stream_ready;
446 else return stream_end_reached;
467 std::cout <<
"Chunk::Read(void*,file_offset_t,file_offset_t)" << std::endl;
471 if (pos >= ullCurrentChunkSize)
return 0;
472 if (pos + WordCount * WordSize >= ullCurrentChunkSize)
473 WordCount = (ullCurrentChunkSize - pos) / WordSize;
478 if (lseek(hRead, ullStartPos + pos, SEEK_SET) < 0)
return 0;
479 ssize_t readWords = read(hRead, pData, WordCount * WordSize);
482 std::cerr <<
"POSIX read() failed: " << strerror(errno) << std::endl << std::flush;
486 readWords /= WordSize;
488 LARGE_INTEGER liFilePos;
489 liFilePos.QuadPart = ullStartPos + pos;
490 if (!SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN))
493 ReadFile(hRead, pData, WordCount * WordSize, &readWords, NULL);
494 if (readWords < 1)
return 0;
495 readWords /= WordSize;
497 if (fseeko(hRead, ullStartPos + pos, SEEK_SET))
return 0;
498 file_offset_t readWords = fread(pData, WordSize, WordCount, hRead);
500 if (!pFile->bEndianNative && WordSize != 1) {
504 swapBytes_16((uint16_t*) pData + iWord);
508 swapBytes_32((uint32_t*) pData + iWord);
512 swapBytes_64((uint64_t*) pData + iWord);
516 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
520 SetPos(readWords * WordSize, stream_curpos);
543 if (io.Mode != stream_mode_read_write)
544 throw Exception(
"Cannot write data to chunk, file has to be opened in read+write mode first");
546 if (pos >= ullCurrentChunkSize || pos + WordCount * WordSize > ullCurrentChunkSize)
547 throw Exception(
"End of chunk reached while trying to write data");
548 if (!pFile->bEndianNative && WordSize != 1) {
552 swapBytes_16((uint16_t*) pData + iWord);
556 swapBytes_32((uint32_t*) pData + iWord);
560 swapBytes_64((uint64_t*) pData + iWord);
564 swapBytes((uint8_t*) pData + iWord * WordSize, WordSize);
569 if (lseek(io.hWrite, ullStartPos + pos, SEEK_SET) < 0) {
570 throw Exception(
"Could not seek to position " + ToString(pos) +
571 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
573 ssize_t writtenWords = write(io.hWrite, pData, WordCount * WordSize);
574 if (writtenWords < 1)
throw Exception(
"POSIX IO Error while trying to write chunk data");
575 writtenWords /= WordSize;
577 LARGE_INTEGER liFilePos;
578 liFilePos.QuadPart = ullStartPos + pos;
579 if (!SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN)) {
580 throw Exception(
"Could not seek to position " + ToString(pos) +
581 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
584 WriteFile(io.hWrite, pData, WordCount * WordSize, &writtenWords, NULL);
585 if (writtenWords < 1)
throw Exception(
"Windows IO Error while trying to write chunk data");
586 writtenWords /= WordSize;
588 if (fseeko(io.hWrite, ullStartPos + pos, SEEK_SET)) {
589 throw Exception(
"Could not seek to position " + ToString(pos) +
590 " in chunk (" + ToString(ullStartPos + pos) +
" in file)");
592 file_offset_t writtenWords = fwrite(pData, WordSize, WordCount, io.hWrite);
594 SetPos(writtenWords * WordSize, stream_curpos);
601 if (readWords != WordCount)
throw RIFF::Exception(
"End of chunk data reached.");
619 std::cout <<
"Chunk::ReadInt8(int8_t*,file_offset_t)" << std::endl;
640 return Write(pData, WordCount, 1);
658 std::cout <<
"Chunk::ReadUint8(uint8_t*,file_offset_t)" << std::endl;
679 return Write(pData, WordCount, 1);
697 std::cout <<
"Chunk::ReadInt16(int16_t*,file_offset_t)" << std::endl;
718 return Write(pData, WordCount, 2);
736 std::cout <<
"Chunk::ReadUint16(uint16_t*,file_offset_t)" << std::endl;
757 return Write(pData, WordCount, 2);
775 std::cout <<
"Chunk::ReadInt32(int32_t*,file_offset_t)" << std::endl;
796 return Write(pData, WordCount, 4);
814 std::cout <<
"Chunk::ReadUint32(uint32_t*,file_offset_t)" << std::endl;
831 char* buf =
new char[size];
833 s.assign(buf, std::find(buf, buf + size,
'\0'));
853 return Write(pData, WordCount, 4);
866 std::cout <<
"Chunk::ReadInt8()" << std::endl;
883 std::cout <<
"Chunk::ReadUint8()" << std::endl;
901 std::cout <<
"Chunk::ReadInt16()" << std::endl;
919 std::cout <<
"Chunk::ReadUint16()" << std::endl;
937 std::cout <<
"Chunk::ReadInt32()" << std::endl;
955 std::cout <<
"Chunk::ReadUint32()" << std::endl;
985 if (!pChunkData && pFile->Filename !=
"" ) {
988 if (lseek(hRead, ullStartPos, SEEK_SET) == -1)
return NULL;
990 LARGE_INTEGER liFilePos;
991 liFilePos.QuadPart = ullStartPos;
992 if (!SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN))
return NULL;
994 if (fseeko(hRead, ullStartPos, SEEK_SET))
return NULL;
996 file_offset_t ullBufferSize = (ullCurrentChunkSize > ullNewChunkSize) ? ullCurrentChunkSize : ullNewChunkSize;
997 pChunkData =
new uint8_t[ullBufferSize];
998 if (!pChunkData)
return NULL;
999 memset(pChunkData, 0, ullBufferSize);
1002 #elif defined(WIN32)
1004 ReadFile(hRead, pChunkData,
GetSize(), &readWords, NULL);
1009 delete[] pChunkData;
1010 return (pChunkData = NULL);
1012 ullChunkDataSize = ullBufferSize;
1013 }
else if (ullNewChunkSize > ullChunkDataSize) {
1014 uint8_t* pNewBuffer =
new uint8_t[ullNewChunkSize];
1015 if (!pNewBuffer)
throw Exception(
"Could not enlarge chunk data buffer to " + ToString(ullNewChunkSize) +
" bytes");
1016 memset(pNewBuffer, 0 , ullNewChunkSize);
1018 memcpy(pNewBuffer, pChunkData, ullChunkDataSize);
1019 delete[] pChunkData;
1021 pChunkData = pNewBuffer;
1022 ullChunkDataSize = ullNewChunkSize;
1035 delete[] pChunkData;
1060 throw Exception(
"There is at least one empty chunk (zero size): " + __resolveChunkPath(
this));
1061 if ((NewSize >> 48) != 0)
1062 throw Exception(
"Unrealistic high chunk size detected: " + __resolveChunkPath(
this));
1063 if (ullNewChunkSize == NewSize)
return;
1064 ullNewChunkSize = NewSize;
1087 if (io.Mode != stream_mode_read_write)
1088 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1096 lseek(io.hWrite, ullWritePos, SEEK_SET);
1097 if (write(io.hWrite, pChunkData, ullNewChunkSize) != ullNewChunkSize) {
1098 throw Exception(
"Writing Chunk data (from RAM) failed");
1100 #elif defined(WIN32)
1101 LARGE_INTEGER liFilePos;
1102 liFilePos.QuadPart = ullWritePos;
1103 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1104 DWORD dwBytesWritten;
1105 WriteFile(io.hWrite, pChunkData, ullNewChunkSize, &dwBytesWritten, NULL);
1106 if (dwBytesWritten != ullNewChunkSize) {
1107 throw Exception(
"Writing Chunk data (from RAM) failed");
1110 fseeko(io.hWrite, ullWritePos, SEEK_SET);
1111 if (fwrite(pChunkData, 1, ullNewChunkSize, io.hWrite) != ullNewChunkSize) {
1112 throw Exception(
"Writing Chunk data (from RAM) failed");
1117 int8_t* pCopyBuffer =
new int8_t[4096];
1118 file_offset_t ullToMove = (ullNewChunkSize < ullCurrentChunkSize) ? ullNewChunkSize : ullCurrentChunkSize;
1120 DWORD iBytesMoved = 1;
1122 int iBytesMoved = 1;
1124 for (
file_offset_t ullOffset = 0; ullToMove > 0 && iBytesMoved > 0; ullOffset += iBytesMoved, ullToMove -= iBytesMoved) {
1125 iBytesMoved = (ullToMove < 4096) ?
int(ullToMove) : 4096;
1127 lseek(io.hRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
1128 iBytesMoved = (int) read(io.hRead, pCopyBuffer, (
size_t) iBytesMoved);
1129 lseek(io.hWrite, ullWritePos + ullOffset, SEEK_SET);
1130 iBytesMoved = (int) write(io.hWrite, pCopyBuffer, (
size_t) iBytesMoved);
1131 #elif defined(WIN32)
1132 LARGE_INTEGER liFilePos;
1133 liFilePos.QuadPart = ullStartPos + ullCurrentDataOffset + ullOffset;
1134 SetFilePointerEx(io.hRead, liFilePos, NULL, FILE_BEGIN);
1135 ReadFile(io.hRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1136 liFilePos.QuadPart = ullWritePos + ullOffset;
1137 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1138 WriteFile(io.hWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
1140 fseeko(io.hRead, ullStartPos + ullCurrentDataOffset + ullOffset, SEEK_SET);
1141 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, io.hRead);
1142 fseeko(io.hWrite, ullWritePos + ullOffset, SEEK_SET);
1143 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, io.hWrite);
1146 delete[] pCopyBuffer;
1147 if (iBytesMoved < 0)
throw Exception(
"Writing Chunk data (from file) failed");
1151 ullCurrentChunkSize = ullNewChunkSize;
1152 WriteHeader(ullOriginalPos);
1155 ullStartPos = ullOriginalPos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1158 if (pProgress && pProgress->
__private) {
1159 _FileProgress* fileProgress = (_FileProgress*) pProgress->
__private;
1160 fileProgress->advance(pProgress, ullNewChunkSize +
1165 if ((ullStartPos + ullNewChunkSize) % 2 != 0) {
1166 const char cPadByte = 0;
1168 lseek(io.hWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
1169 write(io.hWrite, &cPadByte, 1);
1170 #elif defined(WIN32)
1171 LARGE_INTEGER liFilePos;
1172 liFilePos.QuadPart = ullStartPos + ullNewChunkSize;
1173 SetFilePointerEx(io.hWrite, liFilePos, NULL, FILE_BEGIN);
1174 DWORD dwBytesWritten;
1175 WriteFile(io.hWrite, &cPadByte, 1, &dwBytesWritten, NULL);
1177 fseeko(io.hWrite, ullStartPos + ullNewChunkSize, SEEK_SET);
1178 fwrite(&cPadByte, 1, 1, io.hWrite);
1180 return ullStartPos + ullNewChunkSize + 1;
1183 return ullStartPos + ullNewChunkSize;
1187 std::lock_guard<std::mutex> lock(chunkPos.mutex);
1188 chunkPos.ullPos = 0;
1189 chunkPos.byThread.clear();
1197 List::List(
File* pFile) :
Chunk(pFile) {
1199 std::cout <<
"List::List(File* pFile)" << std::endl;
1202 pSubChunksMap = NULL;
1205 List::List(File* pFile,
file_offset_t StartPos, List* Parent)
1206 : Chunk(pFile, StartPos, Parent) {
1208 std::cout <<
"List::List(File*,file_offset_t,List*)" << std::endl;
1211 pSubChunksMap = NULL;
1212 ReadHeader(StartPos);
1213 ullStartPos = StartPos + LIST_HEADER_SIZE(pFile->FileOffsetSize);
1216 List::List(File* pFile, List* pParent, uint32_t uiListID)
1217 : Chunk(pFile, pParent, CHUNK_ID_LIST, 0) {
1219 pSubChunksMap = NULL;
1220 ListType = uiListID;
1225 std::cout <<
"List::~List()" << std::endl;
1230 void List::DeleteChunkList() {
1232 ChunkList::iterator iter = pSubChunks->begin();
1233 ChunkList::iterator end = pSubChunks->end();
1234 while (iter != end) {
1241 if (pSubChunksMap) {
1242 delete pSubChunksMap;
1243 pSubChunksMap = NULL;
1257 if (!pSubChunks) LoadSubChunks();
1258 if (pos >= pSubChunks->size())
return NULL;
1259 return (*pSubChunks)[pos];
1275 std::cout <<
"List::GetSubChunk(uint32_t)" << std::endl;
1277 if (!pSubChunksMap) LoadSubChunks();
1278 return (*pSubChunksMap)[ChunkID];
1292 if (!pSubChunks) LoadSubChunks();
1293 if (pos >= pSubChunks->size())
return NULL;
1294 for (
size_t iCk = 0, iLst = 0; iCk < pSubChunks->size(); ++iCk) {
1295 Chunk* pChunk = (*pSubChunks)[iCk];
1296 if (pChunk->
GetChunkID() != CHUNK_ID_LIST)
continue;
1297 if (iLst == pos)
return (
List*) pChunk;
1316 std::cout <<
"List::GetSubList(uint32_t)" << std::endl;
1318 if (!pSubChunks) LoadSubChunks();
1319 ChunkList::iterator iter = pSubChunks->begin();
1320 ChunkList::iterator end = pSubChunks->end();
1321 while (iter != end) {
1322 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1344 std::cout <<
"List::GetFirstSubChunk()" << std::endl;
1346 if (!pSubChunks) LoadSubChunks();
1347 ChunksIterator = pSubChunks->begin();
1348 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1363 std::cout <<
"List::GetNextSubChunk()" << std::endl;
1365 if (!pSubChunks)
return NULL;
1367 return (ChunksIterator != pSubChunks->end()) ? *ChunksIterator : NULL;
1383 std::cout <<
"List::GetFirstSubList()" << std::endl;
1385 if (!pSubChunks) LoadSubChunks();
1386 ListIterator = pSubChunks->begin();
1387 ChunkList::iterator end = pSubChunks->end();
1388 while (ListIterator != end) {
1389 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1407 std::cout <<
"List::GetNextSubList()" << std::endl;
1409 if (!pSubChunks)
return NULL;
1410 if (ListIterator == pSubChunks->end())
return NULL;
1412 ChunkList::iterator end = pSubChunks->end();
1413 while (ListIterator != end) {
1414 if ((*ListIterator)->GetChunkID() == CHUNK_ID_LIST)
return (
List*) *ListIterator;
1424 if (!pSubChunks) LoadSubChunks();
1425 return pSubChunks->size();
1434 if (!pSubChunks) LoadSubChunks();
1435 ChunkList::iterator iter = pSubChunks->begin();
1436 ChunkList::iterator end = pSubChunks->end();
1437 while (iter != end) {
1438 if ((*iter)->GetChunkID() == ChunkID) {
1459 if (!pSubChunks) LoadSubChunks();
1460 ChunkList::iterator iter = pSubChunks->begin();
1461 ChunkList::iterator end = pSubChunks->end();
1462 while (iter != end) {
1463 if ((*iter)->GetChunkID() == CHUNK_ID_LIST) {
1486 if (ullBodySize == 0)
throw Exception(
"Chunk body size must be at least 1 byte");
1487 if (!pSubChunks) LoadSubChunks();
1489 Chunk* pNewChunk =
new Chunk(pFile,
this, uiChunkID, 0);
1490 pSubChunks->push_back(pNewChunk);
1491 (*pSubChunksMap)[uiChunkID] = pNewChunk;
1492 pNewChunk->
Resize(ullBodySize);
1495 pFile->nDataChunkCount++;
1512 if (!pSubChunks) LoadSubChunks();
1513 for (
size_t i = 0; i < pSubChunks->size(); ++i) {
1514 if ((*pSubChunks)[i] == pSrc) {
1515 pSubChunks->erase(pSubChunks->begin() + i);
1516 ChunkList::iterator iter =
1517 find(pSubChunks->begin(), pSubChunks->end(), pDst);
1518 pSubChunks->insert(iter, pSrc);
1533 if (pNewParent ==
this || !pNewParent)
return;
1534 if (!pSubChunks) LoadSubChunks();
1535 if (!pNewParent->pSubChunks) pNewParent->LoadSubChunks();
1536 ChunkList::iterator iter =
1537 find(pSubChunks->begin(), pSubChunks->end(), pSrc);
1538 if (iter == pSubChunks->end())
return;
1539 pSubChunks->erase(iter);
1540 pNewParent->pSubChunks->push_back(pSrc);
1542 if ((*pSubChunksMap)[pSrc->
GetChunkID()] == pSrc) {
1545 ChunkList::iterator iter = pSubChunks->begin();
1546 ChunkList::iterator end = pSubChunks->end();
1547 for (; iter != end; ++iter) {
1548 if ((*iter)->GetChunkID() == pSrc->
GetChunkID()) {
1549 (*pSubChunksMap)[pSrc->
GetChunkID()] = *iter;
1555 if (!(*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()])
1556 (*pNewParent->pSubChunksMap)[pSrc->
GetChunkID()] = pSrc;
1569 if (!pSubChunks) LoadSubChunks();
1571 List* pNewListChunk =
new List(pFile,
this, uiListType);
1572 pSubChunks->push_back(pNewListChunk);
1573 (*pSubChunksMap)[CHUNK_ID_LIST] = pNewListChunk;
1576 pFile->nListChunkCount++;
1578 return pNewListChunk;
1592 if (!pSubChunks) LoadSubChunks();
1593 ChunkList::iterator iter =
1594 find(pSubChunks->begin(), pSubChunks->end(), pSubChunk);
1595 if (iter == pSubChunks->end())
return;
1596 pSubChunks->erase(iter);
1598 if (
dynamic_cast<List*
>(pSubChunk))
1599 pFile->nListChunkCount--;
1601 pFile->nDataChunkCount--;
1603 if ((*pSubChunksMap)[pSubChunk->
GetChunkID()] == pSubChunk) {
1604 pSubChunksMap->erase(pSubChunk->
GetChunkID());
1606 ChunkList::iterator iter = pSubChunks->begin();
1607 ChunkList::iterator end = pSubChunks->end();
1608 for (; iter != end; ++iter) {
1609 if ((*iter)->GetChunkID() == pSubChunk->
GetChunkID()) {
1610 (*pSubChunksMap)[pSubChunk->
GetChunkID()] = *iter;
1626 if (!pSubChunks) LoadSubChunks();
1628 ChunkList::iterator iter = pSubChunks->begin();
1629 ChunkList::iterator end = pSubChunks->end();
1630 for (; iter != end; ++iter)
1631 size += (*iter)->RequiredPhysicalSize(fileOffsetSize);
1637 std::cout <<
"List::Readheader(file_offset_t) ";
1639 Chunk::ReadHeader(filePos);
1640 if (ullCurrentChunkSize < 4)
return;
1641 ullNewChunkSize = ullCurrentChunkSize -= 4;
1646 lseek(hRead, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1647 read(hRead, &ListType, 4);
1648 #elif defined(WIN32)
1649 LARGE_INTEGER liFilePos;
1650 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1651 SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN);
1653 ReadFile(hRead, &ListType, 4, &dwBytesRead, NULL);
1655 fseeko(hRead, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1656 fread(&ListType, 4, 1, hRead);
1659 std::cout <<
"listType=" << convertToString(ListType) << std::endl;
1661 if (!pFile->bEndianNative) {
1668 ullNewChunkSize += 4;
1669 Chunk::WriteHeader(filePos);
1670 ullNewChunkSize -= 4;
1675 lseek(hWrite, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1676 write(hWrite, &ListType, 4);
1677 #elif defined(WIN32)
1678 LARGE_INTEGER liFilePos;
1679 liFilePos.QuadPart = filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize);
1680 SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN);
1681 DWORD dwBytesWritten;
1682 WriteFile(hWrite, &ListType, 4, &dwBytesWritten, NULL);
1684 fseeko(hWrite, filePos + CHUNK_HEADER_SIZE(pFile->
FileOffsetSize), SEEK_SET);
1685 fwrite(&ListType, 4, 1, hWrite);
1689 void List::LoadSubChunks(progress_t* pProgress) {
1691 std::cout <<
"List::LoadSubChunks()";
1694 pSubChunks =
new ChunkList();
1695 pSubChunksMap =
new ChunkMap();
1698 if (!_isValidHandle(hRead))
return;
1707 if (
Read(&ckid, 4, 1) != 4)
1708 throw Exception(
"LoadSubChunks(): Failed reading RIFF chunk ID");
1710 std::cout <<
" ckid=" << convertToString(ckid) << std::endl;
1713 if (ckid == CHUNK_ID_LIST) {
1714 ck =
new RIFF::List(pFile, ullStartPos + pos - 4,
this);
1717 pFile->nListChunkCount++;
1720 ck =
new RIFF::Chunk(pFile, ullStartPos + pos - 4,
this);
1723 pFile->nDataChunkCount++;
1725 pSubChunks->push_back(ck);
1726 (*pSubChunksMap)[ckid] = ck;
1732 __notify_progress(pProgress, 1.0);
1735 void List::LoadSubChunksRecursively(progress_t* pProgress) {
1741 progress_t subprogress;
1742 __divide_progress(pProgress, &subprogress, n, i);
1744 pList->LoadSubChunksRecursively(&subprogress);
1746 pList->LoadSubChunksRecursively(NULL);
1749 __notify_progress(pProgress, 1.0);
1771 if (pFile->
GetMode() != stream_mode_read_write)
1772 throw Exception(
"Cannot write list chunk, file has to be opened in read+write mode");
1776 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
1777 ullWritePos = (*iter)->WriteChunk(ullWritePos, ullCurrentDataOffset, pProgress);
1782 ullCurrentChunkSize = ullNewChunkSize = ullWritePos - ullOriginalPos - LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1783 WriteHeader(ullOriginalPos);
1786 ullStartPos = ullOriginalPos + LIST_HEADER_SIZE(pFile->
FileOffsetSize);
1788 if (pProgress && pProgress->
__private) {
1789 _FileProgress* fileProgress = (_FileProgress*) pProgress->
__private;
1790 fileProgress->advance(pProgress,
1800 for (ChunkList::iterator iter = pSubChunks->begin(), end = pSubChunks->end(); iter != end; ++iter) {
1801 (*iter)->__resetPos();
1810 return convertToString(ListType);
1836 io.isPerThread =
false;
1837 io.hRead = io.hWrite = RIFF_INVALID_FILE_HANDLE;
1838 io.Mode = stream_mode_closed;
1839 bEndianNative =
true;
1840 ListType = FileType;
1842 nDataChunkCount = 0;
1843 nListChunkCount = 0;
1860 std::cout <<
"File::File("<<path<<
")" << std::endl;
1862 bEndianNative =
true;
1864 nDataChunkCount = 0;
1865 nListChunkCount = 0;
1867 __openExistingFile(path);
1868 if (ChunkID != CHUNK_ID_RIFF && ChunkID != CHUNK_ID_RIFX) {
1905 :
List(this), Filename(path), bIsNewFile(false), Layout(layout),
1906 FileOffsetPreference(fileOffsetSize)
1910 throw Exception(
"Invalid RIFF::offset_size_t");
1912 nDataChunkCount = 0;
1913 nListChunkCount = 0;
1915 __openExistingFile(path, &FileType);
1933 void File::__openExistingFile(
const String& path, uint32_t* FileType) {
1934 io.isPerThread =
false;
1936 io.hRead = io.hWrite = open(path.c_str(), O_RDONLY | O_NONBLOCK);
1937 if (!_isValidHandle(io.hRead)) {
1938 String sError = strerror(errno);
1941 #elif defined(WIN32)
1942 io.hRead = io.hWrite = CreateFile(
1943 path.c_str(), GENERIC_READ,
1944 FILE_SHARE_READ | FILE_SHARE_WRITE,
1945 NULL, OPEN_EXISTING,
1946 FILE_ATTRIBUTE_NORMAL |
1947 FILE_FLAG_RANDOM_ACCESS, NULL
1949 if (!_isValidHandle(io.hRead)) {
1953 io.hRead = io.hWrite = fopen(path.c_str(),
"rb");
1954 if (!_isValidHandle(io.hRead))
1957 io.Mode = stream_mode_read;
1967 if (FileType && ChunkID != *FileType)
1975 if (
Read(&ckid, 4, 1) != 4) {
1976 throw RIFF::Exception(
"Invalid file header ID (premature end of header)");
1977 }
else if (ckid != *FileType) {
1978 String s =
" (expected '" + convertToString(*FileType) +
"' but got '" + convertToString(ckid) +
"')";
1988 String File::GetFileName()
const {
1992 void File::SetFileName(
const String& path) {
2004 File::HandlePair& File::FileHandlePairUnsafeRef() {
2005 if (io.byThread.empty())
return io;
2006 const std::thread::id tid = std::this_thread::get_id();
2007 const auto it = io.byThread.find(tid);
2008 return (it != io.byThread.end()) ?
2010 io.byThread[tid] = {
2012 RIFF_INVALID_FILE_HANDLE,
2013 RIFF_INVALID_FILE_HANDLE,
2025 std::lock_guard<std::mutex> lock(io.mutex);
2026 if (io.byThread.empty())
return io;
2027 const std::thread::id tid = std::this_thread::get_id();
2028 const auto it = io.byThread.find(tid);
2029 return (it != io.byThread.end()) ?
2031 io.byThread[tid] = {
2033 RIFF_INVALID_FILE_HANDLE,
2034 RIFF_INVALID_FILE_HANDLE,
2086 bool bResetPos =
false;
2087 bool res = SetModeInternal(NewMode, &bResetPos);
2096 bool File::SetModeInternal(
stream_mode_t NewMode,
bool* pResetPos) {
2097 std::lock_guard<std::mutex> lock(io.mutex);
2098 HandlePair& io = FileHandlePairUnsafeRef();
2099 if (NewMode != io.Mode) {
2101 case stream_mode_read:
2102 if (_isValidHandle(io.hRead)) _close(io.hRead);
2104 io.hRead = io.hWrite = open(Filename.c_str(), O_RDONLY | O_NONBLOCK);
2105 if (!_isValidHandle(io.hRead)) {
2106 String sError = strerror(errno);
2107 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode: " + sError);
2109 #elif defined(WIN32)
2110 io.hRead = io.hWrite = CreateFile(
2111 Filename.c_str(), GENERIC_READ,
2112 FILE_SHARE_READ | FILE_SHARE_WRITE,
2113 NULL, OPEN_EXISTING,
2114 FILE_ATTRIBUTE_NORMAL |
2115 FILE_FLAG_RANDOM_ACCESS,
2118 if (!_isValidHandle(io.hRead)) {
2119 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
2122 io.hRead = io.hWrite = fopen(Filename.c_str(),
"rb");
2123 if (!_isValidHandle(io.hRead))
2124 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read mode");
2128 case stream_mode_read_write:
2129 if (_isValidHandle(io.hRead)) _close(io.hRead);
2131 io.hRead = io.hWrite = open(Filename.c_str(), O_RDWR | O_NONBLOCK);
2132 if (!_isValidHandle(io.hRead)) {
2133 io.hRead = io.hWrite = open(Filename.c_str(), O_RDONLY | O_NONBLOCK);
2134 String sError = strerror(errno);
2135 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode: " + sError);
2137 #elif defined(WIN32)
2138 io.hRead = io.hWrite = CreateFile(
2140 GENERIC_READ | GENERIC_WRITE,
2143 FILE_ATTRIBUTE_NORMAL |
2144 FILE_FLAG_RANDOM_ACCESS,
2147 if (!_isValidHandle(io.hRead)) {
2148 io.hRead = io.hWrite = CreateFile(
2149 Filename.c_str(), GENERIC_READ,
2150 FILE_SHARE_READ | FILE_SHARE_WRITE,
2151 NULL, OPEN_EXISTING,
2152 FILE_ATTRIBUTE_NORMAL |
2153 FILE_FLAG_RANDOM_ACCESS,
2156 throw Exception(
"Could not (re)open file \"" + Filename +
"\" in read+write mode");
2159 io.hRead = io.hWrite = fopen(Filename.c_str(),
"r+b");
2160 if (!_isValidHandle(io.hRead)) {
2161 io.hRead = io.hWrite = fopen(Filename.c_str(),
"rb");
2162 throw Exception(
"Could not open file \"" + Filename +
"\" in read+write mode");
2167 case stream_mode_closed:
2168 if (_isValidHandle(io.hRead)) _close(io.hRead);
2169 if (_isValidHandle(io.hWrite)) _close(io.hWrite);
2170 io.hRead = io.hWrite = RIFF_INVALID_FILE_HANDLE;
2173 throw Exception(
"Unknown file access mode");
2192 bEndianNative = Endian != endian_little;
2194 bEndianNative = Endian != endian_big;
2211 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
2213 const bool bNeedLoadSubChunks = !pSubChunks;
2219 __divide_progress(pProgress, &subprogress, 1.f, 0.f, 0.2f);
2221 LoadSubChunksRecursively(&subprogress);
2223 __notify_progress(&subprogress, 1.f);
2225 LoadSubChunksRecursively(NULL);
2228 SetMode(stream_mode_read_write);
2241 const Handle hRead = io.hRead;
2242 const Handle hWrite = io.hWrite;
2254 if (newFileSize > workingFileSize) {
2255 positiveSizeDiff = newFileSize - workingFileSize;
2260 __divide_progress(pProgress, &subprogress, 1.f,
2261 bNeedLoadSubChunks ? 0.2f : 0.f,
2262 bNeedLoadSubChunks ? 0.7f : 0.6f);
2265 ResizeFile(newFileSize);
2268 int8_t* pCopyBuffer =
new int8_t[4096];
2270 DWORD iBytesMoved = 1;
2272 ssize_t iBytesMoved = 1;
2274 for (
file_offset_t ullPos = workingFileSize, iNotif = 0; iBytesMoved > 0; ++iNotif) {
2275 iBytesMoved = (ullPos < 4096) ? ullPos : 4096;
2276 ullPos -= iBytesMoved;
2278 lseek(hRead, ullPos, SEEK_SET);
2279 iBytesMoved = read(hRead, pCopyBuffer, iBytesMoved);
2280 lseek(hWrite, ullPos + positiveSizeDiff, SEEK_SET);
2281 iBytesMoved = write(hWrite, pCopyBuffer, iBytesMoved);
2282 #elif defined(WIN32)
2283 LARGE_INTEGER liFilePos;
2284 liFilePos.QuadPart = ullPos;
2285 SetFilePointerEx(hRead, liFilePos, NULL, FILE_BEGIN);
2286 ReadFile(hRead, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
2287 liFilePos.QuadPart = ullPos + positiveSizeDiff;
2288 SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN);
2289 WriteFile(hWrite, pCopyBuffer, iBytesMoved, &iBytesMoved, NULL);
2291 fseeko(hRead, ullPos, SEEK_SET);
2292 iBytesMoved = fread(pCopyBuffer, 1, iBytesMoved, hRead);
2293 fseeko(hWrite, ullPos + positiveSizeDiff, SEEK_SET);
2294 iBytesMoved = fwrite(pCopyBuffer, 1, iBytesMoved, hWrite);
2296 if (pProgress && !(iNotif % 8) && iBytesMoved > 0)
2297 __notify_progress(&subprogress,
float(workingFileSize - ullPos) /
float(workingFileSize));
2299 delete[] pCopyBuffer;
2300 if (iBytesMoved < 0)
throw Exception(
"Could not modify file while trying to enlarge it");
2303 __notify_progress(&subprogress, 1.f);
2310 _FileProgress fileProgress = { 0, newFileSize };
2312 __divide_progress(pProgress, &subprogress, 1.f,
2313 bNeedLoadSubChunks ? 0.7f : 0.6f, 1.f);
2318 const file_offset_t finalActualSize = __GetFileSize(hWrite);
2321 __notify_progress(&subprogress, 1.f);
2324 if (finalSize < finalActualSize) ResizeFile(finalSize);
2327 __notify_progress(pProgress, 1.0);
2350 throw Exception(
"Saving a RIFF file with layout_flat is not implemented yet");
2352 const bool bNeedLoadSubChunks = !pSubChunks;
2358 __divide_progress(pProgress, &subprogress, 1.f, 0.f, 0.3f);
2360 LoadSubChunksRecursively(&subprogress);
2362 __notify_progress(&subprogress, 1.f);
2364 LoadSubChunksRecursively(NULL);
2366 if (!bIsNewFile)
SetMode(stream_mode_read);
2369 std::lock_guard<std::mutex> lock(io.mutex);
2370 HandlePair& io = FileHandlePairUnsafeRef();
2374 io.hWrite = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP);
2375 if (!_isValidHandle(io.hWrite)) {
2376 io.hWrite = io.hRead;
2377 String sError = strerror(errno);
2378 throw Exception(
"Could not open file \"" + path +
"\" for writing: " + sError);
2380 #elif defined(WIN32)
2381 io.hWrite = CreateFile(
2382 path.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
2383 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
2384 FILE_FLAG_RANDOM_ACCESS, NULL
2386 if (!_isValidHandle(io.hWrite)) {
2387 io.hWrite = io.hRead;
2388 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2391 io.hWrite = fopen(path.c_str(),
"w+b");
2392 if (!_isValidHandle(io.hWrite)) {
2393 io.hWrite = io.hRead;
2394 throw Exception(
"Could not open file \"" + path +
"\" for writing");
2397 io.Mode = stream_mode_read_write;
2412 __divide_progress(pProgress, &subprogress, 1.f,
2413 bNeedLoadSubChunks ? 0.3f : 0.f, 1.f);
2414 _FileProgress fileProgress = { 0, newFileSize };
2417 ullTotalSize =
WriteChunk(0, 0, &subprogress);
2419 __notify_progress(&subprogress, 1.f);
2426 if (ullActualSize > ullTotalSize) ResizeFile(ullTotalSize);
2429 std::lock_guard<std::mutex> lock(io.mutex);
2430 HandlePair& io = FileHandlePairUnsafeRef();
2432 if (_isValidHandle(io.hWrite)) _close(io.hWrite);
2433 io.hWrite = io.hRead;
2440 SetMode(stream_mode_read_write);
2443 __notify_progress(pProgress, 1.0);
2449 if (ftruncate(hWrite, ullNewSize) < 0)
2450 throw Exception(
"Could not resize file \"" + Filename +
"\"");
2451 #elif defined(WIN32)
2452 LARGE_INTEGER liFilePos;
2453 liFilePos.QuadPart = ullNewSize;
2455 !SetFilePointerEx(hWrite, liFilePos, NULL, FILE_BEGIN) ||
2456 !SetEndOfFile(hWrite)
2457 )
throw Exception(
"Could not resize file \"" + Filename +
"\"");
2459 # error Sorry, this version of libgig only supports POSIX and Windows systems yet.
2460 # error Reason: portable implementation of RIFF::File::ResizeFile() is missing (yet)!
2466 std::cout <<
"File::~File()" << std::endl;
2479 void File::Cleanup() {
2481 for (
auto it = io.byThread.begin(); it != io.byThread.end(); ++it) {
2482 _close(it->second.hRead);
2501 size = __GetFileSize(hRead);
2543 switch (fileOffsetSize) {
2553 default:
throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2559 switch (FileOffsetPreference) {
2561 return (fileSize >> 32) ? 8 : 4;
2567 throw Exception(
"Internal error: Invalid RIFF::offset_size_t");
2646 return io.isPerThread;
2665 std::lock_guard<std::mutex> lock(io.mutex);
2666 if (!io.byThread.empty() == enable)
return;
2667 io.isPerThread = enable;
2669 const std::thread::id tid = std::this_thread::get_id();
2670 io.byThread[tid] = io;
2673 for (
auto it = io.byThread.begin(); it != io.byThread.end(); ++it) {
2674 if (it == io.byThread.begin()) {
2675 io.hRead = it->second.hRead;
2676 io.hWrite = it->second.hWrite;
2678 _close(it->second.hRead);
2679 _close(it->second.hWrite);
2682 io.byThread.clear();
2695 return nDataChunkCount;
2707 return nListChunkCount;
2723 return nDataChunkCount + nListChunkCount;
2728 struct stat filestat;
2729 if (fstat(hFile, &filestat) == -1)
2730 throw Exception(
"POSIX FS error: could not determine file size");
2731 return filestat.st_size;
2733 #elif defined(WIN32)
2736 if (!GetFileSizeEx(hFile, &size))
2737 throw Exception(
"Windows FS error: could not determine file size");
2738 return size.QuadPart;
2742 off_t curpos = ftello(hFile);
2743 if (fseeko(hFile, 0, SEEK_END) == -1)
2744 throw Exception(
"FS error: could not determine file size");
2745 off_t size = ftello(hFile);
2746 fseeko(hFile, curpos, SEEK_SET);
2755 Exception::Exception() {
2758 Exception::Exception(String format, ...) {
2760 va_start(arg, format);
2761 Message = assemble(format, arg);
2765 Exception::Exception(String format, va_list arg) {
2766 Message = assemble(format, arg);
2769 Exception::~Exception() {
2772 void Exception::PrintMessage()
const {
2773 std::cout <<
"RIFF::Exception: " << Message << std::endl;
2776 String Exception::assemble(String format, va_list arg) {
2778 vasprintf(&buf, format.c_str(), arg);
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'...
virtual void __resetPos()
Sets Chunk's read/write position to zero.
void Resize(file_offset_t NewSize)
Resize chunk.
int8_t ReadInt8()
Reads one 8 Bit signed integer word and increments the position within the chunk.
uint32_t ReadUint32()
Reads one 32 Bit unsigned integer word and increments the position within the chunk.
stream_state_t GetState() const
Returns the current state of the chunk object.
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).
file_offset_t GetFilePos() const
Current, actual offset in file of current chunk data body read/write position.
void ReleaseChunkData()
Free loaded chunk body from RAM.
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.
file_offset_t RemainingBytes() const
Returns the number of bytes left to read in the chunk body.
int16_t ReadInt16()
Reads one 16 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 chunk persistently e.g.
file_offset_t GetPos() const
Current read/write position within the chunk data body (starting with 0).
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 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.
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 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...
uint32_t GetChunkID() const
Chunk ID in unsigned integer representation.
void * LoadChunkData()
Load chunk body into RAM.
String GetChunkIDString() const
Returns the String representation of the chunk's ID (e.g.
uint8_t ReadUint8()
Reads one 8 Bit unsigned integer word and increments the position within the chunk.
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 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...
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...
void ReadString(String &s, int size)
Reads a null-padded string of size characters and copies it into the string s.
uint16_t ReadUint16()
Reads one 16 Bit unsigned integer word and increments the position within the chunk.
file_offset_t GetSize() const
Chunk size in bytes (without header, thus the chunk data body)
int32_t ReadInt32()
Reads one 32 Bit signed integer word and increments the position within the chunk.
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...
Will be thrown whenever an error occurs while handling a RIFF file.
Handle FileWriteHandle() const
Returns the OS dependent file I/O write handle intended to be used by the calling thread.
HandlePair FileHandlePair() const
Returns the OS dependent file I/O read and write handles intended to be used by the calling thread.
bool SetMode(stream_mode_t NewMode)
Change file access mode.
int GetRequiredFileOffsetSize()
Returns the required size (in bytes) of file offsets stored in the headers of all chunks of this file...
int GetFileOffsetSize() const
Returns the current size (in bytes) of file offsets stored in the headers of all chunks of this file.
File(uint32_t FileType)
Create new RIFF file.
file_offset_t GetCurrentFileSize() const
Returns the current size of this file (in bytes) as it is currently yet stored on disk.
void SetByteOrder(endian_t Endian)
Set the byte order to be used when saving.
bool IsNew() const
Returns true if this file has been created new from scratch and has not been stored to disk yet.
file_offset_t GetRequiredFileSize()
Returns the required size (in bytes) for this RIFF File to be saved to disk.
size_t totalDataChunkCount() const
File's total amount of ordinary (data) chunks.
Handle FileHandle() const
Returns the OS dependent file I/O read handle intended to be used by the calling thread.
bool IsIOPerThread() const
Whether file streams are independent for each thread.
size_t totalChunkCount() const
File's total amount of data chunks and list chunks.
stream_mode_t GetMode() const
Returns the file I/O mode currently being available for the calling thread for this RIFF file (either...
size_t totalListChunkCount() const
File's total amount of list chunks.
virtual void Save(progress_t *pProgress=NULL)
Save changes to same file.
layout_t Layout
An ordinary RIFF file is always set to layout_standard.
int Handle
OS dependent type serving as file handle / descriptor for OS dependent file I/O operations.
int FileOffsetSize
Size of file offsets (in bytes) when this file was opened (or saved the last time).
void SetIOPerThread(bool enable)
Enable/disable file streams being independent for each thread.
size_t CountSubLists()
Returns number of sublists within the list.
Chunk * GetSubChunk(uint32_t ChunkID)
Returns subchunk with chunk ID ChunkID within this chunk list.
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...
void MoveSubChunk(Chunk *pSrc, Chunk *pDst)
Moves a sub chunk witin this list.
List * GetFirstSubList()
Returns the first sublist within the list (that is a subchunk with chunk ID "LIST").
List * AddSubList(uint32_t uiListType)
Creates a new list sub chunk.
Chunk * GetFirstSubChunk()
Returns the first subchunk within the list (which may be an ordinary chunk as well as a list chunk).
virtual file_offset_t WriteChunk(file_offset_t ullWritePos, file_offset_t ullCurrentDataOffset, progress_t *pProgress=NULL)
Write list chunk persistently e.g.
void DeleteSubChunk(Chunk *pSubChunk)
Removes a sub chunk.
List * GetSubListAt(size_t pos)
Returns sublist chunk with list type ListType at supplied pos position among all subchunks of type Li...
size_t CountSubChunks()
Returns number of subchunks within the list (including list chunks).
List * GetSubList(uint32_t ListType)
Returns sublist chunk with list type ListType 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).
uint32_t GetListType() const
Returns unsigned integer representation of the list's ID.
String GetListTypeString() const
Returns string representation of the lists's id.
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.
virtual void __resetPos()
Sets List Chunk's read/write position to zero and causes all sub chunks to do the same.
Chunk * GetSubChunkAt(size_t pos)
Returns subchunk at supplied pos position within this chunk list.
RIFF specific classes and definitions.
String libraryVersion()
Returns version of this C++ library.
stream_whence_t
File stream position dependent to these relations.
stream_state_t
Current state of the file stream.
String libraryName()
Returns the name of this C++ library.
offset_size_t
Size of RIFF file offsets used in all RIFF chunks' headers.
@ offset_size_64bit
Always use 64 bit offsets (even for files smaller than 4 GB).
@ offset_size_auto
Use 32 bit offsets for files smaller than 4 GB, use 64 bit offsets for files equal or larger than 4 G...
@ offset_size_32bit
Always use 32 bit offsets (even for files larger than 4 GB).
stream_mode_t
Whether file stream is open in read or in read/write mode.
layout_t
General RIFF chunk structure of a RIFF file.
@ layout_standard
Standard RIFF file layout: First chunk in file is a List chunk which contains all other chunks and th...
@ layout_flat
Not a "real" RIFF file: First chunk in file is an ordinary data chunk, not a List chunk,...
endian_t
Alignment of data bytes in memory (system dependant).
uint64_t file_offset_t
Type used by libgig for handling file positioning during file I/O tasks.
Used for indicating the progress of a certain task.
float __range_min
Only for internal usage, do not modify!
void * __private
Only for internal usage, do not modify!
void(* callback)(progress_t *)
Callback function pointer which has to be assigned to a function for progress notification.
void * custom
This pointer can be used for arbitrary data.
const char * activity
Text which describes current ongoing action (e.g. to be displayed along a progress bar).
std::vector< progress_t > subdivide(int iSubtasks) const
Divides this progress task into the requested amount of equal weighted sub-progress tasks and returns...
float __range_max
Only for internal usage, do not modify!